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