@@ -83,12 +83,13 @@ func (p *Parser) parseSelectStatement() (*ast.SelectStatement, error) {
8383 stmt := & ast.SelectStatement {}
8484
8585 // Parse query expression (handles UNION, parens, etc.)
86- qe , into , err := p .parseQueryExpressionWithInto ()
86+ qe , into , on , err := p .parseQueryExpressionWithInto ()
8787 if err != nil {
8888 return nil , err
8989 }
9090 stmt .QueryExpression = qe
9191 stmt .Into = into
92+ stmt .On = on
9293
9394 // Parse optional OPTION clause
9495 if p .curTok .Type == TokenOption {
@@ -108,15 +109,15 @@ func (p *Parser) parseSelectStatement() (*ast.SelectStatement, error) {
108109}
109110
110111func (p * Parser ) parseQueryExpression () (ast.QueryExpression , error ) {
111- qe , _ , err := p .parseQueryExpressionWithInto ()
112+ qe , _ , _ , err := p .parseQueryExpressionWithInto ()
112113 return qe , err
113114}
114115
115- func (p * Parser ) parseQueryExpressionWithInto () (ast.QueryExpression , * ast.SchemaObjectName , error ) {
116+ func (p * Parser ) parseQueryExpressionWithInto () (ast.QueryExpression , * ast.SchemaObjectName , * ast. Identifier , error ) {
116117 // Parse primary query expression (could be SELECT or parenthesized)
117- left , into , err := p .parsePrimaryQueryExpression ()
118+ left , into , on , err := p .parsePrimaryQueryExpression ()
118119 if err != nil {
119- return nil , nil , err
120+ return nil , nil , nil , err
120121 }
121122
122123 // Track if we have any binary operations
@@ -144,14 +145,15 @@ func (p *Parser) parseQueryExpressionWithInto() (ast.QueryExpression, *ast.Schem
144145 }
145146
146147 // Parse the right side
147- right , rightInto , err := p .parsePrimaryQueryExpression ()
148+ right , rightInto , rightOn , err := p .parsePrimaryQueryExpression ()
148149 if err != nil {
149- return nil , nil , err
150+ return nil , nil , nil , err
150151 }
151152
152153 // INTO can only appear in the first query of a UNION
153154 if rightInto != nil && into == nil {
154155 into = rightInto
156+ on = rightOn
155157 }
156158
157159 bqe := & ast.BinaryQueryExpression {
@@ -168,7 +170,7 @@ func (p *Parser) parseQueryExpressionWithInto() (ast.QueryExpression, *ast.Schem
168170 if p .curTok .Type == TokenOrder {
169171 obc , err := p .parseOrderByClause ()
170172 if err != nil {
171- return nil , nil , err
173+ return nil , nil , nil , err
172174 }
173175
174176 if hasBinaryOp {
@@ -184,47 +186,53 @@ func (p *Parser) parseQueryExpressionWithInto() (ast.QueryExpression, *ast.Schem
184186 }
185187 }
186188
187- return left , into , nil
189+ return left , into , on , nil
188190}
189191
190- func (p * Parser ) parsePrimaryQueryExpression () (ast.QueryExpression , * ast.SchemaObjectName , error ) {
192+ func (p * Parser ) parsePrimaryQueryExpression () (ast.QueryExpression , * ast.SchemaObjectName , * ast. Identifier , error ) {
191193 if p .curTok .Type == TokenLParen {
192194 p .nextToken () // consume (
193- qe , into , err := p .parseQueryExpressionWithInto ()
195+ qe , into , on , err := p .parseQueryExpressionWithInto ()
194196 if err != nil {
195- return nil , nil , err
197+ return nil , nil , nil , err
196198 }
197199 if p .curTok .Type != TokenRParen {
198- return nil , nil , fmt .Errorf ("expected ), got %s" , p .curTok .Literal )
200+ return nil , nil , nil , fmt .Errorf ("expected ), got %s" , p .curTok .Literal )
199201 }
200202 p .nextToken () // consume )
201- return & ast.QueryParenthesisExpression {QueryExpression : qe }, into , nil
203+ return & ast.QueryParenthesisExpression {QueryExpression : qe }, into , on , nil
202204 }
203205
204206 return p .parseQuerySpecificationWithInto ()
205207}
206208
207- func (p * Parser ) parseQuerySpecificationWithInto () (* ast.QuerySpecification , * ast.SchemaObjectName , error ) {
209+ func (p * Parser ) parseQuerySpecificationWithInto () (* ast.QuerySpecification , * ast.SchemaObjectName , * ast. Identifier , error ) {
208210 qs , err := p .parseQuerySpecificationCore ()
209211 if err != nil {
210- return nil , nil , err
212+ return nil , nil , nil , err
211213 }
212214
213215 // Check for INTO clause after SELECT elements, before FROM
214216 var into * ast.SchemaObjectName
217+ var on * ast.Identifier
215218 if p .curTok .Type == TokenInto {
216219 p .nextToken () // consume INTO
217220 into , err = p .parseSchemaObjectName ()
218221 if err != nil {
219- return nil , nil , err
222+ return nil , nil , nil , err
223+ }
224+ // Check for ON filegroup clause
225+ if strings .ToUpper (p .curTok .Literal ) == "ON" {
226+ p .nextToken () // consume ON
227+ on = p .parseIdentifier ()
220228 }
221229 }
222230
223231 // Parse optional FROM clause
224232 if p .curTok .Type == TokenFrom {
225233 fromClause , err := p .parseFromClause ()
226234 if err != nil {
227- return nil , nil , err
235+ return nil , nil , nil , err
228236 }
229237 qs .FromClause = fromClause
230238 }
@@ -233,7 +241,7 @@ func (p *Parser) parseQuerySpecificationWithInto() (*ast.QuerySpecification, *as
233241 if p .curTok .Type == TokenWhere {
234242 whereClause , err := p .parseWhereClause ()
235243 if err != nil {
236- return nil , nil , err
244+ return nil , nil , nil , err
237245 }
238246 qs .WhereClause = whereClause
239247 }
@@ -242,7 +250,7 @@ func (p *Parser) parseQuerySpecificationWithInto() (*ast.QuerySpecification, *as
242250 if p .curTok .Type == TokenGroup {
243251 groupByClause , err := p .parseGroupByClause ()
244252 if err != nil {
245- return nil , nil , err
253+ return nil , nil , nil , err
246254 }
247255 qs .GroupByClause = groupByClause
248256 }
@@ -251,15 +259,15 @@ func (p *Parser) parseQuerySpecificationWithInto() (*ast.QuerySpecification, *as
251259 if p .curTok .Type == TokenHaving {
252260 havingClause , err := p .parseHavingClause ()
253261 if err != nil {
254- return nil , nil , err
262+ return nil , nil , nil , err
255263 }
256264 qs .HavingClause = havingClause
257265 }
258266
259267 // Note: ORDER BY is parsed at the top level in parseQueryExpressionWithInto
260268 // to correctly handle UNION/EXCEPT/INTERSECT cases
261269
262- return qs , into , nil
270+ return qs , into , on , nil
263271}
264272
265273func (p * Parser ) parseQuerySpecificationCore () (* ast.QuerySpecification , error ) {
0 commit comments