1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_constraint.c
13 *-------------------------------------------------------------------------
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"
37 * CreateConstraintEntry
38 * Create a constraint table entry.
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.
45 CreateConstraintEntry(const char *constraintName,
46 Oid constraintNamespace,
52 const int16 *constraintKey,
57 const int16 *foreignKey,
62 char foreignUpdateType,
63 char foreignDeleteType,
64 char foreignMatchType,
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;
87 ObjectAddress conobject;
89 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
91 Assert(constraintName);
92 namestrcpy(&cname, constraintName);
95 * Convert C arrays into Postgres arrays.
97 if (constraintNKeys > 0)
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');
110 if (foreignNKeys > 0)
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');
135 conpfeqopArray = NULL;
136 conppeqopArray = NULL;
137 conffeqopArray = NULL;
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');
151 conexclopArray = NULL;
153 /* initialize nulls and values */
154 for (i = 0; i < Natts_pg_constraint; i++)
157 values[i] = (Datum) NULL;
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);
178 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
180 nulls[Anum_pg_constraint_conkey - 1] = true;
183 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
185 nulls[Anum_pg_constraint_confkey - 1] = true;
188 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
190 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
193 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
195 nulls[Anum_pg_constraint_conppeqop - 1] = true;
198 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
200 nulls[Anum_pg_constraint_conffeqop - 1] = true;
203 values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
205 nulls[Anum_pg_constraint_conexclop - 1] = true;
208 * initialize the binary form of the check constraint.
211 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
213 nulls[Anum_pg_constraint_conbin - 1] = true;
216 * initialize the text form of the check constraint
219 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
221 nulls[Anum_pg_constraint_consrc - 1] = true;
223 tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
225 conOid = simple_heap_insert(conDesc, tup);
227 /* update catalog indexes */
228 CatalogUpdateIndexes(conDesc, tup);
230 conobject.classId = ConstraintRelationId;
231 conobject.objectId = conOid;
232 conobject.objectSubId = 0;
234 heap_close(conDesc, RowExclusiveLock);
236 if (OidIsValid(relId))
239 * Register auto dependency from constraint to owning relation, or to
240 * specific column(s) if any are mentioned.
242 ObjectAddress relobject;
244 relobject.classId = RelationRelationId;
245 relobject.objectId = relId;
246 if (constraintNKeys > 0)
248 for (i = 0; i < constraintNKeys; i++)
250 relobject.objectSubId = constraintKey[i];
252 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
257 relobject.objectSubId = 0;
259 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
263 if (OidIsValid(domainId))
266 * Register auto dependency from constraint to owning domain
268 ObjectAddress domobject;
270 domobject.classId = TypeRelationId;
271 domobject.objectId = domainId;
272 domobject.objectSubId = 0;
274 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
277 if (OidIsValid(foreignRelId))
280 * Register normal dependency from constraint to foreign relation, or
281 * to specific column(s) if any are mentioned.
283 ObjectAddress relobject;
285 relobject.classId = RelationRelationId;
286 relobject.objectId = foreignRelId;
287 if (foreignNKeys > 0)
289 for (i = 0; i < foreignNKeys; i++)
291 relobject.objectSubId = foreignKey[i];
293 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
298 relobject.objectSubId = 0;
300 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
304 if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
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
312 ObjectAddress relobject;
314 relobject.classId = RelationRelationId;
315 relobject.objectId = indexRelId;
316 relobject.objectSubId = 0;
318 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
321 if (foreignNKeys > 0)
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
329 ObjectAddress oprobject;
331 oprobject.classId = OperatorRelationId;
332 oprobject.objectSubId = 0;
334 for (i = 0; i < foreignNKeys; i++)
336 oprobject.objectId = pfEqOp[i];
337 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
338 if (ppEqOp[i] != pfEqOp[i])
340 oprobject.objectId = ppEqOp[i];
341 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
343 if (ffEqOp[i] != pfEqOp[i])
345 oprobject.objectId = ffEqOp[i];
346 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
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.)
362 * Register dependencies from constraint to objects mentioned in CHECK
365 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
370 /* Post creation hook for new constraint */
371 InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
379 * Test whether given name is currently used as a constraint name
380 * for the given object (relation or domain).
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*.
387 * NB: Caller should hold exclusive lock on the given object, else
388 * this test can be fooled by concurrent additions.
391 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
392 Oid objNamespace, const char *conname)
400 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
404 ScanKeyInit(&skey[0],
405 Anum_pg_constraint_conname,
406 BTEqualStrategyNumber, F_NAMEEQ,
407 CStringGetDatum(conname));
409 ScanKeyInit(&skey[1],
410 Anum_pg_constraint_connamespace,
411 BTEqualStrategyNumber, F_OIDEQ,
412 ObjectIdGetDatum(objNamespace));
414 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
417 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
419 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
421 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
426 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
433 systable_endscan(conscan);
434 heap_close(conDesc, AccessShareLock);
440 * Select a nonconflicting name for a new constraint.
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.
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.
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.
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.
460 * Returns a palloc'd string.
463 ChooseConstraintName(const char *name1, const char *name2,
464 const char *label, Oid namespaceid,
468 char *conname = NULL;
469 char modlabel[NAMEDATALEN];
476 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
478 /* try the unmodified label first */
479 StrNCpy(modlabel, label, sizeof(modlabel));
483 conname = makeObjectName(name1, name2, modlabel);
489 if (strcmp((char *) lfirst(l), conname) == 0)
498 ScanKeyInit(&skey[0],
499 Anum_pg_constraint_conname,
500 BTEqualStrategyNumber, F_NAMEEQ,
501 CStringGetDatum(conname));
503 ScanKeyInit(&skey[1],
504 Anum_pg_constraint_connamespace,
505 BTEqualStrategyNumber, F_OIDEQ,
506 ObjectIdGetDatum(namespaceid));
508 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
511 found = (HeapTupleIsValid(systable_getnext(conscan)));
513 systable_endscan(conscan);
519 /* found a conflict, so try a new name component */
521 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
524 heap_close(conDesc, AccessShareLock);
530 * Delete a single constraint record.
533 RemoveConstraintById(Oid conId)
537 Form_pg_constraint con;
539 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
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);
547 * Special processing depending on what the constraint is for.
549 if (OidIsValid(con->conrelid))
554 * If the constraint is for a relation, open and exclusive-lock the
557 rel = heap_open(con->conrelid, AccessExclusiveLock);
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.
564 if (con->contype == CONSTRAINT_CHECK)
568 Form_pg_class classForm;
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",
576 classForm = (Form_pg_class) GETSTRUCT(relTup);
578 if (classForm->relchecks == 0) /* should not happen */
579 elog(ERROR, "relation \"%s\" has relchecks = 0",
580 RelationGetRelationName(rel));
581 classForm->relchecks--;
583 simple_heap_update(pgrel, &relTup->t_self, relTup);
585 CatalogUpdateIndexes(pgrel, relTup);
587 heap_freetuple(relTup);
589 heap_close(pgrel, RowExclusiveLock);
592 /* Keep lock on constraint's rel until end of xact */
593 heap_close(rel, NoLock);
595 else if (OidIsValid(con->contypid))
598 * XXX for now, do nothing special when dropping a domain constraint
600 * Probably there should be some form of locking on the domain type,
601 * but we have no such concept at the moment.
605 elog(ERROR, "constraint %u is not of a known type", conId);
607 /* Fry the constraint itself */
608 simple_heap_delete(conDesc, &tup->t_self);
611 ReleaseSysCache(tup);
612 heap_close(conDesc, RowExclusiveLock);
616 * RenameConstraintById
617 * Rename a constraint.
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
626 RenameConstraintById(Oid conId, const char *newname)
630 Form_pg_constraint con;
632 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
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);
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.
643 if (OidIsValid(con->conrelid) &&
644 ConstraintNameIsUsed(CONSTRAINT_RELATION,
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,
658 (errcode(ERRCODE_DUPLICATE_OBJECT),
659 errmsg("constraint \"%s\" for domain %s already exists",
660 newname, format_type_be(con->contypid))));
662 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
663 namestrcpy(&(con->conname), newname);
665 simple_heap_update(conDesc, &tuple->t_self, tuple);
667 /* update the system catalog indexes */
668 CatalogUpdateIndexes(conDesc, tuple);
670 InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
672 heap_freetuple(tuple);
673 heap_close(conDesc, RowExclusiveLock);
677 * AlterConstraintNamespaces
678 * Find any constraints belonging to the specified object,
679 * and move them to the specified new namespace.
681 * isType indicates whether the owning object is a type or a relation.
684 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
685 Oid newNspId, bool isType, ObjectAddresses *objsMoved)
692 conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
697 Anum_pg_constraint_contypid,
698 BTEqualStrategyNumber, F_OIDEQ,
699 ObjectIdGetDatum(ownerId));
701 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
707 Anum_pg_constraint_conrelid,
708 BTEqualStrategyNumber, F_OIDEQ,
709 ObjectIdGetDatum(ownerId));
711 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
715 while (HeapTupleIsValid((tup = systable_getnext(scan))))
717 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
718 ObjectAddress thisobj;
720 thisobj.classId = ConstraintRelationId;
721 thisobj.objectId = HeapTupleGetOid(tup);
722 thisobj.objectSubId = 0;
724 if (object_address_present(&thisobj, objsMoved))
727 if (conform->connamespace == oldNspId)
729 tup = heap_copytuple(tup);
730 conform = (Form_pg_constraint) GETSTRUCT(tup);
732 conform->connamespace = newNspId;
734 simple_heap_update(conRel, &tup->t_self, tup);
735 CatalogUpdateIndexes(conRel, tup);
738 * Note: currently, the constraint will not have its own
739 * dependency on the namespace, so we don't need to do
740 * changeDependencyFor().
744 InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
746 add_exact_object_address(&thisobj, objsMoved);
749 systable_endscan(scan);
751 heap_close(conRel, RowExclusiveLock);
755 * get_relation_constraint_oid
756 * Find a constraint on the specified relation with the specified name.
757 * Returns constraint's OID.
760 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
762 Relation pg_constraint;
766 Oid conOid = InvalidOid;
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;
773 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
775 ScanKeyInit(&skey[0],
776 Anum_pg_constraint_conrelid,
777 BTEqualStrategyNumber, F_OIDEQ,
778 ObjectIdGetDatum(relid));
780 scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
783 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
785 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
787 if (strcmp(NameStr(con->conname), conname) == 0)
789 if (OidIsValid(conOid))
791 (errcode(ERRCODE_DUPLICATE_OBJECT),
792 errmsg("table \"%s\" has multiple constraints named \"%s\"",
793 get_rel_name(relid), conname)));
794 conOid = HeapTupleGetOid(tuple);
798 systable_endscan(scan);
800 /* If no such constraint exists, complain */
801 if (!OidIsValid(conOid) && !missing_ok)
803 (errcode(ERRCODE_UNDEFINED_OBJECT),
804 errmsg("constraint \"%s\" for table \"%s\" does not exist",
805 conname, get_rel_name(relid))));
807 heap_close(pg_constraint, AccessShareLock);
813 * get_domain_constraint_oid
814 * Find a constraint on the specified domain with the specified name.
815 * Returns constraint's OID.
818 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
820 Relation pg_constraint;
824 Oid conOid = InvalidOid;
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;
831 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
833 ScanKeyInit(&skey[0],
834 Anum_pg_constraint_contypid,
835 BTEqualStrategyNumber, F_OIDEQ,
836 ObjectIdGetDatum(typid));
838 scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
841 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
843 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
845 if (strcmp(NameStr(con->conname), conname) == 0)
847 if (OidIsValid(conOid))
849 (errcode(ERRCODE_DUPLICATE_OBJECT),
850 errmsg("domain \"%s\" has multiple constraints named \"%s\"",
851 format_type_be(typid), conname)));
852 conOid = HeapTupleGetOid(tuple);
856 systable_endscan(scan);
858 /* If no such constraint exists, complain */
859 if (!OidIsValid(conOid) && !missing_ok)
861 (errcode(ERRCODE_UNDEFINED_OBJECT),
862 errmsg("constraint \"%s\" for domain \"%s\" does not exist",
863 conname, format_type_be(typid))));
865 heap_close(pg_constraint, AccessShareLock);
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.
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.
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
886 check_functional_grouping(Oid relid,
887 Index varno, Index varlevelsup,
888 List *grouping_columns,
889 List **constraintDeps)
892 Relation pg_constraint;
897 /* Scan pg_constraint for constraints of the target rel */
898 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
900 ScanKeyInit(&skey[0],
901 Anum_pg_constraint_conrelid,
902 BTEqualStrategyNumber, F_OIDEQ,
903 ObjectIdGetDatum(relid));
905 scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
908 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
910 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
919 /* Only PK constraints are of interest for now, see comment above */
920 if (con->contype != CONSTRAINT_PRIMARY)
922 /* Constraint must be non-deferrable */
923 if (con->condeferrable)
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);
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 ||
937 ARR_ELEMTYPE(arr) != INT2OID)
938 elog(ERROR, "conkey is not a 1-D smallint array");
939 attnums = (int16 *) ARR_DATA_PTR(arr);
942 for (i = 0; i < numkeys; i++)
944 AttrNumber attnum = attnums[i];
948 foreach(gl, grouping_columns)
950 Var *gvar = (Var *) lfirst(gl);
952 if (IsA(gvar, Var) &&
953 gvar->varno == varno &&
954 gvar->varlevelsup == varlevelsup &&
955 gvar->varattno == attnum)
967 /* The PK is a subset of grouping_columns, so we win */
968 *constraintDeps = lappend_oid(*constraintDeps,
969 HeapTupleGetOid(tuple));
975 systable_endscan(scan);
977 heap_close(pg_constraint, AccessShareLock);