Skip to content

feat: close the OLAP P2 tier — rename/exchange, numbers(), JSON, and 13 named refusals - #33

Merged
9bany merged 1 commit into
masterfrom
feat/p2-rename-exchange-and-named-refusals
Sep 7, 2026
Merged

9bany merged 1 commit into
masterfrom
feat/p2-rename-exchange-and-named-refusals

Conversation

@9bany

@9bany 9bany commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

The P2 row of the OLAP surface had nothing in it: 0 of 22 distinct entries implemented, and 16 of them not even refused by name — they fell off the end of the grammar, which error.rs exists to prevent.

Most of P2 has an answer here already, under a different spelling. So this closes the tier by answering each row rather than by implementing each row: 4 built, 15 refused by name, 3 deferred with the blocker written down.

Built:

  • ALTER TABLE t RENAME TO u and EXCHANGE TABLES a AND b. Below the catalog a table is reached by an interned TableId, so a name is one record and changing it moves no data. Catalog::rename_table already existed, tested, with no caller outside tests; sql_no_rename meanwhile claimed nothing below renames one, which was false for a table. The refusal narrows to the half that is true — a field's name is what routes a fact to a bitmap. An exchange is two inserts into one map in one transaction, so no moment exists where either name resolves to nothing. It is the step sql_no_alter_column and sql_no_alter_engine have been prescribing without providing, and it is its own undo.
  • SELECT * FROM numbers(n). A Shown and not a query, for the reason system.* is one: no plan produces these rows. It carries its own ceiling and refuses past it rather than clamping — SETTINGS binds a query and never reaches here, so there is no EXPLAIN line that would report a clamp.
  • JSONExtractString/Int/Float/Raw and JSONHas over a TEXT column. No JSON type and no new Datum shape: a keyed column holds a string, and these read a key out of it on the way into a cell. One level of key, hand-rolled scanner, no dependency — the argument sql_no_regex already makes.
  • runningDifference(x), as a window function rather than a scalar: it needs the order the difference is taken along.

Refused by name, each with the local spelling in its sentence: sql_no_sample, sql_no_overwrite, sql_no_copy_into, sql_no_table_function, sql_no_temporary_table, sql_no_distribution, sql_computed_column, sql_composite_type, sql_enum_type, sql_no_array_join, sql_array_function, sql_no_sequence_function, sql_numbers_too_large. Refused::ALL goes 84 -> 97.

Four existing sentences get extended: sql_no_alter_column and sql_no_alter_engine can now name the exchange as the last step, sql_unknown_column_type maps IPv4 to UINT(32) and UUID/IPv6 to TEXT rather than reporting them absent, and sql_no_analyze separates "no cost model to feed" from "no channel carrying measurements back".

DDL travels through its own wire enum, so the two schema statements take tags 15 and 16 in wire/fact.rs. No Plan variant and no merge arm: big-plan, big-cluster/src/merge.rs and big-exec are untouched.

Two documents were already wrong and are corrected here. crates/big-sql/readme.md still listed window functions, select-list arithmetic and LIKE as refused, stale since M2.5 and M4. docs/sql-testing.md carried four stale numbers: 40 Refused variants, ~405 corpus cases, three gates where there are seven, and one excused refusal where there are nine.

Deferred with the blocker named rather than left as an omission: materialized views, time travel AS OF (the pager has a real copy-on-write snapshot registry, but nothing above it creates or opens one, and a snapshot carries txn_id rather than a timestamp), and EXPLAIN ANALYZE.

One commit rather than one per phase: the phases share error.rs, lib.rs, parse/mod.rs and query.rs, so a split along them would not compile at the intermediate steps.

…13 named refusals

The P2 row of the OLAP surface had nothing in it: 0 of 22 distinct entries
implemented, and 16 of them not even refused by name — they fell off the end of
the grammar, which `error.rs` exists to prevent.

