Hi,
After my tableam patch Andrew's buildfarm animal started failing in the
cross-version upgrades:
https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=crake&dt=2019-03-06%2019%3A32%3A24
But I actually don't think that't really fault of the tableam patch. The
reason for the assertion is that we assert that
Assert(relation->rd_rel->relam != InvalidOid);
for tables that have storage. The table in question is a toast table.
The reason that table doesn't have an AM is that it's the toast table
for a partitioned relation, and for toast tables we just copy the AM
from the main table.
The backtrace shows:
#7 0x0000558b4bdbecfc in create_toast_table (rel=0x7fdab64289e0, toastOid=0,
toastIndexOid=0, reloptions=0, lockmode=8, check=false)
at /home/andres/src/postgresql/src/backend/catalog/toasting.c:263
263 toast_relid = heap_create_with_catalog(toast_relname,
(gdb) p *rel->rd_rel
$2 = {oid = 80244, relname = {
data =
"partitioned_table\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
relnamespace = 2200, reltype = 80246, reloftype = 0, relowner = 10, relam = 0,
relfilenode = 0,
reltablespace = 0, relpages = 0, reltuples = 0, relallvisible = 0,
reltoastrelid = 0, relhasindex = false, relisshared = false, relpersistence =
112 'p',
relkind = 112 'p', relnatts = 2, relchecks = 0, relhasrules = false,
relhastriggers = false, relhassubclass = false, relrowsecurity = false,
relforcerowsecurity = false, relispopulated = true, relreplident = 100 'd',
relispartition = false, relrewrite = 0, relfrozenxid = 0, relminmxid = 0}
that were trying to create a toast table for a partitioned table. Which
seems wrong to me, given that recent commits made partitioned tables
have no storage.
The reason we're creating a storage is that we're upgrading from a
version of PG where partitioned tables *did* have storage. And thus the
dump looks like:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('80246'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT
pg_catalog.binary_upgrade_set_next_array_pg_type_oid('80245'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type toast oid
SELECT
pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('80248'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT
pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('80244'::pg_catalog.oid);
SELECT
pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('80247'::pg_catalog.oid);
SELECT
pg_catalog.binary_upgrade_set_next_index_pg_class_oid('80249'::pg_catalog.oid);
CREATE TABLE "public"."partitioned_table" (
"a" integer,
"b" "text"
)
PARTITION BY LIST ("a");
and create_toast_table() has logic like:
{
/*
* In binary-upgrade mode, create a TOAST table if and only if
* pg_upgrade told us to (ie, a TOAST table OID has been
provided).
*
* This indicates that the old cluster had a TOAST table for the
* current table. We must create a TOAST table to receive the
old
* TOAST file, even if the table seems not to need one.
*
* Contrariwise, if the old cluster did not have a TOAST table,
we
* should be able to get along without one even if the new
version's
* needs_toast_table rules suggest we should have one. There
is a lot
* of daylight between where we will create a TOAST table and
where
* one is really necessary to avoid failures, so small
cross-version
* differences in the when-to-create heuristic shouldn't be a
problem.
* If we tried to create a TOAST table anyway, we would have the
* problem that it might take up an OID that will conflict with
some
* old-cluster table we haven't seen yet.
*/
if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid) ||
!OidIsValid(binary_upgrade_next_toast_pg_type_oid))
return false;
I think we probably should have pg_dump suppress emitting information
about the toast table of partitioned tables?
While I'm not hugely bothered by binary upgrade mode creating
inconsistent states - there's plenty of ways to crash the server that
way - it probably also would be a good idea to have heap_create()
elog(ERROR) when accessmtd is invalid.
Greetings,
Andres Freund