mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
pg_dump: Fix array literals in fetchAttributeStats().
Presently, fetchAttributeStats() builds array literals by treating
the elements as SQL identifiers. This is incorrect for a couple of
reasons:
* Array literal content must match the external text representation
of the array, i.e., what array_out() would return. One notable
problem is that double quotes are escaped with "" in identifiers
but with \" in array literals. To fix, build the array content
using the pre-existing appendPGArray() function.
* Array literals must be written as string constants. A notable
problem here is that single quotes are escaped via '' in strings
but are not escaped in the text representation of an array. To
fix, append the aforementioned array literal content to the query
with appendStringLiteralAH().
While at it, modify a test case to use an identifier that would
cause the test to fail without this change.
Oversight in commit 9c02e3a986
.
Reported-by: Philippe Beaudoin <pbh.emaj@free.fr>
Author: Jian He <jian.universality@gmail.com>
Co-authored-by: Nathan Bossart <nathandbossart@gmail.com>
Co-authored-by: Stepan Neretin <slpmcf@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Bug: #18923
Discussion: https://postgr.es/m/18923-e79273f87c6bed69%40postgresql.org
This commit is contained in:
@ -10765,6 +10765,9 @@ fetchAttributeStats(Archive *fout)
|
|||||||
restarted = true;
|
restarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendPQExpBufferChar(nspnames, '{');
|
||||||
|
appendPQExpBufferChar(relnames, '{');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the TOC for the next set of relevant stats entries. We assume
|
* Scan the TOC for the next set of relevant stats entries. We assume
|
||||||
* that statistics are dumped in the order they are listed in the TOC.
|
* that statistics are dumped in the order they are listed in the TOC.
|
||||||
@ -10776,23 +10779,25 @@ fetchAttributeStats(Archive *fout)
|
|||||||
if ((te->reqs & REQ_STATS) != 0 &&
|
if ((te->reqs & REQ_STATS) != 0 &&
|
||||||
strcmp(te->desc, "STATISTICS DATA") == 0)
|
strcmp(te->desc, "STATISTICS DATA") == 0)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(nspnames, "%s%s", count ? "," : "",
|
appendPGArray(nspnames, te->namespace);
|
||||||
fmtId(te->namespace));
|
appendPGArray(relnames, te->tag);
|
||||||
appendPQExpBuffer(relnames, "%s%s", count ? "," : "",
|
|
||||||
fmtId(te->tag));
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendPQExpBufferChar(nspnames, '}');
|
||||||
|
appendPQExpBufferChar(relnames, '}');
|
||||||
|
|
||||||
/* Execute the query for the next batch of relations. */
|
/* Execute the query for the next batch of relations. */
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
PQExpBuffer query = createPQExpBuffer();
|
PQExpBuffer query = createPQExpBuffer();
|
||||||
|
|
||||||
appendPQExpBuffer(query, "EXECUTE getAttributeStats("
|
appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
|
||||||
"'{%s}'::pg_catalog.name[],"
|
appendStringLiteralAH(query, nspnames->data, fout);
|
||||||
"'{%s}'::pg_catalog.name[])",
|
appendPQExpBufferStr(query, "::pg_catalog.name[],");
|
||||||
nspnames->data, relnames->data);
|
appendStringLiteralAH(query, relnames->data, fout);
|
||||||
|
appendPQExpBufferStr(query, "::pg_catalog.name[])");
|
||||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||||
destroyPQExpBuffer(query);
|
destroyPQExpBuffer(query);
|
||||||
}
|
}
|
||||||
|
@ -4834,13 +4834,13 @@ my %tests = (
|
|||||||
CREATE TABLE dump_test.has_stats
|
CREATE TABLE dump_test.has_stats
|
||||||
AS SELECT g.g AS x, g.g / 2 AS y FROM generate_series(1,100) AS g(g);
|
AS SELECT g.g AS x, g.g / 2 AS y FROM generate_series(1,100) AS g(g);
|
||||||
CREATE MATERIALIZED VIEW dump_test.has_stats_mv AS SELECT * FROM dump_test.has_stats;
|
CREATE MATERIALIZED VIEW dump_test.has_stats_mv AS SELECT * FROM dump_test.has_stats;
|
||||||
CREATE INDEX dup_test_post_data_ix ON dump_test.has_stats(x, (x - 1));
|
CREATE INDEX """dump_test""\'s post-data index" ON dump_test.has_stats(x, (x - 1));
|
||||||
ANALYZE dump_test.has_stats, dump_test.has_stats_mv;',
|
ANALYZE dump_test.has_stats, dump_test.has_stats_mv;',
|
||||||
regexp => qr/^
|
regexp => qr/^
|
||||||
\QSELECT * FROM pg_catalog.pg_restore_relation_stats(\E\s+
|
\QSELECT * FROM pg_catalog.pg_restore_relation_stats(\E\s+
|
||||||
'version',\s'\d+'::integer,\s+
|
'version',\s'\d+'::integer,\s+
|
||||||
'schemaname',\s'dump_test',\s+
|
'schemaname',\s'dump_test',\s+
|
||||||
'relname',\s'dup_test_post_data_ix',\s+
|
'relname',\s'"dump_test"''s\ post-data\ index',\s+
|
||||||
'relpages',\s'\d+'::integer,\s+
|
'relpages',\s'\d+'::integer,\s+
|
||||||
'reltuples',\s'\d+'::real,\s+
|
'reltuples',\s'\d+'::real,\s+
|
||||||
'relallvisible',\s'\d+'::integer,\s+
|
'relallvisible',\s'\d+'::integer,\s+
|
||||||
@ -4849,7 +4849,7 @@ my %tests = (
|
|||||||
\QSELECT * FROM pg_catalog.pg_restore_attribute_stats(\E\s+
|
\QSELECT * FROM pg_catalog.pg_restore_attribute_stats(\E\s+
|
||||||
'version',\s'\d+'::integer,\s+
|
'version',\s'\d+'::integer,\s+
|
||||||
'schemaname',\s'dump_test',\s+
|
'schemaname',\s'dump_test',\s+
|
||||||
'relname',\s'dup_test_post_data_ix',\s+
|
'relname',\s'"dump_test"''s\ post-data\ index',\s+
|
||||||
'attnum',\s'2'::smallint,\s+
|
'attnum',\s'2'::smallint,\s+
|
||||||
'inherited',\s'f'::boolean,\s+
|
'inherited',\s'f'::boolean,\s+
|
||||||
'null_frac',\s'0'::real,\s+
|
'null_frac',\s'0'::real,\s+
|
||||||
|
Reference in New Issue
Block a user