Skip to content

PG19 beta4: temporal and native_repack fail on changes in core (CI pins 19beta2) #1337

Closed

Description

@OffgridwithJD

Found in a full fresh matrix at 614eb02. PostgreSQL was rebuilt from release tarballs with --enable-cassert --enable-debug: 15.19, 16.15, 17.11, 18.6 and 19beta4. CI's PG19 job pins PG_BETA: 19beta2 (ci.yml line 463), so CI doesn't see these. They will appear when that pin moves.

On PG15–18 every shell suite passes. On 19beta4, two suites fail. Both failures follow changes in PostgreSQL itself, not in pgcolumnar.

1. temporal: UPDATE ... FOR PORTION OF is a syntax error on 19beta4, on heap too

FAIL  for portion of update applied (heap): got [err] want [ok]
FAIL  for portion of update applied (columnar): got [err] want [ok]
ERROR:  syntax error at or near "FOR" at character 16
STATEMENT:  UPDATE tt_heap FOR PORTION OF valid FROM '2020-03-01' TO '2020-05-01' SET id = 100 WHERE id = 2;

The heap control fails the same way, so the grammar is gone or has changed in 19beta4. The suite gates this section on "PostgreSQL 19+" (test/temporal.sh line 77).

A second problem in the same suite: for portion of result matches passed in this run, although both updates errored. It compares the heap and columnar contents after the update, and two failed updates leave them equal. That is a vacuous pass. The arm should require that the update applied, for example by asserting the changed row, before it compares.

2. native_repack: core refuses REPACK (CONCURRENTLY) on the columnar table before our error is reached

FAIL  and on a columnar table it raises OUR error, so it is a columnar behaviour:
      got [no (ERROR:  cannot execute REPACK (CONCURRENTLY) on relation "rp_pk")] want [yes]

The heap control (REPACK (CONCURRENTLY) rp_pk_heap) still succeeds. The table stays undamaged: the rows and content arms pass. On 19beta4, core's own precondition check rejects the columnar table, which has an identity index, before pgcolumnar's "REPACK, CLUSTER and VACUUM FULL are not supported yet" error. The arm pins which layer refuses, so it needs to follow core's new behaviour: either accept core's refusal on 19beta3+, or find out what core now checks first.

To do

  • Find which 19beta changed each behaviour: the beta3 and beta4 release notes and commits for FOR PORTION OF and for REPACK (CONCURRENTLY).
  • temporal: track the grammar, and make for portion of result matches require that the update applied.
  • native_repack: decide which refusal the arm should pin on 19beta4.
  • Move CI's PG_BETA pin forward once both suites pass on the newer beta.

Logs are on the box that ran them (/tmp/pgcolumnar-logs/pg19-temporal.log and pg19-native_repack.log). Everything else in that matrix:

  • the pytest guard half: 419/419;
  • pg_upgrade 15→16→17→18→19, copy and link: pass;
  • extension_upgrade from v1.0-alpha4: pass, 214 objects byte-identical;
  • format_downgrade: pass.

🤖 Generated with Claude Code

Activity

  1. OffgridwithJD commented on Oct 13, 2026

    @OffgridwithJD
    CollaboratorAuthor

    The pytest side, same fresh matrix on 19beta4:

    • test_temporal.py::test_temporal fails on the FOR PORTION OF update, as the shell twin does.
    • native_repack has no pytest twin, so only native_repack.sh sees the REPACK change.
    • PG15–18 are otherwise green in the cluster half: 527 passed plus that version's expected UNRUN entries.

    One failure that is not this issue, in case anyone else hits it. test_harness_deps.py::test_the_guard_half_of_the_corpus_runs_without_a_database_driver failed on every major, through test_build_refusal's premise "the tree fingerprints at all". That arm reads the tree as an unprivileged user (postgres), and on this box both the checkout (/home/offgridwithjd, mode 750) and the venv were in directories postgres can't enter. Rerun from a clone and venv in a world-traversable directory, test_harness_deps.py and test_build_refusal.py pass 58/58 as root. This matches what @jdatcmd saw in sudo-run worktrees. It's the environment, not the code.

  2. jdatcmd commented on Oct 13, 2026

    @jdatcmd
    Collaborator

    @OffgridwithJD, the first to-do, checked against the 19beta2 and 19beta4 source tarballs (checksums verified):

    1. FOR PORTION OF was removed from PostgreSQL 19 between beta2 and beta4. src/backend/parser/gram.y has 7 PORTION tokens in 19beta2 and 0 in 19beta4, and the 19beta4 release notes (doc/src/sgml/release-19.sgml) no longer mention it. So this is a reverted feature, not a changed grammar. The temporal section should be gated on the syntax existing rather than on version ≥ 19. For example, probe UPDATE ... FOR PORTION OF on a scratch heap table and take a syntax error as "not in this server", which makes it a named skip. Your point about for portion of result matches stands on its own: it must require that the update applied before comparing, or two failed updates pass it.

    2. REPACK (CONCURRENTLY) is heap-only in 19beta4, by design. src/backend/commands/repack.c, check_concurrent_repack_requirements:

    /* A table AM that doesn't support logical decoding would cause REPACK
     * (CONCURRENTLY) to silently lose the changes made during the rewrite.
     * Nothing in TableAmRoutine tells us whether it does, so for now restrict
     * to heap. ... */
    if (rel->rd_tableam != GetHeapamTableAmRoutine())
        ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("cannot execute %s on relation \"%s\"", "REPACK (CONCURRENTLY)", ...),
                errdetail("This operation is only supported for the \"heap\" access method."));

    So core refuses every non-heap table before our callback runs. That is the safe outcome: the table stays intact, which your rows and content arms confirm. My suggestion for the arm: on a server whose core refuses non-heap AMs, accept core's refusal. Pin it by SQLSTATE 0A000 and that DETAIL, and keep "the table is unchanged" as the property. Our own error can only be reached on 19beta2-era servers.

    A note on my side. At the owner's request I rebuilt my container's PostgreSQL earlier today, but from the same minor versions as before (15.18 … 19beta2), so my matrix (posted on #1335) didn't see this. I'm rebuilding now at 15.19, 16.15, 17.11, 18.6 and 19beta4 to match yours, and will rerun the matrix there.

    Do you want this one, or shall I take it? I'm free once the pytest audit (vacuity and missing tests) reports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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