Skip to content

Zone maps keep the old collation after ALTER COLUMN ... COLLATE, so queries return wrong results #1327

Closed

Description

@jdatcmd

Wrong results after a collation change that does not rewrite the table

What happens: ALTER COLUMN ... TYPE text COLLATE <other> on a columnar table keeps the relfilenode. The zone maps keep the old collation's min and max, so chunk-group pruning and min/max skip rows the new collation orders differently.

Reproduced on main at 036d452, PG17:

CREATE TABLE c (s text COLLATE "C") USING pgcolumnar;
INSERT INTO c VALUES ('a'), ('B'), ('m'), ('b');
CREATE TABLE h (s text COLLATE "C");
INSERT INTO h VALUES ('a'), ('B'), ('m'), ('b');
ALTER TABLE c ALTER COLUMN s TYPE text COLLATE "en_US.utf8";   -- relfilenode 16548 before and after
ALTER TABLE h ALTER COLUMN s TYPE text COLLATE "en_US.utf8";
SELECT min(s) || '|' || max(s) FROM c;                          -- B|m   (heap: a|m)
SELECT string_agg(s, ',' ORDER BY s) FROM c WHERE s < 'B';      -- empty (heap: a,b)

Expected: the same answers as heap.

Possible fixes, not chosen:

  • force a rewrite, or invalidate the column's zone maps, when a column's collation changes;
  • or store the collation with each zone map and ignore a mismatched one.

Arm to add first, in both twins: change a column's collation without a rewrite, then require min, max and a WHERE s < 'B' to equal heap's.

Found while reviewing #1325, whose column_extent() would print the same narrow bound. That PR's planner bound reads only timestamp columns, so the bug is not that PR's.

Activity

  1. OffgridwithJD commented on Oct 13, 2026

    @OffgridwithJD
    Collaborator

    @jdatcmd I'm taking this, as I offered on #1325. Tell me if you'd rather keep it.

    The plan is red first, in both twins: change a column's collation without a rewrite, then require min, max and WHERE s < 'B' to equal heap's. I'll measure which fix is cheaper before choosing between them: a rewrite or invalidation on a collation change, or the collation recorded with each zone map. The extent catalog (#1325) also stores min/max per column, so whichever fix I choose has to cover it as well.

  2. added 2 commits that reference this issue on Oct 13, 2026
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