Skip to content

Commit e68ce0b

Browse files
authored
fix: forbid SRF in copy transform. (#18795)
1 parent be3f0c8 commit e68ce0b

File tree

5 files changed

+81
-32
lines changed

5 files changed

+81
-32
lines changed

src/query/ast/src/parser/copy.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,18 @@ fn copy_into_location(i: Input) -> IResult<Statement> {
125125
pub fn copy_into(i: Input) -> IResult<Statement> {
126126
rule!(
127127
#copy_into_location:"`COPY
128-
INTO { internalStage | externalStage | externalLocation }
128+
INTO { @<stage_name>[/<path>] | '<uri>' }
129129
FROM { [<database_name>.]<table_name> | ( <query> ) }
130-
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
130+
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV } [ formatTypeOptions ] } ) ]
131131
[ copyOptions ]`"
132132
| #copy_into_table: "`COPY
133133
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
134-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
134+
FROM { @<stage_name>[/<path>]
135+
| '<uri>'
136+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
135137
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
136138
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
137139
[ PATTERN = '<regex_pattern>' ]
138-
[ VALIDATION_MODE = RETURN_ROWS ]
139140
[ copyOptions ]`"
140141
)(i)
141142
}

src/query/ast/tests/it/testdata/stmt-error.txt

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -756,11 +756,12 @@ error:
756756
| |
757757
| while parsing `COPY
758758
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
759-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
759+
FROM { @<stage_name>[/<path>]
760+
| '<uri>'
761+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
760762
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
761763
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
762764
[ PATTERN = '<regex_pattern>' ]
763-
[ VALIDATION_MODE = RETURN_ROWS ]
764765
[ copyOptions ]`
765766

766767

@@ -787,11 +788,12 @@ error:
787788
| |
788789
| while parsing `COPY
789790
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
790-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
791+
FROM { @<stage_name>[/<path>]
792+
| '<uri>'
793+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
791794
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
792795
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
793796
[ PATTERN = '<regex_pattern>' ]
794-
[ VALIDATION_MODE = RETURN_ROWS ]
795797
[ copyOptions ]`
796798

797799

@@ -806,11 +808,12 @@ error:
806808
| |
807809
| while parsing `COPY
808810
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
809-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
811+
FROM { @<stage_name>[/<path>]
812+
| '<uri>'
813+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
810814
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
811815
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
812816
[ PATTERN = '<regex_pattern>' ]
813-
[ VALIDATION_MODE = RETURN_ROWS ]
814817
[ copyOptions ]`
815818

816819

@@ -825,11 +828,12 @@ error:
825828
| |
826829
| while parsing `COPY
827830
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
828-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
831+
FROM { @<stage_name>[/<path>]
832+
| '<uri>'
833+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
829834
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
830835
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
831836
[ PATTERN = '<regex_pattern>' ]
832-
[ VALIDATION_MODE = RETURN_ROWS ]
833837
[ copyOptions ]`
834838

835839

@@ -844,11 +848,12 @@ error:
844848
| |
845849
| while parsing `COPY
846850
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
847-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
851+
FROM { @<stage_name>[/<path>]
852+
| '<uri>'
853+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
848854
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
849855
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
850856
[ PATTERN = '<regex_pattern>' ]
851-
[ VALIDATION_MODE = RETURN_ROWS ]
852857
[ copyOptions ]`
853858

854859

@@ -863,11 +868,12 @@ error:
863868
| |
864869
| while parsing `COPY
865870
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
866-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
871+
FROM { @<stage_name>[/<path>]
872+
| '<uri>'
873+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
867874
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
868875
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
869876
[ PATTERN = '<regex_pattern>' ]
870-
[ VALIDATION_MODE = RETURN_ROWS ]
871877
[ copyOptions ]`
872878

873879

@@ -882,11 +888,12 @@ error:
882888
| |
883889
| while parsing `COPY
884890
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
885-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
891+
FROM { @<stage_name>[/<path>]
892+
| '<uri>'
893+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
886894
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
887895
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
888896
[ PATTERN = '<regex_pattern>' ]
889-
[ VALIDATION_MODE = RETURN_ROWS ]
890897
[ copyOptions ]`
891898

892899

@@ -901,11 +908,12 @@ error:
901908
| |
902909
| while parsing `COPY
903910
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
904-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
911+
FROM { @<stage_name>[/<path>]
912+
| '<uri>'
913+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
905914
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
906915
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
907916
[ PATTERN = '<regex_pattern>' ]
908-
[ VALIDATION_MODE = RETURN_ROWS ]
909917
[ copyOptions ]`
910918

911919

@@ -923,11 +931,12 @@ error:
923931
1 | COPY INTO mytable
924932
| ---- while parsing `COPY
925933
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
926-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
934+
FROM { @<stage_name>[/<path>]
935+
| '<uri>'
936+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
927937
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
928938
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
929939
[ PATTERN = '<regex_pattern>' ]
930-
[ VALIDATION_MODE = RETURN_ROWS ]
931940
[ copyOptions ]`
932941
2 | FROM @my_stage
933942
3 | FILE_FORMAT = (
@@ -1279,11 +1288,12 @@ error:
12791288
| |
12801289
| while parsing `COPY
12811290
INTO { [<database_name>.]<table_name> { ( <columns> ) } }
1282-
FROM { internalStage | externalStage | externalLocation | ( <query> ) }
1291+
FROM { @<stage_name>[/<path>]
1292+
| '<uri>'
1293+
| ( select <expr>, [ <expr> ...] from {@<stage_name>[/<path>]( <args> ) | '<uri>'} ) }
12831294
[ FILE_FORMAT = ( { TYPE = { CSV | NDJSON | PARQUET | TSV | AVRO } [ formatTypeOptions ] } ) ]
12841295
[ FILES = ( '<file_name>' [ , '<file_name>' ] [ , ... ] ) ]
12851296
[ PATTERN = '<regex_pattern>' ]
1286-
[ VALIDATION_MODE = RETURN_ROWS ]
12871297
[ copyOptions ]`
12881298

12891299

src/query/sql/src/planner/binder/binder.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use databend_common_expression::types::DataType;
3434
use databend_common_expression::Constant;
3535
use databend_common_expression::ConstantFolder;
3636
use databend_common_expression::Expr;
37+
use databend_common_expression::FunctionKind;
3738
use databend_common_expression::SEARCH_MATCHED_COLUMN_ID;
3839
use databend_common_expression::SEARCH_SCORE_COLUMN_ID;
3940
use databend_common_functions::BUILTIN_FUNCTIONS;
@@ -1006,13 +1007,17 @@ impl Binder {
10061007
&self,
10071008
scalar: &ScalarExpr,
10081009
) -> Result<bool> {
1009-
let f = |scalar: &ScalarExpr| {
1010-
matches!(
1011-
scalar,
1012-
ScalarExpr::AggregateFunction(_)
1013-
| ScalarExpr::WindowFunction(_)
1014-
| ScalarExpr::AsyncFunctionCall(_)
1015-
)
1010+
let f = |scalar: &ScalarExpr| match scalar {
1011+
ScalarExpr::AggregateFunction(_)
1012+
| ScalarExpr::WindowFunction(_)
1013+
| ScalarExpr::UDAFCall(_)
1014+
| ScalarExpr::SubqueryExpr(_)
1015+
| ScalarExpr::AsyncFunctionCall(_) => true,
1016+
ScalarExpr::FunctionCall(func) => BUILTIN_FUNCTIONS
1017+
.get_property(&func.func_name)
1018+
.map(|property| property.kind == FunctionKind::SRF)
1019+
.unwrap_or(true),
1020+
_ => false,
10161021
};
10171022
let mut finder = Finder::new(&f);
10181023
finder.visit(scalar)?;

src/query/sql/src/planner/binder/copy_into_table.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ impl Binder {
496496
if !self.check_allowed_scalar_expr_with_subquery_for_copy_table(&item.scalar)? {
497497
// in fact, if there is a join, we will stop in `check_transform_query()`
498498
return Err(ErrorCode::SemanticError(
499-
"copy into table source can't contain window|aggregate|join functions"
499+
"copy into <table> can't contain aggregate|flatten|window functions"
500500
.to_string(),
501501
));
502502
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
statement error unexpected `\(`
2+
copy into t1 from(select * from (select 1))
3+
4+
statement error unexpected `where`
5+
copy into t1 from (select a from @s1 where a > 1)
6+
7+
statement error unexpected `order`
8+
copy into t1 from (select a from @s1 order by a)
9+
10+
statement error unexpected `,`
11+
copy into t1 from (select a, b from '@s1', t2)
12+
13+
statement error unexpected `group`
14+
copy into t1 from (select a from @s1 group by a)
15+
16+
statement ok
17+
create or replace stage s1;
18+
19+
statement ok
20+
copy into @s1 from (select 1)
21+
22+
23+
statement ok
24+
create or replace table t1(a int);
25+
26+
statement error can't contain aggregate|flatten|window functions
27+
copy into t1 from (select JSON_ARRAY_ELEMENTS(parse_json($1)) as c1 from @s1);
28+
29+
statement error can't contain aggregate|flatten|window functions
30+
copy into t1 from (select sum($1::int) as c1 from @s1) file_format=(type=csv);
31+
32+
statement error can't contain aggregate|flatten|window functions
33+
copy into t1 from (select rank() OVER (ORDER BY $1), $1 from @s1) file_format=(type=csv);

0 commit comments

Comments
 (0)