diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index dc65c68f8..27c77d8a8 100755 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -59,6 +59,7 @@ using namespace logging; #include "ha_mcs_impl_if.h" #include "ha_mcs_sysvars.h" #include "ha_subquery.h" +#include "ha_mcs_pushdown.h" using namespace cal_impl_if; #include "calpontselectexecutionplan.h" @@ -136,6 +137,142 @@ public: namespace cal_impl_if { +// This is taken from Item_cond::fix_fields in sql/item_cmpfunc.cc. +void calculateNotNullTables(const std::vector& condList, + table_map& not_null_tables) +{ + for (Item* item : condList) + { + if (item->can_eval_in_optimize() && !item->with_sp_var() && + !cond_has_datetime_is_null(item)) + { + if (item->eval_const_cond()) + { + } + else + { + not_null_tables = (table_map) 0; + } + } + else + { + not_null_tables |= item->not_null_tables(); + } + } +} + +// Recursively iterate through the join_list and store all non-null +// TABLE_LIST::on_expr items to a hash map keyed by the TABLE_LIST ptr. +// This is then used by convertOuterJoinToInnerJoin(). +void buildTableOnExprList(List* join_list, + TableOnExprList& tableOnExprList) +{ + TABLE_LIST *table; + NESTED_JOIN *nested_join; + List_iterator li(*join_list); + + while ((table = li++)) + { + if ((nested_join = table->nested_join)) + { + buildTableOnExprList(&nested_join->join_list, tableOnExprList); + } + + if (table->on_expr) + tableOnExprList[table].push_back(table->on_expr); + } +} + +// This is a trimmed down version of simplify_joins() in sql/sql_select.cc. +// Refer to that function for more details. But we have customized the +// original implementation in simplify_joins() to avoid any changes to +// the SELECT_LEX::JOIN::conds. Specifically, in some cases, simplify_joins() +// would create new Item_cond_and objects. We want to avoid such changes to +// the SELECT_LEX in a scenario where the select_handler execution has failed +// and we want to fallback to the server execution (MCOL-4525). Here, we mimick +// the creation of Item_cond_and using tableOnExprList and condList. +void convertOuterJoinToInnerJoin(List* join_list, + TableOnExprList& tableOnExprList, + std::vector& condList, + TableOuterJoinMap& tableOuterJoinMap) +{ + TABLE_LIST *table; + NESTED_JOIN *nested_join; + List_iterator li(*join_list); + + while ((table = li++)) + { + table_map used_tables; + table_map not_null_tables = (table_map) 0; + + if ((nested_join = table->nested_join)) + { + auto iter = tableOnExprList.find(table); + + if ((iter != tableOnExprList.end()) && !iter->second.empty()) + { + convertOuterJoinToInnerJoin(&nested_join->join_list, + tableOnExprList, tableOnExprList[table], tableOuterJoinMap); + } + + nested_join->used_tables = (table_map) 0; + nested_join->not_null_tables = (table_map) 0; + + convertOuterJoinToInnerJoin(&nested_join->join_list, + tableOnExprList, condList, tableOuterJoinMap); + + used_tables = nested_join->used_tables; + not_null_tables = nested_join->not_null_tables; + } + else + { + used_tables = table->get_map(); + + if (!condList.empty()) + { + if (condList.size() == 1) + { + not_null_tables = condList[0]->not_null_tables(); + } + else + { + calculateNotNullTables(condList, not_null_tables); + } + } + } + + if (table->embedding) + { + table->embedding->nested_join->used_tables |= used_tables; + table->embedding->nested_join->not_null_tables |= not_null_tables; + } + + if (!(table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) || + (used_tables & not_null_tables)) + { + if (table->outer_join) + { + tableOuterJoinMap[table] = table->outer_join; + } + + table->outer_join = 0; + + auto iter = tableOnExprList.find(table); + + if (iter != tableOnExprList.end() && !iter->second.empty()) + { + // The original implementation in simplify_joins() creates + // an Item_cond_and object here. Instead of doing so, we + // append the table->on_expr to the condList and hence avoid + // making any permanent changes to SELECT_LEX::JOIN::conds. + condList.insert(condList.end(), + tableOnExprList[table].begin(), tableOnExprList[table].end()); + iter->second.clear(); + } + } + } +} + CalpontSystemCatalog::TableAliasName makeTableAliasName(TABLE_LIST* table) { return make_aliasview( @@ -1281,10 +1418,24 @@ uint32_t buildJoin(gp_walk_info& gwi, List& join_list, if (table->nested_join && !table->derived) buildJoin(gwi, table->nested_join->join_list, outerJoinStack); - if (table->on_expr) - { - Item_cond* expr = reinterpret_cast(table->on_expr); + std::vector tableOnExprList; + auto iter = gwi.tableOnExprList.find(table); + + // Check if this table's on_expr is available in the hash map + // built/updated during convertOuterJoinToInnerJoin(). + if ((iter != gwi.tableOnExprList.end()) && !iter->second.empty()) + { + tableOnExprList = iter->second; + } + // This table's on_expr has not been seen/processed before. + else if ((iter == gwi.tableOnExprList.end()) && table->on_expr) + { + tableOnExprList.push_back(table->on_expr); + } + + if (!tableOnExprList.empty()) + { if (table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) { // inner tables block @@ -1312,18 +1463,23 @@ uint32_t buildJoin(gp_walk_info& gwi, List& join_list, cerr << endl; cerr << " outer table expression: " << endl; - expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); + + for (Item* expr : tableOnExprList) + expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); #endif - expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); - - // Error out subquery in outer join on filter for now - if (gwi_outer.hasSubSelect) + for (Item* expr : tableOnExprList) { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_OUTER_JOIN_SUBSELECT); - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText); - return -1; + expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); + + // Error out subquery in outer join on filter for now + if (gwi_outer.hasSubSelect) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_OUTER_JOIN_SUBSELECT); + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText); + return -1; + } } // build outerjoinon filter @@ -1356,11 +1512,15 @@ uint32_t buildJoin(gp_walk_info& gwi, List& join_list, } else // inner join { - expr->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + for (Item* expr : tableOnExprList) + { + expr->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + } #ifdef DEBUG_WALK_COND cerr << " inner join expression: " << endl; - expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + for (Item* expr : tableOnExprList) + expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); #endif } } @@ -2667,6 +2827,22 @@ void setError(THD* thd, uint32_t errcode, string errmsg, gp_walk_info& gwi) clearStacks(gwi); } +int setErrorAndReturn(gp_walk_info &gwi) +{ + // if this is dervied table process phase, mysql may have not developed the plan + // completely. Do not error and eventually mysql will call JOIN::exec() again. + // related to bug 2922. Need to find a way to skip calling rnd_init for derived table + // processing. + if (gwi.thd->derived_tables_processing) + { + gwi.cs_vtable_is_update_with_derive = true; + return -1; + } + + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; +} + const string bestTableName(const Item_field* ifp) { idbassert(ifp); @@ -6364,7 +6540,6 @@ int processFrom(bool &isUnion, csep->distinctUnionNum(distUnionNum); } - return 0; } @@ -6382,24 +6557,24 @@ int processWhere(SELECT_LEX &select_lex, const std::vector& condStack) { JOIN* join = select_lex.join; - Item_cond* icp = 0; + Item* icp = 0; bool isUpdateDelete = false; // Flag to indicate if this is a prepared statement bool isPS = gwi.thd->stmt_arena && gwi.thd->stmt_arena->is_stmt_execute(); if (join != 0 && !isPS) - icp = reinterpret_cast(join->conds); + icp = join->conds; else if (isPS && select_lex.prep_where) - icp = (Item_cond*)(select_lex.prep_where); + icp = select_lex.prep_where; // if icp is null, try to find the where clause other where if (!join && gwi.thd->lex->derived_tables) { if (select_lex.prep_where) - icp = (Item_cond*)(select_lex.prep_where); + icp = select_lex.prep_where; else if (select_lex.where) - icp = (Item_cond*)(select_lex.where); + icp = select_lex.where; } else if (!join && ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || @@ -6429,20 +6604,7 @@ int processWhere(SELECT_LEX &select_lex, if (gwi.fatalParseError) { - // if this is dervied table process phase, mysql may have not developed the plan - // completely. Do not error and eventually mysql will call JOIN::exec() again. - // related to bug 2922. Need to find a way to skip calling rnd_init for derived table - // processing. - if (gwi.thd->derived_tables_processing) - { - // MCOL-2178 isUnion member only assigned, never used - //MIGR::infinidb_vtable.isUnion = false; - gwi.cs_vtable_is_update_with_derive = true; - return -1; - } - - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; + return setErrorAndReturn(gwi); } } else if (isUpdateDelete) @@ -6460,33 +6622,19 @@ int processWhere(SELECT_LEX &select_lex, if (gwi.fatalParseError) { - if (gwi.thd->derived_tables_processing) - { - gwi.cs_vtable_is_update_with_derive = true; - return -1; - } - - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; + return setErrorAndReturn(gwi); } } } // if condStack is empty(), check the select_lex for where conditions // as a last resort - else if ((icp = reinterpret_cast(select_lex.where)) != 0) + else if ((icp = select_lex.where) != 0) { icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); if (gwi.fatalParseError) { - if (gwi.thd->derived_tables_processing) - { - gwi.cs_vtable_is_update_with_derive = true; - return -1; - } - - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; + return setErrorAndReturn(gwi); } } } @@ -6496,6 +6644,19 @@ int processWhere(SELECT_LEX &select_lex, (dynamic_cast(gwi.rcWorkStack.top()))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); } + for (Item* item : gwi.condList) + { + if (item && (item != icp)) + { + item->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + + if (gwi.fatalParseError) + { + return setErrorAndReturn(gwi); + } + } + } + // ZZ - the followinig debug shows the structure of nested outer join. should // use a recursive function. #ifdef OUTER_JOIN_DEBUG @@ -8352,9 +8513,9 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) return 0; } -int cs_get_derived_plan(derived_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) +int cs_get_derived_plan(ha_columnstore_derived_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) { - SELECT_LEX select_lex = *handler->select; + SELECT_LEX& select_lex = *handler->select; int status = getSelectPlan(gwi, select_lex, csep, false); if (status > 0) @@ -8372,9 +8533,20 @@ int cs_get_derived_plan(derived_handler* handler, THD* thd, SCSEP& csep, gp_walk return 0; } -int cs_get_select_plan(select_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) +int cs_get_select_plan(ha_columnstore_select_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) { - SELECT_LEX select_lex = *handler->select; + SELECT_LEX& select_lex = *handler->select; + + if (select_lex.where) + { + gwi.condList.push_back(select_lex.where); + } + + buildTableOnExprList(&select_lex.top_join_list, gwi.tableOnExprList); + + convertOuterJoinToInnerJoin(&select_lex.top_join_list, + gwi.tableOnExprList, gwi.condList, handler->tableOuterJoinMap); + int status = getSelectPlan(gwi, select_lex, csep, false, true); if (status > 0) diff --git a/dbcon/mysql/ha_mcs_impl.cpp b/dbcon/mysql/ha_mcs_impl.cpp index 63fb8c026..0f9f91e29 100644 --- a/dbcon/mysql/ha_mcs_impl.cpp +++ b/dbcon/mysql/ha_mcs_impl.cpp @@ -4679,8 +4679,8 @@ int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table) sm::cpsm_conhdl_t* hndl; SCSEP csep; // Declare handlers ptrs in this scope for future use. - select_handler* sh = nullptr; - derived_handler* dh = nullptr; + ha_columnstore_select_handler* sh = nullptr; + ha_columnstore_derived_handler* dh = nullptr; // update traceFlags according to the autoswitch state. ci->traceFlags = (ci->traceFlags | CalpontSelectExecutionPlan::TRACE_TUPLE_OFF)^ @@ -4774,12 +4774,12 @@ int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table) int status = 42; if (handler_info->hndl_type == mcs_handler_types_t::SELECT) { - sh = reinterpret_cast(handler_info->hndl_ptr); + sh = reinterpret_cast(handler_info->hndl_ptr); status = cs_get_select_plan(sh, thd, csep, gwi); } else if (handler_info->hndl_type == DERIVED) { - dh = reinterpret_cast(handler_info->hndl_ptr); + dh = reinterpret_cast(handler_info->hndl_ptr); status = cs_get_derived_plan(dh, thd, csep, gwi); } diff --git a/dbcon/mysql/ha_mcs_impl_if.h b/dbcon/mysql/ha_mcs_impl_if.h index 35397f8d0..69327c004 100644 --- a/dbcon/mysql/ha_mcs_impl_if.h +++ b/dbcon/mysql/ha_mcs_impl_if.h @@ -34,6 +34,8 @@ #include "idb_mysql.h" struct st_ha_create_information; +class ha_columnstore_select_handler; +class ha_columnstore_derived_handler; #include "configcpp.h" #include "idberrorinfo.h" @@ -89,7 +91,8 @@ enum ClauseType typedef std::vector JoinInfoVec; typedef std::map > TableMap; - +typedef std::tr1::unordered_map> TableOnExprList; +typedef std::tr1::unordered_map TableOuterJoinMap; struct gp_walk_info { @@ -164,6 +167,10 @@ struct gp_walk_info execplan::ReturnedColumn* inSubQueryLHS; Item* inSubQueryLHSItem; + // The below 2 fields are required for MCOL-4525. + TableOnExprList tableOnExprList; + std::vector condList; + gp_walk_info() : sessionid(0), fatalParseError(false), condPush(false), @@ -348,8 +355,8 @@ const std::string infinidb_err_msg = "\nThe query includes syntax that is not su int cp_get_plan(THD* thd, execplan::SCSEP& csep); int cp_get_table_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_table_info& ti); int cp_get_group_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_group_info& gi); -int cs_get_derived_plan(derived_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); -int cs_get_select_plan(select_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); +int cs_get_derived_plan(ha_columnstore_derived_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); +int cs_get_select_plan(ha_columnstore_select_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false, bool isSelectHandlerTop = false, const std::vector& condStack = std::vector()); int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, cal_group_info& gi, bool isUnion = false); void setError(THD* thd, uint32_t errcode, const std::string errmsg, gp_walk_info* gwi); diff --git a/dbcon/mysql/ha_mcs_opt_rewrites.cpp b/dbcon/mysql/ha_mcs_opt_rewrites.cpp index af8ca011a..1e41089db 100644 --- a/dbcon/mysql/ha_mcs_opt_rewrites.cpp +++ b/dbcon/mysql/ha_mcs_opt_rewrites.cpp @@ -19,234 +19,6 @@ #include "ha_mcs_opt_rewrites.h" -// Search simplify_joins() function in the server's code for detail -COND * -simplify_joins_mcs(JOIN *join, List *join_list, COND *conds, bool top, - bool in_sj) -{ - TABLE_LIST *table; - NESTED_JOIN *nested_join; - TABLE_LIST *prev_table= 0; - List_iterator li(*join_list); - bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN); - DBUG_ENTER("simplify_joins_mcs"); - - /* - Try to simplify join operations from join_list. - The most outer join operation is checked for conversion first. - */ - while ((table= li++)) - { - table_map used_tables; - table_map not_null_tables= (table_map) 0; - - if ((nested_join= table->nested_join)) - { - /* - If the element of join_list is a nested join apply - the procedure to its nested join list first. - */ - if (table->on_expr) - { - Item *expr= table->on_expr; - /* - If an on expression E is attached to the table, - check all null rejected predicates in this expression. - If such a predicate over an attribute belonging to - an inner table of an embedded outer join is found, - the outer join is converted to an inner join and - the corresponding on expression is added to E. - */ - expr= simplify_joins_mcs(join, &nested_join->join_list, - expr, FALSE, in_sj || table->sj_on_expr); - - if (!table->prep_on_expr || expr != table->on_expr) - { - DBUG_ASSERT(expr); - - table->on_expr= expr; - table->prep_on_expr= expr->copy_andor_structure(join->thd); - } - } - nested_join->used_tables= (table_map) 0; - nested_join->not_null_tables=(table_map) 0; - conds= simplify_joins_mcs(join, &nested_join->join_list, conds, top, - in_sj || table->sj_on_expr); - used_tables= nested_join->used_tables; - not_null_tables= nested_join->not_null_tables; - /* The following two might become unequal after table elimination: */ - nested_join->n_tables= nested_join->join_list.elements; - } - else - { - if (!table->prep_on_expr) - table->prep_on_expr= table->on_expr; - used_tables= table->get_map(); - if (conds) - not_null_tables= conds->not_null_tables(); - } - - if (table->embedding) - { - table->embedding->nested_join->used_tables|= used_tables; - table->embedding->nested_join->not_null_tables|= not_null_tables; - } - - if (!(table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) || - (used_tables & not_null_tables)) - { - /* - For some of the inner tables there are conjunctive predicates - that reject nulls => the outer join can be replaced by an inner join. - */ - if (table->outer_join && !table->embedding && table->table) - table->table->maybe_null= FALSE; - table->outer_join= 0; - if (!(straight_join || table->straight)) - { - table->dep_tables= 0; - TABLE_LIST *embedding= table->embedding; - while (embedding) - { - if (embedding->nested_join->join_list.head()->outer_join) - { - if (!embedding->sj_subq_pred) - table->dep_tables= embedding->dep_tables; - break; - } - embedding= embedding->embedding; - } - } - if (table->on_expr) - { - /* Add ON expression to the WHERE or upper-level ON condition. */ - if (conds) - { - conds= and_conds(join->thd, conds, table->on_expr); - conds->top_level_item(); - /* conds is always a new item as both cond and on_expr existed */ - DBUG_ASSERT(!conds->fixed()); - conds->fix_fields(join->thd, &conds); - } - else - conds= table->on_expr; - table->prep_on_expr= table->on_expr= 0; - } - } - - /* - Only inner tables of non-convertible outer joins - remain with on_expr. - */ - if (table->on_expr) - { - table_map table_on_expr_used_tables= table->on_expr->used_tables(); - table->dep_tables|= table_on_expr_used_tables; - if (table->embedding) - { - table->dep_tables&= ~table->embedding->nested_join->used_tables; - /* - Embedding table depends on tables used - in embedded on expressions. - */ - table->embedding->on_expr_dep_tables|= table_on_expr_used_tables; - } - else - table->dep_tables&= ~table->get_map(); - } - - if (prev_table) - { - /* The order of tables is reverse: prev_table follows table */ - if (prev_table->straight || straight_join) - prev_table->dep_tables|= used_tables; - if (prev_table->on_expr) - { - prev_table->dep_tables|= table->on_expr_dep_tables; - table_map prev_used_tables= prev_table->nested_join ? - prev_table->nested_join->used_tables : - prev_table->get_map(); - /* - If on expression contains only references to inner tables - we still make the inner tables dependent on the outer tables. - It would be enough to set dependency only on one outer table - for them. Yet this is really a rare case. - Note: - RAND_TABLE_BIT mask should not be counted as it - prevents update of inner table dependences. - For example it might happen if RAND() function - is used in JOIN ON clause. - */ - if (!((prev_table->on_expr->used_tables() & - ~(OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) & - ~prev_used_tables)) - prev_table->dep_tables|= used_tables; - } - } - prev_table= table; - } - - /* - Flatten nested joins that can be flattened. - no ON expression and not a semi-join => can be flattened. - */ - li.rewind(); - while ((table= li++)) - { - nested_join= table->nested_join; - if (table->sj_on_expr && !in_sj) - { - /* - If this is a semi-join that is not contained within another semi-join - leave it intact (otherwise it is flattened) - */ - /* - Make sure that any semi-join appear in - the join->select_lex->sj_nests list only once - */ - List_iterator_fast sj_it(join->select_lex->sj_nests); - TABLE_LIST *sj_nest; - while ((sj_nest= sj_it++)) - { - if (table == sj_nest) - break; - } - if (sj_nest) - continue; - join->select_lex->sj_nests.push_back(table, join->thd->mem_root); - - /* - Also, walk through semi-join children and mark those that are now - top-level - */ - TABLE_LIST *tbl; - List_iterator it(nested_join->join_list); - while ((tbl= it++)) - { - if (!tbl->on_expr && tbl->table) - tbl->table->maybe_null= FALSE; - } - } - else if (nested_join && !table->on_expr) - { - TABLE_LIST *tbl; - List_iterator it(nested_join->join_list); - List repl_list; - while ((tbl= it++)) - { - tbl->embedding= table->embedding; - if (!tbl->embedding && !tbl->on_expr && tbl->table) - tbl->table->maybe_null= FALSE; - tbl->join_list= table->join_list; - repl_list.push_back(tbl, join->thd->mem_root); - tbl->dep_tables|= table->dep_tables; - } - li.replace(repl_list); - } - } - DBUG_RETURN(conds); -} - /*@brief in_subselect_rewrite_walk - Rewrites Item_in_subselect*/ /************************************************************ * DESCRIPTION: @@ -367,27 +139,3 @@ bool in_subselect_rewrite(SELECT_LEX *select_lex) return result; } - -uint build_bitmap_for_nested_joins_mcs(List *join_list, - uint first_unused) -{ - List_iterator li(*join_list); - TABLE_LIST *table; - DBUG_ENTER("build_bitmap_for_nested_joins_mcs"); - while ((table= li++)) - { - NESTED_JOIN *nested_join; - if ((nested_join= table->nested_join)) - { - if (nested_join->n_tables != 1) - { - /* Don't assign bits to sj-nests */ - if (table->on_expr) - nested_join->nj_map= (nested_join_map) 1 << first_unused++; - first_unused= build_bitmap_for_nested_joins_mcs(&nested_join->join_list, - first_unused); - } - } - } - DBUG_RETURN(first_unused); -} diff --git a/dbcon/mysql/ha_mcs_opt_rewrites.h b/dbcon/mysql/ha_mcs_opt_rewrites.h index 2ddba9781..1b323ec5f 100644 --- a/dbcon/mysql/ha_mcs_opt_rewrites.h +++ b/dbcon/mysql/ha_mcs_opt_rewrites.h @@ -22,9 +22,5 @@ bool in_subselect_rewrite(SELECT_LEX *select_lex); void opt_flag_unset_PS(SELECT_LEX *select_lex); -COND *simplify_joins_mcs(JOIN *join, List *join_list, - COND *conds, bool top, bool in_sj); -uint build_bitmap_for_nested_joins_mcs(List *join_list, - uint first_unused); #endif diff --git a/dbcon/mysql/ha_mcs_pushdown.cpp b/dbcon/mysql/ha_mcs_pushdown.cpp index 7470af6a7..d0fc84cbd 100644 --- a/dbcon/mysql/ha_mcs_pushdown.cpp +++ b/dbcon/mysql/ha_mcs_pushdown.cpp @@ -21,7 +21,6 @@ void check_walk(const Item* item, void* arg); - void disable_indices_for_CEJ(THD *thd_) { TABLE_LIST* global_list; @@ -30,7 +29,7 @@ void disable_indices_for_CEJ(THD *thd_) // MCOL-652 - doing this with derived tables can cause bad things to happen if (!global_list->derived) { - global_list->index_hints= new (thd_->mem_root) List(); + global_list->index_hints = new (thd_->mem_root) List(); global_list->index_hints->push_front(new (thd_->mem_root) Index_hint(INDEX_HINT_USE, @@ -84,8 +83,8 @@ void find_tables(const Item* item, void* arg) { if (typeid(*item) == typeid(Item_field)) { - Item_field *ifp= (Item_field*)item; - List *tables_list= (List
*)arg; + Item_field *ifp = (Item_field*)item; + List
*tables_list = (List
*)arg; tables_list->push_back(ifp->field->table); } } @@ -109,8 +108,8 @@ bool is_joinkeys_predicate(const Item_func *ifp) if (ifp->arguments()[0]->type() == Item::FIELD_ITEM && ifp->arguments()[1]->type() == Item::FIELD_ITEM) { - Item_field* left= reinterpret_cast(ifp->arguments()[0]); - Item_field* right= reinterpret_cast(ifp->arguments()[1]); + Item_field* left = reinterpret_cast(ifp->arguments()[0]); + Item_field* right = reinterpret_cast(ifp->arguments()[1]); // If MDB crashes here with non-fixed Item_field and field == NULL // there must be a check over on_expr for a different SELECT_LEX. @@ -123,8 +122,8 @@ bool is_joinkeys_predicate(const Item_func *ifp) else { List
llt; List
rlt; - Item *left= ifp->arguments()[0]; - Item *right= ifp->arguments()[1]; + Item *left = ifp->arguments()[0]; + Item *right = ifp->arguments()[1]; // Search for tables inside left and right expressions // and compare them left->traverse_cond(find_tables, (void*)&llt, Item::POSTFIX); @@ -133,7 +132,7 @@ bool is_joinkeys_predicate(const Item_func *ifp) // the idea is useless. if (llt.elements && rlt.elements && (llt.elem(0) != rlt.elem(0))) { - result= true; + result = true; } } } @@ -151,7 +150,7 @@ bool is_joinkeys_predicate(const Item_func *ifp) ***********************************************************/ void find_nonequi_join(const Item* item, void *arg) { - bool *unsupported_feature = reinterpret_cast(arg); + bool *unsupported_feature = reinterpret_cast(arg); if ( *unsupported_feature ) return; @@ -184,7 +183,7 @@ void find_nonequi_join(const Item* item, void *arg) ***********************************************************/ void find_join(const Item* item, void* arg) { - bool *unsupported_feature = reinterpret_cast(arg); + bool *unsupported_feature = reinterpret_cast(arg); if ( *unsupported_feature ) return; @@ -219,10 +218,10 @@ void save_join_predicates(const Item* item, void* arg) { if (item->type() == Item::FUNC_ITEM) { - const Item_func* ifp= reinterpret_cast(item); + const Item_func* ifp = reinterpret_cast(item); if (is_joinkeys_predicate(ifp)) { - List *join_preds_list= (List*)arg; + List *join_preds_list = (List*)arg; join_preds_list->push_back(const_cast(item)); } } @@ -241,7 +240,7 @@ void save_join_predicates(const Item* item, void* arg) ***********************************************************/ void check_walk(const Item* item, void* arg) { - bool *unsupported_feature = reinterpret_cast(arg); + bool *unsupported_feature = reinterpret_cast(arg); if ( *unsupported_feature ) return; @@ -307,7 +306,7 @@ void check_walk(const Item* item, void* arg) ***********************************************************/ void check_user_var_func(const Item* item, void* arg) { - bool* unsupported_feature = reinterpret_cast(arg); + bool* unsupported_feature = reinterpret_cast(arg); if (*unsupported_feature) return; @@ -509,8 +508,8 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute()) return handler; - SELECT_LEX_UNIT *unit= table_ptr->derived; - SELECT_LEX *sl= unit->first_select(); + SELECT_LEX_UNIT *unit = table_ptr->derived; + SELECT_LEX *sl = unit->first_select(); bool unsupported_feature = false; @@ -523,7 +522,7 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) } // JOIN expression from WHERE, ON expressions - JOIN* join= sl->join; + JOIN* join = sl->join; //TODO DRRTUY Make a proper tree traverse //To search for CROSS JOIN-s we use tree invariant //G(V,E) where [V] = [E]+1 @@ -533,7 +532,7 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) { if (tl->where) { - Item_cond* where_icp= reinterpret_cast(tl->where); + Item_cond* where_icp = reinterpret_cast(tl->where); where_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); where_icp->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX); } @@ -542,7 +541,7 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) // TABLE_LIST in FROM until CS meets unsupported feature if (tl->on_expr) { - Item_cond* on_icp= reinterpret_cast(tl->on_expr); + Item_cond* on_icp = reinterpret_cast(tl->on_expr); on_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); on_icp->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX); } @@ -559,7 +558,7 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) if (!unsupported_feature && !join_preds_list.elements && join && join->conds) { - Item_cond* conds= reinterpret_cast(join->conds); + Item_cond* conds = reinterpret_cast(join->conds); conds->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); conds->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX); } @@ -569,18 +568,18 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr) if (!unsupported_feature && join && join->table_count >= 2 && !join_preds_list.elements) { - unsupported_feature= true; + unsupported_feature = true; } // CROSS JOIN with not enough JOIN predicates if(!unsupported_feature && join && join_preds_list.elements < join->table_count-1) { - unsupported_feature= true; + unsupported_feature = true; } - if ( !unsupported_feature ) - handler= new ha_columnstore_derived_handler(thd, table_ptr); + if (!unsupported_feature) + handler = new ha_columnstore_derived_handler(thd, table_ptr); return handler; } @@ -619,7 +618,7 @@ int ha_columnstore_derived_handler::init_scan() { DBUG_ENTER("ha_columnstore_derived_handler::init_scan"); - mcs_handler_info mhi = mcs_handler_info(reinterpret_cast(this), DERIVED); + mcs_handler_info mhi(reinterpret_cast(this), DERIVED); // this::table is the place for the result set int rc = ha_mcs_impl_pushdown_init(&mhi, table); @@ -747,7 +746,7 @@ int ha_mcs_group_by_handler::end_scan() * More details in server/sql/select_handler.h * PARAMETERS: * thd - THD pointer. - * sel - SELECT_LEX* that describes the query. + * select_lex - SELECT_LEX* that describes the query. * RETURN: * select_handler if possible * NULL in other case @@ -800,13 +799,12 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) // We apply dedicated rewrites from MDB here so MDB's data structures // becomes dirty and CS has to raise an error in case of any problem // or unsupported feature. - handler= new ha_columnstore_select_handler(thd, select_lex); - JOIN *join= select_lex->join; + handler = new ha_columnstore_select_handler(thd, select_lex); + JOIN *join = select_lex->join; bool unsupported_feature = false; { Query_arena *arena, backup; - arena= thd->activate_stmt_arena_if_needed(&backup); - + arena = thd->activate_stmt_arena_if_needed(&backup); disable_indices_for_CEJ(thd); if (arena) @@ -822,25 +820,20 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) COND *conds = nullptr; if (!unsupported_feature) { - SELECT_LEX *sel= select_lex; // Rewrite once for PS // Refer to JOIN::optimize_inner() in sql/sql_select.cc // for details on the optimizations performed in this block. - if (sel->first_cond_optimization) + if (select_lex->first_cond_optimization) { create_explain_query_if_not_exists(thd->lex, thd->mem_root); - arena= thd->activate_stmt_arena_if_needed(&backup); - sel->first_cond_optimization= false; - - conds= simplify_joins_mcs(join, select_lex->join_list, - join->conds, true, false); - - build_bitmap_for_nested_joins_mcs(select_lex->join_list, 0); - sel->where= conds; + arena = thd->activate_stmt_arena_if_needed(&backup); + select_lex->first_cond_optimization= false; + conds = join->conds; + select_lex->where = conds; if (isPS) { - sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; + select_lex->prep_where = conds ? conds->copy_andor_structure(thd) : 0; } select_lex->update_used_tables(); @@ -849,23 +842,21 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) thd->restore_active_arena(arena, &backup); // Unset SL::first_cond_optimization - opt_flag_unset_PS(sel); + opt_flag_unset_PS(select_lex); } - } - if (!unsupported_feature && conds) - { #ifdef DEBUG_WALK_COND - conds->traverse_cond(cal_impl_if::debug_walk, NULL, Item::POSTFIX); + if (conds) + { + conds->traverse_cond(cal_impl_if::debug_walk, NULL, Item::POSTFIX); + } #endif - join->conds = conds; } } // We shouldn't raise error now so set an error to raise it later in init_SH. - handler->rewrite_error= unsupported_feature; - // Return SH even if init fails b/c CS changed SELECT_LEX structures - // with simplify_joins_mcs() + handler->rewrite_error = unsupported_feature; + // Return SH even if init fails return handler; } @@ -880,8 +871,8 @@ ha_columnstore_select_handler::ha_columnstore_select_handler(THD *thd, SELECT_LEX* select_lex) : select_handler(thd, mcs_hton) { - select= select_lex; - rewrite_error= false; + select = select_lex; + rewrite_error = false; } /*********************************************************** @@ -913,16 +904,15 @@ int ha_columnstore_select_handler::init_scan() // Skip execution for EXPLAIN queries if (!thd->lex->describe) { - mcs_handler_info mhi= mcs_handler_info( - reinterpret_cast(this), SELECT); - rc= ha_mcs_impl_pushdown_init(&mhi, this->table); + mcs_handler_info mhi(reinterpret_cast(this), SELECT); + rc = ha_mcs_impl_pushdown_init(&mhi, this->table); } } else { my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), err_msg.c_str()); sql_print_error("%s", err_msg.c_str()); - rc= ER_INTERNAL_ERROR; + rc = ER_INTERNAL_ERROR; } DBUG_RETURN(rc); @@ -942,7 +932,7 @@ int ha_columnstore_select_handler::next_row() { DBUG_ENTER("ha_columnstore_select_handler::next_row"); - int rc= ha_mcs_impl_select_next(table->record[0], table); + int rc = ha_mcs_impl_select_next(table->record[0], table); DBUG_RETURN(rc); } diff --git a/dbcon/mysql/ha_mcs_pushdown.h b/dbcon/mysql/ha_mcs_pushdown.h index ce4dc839e..012dac343 100644 --- a/dbcon/mysql/ha_mcs_pushdown.h +++ b/dbcon/mysql/ha_mcs_pushdown.h @@ -142,6 +142,10 @@ private: public: bool rewrite_error; std::string err_msg; + // MCOL-4525 Store the original TABLE_LIST::outer_join value in a hash map. + // This will be used to restore to the original state later in case + // query execution fails using the select_handler. + cal_impl_if::TableOuterJoinMap tableOuterJoinMap; ha_columnstore_select_handler(THD* thd_arg, SELECT_LEX* sel); ~ha_columnstore_select_handler(); int init_scan() override; diff --git a/mysql-test/columnstore/basic/r/mcol-4665.result b/mysql-test/columnstore/basic/r/mcol-4665.result new file mode 100644 index 000000000..aabd08164 --- /dev/null +++ b/mysql-test/columnstore/basic/r/mcol-4665.result @@ -0,0 +1,223 @@ +# +# MCOL-4665 Move outer join to inner join conversion into the engine. +# +DROP DATABASE IF EXISTS mcol4665; +CREATE DATABASE mcol4665; +USE mcol4665; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +create table t4 (a int); +insert into t1 values (1), (2), (3), (4); +insert into t2 values (2), (3), (4); +insert into t3 values (3), (4); +insert into t4 values (4); +select * from t1 left join t2 on t1.a=t2.a order by 1,2; +a a +1 NULL +2 2 +3 3 +4 4 +select * from t1 left join t2 on t1.a=t2.a where t2.a < 100 order by 1,2; +a a +2 2 +3 3 +4 4 +select * from t1 left join t2 on t1.a=t2.a where t2.a is null order by 1,2; +a a +1 NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a < 100 order by 1,2,3; +a a a +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a is null order by 1,2,3; +a a a +1 NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a < 100 order by 1,2,3; +a a a +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a is null order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a < 100 order by 1,2,3; +a a a +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a is null order by 1,2,3; +a a a +1 NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a < 100 order by 1,2,3; +a a a +3 3 3 +4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a is null order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a order by 1,2,3; +a a a +1 NULL NULL +2 NULL NULL +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a < 100 order by 1,2,3; +a a a +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a < 100 order by 1,2,3; +a a a +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a is null order by 1,2,3; +a a a +1 NULL NULL +2 NULL NULL +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a < 100 order by 1,2,3; +a a a +2 2 NULL +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a is null order by 1,2,3; +a a a +1 NULL NULL +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a < 100 order by 1,2,3; +a a a +3 3 3 +4 4 4 +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a is null order by 1,2,3; +a a a +1 NULL NULL +2 2 NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a < 100 order by 1,2,3,4; +a a a a +2 2 NULL NULL +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a < 100 order by 1,2,3,4; +a a a a +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 3 NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 NULL NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a < 100 order by 1,2,3,4; +a a a a +2 2 NULL NULL +3 3 NULL NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a < 100 order by 1,2,3,4; +a a a a +2 2 NULL NULL +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a < 100 order by 1,2,3,4; +a a a a +3 3 3 NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 3 NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 NULL NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a < 100 order by 1,2,3,4; +a a a a +2 2 NULL NULL +3 3 NULL NULL +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a < 100 order by 1,2,3,4; +a a a a +4 4 4 4 +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a is null order by 1,2,3,4; +a a a a +1 NULL NULL NULL +2 2 NULL NULL +3 3 NULL NULL +DROP DATABASE mcol4665; diff --git a/mysql-test/columnstore/basic/t/mcol-4665.test b/mysql-test/columnstore/basic/t/mcol-4665.test new file mode 100644 index 000000000..cbbaab5b1 --- /dev/null +++ b/mysql-test/columnstore/basic/t/mcol-4665.test @@ -0,0 +1,84 @@ +--source ../include/have_columnstore.inc +--source ctype_cmp_combinations.inc +--source default_storage_engine_by_combination.inc + + +--echo # +--echo # MCOL-4665 Move outer join to inner join conversion into the engine. +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS mcol4665; +--enable_warnings + +CREATE DATABASE mcol4665; +USE mcol4665; + +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +create table t4 (a int); +insert into t1 values (1), (2), (3), (4); +insert into t2 values (2), (3), (4); +insert into t3 values (3), (4); +insert into t4 values (4); + +select * from t1 left join t2 on t1.a=t2.a order by 1,2; +select * from t1 left join t2 on t1.a=t2.a where t2.a < 100 order by 1,2; +select * from t1 left join t2 on t1.a=t2.a where t2.a is null order by 1,2; + +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a < 100 order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a is null order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a < 100 order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a is null order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a < 100 order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a is null order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a < 100 order by 1,2,3; +select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a is null order by 1,2,3; + +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a < 100 order by 1,2,3; +# Below query is disabled until MCOL-4715 is fixed +# select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a is null order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a < 100 order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a is null order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a < 100 order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a is null order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a < 100 order by 1,2,3; +select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a is null order by 1,2,3; + +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a < 100 order by 1,2,3,4; +# Below query is disabled until MCOL-4715 is fixed +# select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a < 100 order by 1,2,3,4; +# Below query is disabled until MCOL-4715 is fixed +# select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a is null order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a < 100 order by 1,2,3,4; +select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a is null order by 1,2,3,4; + +DROP DATABASE mcol4665;