From e54e13fa1472bda6bb9a9119ca165f9a9f3cd121 Mon Sep 17 00:00:00 2001 From: lujiashun Date: Thu, 17 Nov 2022 14:16:09 +0800 Subject: [PATCH] fix(tianmu): fix query syntax (WHERE NOT IN ) is not supported. (#767) --- mysql-test/suite/tianmu/r/issue767.result | 152 ++++++++++++++++++++++ mysql-test/suite/tianmu/t/issue767.test | 49 +++++++ storage/tianmu/core/query.cpp | 87 ++++++++----- 3 files changed, 255 insertions(+), 33 deletions(-) create mode 100644 mysql-test/suite/tianmu/r/issue767.result create mode 100644 mysql-test/suite/tianmu/t/issue767.test diff --git a/mysql-test/suite/tianmu/r/issue767.result b/mysql-test/suite/tianmu/r/issue767.result new file mode 100644 index 000000000..5f62a2344 --- /dev/null +++ b/mysql-test/suite/tianmu/r/issue767.result @@ -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); +val +0 +1 +10 +11 +20 +21 +42 +43 +drop table t1; +drop table t2; diff --git a/mysql-test/suite/tianmu/t/issue767.test b/mysql-test/suite/tianmu/t/issue767.test new file mode 100644 index 000000000..f4e29c309 --- /dev/null +++ b/mysql-test/suite/tianmu/t/issue767.test @@ -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); + +drop table t1; +drop table t2; diff --git a/storage/tianmu/core/query.cpp b/storage/tianmu/core/query.cpp index 75859c35c..f2e1ec352 100644 --- a/storage/tianmu/core/query.cpp +++ b/storage/tianmu/core/query.cpp @@ -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(having)->functype() != Item_func::ISNOTNULLTEST_FUNC && + (down_cast(having)->functype() != Item_func::TRIG_COND_FUNC || + down_cast(having)->arguments()[0]->type() != Item::FUNC_ITEM || + down_cast(down_cast(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(having); // if the condition is a complex formula it must be AND if (having_cond->functype() != Item_func::COND_AND_FUNC) return false; @@ -1662,33 +1664,37 @@ 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(cond_removed)->functype() == Item_func::TRIG_COND_FUNC) { + cond_removed = down_cast(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(cond_removed)->arg_count != 2) return false; // the right side of equality is the field of the original subselect - if (dynamic_cast(((Item_func *)cond_removed)->arguments()[1]) == nullptr) + if (dynamic_cast(down_cast(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(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(having)->functype() == Item_func::ISNOTNULLTEST_FUNC || + down_cast(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(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(conds)->argument_list()->elements < 2) return false; - List_iterator li(*(((Item_cond *)conds)->argument_list())); + + List_iterator li(*(down_cast(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(conds)->argument_list(); cond_removed = cond_to_reinsert; } else { // if no conjunctive formula the original condition was empty @@ -1696,14 +1702,15 @@ bool Query::ClearSubselectTransformation(common::Operator &oper_for_subselect, I conds = nullptr; } if (cond_removed->type() == Item::FUNC_ITEM && - ((Item_func *)cond_removed)->functype() == Item_func::TRIG_COND_FUNC) { + down_cast(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(down_cast(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(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(cond_removed); List_iterator_fast li(*(cond_cond->argument_list())); cond_removed = li++; if (cond_removed == nullptr) @@ -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(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(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(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(left_ref)->real_item(); + if (left_ref->type() != Item::REF_ITEM || down_cast(left_ref)->ref_type() != Item_ref::DIRECT_REF || + down_cast(left_ref)->real_item() != left_expr_for_subselect) return false; // set the operation type - switch (((Item_func *)cond_removed)->functype()) { + switch (down_cast(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;