Skip to content

Commit 699e78f

Browse files
authored
Fix refreshable View with named parameters (#217)
* Removing unwanted code Signed-off-by: Sharad Gaur <[email protected]> * Adding to walk.go Signed-off-by: Sharad Gaur <[email protected]> --------- Signed-off-by: Sharad Gaur <[email protected]>
1 parent 3f5e89d commit 699e78f

File tree

9 files changed

+271
-10
lines changed

9 files changed

+271
-10
lines changed

parser/ast.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,6 +4073,40 @@ func (m *MapLiteral) Accept(visitor ASTVisitor) error {
40734073
return visitor.VisitMapLiteral(m)
40744074
}
40754075

4076+
type NamedParameterExpr struct {
4077+
NamePos Pos
4078+
Name *Ident
4079+
Value Expr
4080+
}
4081+
4082+
func (n *NamedParameterExpr) Pos() Pos {
4083+
return n.NamePos
4084+
}
4085+
4086+
func (n *NamedParameterExpr) End() Pos {
4087+
return n.Value.End()
4088+
}
4089+
4090+
func (n *NamedParameterExpr) String() string {
4091+
var builder strings.Builder
4092+
builder.WriteString(n.Name.String())
4093+
builder.WriteByte('=')
4094+
builder.WriteString(n.Value.String())
4095+
return builder.String()
4096+
}
4097+
4098+
func (n *NamedParameterExpr) Accept(visitor ASTVisitor) error {
4099+
visitor.Enter(n)
4100+
defer visitor.Leave(n)
4101+
if err := n.Name.Accept(visitor); err != nil {
4102+
return err
4103+
}
4104+
if err := n.Value.Accept(visitor); err != nil {
4105+
return err
4106+
}
4107+
return visitor.VisitNamedParameterExpr(n)
4108+
}
4109+
40764110
type QueryParam struct {
40774111
LBracePos Pos
40784112
RBracePos Pos

parser/ast_visitor.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type ASTVisitor interface {
8585
VisitSettingsExprList(expr *SettingsClause) error
8686
VisitParamExprList(expr *ParamExprList) error
8787
VisitMapLiteral(expr *MapLiteral) error
88+
VisitNamedParameterExpr(expr *NamedParameterExpr) error
8889
VisitArrayParamList(expr *ArrayParamList) error
8990
VisitQueryParam(expr *QueryParam) error
9091
VisitObjectParams(expr *ObjectParams) error
@@ -813,6 +814,13 @@ func (v *DefaultASTVisitor) VisitMapLiteral(expr *MapLiteral) error {
813814
return nil
814815
}
815816

817+
func (v *DefaultASTVisitor) VisitNamedParameterExpr(expr *NamedParameterExpr) error {
818+
if v.Visit != nil {
819+
return v.Visit(expr)
820+
}
821+
return nil
822+
}
823+
816824
func (v *DefaultASTVisitor) VisitObjectParams(expr *ObjectParams) error {
817825
if v.Visit != nil {
818826
return v.Visit(expr)

parser/parser_table.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,52 @@ func (p *Parser) parseTableArgList(pos Pos) (*TableArgListExpr, error) {
649649

650650
args := make([]Expr, 0)
651651
for !p.lexer.isEOF() {
652-
arg, err := p.parseTableArgExpr(p.Pos())
652+
// Check if this is a named parameter (identifier followed by =)
653+
var arg Expr
654+
var err error
655+
656+
// Try to detect named parameter pattern: last token is identifier, next token is =
657+
isNamedParam := false
658+
lastKind := p.lastTokenKind()
659+
if lastKind == TokenKindIdent || lastKind == TokenKindKeyword {
660+
// Last token is an identifier, peek at the next token
661+
nextToken, peekErr := p.lexer.peekToken()
662+
663+
if peekErr == nil && nextToken != nil && nextToken.Kind == TokenKindSingleEQ {
664+
isNamedParam = true
665+
}
666+
}
667+
668+
if isNamedParam {
669+
// Parse as named parameter - the identifier is already the last token
670+
// We need to get it, consume the =, and parse the value
671+
name := &Ident{
672+
NamePos: p.last().Pos,
673+
NameEnd: p.last().End,
674+
Name: p.last().String,
675+
}
676+
// Consume the = token
677+
if err := p.lexer.consumeToken(); err != nil {
678+
return nil, err
679+
}
680+
if err := p.expectTokenKind(TokenKindSingleEQ); err != nil {
681+
return nil, err
682+
}
683+
// Parse the value
684+
value, err := p.parseTableArgExpr(p.Pos())
685+
if err != nil {
686+
return nil, err
687+
}
688+
arg = &NamedParameterExpr{
689+
NamePos: name.NamePos,
690+
Name: name,
691+
Value: value,
692+
}
693+
} else {
694+
// Parse as regular table arg expression
695+
arg, err = p.parseTableArgExpr(p.Pos())
696+
}
697+
653698
if err != nil {
654699
return nil, err
655700
}

parser/parser_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,15 @@ func TestParser_InvalidSyntax(t *testing.T) {
132132
invalidSQLs := []string{
133133
"SELECT * FROM",
134134
// WITH FILL error cases
135-
"SELECT n FROM t ORDER BY n WITH", // WITH without FILL
136-
"SELECT n FROM t ORDER BY n FILL", // FILL without WITH
137-
"SELECT n FROM t ORDER BY n WITH FILL FROM", // FROM without value
138-
"SELECT n FROM t ORDER BY n WITH FILL TO", // TO without value
139-
"SELECT n FROM t ORDER BY n WITH FILL STEP", // STEP without value
140-
"SELECT n FROM t ORDER BY n WITH FILL STALENESS", // STALENESS without value
141-
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE (x", // Missing closing paren
142-
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE x AS x + 1", // Missing parens around column list
143-
"ALTER TABLE foo_mv MODIFY QUERY AS SELECT * FROM baz", // MODIFY QUERY followed by an invalid query
135+
"SELECT n FROM t ORDER BY n WITH", // WITH without FILL
136+
"SELECT n FROM t ORDER BY n FILL", // FILL without WITH
137+
"SELECT n FROM t ORDER BY n WITH FILL FROM", // FROM without value
138+
"SELECT n FROM t ORDER BY n WITH FILL TO", // TO without value
139+
"SELECT n FROM t ORDER BY n WITH FILL STEP", // STEP without value
140+
"SELECT n FROM t ORDER BY n WITH FILL STALENESS", // STALENESS without value
141+
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE (x", // Missing closing paren
142+
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE x AS x + 1", // Missing parens around column list
143+
"ALTER TABLE foo_mv MODIFY QUERY AS SELECT * FROM baz", // MODIFY QUERY followed by an invalid query
144144
}
145145
for _, sql := range invalidSQLs {
146146
parser := NewParser(sql)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CREATE MATERIALIZED VIEW database_name.view_name
2+
REFRESH EVERY 5 MINUTE TO database_name.table_name AS
3+
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Origin SQL:
2+
CREATE MATERIALIZED VIEW database_name.view_name
3+
REFRESH EVERY 5 MINUTE TO database_name.table_name AS
4+
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');
5+
6+
-- Format SQL:
7+
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/');
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
[
2+
{
3+
"CreatePos": 0,
4+
"StatementEnd": 206,
5+
"Name": {
6+
"Database": {
7+
"Name": "database_name",
8+
"QuoteType": 1,
9+
"NamePos": 25,
10+
"NameEnd": 38
11+
},
12+
"Table": {
13+
"Name": "view_name",
14+
"QuoteType": 1,
15+
"NamePos": 39,
16+
"NameEnd": 48
17+
}
18+
},
19+
"IfNotExists": false,
20+
"OnCluster": null,
21+
"Refresh": {
22+
"RefreshPos": 57,
23+
"Frequency": "EVERY",
24+
"Interval": {
25+
"IntervalPos": 0,
26+
"Expr": {
27+
"NumPos": 71,
28+
"NumEnd": 72,
29+
"Literal": "5",
30+
"Base": 10
31+
},
32+
"Unit": {
33+
"Name": "MINUTE",
34+
"QuoteType": 1,
35+
"NamePos": 73,
36+
"NameEnd": 79
37+
}
38+
},
39+
"Offset": null
40+
},
41+
"RandomizeFor": null,
42+
"DependsOn": null,
43+
"Settings": null,
44+
"HasAppend": false,
45+
"Engine": null,
46+
"HasEmpty": false,
47+
"Destination": {
48+
"ToPos": 80,
49+
"TableIdentifier": {
50+
"Database": {
51+
"Name": "database_name",
52+
"QuoteType": 1,
53+
"NamePos": 83,
54+
"NameEnd": 96
55+
},
56+
"Table": {
57+
"Name": "table_name",
58+
"QuoteType": 1,
59+
"NamePos": 97,
60+
"NameEnd": 107
61+
}
62+
},
63+
"TableSchema": null
64+
},
65+
"SubQuery": {
66+
"HasParen": false,
67+
"Select": {
68+
"SelectPos": 119,
69+
"StatementEnd": 206,
70+
"With": null,
71+
"Top": null,
72+
"HasDistinct": false,
73+
"DistinctOn": null,
74+
"SelectItems": [
75+
{
76+
"Expr": {
77+
"Name": "*",
78+
"QuoteType": 0,
79+
"NamePos": 126,
80+
"NameEnd": 126
81+
},
82+
"Modifiers": [],
83+
"Alias": null
84+
}
85+
],
86+
"From": {
87+
"FromPos": 128,
88+
"Expr": {
89+
"Table": {
90+
"TablePos": 133,
91+
"TableEnd": 206,
92+
"Alias": null,
93+
"Expr": {
94+
"Name": {
95+
"Name": "gcs",
96+
"QuoteType": 1,
97+
"NamePos": 133,
98+
"NameEnd": 136
99+
},
100+
"Args": {
101+
"LeftParenPos": 136,
102+
"RightParenPos": 206,
103+
"Args": [
104+
{
105+
"Name": "gcs_creds",
106+
"QuoteType": 1,
107+
"NamePos": 137,
108+
"NameEnd": 146
109+
},
110+
{
111+
"NamePos": 147,
112+
"Name": {
113+
"Name": "url",
114+
"QuoteType": 0,
115+
"NamePos": 147,
116+
"NameEnd": 150
117+
},
118+
"Value": {
119+
"LiteralPos": 152,
120+
"LiteralEnd": 205,
121+
"Literal": "https://storage.googleapis.com/some-bucket/some-path/"
122+
}
123+
}
124+
]
125+
}
126+
},
127+
"HasFinal": false
128+
},
129+
"StatementEnd": 206,
130+
"SampleRatio": null,
131+
"HasFinal": false
132+
}
133+
},
134+
"ArrayJoin": null,
135+
"Window": null,
136+
"Prewhere": null,
137+
"Where": null,
138+
"GroupBy": null,
139+
"WithTotal": false,
140+
"Having": null,
141+
"OrderBy": null,
142+
"LimitBy": null,
143+
"Limit": null,
144+
"Settings": null,
145+
"Format": null,
146+
"UnionAll": null,
147+
"UnionDistinct": null,
148+
"Except": null
149+
}
150+
},
151+
"Populate": false,
152+
"Comment": null,
153+
"Definer": null,
154+
"SQLSecurity": ""
155+
}
156+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SELECT * FROM gcs(gcs_creds,url='https://storage.googleapis.com/some-bucket/some-path/');

parser/walk.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,13 @@ func Walk(node Expr, fn WalkFunc) bool {
13191319
return false
13201320
}
13211321
}
1322+
case *NamedParameterExpr:
1323+
if !Walk(n.Name, fn) {
1324+
return false
1325+
}
1326+
if !Walk(n.Value, fn) {
1327+
return false
1328+
}
13221329
case *ObjectParams:
13231330
if !Walk(n.Object, fn) {
13241331
return false

0 commit comments

Comments
 (0)