PostgreSQL Source Code git master
pg_constraint.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_constraint.c
4 * routines to support manipulation of the pg_constraint relation
5 *
6 * Portions Copyright (c) 1996-2025, 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/gist.h"
19#include "access/htup_details.h"
20#include "access/sysattr.h"
21#include "access/table.h"
22#include "catalog/catalog.h"
23#include "catalog/dependency.h"
24#include "catalog/heap.h"
25#include "catalog/indexing.h"
28#include "catalog/pg_operator.h"
29#include "catalog/pg_type.h"
30#include "commands/defrem.h"
31#include "common/int.h"
32#include "utils/array.h"
33#include "utils/builtins.h"
34#include "utils/fmgroids.h"
35#include "utils/lsyscache.h"
36#include "utils/rel.h"
37#include "utils/syscache.h"
38
39
40/*
41 * CreateConstraintEntry
42 * Create a constraint table entry.
43 *
44 * Subsidiary records (such as triggers or indexes to implement the
45 * constraint) are *not* created here. But we do make dependency links
46 * from the constraint to the things it depends on.
47 *
48 * The new constraint's OID is returned.
49 */
50Oid
51CreateConstraintEntry(const char *constraintName,
52 Oid constraintNamespace,
53 char constraintType,
54 bool isDeferrable,
55 bool isDeferred,
56 bool isEnforced,
57 bool isValidated,
58 Oid parentConstrId,
59 Oid relId,
60 const int16 *constraintKey,
61 int constraintNKeys,
62 int constraintNTotalKeys,
63 Oid domainId,
64 Oid indexRelId,
65 Oid foreignRelId,
66 const int16 *foreignKey,
67 const Oid *pfEqOp,
68 const Oid *ppEqOp,
69 const Oid *ffEqOp,
70 int foreignNKeys,
71 char foreignUpdateType,
72 char foreignDeleteType,
73 const int16 *fkDeleteSetCols,
74 int numFkDeleteSetCols,
75 char foreignMatchType,
76 const Oid *exclOp,
77 Node *conExpr,
78 const char *conBin,
79 bool conIsLocal,
80 int16 conInhCount,
81 bool conNoInherit,
82 bool conPeriod,
83 bool is_internal)
84{
85 Relation conDesc;
86 Oid conOid;
87 HeapTuple tup;
88 bool nulls[Natts_pg_constraint];
89 Datum values[Natts_pg_constraint];
90 ArrayType *conkeyArray;
91 ArrayType *confkeyArray;
92 ArrayType *conpfeqopArray;
93 ArrayType *conppeqopArray;
94 ArrayType *conffeqopArray;
95 ArrayType *conexclopArray;
96 ArrayType *confdelsetcolsArray;
98 int i;
99 ObjectAddress conobject;
100 ObjectAddresses *addrs_auto;
101 ObjectAddresses *addrs_normal;
102
103 /* Only CHECK constraint can be not enforced */
104 Assert(isEnforced || constraintType == CONSTRAINT_CHECK);
105 /* NOT ENFORCED constraint must be NOT VALID */
106 Assert(isEnforced || !isValidated);
107
108 conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
109
110 Assert(constraintName);
111 namestrcpy(&cname, constraintName);
112
113 /*
114 * Convert C arrays into Postgres arrays.
115 */
116 if (constraintNKeys > 0)
117 {
118 Datum *conkey;
119
120 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
121 for (i = 0; i < constraintNKeys; i++)
122 conkey[i] = Int16GetDatum(constraintKey[i]);
123 conkeyArray = construct_array_builtin(conkey, constraintNKeys, INT2OID);
124 }
125 else
126 conkeyArray = NULL;
127
128 if (foreignNKeys > 0)
129 {
130 Datum *fkdatums;
131
132 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
133 for (i = 0; i < foreignNKeys; i++)
134 fkdatums[i] = Int16GetDatum(foreignKey[i]);
135 confkeyArray = construct_array_builtin(fkdatums, foreignNKeys, INT2OID);
136 for (i = 0; i < foreignNKeys; i++)
137 fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
138 conpfeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
139 for (i = 0; i < foreignNKeys; i++)
140 fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
141 conppeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
142 for (i = 0; i < foreignNKeys; i++)
143 fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
144 conffeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
145
146 if (numFkDeleteSetCols > 0)
147 {
148 for (i = 0; i < numFkDeleteSetCols; i++)
149 fkdatums[i] = Int16GetDatum(fkDeleteSetCols[i]);
150 confdelsetcolsArray = construct_array_builtin(fkdatums, numFkDeleteSetCols, INT2OID);
151 }
152 else
153 confdelsetcolsArray = NULL;
154 }
155 else
156 {
157 confkeyArray = NULL;
158 conpfeqopArray = NULL;
159 conppeqopArray = NULL;
160 conffeqopArray = NULL;
161 confdelsetcolsArray = NULL;
162 }
163
164 if (exclOp != NULL)
165 {
166 Datum *opdatums;
167
168 opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
169 for (i = 0; i < constraintNKeys; i++)
170 opdatums[i] = ObjectIdGetDatum(exclOp[i]);
171 conexclopArray = construct_array_builtin(opdatums, constraintNKeys, OIDOID);
172 }
173 else
174 conexclopArray = NULL;
175
176 /* initialize nulls and values */
177 for (i = 0; i < Natts_pg_constraint; i++)
178 {
179 nulls[i] = false;
180 values[i] = (Datum) NULL;
181 }
182
183 conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId,
184 Anum_pg_constraint_oid);
185 values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid);
186 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
187 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
188 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
189 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
190 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
191 values[Anum_pg_constraint_conenforced - 1] = BoolGetDatum(isEnforced);
192 values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
193 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
194 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
195 values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
196 values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId);
197 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
198 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
199 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
200 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
201 values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
202 values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount);
203 values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
204 values[Anum_pg_constraint_conperiod - 1] = BoolGetDatum(conPeriod);
205
206 if (conkeyArray)
207 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
208 else
209 nulls[Anum_pg_constraint_conkey - 1] = true;
210
211 if (confkeyArray)
212 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
213 else
214 nulls[Anum_pg_constraint_confkey - 1] = true;
215
216 if (conpfeqopArray)
217 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
218 else
219 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
220
221 if (conppeqopArray)
222 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
223 else
224 nulls[Anum_pg_constraint_conppeqop - 1] = true;
225
226 if (conffeqopArray)
227 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
228 else
229 nulls[Anum_pg_constraint_conffeqop - 1] = true;
230
231 if (confdelsetcolsArray)
232 values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray);
233 else
234 nulls[Anum_pg_constraint_confdelsetcols - 1] = true;
235
236 if (conexclopArray)
237 values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
238 else
239 nulls[Anum_pg_constraint_conexclop - 1] = true;
240
241 if (conBin)
242 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
243 else
244 nulls[Anum_pg_constraint_conbin - 1] = true;
245
246 tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
247
248 CatalogTupleInsert(conDesc, tup);
249
250 ObjectAddressSet(conobject, ConstraintRelationId, conOid);
251
253
254 /* Handle set of auto dependencies */
255 addrs_auto = new_object_addresses();
256
257 if (OidIsValid(relId))
258 {
259 /*
260 * Register auto dependency from constraint to owning relation, or to
261 * specific column(s) if any are mentioned.
262 */
263 ObjectAddress relobject;
264
265 if (constraintNTotalKeys > 0)
266 {
267 for (i = 0; i < constraintNTotalKeys; i++)
268 {
269 ObjectAddressSubSet(relobject, RelationRelationId, relId,
270 constraintKey[i]);
271 add_exact_object_address(&relobject, addrs_auto);
272 }
273 }
274 else
275 {
276 ObjectAddressSet(relobject, RelationRelationId, relId);
277 add_exact_object_address(&relobject, addrs_auto);
278 }
279 }
280
281 if (OidIsValid(domainId))
282 {
283 /*
284 * Register auto dependency from constraint to owning domain
285 */
286 ObjectAddress domobject;
287
288 ObjectAddressSet(domobject, TypeRelationId, domainId);
289 add_exact_object_address(&domobject, addrs_auto);
290 }
291
292 record_object_address_dependencies(&conobject, addrs_auto,
294 free_object_addresses(addrs_auto);
295
296 /* Handle set of normal dependencies */
297 addrs_normal = new_object_addresses();
298
299 if (OidIsValid(foreignRelId))
300 {
301 /*
302 * Register normal dependency from constraint to foreign relation, or
303 * to specific column(s) if any are mentioned.
304 */
305 ObjectAddress relobject;
306
307 if (foreignNKeys > 0)
308 {
309 for (i = 0; i < foreignNKeys; i++)
310 {
311 ObjectAddressSubSet(relobject, RelationRelationId,
312 foreignRelId, foreignKey[i]);
313 add_exact_object_address(&relobject, addrs_normal);
314 }
315 }
316 else
317 {
318 ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
319 add_exact_object_address(&relobject, addrs_normal);
320 }
321 }
322
323 if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
324 {
325 /*
326 * Register normal dependency on the unique index that supports a
327 * foreign-key constraint. (Note: for indexes associated with unique
328 * or primary-key constraints, the dependency runs the other way, and
329 * is not made here.)
330 */
331 ObjectAddress relobject;
332
333 ObjectAddressSet(relobject, RelationRelationId, indexRelId);
334 add_exact_object_address(&relobject, addrs_normal);
335 }
336
337 if (foreignNKeys > 0)
338 {
339 /*
340 * Register normal dependencies on the equality operators that support
341 * a foreign-key constraint. If the PK and FK types are the same then
342 * all three operators for a column are the same; otherwise they are
343 * different.
344 */
345 ObjectAddress oprobject;
346
347 oprobject.classId = OperatorRelationId;
348 oprobject.objectSubId = 0;
349
350 for (i = 0; i < foreignNKeys; i++)
351 {
352 oprobject.objectId = pfEqOp[i];
353 add_exact_object_address(&oprobject, addrs_normal);
354 if (ppEqOp[i] != pfEqOp[i])
355 {
356 oprobject.objectId = ppEqOp[i];
357 add_exact_object_address(&oprobject, addrs_normal);
358 }
359 if (ffEqOp[i] != pfEqOp[i])
360 {
361 oprobject.objectId = ffEqOp[i];
362 add_exact_object_address(&oprobject, addrs_normal);
363 }
364 }
365 }
366
367 record_object_address_dependencies(&conobject, addrs_normal,
369 free_object_addresses(addrs_normal);
370
371 /*
372 * We don't bother to register dependencies on the exclusion operators of
373 * an exclusion constraint. We assume they are members of the opclass
374 * supporting the index, so there's an indirect dependency via that. (This
375 * would be pretty dicey for cross-type operators, but exclusion operators
376 * can never be cross-type.)
377 */
378
379 if (conExpr != NULL)
380 {
381 /*
382 * Register dependencies from constraint to objects mentioned in CHECK
383 * expression.
384 */
385 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
387 DEPENDENCY_NORMAL, false);
388 }
389
390 /* Post creation hook for new constraint */
391 InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
392 is_internal);
393
394 return conOid;
395}
396
397/*
398 * Test whether given name is currently used as a constraint name
399 * for the given object (relation or domain).
400 *
401 * This is used to decide whether to accept a user-specified constraint name.
402 * It is deliberately not the same test as ChooseConstraintName uses to decide
403 * whether an auto-generated name is OK: here, we will allow it unless there
404 * is an identical constraint name in use *on the same object*.
405 *
406 * NB: Caller should hold exclusive lock on the given object, else
407 * this test can be fooled by concurrent additions.
408 */
409bool
411 const char *conname)
412{
413 bool found;
414 Relation conDesc;
415 SysScanDesc conscan;
416 ScanKeyData skey[3];
417
418 conDesc = table_open(ConstraintRelationId, AccessShareLock);
419
420 ScanKeyInit(&skey[0],
421 Anum_pg_constraint_conrelid,
422 BTEqualStrategyNumber, F_OIDEQ,
424 ? objId : InvalidOid));
425 ScanKeyInit(&skey[1],
426 Anum_pg_constraint_contypid,
427 BTEqualStrategyNumber, F_OIDEQ,
429 ? objId : InvalidOid));
430 ScanKeyInit(&skey[2],
431 Anum_pg_constraint_conname,
432 BTEqualStrategyNumber, F_NAMEEQ,
433 CStringGetDatum(conname));
434
435 conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId,
436 true, NULL, 3, skey);
437
438 /* There can be at most one matching row */
439 found = (HeapTupleIsValid(systable_getnext(conscan)));
440
441 systable_endscan(conscan);
443
444 return found;
445}
446
447/*
448 * Does any constraint of the given name exist in the given namespace?
449 *
450 * This is used for code that wants to match ChooseConstraintName's rule
451 * that we should avoid autogenerating duplicate constraint names within a
452 * namespace.
453 */
454bool
455ConstraintNameExists(const char *conname, Oid namespaceid)
456{
457 bool found;
458 Relation conDesc;
459 SysScanDesc conscan;
460 ScanKeyData skey[2];
461
462 conDesc = table_open(ConstraintRelationId, AccessShareLock);
463
464 ScanKeyInit(&skey[0],
465 Anum_pg_constraint_conname,
466 BTEqualStrategyNumber, F_NAMEEQ,
467 CStringGetDatum(conname));
468
469 ScanKeyInit(&skey[1],
470 Anum_pg_constraint_connamespace,
471 BTEqualStrategyNumber, F_OIDEQ,
472 ObjectIdGetDatum(namespaceid));
473
474 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
475 NULL, 2, skey);
476
477 found = (HeapTupleIsValid(systable_getnext(conscan)));
478
479 systable_endscan(conscan);
481
482 return found;
483}
484
485/*
486 * Select a nonconflicting name for a new constraint.
487 *
488 * The objective here is to choose a name that is unique within the
489 * specified namespace. Postgres does not require this, but the SQL
490 * spec does, and some apps depend on it. Therefore we avoid choosing
491 * default names that so conflict.
492 *
493 * name1, name2, and label are used the same way as for makeObjectName(),
494 * except that the label can't be NULL; digits will be appended to the label
495 * if needed to create a name that is unique within the specified namespace.
496 *
497 * 'others' can be a list of string names already chosen within the current
498 * command (but not yet reflected into the catalogs); we will not choose
499 * a duplicate of one of these either.
500 *
501 * Note: it is theoretically possible to get a collision anyway, if someone
502 * else chooses the same name concurrently. This is fairly unlikely to be
503 * a problem in practice, especially if one is holding an exclusive lock on
504 * the relation identified by name1.
505 *
506 * Returns a palloc'd string.
507 */
508char *
509ChooseConstraintName(const char *name1, const char *name2,
510 const char *label, Oid namespaceid,
511 List *others)
512{
513 int pass = 0;
514 char *conname = NULL;
515 char modlabel[NAMEDATALEN];
516 Relation conDesc;
517 SysScanDesc conscan;
518 ScanKeyData skey[2];
519 bool found;
520 ListCell *l;
521
522 conDesc = table_open(ConstraintRelationId, AccessShareLock);
523
524 /* try the unmodified label first */
525 strlcpy(modlabel, label, sizeof(modlabel));
526
527 for (;;)
528 {
529 conname = makeObjectName(name1, name2, modlabel);
530
531 found = false;
532
533 foreach(l, others)
534 {
535 if (strcmp((char *) lfirst(l), conname) == 0)
536 {
537 found = true;
538 break;
539 }
540 }
541
542 if (!found)
543 {
544 ScanKeyInit(&skey[0],
545 Anum_pg_constraint_conname,
546 BTEqualStrategyNumber, F_NAMEEQ,
547 CStringGetDatum(conname));
548
549 ScanKeyInit(&skey[1],
550 Anum_pg_constraint_connamespace,
551 BTEqualStrategyNumber, F_OIDEQ,
552 ObjectIdGetDatum(namespaceid));
553
554 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
555 NULL, 2, skey);
556
557 found = (HeapTupleIsValid(systable_getnext(conscan)));
558
559 systable_endscan(conscan);
560 }
561
562 if (!found)
563 break;
564
565 /* found a conflict, so try a new name component */
566 pfree(conname);
567 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
568 }
569
571
572 return conname;
573}
574
575/*
576 * Find and return a copy of the pg_constraint tuple that implements a
577 * validated not-null constraint for the given column of the given relation.
578 * If no such constraint exists, return NULL.
579 *
580 * XXX This would be easier if we had pg_attribute.notnullconstr with the OID
581 * of the constraint that implements the not-null constraint for that column.
582 * I'm not sure it's worth the catalog bloat and de-normalization, however.
583 */
586{
587 Relation pg_constraint;
588 HeapTuple conTup,
589 retval = NULL;
590 SysScanDesc scan;
592
593 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
595 Anum_pg_constraint_conrelid,
596 BTEqualStrategyNumber, F_OIDEQ,
597 ObjectIdGetDatum(relid));
598 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
599 true, NULL, 1, &key);
600
601 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
602 {
604 AttrNumber conkey;
605
606 /*
607 * We're looking for a NOTNULL constraint that's marked validated,
608 * with the column we're looking for as the sole element in conkey.
609 */
610 if (con->contype != CONSTRAINT_NOTNULL)
611 continue;
612 if (!con->convalidated)
613 continue;
614
615 conkey = extractNotNullColumn(conTup);
616 if (conkey != attnum)
617 continue;
618
619 /* Found it */
620 retval = heap_copytuple(conTup);
621 break;
622 }
623
624 systable_endscan(scan);
625 table_close(pg_constraint, AccessShareLock);
626
627 return retval;
628}
629
630/*
631 * Find and return the pg_constraint tuple that implements a validated
632 * not-null constraint for the given column of the given relation. If
633 * no such column or no such constraint exists, return NULL.
634 */
636findNotNullConstraint(Oid relid, const char *colname)
637{
639
640 attnum = get_attnum(relid, colname);
642 return NULL;
643
644 return findNotNullConstraintAttnum(relid, attnum);
645}
646
647/*
648 * Find and return the pg_constraint tuple that implements a validated
649 * not-null constraint for the given domain.
650 */
653{
654 Relation pg_constraint;
655 HeapTuple conTup,
656 retval = NULL;
657 SysScanDesc scan;
659
660 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
662 Anum_pg_constraint_contypid,
663 BTEqualStrategyNumber, F_OIDEQ,
664 ObjectIdGetDatum(typid));
665 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
666 true, NULL, 1, &key);
667
668 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
669 {
671
672 /*
673 * We're looking for a NOTNULL constraint that's marked validated.
674 */
675 if (con->contype != CONSTRAINT_NOTNULL)
676 continue;
677 if (!con->convalidated)
678 continue;
679
680 /* Found it */
681 retval = heap_copytuple(conTup);
682 break;
683 }
684
685 systable_endscan(scan);
686 table_close(pg_constraint, AccessShareLock);
687
688 return retval;
689}
690
691/*
692 * Given a pg_constraint tuple for a not-null constraint, return the column
693 * number it is for.
694 */
697{
698 Datum adatum;
699 ArrayType *arr;
700
701 /* only tuples for not-null constraints should be given */
702 Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL);
703
704 adatum = SysCacheGetAttrNotNull(CONSTROID, constrTup,
705 Anum_pg_constraint_conkey);
706 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
707 if (ARR_NDIM(arr) != 1 ||
708 ARR_HASNULL(arr) ||
709 ARR_ELEMTYPE(arr) != INT2OID ||
710 ARR_DIMS(arr)[0] != 1)
711 elog(ERROR, "conkey is not a 1-D smallint array");
712
713 /* We leak the detoasted datum, but we don't care */
714
715 return ((AttrNumber *) ARR_DATA_PTR(arr))[0];
716}
717
718/*
719 * AdjustNotNullInheritance
720 * Adjust inheritance status for a single not-null constraint
721 *
722 * If no not-null constraint is found for the column, return false.
723 * Caller can create one.
724 * If a constraint exists but the connoinherit flag is not what the caller
725 * wants, throw an error about the incompatibility. Otherwise, we adjust
726 * conislocal/coninhcount and return true.
727 * In the latter case, if is_local is true we flip conislocal true, or do
728 * nothing if it's already true; otherwise we increment coninhcount by 1.
729 */
730bool
732 bool is_local, bool is_no_inherit)
733{
734 HeapTuple tup;
735
737 if (HeapTupleIsValid(tup))
738 {
739 Relation pg_constraint;
740 Form_pg_constraint conform;
741 bool changed = false;
742
743 pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
744 conform = (Form_pg_constraint) GETSTRUCT(tup);
745
746 /*
747 * If the NO INHERIT flag we're asked for doesn't match what the
748 * existing constraint has, throw an error.
749 */
750 if (is_no_inherit != conform->connoinherit)
752 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
753 errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"",
754 NameStr(conform->conname), get_rel_name(relid)));
755
756 if (!is_local)
757 {
758 if (pg_add_s16_overflow(conform->coninhcount, 1,
759 &conform->coninhcount))
761 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
762 errmsg("too many inheritance parents"));
763 changed = true;
764 }
765 else if (!conform->conislocal)
766 {
767 conform->conislocal = true;
768 changed = true;
769 }
770
771 if (changed)
772 CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
773
774 table_close(pg_constraint, RowExclusiveLock);
775
776 return true;
777 }
778
779 return false;
780}
781
782/*
783 * RelationGetNotNullConstraints
784 * Return the list of not-null constraints for the given rel
785 *
786 * Caller can request cooked constraints, or raw.
787 *
788 * This is seldom needed, so we just scan pg_constraint each time.
789 *
790 * 'include_noinh' determines whether to include NO INHERIT constraints or not.
791 */
792List *
793RelationGetNotNullConstraints(Oid relid, bool cooked, bool include_noinh)
794{
795 List *notnulls = NIL;
796 Relation constrRel;
797 HeapTuple htup;
798 SysScanDesc conscan;
799 ScanKeyData skey;
800
801 constrRel = table_open(ConstraintRelationId, AccessShareLock);
802 ScanKeyInit(&skey,
803 Anum_pg_constraint_conrelid,
804 BTEqualStrategyNumber, F_OIDEQ,
805 ObjectIdGetDatum(relid));
806 conscan = systable_beginscan(constrRel, ConstraintRelidTypidNameIndexId, true,
807 NULL, 1, &skey);
808
809 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
810 {
812 AttrNumber colnum;
813
814 if (conForm->contype != CONSTRAINT_NOTNULL)
815 continue;
816 if (conForm->connoinherit && !include_noinh)
817 continue;
818
819 colnum = extractNotNullColumn(htup);
820
821 if (cooked)
822 {
823 CookedConstraint *cooked;
824
825 cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
826
827 cooked->contype = CONSTR_NOTNULL;
828 cooked->conoid = conForm->oid;
829 cooked->name = pstrdup(NameStr(conForm->conname));
830 cooked->attnum = colnum;
831 cooked->expr = NULL;
832 cooked->is_enforced = true;
833 cooked->skip_validation = false;
834 cooked->is_local = true;
835 cooked->inhcount = 0;
836 cooked->is_no_inherit = conForm->connoinherit;
837
838 notnulls = lappend(notnulls, cooked);
839 }
840 else
841 {
842 Constraint *constr;
843
844 constr = makeNode(Constraint);
845 constr->contype = CONSTR_NOTNULL;
846 constr->conname = pstrdup(NameStr(conForm->conname));
847 constr->deferrable = false;
848 constr->initdeferred = false;
849 constr->location = -1;
850 constr->keys = list_make1(makeString(get_attname(relid, colnum,
851 false)));
852 constr->is_enforced = true;
853 constr->skip_validation = false;
854 constr->initially_valid = true;
855 constr->is_no_inherit = conForm->connoinherit;
856 notnulls = lappend(notnulls, constr);
857 }
858 }
859
860 systable_endscan(conscan);
861 table_close(constrRel, AccessShareLock);
862
863 return notnulls;
864}
865
866
867/*
868 * Delete a single constraint record.
869 */
870void
872{
873 Relation conDesc;
874 HeapTuple tup;
876
877 conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
878
879 tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
880 if (!HeapTupleIsValid(tup)) /* should not happen */
881 elog(ERROR, "cache lookup failed for constraint %u", conId);
882 con = (Form_pg_constraint) GETSTRUCT(tup);
883
884 /*
885 * Special processing depending on what the constraint is for.
886 */
887 if (OidIsValid(con->conrelid))
888 {
889 Relation rel;
890
891 /*
892 * If the constraint is for a relation, open and exclusive-lock the
893 * relation it's for.
894 */
895 rel = table_open(con->conrelid, AccessExclusiveLock);
896
897 /*
898 * We need to update the relchecks count if it is a check constraint
899 * being dropped. This update will force backends to rebuild relcache
900 * entries when we commit.
901 */
902 if (con->contype == CONSTRAINT_CHECK)
903 {
904 Relation pgrel;
905 HeapTuple relTup;
906 Form_pg_class classForm;
907
908 pgrel = table_open(RelationRelationId, RowExclusiveLock);
909 relTup = SearchSysCacheCopy1(RELOID,
910 ObjectIdGetDatum(con->conrelid));
911 if (!HeapTupleIsValid(relTup))
912 elog(ERROR, "cache lookup failed for relation %u",
913 con->conrelid);
914 classForm = (Form_pg_class) GETSTRUCT(relTup);
915
916 if (classForm->relchecks == 0) /* should not happen */
917 elog(ERROR, "relation \"%s\" has relchecks = 0",
919 classForm->relchecks--;
920
921 CatalogTupleUpdate(pgrel, &relTup->t_self, relTup);
922
923 heap_freetuple(relTup);
924
926 }
927
928 /* Keep lock on constraint's rel until end of xact */
929 table_close(rel, NoLock);
930 }
931 else if (OidIsValid(con->contypid))
932 {
933 /*
934 * XXX for now, do nothing special when dropping a domain constraint
935 *
936 * Probably there should be some form of locking on the domain type,
937 * but we have no such concept at the moment.
938 */
939 }
940 else
941 elog(ERROR, "constraint %u is not of a known type", conId);
942
943 /* Fry the constraint itself */
944 CatalogTupleDelete(conDesc, &tup->t_self);
945
946 /* Clean up */
947 ReleaseSysCache(tup);
949}
950
951/*
952 * RenameConstraintById
953 * Rename a constraint.
954 *
955 * Note: this isn't intended to be a user-exposed function; it doesn't check
956 * permissions etc. Currently this is only invoked when renaming an index
957 * that is associated with a constraint, but it's made a little more general
958 * than that with the expectation of someday having ALTER TABLE RENAME
959 * CONSTRAINT.
960 */
961void
962RenameConstraintById(Oid conId, const char *newname)
963{
964 Relation conDesc;
965 HeapTuple tuple;
967
968 conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
969
970 tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
971 if (!HeapTupleIsValid(tuple))
972 elog(ERROR, "cache lookup failed for constraint %u", conId);
973 con = (Form_pg_constraint) GETSTRUCT(tuple);
974
975 /*
976 * For user-friendliness, check whether the name is already in use.
977 */
978 if (OidIsValid(con->conrelid) &&
980 con->conrelid,
981 newname))
984 errmsg("constraint \"%s\" for relation \"%s\" already exists",
985 newname, get_rel_name(con->conrelid))));
986 if (OidIsValid(con->contypid) &&
988 con->contypid,
989 newname))
992 errmsg("constraint \"%s\" for domain %s already exists",
993 newname, format_type_be(con->contypid))));
994
995 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
996 namestrcpy(&(con->conname), newname);
997
998 CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
999
1000 InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
1001
1002 heap_freetuple(tuple);
1003 table_close(conDesc, RowExclusiveLock);
1004}
1005
1006/*
1007 * AlterConstraintNamespaces
1008 * Find any constraints belonging to the specified object,
1009 * and move them to the specified new namespace.
1010 *
1011 * isType indicates whether the owning object is a type or a relation.
1012 */
1013void
1015 Oid newNspId, bool isType, ObjectAddresses *objsMoved)
1016{
1017 Relation conRel;
1018 ScanKeyData key[2];
1019 SysScanDesc scan;
1020 HeapTuple tup;
1021
1022 conRel = table_open(ConstraintRelationId, RowExclusiveLock);
1023
1024 ScanKeyInit(&key[0],
1025 Anum_pg_constraint_conrelid,
1026 BTEqualStrategyNumber, F_OIDEQ,
1027 ObjectIdGetDatum(isType ? InvalidOid : ownerId));
1028 ScanKeyInit(&key[1],
1029 Anum_pg_constraint_contypid,
1030 BTEqualStrategyNumber, F_OIDEQ,
1031 ObjectIdGetDatum(isType ? ownerId : InvalidOid));
1032
1033 scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true,
1034 NULL, 2, key);
1035
1036 while (HeapTupleIsValid((tup = systable_getnext(scan))))
1037 {
1039 ObjectAddress thisobj;
1040
1041 ObjectAddressSet(thisobj, ConstraintRelationId, conform->oid);
1042
1043 if (object_address_present(&thisobj, objsMoved))
1044 continue;
1045
1046 /* Don't update if the object is already part of the namespace */
1047 if (conform->connamespace == oldNspId && oldNspId != newNspId)
1048 {
1049 tup = heap_copytuple(tup);
1050 conform = (Form_pg_constraint) GETSTRUCT(tup);
1051
1052 conform->connamespace = newNspId;
1053
1054 CatalogTupleUpdate(conRel, &tup->t_self, tup);
1055
1056 /*
1057 * Note: currently, the constraint will not have its own
1058 * dependency on the namespace, so we don't need to do
1059 * changeDependencyFor().
1060 */
1061 }
1062
1063 InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
1064
1065 add_exact_object_address(&thisobj, objsMoved);
1066 }
1067
1068 systable_endscan(scan);
1069
1071}
1072
1073/*
1074 * ConstraintSetParentConstraint
1075 * Set a partition's constraint as child of its parent constraint,
1076 * or remove the linkage if parentConstrId is InvalidOid.
1077 *
1078 * This updates the constraint's pg_constraint row to show it as inherited, and
1079 * adds PARTITION dependencies to prevent the constraint from being deleted
1080 * on its own. Alternatively, reverse that.
1081 */
1082void
1084 Oid parentConstrId,
1085 Oid childTableId)
1086{
1087 Relation constrRel;
1088 Form_pg_constraint constrForm;
1089 HeapTuple tuple,
1090 newtup;
1091 ObjectAddress depender;
1092 ObjectAddress referenced;
1093
1094 constrRel = table_open(ConstraintRelationId, RowExclusiveLock);
1095 tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId));
1096 if (!HeapTupleIsValid(tuple))
1097 elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
1098 newtup = heap_copytuple(tuple);
1099 constrForm = (Form_pg_constraint) GETSTRUCT(newtup);
1100 if (OidIsValid(parentConstrId))
1101 {
1102 /* don't allow setting parent for a constraint that already has one */
1103 Assert(constrForm->coninhcount == 0);
1104 if (constrForm->conparentid != InvalidOid)
1105 elog(ERROR, "constraint %u already has a parent constraint",
1106 childConstrId);
1107
1108 constrForm->conislocal = false;
1109 if (pg_add_s16_overflow(constrForm->coninhcount, 1,
1110 &constrForm->coninhcount))
1111 ereport(ERROR,
1112 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1113 errmsg("too many inheritance parents"));
1114
1115 constrForm->conparentid = parentConstrId;
1116
1117 CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1118
1119 ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
1120
1121 ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
1122 recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
1123
1124 ObjectAddressSet(referenced, RelationRelationId, childTableId);
1125 recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
1126 }
1127 else
1128 {
1129 constrForm->coninhcount--;
1130 constrForm->conislocal = true;
1131 constrForm->conparentid = InvalidOid;
1132
1133 /* Make sure there's no further inheritance. */
1134 Assert(constrForm->coninhcount == 0);
1135
1136 CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1137
1138 deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1139 ConstraintRelationId,
1141 deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1142 RelationRelationId,
1144 }
1145
1146 ReleaseSysCache(tuple);
1147 table_close(constrRel, RowExclusiveLock);
1148}
1149
1150
1151/*
1152 * get_relation_constraint_oid
1153 * Find a constraint on the specified relation with the specified name.
1154 * Returns constraint's OID.
1155 */
1156Oid
1157get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
1158{
1159 Relation pg_constraint;
1160 HeapTuple tuple;
1161 SysScanDesc scan;
1162 ScanKeyData skey[3];
1163 Oid conOid = InvalidOid;
1164
1165 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1166
1167 ScanKeyInit(&skey[0],
1168 Anum_pg_constraint_conrelid,
1169 BTEqualStrategyNumber, F_OIDEQ,
1170 ObjectIdGetDatum(relid));
1171 ScanKeyInit(&skey[1],
1172 Anum_pg_constraint_contypid,
1173 BTEqualStrategyNumber, F_OIDEQ,
1175 ScanKeyInit(&skey[2],
1176 Anum_pg_constraint_conname,
1177 BTEqualStrategyNumber, F_NAMEEQ,
1178 CStringGetDatum(conname));
1179
1180 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1181 NULL, 3, skey);
1182
1183 /* There can be at most one matching row */
1184 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1185 conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1186
1187 systable_endscan(scan);
1188
1189 /* If no such constraint exists, complain */
1190 if (!OidIsValid(conOid) && !missing_ok)
1191 ereport(ERROR,
1192 (errcode(ERRCODE_UNDEFINED_OBJECT),
1193 errmsg("constraint \"%s\" for table \"%s\" does not exist",
1194 conname, get_rel_name(relid))));
1195
1196 table_close(pg_constraint, AccessShareLock);
1197
1198 return conOid;
1199}
1200
1201/*
1202 * get_relation_constraint_attnos
1203 * Find a constraint on the specified relation with the specified name
1204 * and return the constrained columns.
1205 *
1206 * Returns a Bitmapset of the column attnos of the constrained columns, with
1207 * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system
1208 * columns can be represented.
1209 *
1210 * *constraintOid is set to the OID of the constraint, or InvalidOid on
1211 * failure.
1212 */
1213Bitmapset *
1214get_relation_constraint_attnos(Oid relid, const char *conname,
1215 bool missing_ok, Oid *constraintOid)
1216{
1217 Bitmapset *conattnos = NULL;
1218 Relation pg_constraint;
1219 HeapTuple tuple;
1220 SysScanDesc scan;
1221 ScanKeyData skey[3];
1222
1223 /* Set *constraintOid, to avoid complaints about uninitialized vars */
1224 *constraintOid = InvalidOid;
1225
1226 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1227
1228 ScanKeyInit(&skey[0],
1229 Anum_pg_constraint_conrelid,
1230 BTEqualStrategyNumber, F_OIDEQ,
1231 ObjectIdGetDatum(relid));
1232 ScanKeyInit(&skey[1],
1233 Anum_pg_constraint_contypid,
1234 BTEqualStrategyNumber, F_OIDEQ,
1236 ScanKeyInit(&skey[2],
1237 Anum_pg_constraint_conname,
1238 BTEqualStrategyNumber, F_NAMEEQ,
1239 CStringGetDatum(conname));
1240
1241 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1242 NULL, 3, skey);
1243
1244 /* There can be at most one matching row */
1245 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1246 {
1247 Datum adatum;
1248 bool isNull;
1249
1250 *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1251
1252 /* Extract the conkey array, ie, attnums of constrained columns */
1253 adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1254 RelationGetDescr(pg_constraint), &isNull);
1255 if (!isNull)
1256 {
1257 ArrayType *arr;
1258 int numcols;
1259 int16 *attnums;
1260 int i;
1261
1262 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1263 numcols = ARR_DIMS(arr)[0];
1264 if (ARR_NDIM(arr) != 1 ||
1265 numcols < 0 ||
1266 ARR_HASNULL(arr) ||
1267 ARR_ELEMTYPE(arr) != INT2OID)
1268 elog(ERROR, "conkey is not a 1-D smallint array");
1269 attnums = (int16 *) ARR_DATA_PTR(arr);
1270
1271 /* Construct the result value */
1272 for (i = 0; i < numcols; i++)
1273 {
1274 conattnos = bms_add_member(conattnos,
1276 }
1277 }
1278 }
1279
1280 systable_endscan(scan);
1281
1282 /* If no such constraint exists, complain */
1283 if (!OidIsValid(*constraintOid) && !missing_ok)
1284 ereport(ERROR,
1285 (errcode(ERRCODE_UNDEFINED_OBJECT),
1286 errmsg("constraint \"%s\" for table \"%s\" does not exist",
1287 conname, get_rel_name(relid))));
1288
1289 table_close(pg_constraint, AccessShareLock);
1290
1291 return conattnos;
1292}
1293
1294/*
1295 * Return the OID of the constraint enforced by the given index in the
1296 * given relation; or InvalidOid if no such index is cataloged.
1297 *
1298 * Much like get_constraint_index, this function is concerned only with the
1299 * one constraint that "owns" the given index. Therefore, constraints of
1300 * types other than unique, primary-key, and exclusion are ignored.
1301 */
1302Oid
1304{
1305 Relation pg_constraint;
1306 SysScanDesc scan;
1308 HeapTuple tuple;
1309 Oid constraintId = InvalidOid;
1310
1311 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1312
1314 Anum_pg_constraint_conrelid,
1316 F_OIDEQ,
1317 ObjectIdGetDatum(relationId));
1318 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
1319 true, NULL, 1, &key);
1320 while ((tuple = systable_getnext(scan)) != NULL)
1321 {
1322 Form_pg_constraint constrForm;
1323
1324 constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
1325
1326 /* See above */
1327 if (constrForm->contype != CONSTRAINT_PRIMARY &&
1328 constrForm->contype != CONSTRAINT_UNIQUE &&
1329 constrForm->contype != CONSTRAINT_EXCLUSION)
1330 continue;
1331
1332 if (constrForm->conindid == indexId)
1333 {
1334 constraintId = constrForm->oid;
1335 break;
1336 }
1337 }
1338 systable_endscan(scan);
1339
1340 table_close(pg_constraint, AccessShareLock);
1341 return constraintId;
1342}
1343
1344/*
1345 * get_domain_constraint_oid
1346 * Find a constraint on the specified domain with the specified name.
1347 * Returns constraint's OID.
1348 */
1349Oid
1350get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
1351{
1352 Relation pg_constraint;
1353 HeapTuple tuple;
1354 SysScanDesc scan;
1355 ScanKeyData skey[3];
1356 Oid conOid = InvalidOid;
1357
1358 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1359
1360 ScanKeyInit(&skey[0],
1361 Anum_pg_constraint_conrelid,
1362 BTEqualStrategyNumber, F_OIDEQ,
1364 ScanKeyInit(&skey[1],
1365 Anum_pg_constraint_contypid,
1366 BTEqualStrategyNumber, F_OIDEQ,
1367 ObjectIdGetDatum(typid));
1368 ScanKeyInit(&skey[2],
1369 Anum_pg_constraint_conname,
1370 BTEqualStrategyNumber, F_NAMEEQ,
1371 CStringGetDatum(conname));
1372
1373 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1374 NULL, 3, skey);
1375
1376 /* There can be at most one matching row */
1377 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1378 conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1379
1380 systable_endscan(scan);
1381
1382 /* If no such constraint exists, complain */
1383 if (!OidIsValid(conOid) && !missing_ok)
1384 ereport(ERROR,
1385 (errcode(ERRCODE_UNDEFINED_OBJECT),
1386 errmsg("constraint \"%s\" for domain %s does not exist",
1387 conname, format_type_be(typid))));
1388
1389 table_close(pg_constraint, AccessShareLock);
1390
1391 return conOid;
1392}
1393
1394/*
1395 * get_primary_key_attnos
1396 * Identify the columns in a relation's primary key, if any.
1397 *
1398 * Returns a Bitmapset of the column attnos of the primary key's columns,
1399 * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
1400 * system columns can be represented.
1401 *
1402 * If there is no primary key, return NULL. We also return NULL if the pkey
1403 * constraint is deferrable and deferrableOk is false.
1404 *
1405 * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
1406 * on failure.
1407 */
1408Bitmapset *
1409get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
1410{
1411 Bitmapset *pkattnos = NULL;
1412 Relation pg_constraint;
1413 HeapTuple tuple;
1414 SysScanDesc scan;
1415 ScanKeyData skey[1];
1416
1417 /* Set *constraintOid, to avoid complaints about uninitialized vars */
1418 *constraintOid = InvalidOid;
1419
1420 /* Scan pg_constraint for constraints of the target rel */
1421 pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1422
1423 ScanKeyInit(&skey[0],
1424 Anum_pg_constraint_conrelid,
1425 BTEqualStrategyNumber, F_OIDEQ,
1426 ObjectIdGetDatum(relid));
1427
1428 scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1429 NULL, 1, skey);
1430
1431 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1432 {
1434 Datum adatum;
1435 bool isNull;
1436 ArrayType *arr;
1437 int16 *attnums;
1438 int numkeys;
1439 int i;
1440
1441 /* Skip constraints that are not PRIMARY KEYs */
1442 if (con->contype != CONSTRAINT_PRIMARY)
1443 continue;
1444
1445 /*
1446 * If the primary key is deferrable, but we've been instructed to
1447 * ignore deferrable constraints, then we might as well give up
1448 * searching, since there can only be a single primary key on a table.
1449 */
1450 if (con->condeferrable && !deferrableOk)
1451 break;
1452
1453 /* Extract the conkey array, ie, attnums of PK's columns */
1454 adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1455 RelationGetDescr(pg_constraint), &isNull);
1456 if (isNull)
1457 elog(ERROR, "null conkey for constraint %u",
1458 ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1459 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1460 numkeys = ARR_DIMS(arr)[0];
1461 if (ARR_NDIM(arr) != 1 ||
1462 numkeys < 0 ||
1463 ARR_HASNULL(arr) ||
1464 ARR_ELEMTYPE(arr) != INT2OID)
1465 elog(ERROR, "conkey is not a 1-D smallint array");
1466 attnums = (int16 *) ARR_DATA_PTR(arr);
1467
1468 /* Construct the result value */
1469 for (i = 0; i < numkeys; i++)
1470 {
1471 pkattnos = bms_add_member(pkattnos,
1473 }
1474 *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1475
1476 /* No need to search further */
1477 break;
1478 }
1479
1480 systable_endscan(scan);
1481
1482 table_close(pg_constraint, AccessShareLock);
1483
1484 return pkattnos;
1485}
1486
1487/*
1488 * Extract data from the pg_constraint tuple of a foreign-key constraint.
1489 *
1490 * All arguments save the first are output arguments. All output arguments
1491 * other than numfks, conkey and confkey can be passed as NULL if caller
1492 * doesn't need them.
1493 */
1494void
1496 AttrNumber *conkey, AttrNumber *confkey,
1497 Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
1498 int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
1499{
1500 Datum adatum;
1501 bool isNull;
1502 ArrayType *arr;
1503 int numkeys;
1504
1505 /*
1506 * We expect the arrays to be 1-D arrays of the right types; verify that.
1507 * We don't need to use deconstruct_array() since the array data is just
1508 * going to look like a C array of values.
1509 */
1510 adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1511 Anum_pg_constraint_conkey);
1512 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1513 if (ARR_NDIM(arr) != 1 ||
1514 ARR_HASNULL(arr) ||
1515 ARR_ELEMTYPE(arr) != INT2OID)
1516 elog(ERROR, "conkey is not a 1-D smallint array");
1517 numkeys = ARR_DIMS(arr)[0];
1518 if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS)
1519 elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1520 memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1521 if ((Pointer) arr != DatumGetPointer(adatum))
1522 pfree(arr); /* free de-toasted copy, if any */
1523
1524 adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1525 Anum_pg_constraint_confkey);
1526 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1527 if (ARR_NDIM(arr) != 1 ||
1528 ARR_DIMS(arr)[0] != numkeys ||
1529 ARR_HASNULL(arr) ||
1530 ARR_ELEMTYPE(arr) != INT2OID)
1531 elog(ERROR, "confkey is not a 1-D smallint array");
1532 memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1533 if ((Pointer) arr != DatumGetPointer(adatum))
1534 pfree(arr); /* free de-toasted copy, if any */
1535
1536 if (pf_eq_oprs)
1537 {
1538 adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1539 Anum_pg_constraint_conpfeqop);
1540 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1541 /* see TryReuseForeignKey if you change the test below */
1542 if (ARR_NDIM(arr) != 1 ||
1543 ARR_DIMS(arr)[0] != numkeys ||
1544 ARR_HASNULL(arr) ||
1545 ARR_ELEMTYPE(arr) != OIDOID)
1546 elog(ERROR, "conpfeqop is not a 1-D Oid array");
1547 memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1548 if ((Pointer) arr != DatumGetPointer(adatum))
1549 pfree(arr); /* free de-toasted copy, if any */
1550 }
1551
1552 if (pp_eq_oprs)
1553 {
1554 adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1555 Anum_pg_constraint_conppeqop);
1556 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1557 if (ARR_NDIM(arr) != 1 ||
1558 ARR_DIMS(arr)[0] != numkeys ||
1559 ARR_HASNULL(arr) ||
1560 ARR_ELEMTYPE(arr) != OIDOID)
1561 elog(ERROR, "conppeqop is not a 1-D Oid array");
1562 memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1563 if ((Pointer) arr != DatumGetPointer(adatum))
1564 pfree(arr); /* free de-toasted copy, if any */
1565 }
1566
1567 if (ff_eq_oprs)
1568 {
1569 adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1570 Anum_pg_constraint_conffeqop);
1571 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1572 if (ARR_NDIM(arr) != 1 ||
1573 ARR_DIMS(arr)[0] != numkeys ||
1574 ARR_HASNULL(arr) ||
1575 ARR_ELEMTYPE(arr) != OIDOID)
1576 elog(ERROR, "conffeqop is not a 1-D Oid array");
1577 memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1578 if ((Pointer) arr != DatumGetPointer(adatum))
1579 pfree(arr); /* free de-toasted copy, if any */
1580 }
1581
1582 if (fk_del_set_cols)
1583 {
1584 adatum = SysCacheGetAttr(CONSTROID, tuple,
1585 Anum_pg_constraint_confdelsetcols, &isNull);
1586 if (isNull)
1587 {
1588 *num_fk_del_set_cols = 0;
1589 }
1590 else
1591 {
1592 int num_delete_cols;
1593
1594 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1595 if (ARR_NDIM(arr) != 1 ||
1596 ARR_HASNULL(arr) ||
1597 ARR_ELEMTYPE(arr) != INT2OID)
1598 elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1599 num_delete_cols = ARR_DIMS(arr)[0];
1600 memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1601 if ((Pointer) arr != DatumGetPointer(adatum))
1602 pfree(arr); /* free de-toasted copy, if any */
1603
1604 *num_fk_del_set_cols = num_delete_cols;
1605 }
1606 }
1607
1608 *numfks = numkeys;
1609}
1610
1611/*
1612 * FindFKPeriodOpers -
1613 *
1614 * Looks up the operator oids used for the PERIOD part of a temporal foreign key.
1615 * The opclass should be the opclass of that PERIOD element.
1616 * Everything else is an output: containedbyoperoid is the ContainedBy operator for
1617 * types matching the PERIOD element.
1618 * aggedcontainedbyoperoid is also a ContainedBy operator,
1619 * but one whose rhs is a multirange.
1620 * That way foreign keys can compare fkattr <@ range_agg(pkattr).
1621 * intersectoperoid is used by NO ACTION constraints to trim the range being considered
1622 * to just what was updated/deleted.
1623 */
1624void
1626 Oid *containedbyoperoid,
1627 Oid *aggedcontainedbyoperoid,
1628 Oid *intersectoperoid)
1629{
1630 Oid opfamily = InvalidOid;
1631 Oid opcintype = InvalidOid;
1632 StrategyNumber strat;
1633
1634 /* Make sure we have a range or multirange. */
1635 if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1636 {
1637 if (opcintype != ANYRANGEOID && opcintype != ANYMULTIRANGEOID)
1638 ereport(ERROR,
1639 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1640 errmsg("invalid type for PERIOD part of foreign key"),
1641 errdetail("Only range and multirange are supported."));
1642
1643 }
1644 else
1645 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1646
1647 /*
1648 * Look up the ContainedBy operator whose lhs and rhs are the opclass's
1649 * type. We use this to optimize RI checks: if the new value includes all
1650 * of the old value, then we can treat the attribute as if it didn't
1651 * change, and skip the RI check.
1652 */
1654 InvalidOid,
1656 containedbyoperoid,
1657 &strat);
1658
1659 /*
1660 * Now look up the ContainedBy operator. Its left arg must be the type of
1661 * the column (or rather of the opclass). Its right arg must match the
1662 * return type of the support proc.
1663 */
1665 ANYMULTIRANGEOID,
1667 aggedcontainedbyoperoid,
1668 &strat);
1669
1670 switch (opcintype)
1671 {
1672 case ANYRANGEOID:
1673 *intersectoperoid = OID_RANGE_INTERSECT_RANGE_OP;
1674 break;
1675 case ANYMULTIRANGEOID:
1676 *intersectoperoid = OID_MULTIRANGE_INTERSECT_MULTIRANGE_OP;
1677 break;
1678 default:
1679 elog(ERROR, "unexpected opcintype: %u", opcintype);
1680 }
1681}
1682
1683/*
1684 * Determine whether a relation can be proven functionally dependent on
1685 * a set of grouping columns. If so, return true and add the pg_constraint
1686 * OIDs of the constraints needed for the proof to the *constraintDeps list.
1687 *
1688 * grouping_columns is a list of grouping expressions, in which columns of
1689 * the rel of interest are Vars with the indicated varno/varlevelsup.
1690 *
1691 * Currently we only check to see if the rel has a primary key that is a
1692 * subset of the grouping_columns. We could also use plain unique constraints
1693 * if all their columns are known not null, but there's a problem: we need
1694 * to be able to represent the not-null-ness as part of the constraints added
1695 * to *constraintDeps. FIXME whenever not-null constraints get represented
1696 * in pg_constraint.
1697 */
1698bool
1700 Index varno, Index varlevelsup,
1701 List *grouping_columns,
1702 List **constraintDeps)
1703{
1704 Bitmapset *pkattnos;
1705 Bitmapset *groupbyattnos;
1706 Oid constraintOid;
1707 ListCell *gl;
1708
1709 /* If the rel has no PK, then we can't prove functional dependency */
1710 pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
1711 if (pkattnos == NULL)
1712 return false;
1713
1714 /* Identify all the rel's columns that appear in grouping_columns */
1715 groupbyattnos = NULL;
1716 foreach(gl, grouping_columns)
1717 {
1718 Var *gvar = (Var *) lfirst(gl);
1719
1720 if (IsA(gvar, Var) &&
1721 gvar->varno == varno &&
1722 gvar->varlevelsup == varlevelsup)
1723 groupbyattnos = bms_add_member(groupbyattnos,
1725 }
1726
1727 if (bms_is_subset(pkattnos, groupbyattnos))
1728 {
1729 /* The PK is a subset of grouping_columns, so we win */
1730 *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1731 return true;
1732 }
1733
1734 return false;
1735}
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:703
char * Pointer
Definition: c.h:479
#define Assert(condition)
Definition: c.h:815
int16_t int16
Definition: c.h:483
unsigned int Index
Definition: c.h:571
#define OidIsValid(objectId)
Definition: c.h:732
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
@ COMPARE_CONTAINED_BY
Definition: cmptype.h:41
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2608
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:903
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2524
void GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
Definition: indexcmds.c:2453
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
static bool pg_add_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:67
int i
Definition: isn.c:72
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1955
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:859
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1236
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:828
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define makeNode(_type_)
Definition: nodes.h:155
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
@ CONSTR_NOTNULL
Definition: parsenodes.h:2770
int16 attnum
Definition: pg_attribute.h:74
static char * label
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define INDEX_MAX_KEYS
#define NAMEDATALEN
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:51
HeapTuple findNotNullConstraint(Oid relid, const char *colname)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
void RemoveConstraintById(Oid conId)
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid, Oid *intersectoperoid)
void RenameConstraintById(Oid conId, const char *newname)
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
Bitmapset * get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
HeapTuple findDomainNotNullConstraint(Oid typid)
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
List * RelationGetNotNullConstraints(Oid relid, bool cooked, bool include_noinh)
bool ConstraintNameExists(const char *conname, Oid namespaceid)
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
Bitmapset * get_relation_constraint_attnos(Oid relid, const char *conname, bool missing_ok, Oid *constraintOid)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
AttrNumber extractNotNullColumn(HeapTuple constrTup)
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
bool AdjustNotNullInheritance(Oid relid, AttrNumber attnum, bool is_local, bool is_no_inherit)
FormData_pg_constraint * Form_pg_constraint
ConstraintCategory
@ CONSTRAINT_DOMAIN
@ CONSTRAINT_RELATION
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:351
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
#define snprintf
Definition: port.h:239
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:538
#define RelationGetRelationName(relation)
Definition: rel.h:546
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
uint16 StrategyNumber
Definition: stratnum.h:22
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
bool initdeferred
Definition: parsenodes.h:2805
ParseLoc location
Definition: parsenodes.h:2846
List * keys
Definition: parsenodes.h:2817
ConstrType contype
Definition: parsenodes.h:2802
bool is_no_inherit
Definition: parsenodes.h:2809
bool is_enforced
Definition: parsenodes.h:2806
bool initially_valid
Definition: parsenodes.h:2808
bool skip_validation
Definition: parsenodes.h:2807
bool deferrable
Definition: parsenodes.h:2804
char * conname
Definition: parsenodes.h:2803
Oid conoid
Definition: heap.h:40
char * name
Definition: heap.h:41
AttrNumber attnum
Definition: heap.h:42
bool skip_validation
Definition: heap.h:45
bool is_enforced
Definition: heap.h:44
bool is_no_inherit
Definition: heap.h:48
int16 inhcount
Definition: heap.h:47
bool is_local
Definition: heap.h:46
ConstrType contype
Definition: heap.h:38
Node * expr
Definition: heap.h:43
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Definition: nodes.h:129
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Index varlevelsup
Definition: primnodes.h:294
Definition: c.h:698
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
String * makeString(char *str)
Definition: value.c:63