aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_dump/pg_dump.c134
-rw-r--r--src/bin/pg_dump/t/002_pg_dump.pl2
2 files changed, 99 insertions, 37 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e3240708284..9202a43eb20 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -15764,6 +15764,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
DumpOptions *dopt = fout->dopt;
PQExpBuffer q = createPQExpBuffer();
PQExpBuffer delq = createPQExpBuffer();
+ PQExpBuffer extra = createPQExpBuffer();
char *qrelname;
char *qualrelname;
int numParents;
@@ -15830,7 +15831,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
char *partkeydef = NULL;
char *ftoptions = NULL;
char *srvname = NULL;
- char *foreign = "";
+ const char *foreign = "";
/*
* Set reltypename, and collect any relkind-specific data that we
@@ -16188,51 +16189,98 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
{
+ bool firstitem;
+
+ /*
+ * Drop any dropped columns. Merge the pg_attribute manipulations
+ * into a single SQL command, so that we don't cause repeated
+ * relcache flushes on the target table. Otherwise we risk O(N^2)
+ * relcache bloat while dropping N columns.
+ */
+ resetPQExpBuffer(extra);
+ firstitem = true;
for (j = 0; j < tbinfo->numatts; j++)
{
if (tbinfo->attisdropped[j])
{
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
- appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
- "SET attlen = %d, "
- "attalign = '%c', attbyval = false\n"
- "WHERE attname = ",
+ if (firstitem)
+ {
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
+ "UPDATE pg_catalog.pg_attribute\n"
+ "SET attlen = v.dlen, "
+ "attalign = v.dalign, "
+ "attbyval = false\n"
+ "FROM (VALUES ");
+ firstitem = false;
+ }
+ else
+ appendPQExpBufferStr(q, ",\n ");
+ appendPQExpBufferChar(q, '(');
+ appendStringLiteralAH(q, tbinfo->attnames[j], fout);
+ appendPQExpBuffer(q, ", %d, '%c')",
tbinfo->attlen[j],
tbinfo->attalign[j]);
- appendStringLiteralAH(q, tbinfo->attnames[j], fout);
- appendPQExpBufferStr(q, "\n AND attrelid = ");
- appendStringLiteralAH(q, qualrelname, fout);
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
-
- if (tbinfo->relkind == RELKIND_RELATION ||
- tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
- qualrelname);
- else
- appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
- qualrelname);
- appendPQExpBuffer(q, "DROP COLUMN %s;\n",
+ /* The ALTER ... DROP COLUMN commands must come after */
+ appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
+ foreign, qualrelname);
+ appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
fmtId(tbinfo->attnames[j]));
}
- else if (!tbinfo->attislocal[j])
+ }
+ if (!firstitem)
+ {
+ appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
+ "WHERE attrelid = ");
+ appendStringLiteralAH(q, qualrelname, fout);
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
+ " AND attname = v.dname;\n");
+ /* Now we can issue the actual DROP COLUMN commands */
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
+ }
+
+ /*
+ * Fix up inherited columns. As above, do the pg_attribute
+ * manipulations in a single SQL command.
+ */
+ firstitem = true;
+ for (j = 0; j < tbinfo->numatts; j++)
+ {
+ if (!tbinfo->attisdropped[j] &&
+ !tbinfo->attislocal[j])
{
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
- "SET attislocal = false\n"
- "WHERE attname = ");
+ if (firstitem)
+ {
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
+ "SET attislocal = false\n"
+ "WHERE attrelid = ");
+ appendStringLiteralAH(q, qualrelname, fout);
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
+ " AND attname IN (");
+ firstitem = false;
+ }
+ else
+ appendPQExpBufferStr(q, ", ");
appendStringLiteralAH(q, tbinfo->attnames[j], fout);
- appendPQExpBufferStr(q, "\n AND attrelid = ");
- appendStringLiteralAH(q, qualrelname, fout);
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
}
}
+ if (!firstitem)
+ appendPQExpBufferStr(q, ");\n");
/*
* Add inherited CHECK constraints, if any.
*
* For partitions, they were already dumped, and conislocal
* doesn't need fixing.
+ *
+ * As above, issue only one direct manipulation of pg_constraint.
+ * Although it is tempting to merge the ALTER ADD CONSTRAINT
+ * commands into one as well, refrain for now due to concern about
+ * possible backend memory bloat if there are many such
+ * constraints.
*/
+ resetPQExpBuffer(extra);
+ firstitem = true;
for (k = 0; k < tbinfo->ncheck; k++)
{
ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
@@ -16240,18 +16288,31 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
if (constr->separate || constr->conislocal || tbinfo->ispartition)
continue;
- appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
+ if (firstitem)
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
foreign, qualrelname,
fmtId(constr->dobj.name),
constr->condef);
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
- "SET conislocal = false\n"
- "WHERE contype = 'c' AND conname = ");
- appendStringLiteralAH(q, constr->dobj.name, fout);
- appendPQExpBufferStr(q, "\n AND conrelid = ");
- appendStringLiteralAH(q, qualrelname, fout);
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
+ /* Update pg_constraint after all the ALTER TABLEs */
+ if (firstitem)
+ {
+ appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
+ "SET conislocal = false\n"
+ "WHERE contype = 'c' AND conrelid = ");
+ appendStringLiteralAH(extra, qualrelname, fout);
+ appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
+ appendPQExpBufferStr(extra, " AND conname IN (");
+ firstitem = false;
+ }
+ else
+ appendPQExpBufferStr(extra, ", ");
+ appendStringLiteralAH(extra, constr->dobj.name, fout);
+ }
+ if (!firstitem)
+ {
+ appendPQExpBufferStr(extra, ");\n");
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
}
if (numParents > 0 && !tbinfo->ispartition)
@@ -16438,7 +16499,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
tbinfo->attfdwoptions[j][0] != '\0')
appendPQExpBuffer(q,
- "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
+ "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
" %s\n"
");\n",
qualrelname,
@@ -16539,6 +16600,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(extra);
free(qrelname);
free(qualrelname);
}
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index d3dd8784d64..5bcc2244d58 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -1154,7 +1154,7 @@ my %tests = (
'ALTER FOREIGN TABLE foreign_table ALTER COLUMN c1 OPTIONS' => {
regexp => qr/^
- \QALTER FOREIGN TABLE dump_test.foreign_table ALTER COLUMN c1 OPTIONS (\E\n
+ \QALTER FOREIGN TABLE ONLY dump_test.foreign_table ALTER COLUMN c1 OPTIONS (\E\n
\s+\Qcolumn_name 'col1'\E\n
\Q);\E\n
/xm,