Skip to content

Commit e3fcbbd

Browse files
committed
Postpone calls of unsafe server-side functions in pg_dump.
Avoid calling pg_get_partkeydef(), pg_get_expr(relpartbound), and regtypeout until we have lock on the relevant tables. The existing coding is at serious risk of failure if there are any concurrent DROP TABLE commands going on --- including drops of other sessions' temp tables. Arguably this is a bug fix that should be back-patched, but it's moderately invasive and we've not had all that many complaints about such failures. Let's just put it in HEAD for now. Discussion: https://postgr.es/m/2273648.1634764485@sss.pgh.pa.us Discussion: https://postgr.es/m/7d7eb6128f40401d81b3b7a898b6b4de@W2012-02.nidsa.loc
1 parent 0c9d844 commit e3fcbbd

File tree

2 files changed

+64
-33
lines changed

2 files changed

+64
-33
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6272,20 +6272,23 @@ getTables(Archive *fout, int *numTables)
62726272
int i_is_identity_sequence;
62736273
int i_relacl;
62746274
int i_acldefault;
6275-
int i_partkeydef;
62766275
int i_ispartition;
6277-
int i_partbound;
62786276

62796277
/*
62806278
* Find all the tables and table-like objects.
62816279
*
6280+
* We must fetch all tables in this phase because otherwise we cannot
6281+
* correctly identify inherited columns, owned sequences, etc.
6282+
*
62826283
* We include system catalogs, so that we can work if a user table is
62836284
* defined to inherit from a system catalog (pretty weird, but...)
62846285
*
62856286
* Note: in this phase we should collect only a minimal amount of
62866287
* information about each table, basically just enough to decide if it is
6287-
* interesting. We must fetch all tables in this phase because otherwise
6288-
* we cannot correctly identify inherited columns, owned sequences, etc.
6288+
* interesting. In particular, since we do not yet have lock on any user
6289+
* table, we MUST NOT invoke any server-side data collection functions
6290+
* (for instance, pg_get_partkeydef()). Those are likely to fail or give
6291+
* wrong answers if any concurrent DDL is happening.
62896292
*/
62906293

62916294
appendPQExpBuffer(query,
@@ -6379,10 +6382,10 @@ getTables(Archive *fout, int *numTables)
63796382

63806383
if (fout->remoteVersion >= 90000)
63816384
appendPQExpBufferStr(query,
6382-
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, ");
6385+
"c.reloftype, ");
63836386
else
63846387
appendPQExpBufferStr(query,
6385-
"NULL AS reloftype, ");
6388+
"0 AS reloftype, ");
63866389

63876390
if (fout->remoteVersion >= 90100)
63886391
appendPQExpBufferStr(query,
@@ -6423,14 +6426,10 @@ getTables(Archive *fout, int *numTables)
64236426

64246427
if (fout->remoteVersion >= 100000)
64256428
appendPQExpBufferStr(query,
6426-
"pg_get_partkeydef(c.oid) AS partkeydef, "
6427-
"c.relispartition AS ispartition, "
6428-
"pg_get_expr(c.relpartbound, c.oid) AS partbound ");
6429+
"c.relispartition AS ispartition ");
64296430
else
64306431
appendPQExpBufferStr(query,
6431-
"NULL AS partkeydef, "
6432-
"false AS ispartition, "
6433-
"NULL AS partbound ");
6432+
"false AS ispartition ");
64346433

64356434
/*
64366435
* Left join to pg_depend to pick up dependency info linking sequences to
@@ -6539,9 +6538,7 @@ getTables(Archive *fout, int *numTables)
65396538
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
65406539
i_relacl = PQfnumber(res, "relacl");
65416540
i_acldefault = PQfnumber(res, "acldefault");
6542-
i_partkeydef = PQfnumber(res, "partkeydef");
65436541
i_ispartition = PQfnumber(res, "ispartition");
6544-
i_partbound = PQfnumber(res, "partbound");
65456542

65466543
if (dopt->lockWaitTimeout)
65476544
{
@@ -6607,19 +6604,14 @@ getTables(Archive *fout, int *numTables)
66076604
else
66086605
tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
66096606
tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6610-
if (PQgetisnull(res, i, i_reloftype))
6611-
tblinfo[i].reloftype = NULL;
6612-
else
6613-
tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6607+
tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
66146608
tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
66156609
if (PQgetisnull(res, i, i_amname))
66166610
tblinfo[i].amname = NULL;
66176611
else
66186612
tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
66196613
tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6620-
tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
66216614
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6622-
tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
66236615

66246616
/* other fields were zeroed above */
66256617

