@@ -2498,24 +2498,30 @@ pub enum Statement {
2498
2498
values : Vec < Option < String > > ,
2499
2499
} ,
2500
2500
/// ```sql
2501
- /// COPY INTO
2501
+ /// COPY INTO <table> | <location>
2502
2502
/// ```
2503
- /// See <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2503
+ /// See:
2504
+ /// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2505
+ /// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
2506
+ ///
2504
2507
/// Copy Into syntax available for Snowflake is different than the one implemented in
2505
2508
/// Postgres. Although they share common prefix, it is reasonable to implement them
2506
2509
/// in different enums. This can be refactored later once custom dialects
2507
2510
/// are allowed to have custom Statements.
2508
2511
CopyIntoSnowflake {
2512
+ kind : CopyIntoSnowflakeKind ,
2509
2513
into : ObjectName ,
2510
- from_stage : ObjectName ,
2511
- from_stage_alias : Option < Ident > ,
2514
+ from_obj : Option < ObjectName > ,
2515
+ from_obj_alias : Option < Ident > ,
2512
2516
stage_params : StageParamsObject ,
2513
2517
from_transformations : Option < Vec < StageLoadSelectItem > > ,
2518
+ from_query : Option < Box < Query > > ,
2514
2519
files : Option < Vec < String > > ,
2515
2520
pattern : Option < String > ,
2516
2521
file_format : DataLoadingOptions ,
2517
2522
copy_options : DataLoadingOptions ,
2518
2523
validation_mode : Option < String > ,
2524
+ partition : Option < Box < Expr > > ,
2519
2525
} ,
2520
2526
/// ```sql
2521
2527
/// CLOSE
@@ -5048,60 +5054,69 @@ impl fmt::Display for Statement {
5048
5054
Ok ( ( ) )
5049
5055
}
5050
5056
Statement :: CopyIntoSnowflake {
5057
+ kind,
5051
5058
into,
5052
- from_stage ,
5053
- from_stage_alias ,
5059
+ from_obj ,
5060
+ from_obj_alias ,
5054
5061
stage_params,
5055
5062
from_transformations,
5063
+ from_query,
5056
5064
files,
5057
5065
pattern,
5058
5066
file_format,
5059
5067
copy_options,
5060
5068
validation_mode,
5069
+ partition,
5061
5070
} => {
5062
5071
write ! ( f, "COPY INTO {}" , into) ?;
5063
- if from_transformations. is_none ( ) {
5064
- // Standard data load
5065
- write ! ( f, " FROM {}{}" , from_stage, stage_params) ?;
5066
- if from_stage_alias. as_ref ( ) . is_some ( ) {
5067
- write ! ( f, " AS {}" , from_stage_alias. as_ref( ) . unwrap( ) ) ?;
5068
- }
5069
- } else {
5072
+ if let Some ( from_transformations) = from_transformations {
5070
5073
// Data load with transformation
5071
- write ! (
5072
- f,
5073
- " FROM (SELECT {} FROM {}{}" ,
5074
- display_separated( from_transformations. as_ref( ) . unwrap( ) , ", " ) ,
5075
- from_stage,
5076
- stage_params,
5077
- ) ?;
5078
- if from_stage_alias. as_ref ( ) . is_some ( ) {
5079
- write ! ( f, " AS {}" , from_stage_alias. as_ref( ) . unwrap( ) ) ?;
5074
+ if let Some ( from_stage) = from_obj {
5075
+ write ! (
5076
+ f,
5077
+ " FROM (SELECT {} FROM {}{}" ,
5078
+ display_separated( from_transformations, ", " ) ,
5079
+ from_stage,
5080
+ stage_params
5081
+ ) ?;
5082
+ }
5083
+ if let Some ( from_obj_alias) = from_obj_alias {
5084
+ write ! ( f, " AS {}" , from_obj_alias) ?;
5080
5085
}
5081
5086
write ! ( f, ")" ) ?;
5087
+ } else if let Some ( from_obj) = from_obj {
5088
+ // Standard data load
5089
+ write ! ( f, " FROM {}{}" , from_obj, stage_params) ?;
5090
+ if let Some ( from_obj_alias) = from_obj_alias {
5091
+ write ! ( f, " AS {from_obj_alias}" ) ?;
5092
+ }
5093
+ } else if let Some ( from_query) = from_query {
5094
+ // Data unload from query
5095
+ write ! ( f, " FROM ({from_query})" ) ?;
5082
5096
}
5083
- if files . is_some ( ) {
5084
- write ! (
5085
- f ,
5086
- " FILES = ('{}')" ,
5087
- display_separated ( files . as_ref ( ) . unwrap ( ) , "', '" )
5088
- ) ?;
5097
+
5098
+ if let Some ( files ) = files {
5099
+ write ! ( f , " FILES = ('{}')" , display_separated ( files , "', '" ) ) ? ;
5100
+ }
5101
+ if let Some ( pattern ) = pattern {
5102
+ write ! ( f , " PATTERN = '{}'" , pattern ) ?;
5089
5103
}
5090
- if pattern . is_some ( ) {
5091
- write ! ( f, " PATTERN = '{}'" , pattern . as_ref ( ) . unwrap ( ) ) ?;
5104
+ if let Some ( partition ) = partition {
5105
+ write ! ( f, " PARTITION BY {partition}" ) ?;
5092
5106
}
5093
5107
if !file_format. options . is_empty ( ) {
5094
5108
write ! ( f, " FILE_FORMAT=({})" , file_format) ?;
5095
5109
}
5096
5110
if !copy_options. options . is_empty ( ) {
5097
- write ! ( f, " COPY_OPTIONS=({})" , copy_options) ?;
5111
+ match kind {
5112
+ CopyIntoSnowflakeKind :: Table => {
5113
+ write ! ( f, " COPY_OPTIONS=({})" , copy_options) ?
5114
+ }
5115
+ CopyIntoSnowflakeKind :: Location => write ! ( f, " {copy_options}" ) ?,
5116
+ }
5098
5117
}
5099
- if validation_mode. is_some ( ) {
5100
- write ! (
5101
- f,
5102
- " VALIDATION_MODE = {}" ,
5103
- validation_mode. as_ref( ) . unwrap( )
5104
- ) ?;
5118
+ if let Some ( validation_mode) = validation_mode {
5119
+ write ! ( f, " VALIDATION_MODE = {}" , validation_mode) ?;
5105
5120
}
5106
5121
Ok ( ( ) )
5107
5122
}
@@ -8543,6 +8558,19 @@ impl Display for StorageSerializationPolicy {
8543
8558
}
8544
8559
}
8545
8560
8561
+ /// Variants of the Snowflake `COPY INTO` statement
8562
+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
8563
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
8564
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
8565
+ pub enum CopyIntoSnowflakeKind {
8566
+ /// Loads data from files to a table
8567
+ /// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
8568
+ Table ,
8569
+ /// Unloads data from a table or query to external files
8570
+ /// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
8571
+ Location ,
8572
+ }
8573
+
8546
8574
#[ cfg( test) ]
8547
8575
mod tests {
8548
8576
use super :: * ;
0 commit comments