Commit daea668
feat(parser): add SQL Server PIVOT/UNPIVOT clause parsing (#477)
* feat(parser): add SQL Server PIVOT/UNPIVOT clause parsing (#456)
Add support for SQL Server and Oracle PIVOT/UNPIVOT operators in FROM
clauses. PIVOT transforms rows to columns via an aggregate function,
while UNPIVOT performs the reverse column-to-row transformation.
- Add PivotClause and UnpivotClause AST node types
- Add Pivot/Unpivot fields to TableReference struct
- Implement parsePivotClause/parseUnpivotClause in new pivot.go
- Wire parsing into parseFromTableReference and parseJoinedTableRef
- Add PIVOT/UNPIVOT to tokenizer keyword map for correct token typing
- Update formatter to render PIVOT/UNPIVOT clauses
- Enable testdata/mssql/11_pivot.sql and 12_unpivot.sql
- Add 4 dedicated tests covering subquery+alias, plain table, AS alias
Closes #456
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* security: add CVE-2026-32285 to .trivyignore
CVE-2026-32285 affects github.com/buger/jsonparser v1.1.1, which is a
transitive dependency via mark3labs/mcp-go → invopop/jsonschema →
wk8/go-ordered-map → buger/jsonparser.
No fixed version is available upstream. The package is not called
directly by any GoSQLX code and risk is scoped to MCP JSON schema
generation. Added to .trivyignore until a patched version is released.
Fixes Trivy Repository Scan CI failures in PR #475 and #477.
* fix(parser): scope PIVOT/UNPIVOT to SQL Server/Oracle dialects
PIVOT and UNPIVOT were registered in the global tokenizer keyword map,
which made them reserved words across every dialect. Queries like
`SELECT pivot FROM users` then failed in PostgreSQL/MySQL/SQLite/
ClickHouse where these identifiers are perfectly legal.
Changes:
- Remove PIVOT/UNPIVOT from tokenizer keywordTokenTypes (they are now
tokenized as identifiers in all dialects).
- Gate isPivotKeyword/isUnpivotKeyword on the parser dialect (TSQL/
Oracle only) and accept identifier-typed tokens by value match.
- Skip alias consumption in parseFromTableReference / parseJoinedTableRef
when the upcoming identifier is a contextual PIVOT/UNPIVOT keyword,
so the pivot-clause parser can claim it.
- Fix unsafe single-value type assertion in TestTSQL_PivotWithASAlias
to comply with the project's mandatory two-value form.
- Add TestPivotIdentifierInNonTSQLDialects regression covering pivot/
unpivot as identifiers in PostgreSQL, MySQL, and SQLite.
All parser/tokenizer/formatter tests pass with -race.
* fix(parser): polish PIVOT/UNPIVOT round-trip and validation
- Formatter emits AS before PIVOT/UNPIVOT aliases for clean round-trip.
- Tokenizer records Quote='[' on SQL Server bracket-quoted identifiers;
pivot parser uses renderQuotedIdent to preserve [North] etc. in
PivotClause.InValues and UnpivotClause.InColumns.
- Reject empty IN lists for both PIVOT and UNPIVOT.
- Extract parsePivotAlias helper, collapsing four duplicated alias
blocks in select_subquery.go.
- Add TestPivotNegativeCases (missing parens, missing FOR/IN, empty IN)
and TestPivotBracketedInValuesPreserved.
Full test suite passes with -race.
* fix(parser): escape embedded delimiters and fix empty-IN error order
- renderQuotedIdent now doubles embedded `]`, `"`, and `` ` ``
per dialect convention so identifiers like [foo]bar] round-trip
unambiguously.
- Empty PIVOT/UNPIVOT IN list check now runs before the closing-`)`
check so the user-facing error is "at least one value/column..."
instead of the misleading ") to close ... IN list".
- Clarify renderQuotedIdent comment to reference Token.Quote and
Word.QuoteStyle as the actual sources.
* refactor(formatter): thread nodeFormatter through tableRefSQL and joinSQL
Previously these package-level renderers hardcoded keyword literals
(PIVOT, UNPIVOT, FOR, IN, LATERAL, JOIN, ON) which bypassed the
caller's case policy (f.kw). Thread *nodeFormatter into both
functions and route every keyword through f.kw so uppercase/lowercase
options apply uniformly across FROM, JOIN, MERGE, DELETE USING, and
UPDATE FROM paths.
Addresses claude-review feedback on PR #477. All formatter, parser,
and tokenizer tests pass with -race.
---------
Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent d07122b commit daea668
File tree
6 files changed
+625
-21
lines changed- pkg
- formatter
- sql
- ast
- parser
- tokenizer
6 files changed
+625
-21
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
227 | 227 | | |
228 | 228 | | |
229 | 229 | | |
230 | | - | |
| 230 | + | |
231 | 231 | | |
232 | 232 | | |
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | 236 | | |
237 | 237 | | |
238 | | - | |
| 238 | + | |
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
| |||
400 | 400 | | |
401 | 401 | | |
402 | 402 | | |
403 | | - | |
| 403 | + | |
404 | 404 | | |
405 | 405 | | |
406 | 406 | | |
| |||
452 | 452 | | |
453 | 453 | | |
454 | 454 | | |
455 | | - | |
| 455 | + | |
456 | 456 | | |
457 | 457 | | |
458 | 458 | | |
| |||
883 | 883 | | |
884 | 884 | | |
885 | 885 | | |
886 | | - | |
| 886 | + | |
887 | 887 | | |
888 | 888 | | |
889 | 889 | | |
| |||
892 | 892 | | |
893 | 893 | | |
894 | 894 | | |
895 | | - | |
| 895 | + | |
896 | 896 | | |
897 | 897 | | |
898 | 898 | | |
| |||
1173 | 1173 | | |
1174 | 1174 | | |
1175 | 1175 | | |
1176 | | - | |
1177 | | - | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
1178 | 1179 | | |
1179 | 1180 | | |
1180 | | - | |
| 1181 | + | |
| 1182 | + | |
1181 | 1183 | | |
1182 | 1184 | | |
1183 | 1185 | | |
| |||
1186 | 1188 | | |
1187 | 1189 | | |
1188 | 1190 | | |
1189 | | - | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
| 1194 | + | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
1190 | 1215 | | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
1191 | 1231 | | |
1192 | 1232 | | |
1193 | 1233 | | |
| |||
1217 | 1257 | | |
1218 | 1258 | | |
1219 | 1259 | | |
1220 | | - | |
| 1260 | + | |
1221 | 1261 | | |
1222 | | - | |
1223 | | - | |
1224 | | - | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
1225 | 1267 | | |
1226 | | - | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
1227 | 1271 | | |
1228 | 1272 | | |
1229 | 1273 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
231 | 231 | | |
232 | 232 | | |
233 | 233 | | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
234 | 240 | | |
235 | 241 | | |
236 | 242 | | |
| |||
244 | 250 | | |
245 | 251 | | |
246 | 252 | | |
| 253 | + | |
247 | 254 | | |
248 | | - | |
| 255 | + | |
249 | 256 | | |
250 | | - | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
251 | 264 | | |
252 | 265 | | |
253 | 266 | | |
| |||
1969 | 1982 | | |
1970 | 1983 | | |
1971 | 1984 | | |
| 1985 | + | |
| 1986 | + | |
| 1987 | + | |
| 1988 | + | |
| 1989 | + | |
| 1990 | + | |
| 1991 | + | |
| 1992 | + | |
| 1993 | + | |
| 1994 | + | |
| 1995 | + | |
| 1996 | + | |
| 1997 | + | |
| 1998 | + | |
| 1999 | + | |
| 2000 | + | |
| 2001 | + | |
| 2002 | + | |
| 2003 | + | |
| 2004 | + | |
| 2005 | + | |
| 2006 | + | |
| 2007 | + | |
| 2008 | + | |
| 2009 | + | |
| 2010 | + | |
| 2011 | + | |
| 2012 | + | |
| 2013 | + | |
| 2014 | + | |
| 2015 | + | |
| 2016 | + | |
| 2017 | + | |
| 2018 | + | |
| 2019 | + | |
1972 | 2020 | | |
1973 | 2021 | | |
1974 | 2022 | | |
| |||
0 commit comments