From ba485a1c864642c3586f349df01fa24ee2cd7032 Mon Sep 17 00:00:00 2001 From: jian he Date: Thu, 3 Apr 2025 15:33:17 +0800 Subject: [PATCH v6 1/1] ensure pg_dump table constraint info remain the same resolve case where parent constraint convalidated is false and children constraint convalidated is true all the dumped information is correct. --- src/backend/catalog/heap.c | 21 +++++++++++++++++---- src/backend/catalog/pg_constraint.c | 10 ++++++++++ src/bin/pg_dump/common.c | 4 ++++ src/bin/pg_dump/pg_dump.c | 18 +++++++++++++++++- src/bin/pg_dump/pg_dump.h | 5 ++++- src/test/regress/expected/inherit.out | 2 +- 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 734e34110fa..25067bd9d43 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2839,11 +2839,24 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, { if (is_local) con->conislocal = true; - else if (pg_add_s16_overflow(con->coninhcount, 1, + else + { + if(pg_add_s16_overflow(con->coninhcount, 1, &con->coninhcount)) - ereport(ERROR, - errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many inheritance parents")); + ereport(ERROR, + errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many inheritance parents")); + + /* + * If the child already has a valid constraint and we are + * creating an invalid one with same definition on it. The + * child's constraint will remain valid, but can no longer be + * marked as local. + */ + if (!is_initially_valid && con->convalidated && + is_enforced && con->conenforced) + con->conislocal = false; + } } if (is_no_inherit) diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index c7ccc5bef32..8b8bd78f20a 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -775,6 +775,16 @@ AdjustNotNullInheritance(Relation rel, AttrNumber attnum, ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); + + /* + * If the child already has a valid constraint and we are + * creating an invalid one with same definition on it. The + * child's constraint will remain valid, but can no longer be + * marked as local. + */ + if (is_notvalid && conform->convalidated && conform->conenforced) + conform->conislocal = false; + changed = true; } else if (!conform->conislocal) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 56b6c368acf..ff6a4eacda0 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -546,6 +546,10 @@ flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables parent->notnull_constrs[inhAttrInd] != NULL) foundNotNull = true; + if (fout->remoteVersion >= 180000 && + parent->notnull_invalid[inhAttrInd]) + tbinfo->notnull_parent_invalid[j] = true; + foundDefault |= (parentDef != NULL && strcmp(parentDef->adef_expr, "NULL") != 0 && !parent->attgenerated[inhAttrInd]); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 96e45f888d4..9ca435aa936 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -9252,6 +9252,8 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *)); tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *)); tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *)); + tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool)); + tbinfo->notnull_parent_invalid = (bool *) pg_malloc(numatts * sizeof(bool)); tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool)); tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool)); tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *)); @@ -9277,6 +9279,8 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen)); tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign)); tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't'); + tbinfo->notnull_parent_invalid[j] = false; /* only change in flagInhAttrs */ + tbinfo->notnull_invalid[j] = false; /* only change in determineNotNullFlags */ /* Handle not-null constraint name and flags */ determineNotNullFlags(fout, res, r, @@ -9756,7 +9760,7 @@ determineNotNullFlags(Archive *fout, PGresult *res, int r, /* nothing else to do */ tbinfo->notnull_constrs[j] = NULL; - + tbinfo->notnull_invalid[j] = true; return; } @@ -16843,6 +16847,18 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) dopt->binary_upgrade || tbinfo->ispartition)); + /* + * if parent have invalid not-null, child have valid + * not-null, then we print not null on child too. later + * parent's invalid not-null will generate a ALTER TABLE ADD + * CONSTRAINT, which will cascade to children, which is + * fine. + */ + if (!print_notnull && + tbinfo->notnull_constrs[j] != NULL && + tbinfo->notnull_parent_invalid[j]) + print_notnull = true; + if (print_notnull) { if (tbinfo->notnull_constrs[j][0] == '\0') diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 195b4495768..dd603c9dd53 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -365,7 +365,10 @@ typedef struct _tableInfo * there isn't one on this column. If * empty string, unnamed constraint * (pre-v17) */ - bool *notnull_validated; /* true if NOT NULL is valid */ + bool *notnull_invalid; /* true mean NOT NULL INVALID, + false mean valid not null or no not null */ + bool *notnull_parent_invalid; /* true mean NOT NULL INVALID, + false mean valid not null or no not null */ bool *notnull_noinh; /* NOT NULL is NO INHERIT */ bool *notnull_islocal; /* true if NOT NULL has local definition */ struct _attrDefInfo **attrdefs; /* DEFAULT expressions */ diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index c01e9d5244f..2cb2c482ea5 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1558,7 +1558,7 @@ order by 1, 2; relname | conname | convalidated | conislocal | coninhcount | connoinherit -------------------------+----------------------+--------------+------------+-------------+-------------- invalid_check_con | inh_check_constraint | f | t | 0 | f - invalid_check_con_child | inh_check_constraint | t | t | 1 | f + invalid_check_con_child | inh_check_constraint | t | f | 1 | f (2 rows) -- We don't drop the invalid_check_con* tables, to test dump/reload with -- 2.34.1