1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.24 2005/04/14 01:38:16 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/genam.h"
19 #include "catalog/catalog.h"
20 #include "catalog/catname.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_constraint.h"
24 #include "catalog/pg_depend.h"
25 #include "catalog/pg_type.h"
26 #include "commands/defrem.h"
27 #include "miscadmin.h"
28 #include "utils/array.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/lsyscache.h"
32 #include "utils/syscache.h"
36 * CreateConstraintEntry
37 * Create a constraint table entry.
39 * Subsidiary records (such as triggers or indexes to implement the
40 * constraint) are *not* created here. But we do make dependency links
41 * from the constraint to the things it depends on.
44 CreateConstraintEntry(const char *constraintName,
45 Oid constraintNamespace,
50 const int16 *constraintKey,
54 const int16 *foreignKey,
56 char foreignUpdateType,
57 char foreignDeleteType,
58 char foreignMatchType,
67 char nulls[Natts_pg_constraint];
68 Datum values[Natts_pg_constraint];
69 ArrayType *conkeyArray;
70 ArrayType *confkeyArray;
73 ObjectAddress conobject;
75 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
77 Assert(constraintName);
78 namestrcpy(&cname, constraintName);
81 * Convert C arrays into Postgres arrays.
83 if (constraintNKeys > 0)
87 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
88 for (i = 0; i < constraintNKeys; i++)
89 conkey[i] = Int16GetDatum(constraintKey[i]);
90 conkeyArray = construct_array(conkey, constraintNKeys,
91 INT2OID, 2, true, 's');
100 confkey = (Datum *) palloc(foreignNKeys * sizeof(Datum));
101 for (i = 0; i < foreignNKeys; i++)
102 confkey[i] = Int16GetDatum(foreignKey[i]);
103 confkeyArray = construct_array(confkey, foreignNKeys,
104 INT2OID, 2, true, 's');
109 /* initialize nulls and values */
110 for (i = 0; i < Natts_pg_constraint; i++)
113 values[i] = (Datum) NULL;
116 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
117 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
118 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
119 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
120 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
121 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
122 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
123 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
124 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
125 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
126 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
129 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
131 nulls[Anum_pg_constraint_conkey - 1] = 'n';
134 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
136 nulls[Anum_pg_constraint_confkey - 1] = 'n';
139 * initialize the binary form of the check constraint.
142 values[Anum_pg_constraint_conbin - 1] = DirectFunctionCall1(textin,
143 CStringGetDatum(conBin));
145 nulls[Anum_pg_constraint_conbin - 1] = 'n';
148 * initialize the text form of the check constraint
151 values[Anum_pg_constraint_consrc - 1] = DirectFunctionCall1(textin,
152 CStringGetDatum(conSrc));
154 nulls[Anum_pg_constraint_consrc - 1] = 'n';
156 tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
158 conOid = simple_heap_insert(conDesc, tup);
160 /* update catalog indexes */
161 CatalogUpdateIndexes(conDesc, tup);
163 conobject.classId = RelationGetRelid(conDesc);
164 conobject.objectId = conOid;
165 conobject.objectSubId = 0;
167 heap_close(conDesc, RowExclusiveLock);
169 if (OidIsValid(relId))
172 * Register auto dependency from constraint to owning relation, or
173 * to specific column(s) if any are mentioned.
175 ObjectAddress relobject;
177 relobject.classId = RelationRelationId;
178 relobject.objectId = relId;
179 if (constraintNKeys > 0)
181 for (i = 0; i < constraintNKeys; i++)
183 relobject.objectSubId = constraintKey[i];
185 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
190 relobject.objectSubId = 0;
192 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
196 if (OidIsValid(domainId))
199 * Register auto dependency from constraint to owning domain
201 ObjectAddress domobject;
203 domobject.classId = TypeRelationId;
204 domobject.objectId = domainId;
205 domobject.objectSubId = 0;
207 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
210 if (OidIsValid(foreignRelId))
213 * Register normal dependency from constraint to foreign relation,
214 * or to specific column(s) if any are mentioned.
216 ObjectAddress relobject;
218 relobject.classId = RelationRelationId;
219 relobject.objectId = foreignRelId;
220 if (foreignNKeys > 0)
222 for (i = 0; i < foreignNKeys; i++)
224 relobject.objectSubId = foreignKey[i];
226 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
231 relobject.objectSubId = 0;
233 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
237 if (OidIsValid(indexRelId))
240 * Register normal dependency on the unique index that supports a
241 * foreign-key constraint.
243 ObjectAddress relobject;
245 relobject.classId = RelationRelationId;
246 relobject.objectId = indexRelId;
247 relobject.objectSubId = 0;
249 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
255 * Register dependencies from constraint to objects mentioned in
258 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
268 * Test whether given name is currently used as a constraint name
269 * for the given object (relation or domain).
271 * This is used to decide whether to accept a user-specified constraint name.
272 * It is deliberately not the same test as ChooseConstraintName uses to decide
273 * whether an auto-generated name is OK: here, we will allow it unless there
274 * is an identical constraint name in use *on the same object*.
276 * NB: Caller should hold exclusive lock on the given object, else
277 * this test can be fooled by concurrent additions.
280 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
281 Oid objNamespace, const char *conname)
289 conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
293 ScanKeyInit(&skey[0],
294 Anum_pg_constraint_conname,
295 BTEqualStrategyNumber, F_NAMEEQ,
296 CStringGetDatum(conname));
298 ScanKeyInit(&skey[1],
299 Anum_pg_constraint_connamespace,
300 BTEqualStrategyNumber, F_OIDEQ,
301 ObjectIdGetDatum(objNamespace));
303 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
304 SnapshotNow, 2, skey);
306 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
308 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
310 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
315 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
322 systable_endscan(conscan);
323 heap_close(conDesc, AccessShareLock);
329 * Select a nonconflicting name for a new constraint.
331 * The objective here is to choose a name that is unique within the
332 * specified namespace. Postgres does not require this, but the SQL
333 * spec does, and some apps depend on it. Therefore we avoid choosing
334 * default names that so conflict.
336 * name1, name2, and label are used the same way as for makeObjectName(),
337 * except that the label can't be NULL; digits will be appended to the label
338 * if needed to create a name that is unique within the specified namespace.
340 * 'others' can be a list of string names already chosen within the current
341 * command (but not yet reflected into the catalogs); we will not choose
342 * a duplicate of one of these either.
344 * Note: it is theoretically possible to get a collision anyway, if someone
345 * else chooses the same name concurrently. This is fairly unlikely to be
346 * a problem in practice, especially if one is holding an exclusive lock on
347 * the relation identified by name1.
349 * Returns a palloc'd string.
352 ChooseConstraintName(const char *name1, const char *name2,
353 const char *label, Oid namespace,
357 char *conname = NULL;
358 char modlabel[NAMEDATALEN];
365 conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
367 /* try the unmodified label first */
368 StrNCpy(modlabel, label, sizeof(modlabel));
372 conname = makeObjectName(name1, name2, modlabel);
378 if (strcmp((char *) lfirst(l), conname) == 0)
387 ScanKeyInit(&skey[0],
388 Anum_pg_constraint_conname,
389 BTEqualStrategyNumber, F_NAMEEQ,
390 CStringGetDatum(conname));
392 ScanKeyInit(&skey[1],
393 Anum_pg_constraint_connamespace,
394 BTEqualStrategyNumber, F_OIDEQ,
395 ObjectIdGetDatum(namespace));
397 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
398 SnapshotNow, 2, skey);
400 found = (HeapTupleIsValid(systable_getnext(conscan)));
402 systable_endscan(conscan);
408 /* found a conflict, so try a new name component */
410 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
413 heap_close(conDesc, AccessShareLock);
419 * Delete a single constraint record.
422 RemoveConstraintById(Oid conId)
428 Form_pg_constraint con;
430 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
432 ScanKeyInit(&skey[0],
433 ObjectIdAttributeNumber,
434 BTEqualStrategyNumber, F_OIDEQ,
435 ObjectIdGetDatum(conId));
437 conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
438 SnapshotNow, 1, skey);
440 tup = systable_getnext(conscan);
441 if (!HeapTupleIsValid(tup))
442 elog(ERROR, "could not find tuple for constraint %u", conId);
443 con = (Form_pg_constraint) GETSTRUCT(tup);
446 * Special processing depending on what the constraint is for.
448 if (OidIsValid(con->conrelid))
453 * If the constraint is for a relation, open and exclusive-lock
454 * the relation it's for.
456 rel = heap_open(con->conrelid, AccessExclusiveLock);
459 * We need to update the relcheck count if it is a check
460 * constraint being dropped. This update will force backends to
461 * rebuild relcache entries when we commit.
463 if (con->contype == CONSTRAINT_CHECK)
467 Form_pg_class classForm;
469 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
470 relTup = SearchSysCacheCopy(RELOID,
471 ObjectIdGetDatum(con->conrelid),
473 if (!HeapTupleIsValid(relTup))
474 elog(ERROR, "cache lookup failed for relation %u",
476 classForm = (Form_pg_class) GETSTRUCT(relTup);
478 if (classForm->relchecks == 0) /* should not happen */
479 elog(ERROR, "relation \"%s\" has relchecks = 0",
480 RelationGetRelationName(rel));
481 classForm->relchecks--;
483 simple_heap_update(pgrel, &relTup->t_self, relTup);
485 CatalogUpdateIndexes(pgrel, relTup);
487 heap_freetuple(relTup);
489 heap_close(pgrel, RowExclusiveLock);
492 /* Keep lock on constraint's rel until end of xact */
493 heap_close(rel, NoLock);
495 else if (OidIsValid(con->contypid))
498 * XXX for now, do nothing special when dropping a domain
501 * Probably there should be some form of locking on the domain type,
502 * but we have no such concept at the moment.
506 elog(ERROR, "constraint %u is not of a known type", conId);
508 /* Fry the constraint itself */
509 simple_heap_delete(conDesc, &tup->t_self);
512 systable_endscan(conscan);
513 heap_close(conDesc, RowExclusiveLock);
517 * GetConstraintNameForTrigger
518 * Get the name of the constraint owning a trigger, if any
520 * Returns a palloc'd string, or NULL if no constraint can be found
523 GetConstraintNameForTrigger(Oid triggerId)
526 Oid constraintId = InvalidOid;
528 Oid pg_constraint_id;
535 pg_trigger_id = get_system_catalog_relid(TriggerRelationName);
536 pg_constraint_id = get_system_catalog_relid(ConstraintRelationName);
539 * We must grovel through pg_depend to find the owning constraint.
540 * Perhaps pg_trigger should have a column for the owning constraint ...
541 * but right now this is not performance-critical code.
543 depRel = heap_openr(DependRelationName, AccessShareLock);
546 Anum_pg_depend_classid,
547 BTEqualStrategyNumber, F_OIDEQ,
548 ObjectIdGetDatum(pg_trigger_id));
550 Anum_pg_depend_objid,
551 BTEqualStrategyNumber, F_OIDEQ,
552 ObjectIdGetDatum(triggerId));
553 /* assume we can ignore objsubid for a trigger */
555 scan = systable_beginscan(depRel, DependDependerIndex, true,
556 SnapshotNow, 2, key);
558 while (HeapTupleIsValid(tup = systable_getnext(scan)))
560 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
562 if (foundDep->refclassid == pg_constraint_id &&
563 foundDep->deptype == DEPENDENCY_INTERNAL)
565 constraintId = foundDep->refobjid;
570 systable_endscan(scan);
572 heap_close(depRel, AccessShareLock);
574 if (!OidIsValid(constraintId))
575 return NULL; /* no owning constraint found */
577 conRel = heap_openr(ConstraintRelationName, AccessShareLock);
580 ObjectIdAttributeNumber,
581 BTEqualStrategyNumber, F_OIDEQ,
582 ObjectIdGetDatum(constraintId));
584 scan = systable_beginscan(conRel, ConstraintOidIndex, true,
585 SnapshotNow, 1, key);
587 tup = systable_getnext(scan);
589 if (HeapTupleIsValid(tup))
591 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
593 result = pstrdup(NameStr(con->conname));
597 /* This arguably should be an error, but we'll just return NULL */
601 systable_endscan(scan);
603 heap_close(conRel, AccessShareLock);