0002-move-unsafe-function-calls-13-backport-1.patch
text/x-patch
Filename: 0002-move-unsafe-function-calls-13-backport-1.patch
Type: text/x-patch
Part: 1
Message:
Re: [BUG] pg_dump blocked
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| src/bin/pg_dump/pg_dump.c | 84 | 71 |
| src/bin/pg_dump/pg_dump.h | 1 | 3 |
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 */