Most of P2 has an answer here already, under a different spelling. So this
closes the tier by answering each row rather than by implementing each row:
4 built, 15 refused by name, 3 deferred with the blocker written down.

Built:

- `ALTER TABLE t RENAME TO u` and `EXCHANGE TABLES a AND b`. Below the catalog a
  table is reached by an interned `TableId`, so a name is one record and
  changing it moves no data. `Catalog::rename_table` already existed, tested,
  with no caller outside tests; `sql_no_rename` meanwhile claimed nothing below
  renames one, which was false for a table. The refusal narrows to the half
  that is true — a field's name is what routes a fact to a bitmap. An exchange
  is two inserts into one map in one transaction, so no moment exists where
  either name resolves to nothing. It is the step `sql_no_alter_column` and
  `sql_no_alter_engine` have been prescribing without providing, and it is its
  own undo.
- `SELECT * FROM numbers(n)`. A `Shown` and not a query, for the reason
  `system.*` is one: no plan produces these rows. It carries its own ceiling and
  refuses past it rather than clamping — `SETTINGS` binds a query and never
  reaches here, so there is no `EXPLAIN` line that would report a clamp.
- `JSONExtractString/Int/Float/Raw` and `JSONHas` over a `TEXT` column. No
  `JSON` type and no new `Datum` shape: a keyed column holds a string, and these
  read a key out of it on the way into a cell. One level of key, hand-rolled
  scanner, no dependency — the argument `sql_no_regex` already makes.
- `runningDifference(x)`, as a window function rather than a scalar: it needs
  the order the difference is taken along.

Refused by name, each with the local spelling in its sentence: `sql_no_sample`,
`sql_no_overwrite`, `sql_no_copy_into`, `sql_no_table_function`,
`sql_no_temporary_table`, `sql_no_distribution`, `sql_computed_column`,
`sql_composite_type`, `sql_enum_type`, `sql_no_array_join`,
`sql_array_function`, `sql_no_sequence_function`, `sql_numbers_too_large`.
`Refused::ALL` goes 84 -> 97.

Four existing sentences get extended: `sql_no_alter_column` and
`sql_no_alter_engine` can now name the exchange as the last step,
`sql_unknown_column_type` maps `IPv4` to `UINT(32)` and `UUID`/`IPv6` to `TEXT`
rather than reporting them absent, and `sql_no_analyze` separates "no cost model
to feed" from "no channel carrying measurements back".

DDL travels through its own wire enum, so the two schema statements take tags 15
and 16 in `wire/fact.rs`. No `Plan` variant and no merge arm: `big-plan`,
`big-cluster/src/merge.rs` and `big-exec` are untouched.

Two documents were already wrong and are corrected here. `crates/big-sql/readme.md`
still listed window functions, select-list arithmetic and `LIKE` as refused,
stale since M2.5 and M4. `docs/sql-testing.md` carried four stale numbers: 40
`Refused` variants, ~405 corpus cases, three gates where there are seven, and
one excused refusal where there are nine.

Deferred with the blocker named rather than left as an omission: materialized
views, time travel `AS OF` (the pager has a real copy-on-write snapshot
registry, but nothing above it creates or opens one, and a snapshot carries
`txn_id` rather than a timestamp), and `EXPLAIN ANALYZE`.

One commit rather than one per phase: the phases share `error.rs`, `lib.rs`,
`parse/mod.rs` and `query.rs`, so a split along them would not compile at the
intermediate steps.
@9bany 9bany changed the title feat: close the OLAP P2 tier — rename/exchange, numbers(), JSON, and … feat: close the OLAP P2 tier — rename/exchange, numbers(), JSON, and 13 named refusals Sep 7, 2026
@9bany
9bany merged commit cbfaa24 into master Sep 7, 2026
13 checks passed
@9bany
9bany deleted the feat/p2-rename-exchange-and-named-refusals branch September 7, 2026 11:17
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.

1 participant