Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -4073,6 +4073,40 @@ func (m *MapLiteral) Accept(visitor ASTVisitor) error {
return visitor.VisitMapLiteral(m)
}

type NamedParameterExpr struct {
NamePos Pos
Name *Ident
Value Expr
}

func (n *NamedParameterExpr) Pos() Pos {
return n.NamePos
}

func (n *NamedParameterExpr) End() Pos {
return n.Value.End()
}

func (n *NamedParameterExpr) String() string {
var builder strings.Builder
builder.WriteString(n.Name.String())
builder.WriteByte('=')
builder.WriteString(n.Value.String())
return builder.String()
}

func (n *NamedParameterExpr) Accept(visitor ASTVisitor) error {
visitor.Enter(n)
defer visitor.Leave(n)
if err := n.Name.Accept(visitor); err != nil {
return err
}
if err := n.Value.Accept(visitor); err != nil {
return err
}
return visitor.VisitNamedParameterExpr(n)
}

type QueryParam struct {
LBracePos Pos
RBracePos Pos
Expand Down
8 changes: 8 additions & 0 deletions parser/ast_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type ASTVisitor interface {
VisitSettingsExprList(expr *SettingsClause) error
VisitParamExprList(expr *ParamExprList) error
VisitMapLiteral(expr *MapLiteral) error
VisitNamedParameterExpr(expr *NamedParameterExpr) error
VisitArrayParamList(expr *ArrayParamList) error
VisitQueryParam(expr *QueryParam) error
VisitObjectParams(expr *ObjectParams) error
Expand Down Expand Up @@ -813,6 +814,13 @@ func (v *DefaultASTVisitor) VisitMapLiteral(expr *MapLiteral) error {
return nil
}

func (v *DefaultASTVisitor) VisitNamedParameterExpr(expr *NamedParameterExpr) error {
if v.Visit != nil {
return v.Visit(expr)
}
return nil
}

func (v *DefaultASTVisitor) VisitObjectParams(expr *ObjectParams) error {
if v.Visit != nil {
return v.Visit(expr)
Expand Down
47 changes: 46 additions & 1 deletion parser/parser_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,52 @@ func (p *Parser) parseTableArgList(pos Pos) (*TableArgListExpr, error) {

args := make([]Expr, 0)
for !p.lexer.isEOF() {
arg, err := p.parseTableArgExpr(p.Pos())
// Check if this is a named parameter (identifier followed by =)
var arg Expr
var err error

// Try to detect named parameter pattern: last token is identifier, next token is =
isNamedParam := false
lastKind := p.lastTokenKind()
if lastKind == TokenKindIdent || lastKind == TokenKindKeyword {
// Last token is an identifier, peek at the next token
nextToken, peekErr := p.lexer.peekToken()

if peekErr == nil && nextToken != nil && nextToken.Kind == TokenKindSingleEQ {
isNamedParam = true
}
}

if isNamedParam {
// Parse as named parameter - the identifier is already the last token
// We need to get it, consume the =, and parse the value
name := &Ident{
NamePos: p.last().Pos,
NameEnd: p.last().End,
Name: p.last().String,
}
// Consume the = token
if err := p.lexer.consumeToken(); err != nil {
return nil, err
}
if err := p.expectTokenKind(TokenKindSingleEQ); err != nil {
return nil, err
}
// Parse the value
value, err := p.parseTableArgExpr(p.Pos())
if err != nil {
return nil, err
}
arg = &NamedParameterExpr{
NamePos: name.NamePos,
Name: name,
Value: value,
}
} else {
// Parse as regular table arg expression
arg, err = p.parseTableArgExpr(p.Pos())
}

if err != nil {
return nil, err
}
Expand Down
18 changes: 9 additions & 9 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,15 @@ func TestParser_InvalidSyntax(t *testing.T) {
invalidSQLs := []string{
"SELECT * FROM",
// WITH FILL error cases
"SELECT n FROM t ORDER BY n WITH", // WITH without FILL
"SELECT n FROM t ORDER BY n FILL", // FILL without WITH
"SELECT n FROM t ORDER BY n WITH FILL FROM", // FROM without value
"SELECT n FROM t ORDER BY n WITH FILL TO", // TO without value
"SELECT n FROM t ORDER BY n WITH FILL STEP", // STEP without value
"SELECT n FROM t ORDER BY n WITH FILL STALENESS", // STALENESS without value
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE (x", // Missing closing paren
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE x AS x + 1", // Missing parens around column list
"ALTER TABLE foo_mv MODIFY QUERY AS SELECT * FROM baz", // MODIFY QUERY followed by an invalid query
"SELECT n FROM t ORDER BY n WITH", // WITH without FILL
"SELECT n FROM t ORDER BY n FILL", // FILL without WITH
"SELECT n FROM t ORDER BY n WITH FILL FROM", // FROM without value
"SELECT n FROM t ORDER BY n WITH FILL TO", // TO without value
"SELECT n FROM t ORDER BY n WITH FILL STEP", // STEP without value
"SELECT n FROM t ORDER BY n WITH FILL STALENESS", // STALENESS without value
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE (x", // Missing closing paren
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE x AS x + 1", // Missing parens around column list
"ALTER TABLE foo_mv MODIFY QUERY AS SELECT * FROM baz", // MODIFY QUERY followed by an invalid query
}
for _, sql := range invalidSQLs {
parser := NewParser(sql)
Expand Down
3 changes: 3 additions & 0 deletions parser/testdata/ddl/create_materialized_view_with_gcs.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE MATERIALIZED VIEW database_name.view_name
REFRESH EVERY 5 MINUTE TO database_name.table_name AS
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Origin SQL:
CREATE MATERIALIZED VIEW database_name.view_name
REFRESH EVERY 5 MINUTE TO database_name.table_name AS
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');

-- Format SQL:
CREATE MATERIALIZED VIEW database_name.view_name REFRESH EVERY 5 MINUTE TO database_name.table_name AS SELECT * FROM gcs(gcs_creds, url='https://storage.googleapis.com/some-bucket/some-path/');
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
[
{
"CreatePos": 0,
"StatementEnd": 206,
"Name": {
"Database": {
"Name": "database_name",
"QuoteType": 1,
"NamePos": 25,
"NameEnd": 38
},
"Table": {
"Name": "view_name",
"QuoteType": 1,
"NamePos": 39,
"NameEnd": 48
}
},
"IfNotExists": false,
"OnCluster": null,
"Refresh": {
"RefreshPos": 57,
"Frequency": "EVERY",
"Interval": {
"IntervalPos": 0,
"Expr": {
"NumPos": 71,
"NumEnd": 72,
"Literal": "5",
"Base": 10
},
"Unit": {
"Name": "MINUTE",
"QuoteType": 1,
"NamePos": 73,
"NameEnd": 79
}
},
"Offset": null
},
"RandomizeFor": null,
"DependsOn": null,
"Settings": null,
"HasAppend": false,
"Engine": null,
"HasEmpty": false,
"Destination": {
"ToPos": 80,
"TableIdentifier": {
"Database": {
"Name": "database_name",
"QuoteType": 1,
"NamePos": 83,
"NameEnd": 96
},
"Table": {
"Name": "table_name",
"QuoteType": 1,
"NamePos": 97,
"NameEnd": 107
}
},
"TableSchema": null
},
"SubQuery": {
"HasParen": false,
"Select": {
"SelectPos": 119,
"StatementEnd": 206,
"With": null,
"Top": null,
"HasDistinct": false,
"DistinctOn": null,
"SelectItems": [
{
"Expr": {
"Name": "*",
"QuoteType": 0,
"NamePos": 126,
"NameEnd": 126
},
"Modifiers": [],
"Alias": null
}
],
"From": {
"FromPos": 128,
"Expr": {
"Table": {
"TablePos": 133,
"TableEnd": 206,
"Alias": null,
"Expr": {
"Name": {
"Name": "gcs",
"QuoteType": 1,
"NamePos": 133,
"NameEnd": 136
},
"Args": {
"LeftParenPos": 136,
"RightParenPos": 206,
"Args": [
{
"Name": "gcs_creds",
"QuoteType": 1,
"NamePos": 137,
"NameEnd": 146
},
{
"NamePos": 147,
"Name": {
"Name": "url",
"QuoteType": 0,
"NamePos": 147,
"NameEnd": 150
},
"Value": {
"LiteralPos": 152,
"LiteralEnd": 205,
"Literal": "https://storage.googleapis.com/some-bucket/some-path/"
}
}
]
}
},
"HasFinal": false
},
"StatementEnd": 206,
"SampleRatio": null,
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
"GroupBy": null,
"WithTotal": false,
"Having": null,
"OrderBy": null,
"LimitBy": null,
"Limit": null,
"Settings": null,
"Format": null,
"UnionAll": null,
"UnionDistinct": null,
"Except": null
}
},
"Populate": false,
"Comment": null,
"Definer": null,
"SQLSecurity": ""
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');
7 changes: 7 additions & 0 deletions parser/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,13 @@ func Walk(node Expr, fn WalkFunc) bool {
return false
}
}
case *NamedParameterExpr:
if !Walk(n.Name, fn) {
return false
}
if !Walk(n.Value, fn) {
return false
}
case *ObjectParams:
if !Walk(n.Object, fn) {
return false
Expand Down