Skip to content

Commit 5ac95e3

Browse files
committed
Add implicit alias handling for EXTRACT and function arguments
Three changes to support implicit aliases (identifiers without AS): 1. Parser: Add parseImplicitAlias call after parsing EXTRACT FROM expr Fixes `EXTRACT(DAY FROM toDate(...) arg_1)` syntax 2. Parser: Add parseImplicitAlias calls in parseFunctionArgumentList Fixes implicit aliases on function arguments like `func('a' arg_1)` 3. Parser: Add parseImplicitAlias calls for regex-style extract function 4. Explain: Update handleDateDiff to support 4 arguments (with timezone) Fixes 12 statements in test 02267_special_operator_parse_alias_check.
1 parent 0197f96 commit 5ac95e3

File tree

3 files changed

+28
-27
lines changed

3 files changed

+28
-27
lines changed

internal/explain/functions.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,9 @@ func explainDateAddSubWithInterval(sb *strings.Builder, opFunc string, arg1, arg
372372
}
373373

374374
// handleDateDiff handles DATE_DIFF/DATEDIFF
375-
// DATE_DIFF(unit, date1, date2) -> dateDiff('unit', date1, date2)
375+
// DATE_DIFF(unit, date1, date2[, timezone]) -> dateDiff('unit', date1, date2[, timezone])
376376
func handleDateDiff(sb *strings.Builder, n *ast.FunctionCall, alias string, indent string, depth int) bool {
377-
if len(n.Arguments) != 3 {
377+
if len(n.Arguments) < 3 || len(n.Arguments) > 4 {
378378
return false
379379
}
380380

@@ -392,12 +392,17 @@ func handleDateDiff(sb *strings.Builder, n *ast.FunctionCall, alias string, inde
392392
return false
393393
}
394394

395+
argCount := 3
396+
if len(n.Arguments) == 4 {
397+
argCount = 4
398+
}
399+
395400
if alias != "" {
396401
fmt.Fprintf(sb, "%sFunction dateDiff (alias %s) (children %d)\n", indent, alias, 1)
397402
} else {
398403
fmt.Fprintf(sb, "%sFunction dateDiff (children %d)\n", indent, 1)
399404
}
400-
fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 3)
405+
fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, argCount)
401406

402407
// First arg: unit as lowercase string literal
403408
fmt.Fprintf(sb, "%s Literal \\'%s\\'\n", indent, strings.ToLower(unitName))
@@ -406,6 +411,11 @@ func handleDateDiff(sb *strings.Builder, n *ast.FunctionCall, alias string, inde
406411
Node(sb, date1Arg, depth+2)
407412
Node(sb, date2Arg, depth+2)
408413

414+
// Fourth arg: optional timezone
415+
if len(n.Arguments) == 4 {
416+
Node(sb, n.Arguments[3], depth+2)
417+
}
418+
409419
return true
410420
}
411421

@@ -1334,13 +1344,10 @@ func explainExtractExprWithAlias(sb *strings.Builder, n *ast.ExtractExpr, alias
13341344
// EXTRACT is represented as Function toYear, toMonth, etc.
13351345
// ClickHouse uses specific function names for date/time extraction
13361346
fnName := extractFieldToFunction(n.Field)
1337-
// Use alias from parameter, or fall back to expression's alias
1338-
effectiveAlias := alias
1339-
if effectiveAlias == "" {
1340-
effectiveAlias = n.Alias
1341-
}
1342-
if effectiveAlias != "" {
1343-
fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, fnName, effectiveAlias, 1)
1347+
// Only use the external alias parameter (from explicit AS on EXTRACT itself)
1348+
// NOT the alias from the From expression - that stays on the inner expression
1349+
if alias != "" {
1350+
fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, fnName, alias, 1)
13441351
} else {
13451352
fmt.Fprintf(sb, "%sFunction %s (children %d)\n", indent, fnName, 1)
13461353
}

parser/expression.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ func (p *Parser) parseFunctionArgumentList() []ast.Expression {
143143

144144
expr := p.parseExpression(LOWEST)
145145
if expr != nil {
146+
// Handle implicit alias (identifier without AS)
147+
expr = p.parseImplicitAlias(expr)
146148
exprs = append(exprs, expr)
147149
}
148150

@@ -154,6 +156,8 @@ func (p *Parser) parseFunctionArgumentList() []ast.Expression {
154156
}
155157
expr := p.parseExpression(LOWEST)
156158
if expr != nil {
159+
// Handle implicit alias (identifier without AS)
160+
expr = p.parseImplicitAlias(expr)
157161
exprs = append(exprs, expr)
158162
}
159163
}
@@ -1390,6 +1394,8 @@ func (p *Parser) parseExtract() ast.Expression {
13901394
if p.currentIs(token.FROM) {
13911395
p.nextToken()
13921396
from := p.parseExpression(LOWEST)
1397+
// Handle implicit alias (identifier without AS)
1398+
from = p.parseImplicitAlias(from)
13931399
p.expect(token.RPAREN)
13941400
return &ast.ExtractExpr{
13951401
Position: pos,
@@ -1425,7 +1431,10 @@ func (p *Parser) parseExtract() ast.Expression {
14251431
// or extract(expr, pattern) where expr can be any expression
14261432
var args []ast.Expression
14271433
for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) {
1428-
args = append(args, p.parseExpression(LOWEST))
1434+
arg := p.parseExpression(LOWEST)
1435+
// Handle implicit alias (identifier without AS)
1436+
arg = p.parseImplicitAlias(arg)
1437+
args = append(args, arg)
14291438
if p.currentIs(token.COMMA) {
14301439
p.nextToken()
14311440
} else {
Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt41": true,
4-
"stmt43": true,
5-
"stmt46": true,
6-
"stmt48": true,
7-
"stmt50": true,
8-
"stmt52": true,
9-
"stmt54": true,
10-
"stmt56": true,
11-
"stmt57": true,
12-
"stmt58": true,
13-
"stmt60": true,
14-
"stmt62": true
15-
}
16-
}
1+
{}

0 commit comments

Comments
 (0)