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

Reply via email to