BUG #19470: PostgreSQL backend aborts (assert failure) when a prepared statement returns a composite type cast t
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t139534psql -h localhost -U postgresBuilt from patchset v3 (message #3), September 21, 2026 at 12:49 AM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t139534_3 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t139534_3 && git checkout t139534_3Patchset v3 (message #3) is on t139534_3
The following bug has been logged on the website:
Bug reference: 19470
Logged by: HaoGang Mao
Email address: haogangmao@gmail.com
PostgreSQL version: 18.3
Operating system: Linux
Description:
Reproduction steps (minimal):
BEGIN;
CREATE TYPE foo AS (a int, b text);
PREPARE p AS SELECT CAST(ROW(1, 'hello') AS foo)::text;
EXECUTE p;
ALTER TYPE foo ALTER ATTRIBUTE a TYPE VARCHAR(100);
EXECUTE p;
COMMIT;
Expected: Error message (type modified while a prepared plan / expression is
active)
Actual: Server connection dropped; backend aborts with SIGABRT due to
assertion failure
Server log (trimmed):
TRAP: failed Assert("false"), File: "heaptuple.c", Line: 1417, PID: <pid>
... heap_deform_tuple()
Hi,
On Sat, May 2, 2026 at 1:27 AM PG Bug reporting form <noreply@postgresql.org>
wrote:
The following bug has been logged on the website:
Bug reference: 19470
Logged by: HaoGang Mao
Email address: haogangmao@gmail.com
PostgreSQL version: 18.3
Operating system: Linux
Description:Reproduction steps (minimal):
BEGIN;
CREATE TYPE foo AS (a int, b text);
PREPARE p AS SELECT CAST(ROW(1, 'hello') AS foo)::text;
EXECUTE p;
ALTER TYPE foo ALTER ATTRIBUTE a TYPE VARCHAR(100);
EXECUTE p;
COMMIT;Expected: Error message (type modified while a prepared plan / expression
is
active)
Actual: Server connection dropped; backend aborts with SIGABRT due to
assertion failureServer log (trimmed):
TRAP: failed Assert("false"), File: "heaptuple.c", Line: 1417, PID: <pid>
... heap_deform_tuple()
Thanks for reporting and the repro, I was able to reproduce this.
The cause of this crash is a cache invalidation failure. When ALTER TYPE is
executed,
the cached plan for the prepared statement is not properly invalidated. So
the executor uses
a stale memory layout during the second execution. This causes tuple
deformation to see type
confusion, reading a 4-byte INT as a Varlena header. The system interprets
the lowest byte
of the integer as a TOAST pointer, reads the adjacent garbage memory as a
TOAST tag,
and triggers the Assert(false) in VARTAG_SIZE, replacing the assertion with
an elog(ERROR)
would prevent the hard crash, it only masks the main issue. I think the
correct fix is that
ALTER TYPE on a composite attribute correctly triggers a plan
re-validation, thoughts?
--
Thanks,
Srinath Reddy Sadipiralla
EDB: https://www.enterprisedb.com/
On Wed, Apr 29, 2026, at 8:27 AM, PG Bug reporting form wrote:
Reproduction steps (minimal):
BEGIN;
CREATE TYPE foo AS (a int, b text);
PREPARE p AS SELECT CAST(ROW(1, 'hello') AS foo)::text;
EXECUTE p;
ALTER TYPE foo ALTER ATTRIBUTE a TYPE VARCHAR(100);
EXECUTE p;
COMMIT;
Thanks for your report! The attached patch fixes this case. I included a
similar test case but I'm fine if the test is not included with this fix. I
decided to create a separate function instead of adding the new conditions to
record_plan_type_dependency() because it keeps the fix simple and isolated.
The crash is reproduced back to v11 which means this fix should be backpatched
to all supported versions.
--
Euler Taveira
EDB https://www.enterprisedb.com/
Hi,
On Tue, May 5, 2026 at 11:37 AM Euler Taveira <euler@eulerto.com> wrote:
On Wed, Apr 29, 2026, at 8:27 AM, PG Bug reporting form wrote:
Reproduction steps (minimal):
BEGIN;
CREATE TYPE foo AS (a int, b text);
PREPARE p AS SELECT CAST(ROW(1, 'hello') AS foo)::text;
EXECUTE p;
ALTER TYPE foo ALTER ATTRIBUTE a TYPE VARCHAR(100);
EXECUTE p;
COMMIT;Thanks for your report! The attached patch fixes this case. I included a
similar test case but I'm fine if the test is not included with this fix. I
decided to create a separate function instead of adding the new conditions to
record_plan_type_dependency() because it keeps the fix simple and isolated.The crash is reproduced back to v11 which means this fix should be backpatched
to all supported versions.
Thanks for working on this.
I think this is on the right track. Using relationOids is the right
mechanism, since the DDL doesn't touch the composite's pg_type row and
a TYPEOID inval item wouldn't work here. Doing it in fix_expr_common
covers extract_query_dependencies too.
What I'm less easy about is whether Const and RowExpr are the only
carriers. As written, the TYPTYPE_COMPOSITE test won't look through an
array over a composite or a domain over one, and nodes like
FieldSelect and ConvertRowtypeExpr also carry composite type OIDs.
Could you check whether any of those reproduce a similar crash? If so
we'd want to look through to the element/base type and/or cover more
node types before this goes in.
Modulo that, I'll prepare to push to all supported branches.
--
Thanks, Amit Langote