@@ -2516,24 +2516,30 @@ pub enum Statement {
2516
2516
values : Vec < Option < String > > ,
2517
2517
} ,
2518
2518
/// ```sql
2519
- /// COPY INTO
2519
+ /// COPY INTO <table> | <location>
2520
2520
/// ```
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
+ ///
2522
2525
/// Copy Into syntax available for Snowflake is different than the one implemented in
2523
2526
/// Postgres. Although they share common prefix, it is reasonable to implement them
2524
2527
/// in different enums. This can be refactored later once custom dialects
2525
2528
/// are allowed to have custom Statements.
2526
2529
CopyIntoSnowflake {
2530
+ kind : CopyIntoSnowflakeKind ,
2527
2531
into : ObjectName ,
2528
- from_stage : ObjectName ,
2529
- from_stage_alias : Option < Ident > ,
2532
+ from_obj : Option < ObjectName > ,
2533
+ from_obj_alias : Option < Ident > ,
2530
2534
stage_params : StageParamsObject ,
2531
2535
from_transformations : Option < Vec < StageLoadSelectItem > > ,
2536
+ from_query : Option < Box < Query > > ,
2532
2537
files : Option < Vec < String > > ,
2533
2538
pattern : Option < String > ,
2534
2539
file_format : DataLoadingOptions ,
2535
2540
copy_options : DataLoadingOptions ,
2536
2541
validation_mode : Option < String > ,
2542
+ partition : Option < Box < Expr > > ,
2537
2543
} ,
2538
2544
/// ```sql
2539
2545
/// CLOSE
@@ -5066,60 +5072,69 @@ impl fmt::Display for Statement {
5066
5072
Ok ( ( ) )
5067
5073
}
5068
5074
Statement :: CopyIntoSnowflake {
5075
+ kind,
5069
5076
into,
5070
- from_stage ,
5071
- from_stage_alias ,
5077
+ from_obj ,
5078
+ from_obj_alias ,
5072
5079
stage_params,
5073
5080
from_transformations,
5081
+ from_query,
5074
5082
files,
5075
5083
pattern,
5076
5084
file_format,
5077
5085
copy_options,
5078
5086
validation_mode,
5087
+ partition,
5079
5088
} => {
5080
5089
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 {
5088
5091
// 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) ?;
5098
5103
}
5099
5104
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})" ) ?;
5100
5114
}
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 ) ?;
5107
5121
}
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}" ) ?;
5110
5124
}
5111
5125
if !file_format. options . is_empty ( ) {
5112
5126
write ! ( f, " FILE_FORMAT=({})" , file_format) ?;
5113
5127
}
5114
5128
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
+ }
5116
5135
}
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) ?;
5123
5138
}
5124
5139
Ok ( ( ) )
5125
5140
}
@@ -8561,6 +8576,19 @@ impl Display for StorageSerializationPolicy {
8561
8576
}
8562
8577
}
8563
8578
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
+
8564
8592
#[ cfg( test) ]
8565
8593
mod tests {
8566
8594
use super :: * ;
0 commit comments