Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / catalog / pg_constraint.c
blob7b5be3c62fe708b7b56ff377d736810950a5e802
1 /*-------------------------------------------------------------------------
3 * pg_constraint.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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/rel.h"
30 #include "utils/syscache.h"
31 #include "utils/tqual.h"
35 * CreateConstraintEntry
36 * Create a constraint table entry.
38 * Subsidiary records (such as triggers or indexes to implement the
39 * constraint) are *not* created here. But we do make dependency links
40 * from the constraint to the things it depends on.
42 Oid
43 CreateConstraintEntry(const char *constraintName,
44 Oid constraintNamespace,
45 char constraintType,
46 bool isDeferrable,
47 bool isDeferred,
48 Oid relId,
49 const int16 *constraintKey,
50 int constraintNKeys,
51 Oid domainId,
52 Oid foreignRelId,
53 const int16 *foreignKey,
54 const Oid *pfEqOp,
55 const Oid *ppEqOp,
56 const Oid *ffEqOp,
57 int foreignNKeys,
58 char foreignUpdateType,
59 char foreignDeleteType,
60 char foreignMatchType,
61 Oid indexRelId,
62 Node *conExpr,
63 const char *conBin,
64 const char *conSrc,
65 bool conIsLocal,
66 int conInhCount)
68 Relation conDesc;
69 Oid conOid;
70 HeapTuple tup;
71 char nulls[Natts_pg_constraint];
72 Datum values[Natts_pg_constraint];
73 ArrayType *conkeyArray;
74 ArrayType *confkeyArray;
75 ArrayType *conpfeqopArray;
76 ArrayType *conppeqopArray;
77 ArrayType *conffeqopArray;
78 NameData cname;
79 int i;
80 ObjectAddress conobject;
82 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
84 Assert(constraintName);
85 namestrcpy(&cname, constraintName);
88 * Convert C arrays into Postgres arrays.
90 if (constraintNKeys > 0)
92 Datum *conkey;
94 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
95 for (i = 0; i < constraintNKeys; i++)
96 conkey[i] = Int16GetDatum(constraintKey[i]);
97 conkeyArray = construct_array(conkey, constraintNKeys,
98 INT2OID, 2, true, 's');
100 else
101 conkeyArray = NULL;
103 if (foreignNKeys > 0)
105 Datum *fkdatums;
107 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
108 for (i = 0; i < foreignNKeys; i++)
109 fkdatums[i] = Int16GetDatum(foreignKey[i]);
110 confkeyArray = construct_array(fkdatums, foreignNKeys,
111 INT2OID, 2, true, 's');
112 for (i = 0; i < foreignNKeys; i++)
113 fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
114 conpfeqopArray = construct_array(fkdatums, foreignNKeys,
115 OIDOID, sizeof(Oid), true, 'i');
116 for (i = 0; i < foreignNKeys; i++)
117 fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
118 conppeqopArray = construct_array(fkdatums, foreignNKeys,
119 OIDOID, sizeof(Oid), true, 'i');
120 for (i = 0; i < foreignNKeys; i++)
121 fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
122 conffeqopArray = construct_array(fkdatums, foreignNKeys,
123 OIDOID, sizeof(Oid), true, 'i');
125 else
127 confkeyArray = NULL;
128 conpfeqopArray = NULL;
129 conppeqopArray = NULL;
130 conffeqopArray = NULL;
133 /* initialize nulls and values */
134 for (i = 0; i < Natts_pg_constraint; i++)
136 nulls[i] = ' ';
137 values[i] = (Datum) NULL;
140 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
141 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
142 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
143 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
144 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
145 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
146 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
147 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
148 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
149 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
150 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
151 values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
152 values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
154 if (conkeyArray)
155 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
156 else
157 nulls[Anum_pg_constraint_conkey - 1] = 'n';
159 if (confkeyArray)
160 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
161 else
162 nulls[Anum_pg_constraint_confkey - 1] = 'n';
164 if (conpfeqopArray)
165 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
166 else
167 nulls[Anum_pg_constraint_conpfeqop - 1] = 'n';
169 if (conppeqopArray)
170 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
171 else
172 nulls[Anum_pg_constraint_conppeqop - 1] = 'n';
174 if (conffeqopArray)
175 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
176 else
177 nulls[Anum_pg_constraint_conffeqop - 1] = 'n';
180 * initialize the binary form of the check constraint.
182 if (conBin)
183 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
184 else
185 nulls[Anum_pg_constraint_conbin - 1] = 'n';
188 * initialize the text form of the check constraint
190 if (conSrc)
191 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
192 else
193 nulls[Anum_pg_constraint_consrc - 1] = 'n';
195 tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
197 conOid = simple_heap_insert(conDesc, tup);
199 /* update catalog indexes */
200 CatalogUpdateIndexes(conDesc, tup);
202 conobject.classId = ConstraintRelationId;
203 conobject.objectId = conOid;
204 conobject.objectSubId = 0;
206 heap_close(conDesc, RowExclusiveLock);
208 if (OidIsValid(relId))
211 * Register auto dependency from constraint to owning relation, or to
212 * specific column(s) if any are mentioned.
214 ObjectAddress relobject;
216 relobject.classId = RelationRelationId;
217 relobject.objectId = relId;
218 if (constraintNKeys > 0)
220 for (i = 0; i < constraintNKeys; i++)
222 relobject.objectSubId = constraintKey[i];
224 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
227 else
229 relobject.objectSubId = 0;
231 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
235 if (OidIsValid(domainId))
238 * Register auto dependency from constraint to owning domain
240 ObjectAddress domobject;
242 domobject.classId = TypeRelationId;
243 domobject.objectId = domainId;
244 domobject.objectSubId = 0;
246 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
249 if (OidIsValid(foreignRelId))
252 * Register normal dependency from constraint to foreign relation, or
253 * to specific column(s) if any are mentioned.
255 ObjectAddress relobject;
257 relobject.classId = RelationRelationId;
258 relobject.objectId = foreignRelId;
259 if (foreignNKeys > 0)
261 for (i = 0; i < foreignNKeys; i++)
263 relobject.objectSubId = foreignKey[i];
265 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
268 else
270 relobject.objectSubId = 0;
272 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
276 if (OidIsValid(indexRelId))
279 * Register normal dependency on the unique index that supports a
280 * foreign-key constraint.
282 ObjectAddress relobject;
284 relobject.classId = RelationRelationId;
285 relobject.objectId = indexRelId;
286 relobject.objectSubId = 0;
288 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
291 if (foreignNKeys > 0)
294 * Register normal dependencies on the equality operators that support
295 * a foreign-key constraint. If the PK and FK types are the same then
296 * all three operators for a column are the same; otherwise they are
297 * different.
299 ObjectAddress oprobject;
301 oprobject.classId = OperatorRelationId;
302 oprobject.objectSubId = 0;
304 for (i = 0; i < foreignNKeys; i++)
306 oprobject.objectId = pfEqOp[i];
307 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
308 if (ppEqOp[i] != pfEqOp[i])
310 oprobject.objectId = ppEqOp[i];
311 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
313 if (ffEqOp[i] != pfEqOp[i])
315 oprobject.objectId = ffEqOp[i];
316 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
321 if (conExpr != NULL)
324 * Register dependencies from constraint to objects mentioned in CHECK
325 * expression.
327 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
328 DEPENDENCY_NORMAL,
329 DEPENDENCY_NORMAL);
332 return conOid;
337 * Test whether given name is currently used as a constraint name
338 * for the given object (relation or domain).
340 * This is used to decide whether to accept a user-specified constraint name.
341 * It is deliberately not the same test as ChooseConstraintName uses to decide
342 * whether an auto-generated name is OK: here, we will allow it unless there
343 * is an identical constraint name in use *on the same object*.
345 * NB: Caller should hold exclusive lock on the given object, else
346 * this test can be fooled by concurrent additions.
348 bool
349 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
350 Oid objNamespace, const char *conname)
352 bool found;
353 Relation conDesc;
354 SysScanDesc conscan;
355 ScanKeyData skey[2];
356 HeapTuple tup;
358 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
360 found = false;
362 ScanKeyInit(&skey[0],
363 Anum_pg_constraint_conname,
364 BTEqualStrategyNumber, F_NAMEEQ,
365 CStringGetDatum(conname));
367 ScanKeyInit(&skey[1],
368 Anum_pg_constraint_connamespace,
369 BTEqualStrategyNumber, F_OIDEQ,
370 ObjectIdGetDatum(objNamespace));
372 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
373 SnapshotNow, 2, skey);
375 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
377 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
379 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
381 found = true;
382 break;
384 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
386 found = true;
387 break;
391 systable_endscan(conscan);
392 heap_close(conDesc, AccessShareLock);
394 return found;
398 * Select a nonconflicting name for a new constraint.
400 * The objective here is to choose a name that is unique within the
401 * specified namespace. Postgres does not require this, but the SQL
402 * spec does, and some apps depend on it. Therefore we avoid choosing
403 * default names that so conflict.
405 * name1, name2, and label are used the same way as for makeObjectName(),
406 * except that the label can't be NULL; digits will be appended to the label
407 * if needed to create a name that is unique within the specified namespace.
409 * 'others' can be a list of string names already chosen within the current
410 * command (but not yet reflected into the catalogs); we will not choose
411 * a duplicate of one of these either.
413 * Note: it is theoretically possible to get a collision anyway, if someone
414 * else chooses the same name concurrently. This is fairly unlikely to be
415 * a problem in practice, especially if one is holding an exclusive lock on
416 * the relation identified by name1.
418 * Returns a palloc'd string.
420 char *
421 ChooseConstraintName(const char *name1, const char *name2,
422 const char *label, Oid namespace,
423 List *others)
425 int pass = 0;
426 char *conname = NULL;
427 char modlabel[NAMEDATALEN];
428 Relation conDesc;
429 SysScanDesc conscan;
430 ScanKeyData skey[2];
431 bool found;
432 ListCell *l;
434 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
436 /* try the unmodified label first */
437 StrNCpy(modlabel, label, sizeof(modlabel));
439 for (;;)
441 conname = makeObjectName(name1, name2, modlabel);
443 found = false;
445 foreach(l, others)
447 if (strcmp((char *) lfirst(l), conname) == 0)
449 found = true;
450 break;
454 if (!found)
456 ScanKeyInit(&skey[0],
457 Anum_pg_constraint_conname,
458 BTEqualStrategyNumber, F_NAMEEQ,
459 CStringGetDatum(conname));
461 ScanKeyInit(&skey[1],
462 Anum_pg_constraint_connamespace,
463 BTEqualStrategyNumber, F_OIDEQ,
464 ObjectIdGetDatum(namespace));
466 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
467 SnapshotNow, 2, skey);
469 found = (HeapTupleIsValid(systable_getnext(conscan)));
471 systable_endscan(conscan);
474 if (!found)
475 break;
477 /* found a conflict, so try a new name component */
478 pfree(conname);
479 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
482 heap_close(conDesc, AccessShareLock);
484 return conname;
488 * Delete a single constraint record.
490 void
491 RemoveConstraintById(Oid conId)
493 Relation conDesc;
494 HeapTuple tup;
495 Form_pg_constraint con;
497 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
499 tup = SearchSysCache(CONSTROID,
500 ObjectIdGetDatum(conId),
501 0, 0, 0);
502 if (!HeapTupleIsValid(tup)) /* should not happen */
503 elog(ERROR, "cache lookup failed for constraint %u", conId);
504 con = (Form_pg_constraint) GETSTRUCT(tup);
507 * Special processing depending on what the constraint is for.
509 if (OidIsValid(con->conrelid))
511 Relation rel;
514 * If the constraint is for a relation, open and exclusive-lock the
515 * relation it's for.
517 rel = heap_open(con->conrelid, AccessExclusiveLock);
520 * We need to update the relcheck count if it is a check constraint
521 * being dropped. This update will force backends to rebuild relcache
522 * entries when we commit.
524 if (con->contype == CONSTRAINT_CHECK)
526 Relation pgrel;
527 HeapTuple relTup;
528 Form_pg_class classForm;
530 pgrel = heap_open(RelationRelationId, RowExclusiveLock);
531 relTup = SearchSysCacheCopy(RELOID,
532 ObjectIdGetDatum(con->conrelid),
533 0, 0, 0);
534 if (!HeapTupleIsValid(relTup))
535 elog(ERROR, "cache lookup failed for relation %u",
536 con->conrelid);
537 classForm = (Form_pg_class) GETSTRUCT(relTup);
539 if (classForm->relchecks == 0) /* should not happen */
540 elog(ERROR, "relation \"%s\" has relchecks = 0",
541 RelationGetRelationName(rel));
542 classForm->relchecks--;
544 simple_heap_update(pgrel, &relTup->t_self, relTup);
546 CatalogUpdateIndexes(pgrel, relTup);
548 heap_freetuple(relTup);
550 heap_close(pgrel, RowExclusiveLock);
553 /* Keep lock on constraint's rel until end of xact */
554 heap_close(rel, NoLock);
556 else if (OidIsValid(con->contypid))
559 * XXX for now, do nothing special when dropping a domain constraint
561 * Probably there should be some form of locking on the domain type,
562 * but we have no such concept at the moment.
565 else
566 elog(ERROR, "constraint %u is not of a known type", conId);
568 /* Fry the constraint itself */
569 simple_heap_delete(conDesc, &tup->t_self);
571 /* Clean up */
572 ReleaseSysCache(tup);
573 heap_close(conDesc, RowExclusiveLock);
577 * RenameConstraintById
578 * Rename a constraint.
580 * Note: this isn't intended to be a user-exposed function; it doesn't check
581 * permissions etc. Currently this is only invoked when renaming an index
582 * that is associated with a constraint, but it's made a little more general
583 * than that with the expectation of someday having ALTER TABLE RENAME
584 * CONSTRAINT.
586 void
587 RenameConstraintById(Oid conId, const char *newname)
589 Relation conDesc;
590 HeapTuple tuple;
591 Form_pg_constraint con;
593 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
595 tuple = SearchSysCacheCopy(CONSTROID,
596 ObjectIdGetDatum(conId),
597 0, 0, 0);
598 if (!HeapTupleIsValid(tuple))
599 elog(ERROR, "cache lookup failed for constraint %u", conId);
600 con = (Form_pg_constraint) GETSTRUCT(tuple);
603 * We need to check whether the name is already in use --- note that
604 * there currently is not a unique index that would catch this.
606 if (OidIsValid(con->conrelid) &&
607 ConstraintNameIsUsed(CONSTRAINT_RELATION,
608 con->conrelid,
609 con->connamespace,
610 newname))
611 ereport(ERROR,
612 (errcode(ERRCODE_DUPLICATE_OBJECT),
613 errmsg("constraint \"%s\" for relation \"%s\" already exists",
614 newname, get_rel_name(con->conrelid))));
615 if (OidIsValid(con->contypid) &&
616 ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
617 con->contypid,
618 con->connamespace,
619 newname))
620 ereport(ERROR,
621 (errcode(ERRCODE_DUPLICATE_OBJECT),
622 errmsg("constraint \"%s\" for domain \"%s\" already exists",
623 newname, format_type_be(con->contypid))));
625 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
626 namestrcpy(&(con->conname), newname);
628 simple_heap_update(conDesc, &tuple->t_self, tuple);
630 /* update the system catalog indexes */
631 CatalogUpdateIndexes(conDesc, tuple);
633 heap_freetuple(tuple);
634 heap_close(conDesc, RowExclusiveLock);
638 * AlterConstraintNamespaces
639 * Find any constraints belonging to the specified object,
640 * and move them to the specified new namespace.
642 * isType indicates whether the owning object is a type or a relation.
644 void
645 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
646 Oid newNspId, bool isType)
648 Relation conRel;
649 ScanKeyData key[1];
650 SysScanDesc scan;
651 HeapTuple tup;
653 conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
655 if (isType)
657 ScanKeyInit(&key[0],
658 Anum_pg_constraint_contypid,
659 BTEqualStrategyNumber, F_OIDEQ,
660 ObjectIdGetDatum(ownerId));
662 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
663 SnapshotNow, 1, key);
665 else
667 ScanKeyInit(&key[0],
668 Anum_pg_constraint_conrelid,
669 BTEqualStrategyNumber, F_OIDEQ,
670 ObjectIdGetDatum(ownerId));
672 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
673 SnapshotNow, 1, key);
676 while (HeapTupleIsValid((tup = systable_getnext(scan))))
678 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
680 if (conform->connamespace == oldNspId)
682 tup = heap_copytuple(tup);
683 conform = (Form_pg_constraint) GETSTRUCT(tup);
685 conform->connamespace = newNspId;
687 simple_heap_update(conRel, &tup->t_self, tup);
688 CatalogUpdateIndexes(conRel, tup);
691 * Note: currently, the constraint will not have its own
692 * dependency on the namespace, so we don't need to do
693 * changeDependencyFor().
698 systable_endscan(scan);
700 heap_close(conRel, RowExclusiveLock);