Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(tianmu): fix query syntax (WHERE NOT IN ) is not supported. (#767) #910

Merged
merged 1 commit into from
Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions mysql-test/suite/tianmu/r/issue767.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use test;
create table t1(val int) ENGINE=tianmu;
create table t2(val2 int) ENGINE=tianmu;
insert into t1 values(0);
insert into t1 values(1);
insert into t1 values(10);
insert into t1 values(11);
insert into t1 values(20);
insert into t1 values(21);
insert into t1 values(42);
insert into t1 values(43);
insert into t2 values(0);
insert into t2 values(1);
insert into t2 values(10);
insert into t2 values(11);
insert into t2 values(20);
insert into t2 values(21);
insert into t2 values(42);
insert into t2 values(43);
select * from t1 where 42 not in (select * from t1 where val > 42);
val
0
1
10
11
20
21
42
43
select * from t1 where 42 not in (select * from t1 where val < 10);
val
0
1
10
11
20
21
42
43
select * from t1 where 42 not in (select * from t1 where val >= 42);
val
select * from t1 where 42 not in (select * from t1 where val <= 10);
val
0
1
10
11
20
21
42
43
insert into t2 values(10);
select * from t1 where val not in (select * from t2 where val2 > 10);
val
0
1
10
select * from t1 where val not in (select * from t2 where val2 >= 10);
val
0
1
select * from t1 where val not in (select * from t2 where val2 < 10);
val
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 <=10);
val
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 > t1.val);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 >= t1.val);
val
select * from t1 where val not in (select * from t2 where val2 < t1.val);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 <= t1.val);
val
select * from t1 where val not in (select * from t2 where val2 > t1.val and val2 >t1.val +10);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 >= t1.val and val2 >= t1.val +10);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 < t1.val and val2 <t1.val +10);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 <= t1.val and val2 >= t1.val +10);
val
0
1
10
11
20
21
42
43
select * from t1 where val not in (select * from t2 where val2 > t1.val);
val
0
1
10
11
20
21
42
43
drop table t1;
drop table t2;
49 changes: 49 additions & 0 deletions mysql-test/suite/tianmu/t/issue767.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--source include/have_tianmu.inc
use test;
create table t1(val int) ENGINE=tianmu;
create table t2(val2 int) ENGINE=tianmu;

insert into t1 values(0);
insert into t1 values(1);
insert into t1 values(10);
insert into t1 values(11);
insert into t1 values(20);
insert into t1 values(21);
insert into t1 values(42);
insert into t1 values(43);
insert into t2 values(0);
insert into t2 values(1);
insert into t2 values(10);
insert into t2 values(11);
insert into t2 values(20);
insert into t2 values(21);
insert into t2 values(42);
insert into t2 values(43);

#original case(just test not in)
select * from t1 where 42 not in (select * from t1 where val > 42);
select * from t1 where 42 not in (select * from t1 where val < 10);
select * from t1 where 42 not in (select * from t1 where val >= 42);
select * from t1 where 42 not in (select * from t1 where val <= 10);

#independent subquery
insert into t2 values(10);
select * from t1 where val not in (select * from t2 where val2 > 10);
select * from t1 where val not in (select * from t2 where val2 >= 10);
select * from t1 where val not in (select * from t2 where val2 < 10);
select * from t1 where val not in (select * from t2 where val2 <=10);

#dependent subquery
select * from t1 where val not in (select * from t2 where val2 > t1.val);
select * from t1 where val not in (select * from t2 where val2 >= t1.val);
select * from t1 where val not in (select * from t2 where val2 < t1.val);
select * from t1 where val not in (select * from t2 where val2 <= t1.val);

select * from t1 where val not in (select * from t2 where val2 > t1.val and val2 >t1.val +10);
select * from t1 where val not in (select * from t2 where val2 >= t1.val and val2 >= t1.val +10);
select * from t1 where val not in (select * from t2 where val2 < t1.val and val2 <t1.val +10);
select * from t1 where val not in (select * from t2 where val2 <= t1.val and val2 >= t1.val +10);
select * from t1 where val not in (select * from t2 where val2 > t1.val);

