@@ -2516,24 +2516,30 @@ pub enum Statement {
25162516 values : Vec < Option < String > > ,
25172517 } ,
25182518 /// ```sql
2519- /// COPY INTO
2519+ /// COPY INTO <table> | <location>
25202520 /// ```
2521- /// See <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2521+ /// See:
2522+ /// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2523+ /// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
2524+ ///
25222525 /// Copy Into syntax available for Snowflake is different than the one implemented in
25232526 /// Postgres. Although they share common prefix, it is reasonable to implement them
25242527 /// in different enums. This can be refactored later once custom dialects
25252528 /// are allowed to have custom Statements.
25262529 CopyIntoSnowflake {
2530+ kind : CopyIntoSnowflakeKind ,
25272531 into : ObjectName ,
2528- from_stage : ObjectName ,
2529- from_stage_alias : Option < Ident > ,
2532+ from_obj : Option < ObjectName > ,
2533+ from_obj_alias : Option < Ident > ,
25302534 stage_params : StageParamsObject ,
25312535 from_transformations : Option < Vec < StageLoadSelectItem > > ,
2536+ from_query : Option < Box < Query > > ,
25322537 files : Option < Vec < String > > ,
25332538 pattern : Option < String > ,
25342539 file_format : DataLoadingOptions ,
25352540 copy_options : DataLoadingOptions ,
25362541 validation_mode : Option < String > ,
2542+ partition : Option < Box < Expr > > ,
25372543 } ,
25382544 /// ```sql
25392545 /// CLOSE
@@ -5066,60 +5072,69 @@ impl fmt::Display for Statement {
50665072 Ok ( ( ) )
50675073 }
50685074 Statement :: CopyIntoSnowflake {
5075+ kind,
50695076 into,
5070- from_stage ,
5071- from_stage_alias ,
5077+ from_obj ,
5078+ from_obj_alias ,
50725079 stage_params,
50735080 from_transformations,
5081+ from_query,
50745082 files,
50755083 pattern,
50765084 file_format,
50775085 copy_options,
50785086 validation_mode,
5087+ partition,
50795088 } => {
50805089 write ! ( f, "COPY INTO {}" , into) ?;
5081- if from_transformations. is_none ( ) {
5082- // Standard data load
5083- write ! ( f, " FROM {}{}" , from_stage, stage_params) ?;
5084- if from_stage_alias. as_ref ( ) . is_some ( ) {
5085- write ! ( f, " AS {}" , from_stage_alias. as_ref( ) . unwrap( ) ) ?;
5086- }
5087- } else {
5090+ if let Some ( from_transformations) = from_transformations {
50885091 // Data load with transformation
5089- write ! (
5090- f,
5091- " FROM (SELECT {} FROM {}{}" ,
5092- display_separated( from_transformations. as_ref( ) . unwrap( ) , ", " ) ,
5093- from_stage,
5094- stage_params,
5095- ) ?;
5096- if from_stage_alias. as_ref ( ) . is_some ( ) {
5097- write ! ( f, " AS {}" , from_stage_alias. as_ref( ) . unwrap( ) ) ?;
5092+ if let Some ( from_stage) = from_obj {
5093+ write ! (
5094+ f,
5095+ " FROM (SELECT {} FROM {}{}" ,
5096+ display_separated( from_transformations, ", " ) ,
5097+ from_stage,
5098+ stage_params
5099+ ) ?;
5100+ }
5101+ if let Some ( from_obj_alias) = from_obj_alias {
5102+ write ! ( f, " AS {}" , from_obj_alias) ?;
50985103 }
50995104 write ! ( f, ")" ) ?;
5105+ } else if let Some ( from_obj) = from_obj {
5106+ // Standard data load
5107+ write ! ( f, " FROM {}{}" , from_obj, stage_params) ?;
5108+ if let Some ( from_obj_alias) = from_obj_alias {
5109+ write ! ( f, " AS {from_obj_alias}" ) ?;
5110+ }
5111+ } else if let Some ( from_query) = from_query {
5112+ // Data unload from query
5113+ write ! ( f, " FROM ({from_query})" ) ?;
51005114 }
5101- if files . is_some ( ) {
5102- write ! (
5103- f ,
5104- " FILES = ('{}')" ,
5105- display_separated ( files . as_ref ( ) . unwrap ( ) , "', '" )
5106- ) ?;
5115+
5116+ if let Some ( files ) = files {
5117+ write ! ( f , " FILES = ('{}')" , display_separated ( files , "', '" ) ) ? ;
5118+ }
5119+ if let Some ( pattern ) = pattern {
5120+ write ! ( f , " PATTERN = '{}'" , pattern ) ?;
51075121 }
5108- if pattern . is_some ( ) {
5109- write ! ( f, " PATTERN = '{}'" , pattern . as_ref ( ) . unwrap ( ) ) ?;
5122+ if let Some ( partition ) = partition {
5123+ write ! ( f, " PARTITION BY {partition}" ) ?;
51105124 }
51115125 if !file_format. options . is_empty ( ) {
51125126 write ! ( f, " FILE_FORMAT=({})" , file_format) ?;
51135127 }
51145128 if !copy_options. options . is_empty ( ) {
5115- write ! ( f, " COPY_OPTIONS=({})" , copy_options) ?;
5129+ match kind {
5130+ CopyIntoSnowflakeKind :: Table => {
5131+ write ! ( f, " COPY_OPTIONS=({})" , copy_options) ?
5132+ }
5133+ CopyIntoSnowflakeKind :: Location => write ! ( f, " {copy_options}" ) ?,
5134+ }
51165135 }
5117- if validation_mode. is_some ( ) {
5118- write ! (
5119- f,
5120- " VALIDATION_MODE = {}" ,
5121- validation_mode. as_ref( ) . unwrap( )
5122- ) ?;
5136+ if let Some ( validation_mode) = validation_mode {
5137+ write ! ( f, " VALIDATION_MODE = {}" , validation_mode) ?;
51235138 }
51245139 Ok ( ( ) )
51255140 }
@@ -8561,6 +8576,19 @@ impl Display for StorageSerializationPolicy {
85618576 }
85628577}
85638578
8579+ /// Variants of the Snowflake `COPY INTO` statement
8580+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
8581+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
8582+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
8583+ pub enum CopyIntoSnowflakeKind {
8584+ /// Loads data from files to a table
8585+ /// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
8586+ Table ,
8587+ /// Unloads data from a table or query to external files
8588+ /// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
8589+ Location ,
8590+ }
8591+
85648592#[ cfg( test) ]
85658593mod tests {
85668594 use super :: * ;
0 commit comments