@@ -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" ) ) ]
@@ -660,7 +660,82 @@ pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, Par
660
660
}
661
661
}
662
662
663
+ /// Parses a `COPY INTO` statement. Snowflake has two variants, `COPY INTO <table>`
664
+ /// and `COPY INTO <location>` which have different syntax.
663
665
pub fn parse_copy_into ( parser : & mut Parser ) -> Result < Statement , ParserError > {
666
+ if is_copy_into_location ( parser) {
667
+ parse_copy_into_location ( parser)
668
+ } else {
669
+ parse_copy_into_table ( parser)
670
+ }
671
+ }
672
+
673
+ /// Returns true if the `COPY INTO` statement is a `COPY INTO <location>`
674
+ /// by peeking at the prefix of the target's object name and trying to
675
+ /// determine if it's a Snowflake stage or a table.
676
+ fn is_copy_into_location ( parser : & mut Parser ) -> bool {
677
+ match parser. peek_token ( ) . token {
678
+ // Indicates an internal stage
679
+ Token :: AtSign => true ,
680
+ // Indicates an external stage, i.e. s3://, gcs:// or azure://
681
+ Token :: SingleQuotedString ( s) if s. contains ( "://" ) => true ,
682
+ _ => false ,
683
+ }
684
+ }
685
+
686
+ fn parse_copy_into_location ( parser : & mut Parser ) -> Result < Statement , ParserError > {
687
+ let into: ObjectName = parse_snowflake_stage_name ( parser) ?;
688
+ parser. expect_keyword_is ( Keyword :: FROM ) ?;
689
+ // Two options: `FROM (query)` or `FROM <table>`
690
+ let ( from_table, from_query) = match parser. next_token ( ) . token {
691
+ Token :: LParen => {
692
+ let query = parser. parse_query ( ) ?;
693
+ parser. expect_token ( & Token :: RParen ) ?;
694
+ ( None , Some ( query) )
695
+ }
696
+ _ => {
697
+ parser. prev_token ( ) ;
698
+ let table = parser. parse_object_name ( true ) ?;
699
+ ( Some ( table) , None )
700
+ }
701
+ } ;
702
+ let stage_params = parse_stage_params ( parser) ?;
703
+
704
+ // The order of the next options is not defined, so we need to loop
705
+ // until we reach the end of the statement
706
+ let mut partition = None ;
707
+ let mut file_format = Vec :: new ( ) ;
708
+ let mut options: Vec < DataLoadingOption > = Vec :: new ( ) ;
709
+ loop {
710
+ if parser. parse_keyword ( Keyword :: FILE_FORMAT ) {
711
+ parser. expect_token ( & Token :: Eq ) ?;
712
+ file_format = parse_parentheses_options ( parser) ?;
713
+ } else if parser. parse_keywords ( & [ Keyword :: PARTITION , Keyword :: BY ] ) {
714
+ partition = Some ( parser. parse_expr ( ) ?)
715
+ } else {
716
+ match parser. next_token ( ) . token {
717
+ Token :: SemiColon | Token :: EOF => break ,
718
+ Token :: Comma => continue ,
719
+ Token :: Word ( key) => options. push ( parse_copy_option ( parser, key) ?) ,
720
+ _ => return parser. expected ( "another option, ; or EOF'" , parser. peek_token ( ) ) ,
721
+ }
722
+ }
723
+ }
724
+
725
+ Ok ( Statement :: CopyIntoSnowflakeLocation {
726
+ into,
727
+ from_table,
728
+ from_query,
729
+ stage_params,
730
+ partition,
731
+ file_format : DataLoadingOptions {
732
+ options : file_format,
733
+ } ,
734
+ copy_options : DataLoadingOptions { options } ,
735
+ } )
736
+ }
737
+
738
+ fn parse_copy_into_table ( parser : & mut Parser ) -> Result < Statement , ParserError > {
664
739
let into: ObjectName = parse_snowflake_stage_name ( parser) ?;
665
740
let mut files: Vec < String > = vec ! [ ] ;
666
741
let mut from_transformations: Option < Vec < StageLoadSelectItem > > = None ;
@@ -761,7 +836,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
761
836
validation_mode = Some ( parser. next_token ( ) . token . to_string ( ) ) ;
762
837
}
763
838
764
- Ok ( Statement :: CopyIntoSnowflake {
839
+ Ok ( Statement :: CopyIntoSnowflakeTable {
765
840
into,
766
841
from_stage,
767
842
from_stage_alias,
@@ -925,55 +1000,55 @@ fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserEr
925
1000
///
926
1001
fn parse_parentheses_options ( parser : & mut Parser ) -> Result < Vec < DataLoadingOption > , ParserError > {
927
1002
let mut options: Vec < DataLoadingOption > = Vec :: new ( ) ;
928
-
929
1003
parser. expect_token ( & Token :: LParen ) ?;
930
1004
loop {
931
1005
match parser. next_token ( ) . token {
932
1006
Token :: RParen => break ,
933
- Token :: Word ( key) => {
934
- parser. expect_token ( & Token :: Eq ) ?;
935
- if parser. parse_keyword ( Keyword :: TRUE ) {
936
- options. push ( DataLoadingOption {
937
- option_name : key. value ,
938
- option_type : DataLoadingOptionType :: BOOLEAN ,
939
- value : "TRUE" . to_string ( ) ,
940
- } ) ;
941
- Ok ( ( ) )
942
- } else if parser. parse_keyword ( Keyword :: FALSE ) {
943
- options. push ( DataLoadingOption {
944
- option_name : key. value ,
945
- option_type : DataLoadingOptionType :: BOOLEAN ,
946
- value : "FALSE" . to_string ( ) ,
947
- } ) ;
948
- Ok ( ( ) )
949
- } else {
950
- match parser. next_token ( ) . token {
951
- Token :: SingleQuotedString ( value) => {
952
- options. push ( DataLoadingOption {
953
- option_name : key. value ,
954
- option_type : DataLoadingOptionType :: STRING ,
955
- value,
956
- } ) ;
957
- Ok ( ( ) )
958
- }
959
- Token :: Word ( word) => {
960
- options. push ( DataLoadingOption {
961
- option_name : key. value ,
962
- option_type : DataLoadingOptionType :: ENUM ,
963
- value : word. value ,
964
- } ) ;
965
- Ok ( ( ) )
966
- }
967
- _ => parser. expected ( "expected option value" , parser. peek_token ( ) ) ,
968
- }
969
- }
970
- }
971
- _ => parser. expected ( "another option or ')'" , parser. peek_token ( ) ) ,
972
- } ?;
1007
+ Token :: Comma => continue ,
1008
+ Token :: Word ( key) => options. push ( parse_copy_option ( parser, key) ?) ,
1009
+ _ => return parser. expected ( "another option or ')'" , parser. peek_token ( ) ) ,
1010
+ } ;
973
1011
}
974
1012
Ok ( options)
975
1013
}
976
1014
1015
+ /// Parses a `KEY = VALUE` construct based on the specified key
1016
+ fn parse_copy_option ( parser : & mut Parser , key : Word ) -> Result < DataLoadingOption , ParserError > {
1017
+ parser. expect_token ( & Token :: Eq ) ?;
1018
+ if parser. parse_keyword ( Keyword :: TRUE ) {
1019
+ Ok ( DataLoadingOption {
1020
+ option_name : key. value ,
1021
+ option_type : DataLoadingOptionType :: BOOLEAN ,
1022
+ value : "TRUE" . to_string ( ) ,
1023
+ } )
1024
+ } else if parser. parse_keyword ( Keyword :: FALSE ) {
1025
+ Ok ( DataLoadingOption {
1026
+ option_name : key. value ,
1027
+ option_type : DataLoadingOptionType :: BOOLEAN ,
1028
+ value : "FALSE" . to_string ( ) ,
1029
+ } )
1030
+ } else {
1031
+ match parser. next_token ( ) . token {
1032
+ Token :: SingleQuotedString ( value) => Ok ( DataLoadingOption {
1033
+ option_name : key. value ,
1034
+ option_type : DataLoadingOptionType :: STRING ,
1035
+ value,
1036
+ } ) ,
1037
+ Token :: Word ( word) => Ok ( DataLoadingOption {
1038
+ option_name : key. value ,
1039
+ option_type : DataLoadingOptionType :: ENUM ,
1040
+ value : word. value ,
1041
+ } ) ,
1042
+ Token :: Number ( n, _) => Ok ( DataLoadingOption {
1043
+ option_name : key. value ,
1044
+ option_type : DataLoadingOptionType :: NUMBER ,
1045
+ value : n,
1046
+ } ) ,
1047
+ _ => parser. expected ( "expected option value" , parser. peek_token ( ) ) ,
1048
+ }
1049
+ }
1050
+ }
1051
+
977
1052
/// Parsing a property of identity or autoincrement column option
978
1053
/// Syntax:
979
1054
/// ```sql
0 commit comments