Preserve relfilenode of pg_largeobject and its index across pg_upgrade.
authorRobert Haas <[email protected]>
Fri, 8 Jul 2022 14:15:19 +0000 (10:15 -0400)
committerRobert Haas <[email protected]>
Fri, 8 Jul 2022 14:20:27 +0000 (10:20 -0400)
Commit 9a974cbcba005256a19991203583a94b4f9a21a9 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[email protected]

src/bin/pg_dump/pg_dump.c
src/bin/pg_upgrade/t/002_pg_upgrade.pl

index f317f0a681f56d439c171600bea87a5b9e008eea..e4fdb6b75b067e1c76323110795db884ed345cd9 100644 (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, 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', relfilenode = '%u'\n"
+                             "WHERE oid = %u;\n",
+                             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)));
 
-       appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
-       appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
-                         "SET relfrozenxid = '%u', relminmxid = '%u'\n"
-                         "WHERE oid = %u;\n",
-                         atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
-                         atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
-                         LargeObjectRelationId);
        ArchiveEntry(fout, nilCatalogId, createDumpId(),
                     ARCHIVE_OPTS(.tag = "pg_largeobject",
                                  .description = "pg_largeobject",
index 2f9b13bf0ae0c8acdb8ccc3dc2ffa08b51fee253..9ed48c4e06aa0a75c836253ff2735a960647af99 100644 (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}.