@@ -23,6 +23,7 @@ import (
2323
2424 "github.com/ajitpratap0/GoSQLX/pkg/models"
2525 "github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
26+ "github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
2627)
2728
2829// SUM(salary) OVER (PARTITION BY dept ORDER BY date ROWS UNBOUNDED PRECEDING) -> window function with frame
@@ -153,6 +154,36 @@ func (p *Parser) parseFunctionCall(funcName string) (*ast.FunctionCall, error) {
153154 OrderBy : orderByExprs ,
154155 }
155156
157+ // ClickHouse parametric aggregates: funcName(params)(args).
158+ // e.g. quantileTDigest(0.95)(value), topK(10)(name).
159+ // What we just parsed becomes Parameters; the next paren group is the
160+ // real arguments. Gated to ClickHouse to avoid false positives.
161+ if p .dialect == string (keywords .DialectClickHouse ) && p .isType (models .TokenTypeLParen ) {
162+ funcCall .Parameters = funcCall .Arguments
163+ funcCall .Arguments = nil
164+ p .advance () // Consume second (
165+ if ! p .isType (models .TokenTypeRParen ) {
166+ for {
167+ arg , err := p .parseExpression ()
168+ if err != nil {
169+ return nil , err
170+ }
171+ funcCall .Arguments = append (funcCall .Arguments , arg )
172+ if p .isType (models .TokenTypeComma ) {
173+ p .advance ()
174+ } else if p .isType (models .TokenTypeRParen ) {
175+ break
176+ } else {
177+ return nil , p .expectedError (", or )" )
178+ }
179+ }
180+ }
181+ if ! p .isType (models .TokenTypeRParen ) {
182+ return nil , p .expectedError (")" )
183+ }
184+ p .advance () // Consume second )
185+ }
186+
156187 // Check for WITHIN GROUP clause (SQL:2003 ordered-set aggregates)
157188 // Syntax: WITHIN GROUP (ORDER BY expression [ASC|DESC] [NULLS FIRST|LAST])
158189 // Used with: PERCENTILE_CONT, PERCENTILE_DISC, MODE, LISTAGG, etc.
0 commit comments