8000 Teach pg_dump to quote reloption values safely. · qadahtm/postgres@e4959fb · GitHub
[go: up one dir, main page]

Skip to content

Commit e4959fb

Browse files
committed
Teach pg_dump to quote reloption values safely.
Commit c7e27be fixed this on the backend side, but we neglected the fact that several code paths in pg_dump were printing reloptions values that had not gotten massaged by ruleutils. Apply essentially the same quoting logic in those places, too.
1 parent aa078a9 commit e4959fb

File tree

2 files changed

+113
-28
lines changed

2 files changed

+113
-28
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 112 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
245245
const char *objlabel);
246246
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
247247
static const char *fmtCopyColumnList(const TableInfo *ti);
248+
static bool nonemptyReloptions(const char *reloptions);
249+
static void fmtReloptionsArray(Archive *fout, PQExpBuffer buffer,
250+
const char *reloptions, const char *prefix);
248251
static void do_sql_command(PGconn *conn, const char *query);
249252
static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
250253
ExecStatusType expected);
@@ -3956,8 +3959,8 @@ getTables(int *numTables)
39563959
"d.refobjid AS owning_tab, "
39573960
"d.refobjsubid AS owning_col, "
39583961
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3959-
"array_to_string(c.reloptions, ', ') AS reloptions, "
3960-
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3962+
"c.reloptions AS reloptions, "
3963+
"tc.reloptions AS toast_reloptions "
39613964
"FROM pg_class c "
39623965
"LEFT JOIN pg_depend d ON "
39633966
"(c.relkind = '%c' AND "
@@ -3992,8 +3995,8 @@ getTables(int *numTables)
39923995
"d.refobjid AS owning_tab, "
39933996
"d.refobjsubid AS owning_col, "
39943997
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3995-
"array_to_string(c.reloptions, ', ') AS reloptions, "
3996-
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3998+
"c.reloptions AS reloptions, "
3999+
"tc.reloptions AS toast_reloptions "
39974000
"FROM pg_class c "
39984001
"LEFT JOIN pg_depend d ON "
39994002
"(c.relkind = '%c' AND "
@@ -4027,8 +4030,8 @@ getTables(int *numTables)
40274030
"d.refobjid AS owning_tab, "
40284031
"d.refobjsubid AS owning_col, "
40294032
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4030-
"array_to_string(c.reloptions, ', ') AS reloptions, "
4031-
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4033+
"c.reloptions AS reloptions, "
4034+
"tc.reloptions AS toast_reloptions "
40324035
"FROM pg_class c "
40334036
"LEFT JOIN pg_depend d ON "
40344037
"(c.relkind = '%c' AND "
@@ -4062,7 +4065,7 @@ getTables(int *numTables)
40624065
"d.refobjid AS owning_tab, "
40634066
"d.refobjsubid AS owning_col, "
40644067
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4065-
"array_to_string(c.reloptions, ', ') AS reloptions, "
4068+
"c.reloptions AS reloptions, "
40664069
"NULL AS toast_reloptions "
40674070
"FROM pg_class c "
40684071
"LEFT JOIN pg_depend d ON "
@@ -4497,7 +4500,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
44974500
i_conoid,
44984501
i_condef,
44994502
i_tablespace,
4500-
i_options;
4503+
i_indreloptions;
45014504
int ntups;
45024505

