Releases: orian/clickhouse-sql-parser
Release list
v1.1.1
Column transformers and qualified stars, following ClickHouse 26.8.
- Column transformers without parentheses and with
STRICT(#126):
* EXCEPT a,* EXCEPT STRICT (a, b),* EXCEPT 'regex',
* REPLACE a + 1 AS a,* APPLY toString,* APPLY x -> x + 1.STRICT
is kept: ClickHouse fails on a missing column instead of ignoring it. SELECT db.t.* FROM db.t, a star qualified by database and table, also
with transformers (#152).go.moddeclaresgo 1.27, and any Go 1.27.x toolchain works.
⚠️ This patch release contains a breaking API change.SelectItem.Modifiers
is now[]*ColumnTransformer(was[]*FunctionExpr), andASTVisitorhas a new
method,VisitColumnTransformer. Visitors embeddingDefaultASTVisitoror
PrintVisitorinherit it. See the Breaking section below (also in
COMPATIBILITY.md).
Breaking
- Column transformers have their own node (#126):
SelectItem.Modifiers
is[]*ColumnTransformer(was[]*FunctionExpr), withKind("EXCEPT",
"REPLACE","APPLY"),Strict,HasParenandArgs.ASTVisitorhas a
new method,VisitColumnTransformer; visitors embeddingDefaultASTVisitor
orPrintVisitorinherit it.
Changed behavior
- Column transformers print with a space before parentheses, as in
ClickHouse:* EXCEPT (a) APPLY (sum)(wasEXCEPT(a) APPLY(sum)) (#126).
Newly rejected input
- An alias on a column matcher:
SELECT * AS x,t.* AS x,
COLUMNS(…) AS x,* EXCEPT (a) AS x(#126). - Column transformer arguments ClickHouse rejects:
EXCEPT (t.a), mixing a
regex with names inEXCEPT,REPLACE (a)withoutAS,APPLY(f, g),
andEXCEPT strict(STRICT is always the modifier; writeEXCEPT (strict))
(#126).
Additive
- Newly accepted input: column transformers without parentheses and with
STRICT:* EXCEPT a,* EXCEPT STRICT (a, b),* EXCEPT 'regex',
* REPLACE a + 1 AS a,* APPLY toString,* APPLY x -> x + 1(#126). - Newly accepted input: a star qualified by database and table,
SELECT db.t.* FROM db.t, with column transformers (db.t.* EXCEPT (a))
(#152). It parses as a*Pathwhose last field is the*identifier;
t.*is still a*NestedIdentifier.
What's Changed
- Parser: accept a star qualified by database and table, db.t.* (#152) by @orian in #155
- Parser: model column transformers; accept STRICT and paren-free forms (#126) by @orian in #156
- Release v1.1.1 by @orian in #157
Full Changelog: v1.1.0...v1.1.1
v1.1.0
The parser now follows ClickHouse 26.8 much more closely.
- Silent SQL losses fixed: it no longer drops or changes clauses when printing. For example,
DETACHused to print asDROP,SELECT 1, limit(1)becameLIMIT (1), andINTERVAL … PRECEDINGlostPRECEDING. - Much more valid SQL accepted:
EXPLAINin all forms,INTERSECT,PASTE/NATURAL JOIN,CREATE/DROP INDEX,{name:Identifier}parameters, table-function expressions, and every SYSTEMSYNC/FLUSH/START|STOPform. - SQL that ClickHouse rejects is rejected too.
- Formatting:
PrintVisitoris about twice as fast. - Traversal:
Walkand the visitor reach every node.
⚠️ This minor release contains breaking API changes. Go 1.27 is required,ASTVisitorhas new methods, some fields changed type or can now be nil, and positions and AST shapes changed. Read the Breaking section below (also inCOMPATIBILITY.md) before upgrading.
Breaking
- Go 1.27 is required (
go.modsaidgo 1.21.0). ASTVisitorhas new methods:VisitStreamClause(#102),VisitCreateIndex
andVisitDropIndex(#135). Visitors embeddingDefaultASTVisitoror
PrintVisitorinherit them; direct implementations must add them.
StreamClause.Acceptnow dispatches toVisitStreamClause.- Changed types:
ShowStmt.Formatis*FormatClause, from the embedded
OutputClauses(name inFormat.Format.Name; was*StringLiteral), and
prints unquoted,FORMAT JSONrather thanFORMAT 'JSON'(#87, #49). - Fields that can now be nil, or hold other node types:
SubQuery.Selectis nil for(EXPLAIN …); seeSubQuery.Explain(#133);TableIndex.Granularityis nil whenGRANULARITYis omitted (#134);ExplainStmt.Statementcan be any statement, not only*SelectQuery, and
is nil forEXPLAIN CURRENT TRANSACTION;ExplainStmt.Typeis empty when
the kind is omitted (#86);SystemCtrlExpr.Cluster(the table) is nil when none is given (#108);TableArgListExpr.Argscan hold any expression (#129).
- Positions (#92):
Pos()/End()of a quotedStringLiteral/Identinclude the quotes; the
LiteralPos/LiteralEnd/NamePos/NameEndfields still exclude them;End()of nodes closed by),]or}points after the delimiter
(ParamExprList,FunctionExpr,ArrayParamList,MapLiteral,
TableSchemaClause,TableArgListExpr,ComplexType,QueryParam, …);- a statement's
[Pos(), End())covers exactly its text (it used to stop
early or include the;); - corrected fields:
CompressionCodec.RightParenPos(the)), column
COMMENTLiteralPos(the string),TypedPlaceholder.RightBracePos(the
}),Fill.FillPos(FILL),IsNullExpr/IsNotNullExpr.IsPos(IS;
Pos()is the operand),ShowStmt/GrantPrivilegeStmt.StatementEnd; SystemSyncExpr.End(),SystemFlushExpr.End(),ExplainStmt.End()and
TableIndex.End()cover the whole node (#62, #114, #86, #134).
- AST shapes:
ATTACH/DETACHkeep their verb (IsAttach/IsDetach;DropStmt.Type()
returnsDETACH TABLE);DETACH TABLE tused to print asDROP TABLE t
(#43, #52, #68);- a parenthesised set-operation operand is a group node: a
SelectQuerywith
HasParenand the inner query inGroup(#79, #93); - trailing
FORMAT/query-levelSETTINGSof a statement live in the embedded
OutputClauses; afterFORMATon a SELECT inSelectQuery.OutputSettings
(#87); - all parts of one TimeSeries target form a single
TimeSeriesTargetClause
(#42); FROM t STREAMisTableExpr.Stream, not the aliasSTREAM(#81);JoinExpr.ModifierskeepsGLOBAL, and can holdNATURAL/PASTE;
a LOCAL JOIN baliasesaasLOCAL(#74, #89);- lower-case
array joinis an ARRAY JOIN (JoinExpr.Leftis a
*ColumnExprList), not a join on a table named by its first expression
(#50); SystemCtrlExpr.Typeis the whole target, e.g."REPLICATION QUEUES"
(#108).
Changed behavior
- Traversal:
Walk(andFind,FindAll,WalkWithBreak,Transform)
andDefaultASTVisitornow reach every child node and agree with each other
(#105, #106). They used to skip, among others,EXCEPToperands,INSERT … VALUESrows, TTL actions, named-collection parameters,DISTINCT ON
columns, projectionORDER BYcolumns andRENAMEpairs. Map keys are
walked in place, so rewriting one changes the AST.IntervalFromand
WindowFrameParamno longer visit their child twice (#98). PrintVisitorprints every node like itsString()(#98) and streams
into one builder (#99).BeautifyVisitoremits every statement type (#51).- Printed SQL fixed (the old output was invalid or meant something else):
WINDOWafterHAVING(#88);IF [NOT] EXISTSbefore the name inDROP INDEX|PROJECTIONandADD INDEX(#64);PRECEDING/FOLLOWINGafter anINTERVALframe bound (#109);SYSTEM SYNC REPLICA(#62),SYSTEM FLUSH DISTRIBUTED(#114),SYSTEM STOP|START DISTRIBUTED SENDSwithout… SENDS SENDS(#108);SELECT 1, limit(1)keeps the column instead of becomingLIMIT (1)
(#138);PASTE/NATURAL JOINare joins, not aliases (#89);(3,)keeps its comma (#70),f(p)(DISTINCT x)itsDISTINCT(#71),
INSERT INTO FUNCTIONitsFUNCTION(#72),PARTITION IDitsID(#76),
WITH TOTALSwithoutGROUP BY(#77),WITH FILL(#47);USINGis always parenthesised and comma joins print,(#74);-1::T
keeps the sign on the literal (#83);TOP n WITH TIES(#90); no double
spaces inCREATE TABLE t AS …/CREATE DATABASE … ENGINE(#45, #68);CREATE TABLEkeeps its query-levelSETTINGS, and repeatedCREATE USER
HOST/SETTINGSclauses are merged (#37).
- Parsing:
INTERSECTis a keyword, not an implicit alias (#107);
SELECT 1 EXCEPT (SELECT 2)is a set operation, not a column transformer
(#107); in an expression{always starts a query parameter, and a
{'k': v}map literal is valid only inINSERT … VALUESrows and as a
SETTINGSvalue (#50).
Newly rejected input
- Select list and joins: a missing select list (
SELECT,SELECT FROM t;
a loneSELECTused to parse to zero statements) (#82); a comma before a
clause other thanFROM(SELECT a, ORDER BY a) (#138); aJOINwithout
ON/USINGexceptCROSS,NATURAL,PASTE,ARRAY(#50);PASTE/
NATURALas an implicit alias, or withON/USING, a strictness,CROSS
orARRAY(#89);GLOBAL ARRAY JOINandLEFT GLOBAL JOIN(#74). - Expressions: column transformers (
EXCEPT,APPLY,REPLACE) after
anything but*,t.*,COLUMNS(…)or* LIKE 'p'(#50);WITH CUBE/ROLLUP
afterGROUP BY CUBE(…)/ROLLUP(…)(#50); a map literal in an expression
(#50); a trailing comma except in a one-element tuple (f(a,),[1,])
(#70). - Repeated or misplaced clauses: repeated engine clauses in
CREATE TABLE,
repeatedCREATE USERclauses,GROUP BYmodifiers out of order (#37);
repeated TimeSeries target parts andRECENTwithoutSAMPLES(#42); an
alias,FINALorSAMPLEafterSTREAM(#81); repeatedWITH TIESand
LIMIT … BY … WITH TIES(#90);FORMAT/SETTINGSafter statements that
take none (GRANT, SYSTEM, USE, SET, DELETE, USER/ROLE, CREATE FUNCTION/NAMED
COLLECTION; used to be dropped silently), a quotedSHOW … FORMAT 'x', and
INSERT … VALUES (…) FORMAT x(#87). - DDL: an empty column list
()(#45);ATTACH OR REPLACE,
ATTACH/DETACHof FUNCTION/ROLE/USER/NAMED COLLECTION,DROP … PERMANENTLY,CREATE DICTIONARY dwithout a definition (#68);OR REPLACE
withIF NOT EXISTSinCREATE TABLE/VIEW(#50); several pairs inRENAME DATABASE(#50); aPARTITIONvalue other than a literal, query parameter,
tuple or CAST of one (DROP PARTITION p,PARTITION toDate(…)) (#50); a
malformedUUID '…'(ClickHouse:CANNOT_PARSE_UUID) (#50). - SYSTEM:
START|STOP DISTRIBUTED MERGES|FETCHES|TTL MERGES(used to print
as… MERGES MERGES) (#108). - Access control (#50): several roles in
ALTER ROLE … RENAME TO;ON CLUSTERbefore the last role name;WITH ADMIN OPTIONon a privilege grant;
a column list on a wildcard target; the target*.table;GRANT ADMIN OPTION ON ….
Additive
- New types:
OutputClauses(#87),StreamClause(#81),CreateIndex,
DropIndex(#135). - New fields:
CreateTable.Settings,WithTimeoutClause.WithTimeoutEnd
(#37);TimeSeriesTargetClause.InnerUUID,EngineShorthand(#42);
IsAttach/IsDetach/Permanently,DropDatabase.Modifier(#68);
ColumnExprList.HasTrailingComma(#70);AlterTableDelete.InPartition
(#76);SelectQuery.HasParen,Group,OutputSettings,Union,
Intersect,IntersectModifier,ExceptModifier(#79, #87, #93, #107,
#125);TableExpr.Stream(#81);LimitClause.WithTies,WithTiesEnd(#90);
OrderExpr.Nulls,Collate(#47);SystemSyncExpr.SyncEnd,Target,
OnCluster,Database,IfExists,Mode,From,CacheName(#62);
SystemCtrlExpr.OnCluster(#108);SystemFlushExpr.AsyncInsertQueue,
OnCluster,Tables,Settings(#114);ExplainStmt.Settings,
ExplainEnd(#86);Ident.Paramfor{name:Identifier}(#131);
SubQuery.Explain(#133); span fieldsCastExpr.RightParenPos,
SubQuery.RightParenPos,UsingClause.UsingEnd,OrderExpr.OrderEnd,
NamedCollectionParam.ParamEnd,IsNullExpr/IsNotNullExpr.NullEnd(#92). - New methods:
VisitStreamClause,VisitCreateIndex,VisitDropIndexon
DefaultASTVisitorandPrintVisitor;InsertStmt.IsTableFunction()(#72). - Newly accepted input:
- SELECT:
INTERSECT [DISTINCT|ALL],EXCEPT DISTINCT|ALL, bareUNION
(#1...
- SELECT:
v1.0.4
What's Changed
- Add ClickHouse SQL corpora and fix parser panics by @orian in #28
- Add parser fuzzing and fix malformed-input crashes by @orian in #29
- Fix truncated SQL panics and expand manual fuzzing by @orian in #30
- Parser: support WITH RECURSIVE common table expressions by @orian in #32
- Expand parser fuzz coverage and fix AST panic paths by @orian in #34
- chore(parser): cover unterminated comments after CTEs by @orian in #33
Full Changelog: v1.0.3...v1.0.4
v1.0.3
v1.0.2
What's Changed
- fix: parse gcd codec chains by @rorylshanks in #26
New Contributors
- @rorylshanks made their first contribution in #26
Full Changelog: v1.0.1...v1.0.2
v1.0.1
v1.0.0
What's Changed
- Parser: support bare TTL ... WHERE row-filter (fixes #2) by @orian in #4
- Parser: support INDEX TYPE kwargs e.g. text(tokenizer = ...) (fixes #3) by @orian in #5
- Parser: support CREATE VIEW DEFINER / SQL SECURITY / post-AS COMMENT (fixes #6) by @orian in #7
- Parser: support ENGINE = TimeSeries target clauses (fixes #8) by @orian in #9
- Rename module path to github.com/orian/clickhouse-sql-parser by @orian in #10
- Parser: support PROJECTION ... (SELECT ...) WITH SETTINGS (...) (fixes #11) by @orian in #12
- ci: run tests + build on main, modernize workflow by @orian in #13
- Parser: accept parameterless dictionary LAYOUT without inner parens (fixes #14) by @orian in #15
- test: cover every ClickHouse dictionary LAYOUT by @orian in #16
- Parser: accept CONSTRAINT ... ASSUME and preserve constraint kind (fixes #17) by @orian in #18
- BeautifyVisitor: render projection SELECT / ORDER BY (fixes #19) by @orian in #20
- Parser: apply column DEFAULT panic fix to canonical main by @orian in #23
Full Changelog: https://github.com/orian/clickhouse-sql-parser/commits/v1.0.0