@@ -292,6 +292,20 @@ func (p *Parser) parseSelect() *ast.SelectQuery {
292292 sel .Limit = p .parseExpression (LOWEST )
293293 }
294294
295+ // LIMIT BY clause (ClickHouse specific: LIMIT n BY expr1, expr2, ...)
296+ if p .currentIs (token .BY ) {
297+ p .nextToken ()
298+ // Parse LIMIT BY expressions - skip them for now
299+ for ! p .isEndOfExpression () {
300+ p .parseExpression (LOWEST )
301+ if p .currentIs (token .COMMA ) {
302+ p .nextToken ()
303+ } else {
304+ break
305+ }
306+ }
307+ }
308+
295309 // WITH TIES modifier
296310 if p .currentIs (token .WITH ) && p .peekIs (token .TIES ) {
297311 p .nextToken () // skip WITH
@@ -657,10 +671,10 @@ func (p *Parser) parseTableExpression() *ast.TableExpression {
657671 }
658672 }
659673
660- // Handle alias
674+ // Handle alias (keywords like LEFT, RIGHT can be used as aliases after AS)
661675 if p .currentIs (token .AS ) {
662676 p .nextToken ()
663- if p .currentIs (token .IDENT ) {
677+ if p .currentIs (token .IDENT ) || p . current . Token . IsKeyword () {
664678 expr .Alias = p .current .Value
665679 p .nextToken ()
666680 }
@@ -684,6 +698,17 @@ func (p *Parser) isKeywordForClause() bool {
684698 return false
685699}
686700
701+ func (p * Parser ) isEndOfExpression () bool {
702+ switch p .current .Token {
703+ case token .EOF , token .RPAREN , token .RBRACKET , token .SEMICOLON ,
704+ token .UNION , token .EXCEPT , token .ORDER , token .LIMIT ,
705+ token .OFFSET , token .SETTINGS , token .FORMAT , token .INTO ,
706+ token .WITH :
707+ return true
708+ }
709+ return false
710+ }
711+
687712func (p * Parser ) parseOrderByList () []* ast.OrderByElement {
688713 var elements []* ast.OrderByElement
689714
@@ -774,11 +799,18 @@ func (p *Parser) parseSettingsList() []*ast.SettingExpr {
774799 }
775800 p .nextToken ()
776801
777- if ! p .expect (token .EQ ) {
778- break
802+ // Settings can have optional value (bool settings can be just name)
803+ if p .currentIs (token .EQ ) {
804+ p .nextToken ()
805+ setting .Value = p .parseExpression (LOWEST )
806+ } else {
807+ // Boolean setting without value - defaults to true
808+ setting .Value = & ast.Literal {
809+ Position : setting .Position ,
810+ Type : ast .LiteralBoolean ,
811+ Value : true ,
812+ }
779813 }
780-
781- setting .Value = p .parseExpression (LOWEST )
782814 settings = append (settings , setting )
783815
784816 if ! p .currentIs (token .COMMA ) {
@@ -1029,11 +1061,27 @@ func (p *Parser) parseCreateTable(create *ast.CreateQuery) {
10291061 }
10301062done_table_options:
10311063
1032- // Parse AS SELECT
1064+ // Parse AS SELECT or AS table_function()
10331065 if p .currentIs (token .AS ) {
10341066 p .nextToken ()
10351067 if p .currentIs (token .SELECT ) || p .currentIs (token .WITH ) {
10361068 create .AsSelect = p .parseSelectWithUnion ()
1069+ } else if p .currentIs (token .IDENT ) {
1070+ // AS table_function(...) like "AS s3Cluster(...)"
1071+ // Skip the function call for now
1072+ p .parseIdentifierName ()
1073+ if p .currentIs (token .LPAREN ) {
1074+ depth := 1
1075+ p .nextToken ()
1076+ for depth > 0 && ! p .currentIs (token .EOF ) {
1077+ if p .currentIs (token .LPAREN ) {
1078+ depth ++
1079+ } else if p .currentIs (token .RPAREN ) {
1080+ depth --
1081+ }
1082+ p .nextToken ()
1083+ }
1084+ }
10371085 }
10381086 }
10391087}
@@ -1153,7 +1201,7 @@ func (p *Parser) parseColumnDeclaration() *ast.ColumnDeclaration {
11531201 // Parse data type
11541202 col .Type = p .parseDataType ()
11551203
1156- // Parse DEFAULT/MATERIALIZED/ALIAS
1204+ // Parse DEFAULT/MATERIALIZED/ALIAS/EPHEMERAL
11571205 switch p .current .Token {
11581206 case token .DEFAULT :
11591207 col .DefaultKind = "DEFAULT"
@@ -1169,6 +1217,16 @@ func (p *Parser) parseColumnDeclaration() *ast.ColumnDeclaration {
11691217 col .Default = p .parseExpression (LOWEST )
11701218 }
11711219
1220+ // Handle EPHEMERAL (can be EPHEMERAL or EPHEMERAL default_value)
1221+ if p .currentIs (token .IDENT ) && strings .ToUpper (p .current .Value ) == "EPHEMERAL" {
1222+ col .DefaultKind = "EPHEMERAL"
1223+ p .nextToken ()
1224+ // Optional default value
1225+ if ! p .currentIs (token .COMMA ) && ! p .currentIs (token .RPAREN ) && ! p .currentIs (token .IDENT ) {
1226+ col .Default = p .parseExpression (LOWEST )
1227+ }
1228+ }
1229+
11721230 // Parse CODEC
11731231 if p .currentIs (token .IDENT ) && strings .ToUpper (p .current .Value ) == "CODEC" {
11741232 p .nextToken ()
@@ -1208,18 +1266,42 @@ func (p *Parser) parseDataType() *ast.DataType {
12081266 // Parse type parameters
12091267 if p .currentIs (token .LPAREN ) {
12101268 p .nextToken ()
1211- for ! p .currentIs (token .RPAREN ) && ! p .currentIs (token .EOF ) {
1212- // Could be another data type or an expression
1213- // Type names can be identifiers or keywords (Array, Nested, etc.)
1214- if (p .currentIs (token .IDENT ) || p .current .Token .IsKeyword ()) && p .isDataTypeName (p .current .Value ) {
1215- dt .Parameters = append (dt .Parameters , p .parseDataType ())
1216- } else {
1217- dt .Parameters = append (dt .Parameters , p .parseExpression (LOWEST ))
1269+
1270+ // Special handling for Nested type - it contains column declarations, not just types
1271+ if strings .ToUpper (dt .Name ) == "NESTED" {
1272+ for ! p .currentIs (token .RPAREN ) && ! p .currentIs (token .EOF ) {
1273+ // Parse as column name + type
1274+ if p .currentIs (token .IDENT ) || p .current .Token .IsKeyword () {
1275+ colName := p .current .Value
1276+ p .nextToken ()
1277+ // Parse the type for this column
1278+ colType := p .parseDataType ()
1279+ if colType != nil {
1280+ // Wrap in a special format or just store as data type
1281+ colType .Name = colName + " " + colType .Name
1282+ dt .Parameters = append (dt .Parameters , colType )
1283+ }
1284+ }
1285+ if p .currentIs (token .COMMA ) {
1286+ p .nextToken ()
1287+ } else {
1288+ break
1289+ }
12181290 }
1219- if p .currentIs (token .COMMA ) {
1220- p .nextToken ()
1221- } else {
1222- break
1291+ } else {
1292+ for ! p .currentIs (token .RPAREN ) && ! p .currentIs (token .EOF ) {
1293+ // Could be another data type or an expression
1294+ // Type names can be identifiers or keywords (Array, Nested, etc.)
1295+ if (p .currentIs (token .IDENT ) || p .current .Token .IsKeyword ()) && p .isDataTypeName (p .current .Value ) {
1296+ dt .Parameters = append (dt .Parameters , p .parseDataType ())
1297+ } else {
1298+ dt .Parameters = append (dt .Parameters , p .parseExpression (LOWEST ))
1299+ }
1300+ if p .currentIs (token .COMMA ) {
1301+ p .nextToken ()
1302+ } else {
1303+ break
1304+ }
12231305 }
12241306 }
12251307 p .expect (token .RPAREN )
@@ -1304,7 +1386,8 @@ func (p *Parser) parseEngineClause() *ast.EngineClause {
13041386 Position : p .current .Pos ,
13051387 }
13061388
1307- if p .currentIs (token .IDENT ) {
1389+ // Engine name can be identifier or keyword (Null, Join, Memory, etc.)
1390+ if p .currentIs (token .IDENT ) || p .current .Token .IsKeyword () {
13081391 engine .Name = p .current .Value
13091392 p .nextToken ()
13101393 }
@@ -1347,8 +1430,29 @@ func (p *Parser) parseDrop() *ast.DropQuery {
13471430 case token .USER :
13481431 dropUser = true
13491432 p .nextToken ()
1433+ case token .FUNCTION :
1434+ p .nextToken ()
1435+ case token .INDEX :
1436+ p .nextToken ()
13501437 default :
1351- p .nextToken () // skip unknown token
1438+ // Handle multi-word DROP types: ROW POLICY, NAMED COLLECTION, SETTINGS PROFILE
1439+ if p .currentIs (token .IDENT ) {
1440+ upper := strings .ToUpper (p .current .Value )
1441+ switch upper {
1442+ case "ROW" , "NAMED" , "POLICY" , "SETTINGS" , "QUOTA" , "ROLE" :
1443+ // Skip the DROP type tokens
1444+ for p .currentIs (token .IDENT ) || p .current .Token .IsKeyword () {
1445+ if p .currentIs (token .IF ) {
1446+ break // Hit IF EXISTS
1447+ }
1448+ p .nextToken ()
1449+ }
1450+ default :
1451+ p .nextToken () // skip unknown token
1452+ }
1453+ } else {
1454+ p .nextToken () // skip unknown token
1455+ }
13521456 }
13531457
13541458 // Handle IF EXISTS
@@ -1385,7 +1489,39 @@ func (p *Parser) parseDrop() *ast.DropQuery {
13851489 }
13861490 }
13871491
1388- // Handle ON CLUSTER
1492+ // Handle multiple tables (DROP TABLE IF EXISTS t1, t2, t3)
1493+ // For now, just skip additional table names
1494+ for p .currentIs (token .COMMA ) {
1495+ p .nextToken ()
1496+ // Skip the table name (may be qualified like db.table)
1497+ p .parseIdentifierName ()
1498+ if p .currentIs (token .DOT ) {
1499+ p .nextToken ()
1500+ p .parseIdentifierName ()
1501+ }
1502+ }
1503+
1504+ // Handle ON table or ON CLUSTER
1505+ if p .currentIs (token .ON ) {
1506+ p .nextToken ()
1507+ if p .currentIs (token .CLUSTER ) {
1508+ p .nextToken ()
1509+ if p .currentIs (token .IDENT ) || p .currentIs (token .STRING ) {
1510+ drop .OnCluster = p .current .Value
1511+ p .nextToken ()
1512+ }
1513+ } else {
1514+ // ON table_name (for DROP ROW POLICY, etc.)
1515+ // Skip the table reference
1516+ p .parseIdentifierName ()
1517+ if p .currentIs (token .DOT ) {
1518+ p .nextToken ()
1519+ p .parseIdentifierName ()
1520+ }
1521+ }
1522+ }
1523+
1524+ // Handle second ON CLUSTER (can appear after ON table)
13891525 if p .currentIs (token .ON ) {
13901526 p .nextToken ()
13911527 if p .currentIs (token .CLUSTER ) {
@@ -1403,6 +1539,14 @@ func (p *Parser) parseDrop() *ast.DropQuery {
14031539 p .nextToken ()
14041540 }
14051541
1542+ // Handle NO DELAY
1543+ if p .currentIs (token .IDENT ) && strings .ToUpper (p .current .Value ) == "NO" {
1544+ p .nextToken ()
1545+ if p .currentIs (token .IDENT ) && strings .ToUpper (p .current .Value ) == "DELAY" {
1546+ p .nextToken ()
1547+ }
1548+ }
1549+
14061550 return drop
14071551}
14081552
0 commit comments