1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2004, 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.21 2004/08/29 04:12:28 momjian 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_type.h"
25 #include "commands/defrem.h"
26 #include "miscadmin.h"
27 #include "utils/array.h"
28 #include "utils/builtins.h"
29 #include "utils/fmgroids.h"
30 #include "utils/syscache.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,
54 char foreignUpdateType,
55 char foreignDeleteType,
56 char foreignMatchType,
65 char nulls[Natts_pg_constraint];
66 Datum values[Natts_pg_constraint];
67 ArrayType *conkeyArray;
68 ArrayType *confkeyArray;
71 ObjectAddress conobject;
73 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
75 Assert(constraintName);
76 namestrcpy(&cname, constraintName);
79 * Convert C arrays into Postgres arrays.
81 if (constraintNKeys > 0)
85 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
86 for (i = 0; i < constraintNKeys; i++)
87 conkey[i] = Int16GetDatum(constraintKey[i]);
88 conkeyArray = construct_array(conkey, constraintNKeys,
89 INT2OID, 2, true, 's');
98 confkey = (Datum *) palloc(foreignNKeys * sizeof(Datum));
99 for (i = 0; i < foreignNKeys; i++)
100 confkey[i] = Int16GetDatum(foreignKey[i]);
101 confkeyArray = construct_array(confkey, foreignNKeys,
102 INT2OID, 2, true, 's');
107 /* initialize nulls and values */
108 for (i = 0; i < Natts_pg_constraint; i++)
111 values[i] = (Datum) NULL;
114 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
115 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
116 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
117 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
118 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
119 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
120 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
121 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
122 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
123 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
124 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
127 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
129 nulls[Anum_pg_constraint_conkey - 1] = 'n';
132 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
134 nulls[Anum_pg_constraint_confkey - 1] = 'n';
137 * initialize the binary form of the check constraint.
140 values[Anum_pg_constraint_conbin - 1] = DirectFunctionCall1(textin,
141 CStringGetDatum(conBin));
143 nulls[Anum_pg_constraint_conbin - 1] = 'n';
146 * initialize the text form of the check constraint
149 values[Anum_pg_constraint_consrc - 1] = DirectFunctionCall1(textin,
150 CStringGetDatum(conSrc));
152 nulls[Anum_pg_constraint_consrc - 1] = 'n';
154 tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
156 conOid = simple_heap_insert(conDesc, tup);
158 /* update catalog indexes */
159 CatalogUpdateIndexes(conDesc, tup);
161 conobject.classId = RelationGetRelid(conDesc);
162 conobject.objectId = conOid;
163 conobject.objectSubId = 0;
165 heap_close(conDesc, RowExclusiveLock);
167 if (OidIsValid(relId))
170 * Register auto dependency from constraint to owning relation, or
171 * to specific column(s) if any are mentioned.
173 ObjectAddress relobject;
175 relobject.classId = RelOid_pg_class;
176 relobject.objectId = relId;
177 if (constraintNKeys > 0)
179 for (i = 0; i < constraintNKeys; i++)
181 relobject.objectSubId = constraintKey[i];
183 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
188 relobject.objectSubId = 0;
190 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
194 if (OidIsValid(domainId))
197 * Register auto dependency from constraint to owning domain
199 ObjectAddress domobject;
201 domobject.classId = RelOid_pg_type;
202 domobject.objectId = domainId;
203 domobject.objectSubId = 0;
205 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
208 if (OidIsValid(foreignRelId))
211 * Register normal dependency from constraint to foreign relation,
212 * or to specific column(s) if any are mentioned.
214 ObjectAddress relobject;
216 relobject.classId = RelOid_pg_class;
217 relobject.objectId = foreignRelId;
218 if (foreignNKeys > 0)
220 for (i = 0; i < foreignNKeys; i++)
222 relobject.objectSubId = foreignKey[i];
224 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
229 relobject.objectSubId = 0;
231 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
235 if (OidIsValid(indexRelId))
238 * Register normal dependency on the unique index that supports a
239 * foreign-key constraint.
241 ObjectAddress relobject;
243 relobject.classId = RelOid_pg_class;
244 relobject.objectId = indexRelId;
245 relobject.objectSubId = 0;
247 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
253 * Register dependencies from constraint to objects mentioned in
256 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
266 * Test whether given name is currently used as a constraint name
267 * for the given object (relation or domain).
269 * This is used to decide whether to accept a user-specified constraint name.
270 * It is deliberately not the same test as ChooseConstraintName uses to decide
271 * whether an auto-generated name is OK: here, we will allow it unless there
272 * is an identical constraint name in use *on the same object*.
274 * NB: Caller should hold exclusive lock on the given object, else
275 * this test can be fooled by concurrent additions.
278 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
279 Oid objNamespace, const char *conname)
287 conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
291 ScanKeyInit(&skey[0],
292 Anum_pg_constraint_conname,
293 BTEqualStrategyNumber, F_NAMEEQ,
294 CStringGetDatum(conname));
296 ScanKeyInit(&skey[1],
297 Anum_pg_constraint_connamespace,
298 BTEqualStrategyNumber, F_OIDEQ,
299 ObjectIdGetDatum(objNamespace));
301 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
302 SnapshotNow, 2, skey);
304 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
306 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
308 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
313 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
320 systable_endscan(conscan);
321 heap_close(conDesc, AccessShareLock);
327 * Select a nonconflicting name for a new constraint.
329 * The objective here is to choose a name that is unique within the
330 * specified namespace. Postgres does not require this, but the SQL
331 * spec does, and some apps depend on it. Therefore we avoid choosing
332 * default names that so conflict.
334 * name1, name2, and label are used the same way as for makeObjectName(),
335 * except that the label can't be NULL; digits will be appended to the label
336 * if needed to create a name that is unique within the specified namespace.
338 * 'others' can be a list of string names already chosen within the current
339 * command (but not yet reflected into the catalogs); we will not choose
340 * a duplicate of one of these either.
342 * Note: it is theoretically possible to get a collision anyway, if someone
343 * else chooses the same name concurrently. This is fairly unlikely to be
344 * a problem in practice, especially if one is holding an exclusive lock on
345 * the relation identified by name1.
347 * Returns a palloc'd string.
350 ChooseConstraintName(const char *name1, const char *name2,
351 const char *label, Oid namespace,
355 char *conname = NULL;
356 char modlabel[NAMEDATALEN];
363 conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
365 /* try the unmodified label first */
366 StrNCpy(modlabel, label, sizeof(modlabel));
370 conname = makeObjectName(name1, name2, modlabel);
376 if (strcmp((char *) lfirst(l), conname) == 0)
385 ScanKeyInit(&skey[0],
386 Anum_pg_constraint_conname,
387 BTEqualStrategyNumber, F_NAMEEQ,
388 CStringGetDatum(conname));
390 ScanKeyInit(&skey[1],
391 Anum_pg_constraint_connamespace,
392 BTEqualStrategyNumber, F_OIDEQ,
393 ObjectIdGetDatum(namespace));
395 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
396 SnapshotNow, 2, skey);
398 found = (HeapTupleIsValid(systable_getnext(conscan)));
400 systable_endscan(conscan);
406 /* found a conflict, so try a new name component */
408 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
411 heap_close(conDesc, AccessShareLock);
417 * Delete a single constraint record.
420 RemoveConstraintById(Oid conId)
426 Form_pg_constraint con;
428 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
430 ScanKeyInit(&skey[0],
431 ObjectIdAttributeNumber,
432 BTEqualStrategyNumber, F_OIDEQ,
433 ObjectIdGetDatum(conId));
435 conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
436 SnapshotNow, 1, skey);
438 tup = systable_getnext(conscan);
439 if (!HeapTupleIsValid(tup))
440 elog(ERROR, "could not find tuple for constraint %u", conId);
441 con = (Form_pg_constraint) GETSTRUCT(tup);
444 * Special processing depending on what the constraint is for.
446 if (OidIsValid(con->conrelid))
451 * If the constraint is for a relation, open and exclusive-lock
452 * the relation it's for.
454 rel = heap_open(con->conrelid, AccessExclusiveLock);
457 * We need to update the relcheck count if it is a check
458 * constraint being dropped. This update will force backends to
459 * rebuild relcache entries when we commit.
461 if (con->contype == CONSTRAINT_CHECK)
465 Form_pg_class classForm;
467 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
468 relTup = SearchSysCacheCopy(RELOID,
469 ObjectIdGetDatum(con->conrelid),
471 if (!HeapTupleIsValid(relTup))
472 elog(ERROR, "cache lookup failed for relation %u",
474 classForm = (Form_pg_class) GETSTRUCT(relTup);
476 if (classForm->relchecks == 0) /* should not happen */
477 elog(ERROR, "relation \"%s\" has relchecks = 0",
478 RelationGetRelationName(rel));
479 classForm->relchecks--;
481 simple_heap_update(pgrel, &relTup->t_self, relTup);
483 CatalogUpdateIndexes(pgrel, relTup);
485 heap_freetuple(relTup);
487 heap_close(pgrel, RowExclusiveLock);
490 /* Keep lock on constraint's rel until end of xact */
491 heap_close(rel, NoLock);
493 else if (OidIsValid(con->contypid))
496 * XXX for now, do nothing special when dropping a domain
499 * Probably there should be some form of locking on the domain type,
500 * but we have no such concept at the moment.
504 elog(ERROR, "constraint %u is not of a known type", conId);
506 /* Fry the constraint itself */
507 simple_heap_delete(conDesc, &tup->t_self);
510 systable_endscan(conscan);
511 heap_close(conDesc, RowExclusiveLock);