Skip to content

Commit 1ac3632

Browse files
authored
feat: Implicit transformation in set operation (#284)
* Some implicit conversions in the set operation have been implemented, but the specifics still need to be added * The max_type function that comes with Logicaltype is used to optimize the judgment logic * fmt
1 parent 5410cb2 commit 1ac3632

2 files changed

Lines changed: 93 additions & 58 deletions

File tree

src/binder/select.rs

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use crate::types::tuple::{Schema, SchemaRef};
3636
use crate::types::value::Utf8Type;
3737
use crate::types::{ColumnId, LogicalType};
3838
use itertools::Itertools;
39+
use sqlparser::ast::CharLengthUnits::Characters;
3940
use sqlparser::ast::{
4041
CharLengthUnits, Distinct, Expr, Ident, Join, JoinConstraint, JoinOperator, Offset,
4142
OrderByExpr, Query, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier,
@@ -156,6 +157,55 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
156157
Ok(plan)
157158
}
158159

160+
fn bind_set_cast(
161+
&self,
162+
mut left_plan: LogicalPlan,
163+
mut right_plan: LogicalPlan,
164+
) -> Result<(LogicalPlan, LogicalPlan), DatabaseError> {
165+
let mut left_cast = vec![];
166+
let mut right_cast = vec![];
167+
168+
let left_schema = left_plan.output_schema();
169+
let right_schema = right_plan.output_schema();
170+
171+
for (left_schema, right_schema) in left_schema.iter().zip(right_schema.iter()) {
172+
let cast_type =
173+
LogicalType::max_logical_type(left_schema.datatype(), right_schema.datatype())?;
174+
if &cast_type != left_schema.datatype() {
175+
left_cast.push(ScalarExpression::TypeCast {
176+
expr: Box::new(ScalarExpression::ColumnRef(left_schema.clone())),
177+
ty: cast_type.clone(),
178+
});
179+
} else {
180+
left_cast.push(ScalarExpression::ColumnRef(left_schema.clone()));
181+
}
182+
if &cast_type != right_schema.datatype() {
183+
right_cast.push(ScalarExpression::TypeCast {
184+
expr: Box::new(ScalarExpression::ColumnRef(right_schema.clone())),
185+
ty: cast_type.clone(),
186+
});
187+
} else {
188+
right_cast.push(ScalarExpression::ColumnRef(right_schema.clone()));
189+
}
190+
}
191+
192+
if left_cast.len() > 0 {
193+
left_plan = LogicalPlan::new(
194+
Operator::Project(ProjectOperator { exprs: left_cast }),
195+
Childrens::Only(left_plan),
196+
);
197+
}
198+
199+
if right_cast.len() > 0 {
200+
right_plan = LogicalPlan::new(
201+
Operator::Project(ProjectOperator { exprs: right_cast }),
202+
Childrens::Only(right_plan),
203+
);
204+
}
205+
206+
Ok((left_plan, right_plan))
207+
}
208+
159209
pub(crate) fn bind_set_operation(
160210
&mut self,
161211
op: &SetOperator,
@@ -169,30 +219,29 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
169219
};
170220
let mut left_plan = self.bind_set_expr(left)?;
171221
let mut right_plan = self.bind_set_expr(right)?;
172-
let fn_eq = |left_schema: &Schema, right_schema: &Schema| {
173-
let left_len = left_schema.len();
174222

175-
if left_len != right_schema.len() {
176-
return false;
177-
}
178-
for i in 0..left_len {
179-
if left_schema[i].datatype() != right_schema[i].datatype() {
180-
return false;
181-
}
182-
}
183-
true
184-
};
223+
let mut left_schema = left_plan.output_schema();
224+
let mut right_schema = right_plan.output_schema();
185225

186-
let left_schema = left_plan.output_schema();
187-
let right_schema = right_plan.output_schema();
226+
let left_len = left_schema.len();
188227

189-
if !fn_eq(left_schema, right_schema) {
228+
if left_len != right_schema.len() {
190229
return Err(DatabaseError::MisMatch(
191-
"the output types on the left",
192-
"the output types on the right",
230+
"the lens on the left",
231+
"the lens on the right",
193232
));
194233
}
195234

235+
if !left_schema
236+
.iter()
237+
.zip(right_schema.iter())
238+
.all(|(left, right)| left.datatype() == right.datatype())
239+
{
240+
(left_plan, right_plan) = self.bind_set_cast(left_plan, right_plan)?;
241+
left_schema = left_plan.output_schema();
242+
right_schema = right_plan.output_schema();
243+
}
244+
196245
match op {
197246
SetOperator::Union => {
198247
if is_all {

tests/slt/sql_2016/E071_05.slt

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,29 @@
11
# E071-05: Columns combined via table operators need not have exactly the same data type
22

3-
# TODO: Columns combined via table operators need not have exactly the same data type
4-
5-
# statement ok
6-
# CREATE TABLE TABLE_E071_05_01_011 ( ID INT PRIMARY KEY, A INT );
7-
8-
# statement ok
9-
# CREATE TABLE TABLE_E071_05_01_012 ( ID INT PRIMARY KEY, B FLOAT );
10-
11-
# SELECT A FROM TABLE_E071_05_01_011 UNION ALL SELECT B FROM TABLE_E071_05_01_012
12-
13-
# statement ok
14-
# CREATE TABLE TABLE_E071_05_01_021 ( ID INT PRIMARY KEY, A INT );
15-
16-
# statement ok
17-
# CREATE TABLE TABLE_E071_05_01_022 ( ID INT PRIMARY KEY, B FLOAT );
18-
19-
# SELECT A FROM TABLE_E071_05_01_021 UNION DISTINCT SELECT B FROM TABLE_E071_05_01_022
20-
21-
# statement ok
22-
# CREATE TABLE TABLE_E071_05_01_031 ( ID INT PRIMARY KEY, A INT );
23-
24-
# statement ok
25-
# CREATE TABLE TABLE_E071_05_01_032 ( ID INT PRIMARY KEY, B FLOAT );
26-
27-
# SELECT A FROM TABLE_E071_05_01_031 UNION SELECT B FROM TABLE_E071_05_01_032
28-
29-
# statement ok
30-
# CREATE TABLE TABLE_E071_05_02_011 ( ID INT PRIMARY KEY, A INT );
31-
32-
# statement ok
33-
# CREATE TABLE TABLE_E071_05_02_012 ( ID INT PRIMARY KEY, B FLOAT );
34-
35-
# SELECT A FROM TABLE_E071_05_02_011 EXCEPT DISTINCT SELECT B FROM TABLE_E071_05_02_012
36-
37-
# statement ok
38-
# CREATE TABLE TABLE_E071_05_02_021 ( ID INT PRIMARY KEY, A INT );
39-
40-
# statement ok
41-
# CREATE TABLE TABLE_E071_05_02_022 ( ID INT PRIMARY KEY, B FLOAT );
42-
43-
# SELECT A FROM TABLE_E071_05_02_021 EXCEPT SELECT B FROM TABLE_E071_05_02_022
3+
statement ok
4+
CREATE TABLE TABLE_E071_05_01_011 ( ID INT PRIMARY KEY, A INT, C FLOAT );
5+
6+
statement ok
7+
CREATE TABLE TABLE_E071_05_01_012 ( ID INT PRIMARY KEY, B FLOAT, D INT );
8+
9+
statement ok
10+
INSERT INTO TABLE_E071_05_01_011(ID,A,C) VALUES (0,1,1.2),(1,2,2.3),(2,1,5.4)
11+
12+
statement ok
13+
INSERT INTO TABLE_E071_05_01_012(ID,B,D) VALUES (1,2.12,23)
14+
15+
query II rowsort
16+
SELECT A,C FROM TABLE_E071_05_01_011 UNION ALL SELECT B,D FROM TABLE_E071_05_01_012
17+
----
18+
1.0 1.2
19+
1.0 5.4
20+
2.0 2.3
21+
2.12 23.0
22+
23+
query II rowsort
24+
SELECT B,D FROM TABLE_E071_05_01_012 UNION ALL SELECT A,C FROM TABLE_E071_05_01_011
25+
----
26+
1.0 1.2
27+
1.0 5.4
28+
2.0 2.3
29+
2.12 23.0

0 commit comments

Comments
 (0)