PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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
53 char constraintType,
54 bool isDeferrable,
55 bool isDeferred,
56 bool isEnforced,
57 bool isValidated,
59 Oid relId,
60 const int16 *constraintKey,
66 const int16 *foreignKey,
67 const Oid *pfEqOp,
68 const Oid *ppEqOp,
69 const Oid *ffEqOp,
70 int foreignNKeys,
76 const Oid *exclOp,
78 const char *conBin,
79 bool conIsLocal,
81 bool conNoInherit,
82 bool conPeriod,
83 bool is_internal)
84{
86 Oid conOid;
88 bool nulls[Natts_pg_constraint];
98 int i;
102
103 /* Only CHECK or FOREIGN KEY constraint can be not enforced */
106 /* NOT ENFORCED constraint must be NOT VALID */
108
110
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++)
125 }
126 else
128
129 if (foreignNKeys > 0)
130 {
132 int nkeys = Max(foreignNKeys, numFkDeleteSetCols);
133
134 fkdatums = (Datum *) palloc(nkeys * sizeof(Datum));
135 for (i = 0; i < foreignNKeys; i++)
138 for (i = 0; i < foreignNKeys; i++)
141 for (i = 0; i < foreignNKeys; i++)
144 for (i = 0; i < foreignNKeys; i++)
147
148 if (numFkDeleteSetCols > 0)
149 {
150 for (i = 0; i < numFkDeleteSetCols; i++)
153 }
154 else
156 }
157 else
158 {
164 }
165
166 if (exclOp != NULL)
167 {
169
170 opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
171 for (i = 0; i < constraintNKeys; i++)
174 }
175 else
177
178 /* initialize nulls and values */
179 for (i = 0; i < Natts_pg_constraint; i++)
180 {
181 nulls[i] = false;
182 values[i] = (Datum) 0;
183 }
184
207
208 if (conkeyArray)
210 else
211 nulls[Anum_pg_constraint_conkey - 1] = true;
212
213 if (confkeyArray)
215 else
216 nulls[Anum_pg_constraint_confkey - 1] = true;
217
218 if (conpfeqopArray)
220 else
221 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
222
223 if (conppeqopArray)
225 else
226 nulls[Anum_pg_constraint_conppeqop - 1] = true;
227
228 if (conffeqopArray)
230 else
231 nulls[Anum_pg_constraint_conffeqop - 1] = true;
232
235 else
236 nulls[Anum_pg_constraint_confdelsetcols - 1] = true;
237
238 if (conexclopArray)
240 else
241 nulls[Anum_pg_constraint_conexclop - 1] = true;
242
243 if (conBin)
245 else
246 nulls[Anum_pg_constraint_conbin - 1] = true;
247
249
251
253
255
256 /* Handle set of auto dependencies */
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 */
266
267 if (constraintNTotalKeys > 0)
268 {
269 for (i = 0; i < constraintNTotalKeys; i++)
270 {
274 }
275 }
276 else
277 {
280 }
281 }
282
283 if (OidIsValid(domainId))
284 {
285 /*
286 * Register auto dependency from constraint to owning domain
287 */
289
292 }
293
297
298 /* Handle set of normal dependencies */
300
302 {
303 /*
304 * Register normal dependency from constraint to foreign relation, or
305 * to specific column(s) if any are mentioned.
306 */
308
309 if (foreignNKeys > 0)
310 {
311 for (i = 0; i < foreignNKeys; i++)
312 {
316 }
317 }
318 else
319 {
322 }
323 }
324
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 */
334
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 */
348
350 oprobject.objectSubId = 0;
351
352 for (i = 0; i < foreignNKeys; i++)
353 {
354 oprobject.objectId = pfEqOp[i];
356 if (ppEqOp[i] != pfEqOp[i])
357 {
358 oprobject.objectId = ppEqOp[i];
360 }
361 if (ffEqOp[i] != pfEqOp[i])
362 {
363 oprobject.objectId = ffEqOp[i];
365 }
366 }
367 }
368
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 */
389 DEPENDENCY_NORMAL, false);
390 }
391
392 /* Post creation hook for new constraint */
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
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
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 * If the given label is empty, we only consider names that include at least
499 * one added digit.
500 *
501 * 'others' can be a list of string names already chosen within the current
502 * command (but not yet reflected into the catalogs); we will not choose
503 * a duplicate of one of these either.
504 *
505 * Note: it is theoretically possible to get a collision anyway, if someone
506 * else chooses the same name concurrently. This is fairly unlikely to be
507 * a problem in practice, especially if one is holding an exclusive lock on
508 * the relation identified by name1.
509 *
510 * Returns a palloc'd string.
511 */
512char *
513ChooseConstraintName(const char *name1, const char *name2,
514 const char *label, Oid namespaceid,
515 List *others)
516{
517 int pass = 0;
518 char *conname = NULL;
519 char modlabel[NAMEDATALEN];
522 ScanKeyData skey[2];
523 bool found;
524 ListCell *l;
525
527
528 /* try the unmodified label first, unless it's empty */
529 if (label[0] != '\0')
530 strlcpy(modlabel, label, sizeof(modlabel));
531 else
532 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
533
534 for (;;)
535 {
536 conname = makeObjectName(name1, name2, modlabel);
537
538 found = false;
539
540 foreach(l, others)
541 {
542 if (strcmp((char *) lfirst(l), conname) == 0)
543 {
544 found = true;
545 break;
546 }
547 }
548
549 if (!found)
550 {
551 ScanKeyInit(&skey[0],
554 CStringGetDatum(conname));
555
556 ScanKeyInit(&skey[1],
560
562 NULL, 2, skey);
563
565
567 }
568
569 if (!found)
570 break;
571
572 /* found a conflict, so try a new name component */
573 pfree(conname);
574 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
575 }
576
578
579 return conname;
580}
581
582/*
583 * Find and return a copy of the pg_constraint tuple that implements a
584 * (possibly not valid) not-null constraint for the given column of the
585 * given relation. If no such constraint exists, return NULL.
586 *
587 * XXX This would be easier if we had pg_attribute.notnullconstr with the OID
588 * of the constraint that implements the not-null constraint for that column.
589 * I'm not sure it's worth the catalog bloat and de-normalization, however.
590 */
593{
596 retval = NULL;
597 SysScanDesc scan;
598 ScanKeyData key;
599
601 ScanKeyInit(&key,
604 ObjectIdGetDatum(relid));
606 true, NULL, 1, &key);
607
609 {
612
613 /*
614 * We're looking for a NOTNULL constraint with the column we're
615 * looking for as the sole element in conkey.
616 */
617 if (con->contype != CONSTRAINT_NOTNULL)
618 continue;
619
621 if (conkey != attnum)
622 continue;
623
624 /* Found it */
625 retval = heap_copytuple(conTup);
626 break;
627 }
628
629 systable_endscan(scan);
631
632 return retval;
633}
634
635/*
636 * Find and return a copy of the pg_constraint tuple that implements a
637 * (possibly not valid) not-null constraint for the given column of the
638 * given relation.
639 * If no such column or no such constraint exists, return NULL.
640 */
642findNotNullConstraint(Oid relid, const char *colname)
643{
645
646 attnum = get_attnum(relid, colname);
648 return NULL;
649
650 return findNotNullConstraintAttnum(relid, attnum);
651}
652
653/*
654 * Find and return the pg_constraint tuple that implements a validated
655 * not-null constraint for the given domain.
656 */
659{
662 retval = NULL;
663 SysScanDesc scan;
664 ScanKeyData key;
665
667 ScanKeyInit(&key,
670 ObjectIdGetDatum(typid));
672 true, NULL, 1, &key);
673
675 {
677
678 /*
679 * We're looking for a NOTNULL constraint that's marked validated.
680 */
681 if (con->contype != CONSTRAINT_NOTNULL)
682 continue;
683 if (!con->convalidated)
684 continue;
685
686 /* Found it */
687 retval = heap_copytuple(conTup);
688 break;
689 }
690
691 systable_endscan(scan);
693
694 return retval;
695}
696
697/*
698 * Given a pg_constraint tuple for a not-null constraint, return the column
699 * number it is for.
700 */
703{
705 ArrayType *arr;
706
707 /* only tuples for not-null constraints should be given */
709
712 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
713 if (ARR_NDIM(arr) != 1 ||
714 ARR_HASNULL(arr) ||
715 ARR_ELEMTYPE(arr) != INT2OID ||
716 ARR_DIMS(arr)[0] != 1)
717 elog(ERROR, "conkey is not a 1-D smallint array");
718
719 /* We leak the detoasted datum, but we don't care */
720
721 return ((AttrNumber *) ARR_DATA_PTR(arr))[0];
722}
723
724/*
725 * AdjustNotNullInheritance
726 * Adjust inheritance status for a single not-null constraint
727 *
728 * If no not-null constraint is found for the column, return false.
729 * Caller can create one.
730 *
731 * If a constraint exists but the connoinherit flag is not what the caller
732 * wants, throw an error about the incompatibility. If the desired
733 * constraint is valid but the existing constraint is not valid, also
734 * throw an error about that (the opposite case is acceptable).
735 *
736 * If everything checks out, we adjust conislocal/coninhcount and return
737 * true. If is_local is true we flip conislocal true, or do nothing if
738 * it's already true; otherwise we increment coninhcount by 1.
739 */
740bool
742 bool is_local, bool is_no_inherit, bool is_notvalid)
743{
745
748 {
751 bool changed = false;
752
755
756 /*
757 * If the NO INHERIT flag we're asked for doesn't match what the
758 * existing constraint has, throw an error.
759 */
760 if (is_no_inherit != conform->connoinherit)
763 errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"",
764 NameStr(conform->conname), get_rel_name(relid)),
765 errhint("You might need to make the existing constraint inheritable using %s.",
766 "ALTER TABLE ... ALTER CONSTRAINT ... INHERIT"));
767
768 /*
769 * Throw an error if the existing constraint is NOT VALID and caller
770 * wants a valid one.
771 */
772 if (!is_notvalid && !conform->convalidated)
775 errmsg("incompatible NOT VALID constraint \"%s\" on relation \"%s\"",
776 NameStr(conform->conname), get_rel_name(relid)),
777 errhint("You might need to validate it using %s.",
778 "ALTER TABLE ... VALIDATE CONSTRAINT"));
779
780 if (!is_local)
781 {
782 if (pg_add_s16_overflow(conform->coninhcount, 1,
783 &conform->coninhcount))
786 errmsg("too many inheritance parents"));
787 changed = true;
788 }
789 else if (!conform->conislocal)
790 {
791 conform->conislocal = true;
792 changed = true;
793 }
794
795 if (changed)
797
799
800 return true;
801 }
802
803 return false;
804}
805
806/*
807 * RelationGetNotNullConstraints
808 * Return the list of not-null constraints for the given rel
809 *
810 * Caller can request cooked constraints, or raw.
811 *
812 * This is seldom needed, so we just scan pg_constraint each time.
813 *
814 * 'include_noinh' determines whether to include NO INHERIT constraints or not.
815 */
816List *
818{
819 List *notnulls = NIL;
821 HeapTuple htup;
824
829 ObjectIdGetDatum(relid));
831 NULL, 1, &skey);
832
834 {
836 AttrNumber colnum;
837
838 if (conForm->contype != CONSTRAINT_NOTNULL)
839 continue;
840 if (conForm->connoinherit && !include_noinh)
841 continue;
842
843 colnum = extractNotNullColumn(htup);
844
845 if (cooked)
846 {
848
850
851 cooked->contype = CONSTR_NOTNULL;
852 cooked->conoid = conForm->oid;
853 cooked->name = pstrdup(NameStr(conForm->conname));
854 cooked->attnum = colnum;
855 cooked->expr = NULL;
856 cooked->is_enforced = true;
857 cooked->skip_validation = !conForm->convalidated;
858 cooked->is_local = true;
859 cooked->inhcount = 0;
860 cooked->is_no_inherit = conForm->connoinherit;
861
862 notnulls = lappend(notnulls, cooked);
863 }
864 else
865 {
866 Constraint *constr;
867
868 constr = makeNode(Constraint);
869 constr->contype = CONSTR_NOTNULL;
870 constr->conname = pstrdup(NameStr(conForm->conname));
871 constr->deferrable = false;
872 constr->initdeferred = false;
873 constr->location = -1;
874 constr->keys = list_make1(makeString(get_attname(relid, colnum,
875 false)));
876 constr->is_enforced = true;
877 constr->skip_validation = !conForm->convalidated;
878 constr->initially_valid = conForm->convalidated;
879 constr->is_no_inherit = conForm->connoinherit;
880 notnulls = lappend(notnulls, constr);
881 }
882 }
883
886
887 return notnulls;
888}
889
890
891/*
892 * Delete a single constraint record.
893 */
894void
896{
900
902
904 if (!HeapTupleIsValid(tup)) /* should not happen */
905 elog(ERROR, "cache lookup failed for constraint %u", conId);
907
908 /*
909 * Special processing depending on what the constraint is for.
910 */
911 if (OidIsValid(con->conrelid))
912 {
913 Relation rel;
914
915 /*
916 * If the constraint is for a relation, open and exclusive-lock the
917 * relation it's for.
918 */
919 rel = table_open(con->conrelid, AccessExclusiveLock);
920
921 /*
922 * We need to update the relchecks count if it is a check constraint
923 * being dropped. This update will force backends to rebuild relcache
924 * entries when we commit.
925 */
926 if (con->contype == CONSTRAINT_CHECK)
927 {
931
934 ObjectIdGetDatum(con->conrelid));
936 elog(ERROR, "cache lookup failed for relation %u",
937 con->conrelid);
939
940 if (classForm->relchecks > 0)
941 classForm->relchecks--;
942 else
943 /* should not happen */
944 elog(WARNING, "relation \"%s\" has relchecks = %d",
945 RelationGetRelationName(rel), classForm->relchecks);
946
948
950
952 }
953
954 /* Keep lock on constraint's rel until end of xact */
955 table_close(rel, NoLock);
956 }
957 else if (OidIsValid(con->contypid))
958 {
959 /*
960 * XXX for now, do nothing special when dropping a domain constraint
961 *
962 * Probably there should be some form of locking on the domain type,
963 * but we have no such concept at the moment.
964 */
965 }
966 else
967 elog(ERROR, "constraint %u is not of a known type", conId);
968
969 /* Fry the constraint itself */
970 CatalogTupleDelete(conDesc, &tup->t_self);
971
972 /* Clean up */
975}
976
977/*
978 * RenameConstraintById
979 * Rename a constraint.
980 *
981 * Note: this isn't intended to be a user-exposed function; it doesn't check
982 * permissions etc. Currently this is only invoked when renaming an index
983 * that is associated with a constraint, but it's made a little more general
984 * than that with the expectation of someday having ALTER TABLE RENAME
985 * CONSTRAINT.
986 */
987void
988RenameConstraintById(Oid conId, const char *newname)
989{
991 HeapTuple tuple;
993
995
997 if (!HeapTupleIsValid(tuple))
998 elog(ERROR, "cache lookup failed for constraint %u", conId);
999 con = (Form_pg_constraint) GETSTRUCT(tuple);
1000
1001 /*
1002 * For user-friendliness, check whether the name is already in use.
1003 */
1004 if (OidIsValid(con->conrelid) &&
1006 con->conrelid,
1007 newname))
1008 ereport(ERROR,
1010 errmsg("constraint \"%s\" for relation \"%s\" already exists",
1011 newname, get_rel_name(con->conrelid))));
1012 if (OidIsValid(con->contypid) &&
1014 con->contypid,
1015 newname))
1016 ereport(ERROR,
1018 errmsg("constraint \"%s\" for domain %s already exists",
1019 newname, format_type_be(con->contypid))));
1020
1021 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
1022 namestrcpy(&(con->conname), newname);
1023
1024 CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
1025
1027
1028 heap_freetuple(tuple);
1030}
1031
1032/*
1033 * AlterConstraintNamespaces
1034 * Find any constraints belonging to the specified object,
1035 * and move them to the specified new namespace.
1036 *
1037 * isType indicates whether the owning object is a type or a relation.
1038 */
1039void
1042{
1044 ScanKeyData key[2];
1045 SysScanDesc scan;
1046 HeapTuple tup;
1047
1049
1050 ScanKeyInit(&key[0],
1053 ObjectIdGetDatum(isType ? InvalidOid : ownerId));
1054 ScanKeyInit(&key[1],
1057 ObjectIdGetDatum(isType ? ownerId : InvalidOid));
1058
1060 NULL, 2, key);
1061
1062 while (HeapTupleIsValid((tup = systable_getnext(scan))))
1063 {
1066
1068
1070 continue;
1071
1072 /* Don't update if the object is already part of the namespace */
1073 if (conform->connamespace == oldNspId && oldNspId != newNspId)
1074 {
1077
1078 conform->connamespace = newNspId;
1079
1080 CatalogTupleUpdate(conRel, &tup->t_self, tup);
1081
1082 /*
1083 * Note: currently, the constraint will not have its own
1084 * dependency on the namespace, so we don't need to do
1085 * changeDependencyFor().
1086 */
1087 }
1088
1090
1092 }
1093
1094 systable_endscan(scan);
1095
1097}
1098
1099/*
1100 * ConstraintSetParentConstraint
1101 * Set a partition's constraint as child of its parent constraint,
1102 * or remove the linkage if parentConstrId is InvalidOid.
1103 *
1104 * This updates the constraint's pg_constraint row to show it as inherited, and
1105 * adds PARTITION dependencies to prevent the constraint from being deleted
1106 * on its own. Alternatively, reverse that.
1107 */
1108void
1112{
1115 HeapTuple tuple,
1116 newtup;
1119
1122 if (!HeapTupleIsValid(tuple))
1123 elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
1124 newtup = heap_copytuple(tuple);
1127 {
1128 /* don't allow setting parent for a constraint that already has one */
1129 Assert(constrForm->coninhcount == 0);
1130 if (constrForm->conparentid != InvalidOid)
1131 elog(ERROR, "constraint %u already has a parent constraint",
1133
1134 constrForm->conislocal = false;
1135 if (pg_add_s16_overflow(constrForm->coninhcount, 1,
1136 &constrForm->coninhcount))
1137 ereport(ERROR,
1139 errmsg("too many inheritance parents"));
1140
1141 constrForm->conparentid = parentConstrId;
1142
1144
1146
1149
1152 }
1153 else
1154 {
1155 constrForm->coninhcount--;
1156 constrForm->conislocal = true;
1157 constrForm->conparentid = InvalidOid;
1158
1159 /* Make sure there's no further inheritance. */
1160 Assert(constrForm->coninhcount == 0);
1161
1163
1170 }
1171
1172 ReleaseSysCache(tuple);
1174}
1175
1176
1177/*
1178 * get_relation_constraint_oid
1179 * Find a constraint on the specified relation with the specified name.
1180 * Returns constraint's OID.
1181 */
1182Oid
1183get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
1184{
1186 HeapTuple tuple;
1187 SysScanDesc scan;
1188 ScanKeyData skey[3];
1190
1192
1193 ScanKeyInit(&skey[0],
1196 ObjectIdGetDatum(relid));
1197 ScanKeyInit(&skey[1],
1201 ScanKeyInit(&skey[2],
1204 CStringGetDatum(conname));
1205
1207 NULL, 3, skey);
1208
1209 /* There can be at most one matching row */
1210 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1211 conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1212
1213 systable_endscan(scan);
1214
1215 /* If no such constraint exists, complain */
1216 if (!OidIsValid(conOid) && !missing_ok)
1217 ereport(ERROR,
1219 errmsg("constraint \"%s\" for table \"%s\" does not exist",
1220 conname, get_rel_name(relid))));
1221
1223
1224 return conOid;
1225}
1226
1227/*
1228 * get_relation_constraint_attnos
1229 * Find a constraint on the specified relation with the specified name
1230 * and return the constrained columns.
1231 *
1232 * Returns a Bitmapset of the column attnos of the constrained columns, with
1233 * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system
1234 * columns can be represented.
1235 *
1236 * *constraintOid is set to the OID of the constraint, or InvalidOid on
1237 * failure.
1238 */
1239Bitmapset *
1240get_relation_constraint_attnos(Oid relid, const char *conname,
1241 bool missing_ok, Oid *constraintOid)
1242{
1245 HeapTuple tuple;
1246 SysScanDesc scan;
1247 ScanKeyData skey[3];
1248
1249 /* Set *constraintOid, to avoid complaints about uninitialized vars */
1251
1253
1254 ScanKeyInit(&skey[0],
1257 ObjectIdGetDatum(relid));
1258 ScanKeyInit(&skey[1],
1262 ScanKeyInit(&skey[2],
1265 CStringGetDatum(conname));
1266
1268 NULL, 3, skey);
1269
1270 /* There can be at most one matching row */
1271 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1272 {
1273 Datum adatum;
1274 bool isNull;
1275
1276 *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1277
1278 /* Extract the conkey array, ie, attnums of constrained columns */
1281 if (!isNull)
1282 {
1283 ArrayType *arr;
1284 int numcols;
1285 int16 *attnums;
1286 int i;
1287
1288 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1289 numcols = ARR_DIMS(arr)[0];
1290 if (ARR_NDIM(arr) != 1 ||
1291 numcols < 0 ||
1292 ARR_HASNULL(arr) ||
1293 ARR_ELEMTYPE(arr) != INT2OID)
1294 elog(ERROR, "conkey is not a 1-D smallint array");
1295 attnums = (int16 *) ARR_DATA_PTR(arr);
1296
1297 /* Construct the result value */
1298 for (i = 0; i < numcols; i++)
1299 {
1302 }
1303 }
1304 }
1305
1306 systable_endscan(scan);
1307
1308 /* If no such constraint exists, complain */
1309 if (!OidIsValid(*constraintOid) && !missing_ok)
1310 ereport(ERROR,
1312 errmsg("constraint \"%s\" for table \"%s\" does not exist",
1313 conname, get_rel_name(relid))));
1314
1316
1317 return conattnos;
1318}
1319
1320/*
1321 * Return the OID of the constraint enforced by the given index in the
1322 * given relation; or InvalidOid if no such index is cataloged.
1323 *
1324 * Much like get_constraint_index, this function is concerned only with the
1325 * one constraint that "owns" the given index. Therefore, constraints of
1326 * types other than unique, primary-key, and exclusion are ignored.
1327 */
1328Oid
1330{
1332 SysScanDesc scan;
1333 ScanKeyData key;
1334 HeapTuple tuple;
1336
1338
1339 ScanKeyInit(&key,
1342 F_OIDEQ,
1345 true, NULL, 1, &key);
1346 while ((tuple = systable_getnext(scan)) != NULL)
1347 {
1349
1351
1352 /* See above */
1353 if (constrForm->contype != CONSTRAINT_PRIMARY &&
1354 constrForm->contype != CONSTRAINT_UNIQUE &&
1355 constrForm->contype != CONSTRAINT_EXCLUSION)
1356 continue;
1357
1358 if (constrForm->conindid == indexId)
1359 {
1360 constraintId = constrForm->oid;
1361 break;
1362 }
1363 }
1364 systable_endscan(scan);
1365
1367 return constraintId;
1368}
1369
1370/*
1371 * get_domain_constraint_oid
1372 * Find a constraint on the specified domain with the specified name.
1373 * Returns constraint's OID.
1374 */
1375Oid
1376get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
1377{
1379 HeapTuple tuple;
1380 SysScanDesc scan;
1381 ScanKeyData skey[3];
1383
1385
1386 ScanKeyInit(&skey[0],
1390 ScanKeyInit(&skey[1],
1393 ObjectIdGetDatum(typid));
1394 ScanKeyInit(&skey[2],
1397 CStringGetDatum(conname));
1398
1400 NULL, 3, skey);
1401
1402 /* There can be at most one matching row */
1403 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1404 conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1405
1406 systable_endscan(scan);
1407
1408 /* If no such constraint exists, complain */
1409 if (!OidIsValid(conOid) && !missing_ok)
1410 ereport(ERROR,
1412 errmsg("constraint \"%s\" for domain %s does not exist",
1413 conname, format_type_be(typid))));
1414
1416
1417 return conOid;
1418}
1419
1420/*
1421 * get_primary_key_attnos
1422 * Identify the columns in a relation's primary key, if any.
1423 *
1424 * Returns a Bitmapset of the column attnos of the primary key's columns,
1425 * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
1426 * system columns can be represented.
1427 *
1428 * If there is no primary key, return NULL. We also return NULL if the pkey
1429 * constraint is deferrable and deferrableOk is false.
1430 *
1431 * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
1432 * on failure.
1433 */
1434Bitmapset *
1436{
1439 HeapTuple tuple;
1440 SysScanDesc scan;
1441 ScanKeyData skey[1];
1442
1443 /* Set *constraintOid, to avoid complaints about uninitialized vars */
1445
1446 /* Scan pg_constraint for constraints of the target rel */
1448
1449 ScanKeyInit(&skey[0],
1452 ObjectIdGetDatum(relid));
1453
1455 NULL, 1, skey);
1456
1457 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1458 {
1460 Datum adatum;
1461 bool isNull;
1462 ArrayType *arr;
1463 int16 *attnums;
1464 int numkeys;
1465 int i;
1466
1467 /* Skip constraints that are not PRIMARY KEYs */
1468 if (con->contype != CONSTRAINT_PRIMARY)
1469 continue;
1470
1471 /*
1472 * If the primary key is deferrable, but we've been instructed to
1473 * ignore deferrable constraints, then we might as well give up
1474 * searching, since there can only be a single primary key on a table.
1475 */
1476 if (con->condeferrable && !deferrableOk)
1477 break;
1478
1479 /* Extract the conkey array, ie, attnums of PK's columns */
1482 if (isNull)
1483 elog(ERROR, "null conkey for constraint %u",
1484 ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1485 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1486 numkeys = ARR_DIMS(arr)[0];
1487 if (ARR_NDIM(arr) != 1 ||
1488 numkeys < 0 ||
1489 ARR_HASNULL(arr) ||
1490 ARR_ELEMTYPE(arr) != INT2OID)
1491 elog(ERROR, "conkey is not a 1-D smallint array");
1492 attnums = (int16 *) ARR_DATA_PTR(arr);
1493
1494 /* Construct the result value */
1495 for (i = 0; i < numkeys; i++)
1496 {
1499 }
1500 *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1501
1502 /* No need to search further */
1503 break;
1504 }
1505
1506 systable_endscan(scan);
1507
1509
1510 return pkattnos;
1511}
1512
1513/*
1514 * Extract data from the pg_constraint tuple of a foreign-key constraint.
1515 *
1516 * All arguments save the first are output arguments. All output arguments
1517 * other than numfks, conkey and confkey can be passed as NULL if caller
1518 * doesn't need them.
1519 */
1520void
1523 Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
1524 int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
1525{
1526 Datum adatum;
1527 bool isNull;
1528 ArrayType *arr;
1529 int numkeys;
1530
1531 /*
1532 * We expect the arrays to be 1-D arrays of the right types; verify that.
1533 * We don't need to use deconstruct_array() since the array data is just
1534 * going to look like a C array of values.
1535 */
1538 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1539 if (ARR_NDIM(arr) != 1 ||
1540 ARR_HASNULL(arr) ||
1541 ARR_ELEMTYPE(arr) != INT2OID)
1542 elog(ERROR, "conkey is not a 1-D smallint array");
1543 numkeys = ARR_DIMS(arr)[0];
1545 elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1546 memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1547 if (arr != DatumGetPointer(adatum))
1548 pfree(arr); /* free de-toasted copy, if any */
1549
1552 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1553 if (ARR_NDIM(arr) != 1 ||
1554 ARR_DIMS(arr)[0] != numkeys ||
1555 ARR_HASNULL(arr) ||
1556 ARR_ELEMTYPE(arr) != INT2OID)
1557 elog(ERROR, "confkey is not a 1-D smallint array");
1558 memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1559 if (arr != DatumGetPointer(adatum))
1560 pfree(arr); /* free de-toasted copy, if any */
1561
1562 if (pf_eq_oprs)
1563 {
1566 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1567 /* see TryReuseForeignKey if you change the test below */
1568 if (ARR_NDIM(arr) != 1 ||
1569 ARR_DIMS(arr)[0] != numkeys ||
1570 ARR_HASNULL(arr) ||
1571 ARR_ELEMTYPE(arr) != OIDOID)
1572 elog(ERROR, "conpfeqop is not a 1-D Oid array");
1573 memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1574 if (arr != DatumGetPointer(adatum))
1575 pfree(arr); /* free de-toasted copy, if any */
1576 }
1577
1578 if (pp_eq_oprs)
1579 {
1582 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1583 if (ARR_NDIM(arr) != 1 ||
1584 ARR_DIMS(arr)[0] != numkeys ||
1585 ARR_HASNULL(arr) ||
1586 ARR_ELEMTYPE(arr) != OIDOID)
1587 elog(ERROR, "conppeqop is not a 1-D Oid array");
1588 memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1589 if (arr != DatumGetPointer(adatum))
1590 pfree(arr); /* free de-toasted copy, if any */
1591 }
1592
1593 if (ff_eq_oprs)
1594 {
1597 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1598 if (ARR_NDIM(arr) != 1 ||
1599 ARR_DIMS(arr)[0] != numkeys ||
1600 ARR_HASNULL(arr) ||
1601 ARR_ELEMTYPE(arr) != OIDOID)
1602 elog(ERROR, "conffeqop is not a 1-D Oid array");
1603 memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1604 if (arr != DatumGetPointer(adatum))
1605 pfree(arr); /* free de-toasted copy, if any */
1606 }
1607
1608 if (fk_del_set_cols)
1609 {
1612 if (isNull)
1613 {
1615 }
1616 else
1617 {
1618 int num_delete_cols;
1619
1620 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1621 if (ARR_NDIM(arr) != 1 ||
1622 ARR_HASNULL(arr) ||
1623 ARR_ELEMTYPE(arr) != INT2OID)
1624 elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1625 num_delete_cols = ARR_DIMS(arr)[0];
1626 memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1627 if (arr != DatumGetPointer(adatum))
1628 pfree(arr); /* free de-toasted copy, if any */
1629
1631 }
1632 }
1633
1634 *numfks = numkeys;
1635}
1636
1637/*
1638 * FindFKPeriodOpers -
1639 *
1640 * Looks up the operator oids used for the PERIOD part of a temporal foreign key.
1641 * The opclass should be the opclass of that PERIOD element.
1642 * Everything else is an output: containedbyoperoid is the ContainedBy operator for
1643 * types matching the PERIOD element.
1644 * aggedcontainedbyoperoid is also a ContainedBy operator,
1645 * but one whose rhs is a multirange.
1646 * That way foreign keys can compare fkattr <@ range_agg(pkattr).
1647 * intersectoperoid is used by NO ACTION constraints to trim the range being considered
1648 * to just what was updated/deleted.
1649 */
1650void
1655{
1656 Oid opfamily = InvalidOid;
1657 Oid opcintype = InvalidOid;
1659
1660 /* Make sure we have a range or multirange. */
1661 if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1662 {
1663 if (opcintype != ANYRANGEOID && opcintype != ANYMULTIRANGEOID)
1664 ereport(ERROR,
1666 errmsg("invalid type for PERIOD part of foreign key"),
1667 errdetail("Only range and multirange are supported."));
1668
1669 }
1670 else
1671 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1672
1673 /*
1674 * Look up the ContainedBy operator whose lhs and rhs are the opclass's
1675 * type. We use this to optimize RI checks: if the new value includes all
1676 * of the old value, then we can treat the attribute as if it didn't
1677 * change, and skip the RI check.
1678 */
1680 InvalidOid,
1683 &strat);
1684
1685 /*
1686 * Now look up the ContainedBy operator. Its left arg must be the type of
1687 * the column (or rather of the opclass). Its right arg must match the
1688 * return type of the support proc.
1689 */
1694 &strat);
1695
1696 switch (opcintype)
1697 {
1698 case ANYRANGEOID:
1700 break;
1701 case ANYMULTIRANGEOID:
1703 break;
1704 default:
1705 elog(ERROR, "unexpected opcintype: %u", opcintype);
1706 }
1707}
1708
1709/*
1710 * Determine whether a relation can be proven functionally dependent on
1711 * a set of grouping columns. If so, return true and add the pg_constraint
1712 * OIDs of the constraints needed for the proof to the *constraintDeps list.
1713 *
1714 * grouping_columns is a list of grouping expressions, in which columns of
1715 * the rel of interest are Vars with the indicated varno/varlevelsup.
1716 *
1717 * Currently we only check to see if the rel has a primary key that is a
1718 * subset of the grouping_columns. We could also use plain unique constraints
1719 * if all their columns are known not null, but there's a problem: we need
1720 * to be able to represent the not-null-ness as part of the constraints added
1721 * to *constraintDeps. FIXME whenever not-null constraints get represented
1722 * in pg_constraint.
1723 */
1724bool
1726 Index varno, Index varlevelsup,
1729{
1733 ListCell *gl;
1734
1735 /* If the rel has no PK, then we can't prove functional dependency */
1737 if (pkattnos == NULL)
1738 return false;
1739
1740 /* Identify all the rel's columns that appear in grouping_columns */
1742 foreach(gl, grouping_columns)
1743 {
1744 Var *gvar = (Var *) lfirst(gl);
1745
1746 if (IsA(gvar, Var) &&
1747 gvar->varno == varno &&
1748 gvar->varlevelsup == varlevelsup)
1751 }
1752
1754 {
1755 /* The PK is a subset of grouping_columns, so we win */
1757 return true;
1758 }
1759
1760 return false;
1761}
#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)
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:814
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define CStringGetTextDatum(s)
Definition builtins.h:97
#define NameStr(name)
Definition c.h:765
#define Max(x, y)
Definition c.h:991
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
unsigned int Index
Definition c.h:628
#define OidIsValid(objectId)
Definition c.h:788
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
@ COMPARE_CONTAINED_BY
Definition cmptype.h:41
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
@ 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:1216
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
char * format_type_be(Oid type_oid)
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
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)
static void * GETSTRUCT(const HeapTupleData *tuple)
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition indexcmds.c:2543
void GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
Definition indexcmds.c:2470
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *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:2078
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:934
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1337
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:903
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
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)
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
#define ObjectAddressSet(addr, class_id, object_id)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
@ CONSTR_NOTNULL
int16 attnum
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)
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:260
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:403
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationGetRelationName(relation)
Definition rel.h:548
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
ParseLoc location
List * keys
ConstrType contype
bool is_no_inherit
bool is_enforced
bool initially_valid
bool skip_validation
bool deferrable
char * conname
ItemPointerData t_self
Definition htup.h:65
Definition pg_list.h:54
Definition nodes.h:135
Definition c.h:760
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
#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