]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_constraint.c
Update copyright for 2014
[postgresql] / 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-2014, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/catalog/pg_constraint.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/htup_details.h"
20 #include "catalog/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/objectaccess.h"
23 #include "catalog/pg_constraint.h"
24 #include "catalog/pg_operator.h"
25 #include "catalog/pg_type.h"
26 #include "commands/defrem.h"
27 #include "utils/array.h"
28 #include "utils/builtins.h"
29 #include "utils/fmgroids.h"
30 #include "utils/lsyscache.h"
31 #include "utils/rel.h"
32 #include "utils/syscache.h"
33 #include "utils/tqual.h"
34
35
36 /*
37  * CreateConstraintEntry
38  *      Create a constraint table entry.
39  *
40  * Subsidiary records (such as triggers or indexes to implement the
41  * constraint) are *not* created here.  But we do make dependency links
42  * from the constraint to the things it depends on.
43  */
44 Oid
45 CreateConstraintEntry(const char *constraintName,
46                                           Oid constraintNamespace,
47                                           char constraintType,
48                                           bool isDeferrable,
49                                           bool isDeferred,
50                                           bool isValidated,
51                                           Oid relId,
52                                           const int16 *constraintKey,
53                                           int constraintNKeys,
54                                           Oid domainId,
55                                           Oid indexRelId,
56                                           Oid foreignRelId,
57                                           const int16 *foreignKey,
58                                           const Oid *pfEqOp,
59                                           const Oid *ppEqOp,
60                                           const Oid *ffEqOp,
61                                           int foreignNKeys,
62                                           char foreignUpdateType,
63                                           char foreignDeleteType,
64                                           char foreignMatchType,
65                                           const Oid *exclOp,
66                                           Node *conExpr,
67                                           const char *conBin,
68                                           const char *conSrc,
69                                           bool conIsLocal,
70                                           int conInhCount,
71                                           bool conNoInherit,
72                                           bool is_internal)
73 {
74         Relation        conDesc;
75         Oid                     conOid;
76         HeapTuple       tup;
77         bool            nulls[Natts_pg_constraint];
78         Datum           values[Natts_pg_constraint];
79         ArrayType  *conkeyArray;
80         ArrayType  *confkeyArray;
81         ArrayType  *conpfeqopArray;
82         ArrayType  *conppeqopArray;
83         ArrayType  *conffeqopArray;
84         ArrayType  *conexclopArray;
85         NameData        cname;
86         int                     i;
87         ObjectAddress conobject;
88
89         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
90
91         Assert(constraintName);
92         namestrcpy(&cname, constraintName);
93
94         /*
95          * Convert C arrays into Postgres arrays.
96          */
97         if (constraintNKeys > 0)
98         {
99                 Datum      *conkey;
100
101                 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
102                 for (i = 0; i < constraintNKeys; i++)
103                         conkey[i] = Int16GetDatum(constraintKey[i]);
104                 conkeyArray = construct_array(conkey, constraintNKeys,
105                                                                           INT2OID, 2, true, 's');
106         }
107         else
108                 conkeyArray = NULL;
109
110         if (foreignNKeys > 0)
111         {
112                 Datum      *fkdatums;
113
114                 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
115                 for (i = 0; i < foreignNKeys; i++)
116                         fkdatums[i] = Int16GetDatum(foreignKey[i]);
117                 confkeyArray = construct_array(fkdatums, foreignNKeys,
118                                                                            INT2OID, 2, true, 's');
119                 for (i = 0; i < foreignNKeys; i++)
120                         fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
121                 conpfeqopArray = construct_array(fkdatums, foreignNKeys,
122                                                                                  OIDOID, sizeof(Oid), true, 'i');
123                 for (i = 0; i < foreignNKeys; i++)
124                         fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
125                 conppeqopArray = construct_array(fkdatums, foreignNKeys,
126                                                                                  OIDOID, sizeof(Oid), true, 'i');
127                 for (i = 0; i < foreignNKeys; i++)
128                         fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
129                 conffeqopArray = construct_array(fkdatums, foreignNKeys,
130                                                                                  OIDOID, sizeof(Oid), true, 'i');
131         }
132         else
133         {
134                 confkeyArray = NULL;
135                 conpfeqopArray = NULL;
136                 conppeqopArray = NULL;
137                 conffeqopArray = NULL;
138         }
139
140         if (exclOp != NULL)
141         {
142                 Datum      *opdatums;
143
144                 opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
145                 for (i = 0; i < constraintNKeys; i++)
146                         opdatums[i] = ObjectIdGetDatum(exclOp[i]);
147                 conexclopArray = construct_array(opdatums, constraintNKeys,
148                                                                                  OIDOID, sizeof(Oid), true, 'i');
149         }
150         else
151                 conexclopArray = NULL;
152
153         /* initialize nulls and values */
154         for (i = 0; i < Natts_pg_constraint; i++)
155         {
156                 nulls[i] = false;
157                 values[i] = (Datum) NULL;
158         }
159
160         values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
161         values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
162         values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
163         values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
164         values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
165         values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
166         values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
167         values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
168         values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
169         values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
170         values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
171         values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
172         values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
173         values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
174         values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
175         values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
176
177         if (conkeyArray)
178                 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
179         else
180                 nulls[Anum_pg_constraint_conkey - 1] = true;
181
182         if (confkeyArray)
183                 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
184         else
185                 nulls[Anum_pg_constraint_confkey - 1] = true;
186
187         if (conpfeqopArray)
188                 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
189         else
190                 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
191
192         if (conppeqopArray)
193                 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
194         else
195                 nulls[Anum_pg_constraint_conppeqop - 1] = true;
196
197         if (conffeqopArray)
198                 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
199         else
200                 nulls[Anum_pg_constraint_conffeqop - 1] = true;
201
202         if (conexclopArray)
203                 values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
204         else
205                 nulls[Anum_pg_constraint_conexclop - 1] = true;
206
207         /*
208          * initialize the binary form of the check constraint.
209          */
210         if (conBin)
211                 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
212         else
213                 nulls[Anum_pg_constraint_conbin - 1] = true;
214
215         /*
216          * initialize the text form of the check constraint
217          */
218         if (conSrc)
219                 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
220         else
221                 nulls[Anum_pg_constraint_consrc - 1] = true;
222
223         tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
224
225         conOid = simple_heap_insert(conDesc, tup);
226
227         /* update catalog indexes */
228         CatalogUpdateIndexes(conDesc, tup);
229
230         conobject.classId = ConstraintRelationId;
231         conobject.objectId = conOid;
232         conobject.objectSubId = 0;
233
234         heap_close(conDesc, RowExclusiveLock);
235
236         if (OidIsValid(relId))
237         {
238                 /*
239                  * Register auto dependency from constraint to owning relation, or to
240                  * specific column(s) if any are mentioned.
241                  */
242                 ObjectAddress relobject;
243
244                 relobject.classId = RelationRelationId;
245                 relobject.objectId = relId;
246                 if (constraintNKeys > 0)
247                 {
248                         for (i = 0; i < constraintNKeys; i++)
249                         {
250                                 relobject.objectSubId = constraintKey[i];
251
252                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
253                         }
254                 }
255                 else
256                 {
257                         relobject.objectSubId = 0;
258
259                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
260                 }
261         }
262
263         if (OidIsValid(domainId))
264         {
265                 /*
266                  * Register auto dependency from constraint to owning domain
267                  */
268                 ObjectAddress domobject;
269
270                 domobject.classId = TypeRelationId;
271                 domobject.objectId = domainId;
272                 domobject.objectSubId = 0;
273
274                 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
275         }
276
277         if (OidIsValid(foreignRelId))
278         {
279                 /*
280                  * Register normal dependency from constraint to foreign relation, or
281                  * to specific column(s) if any are mentioned.
282                  */
283                 ObjectAddress relobject;
284
285                 relobject.classId = RelationRelationId;
286                 relobject.objectId = foreignRelId;
287                 if (foreignNKeys > 0)
288                 {
289                         for (i = 0; i < foreignNKeys; i++)
290                         {
291                                 relobject.objectSubId = foreignKey[i];
292
293                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
294                         }
295                 }
296                 else
297                 {
298                         relobject.objectSubId = 0;
299
300                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
301                 }
302         }
303
304         if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
305         {
306                 /*
307                  * Register normal dependency on the unique index that supports a
308                  * foreign-key constraint.      (Note: for indexes associated with unique
309                  * or primary-key constraints, the dependency runs the other way, and
310                  * is not made here.)
311                  */
312                 ObjectAddress relobject;
313
314                 relobject.classId = RelationRelationId;
315                 relobject.objectId = indexRelId;
316                 relobject.objectSubId = 0;
317
318                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
319         }
320
321         if (foreignNKeys > 0)
322         {
323                 /*
324                  * Register normal dependencies on the equality operators that support
325                  * a foreign-key constraint.  If the PK and FK types are the same then
326                  * all three operators for a column are the same; otherwise they are
327                  * different.
328                  */
329                 ObjectAddress oprobject;
330
331                 oprobject.classId = OperatorRelationId;
332                 oprobject.objectSubId = 0;
333
334                 for (i = 0; i < foreignNKeys; i++)
335                 {
336                         oprobject.objectId = pfEqOp[i];
337                         recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
338                         if (ppEqOp[i] != pfEqOp[i])
339                         {
340                                 oprobject.objectId = ppEqOp[i];
341                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
342                         }
343                         if (ffEqOp[i] != pfEqOp[i])
344                         {
345                                 oprobject.objectId = ffEqOp[i];
346                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
347                         }
348                 }
349         }
350
351         /*
352          * We don't bother to register dependencies on the exclusion operators of
353          * an exclusion constraint.  We assume they are members of the opclass
354          * supporting the index, so there's an indirect dependency via that. (This
355          * would be pretty dicey for cross-type operators, but exclusion operators
356          * can never be cross-type.)
357          */
358
359         if (conExpr != NULL)
360         {
361                 /*
362                  * Register dependencies from constraint to objects mentioned in CHECK
363                  * expression.
364                  */
365                 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
366                                                                                 DEPENDENCY_NORMAL,
367                                                                                 DEPENDENCY_NORMAL);
368         }
369
370         /* Post creation hook for new constraint */
371         InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
372                                                                   is_internal);
373
374         return conOid;
375 }
376
377
378 /*
379  * Test whether given name is currently used as a constraint name
380  * for the given object (relation or domain).
381  *
382  * This is used to decide whether to accept a user-specified constraint name.
383  * It is deliberately not the same test as ChooseConstraintName uses to decide
384  * whether an auto-generated name is OK: here, we will allow it unless there
385  * is an identical constraint name in use *on the same object*.
386  *
387  * NB: Caller should hold exclusive lock on the given object, else
388  * this test can be fooled by concurrent additions.
389  */
390 bool
391 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
392                                          Oid objNamespace, const char *conname)
393 {
394         bool            found;
395         Relation        conDesc;
396         SysScanDesc conscan;
397         ScanKeyData skey[2];
398         HeapTuple       tup;
399
400         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
401
402         found = false;
403
404         ScanKeyInit(&skey[0],
405                                 Anum_pg_constraint_conname,
406                                 BTEqualStrategyNumber, F_NAMEEQ,
407                                 CStringGetDatum(conname));
408
409         ScanKeyInit(&skey[1],
410                                 Anum_pg_constraint_connamespace,
411                                 BTEqualStrategyNumber, F_OIDEQ,
412                                 ObjectIdGetDatum(objNamespace));
413
414         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
415                                                                  NULL, 2, skey);
416
417         while (HeapTupleIsValid(tup = systable_getnext(conscan)))
418         {
419                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
420
421                 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
422                 {
423                         found = true;
424                         break;
425                 }
426                 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
427                 {
428                         found = true;
429                         break;
430                 }
431         }
432
433         systable_endscan(conscan);
434         heap_close(conDesc, AccessShareLock);
435
436         return found;
437 }
438
439 /*
440  * Select a nonconflicting name for a new constraint.
441  *
442  * The objective here is to choose a name that is unique within the
443  * specified namespace.  Postgres does not require this, but the SQL
444  * spec does, and some apps depend on it.  Therefore we avoid choosing
445  * default names that so conflict.
446  *
447  * name1, name2, and label are used the same way as for makeObjectName(),
448  * except that the label can't be NULL; digits will be appended to the label
449  * if needed to create a name that is unique within the specified namespace.
450  *
451  * 'others' can be a list of string names already chosen within the current
452  * command (but not yet reflected into the catalogs); we will not choose
453  * a duplicate of one of these either.
454  *
455  * Note: it is theoretically possible to get a collision anyway, if someone
456  * else chooses the same name concurrently.  This is fairly unlikely to be
457  * a problem in practice, especially if one is holding an exclusive lock on
458  * the relation identified by name1.
459  *
460  * Returns a palloc'd string.
461  */
462 char *
463 ChooseConstraintName(const char *name1, const char *name2,
464                                          const char *label, Oid namespaceid,
465                                          List *others)
466 {
467         int                     pass = 0;
468         char       *conname = NULL;
469         char            modlabel[NAMEDATALEN];
470         Relation        conDesc;
471         SysScanDesc conscan;
472         ScanKeyData skey[2];
473         bool            found;
474         ListCell   *l;
475
476         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
477
478         /* try the unmodified label first */
479         StrNCpy(modlabel, label, sizeof(modlabel));
480
481         for (;;)
482         {
483                 conname = makeObjectName(name1, name2, modlabel);
484
485                 found = false;
486
487                 foreach(l, others)
488                 {
489                         if (strcmp((char *) lfirst(l), conname) == 0)
490                         {
491                                 found = true;
492                                 break;
493                         }
494                 }
495
496                 if (!found)
497                 {
498                         ScanKeyInit(&skey[0],
499                                                 Anum_pg_constraint_conname,
500                                                 BTEqualStrategyNumber, F_NAMEEQ,
501                                                 CStringGetDatum(conname));
502
503                         ScanKeyInit(&skey[1],
504                                                 Anum_pg_constraint_connamespace,
505                                                 BTEqualStrategyNumber, F_OIDEQ,
506                                                 ObjectIdGetDatum(namespaceid));
507
508                         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
509                                                                                  NULL, 2, skey);
510
511                         found = (HeapTupleIsValid(systable_getnext(conscan)));
512
513                         systable_endscan(conscan);
514                 }
515
516                 if (!found)
517                         break;
518
519                 /* found a conflict, so try a new name component */
520                 pfree(conname);
521                 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
522         }
523
524         heap_close(conDesc, AccessShareLock);
525
526         return conname;
527 }
528
529 /*
530  * Delete a single constraint record.
531  */
532 void
533 RemoveConstraintById(Oid conId)
534 {
535         Relation        conDesc;
536         HeapTuple       tup;
537         Form_pg_constraint con;
538
539         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
540
541         tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
542         if (!HeapTupleIsValid(tup)) /* should not happen */
543                 elog(ERROR, "cache lookup failed for constraint %u", conId);
544         con = (Form_pg_constraint) GETSTRUCT(tup);
545
546         /*
547          * Special processing depending on what the constraint is for.
548          */
549         if (OidIsValid(con->conrelid))
550         {
551                 Relation        rel;
552
553                 /*
554                  * If the constraint is for a relation, open and exclusive-lock the
555                  * relation it's for.
556                  */
557                 rel = heap_open(con->conrelid, AccessExclusiveLock);
558
559                 /*
560                  * We need to update the relcheck count if it is a check constraint
561                  * being dropped.  This update will force backends to rebuild relcache
562                  * entries when we commit.
563                  */
564                 if (con->contype == CONSTRAINT_CHECK)
565                 {
566                         Relation        pgrel;
567                         HeapTuple       relTup;
568                         Form_pg_class classForm;
569
570                         pgrel = heap_open(RelationRelationId, RowExclusiveLock);
571                         relTup = SearchSysCacheCopy1(RELOID,
572                                                                                  ObjectIdGetDatum(con->conrelid));
573                         if (!HeapTupleIsValid(relTup))
574                                 elog(ERROR, "cache lookup failed for relation %u",
575                                          con->conrelid);
576                         classForm = (Form_pg_class) GETSTRUCT(relTup);
577
578                         if (classForm->relchecks == 0)          /* should not happen */
579                                 elog(ERROR, "relation \"%s\" has relchecks = 0",
580                                          RelationGetRelationName(rel));
581                         classForm->relchecks--;
582
583                         simple_heap_update(pgrel, &relTup->t_self, relTup);
584
585                         CatalogUpdateIndexes(pgrel, relTup);
586
587                         heap_freetuple(relTup);
588
589                         heap_close(pgrel, RowExclusiveLock);
590                 }
591
592                 /* Keep lock on constraint's rel until end of xact */
593                 heap_close(rel, NoLock);
594         }
595         else if (OidIsValid(con->contypid))
596         {
597                 /*
598                  * XXX for now, do nothing special when dropping a domain constraint
599                  *
600                  * Probably there should be some form of locking on the domain type,
601                  * but we have no such concept at the moment.
602                  */
603         }
604         else
605                 elog(ERROR, "constraint %u is not of a known type", conId);
606
607         /* Fry the constraint itself */
608         simple_heap_delete(conDesc, &tup->t_self);
609
610         /* Clean up */
611         ReleaseSysCache(tup);
612         heap_close(conDesc, RowExclusiveLock);
613 }
614
615 /*
616  * RenameConstraintById
617  *              Rename a constraint.
618  *
619  * Note: this isn't intended to be a user-exposed function; it doesn't check
620  * permissions etc.  Currently this is only invoked when renaming an index
621  * that is associated with a constraint, but it's made a little more general
622  * than that with the expectation of someday having ALTER TABLE RENAME
623  * CONSTRAINT.
624  */
625 void
626 RenameConstraintById(Oid conId, const char *newname)
627 {
628         Relation        conDesc;
629         HeapTuple       tuple;
630         Form_pg_constraint con;
631
632         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
633
634         tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
635         if (!HeapTupleIsValid(tuple))
636                 elog(ERROR, "cache lookup failed for constraint %u", conId);
637         con = (Form_pg_constraint) GETSTRUCT(tuple);
638
639         /*
640          * We need to check whether the name is already in use --- note that there
641          * currently is not a unique index that would catch this.
642          */
643         if (OidIsValid(con->conrelid) &&
644                 ConstraintNameIsUsed(CONSTRAINT_RELATION,
645                                                          con->conrelid,
646                                                          con->connamespace,
647                                                          newname))
648                 ereport(ERROR,
649                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
650                            errmsg("constraint \"%s\" for relation \"%s\" already exists",
651                                           newname, get_rel_name(con->conrelid))));
652         if (OidIsValid(con->contypid) &&
653                 ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
654                                                          con->contypid,
655                                                          con->connamespace,
656                                                          newname))
657                 ereport(ERROR,
658                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
659                                  errmsg("constraint \"%s\" for domain %s already exists",
660                                                 newname, format_type_be(con->contypid))));
661
662         /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
663         namestrcpy(&(con->conname), newname);
664
665         simple_heap_update(conDesc, &tuple->t_self, tuple);
666
667         /* update the system catalog indexes */
668         CatalogUpdateIndexes(conDesc, tuple);
669
670         InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
671
672         heap_freetuple(tuple);
673         heap_close(conDesc, RowExclusiveLock);
674 }
675
676 /*
677  * AlterConstraintNamespaces
678  *              Find any constraints belonging to the specified object,
679  *              and move them to the specified new namespace.
680  *
681  * isType indicates whether the owning object is a type or a relation.
682  */
683 void
684 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
685                                            Oid newNspId, bool isType, ObjectAddresses *objsMoved)
686 {
687         Relation        conRel;
688         ScanKeyData key[1];
689         SysScanDesc scan;
690         HeapTuple       tup;
691
692         conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
693
694         if (isType)
695         {
696                 ScanKeyInit(&key[0],
697                                         Anum_pg_constraint_contypid,
698                                         BTEqualStrategyNumber, F_OIDEQ,
699                                         ObjectIdGetDatum(ownerId));
700
701                 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
702                                                                   NULL, 1, key);
703         }
704         else
705         {
706                 ScanKeyInit(&key[0],
707                                         Anum_pg_constraint_conrelid,
708                                         BTEqualStrategyNumber, F_OIDEQ,
709                                         ObjectIdGetDatum(ownerId));
710
711                 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
712                                                                   NULL, 1, key);
713         }
714
715         while (HeapTupleIsValid((tup = systable_getnext(scan))))
716         {
717                 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
718                 ObjectAddress thisobj;
719
720                 thisobj.classId = ConstraintRelationId;
721                 thisobj.objectId = HeapTupleGetOid(tup);
722                 thisobj.objectSubId = 0;
723
724                 if (object_address_present(&thisobj, objsMoved))
725                         continue;
726
727                 if (conform->connamespace == oldNspId)
728                 {
729                         tup = heap_copytuple(tup);
730                         conform = (Form_pg_constraint) GETSTRUCT(tup);
731
732                         conform->connamespace = newNspId;
733
734                         simple_heap_update(conRel, &tup->t_self, tup);
735                         CatalogUpdateIndexes(conRel, tup);
736
737                         /*
738                          * Note: currently, the constraint will not have its own
739                          * dependency on the namespace, so we don't need to do
740                          * changeDependencyFor().
741                          */
742                 }
743
744                 InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
745
746                 add_exact_object_address(&thisobj, objsMoved);
747         }
748
749         systable_endscan(scan);
750
751         heap_close(conRel, RowExclusiveLock);
752 }
753
754 /*
755  * get_relation_constraint_oid
756  *              Find a constraint on the specified relation with the specified name.
757  *              Returns constraint's OID.
758  */
759 Oid
760 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
761 {
762         Relation        pg_constraint;
763         HeapTuple       tuple;
764         SysScanDesc scan;
765         ScanKeyData skey[1];
766         Oid                     conOid = InvalidOid;
767
768         /*
769          * Fetch the constraint tuple from pg_constraint.  There may be more than
770          * one match, because constraints are not required to have unique names;
771          * if so, error out.
772          */
773         pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
774
775         ScanKeyInit(&skey[0],
776                                 Anum_pg_constraint_conrelid,
777                                 BTEqualStrategyNumber, F_OIDEQ,
778                                 ObjectIdGetDatum(relid));
779
780         scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
781                                                           NULL, 1, skey);
782
783         while (HeapTupleIsValid(tuple = systable_getnext(scan)))
784         {
785                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
786
787                 if (strcmp(NameStr(con->conname), conname) == 0)
788                 {
789                         if (OidIsValid(conOid))
790                                 ereport(ERROR,
791                                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
792                                  errmsg("table \"%s\" has multiple constraints named \"%s\"",
793                                                 get_rel_name(relid), conname)));
794                         conOid = HeapTupleGetOid(tuple);
795                 }
796         }
797
798         systable_endscan(scan);
799
800         /* If no such constraint exists, complain */
801         if (!OidIsValid(conOid) && !missing_ok)
802                 ereport(ERROR,
803                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
804                                  errmsg("constraint \"%s\" for table \"%s\" does not exist",
805                                                 conname, get_rel_name(relid))));
806
807         heap_close(pg_constraint, AccessShareLock);
808
809         return conOid;
810 }
811
812 /*
813  * get_domain_constraint_oid
814  *              Find a constraint on the specified domain with the specified name.
815  *              Returns constraint's OID.
816  */
817 Oid
818 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
819 {
820         Relation        pg_constraint;
821         HeapTuple       tuple;
822         SysScanDesc scan;
823         ScanKeyData skey[1];
824         Oid                     conOid = InvalidOid;
825
826         /*
827          * Fetch the constraint tuple from pg_constraint.  There may be more than
828          * one match, because constraints are not required to have unique names;
829          * if so, error out.
830          */
831         pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
832
833         ScanKeyInit(&skey[0],
834                                 Anum_pg_constraint_contypid,
835                                 BTEqualStrategyNumber, F_OIDEQ,
836                                 ObjectIdGetDatum(typid));
837
838         scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
839                                                           NULL, 1, skey);
840
841         while (HeapTupleIsValid(tuple = systable_getnext(scan)))
842         {
843                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
844
845                 if (strcmp(NameStr(con->conname), conname) == 0)
846                 {
847                         if (OidIsValid(conOid))
848                                 ereport(ERROR,
849                                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
850                                 errmsg("domain \"%s\" has multiple constraints named \"%s\"",
851                                            format_type_be(typid), conname)));
852                         conOid = HeapTupleGetOid(tuple);
853                 }
854         }
855
856         systable_endscan(scan);
857
858         /* If no such constraint exists, complain */
859         if (!OidIsValid(conOid) && !missing_ok)
860                 ereport(ERROR,
861                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
862                                  errmsg("constraint \"%s\" for domain \"%s\" does not exist",
863                                                 conname, format_type_be(typid))));
864
865         heap_close(pg_constraint, AccessShareLock);
866
867         return conOid;
868 }
869
870 /*
871  * Determine whether a relation can be proven functionally dependent on
872  * a set of grouping columns.  If so, return TRUE and add the pg_constraint
873  * OIDs of the constraints needed for the proof to the *constraintDeps list.
874  *
875  * grouping_columns is a list of grouping expressions, in which columns of
876  * the rel of interest are Vars with the indicated varno/varlevelsup.
877  *
878  * Currently we only check to see if the rel has a primary key that is a
879  * subset of the grouping_columns.      We could also use plain unique constraints
880  * if all their columns are known not null, but there's a problem: we need
881  * to be able to represent the not-null-ness as part of the constraints added
882  * to *constraintDeps.  FIXME whenever not-null constraints get represented
883  * in pg_constraint.
884  */
885 bool
886 check_functional_grouping(Oid relid,
887                                                   Index varno, Index varlevelsup,
888                                                   List *grouping_columns,
889                                                   List **constraintDeps)
890 {
891         bool            result = false;
892         Relation        pg_constraint;
893         HeapTuple       tuple;
894         SysScanDesc scan;
895         ScanKeyData skey[1];
896
897         /* Scan pg_constraint for constraints of the target rel */
898         pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
899
900         ScanKeyInit(&skey[0],
901                                 Anum_pg_constraint_conrelid,
902                                 BTEqualStrategyNumber, F_OIDEQ,
903                                 ObjectIdGetDatum(relid));
904
905         scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
906                                                           NULL, 1, skey);
907
908         while (HeapTupleIsValid(tuple = systable_getnext(scan)))
909         {
910                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
911                 Datum           adatum;
912                 bool            isNull;
913                 ArrayType  *arr;
914                 int16      *attnums;
915                 int                     numkeys;
916                 int                     i;
917                 bool            found_col;
918
919                 /* Only PK constraints are of interest for now, see comment above */
920                 if (con->contype != CONSTRAINT_PRIMARY)
921                         continue;
922                 /* Constraint must be non-deferrable */
923                 if (con->condeferrable)
924                         continue;
925
926                 /* Extract the conkey array, ie, attnums of PK's columns */
927                 adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
928                                                           RelationGetDescr(pg_constraint), &isNull);
929                 if (isNull)
930                         elog(ERROR, "null conkey for constraint %u",
931                                  HeapTupleGetOid(tuple));
932                 arr = DatumGetArrayTypeP(adatum);               /* ensure not toasted */
933                 numkeys = ARR_DIMS(arr)[0];
934                 if (ARR_NDIM(arr) != 1 ||
935                         numkeys < 0 ||
936                         ARR_HASNULL(arr) ||
937                         ARR_ELEMTYPE(arr) != INT2OID)
938                         elog(ERROR, "conkey is not a 1-D smallint array");
939                 attnums = (int16 *) ARR_DATA_PTR(arr);
940
941                 found_col = false;
942                 for (i = 0; i < numkeys; i++)
943                 {
944                         AttrNumber      attnum = attnums[i];
945                         ListCell   *gl;
946
947                         found_col = false;
948                         foreach(gl, grouping_columns)
949                         {
950                                 Var                *gvar = (Var *) lfirst(gl);
951
952                                 if (IsA(gvar, Var) &&
953                                         gvar->varno == varno &&
954                                         gvar->varlevelsup == varlevelsup &&
955                                         gvar->varattno == attnum)
956                                 {
957                                         found_col = true;
958                                         break;
959                                 }
960                         }
961                         if (!found_col)
962                                 break;
963                 }
964
965                 if (found_col)
966                 {
967                         /* The PK is a subset of grouping_columns, so we win */
968                         *constraintDeps = lappend_oid(*constraintDeps,
969                                                                                   HeapTupleGetOid(tuple));
970                         result = true;
971                         break;
972                 }
973         }
974
975         systable_endscan(scan);
976
977         heap_close(pg_constraint, AccessShareLock);
978
979         return result;
980 }