Le 17/11/2022 à 17:59, Tom Lane a écrit :
Gilles Darold <gil...@darold.net> writes:
I have an incorrect behavior with pg_dump prior PG version 15. With
PostgreSQL 15, thanks to commit e3fcbbd623b9ccc16cdbda374654d91a4727d173
the problem is gone but for older versions it persists with locks on
partitioned tables.
I didn't want to back-patch e3fcbbd62 at the time, but it's probably aged
long enough now to be safe to back-patch. If we do anything here,
it should be to back-patch the whole thing, else we've only partially
fixed the issue.
Here are the different patched following the PostgreSQL version from 11
to 14, they should apply on the corresponding stable branches. The
patches only concern the move of the unsafe functions,
pg_get_partkeydef() and pg_get_expr(). They should all apply without
problem on their respective branch, pg_dump tap regression test passed
on all versions.
Regards,
--
Gilles Darold
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e110257395..cbe7c1e01d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6322,14 +6322,15 @@ getTables(Archive *fout, int *numTables)
int i_foreignserver;
int i_is_identity_sequence;
int i_changed_acl;
- int i_partkeydef;
int i_ispartition;
- int i_partbound;
int i_amname;
/*
* Find all the tables and table-like objects.
*
+ * We must fetch all tables in this phase because otherwise we cannot
+ * correctly identify inherited columns, owned sequences, etc.
+ *
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
@@ -6343,8 +6344,10 @@ getTables(Archive *fout, int *numTables)
*
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
- * interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, owned sequences, etc.
+ * interesting. In particular, since we do not yet have lock on any user
+ * table, we MUST NOT invoke any server-side data collection functions
+ * (for instance, pg_get_partkeydef()). Those are likely to fail or give
+ * wrong answers if any concurrent DDL is happening.
*
* We purposefully ignore toast OIDs for partitioned tables; the reason is
* that versions 10 and 11 have them, but 12 does not, so emitting them
@@ -6353,9 +6356,7 @@ getTables(Archive *fout, int *numTables)
if (fout->remoteVersion >= 90600)
{
- char *partkeydef = "NULL";
char *ispartition = "false";
- char *partbound = "NULL";
char *relhasoids = "c.relhasoids";
PQExpBuffer acl_subquery = createPQExpBuffer();
@@ -6374,11 +6375,7 @@ getTables(Archive *fout, int *numTables)
*/
if (fout->remoteVersion >= 100000)
- {
- partkeydef = "pg_get_partkeydef(c.oid)";
ispartition = "c.relispartition";
- partbound = "pg_get_expr(c.relpartbound, c.oid)";
- }
/* In PG12 upwards WITH OIDS does not exist anymore. */
if (fout->remoteVersion >= 120000)
@@ -6419,7 +6416,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6439,9 +6436,7 @@ getTables(Archive *fout, int *numTables)
"OR %s IS NOT NULL"
"))"
"AS changed_acl, "
- "%s AS partkeydef, "
- "%s AS ispartition, "
- "%s AS partbound "
+ "%s AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6467,9 +6462,7 @@ getTables(Archive *fout, int *numTables)
attracl_subquery->data,
attinitacl_subquery->data,
attinitracl_subquery->data,
- partkeydef,
ispartition,
- partbound,
RELKIND_SEQUENCE,
RELKIND_PARTITIONED_TABLE,
RELKIND_RELATION, RELKIND_SEQUENCE,
@@ -6512,7 +6505,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6521,9 +6514,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6565,7 +6556,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6574,9 +6565,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6618,7 +6607,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6627,9 +6616,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6671,16 +6658,14 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6720,16 +6705,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6768,16 +6751,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6816,16 +6797,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6863,16 +6842,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"NULL AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6940,9 +6917,7 @@ getTables(Archive *fout, int *numTables)
i_reloftype = PQfnumber(res, "reloftype");
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_changed_acl = PQfnumber(res, "changed_acl");
- i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
- i_partbound = PQfnumber(res, "partbound");
i_amname = PQfnumber(res, "amname");
if (dopt->lockWaitTimeout)
@@ -6990,10 +6965,7 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
- if (PQgetisnull(res, i, i_reloftype))
- tblinfo[i].reloftype = NULL;
- else
- tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
+ tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
if (PQgetisnull(res, i, i_owning_tab))
{
@@ -7050,9 +7022,7 @@ getTables(Archive *fout, int *numTables)
strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
/* Partition key string or NULL */
- tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
- tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
/* foreign server */
tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
@@ -15930,12 +15900,34 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
else
{
+ char *partkeydef = NULL;
char *ftoptions = NULL;
char *srvname = NULL;
char *foreign = "";
+ /*
+ * Set reltypename, and collect any relkind-specific data that we
+ * didn't fetch during getTables().
+ */
switch (tbinfo->relkind)
{
+ case RELKIND_PARTITIONED_TABLE:
+ {
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+
+ reltypename = "TABLE";
+
+ /* retrieve partition key definition */
+ appendPQExpBuffer(query,
+ "SELECT pg_get_partkeydef('%u')",
+ tbinfo->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+ partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ break;
+ }
case RELKIND_FOREIGN_TABLE:
{
PQExpBuffer query = createPQExpBuffer();
@@ -15975,6 +15967,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
break;
default:
reltypename = "TABLE";
+ break;
}
numParents = tbinfo->numParents;
@@ -15996,8 +15989,10 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* Attach to type, if reloftype; except in case of a binary upgrade,
* we dump the table normally and attach it to the type afterward.
*/
- if (tbinfo->reloftype && !dopt->binary_upgrade)
- appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
+ if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
+ appendPQExpBuffer(q, " OF %s",
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroIsError));
if (tbinfo->relkind != RELKIND_MATVIEW)
{
@@ -16035,7 +16030,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* Skip column if fully defined by reloftype, except in
* binary upgrade
*/
- if (tbinfo->reloftype && !print_default && !print_notnull &&
+ if (OidIsValid(tbinfo->reloftype) &&
+ !print_default && !print_notnull &&
!dopt->binary_upgrade)
continue;
@@ -16068,7 +16064,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* table ('OF type_name'), but in binary-upgrade mode,
* print it in that case too.
*/
- if (dopt->binary_upgrade || !tbinfo->reloftype)
+ if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
@@ -16131,7 +16127,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
+ else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
{
/*
* No attributes? we must have a parenthesized attribute list,
@@ -16160,7 +16156,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
+ appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16343,12 +16339,13 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
}
- if (tbinfo->reloftype)
+ if (OidIsValid(tbinfo->reloftype))
{
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
qualrelname,
- tbinfo->reloftype);
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroIsError));
}
}
@@ -16628,6 +16625,8 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer q;
+ PGresult *res;
+ char *partbound;
if (dopt->dataOnly)
return;
@@ -16637,14 +16636,23 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
q = createPQExpBuffer();
- /* Perform ALTER TABLE on the parent */
+ /* Fetch the partition's partbound */
appendPQExpBuffer(q,
+ "SELECT pg_get_expr(c.relpartbound, c.oid) "
+ "FROM pg_class c "
+ "WHERE c.oid = '%u'",
+ attachinfo->partitionTbl->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, q->data);
+ partbound = PQgetvalue(res, 0, 0);
+
+ /* Perform ALTER TABLE on the parent */
+ printfPQExpBuffer(q,
"ALTER TABLE ONLY %s ",
fmtQualifiedDumpable(attachinfo->parentTbl));
appendPQExpBuffer(q,
"ATTACH PARTITION %s %s;\n",
fmtQualifiedDumpable(attachinfo->partitionTbl),
- attachinfo->partitionTbl->partbound);
+ partbound);
/*
* There is no point in creating a drop query as the drop is done by table
@@ -16661,6 +16669,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
.section = SECTION_PRE_DATA,
.createStmt = q->data));
+ PQclear(res);
destroyPQExpBuffer(q);
}
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 8b2a8b67e7..2f24481ec2 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -286,7 +286,7 @@ typedef struct _tableInfo
uint32 toast_frozenxid; /* toast table's relfrozenxid, if any */
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
- char *reloftype; /* underlying type for typed table */
+ Oid reloftype; /* underlying type for typed table */
Oid foreign_server; /* foreign server oid, if applicable */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
@@ -325,8 +325,6 @@ typedef struct _tableInfo
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */
- char *partkeydef; /* partition key definition */
- char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
char *amname; /* relation access method */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 147a860b9b..1081a81d91 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6129,14 +6129,15 @@ getTables(Archive *fout, int *numTables)
int i_foreignserver;
int i_is_identity_sequence;
int i_changed_acl;
- int i_partkeydef;
int i_ispartition;
- int i_partbound;
int i_amname;
/*
* Find all the tables and table-like objects.
*
+ * We must fetch all tables in this phase because otherwise we cannot
+ * correctly identify inherited columns, owned sequences, etc.
+ *
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
@@ -6150,8 +6151,10 @@ getTables(Archive *fout, int *numTables)
*
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
- * interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, owned sequences, etc.
+ * interesting. In particular, since we do not yet have lock on any user
+ * table, we MUST NOT invoke any server-side data collection functions
+ * (for instance, pg_get_partkeydef()). Those are likely to fail or give
+ * wrong answers if any concurrent DDL is happening.
*
* We purposefully ignore toast OIDs for partitioned tables; the reason is
* that versions 10 and 11 have them, but 12 does not, so emitting them
@@ -6160,9 +6163,7 @@ getTables(Archive *fout, int *numTables)
if (fout->remoteVersion >= 90600)
{
- char *partkeydef = "NULL";
char *ispartition = "false";
- char *partbound = "NULL";
char *relhasoids = "c.relhasoids";
PQExpBuffer acl_subquery = createPQExpBuffer();
@@ -6181,11 +6182,7 @@ getTables(Archive *fout, int *numTables)
*/
if (fout->remoteVersion >= 100000)
- {
- partkeydef = "pg_get_partkeydef(c.oid)";
ispartition = "c.relispartition";
- partbound = "pg_get_expr(c.relpartbound, c.oid)";
- }
/* In PG12 upwards WITH OIDS does not exist anymore. */
if (fout->remoteVersion >= 120000)
@@ -6226,7 +6223,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6246,9 +6243,7 @@ getTables(Archive *fout, int *numTables)
"OR %s IS NOT NULL"
"))"
"AS changed_acl, "
- "%s AS partkeydef, "
- "%s AS ispartition, "
- "%s AS partbound "
+ "%s AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6274,9 +6269,7 @@ getTables(Archive *fout, int *numTables)
attracl_subquery->data,
attinitacl_subquery->data,
attinitracl_subquery->data,
- partkeydef,
ispartition,
- partbound,
RELKIND_SEQUENCE,
RELKIND_PARTITIONED_TABLE,
RELKIND_RELATION, RELKIND_SEQUENCE,
@@ -6319,7 +6312,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6328,9 +6321,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6372,7 +6363,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6381,9 +6372,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6425,7 +6414,7 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6434,9 +6423,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6478,16 +6465,14 @@ getTables(Archive *fout, int *numTables)
"CASE WHEN c.relkind = 'f' THEN "
"(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
"ELSE 0 END AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6527,16 +6512,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6575,16 +6558,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6623,16 +6604,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6670,16 +6649,14 @@ getTables(Archive *fout, int *numTables)
"'d' AS relreplident, relpages, "
"NULL AS amname, "
"NULL AS foreignserver, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"NULL AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6747,9 +6724,7 @@ getTables(Archive *fout, int *numTables)
i_reloftype = PQfnumber(res, "reloftype");
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_changed_acl = PQfnumber(res, "changed_acl");
- i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
- i_partbound = PQfnumber(res, "partbound");
i_amname = PQfnumber(res, "amname");
if (dopt->lockWaitTimeout)
@@ -6798,10 +6773,7 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
- if (PQgetisnull(res, i, i_reloftype))
- tblinfo[i].reloftype = NULL;
- else
- tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
+ tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
if (PQgetisnull(res, i, i_owning_tab))
{
@@ -6858,9 +6830,7 @@ getTables(Archive *fout, int *numTables)
strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
/* Partition key string or NULL */
- tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
- tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
/* foreign server */
tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
@@ -15217,15 +15187,15 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
* 'nspname' is the namespace the object is in (NULL if none).
* 'owner' is the owner, NULL if there is no owner (for languages).
* 'acls' contains the ACL string of the object from the appropriate system
- * catalog field; it will be passed to buildACLCommands for building the
- * appropriate GRANT commands.
+ * catalog field; it will be passed to buildACLCommands for building the
+ * appropriate GRANT commands.
* 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
- * object; it will be passed to buildACLCommands for building the
- * appropriate REVOKE commands.
+ * object; it will be passed to buildACLCommands for building the
+ * appropriate REVOKE commands.
* 'initacls' In binary-upgrade mode, ACL string of the object's initial
- * privileges, to be recorded into pg_init_privs
+ * privileges, to be recorded into pg_init_privs
* 'initracls' In binary-upgrade mode, ACL string of the object's
- * revoked-from-default privileges, to be recorded into pg_init_privs
+ * revoked-from-default privileges, to be recorded into pg_init_privs
*
* NB: initacls/initracls are needed because extensions can set privileges on
* an object during the extension's script file and we record those into
@@ -15934,12 +15904,34 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
else
{
+ char *partkeydef = NULL;
char *ftoptions = NULL;
char *srvname = NULL;
char *foreign = "";
+ /*
+ * Set reltypename, and collect any relkind-specific data that we
+ * didn't fetch during getTables().
+ */
switch (tbinfo->relkind)
{
+ case RELKIND_PARTITIONED_TABLE:
+ {
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+
+ reltypename = "TABLE";
+
+ /* retrieve partition key definition */
+ appendPQExpBuffer(query,
+ "SELECT pg_get_partkeydef('%u')",
+ tbinfo->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+ partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ break;
+ }
case RELKIND_FOREIGN_TABLE:
{
PQExpBuffer query = createPQExpBuffer();
@@ -15979,6 +15971,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
break;
default:
reltypename = "TABLE";
+ break;
}
numParents = tbinfo->numParents;
@@ -16000,8 +15993,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Attach to type, if reloftype; except in case of a binary upgrade,
* we dump the table normally and attach it to the type afterward.
*/
- if (tbinfo->reloftype && !dopt->binary_upgrade)
- appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
+ if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
+ appendPQExpBuffer(q, " OF %s",
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroIsError));
if (tbinfo->relkind != RELKIND_MATVIEW)
{
@@ -16039,7 +16034,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Skip column if fully defined by reloftype, except in
* binary upgrade
*/
- if (tbinfo->reloftype && !print_default && !print_notnull &&
+ if (OidIsValid(tbinfo->reloftype) &&
+ !print_default && !print_notnull &&
!dopt->binary_upgrade)
continue;
@@ -16072,7 +16068,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* table ('OF type_name'), but in binary-upgrade mode,
* print it in that case too.
*/
- if (dopt->binary_upgrade || !tbinfo->reloftype)
+ if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
@@ -16135,7 +16131,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
+ else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
{
/*
* No attributes? we must have a parenthesized attribute list,
@@ -16164,7 +16160,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
+ appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16347,12 +16343,13 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
}
- if (tbinfo->reloftype)
+ if (OidIsValid(tbinfo->reloftype))
{
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
qualrelname,
- tbinfo->reloftype);
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroIsError));
}
}
@@ -16365,16 +16362,32 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
*/
if (tbinfo->ispartition)
{
+ PGresult *ares;
+ char *partbound;
+ PQExpBuffer q2;
+
/* With partitions there can only be one parent */
if (tbinfo->numParents != 1)
fatal("invalid number of parents %d for table \"%s\"",
tbinfo->numParents, tbinfo->dobj.name);
+ q2 = createPQExpBuffer();
+ /* Fetch the partition's partbound */
+ appendPQExpBuffer(q2,
+ "SELECT pg_get_expr(c.relpartbound, c.oid) "
+ "FROM pg_class c "
+ "WHERE c.oid = '%u'",
+ tbinfo->dobj.catId.oid);
+ ares = ExecuteSqlQueryForSingleRow(fout, q2->data);
+ partbound = PQgetvalue(ares, 0, 0);
+
/* Perform ALTER TABLE on the parent */
appendPQExpBuffer(q,
"ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
fmtQualifiedDumpable(parents[0]),
- qualrelname, tbinfo->partbound);
+ qualrelname, partbound);
+ PQclear(ares);
+ destroyPQExpBuffer(q2);
}
/*
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 7d41064b8a..cad336c2ff 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -284,7 +284,7 @@ typedef struct _tableInfo
uint32 toast_frozenxid; /* toast table's relfrozenxid, if any */
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
- char *reloftype; /* underlying type for typed table */
+ Oid reloftype; /* underlying type for typed table */
Oid foreign_server; /* foreign server oid, if applicable */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
@@ -322,8 +322,6 @@ typedef struct _tableInfo
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */
- char *partkeydef; /* partition key definition */
- char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
char *amname; /* relation access method */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 17ad1fe07e..6678cc1f5c 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6042,14 +6042,15 @@ getTables(Archive *fout, int *numTables)
int i_relpages;
int i_is_identity_sequence;
int i_changed_acl;
- int i_partkeydef;
int i_ispartition;
- int i_partbound;
int i_amname;
/*
* Find all the tables and table-like objects.
*
+ * We must fetch all tables in this phase because otherwise we cannot
+ * correctly identify inherited columns, owned sequences, etc.
+ *
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
@@ -6063,8 +6064,10 @@ getTables(Archive *fout, int *numTables)
*
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
- * interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, owned sequences, etc.
+ * interesting. In particular, since we do not yet have lock on any user
+ * table, we MUST NOT invoke any server-side data collection functions
+ * (for instance, pg_get_partkeydef()). Those are likely to fail or give
+ * wrong answers if any concurrent DDL is happening.
*
* We purposefully ignore toast OIDs for partitioned tables; the reason is
* that versions 10 and 11 have them, but 12 does not, so emitting them
@@ -6073,9 +6076,7 @@ getTables(Archive *fout, int *numTables)
if (fout->remoteVersion >= 90600)
{
- char *partkeydef = "NULL";
char *ispartition = "false";
- char *partbound = "NULL";
char *relhasoids = "c.relhasoids";
PQExpBuffer acl_subquery = createPQExpBuffer();
@@ -6094,11 +6095,7 @@ getTables(Archive *fout, int *numTables)
*/
if (fout->remoteVersion >= 100000)
- {
- partkeydef = "pg_get_partkeydef(c.oid)";
ispartition = "c.relispartition";
- partbound = "pg_get_expr(c.relpartbound, c.oid)";
- }
/* In PG12 upwards WITH OIDS does not exist anymore. */
if (fout->remoteVersion >= 120000)
@@ -6136,7 +6133,7 @@ getTables(Archive *fout, int *numTables)
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, am.amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6156,9 +6153,7 @@ getTables(Archive *fout, int *numTables)
"OR %s IS NOT NULL"
"))"
"AS changed_acl, "
- "%s AS partkeydef, "
- "%s AS ispartition, "
- "%s AS partbound "
+ "%s AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6184,9 +6179,7 @@ getTables(Archive *fout, int *numTables)
attracl_subquery->data,
attinitacl_subquery->data,
attinitracl_subquery->data,
- partkeydef,
ispartition,
- partbound,
RELKIND_SEQUENCE,
RELKIND_PARTITIONED_TABLE,
RELKIND_RELATION, RELKIND_SEQUENCE,
@@ -6226,7 +6219,7 @@ getTables(Archive *fout, int *numTables)
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, "
"NULL AS amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6235,9 +6228,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6276,7 +6267,7 @@ getTables(Archive *fout, int *numTables)
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, "
"NULL AS amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6285,9 +6276,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6326,7 +6315,7 @@ getTables(Archive *fout, int *numTables)
"c.relpersistence, c.relispopulated, "
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6335,9 +6324,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6376,16 +6363,14 @@ getTables(Archive *fout, int *numTables)
"c.relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6424,16 +6409,14 @@ getTables(Archive *fout, int *numTables)
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6471,16 +6454,14 @@ getTables(Archive *fout, int *numTables)
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6518,16 +6499,14 @@ getTables(Archive *fout, int *numTables)
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
"NULL AS amname, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6564,16 +6543,14 @@ getTables(Archive *fout, int *numTables)
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, relpages, "
"NULL AS amname, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"NULL AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6640,9 +6617,7 @@ getTables(Archive *fout, int *numTables)
i_reloftype = PQfnumber(res, "reloftype");
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_changed_acl = PQfnumber(res, "changed_acl");
- i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
- i_partbound = PQfnumber(res, "partbound");
i_amname = PQfnumber(res, "amname");
if (dopt->lockWaitTimeout)
@@ -6691,10 +6666,7 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
- if (PQgetisnull(res, i, i_reloftype))
- tblinfo[i].reloftype = NULL;
- else
- tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
+ tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
if (PQgetisnull(res, i, i_owning_tab))
{
@@ -6751,9 +6723,7 @@ getTables(Archive *fout, int *numTables)
strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
/* Partition key string or NULL */
- tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
- tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
/*
* Read-lock target tables to make sure they aren't DROPPED or altered
@@ -15097,15 +15067,15 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
* 'nspname' is the namespace the object is in (NULL if none).
* 'owner' is the owner, NULL if there is no owner (for languages).
* 'acls' contains the ACL string of the object from the appropriate system
- * catalog field; it will be passed to buildACLCommands for building the
- * appropriate GRANT commands.
+ * catalog field; it will be passed to buildACLCommands for building the
+ * appropriate GRANT commands.
* 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
- * object; it will be passed to buildACLCommands for building the
- * appropriate REVOKE commands.
+ * object; it will be passed to buildACLCommands for building the
+ * appropriate REVOKE commands.
* 'initacls' In binary-upgrade mode, ACL string of the object's initial
- * privileges, to be recorded into pg_init_privs
+ * privileges, to be recorded into pg_init_privs
* 'initracls' In binary-upgrade mode, ACL string of the object's
- * revoked-from-default privileges, to be recorded into pg_init_privs
+ * revoked-from-default privileges, to be recorded into pg_init_privs
*
* NB: initacls/initracls are needed because extensions can set privileges on
* an object during the extension's script file and we record those into
@@ -15816,11 +15786,33 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
else
{
+ char *partkeydef = NULL;
char *ftoptions = NULL;
char *srvname = NULL;
+ /*
+ * Set reltypename, and collect any relkind-specific data that we
+ * didn't fetch during getTables().
+ */
switch (tbinfo->relkind)
{
+ case RELKIND_PARTITIONED_TABLE:
+ {
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+
+ reltypename = "TABLE";
+
+ /* retrieve partition key definition */
+ appendPQExpBuffer(query,
+ "SELECT pg_get_partkeydef('%u')",
+ tbinfo->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+ partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ break;
+ }
case RELKIND_FOREIGN_TABLE:
{
PQExpBuffer query = createPQExpBuffer();
@@ -15858,6 +15850,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
break;
default:
reltypename = "TABLE";
+ break;
}
numParents = tbinfo->numParents;
@@ -15879,8 +15872,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Attach to type, if reloftype; except in case of a binary upgrade,
* we dump the table normally and attach it to the type afterward.
*/
- if (tbinfo->reloftype && !dopt->binary_upgrade)
- appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
+ if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
+ appendPQExpBuffer(q, " OF %s",
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroAsOpaque));
if (tbinfo->relkind != RELKIND_MATVIEW)
{
@@ -15918,7 +15913,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Skip column if fully defined by reloftype, except in
* binary upgrade
*/
- if (tbinfo->reloftype && !print_default && !print_notnull &&
+ if (OidIsValid(tbinfo->reloftype) &&
+ !print_default && !print_notnull &&
!dopt->binary_upgrade)
continue;
@@ -15951,7 +15947,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* table ('OF type_name'), but in binary-upgrade mode,
* print it in that case too.
*/
- if (dopt->binary_upgrade || !tbinfo->reloftype)
+ if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
@@ -16014,7 +16010,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
+ else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
{
/*
* No attributes? we must have a parenthesized attribute list,
@@ -16043,7 +16039,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
+ appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16227,12 +16223,13 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
}
- if (tbinfo->reloftype)
+ if (OidIsValid(tbinfo->reloftype))
{
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
qualrelname,
- tbinfo->reloftype);
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroAsOpaque));
}
}
@@ -16245,16 +16242,32 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
*/
if (tbinfo->ispartition)
{
+ PGresult *ares;
+ char *partbound;
+ PQExpBuffer q2;
+
/* With partitions there can only be one parent */
if (tbinfo->numParents != 1)
fatal("invalid number of parents %d for table \"%s\"",
tbinfo->numParents, tbinfo->dobj.name);
+ q2 = createPQExpBuffer();
+ /* Fetch the partition's partbound */
+ appendPQExpBuffer(q2,
+ "SELECT pg_get_expr(c.relpartbound, c.oid) "
+ "FROM pg_class c "
+ "WHERE c.oid = '%u'",
+ tbinfo->dobj.catId.oid);
+ ares = ExecuteSqlQueryForSingleRow(fout, q2->data);
+ partbound = PQgetvalue(ares, 0, 0);
+
/* Perform ALTER TABLE on the parent */
appendPQExpBuffer(q,
"ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
fmtQualifiedDumpable(parents[0]),
- qualrelname, tbinfo->partbound);
+ qualrelname, partbound);
+ PQclear(ares);
+ destroyPQExpBuffer(q2);
}
/*
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 0a29919c13..7c93fa3c0e 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -288,7 +288,7 @@ typedef struct _tableInfo
uint32 toast_frozenxid; /* toast table's relfrozenxid, if any */
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
- char *reloftype; /* underlying type for typed table */
+ Oid reloftype; /* underlying type for typed table */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
int owning_col; /* attr # of column owning sequence */
@@ -325,8 +325,6 @@ typedef struct _tableInfo
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */
- char *partkeydef; /* partition key definition */
- char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
char *amname; /* relation access method */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 8554b6eeb1..1d70ff84c6 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5965,13 +5965,14 @@ getTables(Archive *fout, int *numTables)
int i_relpages;
int i_is_identity_sequence;
int i_changed_acl;
- int i_partkeydef;
int i_ispartition;
- int i_partbound;
/*
* Find all the tables and table-like objects.
*
+ * We must fetch all tables in this phase because otherwise we cannot
+ * correctly identify inherited columns, owned sequences, etc.
+ *
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
@@ -5985,15 +5986,15 @@ getTables(Archive *fout, int *numTables)
*
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
- * interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, owned sequences, etc.
+ * interesting. In particular, since we do not yet have lock on any user
+ * table, we MUST NOT invoke any server-side data collection functions
+ * (for instance, pg_get_partkeydef()). Those are likely to fail or give
+ * wrong answers if any concurrent DDL is happening.
*/
if (fout->remoteVersion >= 90600)
{
- char *partkeydef = "NULL";
char *ispartition = "false";
- char *partbound = "NULL";
PQExpBuffer acl_subquery = createPQExpBuffer();
PQExpBuffer racl_subquery = createPQExpBuffer();
@@ -6011,11 +6012,7 @@ getTables(Archive *fout, int *numTables)
*/
if (fout->remoteVersion >= 100000)
- {
- partkeydef = "pg_get_partkeydef(c.oid)";
ispartition = "c.relispartition";
- partbound = "pg_get_expr(c.relpartbound, c.oid)";
- }
/*
* Left join to pick up dependency info linking sequences to their
@@ -6049,7 +6046,7 @@ getTables(Archive *fout, int *numTables)
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6069,9 +6066,7 @@ getTables(Archive *fout, int *numTables)
"OR %s IS NOT NULL"
"))"
"AS changed_acl, "
- "%s AS partkeydef, "
- "%s AS ispartition, "
- "%s AS partbound "
+ "%s AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6095,9 +6090,7 @@ getTables(Archive *fout, int *numTables)
attracl_subquery->data,
attinitacl_subquery->data,
attinitracl_subquery->data,
- partkeydef,
ispartition,
- partbound,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
@@ -6135,7 +6128,7 @@ getTables(Archive *fout, int *numTables)
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6144,9 +6137,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6184,7 +6175,7 @@ getTables(Archive *fout, int *numTables)
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
"c.relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6193,9 +6184,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6233,7 +6222,7 @@ getTables(Archive *fout, int *numTables)
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
"'d' AS relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -6242,9 +6231,7 @@ getTables(Archive *fout, int *numTables)
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6282,16 +6269,14 @@ getTables(Archive *fout, int *numTables)
"0 AS tminmxid, "
"c.relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6329,16 +6314,14 @@ getTables(Archive *fout, int *numTables)
"0 AS tminmxid, "
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "c.reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6375,16 +6358,14 @@ getTables(Archive *fout, int *numTables)
"0 AS tminmxid, "
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"tc.reloptions AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6421,16 +6402,14 @@ getTables(Archive *fout, int *numTables)
"0 AS tminmxid, "
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, c.relpages, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"c.reloptions AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6466,16 +6445,14 @@ getTables(Archive *fout, int *numTables)
"0 AS tfrozenxid, 0 AS tminmxid,"
"'p' AS relpersistence, 't' as relispopulated, "
"'d' AS relreplident, relpages, "
- "NULL AS reloftype, "
+ "0 AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"NULL AS reloptions, "
"NULL AS toast_reloptions, "
"NULL AS changed_acl, "
- "NULL AS partkeydef, "
- "false AS ispartition, "
- "NULL AS partbound "
+ "false AS ispartition "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -6542,9 +6519,7 @@ getTables(Archive *fout, int *numTables)
i_reloftype = PQfnumber(res, "reloftype");
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_changed_acl = PQfnumber(res, "changed_acl");
- i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
- i_partbound = PQfnumber(res, "partbound");
if (dopt->lockWaitTimeout)
{
@@ -6592,10 +6567,7 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
- if (PQgetisnull(res, i, i_reloftype))
- tblinfo[i].reloftype = NULL;
- else
- tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
+ tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
if (PQgetisnull(res, i, i_owning_tab))
{
@@ -6648,9 +6620,7 @@ getTables(Archive *fout, int *numTables)
strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
/* Partition key string or NULL */
- tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
- tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
/*
* Read-lock target tables to make sure they aren't DROPPED or altered
@@ -14937,15 +14907,15 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
* 'nspname' is the namespace the object is in (NULL if none).
* 'owner' is the owner, NULL if there is no owner (for languages).
* 'acls' contains the ACL string of the object from the appropriate system
- * catalog field; it will be passed to buildACLCommands for building the
- * appropriate GRANT commands.
+ * catalog field; it will be passed to buildACLCommands for building the
+ * appropriate GRANT commands.
* 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
- * object; it will be passed to buildACLCommands for building the
- * appropriate REVOKE commands.
+ * object; it will be passed to buildACLCommands for building the
+ * appropriate REVOKE commands.
* 'initacls' In binary-upgrade mode, ACL string of the object's initial
- * privileges, to be recorded into pg_init_privs
+ * privileges, to be recorded into pg_init_privs
* 'initracls' In binary-upgrade mode, ACL string of the object's
- * revoked-from-default privileges, to be recorded into pg_init_privs
+ * revoked-from-default privileges, to be recorded into pg_init_privs
*
* NB: initacls/initracls are needed because extensions can set privileges on
* an object during the extension's script file and we record those into
@@ -15600,6 +15570,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
char *ftoptions;
int j,
k;
+ char *partkeydef;
/* We had better have loaded per-column details about this table */
Assert(tbinfo->interesting);
@@ -15651,8 +15622,31 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
else
{
+ srvname = NULL;
+ ftoptions = NULL;
+ partkeydef = NULL;
+
switch (tbinfo->relkind)
{
+ case RELKIND_PARTITIONED_TABLE:
+ {
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ int i_partkeydef;
+
+ reltypename = "TABLE";
+
+ /* retrieve partition key definition */
+ appendPQExpBuffer(query,
+ "SELECT pg_get_partkeydef('%u') as partkeydef",
+ tbinfo->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+ i_partkeydef = PQfnumber(res, "partkeydef");
+ partkeydef = pg_strdup(PQgetvalue(res, 0, i_partkeydef));
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ break;
+ }
case RELKIND_FOREIGN_TABLE:
{
PQExpBuffer query = createPQExpBuffer();
@@ -15687,13 +15681,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
case RELKIND_MATVIEW:
reltypename = "MATERIALIZED VIEW";
- srvname = NULL;
- ftoptions = NULL;
break;
default:
reltypename = "TABLE";
- srvname = NULL;
- ftoptions = NULL;
+ break;
}
numParents = tbinfo->numParents;
@@ -15715,8 +15706,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Attach to type, if reloftype; except in case of a binary upgrade,
* we dump the table normally and attach it to the type afterward.
*/
- if (tbinfo->reloftype && !dopt->binary_upgrade)
- appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
+ if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
+ appendPQExpBuffer(q, " OF %s",
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroAsOpaque));
if (tbinfo->relkind != RELKIND_MATVIEW)
{
@@ -15754,7 +15747,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* Skip column if fully defined by reloftype, except in
* binary upgrade
*/
- if (tbinfo->reloftype && !print_default && !print_notnull &&
+ if (OidIsValid(tbinfo->reloftype) &&
+ !print_default && !print_notnull &&
!dopt->binary_upgrade)
continue;
@@ -15787,7 +15781,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
* table ('OF type_name'), but in binary-upgrade mode,
* print it in that case too.
*/
- if (dopt->binary_upgrade || !tbinfo->reloftype)
+ if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
@@ -15843,7 +15837,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
+ else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
{
/*
* No attributes? we must have a parenthesized attribute list,
@@ -15872,7 +15866,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
+ appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16056,12 +16050,13 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
}
- if (tbinfo->reloftype)
+ if (OidIsValid(tbinfo->reloftype))
{
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
qualrelname,
- tbinfo->reloftype);
+ getFormattedTypeName(fout, tbinfo->reloftype,
+ zeroAsOpaque));
}
}
@@ -16074,16 +16069,32 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
*/
if (tbinfo->ispartition)
{
+ PGresult *ares;
+ char *partbound;
+ PQExpBuffer q2;
+
/* With partitions there can only be one parent */
if (tbinfo->numParents != 1)
exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
tbinfo->numParents, tbinfo->dobj.name);
+ q2 = createPQExpBuffer();
+ /* Fetch the partition's partbound */
+ appendPQExpBuffer(q2,
+ "SELECT pg_get_expr(c.relpartbound, c.oid) "
+ "FROM pg_class c "
+ "WHERE c.oid = '%u'",
+ tbinfo->dobj.catId.oid);
+ ares = ExecuteSqlQueryForSingleRow(fout, q2->data);
+ partbound = PQgetvalue(ares, 0, 0);
+
/* Perform ALTER TABLE on the parent */
appendPQExpBuffer(q,
"ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
fmtQualifiedDumpable(parents[0]),
- qualrelname, tbinfo->partbound);
+ qualrelname, partbound);
+ PQclear(ares);
+ destroyPQExpBuffer(q2);
}
/*
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 4fbe2aaff9..0b11f792ae 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -288,7 +288,7 @@ typedef struct _tableInfo
uint32 toast_frozenxid; /* toast table's relfrozenxid, if any */
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
- char *reloftype; /* underlying type for typed table */
+ Oid reloftype; /* underlying type for typed table */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
int owning_col; /* attr # of column owning sequence */
@@ -324,8 +324,6 @@ typedef struct _tableInfo
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */
- char *partkeydef; /* partition key definition */
- char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
/*