@@ -15764,6 +15764,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15764
15764
DumpOptions *dopt = fout->dopt;
15765
15765
PQExpBuffer q = createPQExpBuffer();
15766
15766
PQExpBuffer delq = createPQExpBuffer();
15767
+ PQExpBuffer extra = createPQExpBuffer();
15767
15768
char *qrelname;
15768
15769
char *qualrelname;
15769
15770
intnumParents;
@@ -15830,7 +15831,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15830
15831
char *partkeydef = NULL;
15831
15832
char *ftoptions = NULL;
15832
15833
char *srvname = NULL;
15833
- char *foreign = "";
15834
+ const char *foreign = "";
15834
15835
15835
15836
/*
15836
15837
* Set reltypename, and collect any relkind-specific data that we
@@ -16188,70 +16189,130 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16188
16189
tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
16189
16190
tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
16190
16191
{
16192
+ boolfirstitem;
16193
+
16194
+ /*
16195
+ * Drop any dropped columns. Merge the pg_attribute manipulations
16196
+ * into a single SQL command, so that we don't cause repeated
16197
+ * relcache flushes on the target table. Otherwise we risk O(N^2)
16198
+ * relcache bloat while dropping N columns.
16199
+ */
16200
+ resetPQExpBuffer(extra);
16201
+ firstitem = true;
16191
16202
for (j = 0; j < tbinfo->numatts; j++)
16192
16203
{
16193
16204
if (tbinfo->attisdropped[j])
16194
16205
{
16195
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
16196
- appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
16197
- "SET attlen = %d, "
16198
- "attalign = '%c', attbyval = false\n"
16199
- "WHERE attname = ",
16206
+ if (firstitem)
16207
+ {
16208
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
16209
+ "UPDATE pg_catalog.pg_attribute\n"
16210
+ "SET attlen = v.dlen, "
16211
+ "attalign = v.dalign, "
16212
+ "attbyval = false\n"
16213
+ "FROM (VALUES ");
16214
+ firstitem = false;
16215
+ }
16216
+ else
16217
+ appendPQExpBufferStr(q, ",\n ");
16218
+ appendPQExpBufferChar(q, '(');
16219
+ appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16220
+ appendPQExpBuffer(q, ", %d, '%c')",
16200
16221
tbinfo->attlen[j],
16201
16222
tbinfo->attalign[j]);
16202
- appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16203
- appendPQExpBufferStr(q, "\n AND attrelid = ");
16204
- appendStringLiteralAH(q, qualrelname, fout);
16205
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16206
-
16207
- if (tbinfo->relkind == RELKIND_RELATION ||
16208
- tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16209
- appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16210
- qualrelname);
16211
- else
16212
- appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16213
- qualrelname);
16214
- appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16223
+ /* The ALTER ... DROP COLUMN commands must come after */
16224
+ appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
16225
+ foreign, qualrelname);
16226
+ appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
16215
16227
fmtId(tbinfo->attnames[j]));
16216
16228
}
16217
- else if (!tbinfo->attislocal[j])
16229
+ }
16230
+ if (!firstitem)
16231
+ {
16232
+ appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
16233
+ "WHERE attrelid = ");
16234
+ appendStringLiteralAH(q, qualrelname, fout);
16235
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
16236
+ " AND attname = v.dname;\n");
16237
+ /* Now we can issue the actual DROP COLUMN commands */
16238
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
16239
+ }
16240
+
16241
+ /*
16242
+ * Fix up inherited columns. As above, do the pg_attribute
16243
+ * manipulations in a single SQL command.
16244
+ */
16245
+ firstitem = true;
16246
+ for (j = 0; j < tbinfo->numatts; j++)
16247
+ {
16248
+ if (!tbinfo->attisdropped[j] &&
16249
+ !tbinfo->attislocal[j])
16218
16250
{
16219
- appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16220
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16221
- "SET attislocal = false\n"
16222
- "WHERE attname = ");
16251
+ if (firstitem)
16252
+ {
16253
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
16254
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16255
+ "SET attislocal = false\n"
16256
+ "WHERE attrelid = ");
16257
+ appendStringLiteralAH(q, qualrelname, fout);
16258
+ appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
16259
+ " AND attname IN (");
16260
+ firstitem = false;
16261
+ }
16262
+ else
16263
+ appendPQExpBufferStr(q, ", ");
16223
16264
appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16224
- appendPQExpBufferStr(q, "\n AND attrelid = ");
16225
- appendStringLiteralAH(q, qualrelname, fout);
16226
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16227
16265
}
16228
16266
}
16267
+ if (!firstitem)
16268
+ appendPQExpBufferStr(q, ");\n");
16229
16269
16230
16270
/*
16231
16271
* Add inherited CHECK constraints, if any.
16232
16272
*
16233
16273
* For partitions, they were already dumped, and conislocal
16234
16274
* doesn't need fixing.
16275
+ *
16276
+ * As above, issue only one direct manipulation of pg_constraint.
16277
+ * Although it is tempting to merge the ALTER ADD CONSTRAINT
16278
+ * commands into one as well, refrain for now due to concern about
16279
+ * possible backend memory bloat if there are many such
16280
+ * constraints.
16235
16281
*/
16282
+ resetPQExpBuffer(extra);
16283
+ firstitem = true;
16236
16284
for (k = 0; k < tbinfo->ncheck; k++)
16237
16285
{
16238
16286
ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16239
16287
16240
16288
if (constr->separate || constr->conislocal || tbinfo->ispartition)
16241
16289
continue;
16242
16290
16243
- appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
16291
+ if (firstitem)
16292
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
16244
16293
appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
16245
16294
foreign, qualrelname,
16246
16295
fmtId(constr->dobj.name),
16247
16296
constr->condef);
16248
- appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16249
- "SET conislocal = false\n"
16250
- "WHERE contype = 'c' AND conname = ");
16251
- appendStringLiteralAH(q, constr->dobj.name, fout);
16252
- appendPQExpBufferStr(q, "\n AND conrelid = ");
16253
- appendStringLiteralAH(q, qualrelname, fout);
16254
- appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16297
+ /* Update pg_constraint after all the ALTER TABLEs */
16298
+ if (firstitem)
16299
+ {
16300
+ appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
16301
+ "SET conislocal = false\n"
16302
+ "WHERE contype = 'c' AND conrelid = ");
16303
+ appendStringLiteralAH(extra, qualrelname, fout);
16304
+ appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
16305
+ appendPQExpBufferStr(extra, " AND conname IN (");
16306
+ firstitem = false;
16307
+ }
16308
+ else
16309
+ appendPQExpBufferStr(extra, ", ");
16310
+ appendStringLiteralAH(extra, constr->dobj.name, fout);
16311
+ }
16312
+ if (!firstitem)
16313
+ {
16314
+ appendPQExpBufferStr(extra, ");\n");
16315
+ appendBinaryPQExpBuffer(q, extra->data, extra->len);
16255
16316
}
16256
16317
16257
16318
if (numParents > 0 && !tbinfo->ispartition)
@@ -16438,7 +16499,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16438
16499
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16439
16500
tbinfo->attfdwoptions[j][0] != '\0')
16440
16501
appendPQExpBuffer(q,
16441
- "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16502
+ "ALTER FOREIGN TABLEONLY %s ALTER COLUMN %s OPTIONS (\n"
16442
16503
" %s\n"
16443
16504
");\n",
16444
16505
qualrelname,
@@ -16539,6 +16600,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
16539
16600
16540
16601
destroyPQExpBuffer(q);
16541
16602
destroyPQExpBuffer(delq);
16603
+ destroyPQExpBuffer(extra);
16542
16604
free(qrelname);
16543
16605
free(qualrelname);
16544
16606
}