Fix brown paper bag bug in bbe08b8869.

We must issue the TRUNCATE command first and update relfrozenxid
and relminmxid afterward; otherwise, TRUNCATE overwrites the
previously-set values.

Add a test case like I should have done the first time.

Per buildfarm report from TestUpgradeXversion.pm, by way of Tom
Lane.
This commit is contained in:
Robert Haas 2022-07-29 16:31:57 -04:00
parent e6e804aa27
commit 5c9ea19b79
2 changed files with 55 additions and 9 deletions

View File

@ -3141,7 +3141,7 @@ dumpDatabase(Archive *fout)
PGresult *lo_res; PGresult *lo_res;
PQExpBuffer loFrozenQry = createPQExpBuffer(); PQExpBuffer loFrozenQry = createPQExpBuffer();
PQExpBuffer loOutQry = createPQExpBuffer(); PQExpBuffer loOutQry = createPQExpBuffer();
PQExpBuffer loVacQry = createPQExpBuffer(); PQExpBuffer loHorizonQry = createPQExpBuffer();
int i_relfrozenxid, int i_relfrozenxid,
i_relfilenode, i_relfilenode,
i_oid, i_oid,
@ -3168,14 +3168,14 @@ dumpDatabase(Archive *fout)
i_relfilenode = PQfnumber(lo_res, "relfilenode"); i_relfilenode = PQfnumber(lo_res, "relfilenode");
i_oid = PQfnumber(lo_res, "oid"); i_oid = PQfnumber(lo_res, "oid");
appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n"); appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
appendPQExpBufferStr(loVacQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n"); appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
for (int i = 0; i < PQntuples(lo_res); ++i) for (int i = 0; i < PQntuples(lo_res); ++i)
{ {
Oid oid; Oid oid;
Oid relfilenode; Oid relfilenode;
appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n" appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u', relminmxid = '%u'\n" "SET relfrozenxid = '%u', relminmxid = '%u'\n"
"WHERE oid = %u;\n", "WHERE oid = %u;\n",
atooid(PQgetvalue(lo_res, i, i_relfrozenxid)), atooid(PQgetvalue(lo_res, i, i_relfrozenxid)),
@ -3186,18 +3186,18 @@ dumpDatabase(Archive *fout)
relfilenode = atooid(PQgetvalue(lo_res, i, i_relfilenode)); relfilenode = atooid(PQgetvalue(lo_res, i, i_relfilenode));
if (oid == LargeObjectRelationId) if (oid == LargeObjectRelationId)
appendPQExpBuffer(loVacQry, appendPQExpBuffer(loOutQry,
"SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n", "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
relfilenode); relfilenode);
else if (oid == LargeObjectLOidPNIndexId) else if (oid == LargeObjectLOidPNIndexId)
appendPQExpBuffer(loVacQry, appendPQExpBuffer(loOutQry,
"SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n", "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
relfilenode); relfilenode);
} }
appendPQExpBufferStr(loVacQry, appendPQExpBufferStr(loOutQry,
"TRUNCATE pg_catalog.pg_largeobject;\n"); "TRUNCATE pg_catalog.pg_largeobject;\n");
appendPQExpBufferStr(loOutQry, loVacQry->data); appendPQExpBufferStr(loOutQry, loHorizonQry->data);
ArchiveEntry(fout, nilCatalogId, createDumpId(), ArchiveEntry(fout, nilCatalogId, createDumpId(),
ARCHIVE_OPTS(.tag = "pg_largeobject", ARCHIVE_OPTS(.tag = "pg_largeobject",
@ -3208,8 +3208,8 @@ dumpDatabase(Archive *fout)
PQclear(lo_res); PQclear(lo_res);
destroyPQExpBuffer(loFrozenQry); destroyPQExpBuffer(loFrozenQry);
destroyPQExpBuffer(loHorizonQry);
destroyPQExpBuffer(loOutQry); destroyPQExpBuffer(loOutQry);
destroyPQExpBuffer(loVacQry);
} }
PQclear(res); PQclear(res);

View File

@ -161,6 +161,27 @@ $newnode->command_ok(
], ],
'dump before running pg_upgrade'); 'dump before running pg_upgrade');
# Also record the relfrozenxid and relminmxid horizons.
my $horizon_query = <<EOM;
SELECT
c.oid::regclass, c.relfrozenxid, c.relminmxid
FROM
pg_class c, pg_namespace n
WHERE
c.relnamespace = n.oid AND
((n.nspname !~ '^pg_temp_' AND n.nspname !~ '^pg_toast_temp_' AND
n.nspname NOT IN ('pg_catalog', 'information_schema', 'binary_upgrade',
'pg_toast'))
OR (n.nspname = 'pg_catalog' AND relname IN ('pg_largeobject')))
EOM
$horizon_query =~ s/\s+/ /g; # run it together on one line
$newnode->command_ok(
[
'psql', '-At', '-d', $oldnode->connstr('postgres'),
'-o', "$tempdir/horizon1.txt", '-c', $horizon_query,
],
'horizons before running pg_upgrade');
# After dumping, update references to the old source tree's regress.so # After dumping, update references to the old source tree's regress.so
# to point to the new tree. # to point to the new tree.
if (defined($ENV{oldinstall})) if (defined($ENV{oldinstall}))
@ -294,6 +315,14 @@ $newnode->command_ok(
], ],
'dump after running pg_upgrade'); 'dump after running pg_upgrade');
# And second record of horizons as well.
$newnode->command_ok(
[
'psql', '-At', '-d', $newnode->connstr('postgres'),
'-o', "$tempdir/horizon2.txt", '-c', $horizon_query,
],
'horizons after running pg_upgrade');
# Compare the two dumps, there should be no differences. # Compare the two dumps, there should be no differences.
my $compare_res = compare("$tempdir/dump1.sql", "$tempdir/dump2.sql"); my $compare_res = compare("$tempdir/dump1.sql", "$tempdir/dump2.sql");
is($compare_res, 0, 'old and new dumps match after pg_upgrade'); is($compare_res, 0, 'old and new dumps match after pg_upgrade');
@ -311,4 +340,21 @@ if ($compare_res != 0)
print "=== EOF ===\n"; print "=== EOF ===\n";
} }
# Compare the horizons, there should be no differences.
$compare_res = compare("$tempdir/horizon1.txt", "$tempdir/horizon2.txt");
is($compare_res, 0, 'old and new horizons match after pg_upgrade');
# Provide more context if the horizons do not match.
if ($compare_res != 0)
{
my ($stdout, $stderr) =
run_command([ 'diff', "$tempdir/horizon1.txt", "$tempdir/horizon2.txt" ]);
print "=== diff of $tempdir/horizon1.txt and $tempdir/horizon2.txt\n";
print "=== stdout ===\n";
print $stdout;
print "=== stderr ===\n";
print $stderr;
print "=== EOF ===\n";
}
done_testing(); done_testing();