Skip to content

Commit ee22d41

Browse files
committed
Fix multiple parser issues from TODO.md
- Fix table/database names starting with numbers (e.g., 03657_test) - Add parseIdentifierName helper for numeric-prefix identifiers - Support FORMAT Null and other keyword format names - Add FETCH FIRST ... ROW ONLY syntax support - Add INSERT INTO FUNCTION support - Allow keywords as alias names - Add MOD and DIV keyword operators - Support $ in identifier names for parameterized settings - Handle == as equality operator in lexer Tests passing increased from 5196 to 5352 (+156 tests)
1 parent b22df7b commit ee22d41

5 files changed

Lines changed: 150 additions & 148 deletions

File tree

ast/ast.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ func (s *SettingExpr) End() token.Position { return s.Position }
201201
type InsertQuery struct {
202202
Position token.Position `json:"-"`
203203
Database string `json:"database,omitempty"`
204-
Table string `json:"table"`
204+
Table string `json:"table,omitempty"`
205+
Function *FunctionCall `json:"function,omitempty"` // For INSERT INTO FUNCTION syntax
205206
Columns []*Identifier `json:"columns,omitempty"`
206207
Select Statement `json:"select,omitempty"`
207208
Format *Identifier `json:"format,omitempty"`

lexer/lexer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ func (l *Lexer) NextToken() Item {
118118
return Item{Token: token.PERCENT, Value: "%", Pos: pos}
119119
case '=':
120120
l.readChar()
121+
if l.ch == '=' {
122+
l.readChar()
123+
return Item{Token: token.EQ, Value: "==", Pos: pos}
124+
}
121125
return Item{Token: token.EQ, Value: "=", Pos: pos}
122126
case '!':
123127
if l.peekChar() == '=' {
@@ -407,7 +411,7 @@ func isIdentStart(ch rune) bool {
407411
}
408412

409413
func isIdentChar(ch rune) bool {
410-
return ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch)
414+
return ch == '_' || ch == '$' || unicode.IsLetter(ch) || unicode.IsDigit(ch)
411415
}
412416

413417
// Tokenize returns all tokens from the reader.

parser/expression.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (p *Parser) precedence(tok token.Token) int {
4444
return CONCAT_PREC
4545
case token.PLUS, token.MINUS:
4646
return ADD_PREC
47-
case token.ASTERISK, token.SLASH, token.PERCENT:
47+
case token.ASTERISK, token.SLASH, token.PERCENT, token.DIV, token.MOD:
4848
return MUL_PREC
4949
case token.LPAREN, token.LBRACKET:
5050
return CALL
@@ -173,7 +173,7 @@ func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {
173173
switch p.current.Token {
174174
case token.PLUS, token.MINUS, token.ASTERISK, token.SLASH, token.PERCENT,
175175
token.EQ, token.NEQ, token.LT, token.GT, token.LTE, token.GTE,
176-
token.AND, token.OR, token.CONCAT:
176+
token.AND, token.OR, token.CONCAT, token.DIV, token.MOD:
177177
return p.parseBinaryExpression(left)
178178
case token.NULL_SAFE_EQ:
179179
return p.parseBinaryExpression(left)
@@ -1104,8 +1104,9 @@ func (p *Parser) parseDotAccess(left ast.Expression) ast.Expression {
11041104
func (p *Parser) parseAlias(left ast.Expression) ast.Expression {
11051105
p.nextToken() // skip AS
11061106

1107+
// Alias can be an identifier or a keyword (ClickHouse allows keywords as aliases)
11071108
alias := ""
1108-
if p.currentIs(token.IDENT) {
1109+
if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() {
11091110
alias = p.current.Value
11101111
p.nextToken()
11111112
}

0 commit comments

Comments
 (0)