Skip to content

Commit 10314d0

Browse files
authored
Support COPY query source to file (#343)
1 parent 70336ab commit 10314d0

2 files changed

Lines changed: 50 additions & 14 deletions

File tree

src/binder/copy.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,34 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
8686
target: CopyTarget,
8787
options: &[CopyOption],
8888
) -> Result<LogicalPlan, DatabaseError> {
89+
let ext_source = copy_ext_source(target, options)?;
90+
8991
let (table_name, ..) = match source {
9092
CopySource::Table {
9193
table_name,
9294
columns,
9395
} => (table_name, columns),
94-
CopySource::Query(_) => {
95-
return Err(DatabaseError::UnsupportedStmt("'COPY SOURCE'".to_string()));
96+
CopySource::Query(query) => {
97+
if !to {
98+
return Err(DatabaseError::UnsupportedStmt(
99+
"'COPY FROM query'".to_string(),
100+
));
101+
}
102+
let mut input_plan = self.bind_query(&query)?;
103+
let schema_ref = input_plan.output_schema().clone();
104+
return Ok(LogicalPlan::new(
105+
Operator::CopyToFile(CopyToFileOperator {
106+
target: ext_source,
107+
schema_ref,
108+
}),
109+
Childrens::Only(Box::new(input_plan)),
110+
));
96111
}
97112
};
98113
let table_name: Arc<str> = lower_case_name(&table_name)?.into();
99114

100115
if let Some(table) = self.context.table(table_name.clone())? {
101116
let schema_ref = table.schema_ref().clone();
102-
let ext_source = ExtSource {
103-
path: match target {
104-
CopyTarget::File { filename } => filename.into(),
105-
t => {
106-
return Err(DatabaseError::UnsupportedStmt(format!(
107-
"copy target: {t:?}"
108-
)))
109-
}
110-
},
111-
format: FileFormat::from_options(options),
112-
};
113117

114118
if to {
115119
// COPY <source_table> TO <dest_file>
@@ -139,6 +143,20 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
139143
}
140144
}
141145

146+
fn copy_ext_source(target: CopyTarget, options: &[CopyOption]) -> Result<ExtSource, DatabaseError> {
147+
Ok(ExtSource {
148+
path: match target {
149+
CopyTarget::File { filename } => filename.into(),
150+
t => {
151+
return Err(DatabaseError::UnsupportedStmt(format!(
152+
"copy target: {t:?}"
153+
)))
154+
}
155+
},
156+
format: FileFormat::from_options(options),
157+
})
158+
}
159+
142160
impl FileFormat {
143161
/// Create from copy options.
144162
pub fn from_options(options: &[CopyOption]) -> Self {

tests/slt/copy.slt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,22 @@ SELECT * FROM test_copy
1616
query I
1717
COPY test_copy TO './copy.csv' ( DELIMITER ',' );
1818
----
19-
Copy To ./copy.csv [a, b, c]
19+
Copy To ./copy.csv [a, b, c]
20+
21+
query I
22+
COPY (SELECT a, c FROM test_copy WHERE a = 1) TO './copy_query.csv' ( DELIMITER ',', HEADER true );
23+
----
24+
Copy To ./copy_query.csv [a, c]
25+
26+
statement ok
27+
create table test_copy_query (a int primary key, c varchar(10))
28+
29+
query I
30+
COPY test_copy_query FROM './copy_query.csv' ( DELIMITER ',', HEADER true );
31+
----
32+
1
33+
34+
query I
35+
SELECT * FROM test_copy_query
36+
----
37+
1 two

0 commit comments

Comments
 (0)