45034506
for (i = 0; i < numTables; i++)
@@ -4545,7 +4548,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
45454548
"c.oid AS conoid, "
45464549
"pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
45474550
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4548-
"array_to_string(t.reloptions, ', ') AS options "
4551+
"t.reloptions AS indreloptions "
45494552
"FROM pg_catalog.pg_index i "
45504553
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
45514554
"LEFT JOIN pg_catalog.pg_constraint c "
@@ -4571,7 +4574,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
45714574
"c.oid AS conoid, "
45724575
"null AS condef, "
45734576
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4574-
"array_to_string(t.reloptions, ', ') AS options "
4577+
"t.reloptions AS indreloptions "
45754578
"FROM pg_catalog.pg_index i "
45764579
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
45774580
"LEFT JOIN pg_catalog.pg_depend d "
@@ -4600,7 +4603,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
46004603
"c.oid AS conoid, "
46014604
"null AS condef, "
46024605
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4603-
"null AS options "
4606+
"null AS indreloptions "
46044607
"FROM pg_catalog.pg_index i "
46054608
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
46064609
"LEFT JOIN pg_catalog.pg_depend d "
@@ -4628,7 +4631,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
46284631
"c.oid AS conoid, "
46294632
"null AS condef, "
46304633
"NULL AS tablespace, "
4631-
"null AS options "
4634+
"null AS indreloptions "
46324635
"FROM pg_catalog.pg_index i "
46334636
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
46344637
"LEFT JOIN pg_catalog.pg_depend d "
@@ -4659,7 +4662,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
46594662
"t.oid AS conoid, "
46604663
"null AS condef, "
46614664
"NULL AS tablespace, "
4662-
"null AS options "
4665+
"null AS indreloptions "
46634666
"FROM pg_index i, pg_class t "
46644667
"WHERE t.oid = i.indexrelid "
46654668
"AND i.indrelid = '%u'::oid "
@@ -4685,7 +4688,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
46854688
"t.oid AS conoid, "
46864689
"null AS condef, "
46874690
"NULL AS tablespace, "
4688-
"null AS options "
4691+
"null AS indreloptions "
46894692
"FROM pg_index i, pg_class t "
46904693
"WHERE t.oid = i.indexrelid "
46914694
"AND i.indrelid = '%u'::oid "
@@ -4713,7 +4716,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
47134716
i_conoid = PQfnumber(res, "conoid");
47144717
i_condef = PQfnumber(res, "condef");
47154718
i_tablespace = PQfnumber(res, "tablespace");
4716-
i_options = PQfnumber(res, "options");
4719+
i_indreloptions = PQfnumber(res, "indreloptions");
47174720

47184721
indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
47194722
constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
@@ -4732,7 +4735,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
47324735
indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
47334736
indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
47344737
indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
4735-
indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
4738+
indxinfo[j].indreloptions = strdup(PQgetvalue(res, j, i_indreloptions));
47364739

47374740
/*
47384741
* In pre-7.4 releases, indkeys may contain more entries than
@@ -12448,23 +12451,24 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1244812451
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1244912452
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
1245012453

12451-
if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
12452-
(tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
12454+
if (nonemptyReloptions(tbinfo->reloptions) ||
12455+
nonemptyReloptions(tbinfo->toast_reloptions))
1245312456
{
1245412457
bool addcomma = false;
1245512458

12456-
appendPQExpBuffer(q, "\nWITH (");
12457-
if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12459+
appendPQExpBufferStr(q, "\nWITH (");
12460+
if (nonemptyReloptions(tbinfo->reloptions))
1245812461
{
1245912462
addcomma = true;
12460-
appendPQExpBuffer(q, "%s", tbinfo->reloptions);
12463+
fmtReloptionsArray(fout, q, tbinfo->reloptions, "");
1246112464
}
12462-
if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
12465+
if (nonemptyReloptions(tbinfo->toast_reloptions))
1246312466
{
12464-
appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
12465-
tbinfo->toast_reloptions);
12467+
if (addcomma)
12468+
appendPQExpBufferStr(q, ", ");
12469+
fmtReloptionsArray(fout, q, tbinfo->toast_reloptions, "toast.");
1246612470
}
12467-
appendPQExpBuffer(q, ")");
12471+
appendPQExpBufferChar(q, ')');
1246812472
}
1246912473

1247012474
/* Dump generic options if any */
@@ -12959,8 +12963,12 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
1295912963

1296012964
appendPQExpBuffer(q, ")");
1296112965

