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