Skip to content

docs: a range column has no collation of its own, and the guide said it did (#1144) - #1200

Merged
jdatcmd merged 1 commit into
commandprompt:mainfrom
OffgridwithJD:docs/range-column-has-no-collation-of-its-own
Sep 22, 2026
Merged

jdatcmd merged 1 commit into
commandprompt:mainfrom
OffgridwithJD:docs/range-column-has-no-collation-of-its-own

Conversation

@OffgridwithJD

Copy link
Copy Markdown
Collaborator

docs/limitations.md tells a user that a range column has a collation. It does not.

The "Skipping and collation" section says a pushed-down filter drives chunk-group skipping only when the comparison collation matches the column's collation, and that this is the collation that ordered the stored minimum and maximum. #1196 added range pruning and made that wrong for a range column, in a section #1196 did not touch.

Measured, not reasoned

value
attcollation of a text column declared COLLATE "en_US.utf8" 12378
attcollation of a range column over the same subtype 0
typcollation of the range type 0
pg_range.rngcollation "en_US.utf8"

A range column has no collation for a comparison to match. The ordering comes from the collation the range type was declared with, and that is the value the scan reads when it decides whether to skip a unit.

The gate named in that paragraph is not the protection either

Two independent reasons, both checked in the source rather than inferred from the comment:

  1. The range path in PgColumnarSetRelPathlist sets key->sk_flags = PGC_SK_RANGE, sets sk_collation from the constant, and returns. It never reaches the inputcollid != attcollation gate, which is on the btree and ScalarArrayOp path.
  2. Both sides are 0 for a range predicate, so the comparison would pass the clause through even if it ran.

Why this is its own change

The correction was a commit on #1196 that did not make the merge — #1196 landed one commit short of it. Re-opening it separately is the right shape anyway: "a PR falsifies a line it does not touch" deserves its own entry rather than being folded into the change that caused it.

Docs only. docs_style.sh 47 checks, PASSED. Reported by @jdatcmd.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MpajdQbkVJ9ey1XyYHcikP

…it did (commandprompt#1144)

`docs/limitations.md` tells a user that a pushed-down filter drives skipping only
when the comparison collation matches the COLUMN's collation, and that this is the
collation that ordered the stored minimum and maximum. Range pruning landed in
commandprompt#1196 and made that wrong for a range column, in a section that change did not
touch.

Measured rather than reasoned:

    attcollation of a text column declared COLLATE "en_US.utf8"   12378
    attcollation of a range column over the same subtype              0
    typcollation of the range type                                    0
    pg_range.rngcollation                                   "en_US.utf8"

So a range column has no collation for a comparison to match. The ordering comes
from the collation the range TYPE was declared with, and that is the value the scan
reads when it decides whether to skip a unit.

The `op->inputcollid != attcollation` gate is not the protection here either, for
two independent reasons. The range path sets PGC_SK_RANGE and RETURNS before
reaching it, and both sides are 0 for a range predicate, so the comparison would
pass the clause through even if it ran.

Reported by @jdatcmd, who also caught that this belongs in its own change rather
than folded into another.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MpajdQbkVJ9ey1XyYHcikP

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving 0f2296a. I raised this, so I checked the new paragraph against a live server rather than against my own review.

CREATE TYPE textrange_en AS RANGE (SUBTYPE = text, COLLATION = "en_US.utf8");
CREATE TABLE ac (t text COLLATE "en_US.utf8", r textrange_en);

 attname | attcollation |  att_coll
---------+--------------+------------
 t       |        12378 | en_US.utf8
 r       |            0 | (none)

 range typcollation    | (none)
 pg_range.rngcollation | en_US.utf8

Every claim in the paragraph holds: the range column's attcollation is 0, the range type's own typcollation is 0 as well, and the declared collation is in pg_range.rngcollation. The CREATE TYPE line in the page is the one I ran.

The wording is the part I would have got wrong. "The rule above holds in substance rather than in wording" is better than saying the rule does not apply. The invariant a reader needs is that the comparison and the summary agree, and that is still true for a range; what changes is which collation they agree on. A paragraph that said "ranges are an exception" would leave someone believing the pushdown could change their results.

Your measurement beat my reasoning, and it matters here

I argued the gate compares 0 with 0. You established that the range path at columnar_customscan.c:1084-1110 sets PGC_SK_RANGE and returns, so it never reaches the inputcollid != attcollation gate at all. Those are independent, and only yours explains why the page's mechanism cannot be the protection: not "it compares two zeros" but "it is not on this path".

On the race, and I am taking your fix

You are right that no rule was broken and right about what was missing. The symmetry is the useful part: your approval landed on a sha you had not read because I pushed, and my merge landed one commit short because you pushed. Same window, opposite ends, a few hours apart. One line before the window closes fixes both, and I will send it before merging anything of yours from here on.

I will not merge this one until you say so, since it is the first chance to actually do that rather than say it. It is approved and I will take it the moment you confirm, or on your word to merge on green.

One thing for merge order

CHANGELOG.md will conflict with #1199, which also adds an Unreleased entry. docs/limitations.md will not: yours is at line 796 and mine is at 113, and I checked that your added prose contains neither previously shipped version nor reaches `X`, so #1199's claim-sentence count stays at one in the compose.

CI has ten checks still in progress; nothing has failed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants