@@ -30,7 +30,7 @@ use crate::ast::{
30
30
use crate :: dialect:: { Dialect , Precedence } ;
31
31
use crate :: keywords:: Keyword ;
32
32
use crate :: parser:: { Parser , ParserError } ;
33
- use crate :: tokenizer:: Token ;
33
+ use crate :: tokenizer:: { Token , Word } ;
34
34
#[ cfg( not( feature = "std" ) ) ]
35
35
use alloc:: string:: String ;
36
36
#[ cfg( not( feature = "std" ) ) ]
@@ -611,7 +611,82 @@ pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, Par
611
611
}
612
612
}
613
613
614
+ /// Parses a `COPY INTO` statement. Snowflake has two variants, `COPY INTO <table>`
615
+ /// and `COPY INTO <location>` which have different syntax.
614
616
pub fn parse_copy_into ( parser : & mut Parser ) -> Result < Statement , ParserError > {
617
+ if is_copy_into_location ( parser) {
618
+ parse_copy_into_location ( parser)
619
+ } else {
620
+ parse_copy_into_table ( parser)
621
+ }
622
+ }
623
+
624
+ /// Returns true if the `COPY INTO` statement is a `COPY INTO <location>`
625
+ /// by peeking at the prefix of the target's object name and trying to
626
+ /// determine if it's a Snowflake stage or a table.
627
+ fn is_copy_into_location ( parser : & mut Parser ) -> bool {
628
+ match parser. peek_token ( ) . token {
629
+ // Indicates an internal stage
630
+ Token :: AtSign => true ,
631
+ // Indicates an external stage, i.e. s3://, gcs:// or azure://
632
+ Token :: SingleQuotedString ( s) if s. contains ( "://" ) => true ,
633
+ _ => false ,
634
+ }
635
+ }
636
+
637
+ fn parse_copy_into_location ( parser : & mut Parser ) -> Result < Statement , ParserError > {
638
+ let into: ObjectName = parse_snowflake_stage_name ( parser) ?;
639
+ parser. expect_keyword_is ( Keyword :: FROM ) ?;
640
+ // Two options: `FROM (query)` or `FROM <table>`
641
+ let ( from_table, from_query) = match parser. next_token ( ) . token {
642
+ Token :: LParen => {
643
+ let query = parser. parse_query ( ) ?;
644
+ parser. expect_token ( & Token :: RParen ) ?;
645
+ ( None , Some ( query) )
646
+ }
647
+ _ => {
648
+ parser. prev_token ( ) ;
649
+ let table = parser. parse_object_name ( true ) ?;
650
+ ( Some ( table) , None )
651
+ }
652
+ } ;
653
+ let stage_params = parse_stage_params ( parser) ?;
654
+
655
+ // The order of the next options is not defined, so we need to loop
656
+ // until we reach the end of the statement
657
+ let mut partition = None ;
658
+ let mut file_format = Vec :: new ( ) ;
659
+ let mut options: Vec < DataLoadingOption > = Vec :: new ( ) ;
660
+ loop {
661
+ if parser. parse_keyword ( Keyword :: FILE_FORMAT ) {
662
+ parser. expect_token ( & Token :: Eq ) ?;
663
+ file_format = parse_parentheses_options ( parser) ?;
664
+ } else if parser. parse_keywords ( & [ Keyword :: PARTITION , Keyword :: BY ] ) {
665
+ partition = Some ( parser. parse_expr ( ) ?)
666
+ } else {
667
+ match parser. next_token ( ) . token {
668
+ Token :: SemiColon | Token :: EOF => break ,
669
+ Token :: Comma => continue ,
670
+ Token :: Word ( key) => options. push ( parse_copy_option ( parser, key) ?) ,
671
+ _ => return parser. expected ( "another option, ; or EOF'" , parser. peek_token ( ) ) ,
672
+ }
673
+ }
674
+ }
675
+
676
+ Ok ( Statement :: CopyIntoSnowflakeLocation {
677
+ into,
678
+ from_table,
679
+ from_query,
680
+ stage_params,
681
+ partition,
682
+ file_format : DataLoadingOptions {
683
+ options : file_format,
684
+ } ,
685
+ copy_options : DataLoadingOptions { options } ,
686
+ } )
687
+ }
688
+
689
+ fn parse_copy_into_table ( parser : & mut Parser ) -> Result < Statement , ParserError > {
615
690
let into: ObjectName = parse_snowflake_stage_name ( parser) ?;
616
691
let mut files: Vec < String > = vec ! [ ] ;
617
692
let mut from_transformations: Option < Vec < StageLoadSelectItem > > = None ;
@@ -712,7 +787,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
712
787
validation_mode = Some ( parser. next_token ( ) . token . to_string ( ) ) ;
713
788
}
714
789
715
- Ok ( Statement :: CopyIntoSnowflake {
790
+ Ok ( Statement :: CopyIntoSnowflakeTable {
716
791
into,
717
792
from_stage,
718
793
from_stage_alias,
@@ -876,55 +951,55 @@ fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserEr
876
951
///
877
952
fn parse_parentheses_options ( parser : & mut Parser ) -> Result < Vec < DataLoadingOption > , ParserError > {
878
953
let mut options: Vec < DataLoadingOption > = Vec :: new ( ) ;
879
-
880
954
parser. expect_token ( & Token :: LParen ) ?;
881
955
loop {
882
956
match parser. next_token ( ) . token {
883
957
Token :: RParen => break ,
884
- Token :: Word ( key) => {
885
- parser. expect_token ( & Token :: Eq ) ?;
886
- if parser. parse_keyword ( Keyword :: TRUE ) {
887
- options. push ( DataLoadingOption {
888
- option_name : key. value ,
889
- option_type : DataLoadingOptionType :: BOOLEAN ,
890
- value : "TRUE" . to_string ( ) ,
891
- } ) ;
892
- Ok ( ( ) )
893
- } else if parser. parse_keyword ( Keyword :: FALSE ) {
894
- options. push ( DataLoadingOption {
895
- option_name : key. value ,
896
- option_type : DataLoadingOptionType :: BOOLEAN ,
897
- value : "FALSE" . to_string ( ) ,
898
- } ) ;
899
- Ok ( ( ) )
900
- } else {
901
- match parser. next_token ( ) . token {
902
- Token :: SingleQuotedString ( value) => {
903
- options. push ( DataLoadingOption {
904
- option_name : key. value ,
905
- option_type : DataLoadingOptionType :: STRING ,
906
- value,
907
- } ) ;
908
- Ok ( ( ) )
909
- }
910
- Token :: Word ( word) => {
911
- options. push ( DataLoadingOption {
912
- option_name : key. value ,
913
- option_type : DataLoadingOptionType :: ENUM ,
914
- value : word. value ,
915
- } ) ;
916
- Ok ( ( ) )
917
- }
918
- _ => parser. expected ( "expected option value" , parser. peek_token ( ) ) ,
919
- }
920
- }
921
- }
922
- _ => parser. expected ( "another option or ')'" , parser. peek_token ( ) ) ,
923
- } ?;
958
+ Token :: Comma => continue ,
959
+ Token :: Word ( key) => options. push ( parse_copy_option ( parser, key) ?) ,
960
+ _ => return parser. expected ( "another option or ')'" , parser. peek_token ( ) ) ,
961
+ } ;
924
962
}
925
963
Ok ( options)
926
964
}
927
965
966
+ /// Parses a `KEY = VALUE` construct based on the specified key
967
+ fn parse_copy_option ( parser : & mut Parser , key : Word ) -> Result < DataLoadingOption , ParserError > {
968
+ parser. expect_token ( & Token :: Eq ) ?;
969
+ if parser. parse_keyword ( Keyword :: TRUE ) {
970
+ Ok ( DataLoadingOption {
971
+ option_name : key. value ,
972
+ option_type : DataLoadingOptionType :: BOOLEAN ,
973
+ value : "TRUE" . to_string ( ) ,
974
+ } )
975
+ } else if parser. parse_keyword ( Keyword :: FALSE ) {
976
+ Ok ( DataLoadingOption {
977
+ option_name : key. value ,
978
+ option_type : DataLoadingOptionType :: BOOLEAN ,
979
+ value : "FALSE" . to_string ( ) ,
980
+ } )
981
+ } else {
982
+ match parser. next_token ( ) . token {
983
+ Token :: SingleQuotedString ( value) => Ok ( DataLoadingOption {
984
+ option_name : key. value ,
985
+ option_type : DataLoadingOptionType :: STRING ,
986
+ value,
987
+ } ) ,
988
+ Token :: Word ( word) => Ok ( DataLoadingOption {
989
+ option_name : key. value ,
990
+ option_type : DataLoadingOptionType :: ENUM ,
991
+ value : word. value ,
992
+ } ) ,
993
+ Token :: Number ( n, _) => Ok ( DataLoadingOption {
994
+ option_name : key. value ,
995
+ option_type : DataLoadingOptionType :: NUMBER ,
996
+ value : n,
997
+ } ) ,
998
+ _ => parser. expected ( "expected option value" , parser. peek_token ( ) ) ,
999
+ }
1000
+ }
1001
+ }
1002
+
928
1003
/// Parsing a property of identity or autoincrement column option
929
1004
/// Syntax:
930
1005
/// ```sql
0 commit comments