@@ -23,8 +23,8 @@ use crate::ast::helpers::stmt_data_loading::{
23
23
FileStagingCommand , StageLoadSelectItem , StageLoadSelectItemKind , StageParamsObject ,
24
24
} ;
25
25
use crate :: ast:: {
26
- ColumnOption , ColumnPolicy , ColumnPolicyProperty , CopyIntoSnowflakeKind , Ident ,
27
- IdentityParameters , IdentityProperty , IdentityPropertyFormatKind , IdentityPropertyKind ,
26
+ ColumnOption , ColumnPolicy , ColumnPolicyProperty , CopyIntoSnowflakeKind , DollarQuotedString ,
27
+ Ident , IdentityParameters , IdentityProperty , IdentityPropertyFormatKind , IdentityPropertyKind ,
28
28
IdentityPropertyOrder , ObjectName , ObjectNamePart , RowAccessPolicy , ShowObjects , SqlOption ,
29
29
Statement , TagsColumnOption , WrappedCollection ,
30
30
} ;
@@ -307,22 +307,22 @@ impl Dialect for SnowflakeDialect {
307
307
// they are not followed by other tokens that may change their meaning
308
308
// e.g. `SELECT * EXCEPT (col1) FROM tbl`
309
309
Keyword :: EXCEPT
310
- // e.g. `SELECT 1 LIMIT 5`
311
- | Keyword :: LIMIT
312
- // e.g. `SELECT 1 OFFSET 5 ROWS`
313
- | Keyword :: OFFSET
314
310
// e.g. `INSERT INTO t SELECT 1 RETURNING *`
315
311
| Keyword :: RETURNING if !matches ! ( parser. peek_token_ref( ) . token, Token :: Comma | Token :: EOF ) =>
316
312
{
317
313
false
318
314
}
319
315
316
+ // e.g. `SELECT 1 LIMIT 5` - not an alias
317
+ // e.g. `SELECT 1 OFFSET 5 ROWS` - not an alias
318
+ Keyword :: LIMIT | Keyword :: OFFSET if peek_for_limit_options ( parser) => false ,
319
+
320
320
// `FETCH` can be considered an alias as long as it's not followed by `FIRST`` or `NEXT`
321
321
// which would give it a different meanings, for example:
322
322
// `SELECT 1 FETCH FIRST 10 ROWS` - not an alias
323
323
// `SELECT 1 FETCH 10` - not an alias
324
324
Keyword :: FETCH if parser. peek_one_of_keywords ( & [ Keyword :: FIRST , Keyword :: NEXT ] ) . is_some ( )
325
- || matches ! ( parser. peek_token ( ) . token , Token :: Number ( _ , _ ) ) =>
325
+ || peek_for_limit_options ( parser) =>
326
326
{
327
327
false
328
328
}
@@ -351,20 +351,23 @@ impl Dialect for SnowflakeDialect {
351
351
match kw {
352
352
// The following keywords can be considered an alias as long as
353
353
// they are not followed by other tokens that may change their meaning
354
- Keyword :: LIMIT
355
- | Keyword :: RETURNING
354
+ Keyword :: RETURNING
356
355
| Keyword :: INNER
357
356
| Keyword :: USING
358
357
| Keyword :: PIVOT
359
358
| Keyword :: UNPIVOT
360
359
| Keyword :: EXCEPT
361
360
| Keyword :: MATCH_RECOGNIZE
362
- | Keyword :: OFFSET
363
361
if !matches ! ( parser. peek_token_ref( ) . token, Token :: SemiColon | Token :: EOF ) =>
364
362
{
365
363
false
366
364
}
367
365
366
+ // `LIMIT` can be considered an alias as long as it's not followed by a value. For example:
367
+ // `SELECT * FROM tbl LIMIT WHERE 1=1` - alias
368
+ // `SELECT * FROM tbl LIMIT 3` - not an alias
369
+ Keyword :: LIMIT | Keyword :: OFFSET if peek_for_limit_options ( parser) => false ,
370
+
368
371
// `FETCH` can be considered an alias as long as it's not followed by `FIRST`` or `NEXT`
369
372
// which would give it a different meanings, for example:
370
373
// `SELECT * FROM tbl FETCH FIRST 10 ROWS` - not an alias
@@ -373,7 +376,7 @@ impl Dialect for SnowflakeDialect {
373
376
if parser
374
377
. peek_one_of_keywords ( & [ Keyword :: FIRST , Keyword :: NEXT ] )
375
378
. is_some ( )
376
- || matches ! ( parser. peek_token ( ) . token , Token :: Number ( _ , _ ) ) =>
379
+ || peek_for_limit_options ( parser) =>
377
380
{
378
381
false
379
382
}
@@ -387,6 +390,7 @@ impl Dialect for SnowflakeDialect {
387
390
{
388
391
false
389
392
}
393
+
390
394
Keyword :: GLOBAL if parser. peek_keyword ( Keyword :: FULL ) => false ,
391
395
392
396
// Reserved keywords by the Snowflake dialect, which seem to be less strictive
@@ -472,6 +476,18 @@ impl Dialect for SnowflakeDialect {
472
476
}
473
477
}
474
478
479
+ // Peeks ahead to identify tokens that are expected after
480
+ // a LIMIT/FETCH keyword.
481
+ fn peek_for_limit_options ( parser : & Parser ) -> bool {
482
+ match & parser. peek_token_ref ( ) . token {
483
+ Token :: Number ( _, _) | Token :: Placeholder ( _) => true ,
484
+ Token :: SingleQuotedString ( val) if val. is_empty ( ) => true ,
485
+ Token :: DollarQuotedString ( DollarQuotedString { value, .. } ) if value. is_empty ( ) => true ,
486
+ Token :: Word ( w) if w. keyword == Keyword :: NULL => true ,
487
+ _ => false ,
488
+ }
489
+ }
490
+
475
491
fn parse_file_staging_command ( kw : Keyword , parser : & mut Parser ) -> Result < Statement , ParserError > {
476
492
let stage = parse_snowflake_stage_name ( parser) ?;
477
493
let pattern = if parser. parse_keyword ( Keyword :: PATTERN ) {
0 commit comments