drop table t1;
drop table t2;
87 changes: 54 additions & 33 deletions storage/tianmu/core/query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1632,15 +1632,17 @@ bool Query::ClearSubselectTransformation(common::Operator &oper_for_subselect, I
Item *left_expr_for_subselect) {
cond_to_reinsert = nullptr;
list_to_reinsert = nullptr;
Item *cond_removed;
if (having &&
(having->type() == Item::COND_ITEM ||
(having->type() == Item::FUNC_ITEM && ((Item_func *)having)->functype() != Item_func::ISNOTNULLTEST_FUNC &&
(((Item_func *)having)->functype() != Item_func::TRIG_COND_FUNC ||
((Item_func *)having)->arguments()[0]->type() != Item::FUNC_ITEM ||
((Item_func *)((Item_func *)having)->arguments()[0])->functype() != Item_func::ISNOTNULLTEST_FUNC)))) {
Item *cond_removed = nullptr;
Item *left_ref = nullptr;
if (having && (having->type() == Item::COND_ITEM ||
(having->type() == Item::FUNC_ITEM &&
down_cast<Item_func *>(having)->functype() != Item_func::ISNOTNULLTEST_FUNC &&
(down_cast<Item_func *>(having)->functype() != Item_func::TRIG_COND_FUNC ||
down_cast<Item_func *>(having)->arguments()[0]->type() != Item::FUNC_ITEM ||
down_cast<Item_func *>(down_cast<Item_func *>(having)->arguments()[0])->functype() !=
Item_func::ISNOTNULLTEST_FUNC)))) {
if (having->type() == Item::COND_ITEM) {
Item_cond *having_cond = (Item_cond *)having;
Item_cond *having_cond = down_cast<Item_cond *>(having);
// if the condition is a complex formula it must be AND
if (having_cond->functype() != Item_func::COND_AND_FUNC)
return false;
Expand All @@ -1662,48 +1664,53 @@ bool Query::ClearSubselectTransformation(common::Operator &oper_for_subselect, I
cond_removed = UnRef(cond_removed);
// check if the extra condition was wrapped into trigger
if (cond_removed->type() == Item::FUNC_ITEM &&
((Item_func *)cond_removed)->functype() == Item_func::TRIG_COND_FUNC) {
cond_removed = ((Item_func *)cond_removed)->arguments()[0];
down_cast<Item_func *>(cond_removed)->functype() == Item_func::TRIG_COND_FUNC) {
cond_removed = down_cast<Item_func *>(cond_removed)->arguments()[0];
cond_removed = UnRef(cond_removed);
}
// check if the extra condition is a comparison
if (cond_removed->type() != Item::FUNC_ITEM || ((Item_func *)cond_removed)->arg_count != 2)
if (cond_removed->type() != Item::FUNC_ITEM || down_cast<Item_func *>(cond_removed)->arg_count != 2)
return false;
// the right side of equality is the field of the original subselect
if (dynamic_cast<Item_ref_null_helper *>(((Item_func *)cond_removed)->arguments()[1]) == nullptr)
if (dynamic_cast<Item_ref_null_helper *>(down_cast<Item_func *>(cond_removed)->arguments()[1]) == nullptr)
return false;
field_for_subselect = nullptr;
// the left side of equality should be the left side of the original
// expression with subselect
left_ref = down_cast<Item_func *>(cond_removed)->arguments()[0];
} else if (!having || (having->type() == Item::FUNC_ITEM &&
(((Item_func *)having)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
((Item_func *)having)->functype() == Item_func::TRIG_COND_FUNC))) {
(down_cast<Item_func *>(having)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
down_cast<Item_func *>(having)->functype() == Item_func::TRIG_COND_FUNC))) {
if (!conds)
return false;
if (conds->type() == Item::COND_ITEM && ((Item_cond *)conds)->functype() == Item_func::COND_AND_FUNC) {
if (conds->type() == Item::COND_ITEM && down_cast<Item_cond *>(conds)->functype() == Item_func::COND_AND_FUNC) {
// if the condition is a conjunctive formula
// the extra condition should be in the last argument
if (((Item_cond *)conds)->argument_list()->elements < 2)
if (down_cast<Item_cond *>(conds)->argument_list()->elements < 2)
return false;
List_iterator<Item> li(*(((Item_cond *)conds)->argument_list()));

List_iterator<Item> li(*(down_cast<Item_cond *>(conds)->argument_list()));
while (li++ != nullptr) cond_to_reinsert = *li.ref();
li.rewind();
while (*li.ref() != cond_to_reinsert) li++;
li.remove();
list_to_reinsert = ((Item_cond *)conds)->argument_list();
list_to_reinsert = down_cast<Item_cond *>(conds)->argument_list();
cond_removed = cond_to_reinsert;
} else {
// if no conjunctive formula the original condition was empty
cond_removed = conds;
conds = nullptr;
}
if (cond_removed->type() == Item::FUNC_ITEM &&
((Item_func *)cond_removed)->functype() == Item_func::TRIG_COND_FUNC) {
down_cast<Item_func *>(cond_removed)->functype() == Item_func::TRIG_COND_FUNC) {
// Condition was wrapped into trigger
cond_removed = (Item_cond *)((Item_func *)cond_removed)->arguments()[0];
cond_removed = down_cast<Item_cond *>(down_cast<Item_func *>(cond_removed)->arguments()[0]);
}
if (cond_removed->type() == Item::COND_ITEM && ((Item_func *)cond_removed)->functype() == Item_func::COND_OR_FUNC) {
if (cond_removed->type() == Item::COND_ITEM &&
down_cast<Item_func *>(cond_removed)->functype() == Item_func::COND_OR_FUNC) {
// if the subselect field could have null values
// equality condition was OR-ed with IS nullptr condition
Item_cond *cond_cond = (Item_cond *)cond_removed;
Item_cond *cond_cond = down_cast<Item_cond *>(cond_removed);
List_iterator_fast<Item> li(*(cond_cond->argument_list()));
cond_removed = li++;
if (cond_removed == nullptr)
Expand All @@ -1716,24 +1723,38 @@ bool Query::ClearSubselectTransformation(common::Operator &oper_for_subselect, I
having = nullptr;
}
// check if the extra condition is a comparison
if (cond_removed->type() != Item::FUNC_ITEM || ((Item_func *)cond_removed)->arg_count != 2)
if (cond_removed->type() != Item::FUNC_ITEM || down_cast<Item_func *>(cond_removed)->arg_count != 2)
return false;
// the right side of equality is the field of the original subselect
field_for_subselect = ((Item_func *)cond_removed)->arguments()[1];

auto item_func = down_cast<Item_func *>(cond_removed);
if (item_func->arguments()[0]->type() == Item::REF_ITEM) {
// the right side of equality is the field of the original subselect
field_for_subselect = item_func->arguments()[1];
// the left side of equality should be the left side of the original
// expression with subselect
left_ref = item_func->arguments()[0];
} else if (item_func->arguments()[1]->type() == Item::REF_ITEM) {
// ref #767
// the left side of equality is the field of the original subselect
field_for_subselect = item_func->arguments()[0];
// the right side of equality should be the left side of the original
// expression with subselect
left_ref = item_func->arguments()[1];
} else {
return false;
}
} else
return false;
// the left side of equality should be the left side of the original
// expression with subselect
Item *left_ref = ((Item_func *)cond_removed)->arguments()[0];

if (dynamic_cast<Item_int_with_ref *>(left_ref) != nullptr)
left_ref = ((Item_int_with_ref *)left_ref)->real_item();
if (left_ref->type() != Item::REF_ITEM || ((Item_ref *)left_ref)->ref_type() != Item_ref::DIRECT_REF ||
((Item_ref *)left_ref)->real_item() != left_expr_for_subselect)
left_ref = down_cast<Item_int_with_ref *>(left_ref)->real_item();
if (left_ref->type() != Item::REF_ITEM || down_cast<Item_ref *>(left_ref)->ref_type() != Item_ref::DIRECT_REF ||
down_cast<Item_ref *>(left_ref)->real_item() != left_expr_for_subselect)
return false;
// set the operation type
switch (((Item_func *)cond_removed)->functype()) {
switch (down_cast<Item_func *>(cond_removed)->functype()) {
case Item_func::EQ_FUNC:
oper_for_subselect = common::Operator::O_IN; /*common::Operator::common::Operator::O_IN;*/
oper_for_subselect = common::Operator::O_IN;
break;
case Item_func::NE_FUNC:
oper_for_subselect = common::Operator::O_NOT_EQ;
Expand Down