1
/*-------------------------------------------------------------------------
4
* routines to support manipulation of the pg_constraint relation
6
* Portions Copyright (c) 1996-2011, 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 "catalog/dependency.h"
20
#include "catalog/indexing.h"
21
#include "catalog/objectaccess.h"
22
#include "catalog/pg_constraint.h"
23
#include "catalog/pg_operator.h"
24
#include "catalog/pg_type.h"
25
#include "commands/defrem.h"
26
#include "utils/array.h"
27
#include "utils/builtins.h"
28
#include "utils/fmgroids.h"
29
#include "utils/lsyscache.h"
30
#include "utils/rel.h"
31
#include "utils/syscache.h"
32
#include "utils/tqual.h"
36
* CreateConstraintEntry
37
* Create a constraint table entry.
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.
44
CreateConstraintEntry(const char *constraintName,
45
Oid constraintNamespace,
51
const int16 *constraintKey,
56
const int16 *foreignKey,
61
char foreignUpdateType,
62
char foreignDeleteType,
63
char foreignMatchType,
74
bool nulls[Natts_pg_constraint];
75
Datum values[Natts_pg_constraint];
76
ArrayType *conkeyArray;
77
ArrayType *confkeyArray;
78
ArrayType *conpfeqopArray;
79
ArrayType *conppeqopArray;
80
ArrayType *conffeqopArray;
81
ArrayType *conexclopArray;
84
ObjectAddress conobject;
86
conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
88
Assert(constraintName);
89
namestrcpy(&cname, constraintName);
92
* Convert C arrays into Postgres arrays.
94
if (constraintNKeys > 0)
98
conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
99
for (i = 0; i < constraintNKeys; i++)
100
conkey[i] = Int16GetDatum(constraintKey[i]);
101
conkeyArray = construct_array(conkey, constraintNKeys,
102
INT2OID, 2, true, 's');
107
if (foreignNKeys > 0)
111
fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
112
for (i = 0; i < foreignNKeys; i++)
113
fkdatums[i] = Int16GetDatum(foreignKey[i]);
114
confkeyArray = construct_array(fkdatums, foreignNKeys,
115
INT2OID, 2, true, 's');
116
for (i = 0; i < foreignNKeys; i++)
117
fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
118
conpfeqopArray = construct_array(fkdatums, foreignNKeys,
119
OIDOID, sizeof(Oid), true, 'i');
120
for (i = 0; i < foreignNKeys; i++)
121
fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
122
conppeqopArray = construct_array(fkdatums, foreignNKeys,
123
OIDOID, sizeof(Oid), true, 'i');
124
for (i = 0; i < foreignNKeys; i++)
125
fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
126
conffeqopArray = construct_array(fkdatums, foreignNKeys,
127
OIDOID, sizeof(Oid), true, 'i');
132
conpfeqopArray = NULL;
133
conppeqopArray = NULL;
134
conffeqopArray = NULL;
141
opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
142
for (i = 0; i < constraintNKeys; i++)
143
opdatums[i] = ObjectIdGetDatum(exclOp[i]);
144
conexclopArray = construct_array(opdatums, constraintNKeys,
145
OIDOID, sizeof(Oid), true, 'i');
148
conexclopArray = NULL;
150
/* initialize nulls and values */
151
for (i = 0; i < Natts_pg_constraint; i++)
154
values[i] = (Datum) NULL;
157
values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
158
values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
159
values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
160
values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
161
values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
162
values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
163
values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
164
values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
165
values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
166
values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
167
values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
168
values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
169
values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
170
values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
171
values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
174
values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
176
nulls[Anum_pg_constraint_conkey - 1] = true;
179
values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
181
nulls[Anum_pg_constraint_confkey - 1] = true;
184
values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
186
nulls[Anum_pg_constraint_conpfeqop - 1] = true;
189
values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
191
nulls[Anum_pg_constraint_conppeqop - 1] = true;
194
values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
196
nulls[Anum_pg_constraint_conffeqop - 1] = true;
199
values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
201
nulls[Anum_pg_constraint_conexclop - 1] = true;
204
* initialize the binary form of the check constraint.
207
values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
209
nulls[Anum_pg_constraint_conbin - 1] = true;
212
* initialize the text form of the check constraint
215
values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
217
nulls[Anum_pg_constraint_consrc - 1] = true;
219
tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
221
conOid = simple_heap_insert(conDesc, tup);
223
/* update catalog indexes */
224
CatalogUpdateIndexes(conDesc, tup);
226
conobject.classId = ConstraintRelationId;
227
conobject.objectId = conOid;
228
conobject.objectSubId = 0;
230
heap_close(conDesc, RowExclusiveLock);
232
if (OidIsValid(relId))
235
* Register auto dependency from constraint to owning relation, or to
236
* specific column(s) if any are mentioned.
238
ObjectAddress relobject;
240
relobject.classId = RelationRelationId;
241
relobject.objectId = relId;
242
if (constraintNKeys > 0)
244
for (i = 0; i < constraintNKeys; i++)
246
relobject.objectSubId = constraintKey[i];
248
recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
253
relobject.objectSubId = 0;
255
recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
259
if (OidIsValid(domainId))
262
* Register auto dependency from constraint to owning domain
264
ObjectAddress domobject;
266
domobject.classId = TypeRelationId;
267
domobject.objectId = domainId;
268
domobject.objectSubId = 0;
270
recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
273
if (OidIsValid(foreignRelId))
276
* Register normal dependency from constraint to foreign relation, or
277
* to specific column(s) if any are mentioned.
279
ObjectAddress relobject;
281
relobject.classId = RelationRelationId;
282
relobject.objectId = foreignRelId;
283
if (foreignNKeys > 0)
285
for (i = 0; i < foreignNKeys; i++)
287
relobject.objectSubId = foreignKey[i];
289
recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
294
relobject.objectSubId = 0;
296
recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
300
if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
303
* Register normal dependency on the unique index that supports a
304
* foreign-key constraint. (Note: for indexes associated with unique
305
* or primary-key constraints, the dependency runs the other way, and
308
ObjectAddress relobject;
310
relobject.classId = RelationRelationId;
311
relobject.objectId = indexRelId;
312
relobject.objectSubId = 0;
314
recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
317
if (foreignNKeys > 0)
320
* Register normal dependencies on the equality operators that support
321
* a foreign-key constraint. If the PK and FK types are the same then
322
* all three operators for a column are the same; otherwise they are
325
ObjectAddress oprobject;
327
oprobject.classId = OperatorRelationId;
328
oprobject.objectSubId = 0;
330
for (i = 0; i < foreignNKeys; i++)
332
oprobject.objectId = pfEqOp[i];
333
recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
334
if (ppEqOp[i] != pfEqOp[i])
336
oprobject.objectId = ppEqOp[i];
337
recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
339
if (ffEqOp[i] != pfEqOp[i])
341
oprobject.objectId = ffEqOp[i];
342
recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
348
* We don't bother to register dependencies on the exclusion operators of
349
* an exclusion constraint. We assume they are members of the opclass
350
* supporting the index, so there's an indirect dependency via that. (This
351
* would be pretty dicey for cross-type operators, but exclusion operators
352
* can never be cross-type.)
358
* Register dependencies from constraint to objects mentioned in CHECK
361
recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
366
/* Post creation hook for new constraint */
367
InvokeObjectAccessHook(OAT_POST_CREATE, ConstraintRelationId, conOid, 0);
374
* Test whether given name is currently used as a constraint name
375
* for the given object (relation or domain).
377
* This is used to decide whether to accept a user-specified constraint name.
378
* It is deliberately not the same test as ChooseConstraintName uses to decide
379
* whether an auto-generated name is OK: here, we will allow it unless there
380
* is an identical constraint name in use *on the same object*.
382
* NB: Caller should hold exclusive lock on the given object, else
383
* this test can be fooled by concurrent additions.
386
ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
387
Oid objNamespace, const char *conname)
395
conDesc = heap_open(ConstraintRelationId, AccessShareLock);
399
ScanKeyInit(&skey[0],
400
Anum_pg_constraint_conname,
401
BTEqualStrategyNumber, F_NAMEEQ,
402
CStringGetDatum(conname));
404
ScanKeyInit(&skey[1],
405
Anum_pg_constraint_connamespace,
406
BTEqualStrategyNumber, F_OIDEQ,
407
ObjectIdGetDatum(objNamespace));
409
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
410
SnapshotNow, 2, skey);
412
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
414
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
416
if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
421
else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
428
systable_endscan(conscan);
429
heap_close(conDesc, AccessShareLock);
435
* Select a nonconflicting name for a new constraint.
437
* The objective here is to choose a name that is unique within the
438
* specified namespace. Postgres does not require this, but the SQL
439
* spec does, and some apps depend on it. Therefore we avoid choosing
440
* default names that so conflict.
442
* name1, name2, and label are used the same way as for makeObjectName(),
443
* except that the label can't be NULL; digits will be appended to the label
444
* if needed to create a name that is unique within the specified namespace.
446
* 'others' can be a list of string names already chosen within the current
447
* command (but not yet reflected into the catalogs); we will not choose
448
* a duplicate of one of these either.
450
* Note: it is theoretically possible to get a collision anyway, if someone
451
* else chooses the same name concurrently. This is fairly unlikely to be
452
* a problem in practice, especially if one is holding an exclusive lock on
453
* the relation identified by name1.
455
* Returns a palloc'd string.
458
ChooseConstraintName(const char *name1, const char *name2,
459
const char *label, Oid namespaceid,
463
char *conname = NULL;
464
char modlabel[NAMEDATALEN];
471
conDesc = heap_open(ConstraintRelationId, AccessShareLock);
473
/* try the unmodified label first */
474
StrNCpy(modlabel, label, sizeof(modlabel));
478
conname = makeObjectName(name1, name2, modlabel);
484
if (strcmp((char *) lfirst(l), conname) == 0)
493
ScanKeyInit(&skey[0],
494
Anum_pg_constraint_conname,
495
BTEqualStrategyNumber, F_NAMEEQ,
496
CStringGetDatum(conname));
498
ScanKeyInit(&skey[1],
499
Anum_pg_constraint_connamespace,
500
BTEqualStrategyNumber, F_OIDEQ,
501
ObjectIdGetDatum(namespaceid));
503
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
504
SnapshotNow, 2, skey);
506
found = (HeapTupleIsValid(systable_getnext(conscan)));
508
systable_endscan(conscan);
514
/* found a conflict, so try a new name component */
516
snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
519
heap_close(conDesc, AccessShareLock);
525
* Delete a single constraint record.
528
RemoveConstraintById(Oid conId)
532
Form_pg_constraint con;
534
conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
536
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
537
if (!HeapTupleIsValid(tup)) /* should not happen */
538
elog(ERROR, "cache lookup failed for constraint %u", conId);
539
con = (Form_pg_constraint) GETSTRUCT(tup);
542
* Special processing depending on what the constraint is for.
544
if (OidIsValid(con->conrelid))
549
* If the constraint is for a relation, open and exclusive-lock the
552
rel = heap_open(con->conrelid, AccessExclusiveLock);
555
* We need to update the relcheck count if it is a check constraint
556
* being dropped. This update will force backends to rebuild relcache
557
* entries when we commit.
559
if (con->contype == CONSTRAINT_CHECK)
563
Form_pg_class classForm;
565
pgrel = heap_open(RelationRelationId, RowExclusiveLock);
566
relTup = SearchSysCacheCopy1(RELOID,
567
ObjectIdGetDatum(con->conrelid));
568
if (!HeapTupleIsValid(relTup))
569
elog(ERROR, "cache lookup failed for relation %u",
571
classForm = (Form_pg_class) GETSTRUCT(relTup);
573
if (classForm->relchecks == 0) /* should not happen */
574
elog(ERROR, "relation \"%s\" has relchecks = 0",
575
RelationGetRelationName(rel));
576
classForm->relchecks--;
578
simple_heap_update(pgrel, &relTup->t_self, relTup);
580
CatalogUpdateIndexes(pgrel, relTup);
582
heap_freetuple(relTup);
584
heap_close(pgrel, RowExclusiveLock);
587
/* Keep lock on constraint's rel until end of xact */
588
heap_close(rel, NoLock);
590
else if (OidIsValid(con->contypid))
593
* XXX for now, do nothing special when dropping a domain constraint
595
* Probably there should be some form of locking on the domain type,
596
* but we have no such concept at the moment.
600
elog(ERROR, "constraint %u is not of a known type", conId);
602
/* Fry the constraint itself */
603
simple_heap_delete(conDesc, &tup->t_self);
606
ReleaseSysCache(tup);
607
heap_close(conDesc, RowExclusiveLock);
611
* RenameConstraintById
612
* Rename a constraint.
614
* Note: this isn't intended to be a user-exposed function; it doesn't check
615
* permissions etc. Currently this is only invoked when renaming an index
616
* that is associated with a constraint, but it's made a little more general
617
* than that with the expectation of someday having ALTER TABLE RENAME
621
RenameConstraintById(Oid conId, const char *newname)
625
Form_pg_constraint con;
627
conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
629
tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
630
if (!HeapTupleIsValid(tuple))
631
elog(ERROR, "cache lookup failed for constraint %u", conId);
632
con = (Form_pg_constraint) GETSTRUCT(tuple);
635
* We need to check whether the name is already in use --- note that there
636
* currently is not a unique index that would catch this.
638
if (OidIsValid(con->conrelid) &&
639
ConstraintNameIsUsed(CONSTRAINT_RELATION,
644
(errcode(ERRCODE_DUPLICATE_OBJECT),
645
errmsg("constraint \"%s\" for relation \"%s\" already exists",
646
newname, get_rel_name(con->conrelid))));
647
if (OidIsValid(con->contypid) &&
648
ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
653
(errcode(ERRCODE_DUPLICATE_OBJECT),
654
errmsg("constraint \"%s\" for domain \"%s\" already exists",
655
newname, format_type_be(con->contypid))));
657
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
658
namestrcpy(&(con->conname), newname);
660
simple_heap_update(conDesc, &tuple->t_self, tuple);
662
/* update the system catalog indexes */
663
CatalogUpdateIndexes(conDesc, tuple);
665
heap_freetuple(tuple);
666
heap_close(conDesc, RowExclusiveLock);
670
* AlterConstraintNamespaces
671
* Find any constraints belonging to the specified object,
672
* and move them to the specified new namespace.
674
* isType indicates whether the owning object is a type or a relation.
677
AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
678
Oid newNspId, bool isType)
685
conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
690
Anum_pg_constraint_contypid,
691
BTEqualStrategyNumber, F_OIDEQ,
692
ObjectIdGetDatum(ownerId));
694
scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
695
SnapshotNow, 1, key);
700
Anum_pg_constraint_conrelid,
701
BTEqualStrategyNumber, F_OIDEQ,
702
ObjectIdGetDatum(ownerId));
704
scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
705
SnapshotNow, 1, key);
708
while (HeapTupleIsValid((tup = systable_getnext(scan))))
710
Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
712
if (conform->connamespace == oldNspId)
714
tup = heap_copytuple(tup);
715
conform = (Form_pg_constraint) GETSTRUCT(tup);
717
conform->connamespace = newNspId;
719
simple_heap_update(conRel, &tup->t_self, tup);
720
CatalogUpdateIndexes(conRel, tup);
723
* Note: currently, the constraint will not have its own
724
* dependency on the namespace, so we don't need to do
725
* changeDependencyFor().
730
systable_endscan(scan);
732
heap_close(conRel, RowExclusiveLock);
737
* Find a constraint on the specified relation with the specified name.
738
* Returns constraint's OID.
741
get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
743
Relation pg_constraint;
747
Oid conOid = InvalidOid;
750
* Fetch the constraint tuple from pg_constraint. There may be more than
751
* one match, because constraints are not required to have unique names;
754
pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
756
ScanKeyInit(&skey[0],
757
Anum_pg_constraint_conrelid,
758
BTEqualStrategyNumber, F_OIDEQ,
759
ObjectIdGetDatum(relid));
761
scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
762
SnapshotNow, 1, skey);
764
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
766
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
768
if (strcmp(NameStr(con->conname), conname) == 0)
770
if (OidIsValid(conOid))
772
(errcode(ERRCODE_DUPLICATE_OBJECT),
773
errmsg("table \"%s\" has multiple constraints named \"%s\"",
774
get_rel_name(relid), conname)));
775
conOid = HeapTupleGetOid(tuple);
779
systable_endscan(scan);
781
/* If no such constraint exists, complain */
782
if (!OidIsValid(conOid) && !missing_ok)
784
(errcode(ERRCODE_UNDEFINED_OBJECT),
785
errmsg("constraint \"%s\" for table \"%s\" does not exist",
786
conname, get_rel_name(relid))));
788
heap_close(pg_constraint, AccessShareLock);
794
* Determine whether a relation can be proven functionally dependent on
795
* a set of grouping columns. If so, return TRUE and add the pg_constraint
796
* OIDs of the constraints needed for the proof to the *constraintDeps list.
798
* grouping_columns is a list of grouping expressions, in which columns of
799
* the rel of interest are Vars with the indicated varno/varlevelsup.
801
* Currently we only check to see if the rel has a primary key that is a
802
* subset of the grouping_columns. We could also use plain unique constraints
803
* if all their columns are known not null, but there's a problem: we need
804
* to be able to represent the not-null-ness as part of the constraints added
805
* to *constraintDeps. FIXME whenever not-null constraints get represented
809
check_functional_grouping(Oid relid,
810
Index varno, Index varlevelsup,
811
List *grouping_columns,
812
List **constraintDeps)
815
Relation pg_constraint;
820
/* Scan pg_constraint for constraints of the target rel */
821
pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
823
ScanKeyInit(&skey[0],
824
Anum_pg_constraint_conrelid,
825
BTEqualStrategyNumber, F_OIDEQ,
826
ObjectIdGetDatum(relid));
828
scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
829
SnapshotNow, 1, skey);
831
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
833
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
842
/* Only PK constraints are of interest for now, see comment above */
843
if (con->contype != CONSTRAINT_PRIMARY)
845
/* Constraint must be non-deferrable */
846
if (con->condeferrable)
849
/* Extract the conkey array, ie, attnums of PK's columns */
850
adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
851
RelationGetDescr(pg_constraint), &isNull);
853
elog(ERROR, "null conkey for constraint %u",
854
HeapTupleGetOid(tuple));
855
arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
856
numkeys = ARR_DIMS(arr)[0];
857
if (ARR_NDIM(arr) != 1 ||
860
ARR_ELEMTYPE(arr) != INT2OID)
861
elog(ERROR, "conkey is not a 1-D smallint array");
862
attnums = (int16 *) ARR_DATA_PTR(arr);
865
for (i = 0; i < numkeys; i++)
867
AttrNumber attnum = attnums[i];
871
foreach(gl, grouping_columns)
873
Var *gvar = (Var *) lfirst(gl);
875
if (IsA(gvar, Var) &&
876
gvar->varno == varno &&
877
gvar->varlevelsup == varlevelsup &&
878
gvar->varattno == attnum)
890
/* The PK is a subset of grouping_columns, so we win */
891
*constraintDeps = lappend_oid(*constraintDeps,
892
HeapTupleGetOid(tuple));
898
systable_endscan(scan);
900
heap_close(pg_constraint, AccessShareLock);