@@ -20,7 +20,7 @@ use crate::alloc::string::ToString;
20
20
use crate :: ast:: helpers:: key_value_options:: { KeyValueOption , KeyValueOptionType , KeyValueOptions } ;
21
21
use crate :: ast:: helpers:: stmt_create_table:: CreateTableBuilder ;
22
22
use crate :: ast:: helpers:: stmt_data_loading:: {
23
- FileStagingCommand , StageLoadSelectItem , StageParamsObject ,
23
+ FileStagingCommand , StageLoadSelectItem , StageLoadSelectItemKind , StageParamsObject ,
24
24
} ;
25
25
use crate :: ast:: {
26
26
ColumnOption , ColumnPolicy , ColumnPolicyProperty , CopyIntoSnowflakeKind , Ident ,
@@ -30,7 +30,7 @@ use crate::ast::{
30
30
} ;
31
31
use crate :: dialect:: { Dialect , Precedence } ;
32
32
use crate :: keywords:: Keyword ;
33
- use crate :: parser:: { Parser , ParserError } ;
33
+ use crate :: parser:: { IsOptional , Parser , ParserError } ;
34
34
use crate :: tokenizer:: { Token , Word } ;
35
35
#[ cfg( not( feature = "std" ) ) ]
36
36
use alloc:: boxed:: Box ;
@@ -722,7 +722,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
722
722
} ;
723
723
724
724
let mut files: Vec < String > = vec ! [ ] ;
725
- let mut from_transformations: Option < Vec < StageLoadSelectItem > > = None ;
725
+ let mut from_transformations: Option < Vec < StageLoadSelectItemKind > > = None ;
726
726
let mut from_stage_alias = None ;
727
727
let mut from_stage = None ;
728
728
let mut stage_params = StageParamsObject {
@@ -744,6 +744,11 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
744
744
stage_params = parse_stage_params ( parser) ?;
745
745
}
746
746
747
+ let into_columns = match & parser. peek_token ( ) . token {
748
+ Token :: LParen => Some ( parser. parse_parenthesized_column_list ( IsOptional :: Optional , true ) ?) ,
749
+ _ => None ,
750
+ } ;
751
+
747
752
parser. expect_keyword_is ( Keyword :: FROM ) ?;
748
753
match parser. next_token ( ) . token {
749
754
Token :: LParen if kind == CopyIntoSnowflakeKind :: Table => {
@@ -755,15 +760,10 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
755
760
from_stage = Some ( parse_snowflake_stage_name ( parser) ?) ;
756
761
stage_params = parse_stage_params ( parser) ?;
757
762
758
- // as
759
- from_stage_alias = if parser. parse_keyword ( Keyword :: AS ) {
760
- Some ( match parser. next_token ( ) . token {
761
- Token :: Word ( w) => Ok ( Ident :: new ( w. value ) ) ,
762
- _ => parser. expected ( "stage alias" , parser. peek_token ( ) ) ,
763
- } ?)
764
- } else {
765
- None
766
- } ;
763
+ // Parse an optional alias
764
+ from_stage_alias = parser
765
+ . maybe_parse_table_alias ( ) ?
766
+ . map ( |table_alias| table_alias. name ) ;
767
767
parser. expect_token ( & Token :: RParen ) ?;
768
768
}
769
769
Token :: LParen if kind == CopyIntoSnowflakeKind :: Location => {
@@ -846,6 +846,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
846
846
Ok ( Statement :: CopyIntoSnowflake {
847
847
kind,
848
848
into,
849
+ into_columns,
849
850
from_obj : from_stage,
850
851
from_obj_alias : from_stage_alias,
851
852
stage_params,
@@ -866,86 +867,93 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
866
867
867
868
fn parse_select_items_for_data_load (
868
869
parser : & mut Parser ,
869
- ) -> Result < Option < Vec < StageLoadSelectItem > > , ParserError > {
870
- // [<alias>.]$<file_col_num>[.<element>] [ , [<alias>.]$<file_col_num>[.<element>] ... ]
871
- let mut select_items: Vec < StageLoadSelectItem > = vec ! [ ] ;
870
+ ) -> Result < Option < Vec < StageLoadSelectItemKind > > , ParserError > {
871
+ let mut select_items: Vec < StageLoadSelectItemKind > = vec ! [ ] ;
872
872
loop {
873
- let mut alias: Option < Ident > = None ;
874
- let mut file_col_num: i32 = 0 ;
875
- let mut element: Option < Ident > = None ;
876
- let mut item_as: Option < Ident > = None ;
873
+ match parser. maybe_parse ( parse_select_item_for_data_load) ? {
874
+ // [<alias>.]$<file_col_num>[.<element>] [ , [<alias>.]$<file_col_num>[.<element>] ... ]
875
+ Some ( item) => select_items. push ( StageLoadSelectItemKind :: StageLoadSelectItem ( item) ) ,
876
+ // Fallback, try to parse a standard SQL select item
877
+ None => select_items. push ( StageLoadSelectItemKind :: SelectItem (
878
+ parser. parse_select_item ( ) ?,
879
+ ) ) ,
880
+ }
881
+ if matches ! ( parser. peek_token_ref( ) . token, Token :: Comma ) {
882
+ parser. advance_token ( ) ;
883
+ } else {
884
+ break ;
885
+ }
886
+ }
887
+ Ok ( Some ( select_items) )
888
+ }
877
889
878
- let next_token = parser. next_token ( ) ;
879
- match next_token. token {
890
+ fn parse_select_item_for_data_load (
891
+ parser : & mut Parser ,
892
+ ) -> Result < StageLoadSelectItem , ParserError > {
893
+ let mut alias: Option < Ident > = None ;
894
+ let mut file_col_num: i32 = 0 ;
895
+ let mut element: Option < Ident > = None ;
896
+ let mut item_as: Option < Ident > = None ;
897
+
898
+ let next_token = parser. next_token ( ) ;
899
+ match next_token. token {
900
+ Token :: Placeholder ( w) => {
901
+ file_col_num = w. to_string ( ) . split_off ( 1 ) . parse :: < i32 > ( ) . map_err ( |e| {
902
+ ParserError :: ParserError ( format ! ( "Could not parse '{w}' as i32: {e}" ) )
903
+ } ) ?;
904
+ Ok ( ( ) )
905
+ }
906
+ Token :: Word ( w) => {
907
+ alias = Some ( Ident :: new ( w. value ) ) ;
908
+ Ok ( ( ) )
909
+ }
910
+ _ => parser. expected ( "alias or file_col_num" , next_token) ,
911
+ } ?;
912
+
913
+ if alias. is_some ( ) {
914
+ parser. expect_token ( & Token :: Period ) ?;
915
+ // now we get col_num token
916
+ let col_num_token = parser. next_token ( ) ;
917
+ match col_num_token. token {
880
918
Token :: Placeholder ( w) => {
881
919
file_col_num = w. to_string ( ) . split_off ( 1 ) . parse :: < i32 > ( ) . map_err ( |e| {
882
920
ParserError :: ParserError ( format ! ( "Could not parse '{w}' as i32: {e}" ) )
883
921
} ) ?;
884
922
Ok ( ( ) )
885
923
}
886
- Token :: Word ( w) => {
887
- alias = Some ( Ident :: new ( w. value ) ) ;
888
- Ok ( ( ) )
889
- }
890
- _ => parser. expected ( "alias or file_col_num" , next_token) ,
924
+ _ => parser. expected ( "file_col_num" , col_num_token) ,
891
925
} ?;
926
+ }
892
927
893
- if alias. is_some ( ) {
894
- parser. expect_token ( & Token :: Period ) ?;
895
- // now we get col_num token
896
- let col_num_token = parser. next_token ( ) ;
897
- match col_num_token. token {
898
- Token :: Placeholder ( w) => {
899
- file_col_num = w. to_string ( ) . split_off ( 1 ) . parse :: < i32 > ( ) . map_err ( |e| {
900
- ParserError :: ParserError ( format ! ( "Could not parse '{w}' as i32: {e}" ) )
901
- } ) ?;
902
- Ok ( ( ) )
903
- }
904
- _ => parser. expected ( "file_col_num" , col_num_token) ,
905
- } ?;
906
- }
907
-
908
- // try extracting optional element
909
- match parser. next_token ( ) . token {
910
- Token :: Colon => {
911
- // parse element
912
- element = Some ( Ident :: new ( match parser. next_token ( ) . token {
913
- Token :: Word ( w) => Ok ( w. value ) ,
914
- _ => parser. expected ( "file_col_num" , parser. peek_token ( ) ) ,
915
- } ?) ) ;
916
- }
917
- _ => {
918
- // element not present move back
919
- parser. prev_token ( ) ;
920
- }
928
+ // try extracting optional element
929
+ match parser. next_token ( ) . token {
930
+ Token :: Colon => {
931
+ // parse element
932
+ element = Some ( Ident :: new ( match parser. next_token ( ) . token {
933
+ Token :: Word ( w) => Ok ( w. value ) ,
934
+ _ => parser. expected ( "file_col_num" , parser. peek_token ( ) ) ,
935
+ } ?) ) ;
921
936
}
922
-
923
- // as
924
- if parser. parse_keyword ( Keyword :: AS ) {
925
- item_as = Some ( match parser. next_token ( ) . token {
926
- Token :: Word ( w) => Ok ( Ident :: new ( w. value ) ) ,
927
- _ => parser. expected ( "column item alias" , parser. peek_token ( ) ) ,
928
- } ?) ;
937
+ _ => {
938
+ // element not present move back
939
+ parser. prev_token ( ) ;
929
940
}
941
+ }
930
942
931
- select_items. push ( StageLoadSelectItem {
932
- alias,
933
- file_col_num,
934
- element,
935
- item_as,
936
- } ) ;
937
-
938
- match parser. next_token ( ) . token {
939
- Token :: Comma => {
940
- // continue
941
- }
942
- _ => {
943
- parser. prev_token ( ) ; // need to move back
944
- break ;
945
- }
946
- }
943
+ // as
944
+ if parser. parse_keyword ( Keyword :: AS ) {
945
+ item_as = Some ( match parser. next_token ( ) . token {
946
+ Token :: Word ( w) => Ok ( Ident :: new ( w. value ) ) ,
947
+ _ => parser. expected ( "column item alias" , parser. peek_token ( ) ) ,
948
+ } ?) ;
947
949
}
948
- Ok ( Some ( select_items) )
950
+
951
+ Ok ( StageLoadSelectItem {
952
+ alias,
953
+ file_col_num,
954
+ element,
955
+ item_as,
956
+ } )
949
957
}
950
958
951
959
fn parse_stage_params ( parser : & mut Parser ) -> Result < StageParamsObject , ParserError > {
0 commit comments