aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/heap.c28
-rw-r--r--src/backend/catalog/index.c3
-rw-r--r--src/backend/catalog/pg_constraint.c4
-rw-r--r--src/backend/commands/tablecmds.c50
-rw-r--r--src/backend/commands/trigger.c3
-rw-r--r--src/backend/commands/typecmds.c3
-rw-r--r--src/backend/utils/cache/relcache.c1
7 files changed, 64 insertions, 28 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e11d896ec8c..2f6a6ffba17 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -92,10 +92,10 @@ static Oid AddNewRelationType(const char *typeName,
Oid new_array_type);
static void RelationRemoveInheritance(Oid relid);
static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
- bool is_validated, bool is_local, int inhcount);
+ bool is_validated, bool is_local, int inhcount, bool is_only);
static void StoreConstraints(Relation rel, List *cooked_constraints);
static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
- bool allow_merge, bool is_local);
+ bool allow_merge, bool is_local, bool is_only);
static void SetRelationNumChecks(Relation rel, int numchecks);
static Node *cookConstraint(ParseState *pstate,
Node *raw_constraint,
@@ -1859,7 +1859,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
*/
static void
StoreRelCheck(Relation rel, char *ccname, Node *expr,
- bool is_validated, bool is_local, int inhcount)
+ bool is_validated, bool is_local, int inhcount, bool is_only)
{
char *ccbin;
char *ccsrc;
@@ -1942,7 +1942,8 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
ccbin, /* Binary form of check constraint */
ccsrc, /* Source form of check constraint */
is_local, /* conislocal */
- inhcount); /* coninhcount */
+ inhcount, /* coninhcount */
+ is_only); /* conisonly */
pfree(ccbin);
pfree(ccsrc);
@@ -1983,7 +1984,7 @@ StoreConstraints(Relation rel, List *cooked_constraints)
break;
case CONSTR_CHECK:
StoreRelCheck(rel, con->name, con->expr, !con->skip_validation,
- con->is_local, con->inhcount);
+ con->is_local, con->inhcount, con->is_only);
numchecks++;
break;
default:
@@ -2026,7 +2027,8 @@ AddRelationNewConstraints(Relation rel,
List *newColDefaults,
List *newConstraints,
bool allow_merge,
- bool is_local)
+ bool is_local,
+ bool is_only)
{
List *cookedConstraints = NIL;
TupleDesc tupleDesc;
@@ -2099,6 +2101,7 @@ AddRelationNewConstraints(Relation rel,
cooked->skip_validation = false;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
+ cooked->is_only = is_only;
cookedConstraints = lappend(cookedConstraints, cooked);
}
@@ -2166,7 +2169,7 @@ AddRelationNewConstraints(Relation rel,
* what ATAddCheckConstraint wants.)
*/
if (MergeWithExistingConstraint(rel, ccname, expr,
- allow_merge, is_local))
+ allow_merge, is_local, is_only))
continue;
}
else
@@ -2213,7 +2216,7 @@ AddRelationNewConstraints(Relation rel,
* OK, store it.
*/
StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local,
- is_local ? 0 : 1);
+ is_local ? 0 : 1, is_only);
numchecks++;
@@ -2225,6 +2228,7 @@ AddRelationNewConstraints(Relation rel,
cooked->skip_validation = cdef->skip_validation;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
+ cooked->is_only = is_only;
cookedConstraints = lappend(cookedConstraints, cooked);
}
@@ -2250,7 +2254,8 @@ AddRelationNewConstraints(Relation rel,
*/
static bool
MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
- bool allow_merge, bool is_local)
+ bool allow_merge, bool is_local,
+ bool is_only)
{
bool found;
Relation conDesc;
@@ -2312,6 +2317,11 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
con->conislocal = true;
else
con->coninhcount++;
+ if (is_only)
+ {
+ Assert(is_local);
+ con->conisonly = true;
+ }
simple_heap_update(conDesc, &tup->t_self, tup);
CatalogUpdateIndexes(conDesc, tup);
break;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 758872ff4ed..f9075c4752d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1155,7 +1155,8 @@ index_constraint_create(Relation heapRelation,
NULL,
NULL,
true, /* islocal */
- 0); /* inhcount */
+ 0, /* inhcount */
+ false); /* isonly */
/*
* Register the index as internally dependent on the constraint.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 69979942af4..cfe82ea3a8c 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -66,7 +66,8 @@ CreateConstraintEntry(const char *constraintName,
const char *conBin,
const char *conSrc,
bool conIsLocal,
- int conInhCount)
+ int conInhCount,
+ bool conIsOnly)
{
Relation conDesc;
Oid conOid;
@@ -169,6 +170,7 @@ CreateConstraintEntry(const char *constraintName,
values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
+ values[Anum_pg_constraint_conisonly - 1] = BoolGetDatum(conIsOnly);
if (conkeyArray)
values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 135736a8dc6..00b6cb9d50d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -579,6 +579,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
cooked->skip_validation = false;
cooked->is_local = true; /* not used for defaults */
cooked->inhcount = 0; /* ditto */
+ cooked->is_only = false;
cookedDefaults = lappend(cookedDefaults, cooked);
descriptor->attrs[attnum - 1]->atthasdef = true;
}
@@ -638,7 +639,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
*/
if (rawDefaults || stmt->constraints)
AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
- true, true);
+ true, true, false);
/*
* Clean up. We keep lock on new relation (although it shouldn't be
@@ -1599,6 +1600,10 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
char *name = check[i].ccname;
Node *expr;
+ /* ignore if the constraint is non-inheritable */
+ if (check[i].cconly)
+ continue;
+
/* adjust varattnos of ccbin here */
expr = stringToNode(check[i].ccbin);
change_varattnos_of_a_node(expr, newattno);
@@ -1617,6 +1622,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
cooked->skip_validation = false;
cooked->is_local = false;
cooked->inhcount = 1;
+ cooked->is_only = false;
constraints = lappend(constraints, cooked);
}
}
@@ -4501,7 +4507,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
* This function is intended for CREATE TABLE, so it processes a
* _list_ of defaults, but we just do one.
*/
- AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+ AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
/* Make the additional catalog changes visible */
CommandCounterIncrement();
@@ -4898,7 +4904,7 @@ ATExecColumnDefault(Relation rel, const char *colName,
* This function is intended for CREATE TABLE, so it processes a
* _list_ of defaults, but we just do one.
*/
- AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+ AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
}
}
@@ -5562,10 +5568,16 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
* omitted from the returned list, which is what we want: we do not need
* to do any validation work. That can only happen at child tables,
* though, since we disallow merging at the top level.
+ *
+ * Note: we set is_only based on the recurse flag which is false when
+ * interpretInhOption() of our statement returns false all the way up
+ * in AlterTable and gets passed all the way down to here.
*/
newcons = AddRelationNewConstraints(rel, NIL,
list_make1(copyObject(constr)),
- recursing, !recursing);
+ recursing, /* allow_merge */
+ !recursing, /* is_local */
+ !recurse && !recursing); /* is_only */
/* Add each to-be-validated constraint to Phase 3's queue */
foreach(lcon, newcons)
@@ -5606,21 +5618,18 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
return;
/*
+ * Adding an ONLY constraint? No need to find our children
+ */
+ if (!recurse && !recursing)
+ return;
+
+ /*
* Propagate to children as appropriate. Unlike most other ALTER
* routines, we have to do this one level of recursion at a time; we can't
* use find_all_inheritors to do it in one pass.
*/
children = find_inheritance_children(RelationGetRelid(rel), lockmode);
- /*
- * If we are told not to recurse, there had better not be any child
- * tables; else the addition would put them out of step.
- */
- if (children && !recurse)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
- errmsg("constraint must be added to child tables too")));
-
foreach(child, children)
{
Oid childrelid = lfirst_oid(child);
@@ -5914,7 +5923,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
NULL,
NULL,
true, /* islocal */
- 0); /* inhcount */
+ 0, /* inhcount */
+ false); /* isonly */
/*
* Create the triggers that will enforce the constraint.
@@ -6755,6 +6765,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
HeapTuple tuple;
bool found = false;
bool is_check_constraint = false;
+ bool is_only_constraint = false;
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
@@ -6791,6 +6802,12 @@ ATExecDropConstraint(Relation rel, const char *constrName,
/* Right now only CHECK constraints can be inherited */
if (con->contype == CONSTRAINT_CHECK)
is_check_constraint = true;
+
+ if (con->conisonly)
+ {
+ Assert(is_check_constraint);
+ is_only_constraint = true;
+ }
/*
* Perform the actual constraint deletion
@@ -6802,6 +6819,9 @@ ATExecDropConstraint(Relation rel, const char *constrName,
performDeletion(&conobj, behavior);
found = true;
+
+ /* constraint found and dropped -- no need to keep looping */
+ break;
}
systable_endscan(scan);
@@ -6830,7 +6850,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
* routines, we have to do this one level of recursion at a time; we can't
* use find_all_inheritors to do it in one pass.
*/
- if (is_check_constraint)
+ if (is_check_constraint && !is_only_constraint)
children = find_inheritance_children(RelationGetRelid(rel), lockmode);
else
children = NIL;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f4c93e5b254..eb5114079ad 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -449,7 +449,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
NULL,
NULL,
true, /* islocal */
- 0); /* inhcount */
+ 0, /* inhcount */
+ false); /* isonly */
}
/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 2b8f9aec384..eda43d826fa 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2934,7 +2934,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
ccbin, /* Binary form of check constraint */
ccsrc, /* Source form of check constraint */
true, /* is local */
- 0); /* inhcount */
+ 0, /* inhcount */
+ false); /* is only */
/*
* Return the compiled constraint expression so the calling routine can
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 603e4c1b621..f9ad75e7f89 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3261,6 +3261,7 @@ CheckConstraintFetch(Relation relation)
RelationGetRelationName(relation));
check[found].ccvalid = conform->convalidated;
+ check[found].cconly = conform->conisonly;
check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
NameStr(conform->conname));