Skip to content

Commit 412867a

Browse files
alambaprimadi
andauthored
Add COPY .. TO .. syntax support (#6355)
* Add `COPY .. TO ..` syntax support * fix rustdocs * Apply suggestions from code review Co-authored-by: Armin Primadi <[email protected]> * Update message * Clarify error --------- Co-authored-by: Armin Primadi <[email protected]>
1 parent 4b8a3d6 commit 412867a

File tree

5 files changed

+435
-41
lines changed

5 files changed

+435
-41
lines changed

datafusion/core/src/execution/context.rs

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ use crate::logical_expr::{
6969
LogicalPlanBuilder, SetVariable, TableSource, TableType, UNNAMED_TABLE,
7070
};
7171
use crate::optimizer::OptimizerRule;
72-
use datafusion_sql::{planner::ParserOptions, ResolvedTableReference, TableReference};
72+
use datafusion_sql::{
73+
parser::{CopyToSource, CopyToStatement},
74+
planner::ParserOptions,
75+
ResolvedTableReference, TableReference,
76+
};
7377

7478
use crate::physical_optimizer::coalesce_batches::CoalesceBatches;
7579
use crate::physical_optimizer::repartition::Repartition;
@@ -1686,45 +1690,58 @@ impl SessionState {
16861690
// table providers for all relations referenced in this query
16871691
let mut relations = hashbrown::HashSet::with_capacity(10);
16881692

1689-
match statement {
1690-
DFStatement::Statement(s) => {
1691-
struct RelationVisitor<'a>(&'a mut hashbrown::HashSet<ObjectName>);
1693+
struct RelationVisitor<'a>(&'a mut hashbrown::HashSet<ObjectName>);
1694+
1695+
impl<'a> RelationVisitor<'a> {
1696+
/// Record that `relation` was used in this statement
1697+
fn insert(&mut self, relation: &ObjectName) {
1698+
self.0.get_or_insert_with(relation, |_| relation.clone());
1699+
}
1700+
}
16921701

1693-
impl<'a> Visitor for RelationVisitor<'a> {
1694-
type Break = ();
1702+
impl<'a> Visitor for RelationVisitor<'a> {
1703+
type Break = ();
16951704

1696-
fn pre_visit_relation(
1697-
&mut self,
1698-
relation: &ObjectName,
1699-
) -> ControlFlow<()> {
1700-
self.0.get_or_insert_with(relation, |_| relation.clone());
1701-
ControlFlow::Continue(())
1702-
}
1705+
fn pre_visit_relation(&mut self, relation: &ObjectName) -> ControlFlow<()> {
1706+
self.insert(relation);
1707+
ControlFlow::Continue(())
1708+
}
17031709

1704-
fn pre_visit_statement(
1705-
&mut self,
1706-
statement: &Statement,
1707-
) -> ControlFlow<()> {
1708-
if let Statement::ShowCreate {
1709-
obj_type: ShowCreateObject::Table | ShowCreateObject::View,
1710-
obj_name,
1711-
} = statement
1712-
{
1713-
self.0.get_or_insert_with(obj_name, |_| obj_name.clone());
1714-
}
1715-
ControlFlow::Continue(())
1716-
}
1710+
fn pre_visit_statement(&mut self, statement: &Statement) -> ControlFlow<()> {
1711+
if let Statement::ShowCreate {
1712+
obj_type: ShowCreateObject::Table | ShowCreateObject::View,
1713+
obj_name,
1714+
} = statement
1715+
{
1716+
self.insert(obj_name)
17171717
}
1718-
let mut visitor = RelationVisitor(&mut relations);
1718+
ControlFlow::Continue(())
1719+
}
1720+
}
1721+
1722+
let mut visitor = RelationVisitor(&mut relations);
1723+
match statement {
1724+
DFStatement::Statement(s) => {
17191725
let _ = s.as_ref().visit(&mut visitor);
17201726
}
17211727
DFStatement::CreateExternalTable(table) => {
1722-
relations.insert(ObjectName(vec![Ident::from(table.name.as_str())]));
1723-
}
1724-
DFStatement::DescribeTableStmt(table) => {
1725-
relations
1726-
.get_or_insert_with(&table.table_name, |_| table.table_name.clone());
1728+
visitor
1729+
.0
1730+
.insert(ObjectName(vec![Ident::from(table.name.as_str())]));
17271731
}
1732+
DFStatement::DescribeTableStmt(table) => visitor.insert(&table.table_name),
1733+
DFStatement::CopyTo(CopyToStatement {
1734+
source,
1735+
target: _,
1736+
options: _,
1737+
}) => match source {
1738+
CopyToSource::Relation(table_name) => {
1739+
visitor.insert(table_name);
1740+
}
1741+
CopyToSource::Query(query) => {
1742+
query.visit(&mut visitor);
1743+
}
1744+
},
17281745
}
17291746

17301747
// Always include information_schema if available
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
# tests for copy command
19+
20+
statement ok
21+
create table source_table(col1 integer, col2 varchar) as values (1, 'Foo'), (2, 'Bar');
22+
23+
# Copy from table
24+
statement error DataFusion error: This feature is not implemented: `COPY \.\. TO \.\.` statement is not yet supported
25+
COPY source_table to '/tmp/table.parquet';
26+
27+
# Copy from table with options
28+
statement error DataFusion error: This feature is not implemented: `COPY \.\. TO \.\.` statement is not yet supported
29+
COPY source_table to '/tmp/table.parquet' (row_group_size 55);
30+
31+
# Copy from table with options (and trailing comma)
32+
statement error DataFusion error: This feature is not implemented: `COPY \.\. TO \.\.` statement is not yet supported
33+
COPY source_table to '/tmp/table.parquet' (row_group_size 55, row_group_limit_bytes 9,);
34+
35+
36+
# Error cases:
37+
38+
# Incomplete statement
39+
statement error DataFusion error: SQL error: ParserError\("Expected \), found: EOF"\)
40+
COPY (select col2, sum(col1) from source_table
41+
42+
# Copy from table with non literal
43+
statement error DataFusion error: SQL error: ParserError\("Expected ',' or '\)' after option definition, found: \+"\)
44+
COPY source_table to '/tmp/table.parquet' (row_group_size 55 + 102);

0 commit comments

Comments
 (0)