diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/heap.c | 28 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 3 | ||||
-rw-r--r-- | src/backend/catalog/pg_constraint.c | 4 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 50 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 3 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 3 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 1 |
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)); |