Repository navigation
fix(parser): BigQuery PIVOT/UNPIVOT (#854) - #857
Conversation
Gate PIVOT/UNPIVOT on Capabilities().SupportsPivotUnpivot instead of a hard-coded SQL Server/Oracle/Snowflake list, so BigQuery (which advertises the capability) no longer fails with E2002. The capability is true for exactly SQL Server, Oracle, Snowflake and BigQuery; the default, Generic and all other dialects keep treating pivot/unpivot as identifiers. Add the BigQuery grammar extensions, gated per dialect: - aggregate aliases and multiple aggregates (Oracle, BigQuery) - IN value aliases without AS (all but SQL Server) - UNPIVOT INCLUDE/EXCLUDE NULLS (Oracle, Snowflake, BigQuery) - row-value aliases without AS and INT64 aliases (BigQuery) - multi-column UNPIVOT ((a, b) FOR k IN ((c1, c2) AS 'x')) (Oracle, BigQuery) AST: PivotClause.AggregateAlias/ExtraAggregates, UnpivotClause.NullHandling/ ValueColumns, ast.PivotAggregate and ast.UnpivotNullHandling, rendered by SQL() and pkg/formatter. IN lists now require commas and an alias after AS. Backtick-quoted IN names keep their backticks when rendered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Claude finished @ajitpratap0's task in 39s —— View job PR review: BigQuery PIVOT/UNPIVOT (#857)I read the diff in Overall: this looks good. Using Things to consider
TestsCoverage is broad: positive and negative cases, a dialect-gating matrix, and round trips through both the formatter and None of the points above blocks merging. Point 1 is wording and point 3 is a small test gap. |
|
Claude finished @ajitpratap0's task in 16s —— View job PR review: BigQuery PIVOT/UNPIVOT (#857)I read the diff in Overall: the PR is in good shape. Things to consider
TestsCoverage is broad: positive and negative cases, a dialect-gating matrix, and round trips through both the formatter and None of these block merging. Point 1 is wording, and points 2 and 3 are small test gaps. |
Retain source delimiters for first and additional aggregate aliases and single/multi-column UNPIVOT value names in AST and formatter output. Keep the existing quoting fallback for hand-built names. Pin backtick token byte spans for Unicode and doubled delimiters, add BigQuery and Oracle round trips, and clarify IN-list alias behavior. Co-Authored-By: Codex <noreply@openai.com> Codex-Session: 01a164e5-e59a-7281-b5b1-efc545a2f622
|
Claude finished @ajitpratap0's task in 15s —— View job PR review: BigQuery PIVOT/UNPIVOT (#857)I read the parser changes in Overall: this is in good shape. Gating on Things to consider
TestsCoverage is broad: positive and negative cases, a dialect-gating matrix, and round trips through both the formatter and None of these block merging. Point 1 is wording and the rest are small test or hardening items. |
|
Claude finished @ajitpratap0's task in 24s —— View job PR review: BigQuery PIVOT/UNPIVOT (#857)I read the Overall: the PR is in good shape and I see no blockers. Corrections to the earlier automated reviews
Things to consider
Performance and security
TestsCoverage is broad: positive and negative cases, a dialect-gating matrix, and round trips through both the formatter and |
Keep numeric row aliases after AS in Oracle and BigQuery while rejecting them in Snowflake and SQL Server. Preserve the older nonnumeric alias handling and BigQuery bare numeric aliases. Add a four-dialect acceptance matrix and spaced backtick value/input column round trips in the AST and formatter paths. Co-Authored-By: Codex <noreply@openai.com> Codex-Session: 01a164e5-e59a-7281-b5b1-efc545a2f622
|
Claude finished @ajitpratap0's task in 17s —— View job PR review: BigQuery PIVOT/UNPIVOT (#857)I read the gating code in Overall: no blockers. Gating on Earlier review points that look already handledGoing by the PR description and the latest commits (
Remaining suggestions
Performance and security
|
Summary
Fixes #854.
BigQuery's capabilities set
SupportsPivotUnpivot: true, butpivotDialectAllowed()checked a hard-coded list of SQL Server, Oracle and Snowflake. As a result,gosqlx validate --dialect bigquery "SELECT * FROM sales PIVOT (SUM(amount) FOR quarter IN ('Q1', 'Q2'))"failed with E2002.p.Capabilities().SupportsPivotUnpivot, the same patternisQualifyKeyworduses forSupportsQualify. I checked every dialect: only SQL Server, Oracle, Snowflake and BigQuery claim the capability. The default (Unknown), Generic, PostgreSQL, MySQL, MariaDB, SQLite, ClickHouse and Redshift all returnfalse, so behaviour there is unchanged. Tests pin this. No capability flags changed.SUM(x) [AS] totaland multiple aggregatesINvalue alias withoutAS('Q1' q1)UNPIVOT INCLUDE NULLS/EXCLUDE NULLSAS(string or INT64)ASUNPIVOT ((a, b) FOR k IN ((c1, c2) AS 'x', ...))PivotClause.AggregateAliasandPivotClause.ExtraAggregates []PivotAggregate(the 2nd and later aggregates;Children()includes them, and pool release frees them)UnpivotClause.NullHandlingandUnpivotClause.ValueColumns(multi-column form;ValueColumnis empty in that form)ast.UnpivotNullHandlingSQL()andpkg/formatterrender the new fields.QuotePivotItemnow accepts a well-formed(atom, atom) [AS atom]column set and still double-quotes anything else.Token.Quoteat zero for backticks.renderCurrentIdentcompares the token span width withlen(Token.Value)(bytes), or detects a multiline span; it does not read source text. Tokenizer tests pin byte columns for日本and doubled backticks, and parser/formatter round trips cover both forms. The existing tokenizer metadata contract remains unchanged.Scoped out
INvalues (IN (1 + 1),IN (DATE '2024-01-01')); only literals and names are parsed.(c1, c2) AS ('a', 'b')).Test Plan
pkg/sql/parser/bigquery_pivot_test.gocovers:INaliases with and withoutAS, multiple aliased aggregates, backtick names, subquery source)pivotstill works as an alias in PostgreSQL; the extensions are rejected where the dialect lacks them and accepted for Oracle/Snowflake where it has thempkg/formatter/bigquery_pivot_render_test.gochecksFormatASTandSQL()output and reparsing, including BigQuery backtick aggregate aliases, single/multi-column UNPIVOT value names, non-ASCII and doubled backtick names, and Oracle quoted aliases. Hand-built malformed names retain safe fallback quoting.Quote == 0contract and exact byte spans for Unicode and doubled-backtick identifiers through both tokenization entry points.AS 1UNPIVOT alias is accepted for Oracle/BigQuery and rejected for Snowflake/SQL Server; quoted UNPIVOT value and input-column sets with spaces round-trip through both renderers.task checkpasses;go test -race ./pkg/sql/parser/ ./pkg/formatter/ ./pkg/sql/ast/ ./pkg/sql/tokenizer/passes.TestPerformanceRegressionalso passes.BenchmarkPerformanceBaselinebefore review fixes (2810b973) vs final head (e4aab414): saved test binaries, 10 samples each, interleaved with alternating order on Apple M4 / Go 1.27.2. Pinned benchstat (golang.org/x/perf/cmd/benchstat@v0.0.0-20260908200009-22c9c6c9d4da) shows no significant timing change in any case (all p >= 0.148; geomean -0.22%); bytes/op and allocations/op are identical. No speedup is claimed.Breaking Changes
The AST fields are additive. Parsed quoted aggregate aliases and UNPIVOT value columns now retain source delimiters so rendering preserves the identifier. Two input-validation changes are listed in CHANGELOG:
INlists require commas between entries. Where bare aliases are supported,IN (a b)is one entry (a AS b); otherwise the missing comma is rejected.ASin anINlist must be followed by an alias.IN ('a' AS)used to drop theASsilently.Also, dialect aliases that
dialect.Parsemaps (e.g.mssql,bq) now enable PIVOT, because the gate uses the typed dialect rather than an exact string match.🤖 Generated with Claude Code
https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9