Skip to content

Commit 40fb1b8

Browse files
support format in options of COPY command (#9744)
* support format in options of COPY command * fix clippy lint error * add testcase to verify priority b/w STORED AS and OPTIONS (format <>)
1 parent 02fd450 commit 40fb1b8

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

datafusion/sql/src/statement.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
850850
return plan_err!("Unsupported Value in COPY statement {}", value);
851851
}
852852
};
853-
if !(&key.contains('.')) {
853+
if !(key.contains('.') || key == "format") {
854854
// If config does not belong to any namespace, assume it is
855855
// a format option and apply the format prefix for backwards
856856
// compatibility.
@@ -866,12 +866,16 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
866866
FileType::from_str(&file_type).map_err(|_| {
867867
DataFusionError::Configuration(format!("Unknown FileType {}", file_type))
868868
})?
869+
} else if let Some(format) = options.remove("format") {
870+
// try to infer file format from the "format" key in options
871+
FileType::from_str(&format)
872+
.map_err(|e| DataFusionError::Configuration(format!("{}", e)))?
869873
} else {
870874
let e = || {
871875
DataFusionError::Configuration(
872-
"Format not explicitly set and unable to get file extension! Use STORED AS to define file format."
873-
.to_string(),
874-
)
876+
"Format not explicitly set and unable to get file extension! Use STORED AS to define file format."
877+
.to_string(),
878+
)
875879
};
876880
// try to infer file format from file extension
877881
let extension: &str = &Path::new(&statement.target)

datafusion/sql/tests/sql_integration.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,18 @@ CopyTo: format=csv output_url=output.csv options: ()
442442
quick_test(sql, plan);
443443
}
444444

445+
#[test]
446+
fn plan_copy_stored_as_priority() {
447+
let sql = "COPY (select * from (values (1))) to 'output/' STORED AS CSV OPTIONS (format json)";
448+
let plan = r#"
449+
CopyTo: format=csv output_url=output/ options: (format json)
450+
Projection: column1
451+
Values: (Int64(1))
452+
"#
453+
.trim();
454+
quick_test(sql, plan);
455+
}
456+
445457
#[test]
446458
fn plan_insert() {
447459
let sql =

datafusion/sqllogictest/test_files/copy.slt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,44 @@ OPTIONS (
514514
);
515515

516516

517+
# Format Options Support with format in OPTIONS i.e. COPY { table_name | query } TO 'file_name' OPTIONS (format <format-name>, ...)
518+
519+
query I
520+
COPY (select * from (values (1))) to 'test_files/scratch/copy/'
521+
OPTIONS (format parquet);
522+
----
523+
1
524+
525+
query I
526+
COPY (select * from (values (1))) to 'test_files/scratch/copy/'
527+
OPTIONS (format parquet, compression 'zstd(10)');
528+
----
529+
1
530+
531+
query I
532+
COPY (select * from (values (1))) to 'test_files/scratch/copy/'
533+
OPTIONS (format json, compression gzip);
534+
----
535+
1
536+
537+
query I
538+
COPY (select * from (values (1))) to 'test_files/scratch/copy/'
539+
OPTIONS (
540+
format csv,
541+
has_header false,
542+
compression xz,
543+
datetime_format '%FT%H:%M:%S.%9f',
544+
delimiter ';',
545+
null_value 'NULLVAL'
546+
);
547+
----
548+
1
549+
550+
query error DataFusion error: Invalid or Unsupported Configuration: This feature is not implemented: Unknown FileType: NOTVALIDFORMAT
551+
COPY (select * from (values (1))) to 'test_files/scratch/copy/'
552+
OPTIONS (format notvalidformat, compression 'zstd(5)');
553+
554+
517555
# Error cases:
518556

519557
# Copy from table with options

0 commit comments

Comments
 (0)