Preserve relfilenode of pg_largeobject and its index across pg_upgrade.

Commit 9a974cbcba did this for user
tables, but pg_upgrade treats pg_largeobject as a user table, and so
needs the same treatment. Without this fix, if you rewrite the
pg_largeobject table and then perform an upgrade with pg_upgrade, the
table will apparently be empty on the new cluster, while all of your
objects will end up with an orphaned file.

With this fix, instead of the old cluster's pg_largeobject files ending
up orphaned, the original files fro the new cluster do. That's mostly
harmless because we expect the table to be empty, but we might want
to arrange to remove the as part of the upgrade. Since we're still
debating the best way of doing that, I (rhaas) have decided to postpone
dealing with that problem and get the basic fix committed.

Justin Pryzby, reviewed by Shruthi Gowda and by me.

Discussion: http://postgr.es/m/20220701231413.GI13040@telsasoft.com
This commit is contained in:
Robert Haas 2022-07-08 10:15:19 -04:00
parent 2b2bcc22e5
commit a2996478c3
2 changed files with 24 additions and 15 deletions

View File

@ -3134,7 +3134,7 @@ dumpDatabase(Archive *fout)
/*
* pg_largeobject comes from the old system intact, so set its
* relfrozenxids and relminmxids.
* relfrozenxids, relminmxids and relfilenode.
*/
if (dopt->binary_upgrade)
{
@ -3142,34 +3142,41 @@ dumpDatabase(Archive *fout)
PQExpBuffer loFrozenQry = createPQExpBuffer();
PQExpBuffer loOutQry = createPQExpBuffer();
int i_relfrozenxid,
i_relfilenode,
i_oid,
i_relminmxid;
/*
* pg_largeobject
*/
if (fout->remoteVersion >= 90300)
appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
"FROM pg_catalog.pg_class\n"
"WHERE oid = %u;\n",
LargeObjectRelationId);
"WHERE oid IN (%u, %u);\n",
LargeObjectRelationId, LargeObjectLOidPNIndexId);
else
appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
"FROM pg_catalog.pg_class\n"
"WHERE oid = %u;\n",
LargeObjectRelationId);
"WHERE oid IN (%u, %u);\n",
LargeObjectRelationId, LargeObjectLOidPNIndexId);
lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
i_relminmxid = PQfnumber(lo_res, "relminmxid");
i_relfilenode = PQfnumber(lo_res, "relfilenode");
i_oid = PQfnumber(lo_res, "oid");
appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve values for pg_largeobject and its index\n");
for (int i = 0; i < PQntuples(lo_res); ++i)
appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u', relminmxid = '%u'\n"
"SET relfrozenxid = '%u', relminmxid = '%u', relfilenode = '%u'\n"
"WHERE oid = %u;\n",
atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
LargeObjectRelationId);
atooid(PQgetvalue(lo_res, i, i_relfrozenxid)),
atooid(PQgetvalue(lo_res, i, i_relminmxid)),
atooid(PQgetvalue(lo_res, i, i_relfilenode)),
atooid(PQgetvalue(lo_res, i, i_oid)));
ArchiveEntry(fout, nilCatalogId, createDumpId(),
ARCHIVE_OPTS(.tag = "pg_largeobject",
.description = "pg_largeobject",

View File

@ -208,6 +208,8 @@ if (defined($ENV{oldinstall}))
}
}
$oldnode->safe_psql("regression", "VACUUM FULL pg_largeobject;");
# In a VPATH build, we'll be started in the source directory, but we want
# to run pg_upgrade in the build directory so that any files generated finish
# in it, like delete_old_cluster.{sh,bat}.