1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2007, 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.34 2007/01/05 22:19:25 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_constraint.h"
22 #include "catalog/pg_depend.h"
23 #include "catalog/pg_trigger.h"
24 #include "catalog/pg_type.h"
25 #include "commands/defrem.h"
26 #include "utils/array.h"
27 #include "utils/builtins.h"
28 #include "utils/fmgroids.h"
29 #include "utils/syscache.h"
33 * CreateConstraintEntry
34 * Create a constraint table entry.
36 * Subsidiary records (such as triggers or indexes to implement the
37 * constraint) are *not* created here. But we do make dependency links
38 * from the constraint to the things it depends on.
41 CreateConstraintEntry(const char *constraintName,
42 Oid constraintNamespace,
47 const int16 *constraintKey,
51 const int16 *foreignKey,
53 char foreignUpdateType,
54 char foreignDeleteType,
55 char foreignMatchType,
64 char nulls[Natts_pg_constraint];
65 Datum values[Natts_pg_constraint];
66 ArrayType *conkeyArray;
67 ArrayType *confkeyArray;
70 ObjectAddress conobject;
72 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
74 Assert(constraintName);
75 namestrcpy(&cname, constraintName);
78 * Convert C arrays into Postgres arrays.
80 if (constraintNKeys > 0)
84 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
85 for (i = 0; i < constraintNKeys; i++)
86 conkey[i] = Int16GetDatum(constraintKey[i]);
87 conkeyArray = construct_array(conkey, constraintNKeys,
88 INT2OID, 2, true, 's');
97 confkey = (Datum *) palloc(foreignNKeys * sizeof(Datum));
98 for (i = 0; i < foreignNKeys; i++)
99 confkey[i] = Int16GetDatum(foreignKey[i]);
100 confkeyArray = construct_array(confkey, foreignNKeys,
101 INT2OID, 2, true, 's');
106 /* initialize nulls and values */
107 for (i = 0; i < Natts_pg_constraint; i++)
110 values[i] = (Datum) NULL;
113 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
114 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
115 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
116 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
117 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
118 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
119 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
120 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
121 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
122 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
123 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
126 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
128 nulls[Anum_pg_constraint_conkey - 1] = 'n';
131 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
133 nulls[Anum_pg_constraint_confkey - 1] = 'n';
136 * initialize the binary form of the check constraint.
139 values[Anum_pg_constraint_conbin - 1] = DirectFunctionCall1(textin,
140 CStringGetDatum(conBin));
142 nulls[Anum_pg_constraint_conbin - 1] = 'n';
145 * initialize the text form of the check constraint
148 values[Anum_pg_constraint_consrc - 1] = DirectFunctionCall1(textin,
149 CStringGetDatum(conSrc));
151 nulls[Anum_pg_constraint_consrc - 1] = 'n';
153 tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
155 conOid = simple_heap_insert(conDesc, tup);
157 /* update catalog indexes */
158 CatalogUpdateIndexes(conDesc, tup);
160 conobject.classId = ConstraintRelationId;
161 conobject.objectId = conOid;
162 conobject.objectSubId = 0;
164 heap_close(conDesc, RowExclusiveLock);
166 if (OidIsValid(relId))
169 * Register auto dependency from constraint to owning relation, or to
170 * specific column(s) if any are mentioned.
172 ObjectAddress relobject;
174 relobject.classId = RelationRelationId;
175 relobject.objectId = relId;
176 if (constraintNKeys > 0)
178 for (i = 0; i < constraintNKeys; i++)
180 relobject.objectSubId = constraintKey[i];
182 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
187 relobject.objectSubId = 0;
189 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
193 if (OidIsValid(domainId))
196 * Register auto dependency from constraint to owning domain
198 ObjectAddress domobject;
200 domobject.classId = TypeRelationId;
201 domobject.objectId = domainId;
202 domobject.objectSubId = 0;
204 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
207 if (OidIsValid(foreignRelId))
210 * Register normal dependency from constraint to foreign relation, or
211 * to specific column(s) if any are mentioned.
213 ObjectAddress relobject;
215 relobject.classId = RelationRelationId;
216 relobject.objectId = foreignRelId;
217 if (foreignNKeys > 0)
219 for (i = 0; i < foreignNKeys; i++)
221 relobject.objectSubId = foreignKey[i];
223 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
228 relobject.objectSubId = 0;
230 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
234 if (OidIsValid(indexRelId))
237 * Register normal dependency on the unique index that supports a
238 * foreign-key constraint.
240 ObjectAddress relobject;
242 relobject.classId = RelationRelationId;
243 relobject.objectId = indexRelId;
244 relobject.objectSubId = 0;
246 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
252 * Register dependencies from constraint to objects mentioned in CHECK
255 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
265 * Test whether given name is currently used as a constraint name
266 * for the given object (relation or domain).
268 * This is used to decide whether to accept a user-specified constraint name.
269 * It is deliberately not the same test as ChooseConstraintName uses to decide
270 * whether an auto-generated name is OK: here, we will allow it unless there
271 * is an identical constraint name in use *on the same object*.
273 * NB: Caller should hold exclusive lock on the given object, else
274 * this test can be fooled by concurrent additions.
277 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
278 Oid objNamespace, const char *conname)
286 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
290 ScanKeyInit(&skey[0],
291 Anum_pg_constraint_conname,
292 BTEqualStrategyNumber, F_NAMEEQ,
293 CStringGetDatum(conname));
295 ScanKeyInit(&skey[1],
296 Anum_pg_constraint_connamespace,
297 BTEqualStrategyNumber, F_OIDEQ,
298 ObjectIdGetDatum(objNamespace));
300 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
301 SnapshotNow, 2, skey);
303 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
305 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
307 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
312 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
319 systable_endscan(conscan);
320 heap_close(conDesc, AccessShareLock);
326 * Select a nonconflicting name for a new constraint.
328 * The objective here is to choose a name that is unique within the
329 * specified namespace. Postgres does not require this, but the SQL
330 * spec does, and some apps depend on it. Therefore we avoid choosing
331 * default names that so conflict.
333 * name1, name2, and label are used the same way as for makeObjectName(),
334 * except that the label can't be NULL; digits will be appended to the label
335 * if needed to create a name that is unique within the specified namespace.
337 * 'others' can be a list of string names already chosen within the current
338 * command (but not yet reflected into the catalogs); we will not choose
339 * a duplicate of one of these either.
341 * Note: it is theoretically possible to get a collision anyway, if someone
342 * else chooses the same name concurrently. This is fairly unlikely to be
343 * a problem in practice, especially if one is holding an exclusive lock on
344 * the relation identified by name1.
346 * Returns a palloc'd string.
349 ChooseConstraintName(const char *name1, const char *name2,
350 const char *label, Oid namespace,
354 char *conname = NULL;
355 char modlabel[NAMEDATALEN];
362 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
364 /* try the unmodified label first */
365 StrNCpy(modlabel, label, sizeof(modlabel));
369 conname = makeObjectName(name1, name2, modlabel);
375 if (strcmp((char *) lfirst(l), conname) == 0)
384 ScanKeyInit(&skey[0],
385 Anum_pg_constraint_conname,
386 BTEqualStrategyNumber, F_NAMEEQ,
387 CStringGetDatum(conname));
389 ScanKeyInit(&skey[1],
390 Anum_pg_constraint_connamespace,
391 BTEqualStrategyNumber, F_OIDEQ,
392 ObjectIdGetDatum(namespace));
394 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
395 SnapshotNow, 2, skey);
397 found = (HeapTupleIsValid(systable_getnext(conscan)));
399 systable_endscan(conscan);
405 /* found a conflict, so try a new name component */
407 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
410 heap_close(conDesc, AccessShareLock);
416 * Delete a single constraint record.
419 RemoveConstraintById(Oid conId)
425 Form_pg_constraint con;
427 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
429 ScanKeyInit(&skey[0],
430 ObjectIdAttributeNumber,
431 BTEqualStrategyNumber, F_OIDEQ,
432 ObjectIdGetDatum(conId));
434 conscan = systable_beginscan(conDesc, ConstraintOidIndexId, true,
435 SnapshotNow, 1, skey);
437 tup = systable_getnext(conscan);
438 if (!HeapTupleIsValid(tup))
439 elog(ERROR, "could not find tuple for constraint %u", conId);
440 con = (Form_pg_constraint) GETSTRUCT(tup);
443 * Special processing depending on what the constraint is for.
445 if (OidIsValid(con->conrelid))
450 * If the constraint is for a relation, open and exclusive-lock the
453 rel = heap_open(con->conrelid, AccessExclusiveLock);
456 * We need to update the relcheck count if it is a check constraint
457 * being dropped. This update will force backends to rebuild relcache
458 * entries when we commit.
460 if (con->contype == CONSTRAINT_CHECK)
464 Form_pg_class classForm;
466 pgrel = heap_open(RelationRelationId, RowExclusiveLock);
467 relTup = SearchSysCacheCopy(RELOID,
468 ObjectIdGetDatum(con->conrelid),
470 if (!HeapTupleIsValid(relTup))
471 elog(ERROR, "cache lookup failed for relation %u",
473 classForm = (Form_pg_class) GETSTRUCT(relTup);
475 if (classForm->relchecks == 0) /* should not happen */
476 elog(ERROR, "relation \"%s\" has relchecks = 0",
477 RelationGetRelationName(rel));
478 classForm->relchecks--;
480 simple_heap_update(pgrel, &relTup->t_self, relTup);
482 CatalogUpdateIndexes(pgrel, relTup);
484 heap_freetuple(relTup);
486 heap_close(pgrel, RowExclusiveLock);
489 /* Keep lock on constraint's rel until end of xact */
490 heap_close(rel, NoLock);
492 else if (OidIsValid(con->contypid))
495 * XXX for now, do nothing special when dropping a domain constraint
497 * Probably there should be some form of locking on the domain type,
498 * but we have no such concept at the moment.
502 elog(ERROR, "constraint %u is not of a known type", conId);
504 /* Fry the constraint itself */
505 simple_heap_delete(conDesc, &tup->t_self);
508 systable_endscan(conscan);
509 heap_close(conDesc, RowExclusiveLock);
513 * GetConstraintNameForTrigger
514 * Get the name of the constraint owning a trigger, if any
516 * Returns a palloc'd string, or NULL if no constraint can be found
519 GetConstraintNameForTrigger(Oid triggerId)
522 Oid constraintId = InvalidOid;
530 * We must grovel through pg_depend to find the owning constraint. Perhaps
531 * pg_trigger should have a column for the owning constraint ... but right
532 * now this is not performance-critical code.
534 depRel = heap_open(DependRelationId, AccessShareLock);
537 Anum_pg_depend_classid,
538 BTEqualStrategyNumber, F_OIDEQ,
539 ObjectIdGetDatum(TriggerRelationId));
541 Anum_pg_depend_objid,
542 BTEqualStrategyNumber, F_OIDEQ,
543 ObjectIdGetDatum(triggerId));
544 /* assume we can ignore objsubid for a trigger */
546 scan = systable_beginscan(depRel, DependDependerIndexId, true,
547 SnapshotNow, 2, key);
549 while (HeapTupleIsValid(tup = systable_getnext(scan)))
551 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
553 if (foundDep->refclassid == ConstraintRelationId &&
554 foundDep->deptype == DEPENDENCY_INTERNAL)
556 constraintId = foundDep->refobjid;
561 systable_endscan(scan);
563 heap_close(depRel, AccessShareLock);
565 if (!OidIsValid(constraintId))
566 return NULL; /* no owning constraint found */
568 conRel = heap_open(ConstraintRelationId, AccessShareLock);
571 ObjectIdAttributeNumber,
572 BTEqualStrategyNumber, F_OIDEQ,
573 ObjectIdGetDatum(constraintId));
575 scan = systable_beginscan(conRel, ConstraintOidIndexId, true,
576 SnapshotNow, 1, key);
578 tup = systable_getnext(scan);
580 if (HeapTupleIsValid(tup))
582 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
584 result = pstrdup(NameStr(con->conname));
588 /* This arguably should be an error, but we'll just return NULL */
592 systable_endscan(scan);
594 heap_close(conRel, AccessShareLock);
600 * AlterConstraintNamespaces
601 * Find any constraints belonging to the specified object,
602 * and move them to the specified new namespace.
604 * isType indicates whether the owning object is a type or a relation.
607 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
608 Oid newNspId, bool isType)
615 conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
620 Anum_pg_constraint_contypid,
621 BTEqualStrategyNumber, F_OIDEQ,
622 ObjectIdGetDatum(ownerId));
624 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
625 SnapshotNow, 1, key);
630 Anum_pg_constraint_conrelid,
631 BTEqualStrategyNumber, F_OIDEQ,
632 ObjectIdGetDatum(ownerId));
634 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
635 SnapshotNow, 1, key);
638 while (HeapTupleIsValid((tup = systable_getnext(scan))))
640 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
642 if (conform->connamespace == oldNspId)
644 tup = heap_copytuple(tup);
645 conform = (Form_pg_constraint) GETSTRUCT(tup);
647 conform->connamespace = newNspId;
649 simple_heap_update(conRel, &tup->t_self, tup);
650 CatalogUpdateIndexes(conRel, tup);
653 * Note: currently, the constraint will not have its own
654 * dependency on the namespace, so we don't need to do
655 * changeDependencyFor().
660 systable_endscan(scan);
662 heap_close(conRel, RowExclusiveLock);