OSDN Git Service

First phase of project to use fixed OIDs for all system catalogs and
[pg-rex/syncrep.git] / src / backend / catalog / pg_constraint.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_constraint.c
4  *        routines to support manipulation of the pg_constraint relation
5  *
6  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.24 2005/04/14 01:38:16 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
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_depend.h"
25 #include "catalog/pg_type.h"
26 #include "commands/defrem.h"
27 #include "miscadmin.h"
28 #include "utils/array.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/lsyscache.h"
32 #include "utils/syscache.h"
33
34
35 /*
36  * CreateConstraintEntry
37  *      Create a constraint table entry.
38  *
39  * Subsidiary records (such as triggers or indexes to implement the
40  * constraint) are *not* created here.  But we do make dependency links
41  * from the constraint to the things it depends on.
42  */
43 Oid
44 CreateConstraintEntry(const char *constraintName,
45                                           Oid constraintNamespace,
46                                           char constraintType,
47                                           bool isDeferrable,
48                                           bool isDeferred,
49                                           Oid relId,
50                                           const int16 *constraintKey,
51                                           int constraintNKeys,
52                                           Oid domainId,
53                                           Oid foreignRelId,
54                                           const int16 *foreignKey,
55                                           int foreignNKeys,
56                                           char foreignUpdateType,
57                                           char foreignDeleteType,
58                                           char foreignMatchType,
59                                           Oid indexRelId,
60                                           Node *conExpr,
61                                           const char *conBin,
62                                           const char *conSrc)
63 {
64         Relation        conDesc;
65         Oid                     conOid;
66         HeapTuple       tup;
67         char            nulls[Natts_pg_constraint];
68         Datum           values[Natts_pg_constraint];
69         ArrayType  *conkeyArray;
70         ArrayType  *confkeyArray;
71         NameData        cname;
72         int                     i;
73         ObjectAddress conobject;
74
75         conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
76
77         Assert(constraintName);
78         namestrcpy(&cname, constraintName);
79
80         /*
81          * Convert C arrays into Postgres arrays.
82          */
83         if (constraintNKeys > 0)
84         {
85                 Datum      *conkey;
86
87                 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
88                 for (i = 0; i < constraintNKeys; i++)
89                         conkey[i] = Int16GetDatum(constraintKey[i]);
90                 conkeyArray = construct_array(conkey, constraintNKeys,
91                                                                           INT2OID, 2, true, 's');
92         }
93         else
94                 conkeyArray = NULL;
95
96         if (foreignNKeys > 0)
97         {
98                 Datum      *confkey;
99
100                 confkey = (Datum *) palloc(foreignNKeys * sizeof(Datum));
101                 for (i = 0; i < foreignNKeys; i++)
102                         confkey[i] = Int16GetDatum(foreignKey[i]);
103                 confkeyArray = construct_array(confkey, foreignNKeys,
104                                                                            INT2OID, 2, true, 's');
105         }
106         else
107                 confkeyArray = NULL;
108
109         /* initialize nulls and values */
110         for (i = 0; i < Natts_pg_constraint; i++)
111         {
112                 nulls[i] = ' ';
113                 values[i] = (Datum) NULL;
114         }
115
116         values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
117         values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
118         values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
119         values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
120         values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
121         values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
122         values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
123         values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
124         values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
125         values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
126         values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
127
128         if (conkeyArray)
129                 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
130         else
131                 nulls[Anum_pg_constraint_conkey - 1] = 'n';
132
133         if (confkeyArray)
134                 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
135         else
136                 nulls[Anum_pg_constraint_confkey - 1] = 'n';
137
138         /*
139          * initialize the binary form of the check constraint.
140          */
141         if (conBin)
142                 values[Anum_pg_constraint_conbin - 1] = DirectFunctionCall1(textin,
143                                                                                                 CStringGetDatum(conBin));
144         else
145                 nulls[Anum_pg_constraint_conbin - 1] = 'n';
146
147         /*
148          * initialize the text form of the check constraint
149          */
150         if (conSrc)
151                 values[Anum_pg_constraint_consrc - 1] = DirectFunctionCall1(textin,
152                                                                                                 CStringGetDatum(conSrc));
153         else
154                 nulls[Anum_pg_constraint_consrc - 1] = 'n';
155
156         tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
157
158         conOid = simple_heap_insert(conDesc, tup);
159
160         /* update catalog indexes */
161         CatalogUpdateIndexes(conDesc, tup);
162
163         conobject.classId = RelationGetRelid(conDesc);
164         conobject.objectId = conOid;
165         conobject.objectSubId = 0;
166
167         heap_close(conDesc, RowExclusiveLock);
168
169         if (OidIsValid(relId))
170         {
171                 /*
172                  * Register auto dependency from constraint to owning relation, or
173                  * to specific column(s) if any are mentioned.
174                  */
175                 ObjectAddress relobject;
176
177                 relobject.classId = RelationRelationId;
178                 relobject.objectId = relId;
179                 if (constraintNKeys > 0)
180                 {
181                         for (i = 0; i < constraintNKeys; i++)
182                         {
183                                 relobject.objectSubId = constraintKey[i];
184
185                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
186                         }
187                 }
188                 else
189                 {
190                         relobject.objectSubId = 0;
191
192                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
193                 }
194         }
195
196         if (OidIsValid(domainId))
197         {
198                 /*
199                  * Register auto dependency from constraint to owning domain
200                  */
201                 ObjectAddress domobject;
202
203                 domobject.classId = TypeRelationId;
204                 domobject.objectId = domainId;
205                 domobject.objectSubId = 0;
206
207                 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
208         }
209
210         if (OidIsValid(foreignRelId))
211         {
212                 /*
213                  * Register normal dependency from constraint to foreign relation,
214                  * or to specific column(s) if any are mentioned.
215                  */
216                 ObjectAddress relobject;
217
218                 relobject.classId = RelationRelationId;
219                 relobject.objectId = foreignRelId;
220                 if (foreignNKeys > 0)
221                 {
222                         for (i = 0; i < foreignNKeys; i++)
223                         {
224                                 relobject.objectSubId = foreignKey[i];
225
226                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
227                         }
228                 }
229                 else
230                 {
231                         relobject.objectSubId = 0;
232
233                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
234                 }
235         }
236
237         if (OidIsValid(indexRelId))
238         {
239                 /*
240                  * Register normal dependency on the unique index that supports a
241                  * foreign-key constraint.
242                  */
243                 ObjectAddress relobject;
244
245                 relobject.classId = RelationRelationId;
246                 relobject.objectId = indexRelId;
247                 relobject.objectSubId = 0;
248
249                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
250         }
251
252         if (conExpr != NULL)
253         {
254                 /*
255                  * Register dependencies from constraint to objects mentioned in
256                  * CHECK expression.
257                  */
258                 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
259                                                                                 DEPENDENCY_NORMAL,
260                                                                                 DEPENDENCY_NORMAL);
261         }
262
263         return conOid;
264 }
265
266
267 /*
268  * Test whether given name is currently used as a constraint name
269  * for the given object (relation or domain).
270  *
271  * This is used to decide whether to accept a user-specified constraint name.
272  * It is deliberately not the same test as ChooseConstraintName uses to decide
273  * whether an auto-generated name is OK: here, we will allow it unless there
274  * is an identical constraint name in use *on the same object*.
275  *
276  * NB: Caller should hold exclusive lock on the given object, else
277  * this test can be fooled by concurrent additions.
278  */
279 bool
280 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
281                                          Oid objNamespace, const char *conname)
282 {
283         bool            found;
284         Relation        conDesc;
285         SysScanDesc conscan;
286         ScanKeyData skey[2];
287         HeapTuple       tup;
288
289         conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
290
291         found = false;
292
293         ScanKeyInit(&skey[0],
294                                 Anum_pg_constraint_conname,
295                                 BTEqualStrategyNumber, F_NAMEEQ,
296                                 CStringGetDatum(conname));
297
298         ScanKeyInit(&skey[1],
299                                 Anum_pg_constraint_connamespace,
300                                 BTEqualStrategyNumber, F_OIDEQ,
301                                 ObjectIdGetDatum(objNamespace));
302
303         conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
304                                                                  SnapshotNow, 2, skey);
305
306         while (HeapTupleIsValid(tup = systable_getnext(conscan)))
307         {
308                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
309
310                 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
311                 {
312                         found = true;
313                         break;
314                 }
315                 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
316                 {
317                         found = true;
318                         break;
319                 }
320         }
321
322         systable_endscan(conscan);
323         heap_close(conDesc, AccessShareLock);
324
325         return found;
326 }
327
328 /*
329  * Select a nonconflicting name for a new constraint.
330  *
331  * The objective here is to choose a name that is unique within the
332  * specified namespace.  Postgres does not require this, but the SQL
333  * spec does, and some apps depend on it.  Therefore we avoid choosing
334  * default names that so conflict.
335  *
336  * name1, name2, and label are used the same way as for makeObjectName(),
337  * except that the label can't be NULL; digits will be appended to the label
338  * if needed to create a name that is unique within the specified namespace.
339  *
340  * 'others' can be a list of string names already chosen within the current
341  * command (but not yet reflected into the catalogs); we will not choose
342  * a duplicate of one of these either.
343  *
344  * Note: it is theoretically possible to get a collision anyway, if someone
345  * else chooses the same name concurrently.  This is fairly unlikely to be
346  * a problem in practice, especially if one is holding an exclusive lock on
347  * the relation identified by name1.
348  *
349  * Returns a palloc'd string.
350  */
351 char *
352 ChooseConstraintName(const char *name1, const char *name2,
353                                          const char *label, Oid namespace,
354                                          List *others)
355 {
356         int                     pass = 0;
357         char       *conname = NULL;
358         char            modlabel[NAMEDATALEN];
359         Relation        conDesc;
360         SysScanDesc conscan;
361         ScanKeyData skey[2];
362         bool            found;
363         ListCell   *l;
364
365         conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
366
367         /* try the unmodified label first */
368         StrNCpy(modlabel, label, sizeof(modlabel));
369
370         for (;;)
371         {
372                 conname = makeObjectName(name1, name2, modlabel);
373
374                 found = false;
375
376                 foreach(l, others)
377                 {
378                         if (strcmp((char *) lfirst(l), conname) == 0)
379                         {
380                                 found = true;
381                                 break;
382                         }
383                 }
384
385                 if (!found)
386                 {
387                         ScanKeyInit(&skey[0],
388                                                 Anum_pg_constraint_conname,
389                                                 BTEqualStrategyNumber, F_NAMEEQ,
390                                                 CStringGetDatum(conname));
391
392                         ScanKeyInit(&skey[1],
393                                                 Anum_pg_constraint_connamespace,
394                                                 BTEqualStrategyNumber, F_OIDEQ,
395                                                 ObjectIdGetDatum(namespace));
396
397                         conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
398                                                                                  SnapshotNow, 2, skey);
399
400                         found = (HeapTupleIsValid(systable_getnext(conscan)));
401
402                         systable_endscan(conscan);
403                 }
404
405                 if (!found)
406                         break;
407
408                 /* found a conflict, so try a new name component */
409                 pfree(conname);
410                 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
411         }
412
413         heap_close(conDesc, AccessShareLock);
414
415         return conname;
416 }
417
418 /*
419  * Delete a single constraint record.
420  */
421 void
422 RemoveConstraintById(Oid conId)
423 {
424         Relation        conDesc;
425         ScanKeyData skey[1];
426         SysScanDesc conscan;
427         HeapTuple       tup;
428         Form_pg_constraint con;
429
430         conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
431
432         ScanKeyInit(&skey[0],
433                                 ObjectIdAttributeNumber,
434                                 BTEqualStrategyNumber, F_OIDEQ,
435                                 ObjectIdGetDatum(conId));
436
437         conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
438                                                                  SnapshotNow, 1, skey);
439
440         tup = systable_getnext(conscan);
441         if (!HeapTupleIsValid(tup))
442                 elog(ERROR, "could not find tuple for constraint %u", conId);
443         con = (Form_pg_constraint) GETSTRUCT(tup);
444
445         /*
446          * Special processing depending on what the constraint is for.
447          */
448         if (OidIsValid(con->conrelid))
449         {
450                 Relation        rel;
451
452                 /*
453                  * If the constraint is for a relation, open and exclusive-lock
454                  * the relation it's for.
455                  */
456                 rel = heap_open(con->conrelid, AccessExclusiveLock);
457
458                 /*
459                  * We need to update the relcheck count if it is a check
460                  * constraint being dropped.  This update will force backends to
461                  * rebuild relcache entries when we commit.
462                  */
463                 if (con->contype == CONSTRAINT_CHECK)
464                 {
465                         Relation        pgrel;
466                         HeapTuple       relTup;
467                         Form_pg_class classForm;
468
469                         pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
470                         relTup = SearchSysCacheCopy(RELOID,
471                                                                                 ObjectIdGetDatum(con->conrelid),
472                                                                                 0, 0, 0);
473                         if (!HeapTupleIsValid(relTup))
474                                 elog(ERROR, "cache lookup failed for relation %u",
475                                          con->conrelid);
476                         classForm = (Form_pg_class) GETSTRUCT(relTup);
477
478                         if (classForm->relchecks == 0)          /* should not happen */
479                                 elog(ERROR, "relation \"%s\" has relchecks = 0",
480                                          RelationGetRelationName(rel));
481                         classForm->relchecks--;
482
483                         simple_heap_update(pgrel, &relTup->t_self, relTup);
484
485                         CatalogUpdateIndexes(pgrel, relTup);
486
487                         heap_freetuple(relTup);
488
489                         heap_close(pgrel, RowExclusiveLock);
490                 }
491
492                 /* Keep lock on constraint's rel until end of xact */
493                 heap_close(rel, NoLock);
494         }
495         else if (OidIsValid(con->contypid))
496         {
497                 /*
498                  * XXX for now, do nothing special when dropping a domain
499                  * constraint
500                  *
501                  * Probably there should be some form of locking on the domain type,
502                  * but we have no such concept at the moment.
503                  */
504         }
505         else
506                 elog(ERROR, "constraint %u is not of a known type", conId);
507
508         /* Fry the constraint itself */
509         simple_heap_delete(conDesc, &tup->t_self);
510
511         /* Clean up */
512         systable_endscan(conscan);
513         heap_close(conDesc, RowExclusiveLock);
514 }
515
516 /*
517  * GetConstraintNameForTrigger
518  *              Get the name of the constraint owning a trigger, if any
519  *
520  * Returns a palloc'd string, or NULL if no constraint can be found
521  */
522 char *
523 GetConstraintNameForTrigger(Oid triggerId)
524 {
525         char       *result;
526         Oid                     constraintId = InvalidOid;
527         Oid                     pg_trigger_id;
528         Oid                     pg_constraint_id;
529         Relation        depRel;
530         Relation        conRel;
531         ScanKeyData key[2];
532         SysScanDesc scan;
533         HeapTuple       tup;
534
535         pg_trigger_id = get_system_catalog_relid(TriggerRelationName);
536         pg_constraint_id = get_system_catalog_relid(ConstraintRelationName);
537
538         /*
539          * We must grovel through pg_depend to find the owning constraint.
540          * Perhaps pg_trigger should have a column for the owning constraint ...
541          * but right now this is not performance-critical code.
542          */
543         depRel = heap_openr(DependRelationName, AccessShareLock);
544
545         ScanKeyInit(&key[0],
546                                 Anum_pg_depend_classid,
547                                 BTEqualStrategyNumber, F_OIDEQ,
548                                 ObjectIdGetDatum(pg_trigger_id));
549         ScanKeyInit(&key[1],
550                                 Anum_pg_depend_objid,
551                                 BTEqualStrategyNumber, F_OIDEQ,
552                                 ObjectIdGetDatum(triggerId));
553         /* assume we can ignore objsubid for a trigger */
554
555         scan = systable_beginscan(depRel, DependDependerIndex, true,
556                                                           SnapshotNow, 2, key);
557
558         while (HeapTupleIsValid(tup = systable_getnext(scan)))
559         {
560                 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
561
562                 if (foundDep->refclassid == pg_constraint_id &&
563                         foundDep->deptype == DEPENDENCY_INTERNAL)
564                 {
565                         constraintId = foundDep->refobjid;
566                         break;
567                 }
568         }
569
570         systable_endscan(scan);
571
572         heap_close(depRel, AccessShareLock);
573
574         if (!OidIsValid(constraintId))
575                 return NULL;                            /* no owning constraint found */
576
577         conRel = heap_openr(ConstraintRelationName, AccessShareLock);
578
579         ScanKeyInit(&key[0],
580                                 ObjectIdAttributeNumber,
581                                 BTEqualStrategyNumber, F_OIDEQ,
582                                 ObjectIdGetDatum(constraintId));
583
584         scan = systable_beginscan(conRel, ConstraintOidIndex, true,
585                                                           SnapshotNow, 1, key);
586
587         tup = systable_getnext(scan);
588
589         if (HeapTupleIsValid(tup))
590         {
591                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
592
593                 result = pstrdup(NameStr(con->conname));
594         }
595         else
596         {
597                 /* This arguably should be an error, but we'll just return NULL */
598                 result = NULL;
599         }
600
601         systable_endscan(scan);
602
603         heap_close(conRel, AccessShareLock);
604
605         return result;
606 }