@@ -15651,12 +15643,34 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1565115643
}
1565215644
else
1565315645
{
15646+
char *partkeydef = NULL;
1565415647
char *ftoptions = NULL;
1565515648
char *srvname = NULL;
1565615649
char *foreign = "";
1565715650

15651+
/*
15652+
* Set reltypename, and collect any relkind-specific data that we
15653+
* didn't fetch during getTables().
15654+
*/
1565815655
switch (tbinfo->relkind)
1565915656
{
15657+
case RELKIND_PARTITIONED_TABLE:
15658+
{
15659+
PQExpBuffer query = createPQExpBuffer();
15660+
PGresult *res;
15661+
15662+
reltypename = "TABLE";
15663+
15664+
/* retrieve partition key definition */
15665+
appendPQExpBuffer(query,
15666+
"SELECT pg_get_partkeydef('%u')",
15667+
tbinfo->dobj.catId.oid);
15668+
res = ExecuteSqlQueryForSingleRow(fout, query->data);
15669+
partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
15670+
PQclear(res);
15671+
destroyPQExpBuffer(query);
15672+
break;
15673+
}
1566015674
case RELKIND_FOREIGN_TABLE:
1566115675
{
1566215676
PQExpBuffer query = createPQExpBuffer();
@@ -15696,6 +15710,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1569615710
break;
1569715711
default:
1569815712
reltypename = "TABLE";
15713+
break;
1569915714
}
1570015715

1570115716
numParents = tbinfo->numParents;
@@ -15717,8 +15732,10 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1571715732
* Attach to type, if reloftype; except in case of a binary upgrade,
1571815733
* we dump the table normally and attach it to the type afterward.
1571915734
*/
15720-
if (tbinfo->reloftype && !dopt->binary_upgrade)
15721-
appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15735+
if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
15736+
appendPQExpBuffer(q, " OF %s",
15737+
getFormattedTypeName(fout, tbinfo->reloftype,
15738+
zeroIsError));
1572215739

1572315740
if (tbinfo->relkind != RELKIND_MATVIEW)
1572415741
{
@@ -15756,7 +15773,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1575615773
* Skip column if fully defined by reloftype, except in
1575715774
* binary upgrade
1575815775
*/
15759-
if (tbinfo->reloftype && !print_default && !print_notnull &&
15776+
if (OidIsValid(tbinfo->reloftype) &&
15777+
!print_default && !print_notnull &&
1576015778
!dopt->binary_upgrade)
1576115779
continue;
1576215780

@@ -15789,7 +15807,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1578915807
* table ('OF type_name'), but in binary-upgrade mode,
1579015808
* print it in that case too.
1579115809
*/
15792-
if (dopt->binary_upgrade || !tbinfo->reloftype)
15810+
if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
1579315811
{
1579415812
appendPQExpBuffer(q, " %s",
1579515813
tbinfo->atttypnames[j]);
@@ -15852,7 +15870,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1585215870

1585315871
if (actual_atts)
1585415872
appendPQExpBufferStr(q, "\n)");
15855-
else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
15873+
else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
1585615874
{
1585715875
/*
1585815876
* No attributes? we must have a parenthesized attribute list,
@@ -15881,7 +15899,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1588115899
}
1588215900

1588315901
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15884-
appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15902+
appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
1588515903

1588615904
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1588715905
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16064,12 +16082,13 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1606416082
}
1606516083
}
1606616084

16067-
if (tbinfo->reloftype)
16085+
if (OidIsValid(tbinfo->reloftype))
1606816086
{
1606916087
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
1607016088
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
1607116089
qualrelname,
16072-
tbinfo->reloftype);
16090+
getFormattedTypeName(fout, tbinfo->reloftype,
16091+
zeroIsError));
1607316092
}
1607416093
}
1607516094

@@ -16242,6 +16261,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1624216261
tbinfo->attfdwoptions[j]);
1624316262
} /* end loop over columns */
1624416263

16264+
if (partkeydef)
16265+
free(partkeydef);
1624516266
if (ftoptions)
1624616267
free(ftoptions);
1624716268
if (srvname)
@@ -16358,6 +16379,8 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
1635816379
{
1635916380
DumpOptions *dopt = fout->dopt;
1636016381
PQExpBuffer q;
16382+
PGresult *res;
16383+
char *partbound;
1636116384

1636216385
/* Do nothing in data-only dump */
1636316386
if (dopt->dataOnly)
@@ -16368,14 +16391,23 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
1636816391

1636916392
q = createPQExpBuffer();
1637016393

16371-
/* Perform ALTER TABLE on the parent */
16394+
/* Fetch the partition's partbound */
1637216395
appendPQExpBuffer(q,
16396+
"SELECT pg_get_expr(c.relpartbound, c.oid) "
16397+
"FROM pg_class c "
16398+
"WHERE c.oid = '%u'",
16399+
attachinfo->partitionTbl->dobj.catId.oid);
16400+
res = ExecuteSqlQueryForSingleRow(fout, q->data);
16401+
partbound = PQgetvalue(res, 0, 0);
16402+
16403+
/* Perform ALTER TABLE on the parent */
16404+
printfPQExpBuffer(q,
1637316405
"ALTER TABLE ONLY %s ",
1637416406
fmtQualifiedDumpable(attachinfo->parentTbl));
1637516407
appendPQExpBuffer(q,
1637616408
"ATTACH PARTITION %s %s;\n",
1637716409
fmtQualifiedDumpable(attachinfo->partitionTbl),
16378-
attachinfo->partitionTbl->partbound);
16410+
partbound);
1637916411

1638016412
/*
1638116413
* There is no point in creating a drop query as the drop is done by table
@@ -16392,6 +16424,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
1639216424
.section = SECTION_PRE_DATA,
1639316425
.createStmt = q->data));
1639416426

16427+
PQclear(res);
1639516428
destroyPQExpBuffer(q);
1639616429
}
1639716430

src/bin/pg_dump/pg_dump.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ typedef struct _tableInfo
308308
uint32 toast_minmxid; /* toast table's relminmxid */
309309
int ncheck; /* # of CHECK expressions */
310310
Oid reltype; /* OID of table's composite type, if any */
311-
char *reloftype; /* underlying type for typed table */
311+
Oid reloftype; /* underlying type for typed table */
312312
Oid foreign_server; /* foreign server oid, if applicable */
313313
/* these two are set only if table is a sequence owned by a column: */
314314
Oid owning_tab; /* OID of table owning sequence */
@@ -347,8 +347,6 @@ typedef struct _tableInfo
347347
bool *inhNotNull; /* true if NOT NULL is inherited */
348348
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
349349
struct _constraintInfo *checkexprs; /* CHECK constraints */
350-
char *partkeydef; /* partition key definition */
351-
char *partbound; /* partition bound definition */
352350
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
353351
char *amname; /* relation access method */
354352

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy