1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.12 2002/12/12 20:35:11 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_type.h"
25 #include "miscadmin.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_openr(ConstraintRelationName, 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 = RelationGetRelid(conDesc);
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
170 * to specific column(s) if any are mentioned.
172 ObjectAddress relobject;
174 relobject.classId = RelOid_pg_class;
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 = RelOid_pg_type;
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,
211 * or to specific column(s) if any are mentioned.
213 ObjectAddress relobject;
215 relobject.classId = RelOid_pg_class;
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
238 * a foreign-key constraint.
240 ObjectAddress relobject;
242 relobject.classId = RelOid_pg_class;
243 relobject.objectId = indexRelId;
244 relobject.objectSubId = 0;
246 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
252 * Register dependencies from constraint to objects mentioned in
253 * CHECK expression. We gin up a rather bogus rangetable list to
254 * handle any Vars in the constraint.
258 MemSet(&rte, 0, sizeof(rte));
259 rte.type = T_RangeTblEntry;
260 rte.rtekind = RTE_RELATION;
263 recordDependencyOnExpr(&conobject, conExpr, makeList1(&rte),
272 * Test whether given name is currently used as a constraint name
273 * for the given relation.
275 * NB: Caller should hold exclusive lock on the given relation, else
276 * this test is not very meaningful.
279 ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, const char *cname)
287 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
291 ScanKeyEntryInitialize(&skey[0], 0x0,
292 Anum_pg_constraint_conname, F_NAMEEQ,
293 CStringGetDatum(cname));
295 ScanKeyEntryInitialize(&skey[1], 0x0,
296 Anum_pg_constraint_connamespace, F_OIDEQ,
297 ObjectIdGetDatum(objNamespace));
299 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
300 SnapshotNow, 2, skey);
302 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
304 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
306 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
311 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
318 systable_endscan(conscan);
319 heap_close(conDesc, RowExclusiveLock);
325 * Generate a currently-unused constraint name for the given relation.
327 * The passed counter should be initialized to 0 the first time through.
328 * If multiple constraint names are to be generated in a single command,
329 * pass the new counter value to each successive call, else the same
330 * name will be generated each time.
332 * NB: Caller should hold exclusive lock on the given relation, else
333 * someone else might choose the same name concurrently!
336 GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, int *counter)
342 cname = (char *) palloc(NAMEDATALEN * sizeof(char));
344 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
346 /* Loop until we find a non-conflicting constraint name */
347 /* We assume there will be one eventually ... */
355 snprintf(cname, NAMEDATALEN, "$%d", *counter);
358 * This duplicates ConstraintNameIsUsed() so that we can avoid
359 * re-opening pg_constraint for each iteration.
363 ScanKeyEntryInitialize(&skey[0], 0x0,
364 Anum_pg_constraint_conname, F_NAMEEQ,
365 CStringGetDatum(cname));
367 ScanKeyEntryInitialize(&skey[1], 0x0,
368 Anum_pg_constraint_connamespace, F_OIDEQ,
369 ObjectIdGetDatum(objNamespace));
371 conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, 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);
393 heap_close(conDesc, RowExclusiveLock);
399 * Does the given name look like a generated constraint name?
401 * This is a test on the form of the name, *not* on whether it has
402 * actually been assigned.
405 ConstraintNameIsGenerated(const char *cname)
409 if (strspn(cname + 1, "0123456789") != strlen(cname + 1))
415 * Delete a single constraint record.
418 RemoveConstraintById(Oid conId)
424 Form_pg_constraint con;
426 conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
428 ScanKeyEntryInitialize(&skey[0], 0x0,
429 ObjectIdAttributeNumber, F_OIDEQ,
430 ObjectIdGetDatum(conId));
432 conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
433 SnapshotNow, 1, skey);
435 tup = systable_getnext(conscan);
436 if (!HeapTupleIsValid(tup))
437 elog(ERROR, "RemoveConstraintById: constraint %u not found",
439 con = (Form_pg_constraint) GETSTRUCT(tup);
442 * Special processing depending on what the constraint is for.
444 if (OidIsValid(con->conrelid))
449 * If the constraint is for a relation, open and exclusive-lock the
452 rel = heap_open(con->conrelid, AccessExclusiveLock);
455 * We need to update the relcheck count if it is a check
456 * constraint being dropped. This update will force backends to
457 * rebuild relcache entries when we commit.
459 if (con->contype == CONSTRAINT_CHECK)
463 Form_pg_class classForm;
465 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
466 relTup = SearchSysCacheCopy(RELOID,
467 ObjectIdGetDatum(con->conrelid),
469 if (!HeapTupleIsValid(relTup))
470 elog(ERROR, "cache lookup of relation %u failed",
472 classForm = (Form_pg_class) GETSTRUCT(relTup);
474 if (classForm->relchecks == 0)
475 elog(ERROR, "RemoveConstraintById: relation %s has relchecks = 0",
476 RelationGetRelationName(rel));
477 classForm->relchecks--;
479 simple_heap_update(pgrel, &relTup->t_self, relTup);
481 CatalogUpdateIndexes(pgrel, relTup);
483 heap_freetuple(relTup);
485 heap_close(pgrel, RowExclusiveLock);
488 /* Keep lock on constraint's rel until end of xact */
489 heap_close(rel, NoLock);
491 else if (OidIsValid(con->contypid))
494 * XXX for now, do nothing special when dropping a domain constraint
496 * Probably there should be some form of locking on the domain type,
497 * but we have no such concept at the moment.
502 elog(ERROR, "RemoveConstraintById: Constraint %u is not a known type",
506 /* Fry the constraint itself */
507 simple_heap_delete(conDesc, &tup->t_self);
510 systable_endscan(conscan);
511 heap_close(conDesc, RowExclusiveLock);