On Wed, May 7, 2025 at 10:56 PM Álvaro Herrera <alvhe...@kurilemu.de> wrote: > > Ooh, you know what? I ran your the CREATE DOMAIN statement in your new > test and pg_dump'ed that, and as far as I can tell the _name_ of the > not-null constraint is not dumped either. So it's not just the comment > that we're losing. That's a separate bug, and probably needs to be > fixed first, although I'm not sure if that one is going to be > back-patchable. Which means, I withdraw my earlier assessment that the > comment fix is back-patchable as a whole. >
for PG17. we change the dump of create domain test.d4 as int constraint nn not null; from CREATE DOMAIN test.d4 AS integer NOT NULL; to CREATE DOMAIN test.d4 AS integer CONSTRAINT nn NOT NULL; in PG17 we didn't preserve the constraint name, now if we did, then it's a bug fix, so it can be back-patchable? Anyway, the attachment is for PG18 only now, it will fix the domain constraint name loss and domain not-null comments loss issue together.
From 2db869fc212867e74f61f4e5b2aef1fda017e9f7 Mon Sep 17 00:00:00 2001 From: jian he <jian.universal...@gmail.com> Date: Thu, 8 May 2025 12:48:25 +0800 Subject: [PATCH v3 2/2] sanitize variable or argument name in pg_dump discussion: https://postgr.es/m/CACJufxF-0bqVR=j4jons6n2ka6hhupfyu3_3twknhow_4yf...@mail.gmail.com --- src/bin/pg_dump/pg_dump.c | 32 ++++++++++++++++---------------- src/bin/pg_dump/pg_dump.h | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 7837d4cea36..b3064f1b8d3 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6118,8 +6118,8 @@ getTypes(Archive *fout) /* * If it's a domain, fetch info about its constraints, if any */ - tyinfo[i].nDomChecks = 0; - tyinfo[i].domChecks = NULL; + tyinfo[i].nDomConstrs = 0; + tyinfo[i].domConstrs = NULL; if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) && tyinfo[i].typtype == TYPTYPE_DOMAIN) getDomainConstraints(fout, &(tyinfo[i])); @@ -8296,8 +8296,8 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo)); - tyinfo->nDomChecks = ntups; - tyinfo->domChecks = constrinfo; + tyinfo->nDomConstrs = ntups; + tyinfo->domConstrs = constrinfo; for (i = 0; i < ntups; i++) { @@ -12508,28 +12508,28 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo) /* * Add any CHECK, NOT NULL constraints for the domain */ - for (i = 0; i < tyinfo->nDomChecks; i++) + for (i = 0; i < tyinfo->nDomConstrs; i++) { - ConstraintInfo *domcheck = &(tyinfo->domChecks[i]); + ConstraintInfo *domconstr = &(tyinfo->domConstrs[i]); - if (!domcheck->separate) + if (!domconstr->separate) { - if (domcheck->contype == 'n') + if (domconstr->contype == 'n') { char *default_name; /* XXX should match ChooseConstraintName better */ default_name = psprintf("%s_not_null", qtypname); - if (strcmp(default_name, fmtId(domcheck->dobj.name)) == 0) + if (strcmp(default_name, fmtId(domconstr->dobj.name)) == 0) appendPQExpBufferStr(q, " NOT NULL"); else appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s", - fmtId(domcheck->dobj.name), domcheck->condef); + fmtId(domconstr->dobj.name), domconstr->condef); } else appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s", - fmtId(domcheck->dobj.name), domcheck->condef); + fmtId(domconstr->dobj.name), domconstr->condef); } } @@ -12570,19 +12570,19 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo) NULL, tyinfo->rolname, &tyinfo->dacl); /* Dump any per-constraint comments */ - for (i = 0; i < tyinfo->nDomChecks; i++) + for (i = 0; i < tyinfo->nDomConstrs; i++) { - ConstraintInfo *domcheck = &(tyinfo->domChecks[i]); + ConstraintInfo *domconstr = &(tyinfo->domConstrs[i]); PQExpBuffer conprefix = createPQExpBuffer(); appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN", - fmtId(domcheck->dobj.name)); + fmtId(domconstr->dobj.name)); - if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT) + if (domconstr->dobj.dump & DUMP_COMPONENT_COMMENT) dumpComment(fout, conprefix->data, qtypname, tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, - domcheck->dobj.catId, 0, tyinfo->dobj.dumpId); + domconstr->dobj.catId, 0, tyinfo->dobj.dumpId); destroyPQExpBuffer(conprefix); } diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 7417eab6aef..b5e19ecc2e3 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -223,8 +223,8 @@ typedef struct _typeInfo /* If needed, we'll create a "shell type" entry for it; link that here: */ struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ /* If it's a domain, we store links to its constraints here: */ - int nDomChecks; - struct _constraintInfo *domChecks; + int nDomConstrs; + struct _constraintInfo *domConstrs; } TypeInfo; typedef struct _shellTypeInfo -- 2.34.1
From c6a2e754a5292b72a7e5e328ca4684f9c39517e8 Mon Sep 17 00:00:00 2001 From: jian he <jian.universal...@gmail.com> Date: Thu, 8 May 2025 12:29:01 +0800 Subject: [PATCH v3 1/2] Improve pg_dump handling of domain not-null constraints 1. If requested, we should dump comments for domain not-null constraints. Note: In PostgreSQL 16 and earlier, these constraints do not have entries in pg_constraint. 2. Similar to PG18 table not-null constraint, conditaionlly print out not-null constraint name, This only apply to PG18. discussion: https://postgr.es/m/CACJufxF-0bqVR=j4jons6n2ka6hhupfyu3_3twknhow_4yf...@mail.gmail.com --- src/bin/pg_dump/pg_dump.c | 61 +++++++++++++++++++++++++------- src/bin/pg_dump/pg_dump_sort.c | 9 ++--- src/bin/pg_dump/t/002_pg_dump.pl | 5 +++ 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index e2e7975b34e..7837d4cea36 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -8250,7 +8250,8 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) int i_tableoid, i_oid, i_conname, - i_consrc; + i_consrc, + i_contype; int ntups; if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS]) @@ -8260,10 +8261,19 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) "PREPARE getDomainConstraints(pg_catalog.oid) AS\n" "SELECT tableoid, oid, conname, " "pg_catalog.pg_get_constraintdef(oid) AS consrc, " - "convalidated " + "convalidated, " + "contype " "FROM pg_catalog.pg_constraint " - "WHERE contypid = $1 AND contype = 'c' " - "ORDER BY conname"); + "WHERE contypid = $1 "); + + /* + * in PG18 or later versions, not-null domain constraint catalog + * information is stored in the pg_constraint. + */ + if (fout->remoteVersion < 180000) + appendPQExpBufferStr(query, "AND contype = 'c' "); + + appendPQExpBufferStr(query, "ORDER BY conname"); ExecuteSqlStatement(fout, query->data); @@ -8282,6 +8292,7 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) i_oid = PQfnumber(res, "oid"); i_conname = PQfnumber(res, "conname"); i_consrc = PQfnumber(res, "consrc"); + i_contype = PQfnumber(res, "contype"); constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo)); @@ -8300,7 +8311,7 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) constrinfo[i].dobj.namespace = tyinfo->dobj.namespace; constrinfo[i].contable = NULL; constrinfo[i].condomain = tyinfo; - constrinfo[i].contype = 'c'; + constrinfo[i].contype = *(PQgetvalue(res, i, i_contype)); constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc)); constrinfo[i].confrelid = InvalidOid; constrinfo[i].conindex = 0; @@ -12479,7 +12490,8 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo) appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll)); } - if (typnotnull[0] == 't') + /* PG18 or later versions is handled in below */ + if (typnotnull[0] == 't' && fout->remoteVersion < 180000) appendPQExpBufferStr(q, " NOT NULL"); if (typdefault != NULL) @@ -12494,15 +12506,31 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo) PQclear(res); /* - * Add any CHECK constraints for the domain + * Add any CHECK, NOT NULL constraints for the domain */ for (i = 0; i < tyinfo->nDomChecks; i++) { ConstraintInfo *domcheck = &(tyinfo->domChecks[i]); if (!domcheck->separate) - appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s", - fmtId(domcheck->dobj.name), domcheck->condef); + { + if (domcheck->contype == 'n') + { + char *default_name; + + /* XXX should match ChooseConstraintName better */ + default_name = psprintf("%s_not_null", qtypname); + + if (strcmp(default_name, fmtId(domcheck->dobj.name)) == 0) + appendPQExpBufferStr(q, " NOT NULL"); + else + appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s", + fmtId(domcheck->dobj.name), domcheck->condef); + } + else + appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s", + fmtId(domcheck->dobj.name), domcheck->condef); + } } appendPQExpBufferStr(q, ";\n"); @@ -18370,14 +18398,23 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo) .dropStmt = delq->data)); } } - else if (coninfo->contype == 'c' && tbinfo == NULL) + else if (tbinfo == NULL) { - /* CHECK constraint on a domain */ + /* CHECK, NOT NULL constraint on a domain */ TypeInfo *tyinfo = coninfo->condomain; + Assert(coninfo->contype == 'c' || coninfo->contype == 'n'); + /* Ignore if not to be dumped separately */ if (coninfo->separate) { + const char *keyword; + + if (coninfo->contype == 'c') + keyword = "CHECK CONSTRAINT"; + else + keyword = "CONSTRAINT"; + appendPQExpBuffer(q, "ALTER DOMAIN %s\n", fmtQualifiedDumpable(tyinfo)); appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n", @@ -18396,7 +18433,7 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo) ARCHIVE_OPTS(.tag = tag, .namespace = tyinfo->dobj.namespace->dobj.name, .owner = tyinfo->rolname, - .description = "CHECK CONSTRAINT", + .description = keyword, .section = SECTION_POST_DATA, .createStmt = q->data, .dropStmt = delq->data)); diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 0b0977788f1..e5506ca788c 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -907,7 +907,7 @@ repairTableAttrDefMultiLoop(DumpableObject *tableobj, } /* - * CHECK constraints on domains work just like those on tables ... + * CHECK, NOT NULL constraints on domains work just like those on tables ... */ static void repairDomainConstraintLoop(DumpableObject *domainobj, @@ -1173,11 +1173,10 @@ repairDependencyLoop(DumpableObject **loop, } } - /* Domain and CHECK constraint */ + /* Domain and CHECK, NOT NULL constraint */ if (nLoop == 2 && loop[0]->objType == DO_TYPE && loop[1]->objType == DO_CONSTRAINT && - ((ConstraintInfo *) loop[1])->contype == 'c' && ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0]) { repairDomainConstraintLoop(loop[0], loop[1]); @@ -1186,14 +1185,13 @@ repairDependencyLoop(DumpableObject **loop, if (nLoop == 2 && loop[1]->objType == DO_TYPE && loop[0]->objType == DO_CONSTRAINT && - ((ConstraintInfo *) loop[0])->contype == 'c' && ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1]) { repairDomainConstraintLoop(loop[1], loop[0]); return; } - /* Indirect loop involving domain and CHECK constraint */ + /* Indirect loop involving domain and CHECK OR NOT NULL constraint */ if (nLoop > 2) { for (i = 0; i < nLoop; i++) @@ -1203,7 +1201,6 @@ repairDependencyLoop(DumpableObject **loop, for (j = 0; j < nLoop; j++) { if (loop[j]->objType == DO_CONSTRAINT && - ((ConstraintInfo *) loop[j])->contype == 'c' && ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i]) { repairDomainConstraintMultiLoop(loop[i], loop[j]); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 55d892d9c16..88369bc98ae 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -2289,16 +2289,21 @@ my %tests = ( create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT COLLATE "C" DEFAULT \'10014\' + CONSTRAINT nn NOT NULL CHECK(VALUE ~ \'^\d{5}$\' OR VALUE ~ \'^\d{5}-\d{4}$\'); + COMMENT ON CONSTRAINT nn + ON DOMAIN dump_test.us_postal_code IS \'not null\'; COMMENT ON CONSTRAINT us_postal_code_check ON DOMAIN dump_test.us_postal_code IS \'check it\';', regexp => qr/^ \QCREATE DOMAIN dump_test.us_postal_code AS text COLLATE pg_catalog."C" DEFAULT '10014'::text\E\n\s+ + \QCONSTRAINT nn NOT NULL \E \QCONSTRAINT us_postal_code_check CHECK \E \Q(((VALUE ~ '^\d{5}\E \$\Q'::text) OR (VALUE ~ '^\d{5}-\d{4}\E\$ \Q'::text)));\E(.|\n)* + \QCOMMENT ON CONSTRAINT nn ON DOMAIN dump_test.us_postal_code IS 'not null';\E \QCOMMENT ON CONSTRAINT us_postal_code_check ON DOMAIN dump_test.us_postal_code IS 'check it';\E /xm, like => -- 2.34.1