1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2008, 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.41 2008/05/09 23:32:04 tgl 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_operator.h"
23 #include "catalog/pg_type.h"
24 #include "commands/defrem.h"
25 #include "utils/array.h"
26 #include "utils/builtins.h"
27 #include "utils/fmgroids.h"
28 #include "utils/lsyscache.h"
29 #include "utils/syscache.h"
30 #include "utils/tqual.h"
34 * CreateConstraintEntry
35 * Create a constraint table entry.
37 * Subsidiary records (such as triggers or indexes to implement the
38 * constraint) are *not* created here. But we do make dependency links
39 * from the constraint to the things it depends on.
42 CreateConstraintEntry(const char *constraintName,
43 Oid constraintNamespace,
48 const int16 *constraintKey,
52 const int16 *foreignKey,
57 char foreignUpdateType,
58 char foreignDeleteType,
59 char foreignMatchType,
70 char nulls[Natts_pg_constraint];
71 Datum values[Natts_pg_constraint];
72 ArrayType *conkeyArray;
73 ArrayType *confkeyArray;
74 ArrayType *conpfeqopArray;
75 ArrayType *conppeqopArray;
76 ArrayType *conffeqopArray;
79 ObjectAddress conobject;
81 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
83 Assert(constraintName);
84 namestrcpy(&cname, constraintName);
87 * Convert C arrays into Postgres arrays.
89 if (constraintNKeys > 0)
93 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
94 for (i = 0; i < constraintNKeys; i++)
95 conkey[i] = Int16GetDatum(constraintKey[i]);
96 conkeyArray = construct_array(conkey, constraintNKeys,
97 INT2OID, 2, true, 's');
102 if (foreignNKeys > 0)
106 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
107 for (i = 0; i < foreignNKeys; i++)
108 fkdatums[i] = Int16GetDatum(foreignKey[i]);
109 confkeyArray = construct_array(fkdatums, foreignNKeys,
110 INT2OID, 2, true, 's');
111 for (i = 0; i < foreignNKeys; i++)
112 fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
113 conpfeqopArray = construct_array(fkdatums, foreignNKeys,
114 OIDOID, sizeof(Oid), true, 'i');
115 for (i = 0; i < foreignNKeys; i++)
116 fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
117 conppeqopArray = construct_array(fkdatums, foreignNKeys,
118 OIDOID, sizeof(Oid), true, 'i');
119 for (i = 0; i < foreignNKeys; i++)
120 fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
121 conffeqopArray = construct_array(fkdatums, foreignNKeys,
122 OIDOID, sizeof(Oid), true, 'i');
127 conpfeqopArray = NULL;
128 conppeqopArray = NULL;
129 conffeqopArray = NULL;
132 /* initialize nulls and values */
133 for (i = 0; i < Natts_pg_constraint; i++)
136 values[i] = (Datum) NULL;
139 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
140 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
141 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
142 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
143 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
144 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
145 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
146 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
147 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
148 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
149 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
150 values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
151 values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
154 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
156 nulls[Anum_pg_constraint_conkey - 1] = 'n';
159 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
161 nulls[Anum_pg_constraint_confkey - 1] = 'n';
164 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
166 nulls[Anum_pg_constraint_conpfeqop - 1] = 'n';
169 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
171 nulls[Anum_pg_constraint_conppeqop - 1] = 'n';
174 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
176 nulls[Anum_pg_constraint_conffeqop - 1] = 'n';
179 * initialize the binary form of the check constraint.
182 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
184 nulls[Anum_pg_constraint_conbin - 1] = 'n';
187 * initialize the text form of the check constraint
190 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
192 nulls[Anum_pg_constraint_consrc - 1] = 'n';
194 tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
196 conOid = simple_heap_insert(conDesc, tup);
198 /* update catalog indexes */
199 CatalogUpdateIndexes(conDesc, tup);
201 conobject.classId = ConstraintRelationId;
202 conobject.objectId = conOid;
203 conobject.objectSubId = 0;
205 heap_close(conDesc, RowExclusiveLock);
207 if (OidIsValid(relId))
210 * Register auto dependency from constraint to owning relation, or to
211 * specific column(s) if any are mentioned.
213 ObjectAddress relobject;
215 relobject.classId = RelationRelationId;
216 relobject.objectId = relId;
217 if (constraintNKeys > 0)
219 for (i = 0; i < constraintNKeys; i++)
221 relobject.objectSubId = constraintKey[i];
223 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
228 relobject.objectSubId = 0;
230 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
234 if (OidIsValid(domainId))
237 * Register auto dependency from constraint to owning domain
239 ObjectAddress domobject;
241 domobject.classId = TypeRelationId;
242 domobject.objectId = domainId;
243 domobject.objectSubId = 0;
245 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
248 if (OidIsValid(foreignRelId))
251 * Register normal dependency from constraint to foreign relation, or
252 * to specific column(s) if any are mentioned.
254 ObjectAddress relobject;
256 relobject.classId = RelationRelationId;
257 relobject.objectId = foreignRelId;
258 if (foreignNKeys > 0)
260 for (i = 0; i < foreignNKeys; i++)
262 relobject.objectSubId = foreignKey[i];
264 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
269 relobject.objectSubId = 0;
271 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
275 if (OidIsValid(indexRelId))
278 * Register normal dependency on the unique index that supports a
279 * foreign-key constraint.
281 ObjectAddress relobject;
283 relobject.classId = RelationRelationId;
284 relobject.objectId = indexRelId;
285 relobject.objectSubId = 0;
287 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
290 if (foreignNKeys > 0)
293 * Register normal dependencies on the equality operators that support
294 * a foreign-key constraint. If the PK and FK types are the same then
295 * all three operators for a column are the same; otherwise they are
298 ObjectAddress oprobject;
300 oprobject.classId = OperatorRelationId;
301 oprobject.objectSubId = 0;
303 for (i = 0; i < foreignNKeys; i++)
305 oprobject.objectId = pfEqOp[i];
306 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
307 if (ppEqOp[i] != pfEqOp[i])
309 oprobject.objectId = ppEqOp[i];
310 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
312 if (ffEqOp[i] != pfEqOp[i])
314 oprobject.objectId = ffEqOp[i];
315 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
323 * Register dependencies from constraint to objects mentioned in CHECK
326 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
336 * Test whether given name is currently used as a constraint name
337 * for the given object (relation or domain).
339 * This is used to decide whether to accept a user-specified constraint name.
340 * It is deliberately not the same test as ChooseConstraintName uses to decide
341 * whether an auto-generated name is OK: here, we will allow it unless there
342 * is an identical constraint name in use *on the same object*.
344 * NB: Caller should hold exclusive lock on the given object, else
345 * this test can be fooled by concurrent additions.
348 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
349 Oid objNamespace, const char *conname)
357 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
361 ScanKeyInit(&skey[0],
362 Anum_pg_constraint_conname,
363 BTEqualStrategyNumber, F_NAMEEQ,
364 CStringGetDatum(conname));
366 ScanKeyInit(&skey[1],
367 Anum_pg_constraint_connamespace,
368 BTEqualStrategyNumber, F_OIDEQ,
369 ObjectIdGetDatum(objNamespace));
371 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
372 SnapshotNow, 2, skey);
374 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
376 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
378 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
383 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
390 systable_endscan(conscan);
391 heap_close(conDesc, AccessShareLock);
397 * Select a nonconflicting name for a new constraint.
399 * The objective here is to choose a name that is unique within the
400 * specified namespace. Postgres does not require this, but the SQL
401 * spec does, and some apps depend on it. Therefore we avoid choosing
402 * default names that so conflict.
404 * name1, name2, and label are used the same way as for makeObjectName(),
405 * except that the label can't be NULL; digits will be appended to the label
406 * if needed to create a name that is unique within the specified namespace.
408 * 'others' can be a list of string names already chosen within the current
409 * command (but not yet reflected into the catalogs); we will not choose
410 * a duplicate of one of these either.
412 * Note: it is theoretically possible to get a collision anyway, if someone
413 * else chooses the same name concurrently. This is fairly unlikely to be
414 * a problem in practice, especially if one is holding an exclusive lock on
415 * the relation identified by name1.
417 * Returns a palloc'd string.
420 ChooseConstraintName(const char *name1, const char *name2,
421 const char *label, Oid namespace,
425 char *conname = NULL;
426 char modlabel[NAMEDATALEN];
433 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
435 /* try the unmodified label first */
436 StrNCpy(modlabel, label, sizeof(modlabel));
440 conname = makeObjectName(name1, name2, modlabel);
446 if (strcmp((char *) lfirst(l), conname) == 0)
455 ScanKeyInit(&skey[0],
456 Anum_pg_constraint_conname,
457 BTEqualStrategyNumber, F_NAMEEQ,
458 CStringGetDatum(conname));
460 ScanKeyInit(&skey[1],
461 Anum_pg_constraint_connamespace,
462 BTEqualStrategyNumber, F_OIDEQ,
463 ObjectIdGetDatum(namespace));
465 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
466 SnapshotNow, 2, skey);
468 found = (HeapTupleIsValid(systable_getnext(conscan)));
470 systable_endscan(conscan);
476 /* found a conflict, so try a new name component */
478 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
481 heap_close(conDesc, AccessShareLock);
487 * Delete a single constraint record.
490 RemoveConstraintById(Oid conId)
494 Form_pg_constraint con;
496 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
498 tup = SearchSysCache(CONSTROID,
499 ObjectIdGetDatum(conId),
501 if (!HeapTupleIsValid(tup)) /* should not happen */
502 elog(ERROR, "cache lookup failed for constraint %u", conId);
503 con = (Form_pg_constraint) GETSTRUCT(tup);
506 * Special processing depending on what the constraint is for.
508 if (OidIsValid(con->conrelid))
513 * If the constraint is for a relation, open and exclusive-lock the
516 rel = heap_open(con->conrelid, AccessExclusiveLock);
519 * We need to update the relcheck count if it is a check constraint
520 * being dropped. This update will force backends to rebuild relcache
521 * entries when we commit.
523 if (con->contype == CONSTRAINT_CHECK)
527 Form_pg_class classForm;
529 pgrel = heap_open(RelationRelationId, RowExclusiveLock);
530 relTup = SearchSysCacheCopy(RELOID,
531 ObjectIdGetDatum(con->conrelid),
533 if (!HeapTupleIsValid(relTup))
534 elog(ERROR, "cache lookup failed for relation %u",
536 classForm = (Form_pg_class) GETSTRUCT(relTup);
538 if (classForm->relchecks == 0) /* should not happen */
539 elog(ERROR, "relation \"%s\" has relchecks = 0",
540 RelationGetRelationName(rel));
541 classForm->relchecks--;
543 simple_heap_update(pgrel, &relTup->t_self, relTup);
545 CatalogUpdateIndexes(pgrel, relTup);
547 heap_freetuple(relTup);
549 heap_close(pgrel, RowExclusiveLock);
552 /* Keep lock on constraint's rel until end of xact */
553 heap_close(rel, NoLock);
555 else if (OidIsValid(con->contypid))
558 * XXX for now, do nothing special when dropping a domain constraint
560 * Probably there should be some form of locking on the domain type,
561 * but we have no such concept at the moment.
565 elog(ERROR, "constraint %u is not of a known type", conId);
567 /* Fry the constraint itself */
568 simple_heap_delete(conDesc, &tup->t_self);
571 ReleaseSysCache(tup);
572 heap_close(conDesc, RowExclusiveLock);
576 * RenameConstraintById
577 * Rename a constraint.
579 * Note: this isn't intended to be a user-exposed function; it doesn't check
580 * permissions etc. Currently this is only invoked when renaming an index
581 * that is associated with a constraint, but it's made a little more general
582 * than that with the expectation of someday having ALTER TABLE RENAME
586 RenameConstraintById(Oid conId, const char *newname)
590 Form_pg_constraint con;
592 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
594 tuple = SearchSysCacheCopy(CONSTROID,
595 ObjectIdGetDatum(conId),
597 if (!HeapTupleIsValid(tuple))
598 elog(ERROR, "cache lookup failed for constraint %u", conId);
599 con = (Form_pg_constraint) GETSTRUCT(tuple);
602 * We need to check whether the name is already in use --- note that
603 * there currently is not a unique index that would catch this.
605 if (OidIsValid(con->conrelid) &&
606 ConstraintNameIsUsed(CONSTRAINT_RELATION,
611 (errcode(ERRCODE_DUPLICATE_OBJECT),
612 errmsg("constraint \"%s\" for relation \"%s\" already exists",
613 newname, get_rel_name(con->conrelid))));
614 if (OidIsValid(con->contypid) &&
615 ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
620 (errcode(ERRCODE_DUPLICATE_OBJECT),
621 errmsg("constraint \"%s\" for domain \"%s\" already exists",
622 newname, format_type_be(con->contypid))));
624 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
625 namestrcpy(&(con->conname), newname);
627 simple_heap_update(conDesc, &tuple->t_self, tuple);
629 /* update the system catalog indexes */
630 CatalogUpdateIndexes(conDesc, tuple);
632 heap_freetuple(tuple);
633 heap_close(conDesc, RowExclusiveLock);
637 * AlterConstraintNamespaces
638 * Find any constraints belonging to the specified object,
639 * and move them to the specified new namespace.
641 * isType indicates whether the owning object is a type or a relation.
644 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
645 Oid newNspId, bool isType)
652 conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
657 Anum_pg_constraint_contypid,
658 BTEqualStrategyNumber, F_OIDEQ,
659 ObjectIdGetDatum(ownerId));
661 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
662 SnapshotNow, 1, key);
667 Anum_pg_constraint_conrelid,
668 BTEqualStrategyNumber, F_OIDEQ,
669 ObjectIdGetDatum(ownerId));
671 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
672 SnapshotNow, 1, key);
675 while (HeapTupleIsValid((tup = systable_getnext(scan))))
677 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
679 if (conform->connamespace == oldNspId)
681 tup = heap_copytuple(tup);
682 conform = (Form_pg_constraint) GETSTRUCT(tup);
684 conform->connamespace = newNspId;
686 simple_heap_update(conRel, &tup->t_self, tup);
687 CatalogUpdateIndexes(conRel, tup);
690 * Note: currently, the constraint will not have its own
691 * dependency on the namespace, so we don't need to do
692 * changeDependencyFor().
697 systable_endscan(scan);
699 heap_close(conRel, RowExclusiveLock);