@@ -15670,6 +15670,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15670
15670
DumpOptions *dopt = fout->dopt;
15671
15671
PQExpBuffer q = createPQExpBuffer();
15672
15672
PQExpBuffer delq = createPQExpBuffer();
15673
+ PQExpBuffer extra = createPQExpBuffer();
15673
15674
char *qrelname;
15674
15675
char *qualrelname;
15675
15676
int numParents;
@@ -15736,7 +15737,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15736
15737
char *partkeydef = NULL;
15737
15738
char *ftoptions = NULL;
15738
15739
char *srvname = NULL;
15739
- char *foreign = "";
15740
+ const char *foreign = "";
15740
15741
15741
15742
/*
15742
15743
* Set reltypename, and collect any relkind-specific data that we
@@ -16094,70 +16095,130 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16094
16095
tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
16095
16096
tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
16096
16097
{
16098
+ bool firstitem;
16099
+
16100
+ /*
16101
+ * Drop any dropped columns. Merge the pg_attribute manipulations
16102
+ * into a single SQL command, so that we don't cause repeated
16103
+ * relcache flushes on the target table. Otherwise we risk O(N^2)
16104
+ * relcache bloat while dropping N columns.
16105
+ */
16106
+ resetPQExpBuffer(extra);
16107
+ firstitem = true;
16097
16108
for (j = 0; j < tbinfo->numatts; j++)
16098
16109
{
16099
16110
if (tbinfo->attisdropped[j])
16100
16111
{
16101
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
16102
- appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
16103
- "SET attlen = %d, "
16104
- "attalign = '%c', attbyval = false\n"
16105
- "WHERE attname = ",
16112
+ if (firstitem)
16113
+ {
16114
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
16115
+ "UPDATE pg_catalog.pg_attribute\n"
16116
+ "SET attlen = v.dlen, "
16117
+ "attalign = v.dalign, "
16118
+ "attbyval = false\n"
16119
+ "FROM (VALUES ");
16120
+ firstitem = false;
16121
+ }
16122
+ else
16123
+ appendPQExpBufferStr(q, ",\n ");
16124
+ appendPQExpBufferChar(q, '(');
16125
+ appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16126
+ appendPQExpBuffer(q, ", %d, '%c')",
16106
16127
tbinfo->attlen[j],
16107
16128
tbinfo->attalign[j]);
16108
- appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16109
- appendPQExpBufferStr(q, "\n AND attrelid = ");
16110
- appendStringLiteralAH(q, qualrelname, fout);
16111
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16112
-
16113
- if (tbinfo->relkind == RELKIND_RELATION ||
16114
- tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16115
- appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16116
- qualrelname);
16117
- else
16118
- appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16119
- qualrelname);
16120
- appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16129
+ /* The ALTER ... DROP COLUMN commands must come after */
16130
+ appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
16131
+ foreign, qualrelname);
16132
+ appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
16121
16133
fmtId(tbinfo->attnames[j]));
16122
16134
}
16123
- else if (!tbinfo->attislocal[j])
16135
+ }
16136
+ if (!firstitem)
16137
+ {
16138
+ appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
16139
+ "WHERE attrelid = ");
16140
+ appendStringLiteralAH(q, qualrelname, fout);
16141
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
16142
+ " AND attname = v.dname;\n");
16143
+ /* Now we can issue the actual DROP COLUMN commands */
16144
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
16145
+ }
16146
+
16147
+ /*
16148
+ * Fix up inherited columns. As above, do the pg_attribute
16149
+ * manipulations in a single SQL command.
16150
+ */
16151
+ firstitem = true;
16152
+ for (j = 0; j < tbinfo->numatts; j++)
16153
+ {
16154
+ if (!tbinfo->attisdropped[j] &&
16155
+ !tbinfo->attislocal[j])
16124
16156
{
16125
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16126
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16127
- "SET attislocal = false\n"
16128
- "WHERE attname = ");
16157
+ if (firstitem)
16158
+ {
16159
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
16160
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16161
+ "SET attislocal = false\n"
16162
+ "WHERE attrelid = ");
16163
+ appendStringLiteralAH(q, qualrelname, fout);
16164
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
16165
+ " AND attname IN (");
16166
+ firstitem = false;
16167
+ }
16168
+ else
16169
+ appendPQExpBufferStr(q, ", ");
16129
16170
appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16130
- appendPQExpBufferStr(q, "\n AND attrelid = ");
16131
- appendStringLiteralAH(q, qualrelname, fout);
16132
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16133
16171
}
16134
16172
}
16173
+ if (!firstitem)
16174
+ appendPQExpBufferStr(q, ");\n");
16135
16175
16136
16176
/*
16137
16177
* Add inherited CHECK constraints, if any.
16138
16178
*
16139
16179
* For partitions, they were already dumped, and conislocal
16140
16180
* doesn't need fixing.
16181
+ *
16182
+ * As above, issue only one direct manipulation of pg_constraint.
16183
+ * Although it is tempting to merge the ALTER ADD CONSTRAINT
16184
+ * commands into one as well, refrain for now due to concern about
16185
+ * possible backend memory bloat if there are many such
16186
+ * constraints.
16141
16187
*/
16188
+ resetPQExpBuffer(extra);
16189
+ firstitem = true;
16142
16190
for (k = 0; k < tbinfo->ncheck; k++)
16143
16191
{
16144
16192
ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16145
16193
16146
16194
if (constr->separate || constr->conislocal || tbinfo->ispartition)
16147
16195
continue;
16148
16196
16149
- appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
16197
+ if (firstitem)
16198
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
16150
16199
appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
16151
16200
foreign, qualrelname,
16152
16201
fmtId(constr->dobj.name),
16153
16202
constr->condef);
16154
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16155
- "SET conislocal = false\n"
16156
- "WHERE contype = 'c' AND conname = ");
16157
- appendStringLiteralAH(q, constr->dobj.name, fout);
16158
- appendPQExpBufferStr(q, "\n AND conrelid = ");
16159
- appendStringLiteralAH(q, qualrelname, fout);
16160
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16203
+ /* Update pg_constraint after all the ALTER TABLEs */
16204
+ if (firstitem)
16205
+ {
16206
+ appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
16207
+ "SET conislocal = false\n"
16208
+ "WHERE contype = 'c' AND conrelid = ");
16209
+ appendStringLiteralAH(extra, qualrelname, fout);
16210
+ appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
16211
+ appendPQExpBufferStr(extra, " AND conname IN (");
16212
+ firstitem = false;
16213
+ }
16214
+ else
16215
+ appendPQExpBufferStr(extra, ", ");
16216
+ appendStringLiteralAH(extra, constr->dobj.name, fout);
16217
+ }
16218
+ if (!firstitem)
16219
+ {
16220
+ appendPQExpBufferStr(extra, ");\n");
16221
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
16161
16222
}
16162
16223
16163
16224
if (numParents > 0 && !tbinfo->ispartition)
@@ -16344,7 +16405,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16344
16405
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16345
16406
tbinfo->attfdwoptions[j][0] != '\0')
16346
16407
appendPQExpBuffer(q,
16347
- "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16408
+ "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
16348
16409
" %s\n"
16349
16410
");\n",
16350
16411
qualrelname,
@@ -16445,6 +16506,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16445
16506
16446
16507
destroyPQExpBuffer(q);
16447
16508
destroyPQExpBuffer(delq);
16509
+ destroyPQExpBuffer(extra);
16448
16510
free(qrelname);
16449
16511
free(qualrelname);
16450
16512
}
0 commit comments