Every scan node keeps its own copy of the same six-field record and its own copy of the code that prints it. Adding one line to EXPLAIN therefore means three edits, and the invariant that keeps the three consistent is held by discipline rather than by structure.
From an architecture pass over the hot spots; columnar_vector.c is 4,323 lines and took 38 of the last 300 commits.
The duplication, on current main
The record, twice in columnar_vector.c and once as locals in columnar_customscan.c:
columnar_vector.c:556,594-597,604 npreds, haveStats, groupsRead, groupsSkipped, groupsTotal, usablePreds
columnar_vector.c:693-698 npreds, haveStats, groupsRead, groupsSkipped, groupsTotal, usablePreds
columnar_customscan.c the same quantities, as locals in the EXPLAIN function
The emission, three times:
columnar_customscan.c:1879,1909,1913 Pushed-Down Filters / Usable Skip Predicates / Chunk Groups Total ...
columnar_vector.c:3537,3555,3557 the same three, again
columnar_vector.c:4229,4235,4237 the same three, a third time
It has already cost, twice, and is about to a third time
#484 had to add Columnar Usable Skip Predicates in three places. Its own rationale says why it could not do fewer:
Fixing one would leave a line of plan text meaning two different things depending on which node ran.
That is exactly right, and it is an invariant with nothing enforcing it.
#493 is that invariant already broken on the line that was not touched: Columnar Pushed-Down Filters reports scan keys on the scalar node and vector predicates on the two aggregate nodes. Whatever shape #493 lands as, it is a fourth edit to the same three places.
And the copies have already drifted in a way nobody noticed. In all three nodes Pushed-Down Filters prints outside the "did we actually read anything" guard while Usable Skip Predicates prints inside it. On the scalar node that gap is reachable — measured on merged main:
EXPLAIN (COSTS OFF) SELECT count(*) FROM t WHERE plain > 190000;
-> Custom Scan (PgColumnarScan) on t
Columnar Pushed-Down Filters: 1 <-- present
<-- nothing from the guarded block
A plain EXPLAIN shows the number that hid #477 for a year and omits the one added to correct it. On the aggregate nodes the same gap is currently unreachable, but only because haveStats happens to be true exactly when a filter exists — an accident of scanFold, not a stated rule.
Deepening
One module owns the record and its emission. Each node holds the record, hands it a read state to capture from, and calls it to print. The nodes stop knowing which lines exist or what order they come in.
Then:
Deletion test: removing two of the three copies concentrates the reporting into one place that knows the whole record, rather than moving the problem somewhere else.
Scope, and what this is not
This is only the record and its printing — not what the numbers mean. #493 owns the question of whether Pushed-Down Filters should be one quantity or two, and that decision is independent: it is about which quantity to report, this is about there being three places that report it. They compose, and #493 is easier if this lands first, but neither blocks the other.
I have not built it. Happy to, if you want it; equally happy to leave it as a note if the churn on those files makes now a bad time.
Every scan node keeps its own copy of the same six-field record and its own copy of the code that prints it. Adding one line to
EXPLAINtherefore means three edits, and the invariant that keeps the three consistent is held by discipline rather than by structure.From an architecture pass over the hot spots;
columnar_vector.cis 4,323 lines and took 38 of the last 300 commits.The duplication, on current main
The record, twice in
columnar_vector.cand once as locals incolumnar_customscan.c:The emission, three times:
It has already cost, twice, and is about to a third time
#484 had to add
Columnar Usable Skip Predicatesin three places. Its own rationale says why it could not do fewer:That is exactly right, and it is an invariant with nothing enforcing it.
#493 is that invariant already broken on the line that was not touched:
Columnar Pushed-Down Filtersreports scan keys on the scalar node and vector predicates on the two aggregate nodes. Whatever shape #493 lands as, it is a fourth edit to the same three places.And the copies have already drifted in a way nobody noticed. In all three nodes
Pushed-Down Filtersprints outside the "did we actually read anything" guard whileUsable Skip Predicatesprints inside it. On the scalar node that gap is reachable — measured on merged main:A plain
EXPLAINshows the number that hid #477 for a year and omits the one added to correct it. On the aggregate nodes the same gap is currently unreachable, but only becausehaveStatshappens to be true exactly when a filter exists — an accident ofscanFold, not a stated rule.Deepening
One module owns the record and its emission. Each node holds the record, hands it a read state to capture from, and calls it to print. The nodes stop knowing which lines exist or what order they come in.
Then:
test/pushdown_report.shgets one thing to assert against instead of three arms that must be kept in agreement by handDeletion test: removing two of the three copies concentrates the reporting into one place that knows the whole record, rather than moving the problem somewhere else.
Scope, and what this is not
This is only the record and its printing — not what the numbers mean. #493 owns the question of whether
Pushed-Down Filtersshould be one quantity or two, and that decision is independent: it is about which quantity to report, this is about there being three places that report it. They compose, and #493 is easier if this lands first, but neither blocks the other.I have not built it. Happy to, if you want it; equally happy to leave it as a note if the churn on those files makes now a bad time.