12962-
if (indxinfo->options && strlen(indxinfo->options) > 0)
12963-
appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
12966+
if (nonemptyReloptions(indxinfo->indreloptions))
12967+
{
12968+
appendPQExpBufferStr(q, " WITH (");
12969+
fmtReloptionsArray(fout, q, indxinfo->indreloptions, "");
12970+
appendPQExpBufferChar(q, ')');
12971+
}
1296412972

1296512973
if (coninfo->condeferrable)
1296612974
{
@@ -14572,6 +14580,83 @@ fmtCopyColumnList(const TableInfo *ti)
1457214580
return q->data;
1457314581
}
1457414582

14583+
/*
14584+
* Check if a reloptions array is nonempty.
14585+
*/
14586+
static bool
14587+
nonemptyReloptions(const char *reloptions)
14588+
{
14589+
/* Don't want to print it if it's just "{}" */
14590+
return (reloptions != NULL && strlen(reloptions) > 2);
14591+
}
14592+
14593+
/*
14594+
* Format a reloptions array and append it to the given buffer.
14595+
*
14596+
* "prefix" is prepended to the option names; typically it's "" or "toast.".
14597+
*
14598+
* Note: this logic should generally match the backend's flatten_reloptions()
14599+
* (in adt/ruleutils.c).
14600+
*/
14601+
static void
14602+
fmtReloptionsArray(Archive *fout, PQExpBuffer buffer, const char *reloptions,
14603+
const char *prefix)
14604+
{
14605+
char **options;
14606+
int noptions;
14607+
int i;
14608+
14609+
if (!parsePGArray(reloptions, &options, &noptions))
14610+
{
14611+
write_msg(NULL, "WARNING: could not parse reloptions array\n");
14612+
if (options)
14613+
free(options);
14614+
return;
14615+
}
14616+
14617+
for (i = 0; i < noptions; i++)
14618+
{
14619+
char *option = options[i];
14620+
char *name;
14621+
char *separator;
14622+
char *value;
14623+
14624+
/*
14625+
* Each array element should have the form name=value. If the "=" is
14626+
* missing for some reason, treat it like an empty value.
14627+
*/
14628+
name = option;
14629+
separator = strchr(option, '=');
14630+
if (separator)
14631+
{
14632+
*separator = '\0';
14633+
value = separator + 1;
14634+
}
14635+
else
14636+
value = "";
14637+
14638+
if (i > 0)
14639+
appendPQExpBufferStr(buffer, ", ");
14640+
appendPQExpBuffer(buffer, "%s%s=", prefix, fmtId(name));
14641+
14642+
/*
14643+
* In general we need to quote the value; but to avoid unnecessary
14644+
* clutter, do not quote if it is an identifier that would not need
14645+
* quoting. (We could also allow numbers, but that is a bit trickier
14646+
* than it looks --- for example, are leading zeroes significant? We
14647+
* don't want to assume very much here about what custom reloptions
14648+
* might mean.)
14649+
*/
14650+
if (strcmp(fmtId(value), value) == 0)
14651+
appendPQExpBufferStr(buffer, value);
14652+
else
14653+
appendStringLiteralAH(buffer, value, fout);
14654+
}
14655+
14656+
if (options)
14657+
free(options);
14658+
}
14659+
1457514660
/*
1457614661
* Convenience subroutine to execute a SQL command and check for
1457714662
* COMMAND_OK status.

src/bin/pg_dump/pg_dump.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ typedef struct _indxInfo
313313
TableInfo *indextable; /* link to table the index is for */
314314
char *indexdef;
315315
char *tablespace; /* tablespace in which index is stored */
316-
char *options; /* options specified by WITH (...) */
316+
char *indreloptions; /* options specified by WITH (...) */
317317
int indnkeys;
318318
Oid *indkeys;
319319
bool indisclustered;

0 commit comments

Comments
 (0)
0