Skip to content

COMMIT PREPARED in the preparing session crashes the backend after a pgcolumnar write #1323

Closed

Description

@OffgridwithJD

Found while writing #1304 option 5's two-phase arm. Reproduced on main at 024e737, PG16 assert build, with nothing of mine installed:

CREATE TABLE tp (ts timestamptz, v int) USING pgcolumnar;
INSERT INTO tp SELECT now(), 1;
BEGIN;
INSERT INTO tp SELECT '2044-02-02'::timestamptz + g * interval '2 s', g FROM generate_series(1, 2600) g;
PREPARE TRANSACTION 'x3';
COMMIT PREPARED 'x3';       -- same session: signal 11

COMMIT PREPARED from another session works. That's what parallel_copy does (the leader commits the loaders' prepared transactions), so nothing in the corpus has hit it.

Backtrace (gdb attached to the backend before COMMIT PREPARED):

#0  PgColumnarFlushAllPendingWrites () at src/columnar_write_state.c:3844
#1  pgcolumnar_xact_callback (event=...) at src/columnar_tableam.c:2669
#2  CallXactCallbacks (event=XACT_EVENT_PRE_COMMIT) at xact.c:3703
#3  CommitTransaction () at xact.c:2214
...
#7  exec_simple_query (query_string="COMMIT PREPARED 'x3'") at postgres.c:1303

Cause, as I read it: PgColumnarWriteStates and PgColumnarWriteContext live in a child of TopTransactionContext. PREPARE deletes that context, but the callback's PREPARE arm doesn't reset the two statics. Only the COMMIT/ABORT arms do, via PgColumnarDiscardAllPendingWrites, and PREPARE reaches neither. So the next transaction in the session, here the COMMIT PREPARED itself, walks a freed list at its PRE_COMMIT. The memo has a comment about exactly this for PREPARE ("PREPARE deletes TopTransactionContext without ever reaching the COMMIT/ABORT arms below"), but the write states weren't given the same treatment.

Likely fix: in the PREPARE arm, after the flush, discard the pending write states (and the delete vectors' equivalent if they share the shape). The arm: PREPARE then COMMIT PREPARED in one session, in both twins.

I'm not fixing it inside #1304 option 5. That PR's pytest twin commits from another session and says why.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions