fix: don't surface a ClickHouse ARRAY JOIN operand as a table read#57
Merged
Conversation
Contributor
|
✅ PR title follows the Conventional Commits spec. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #57 +/- ##
=======================================
Coverage 94.76% 94.77%
=======================================
Files 27 27
Lines 5542 5590 +48
Branches 5542 5590 +48
=======================================
+ Hits 5252 5298 +46
- Misses 212 214 +2
Partials 78 78 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6c96097 to
0a6cec5
Compare
sqlparser parses the operand of `ARRAY JOIN` / `LEFT ARRAY JOIN` / `INNER ARRAY JOIN` as a `TableFactor::Table`, indistinguishable from a real table, so `SELECT s FROM t ARRAY JOIN arr` used to surface a phantom read of a table `arr`. Bind the operand as an opaque unnest instead — never a table read: a plain name reads as a column of the left relation (`t.arr`), and an array expression (`arrayConcat(t.a, t.b)`) reads its argument columns. The unnested output is exposed as a synthetic column, so a reference to the alias no longer leaks as a phantom `t.<alias>` read either. The same special case applies on the UPDATE target's join clause (`UPDATE t ARRAY JOIN arr SET …`), and a non-Table operand shape (a derived subquery — invalid ClickHouse but parseable) falls back to the normal factor path so its reads survive. Follow-up from #55. Left as-is (both exotic): the analogous multi-table DELETE-target path (`DELETE … USING t ARRAY JOIN arr`), and a multi-array `ARRAY JOIN a, b` — which sqlparser parses as a comma-join, so `b` still looks like a table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AteCEF9XeviLCkfa3EQMfc
0a6cec5 to
a12b033
Compare
Merged
takaebato
added a commit
that referenced
this pull request
Jul 5, 2026
## 🤖 New release * `sql-insight`: 0.3.0 -> 0.4.0 (✓ API compatible changes) * `sql-insight-cli`: 0.2.1 -> 0.2.2 <details><summary><i><b>Changelog</b></i></summary><p> ## `sql-insight` <blockquote> ## [0.4.0](sql-insight-v0.3.0...sql-insight-v0.4.0) - 2026-07-05 ###⚠️ Breaking Changes #### attribute unqualified SET targets with the read-side rules ([#59](#59)) by @takaebato #### upgrade sqlparser to 0.62 ([#55](#55)) by @takaebato ### Added - resolve Oracle join-view INSERT targets by column attribution ([#61](#61)) by @takaebato - fan out multi-column-alias lineage to every alias ([#60](#60)) by @takaebato - resolve Oracle inline-view INSERT targets to their base table ([#58](#58)) by @takaebato ### Fixed - don't surface a ClickHouse ARRAY JOIN operand as a table read ([#57](#57)) by @takaebato ### Other Changes - changelog breaking-change workflow, version-bump docs, and keywords ([#51](#51)) by @takaebato - tidy keywords, README versions, and add a version-sync check ([#46](#46)) by @takaebato </blockquote> ## `sql-insight-cli` <blockquote> ## [0.2.2](sql-insight-cli-v0.2.1...sql-insight-cli-v0.2.2) - 2026-07-05 ### Added - *(cli)* prebuilt binary distribution — cargo binstall, completions, man, and provenance ([#53](#53)) by @takaebato ### Fixed - *(deps)* update rust crate clap_mangen to 0.3 ([#54](#54)) by @renovate[bot] ### Other Changes - changelog breaking-change workflow, version-bump docs, and keywords ([#51](#51)) by @takaebato - tidy keywords, README versions, and add a version-sync check ([#46](#46)) by @takaebato </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Takahiro Ebato <takahiro.ebato@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a follow-up noted in #55: a ClickHouse
ARRAY JOINoperand was surfaced asa (spurious) table read.
sqlparser parses the operand of
ARRAY JOIN/LEFT ARRAY JOIN/INNER ARRAY JOINas aTableFactor::Table, indistinguishable from a real table — soSELECT s FROM t ARRAY JOIN arrreported a phantom read of a tablearr.(ClickHouse's ARRAY JOIN operand is always an array — a column or an array
expression — never a table.)
This binds the ARRAY JOIN operand as an opaque unnest (a
TableFunction, so notable read):
arr/t.arr) reads as a column of the leftrelation:
read_tablesno longer includes it (SELECT s FROM t ARRAY JOIN arr→
[t], not[t, arr]), andt.arrsurfaces as a column read.arrayConcat(t.a, t.b)) reads its argument columns(
t.a,t.b) — not the function name.AS x, else the operand's own name) is exposed as asynthetic column, so a reference to it no longer leaks as a phantom
t.xread.Edge cases covered on review:
UPDATE t ARRAY JOIN arr SET a = 1no longer reads a phantomarrtable(and
tcorrectly surfaces as a read — the unnest references the writetarget's own data).
parses it) falls back to the normal factor path, so its reads survive instead
of being silently dropped.
|> JOIN) cannot parse an ARRAY JOIN operator — unreachable.Tests: updated the ARRAY JOIN arm coverage (now expects the operand column read),
plus table-level "operand is not a read table" (SELECT and UPDATE), "alias does
not leak as a phantom column", "expression operand reads its arguments", and
"derived operand keeps its reads" tests. All gates green (fmt / clippy /
test --all/ doc).Left as-is (both exotic): the analogous multi-table DELETE-target path
(
DELETE … USING t ARRAY JOIN arr), and a multi-arrayARRAY JOIN a, b— whichsqlparser parses as a comma-join, so
bstill looks like a table.🤖 Generated with Claude Code