diff --git a/dbcon/mysql/ha_mcs.cpp b/dbcon/mysql/ha_mcs.cpp index a061c5abb..7b8e9f76a 100644 --- a/dbcon/mysql/ha_mcs.cpp +++ b/dbcon/mysql/ha_mcs.cpp @@ -45,7 +45,8 @@ group_by_handler* create_columnstore_group_by_handler(THD* thd, Query* query); derived_handler* create_columnstore_derived_handler(THD* thd, TABLE_LIST* derived); -select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* sel); +select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* sel_lex, SELECT_LEX_UNIT* sel_unit); +select_handler* create_columnstore_unit_handler(THD* thd, SELECT_LEX_UNIT* sel_unit); /* Variables for example share methods */ @@ -1835,6 +1836,7 @@ static int columnstore_init_func(void* p) mcs_hton->create_group_by = create_columnstore_group_by_handler; mcs_hton->create_derived = create_columnstore_derived_handler; mcs_hton->create_select = create_columnstore_select_handler; + mcs_hton->create_unit = create_columnstore_unit_handler; mcs_hton->db_type = DB_TYPE_AUTOASSIGN; #ifdef HAVE_PSI_INTERFACE diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index 0a88d3f4c..ecd22421b 100644 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -6681,7 +6681,8 @@ void setExecutionParams(gp_walk_info& gwi, SCSEP& csep) * RETURNS * error id as an int ***********************************************************/ -int processFrom(bool& isUnion, SELECT_LEX& select_lex, gp_walk_info& gwi, SCSEP& csep) +int processFrom(bool& isUnion, SELECT_LEX& select_lex, gp_walk_info& gwi, SCSEP& csep, + bool isSelectHandlerTop, bool isSelectLexUnit) { // populate table map and trigger syscolumn cache for all the tables (@bug 1637). // all tables on FROM list must have at least one col in colmap @@ -6820,7 +6821,7 @@ int processFrom(bool& isUnion, SELECT_LEX& select_lex, gp_walk_info& gwi, SCSEP& // Existed pushdown handlers won't get in this scope // except UNION pushdown that is to come. // is_unit_op() give a segv for derived_handler's SELECT_LEX - if (!isUnion && select_lex.master_unit()->is_unit_op()) + if (!isUnion && (!isSelectHandlerTop || isSelectLexUnit) && select_lex.master_unit()->is_unit_op()) { // MCOL-2178 isUnion member only assigned, never used // MIGR::infinidb_vtable.isUnion = true; @@ -7378,7 +7379,8 @@ void buildInToExistsFilter(gp_walk_info& gwi, SELECT_LEX& select_lex) * error id as an int ***********************************************************/ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool isUnion, - bool isSelectHandlerTop, const std::vector& condStack) + bool isSelectHandlerTop, bool isSelectLexUnit, + const std::vector& condStack) { #ifdef DEBUG_WALK_COND cerr << "getSelectPlan()" << endl; @@ -7406,7 +7408,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i CalpontSelectExecutionPlan::SelectList derivedTbList; // @bug 1796. Remember table order on the FROM list. gwi.clauseType = FROM; - if ((rc = processFrom(isUnion, select_lex, gwi, csep))) + if ((rc = processFrom(isUnion, select_lex, gwi, csep, isSelectHandlerTop, + isSelectLexUnit))) { return rc; } @@ -8799,9 +8802,10 @@ int cs_get_derived_plan(ha_columnstore_derived_handler* handler, THD* thd, SCSEP return 0; } -int cs_get_select_plan(ha_columnstore_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, + bool isSelectLexUnit) { - SELECT_LEX& select_lex = *handler->select; + SELECT_LEX& select_lex = handler->select_lex ? *handler->select_lex : *handler->lex_unit->first_select(); if (select_lex.where) { @@ -8813,7 +8817,7 @@ int cs_get_select_plan(ha_columnstore_select_handler* handler, THD* thd, SCSEP& convertOuterJoinToInnerJoin(&select_lex.top_join_list, gwi.tableOnExprList, gwi.condList, handler->tableOuterJoinMap); - int status = getSelectPlan(gwi, select_lex, csep, false, true); + int status = getSelectPlan(gwi, select_lex, csep, false, true, isSelectLexUnit); if (status > 0) return ER_INTERNAL_ERROR; diff --git a/dbcon/mysql/ha_mcs_impl.cpp b/dbcon/mysql/ha_mcs_impl.cpp index bc38c5975..eb5829434 100644 --- a/dbcon/mysql/ha_mcs_impl.cpp +++ b/dbcon/mysql/ha_mcs_impl.cpp @@ -1392,7 +1392,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector& c gwi.clauseType = WHERE; - if (getSelectPlan(gwi, select_lex, updateCP, false, false, condStack) != + if (getSelectPlan(gwi, select_lex, updateCP, false, false, false, condStack) != 0) //@Bug 3030 Modify the error message for unsupported functions { if (gwi.cs_vtable_is_update_with_derive) @@ -4886,7 +4886,7 @@ int ha_mcs_impl_group_by_end(TABLE* table) * RETURN: * rc as int ***********************************************************/ -int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table) +int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table, bool isSelectLexUnit) { IDEBUG(cout << "pushdown_init for table " << endl); THD* thd = current_thd; @@ -5076,7 +5076,7 @@ int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table) if (handler_info->hndl_type == mcs_handler_types_t::SELECT) { sh = reinterpret_cast(handler_info->hndl_ptr); - status = cs_get_select_plan(sh, thd, csep, gwi); + status = cs_get_select_plan(sh, thd, csep, gwi, isSelectLexUnit); } else if (handler_info->hndl_type == DERIVED) { diff --git a/dbcon/mysql/ha_mcs_impl.h b/dbcon/mysql/ha_mcs_impl.h index dc8da092d..3f1b9d34c 100644 --- a/dbcon/mysql/ha_mcs_impl.h +++ b/dbcon/mysql/ha_mcs_impl.h @@ -44,7 +44,7 @@ extern int ha_mcs_impl_direct_update_delete_rows(bool execute, ha_rows* affected const std::vector& condStack); extern int ha_mcs_impl_delete_row(); extern int ha_mcs_impl_rnd_pos(uchar* buf, uchar* pos); -extern int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table); +extern int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table, bool isSelectLexUnit = false); extern int ha_mcs_impl_select_next(uchar* buf, TABLE* table, long timeZone); extern int ha_mcs_impl_group_by_init(mcs_handler_info* handler_info, TABLE* table); extern int ha_mcs_impl_group_by_next(TABLE* table, long timeZone); diff --git a/dbcon/mysql/ha_mcs_impl_if.h b/dbcon/mysql/ha_mcs_impl_if.h index 3eefebf32..470f98d87 100644 --- a/dbcon/mysql/ha_mcs_impl_if.h +++ b/dbcon/mysql/ha_mcs_impl_if.h @@ -397,9 +397,9 @@ int cp_get_group_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_group_in 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); + gp_walk_info& gwi, bool isSelectLexUnit); int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false, - bool isSelectHandlerTop = false, + bool isSelectHandlerTop = false, bool isSelectLexUnit = 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); diff --git a/dbcon/mysql/ha_mcs_pushdown.cpp b/dbcon/mysql/ha_mcs_pushdown.cpp index 2d6c2120c..5cae5e171 100644 --- a/dbcon/mysql/ha_mcs_pushdown.cpp +++ b/dbcon/mysql/ha_mcs_pushdown.cpp @@ -728,20 +728,22 @@ int ha_mcs_group_by_handler::end_scan() DBUG_RETURN(rc); } -/*@brief create_columnstore_select_handler- Creates handler*/ -/************************************************************ +/*@brief create_columnstore_select_handler_- Creates handler +************************************************************ * DESCRIPTION: * Creates a select handler if there is no non-equi JOIN, e.g * t1.c1 > t2.c2 and logical OR in the filter predicates. * More details in server/sql/select_handler.h * PARAMETERS: * thd - THD pointer. - * select_lex - SELECT_LEX* that describes the query. + * sel_lex - SELECT_LEX* that describes the query. + * sel_unit - SELECT_LEX_UNIT* that describes the query. + * Only one of sel_lex and sel_unit is not null. * RETURN: * select_handler if possible * NULL in other case ***********************************************************/ -select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) +select_handler* create_columnstore_select_handler_(THD* thd, SELECT_LEX* sel_lex, SELECT_LEX_UNIT* sel_unit) { mcs_select_handler_mode_t select_handler_mode = get_select_handler_mode(thd); @@ -778,60 +780,96 @@ select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_l return nullptr; } - // Iterate and traverse through the item list and the JOIN cond - // and do not create SH if the unsupported (set_user_var) - // function is present. - TABLE_LIST* table_ptr = select_lex->get_table_list(); - for (; table_ptr; table_ptr = table_ptr->next_global) + std::vector select_lex_vec; + + if (sel_unit && !sel_lex) { - if (check_user_var(table_ptr->select_lex)) + for (SELECT_LEX* sl = sel_unit->first_select(); sl; sl = sl->next_select()) { - return nullptr; + select_lex_vec.push_back(sl); + } + } + else + { + select_lex_vec.push_back(sel_lex); + } + + for (size_t i = 0; i < select_lex_vec.size(); i++) + { + SELECT_LEX* select_lex = select_lex_vec[i]; + + // Iterate and traverse through the item list and the JOIN cond + // and do not create SH if the unsupported (set_user_var) + // function is present. + TABLE_LIST* table_ptr = select_lex->get_table_list(); + for (; table_ptr; table_ptr = table_ptr->next_global) + { + if (check_user_var(table_ptr->select_lex)) + { + return nullptr; + } } } // 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. - ha_columnstore_select_handler* handler = new ha_columnstore_select_handler(thd, select_lex); + ha_columnstore_select_handler* handler; - JOIN* join = select_lex->join; - - if (select_lex->first_cond_optimization && select_lex->handle_derived(thd->lex, DT_MERGE)) + if (sel_unit && sel_lex) { - if (!thd->is_error()) - { - my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in select_lex::handle_derived()"); - } - - return handler; + handler = new ha_columnstore_select_handler(thd, sel_lex, sel_unit); + } + else if (sel_unit) + { + handler = new ha_columnstore_select_handler(thd, sel_unit); + } + else + { + handler = new ha_columnstore_select_handler(thd, sel_lex); } - // This is partially taken from JOIN::optimize_inner() in sql/sql_select.cc - if (select_lex->first_cond_optimization) + for (size_t i = 0; i < select_lex_vec.size(); i++) { - create_explain_query_if_not_exists(thd->lex, thd->mem_root); - Query_arena *arena, backup; - arena = thd->activate_stmt_arena_if_needed(&backup); - COND* conds = join->conds; - select_lex->where = conds; + SELECT_LEX* select_lex = select_lex_vec[i]; + JOIN* join = select_lex->join; - if (isPS) + if (select_lex->first_cond_optimization && select_lex->handle_derived(thd->lex, DT_MERGE)) { - select_lex->prep_where = conds ? conds->copy_andor_structure(thd) : 0; + if (!thd->is_error()) + { + my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in select_lex::handle_derived()"); + } + + return handler; } - select_lex->update_used_tables(); + // This is partially taken from JOIN::optimize_inner() in sql/sql_select.cc + if (select_lex->first_cond_optimization) + { + create_explain_query_if_not_exists(thd->lex, thd->mem_root); + Query_arena *arena, backup; + arena = thd->activate_stmt_arena_if_needed(&backup); + COND* conds = join->conds; + select_lex->where = conds; - if (arena) - thd->restore_active_arena(arena, &backup); + if (isPS) + { + select_lex->prep_where = conds ? conds->copy_andor_structure(thd) : 0; + } + + select_lex->update_used_tables(); + + if (arena) + thd->restore_active_arena(arena, &backup); #ifdef DEBUG_WALK_COND - if (conds) - { - 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 + } } // Attempt to execute the query using the select handler. @@ -840,69 +878,45 @@ select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_l // Skip execution for EXPLAIN queries if (!thd->lex->describe) { - // This is taken from JOIN::optimize() - join->fields = &select_lex->item_list; - - // Instantiate handler::table, which is the place for the result set. - if (handler->prepare()) + for (size_t i = 0; i < select_lex_vec.size(); i++) { - // check fallback - if (select_handler_mode == mcs_select_handler_mode_t::AUTO) // columnstore_select_handler=AUTO + SELECT_LEX* select_lex = select_lex_vec[i]; + JOIN* join = select_lex->join; + + // This is taken from JOIN::optimize() + join->fields = &select_lex->item_list; + + // Instantiate handler::table, which is the place for the result set. + if ((i == 0) && handler->prepare()) { - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, - "MCS select_handler execution failed. Falling back to server execution"); - restore_query_state(handler); - delete handler; - return nullptr; + // check fallback + if (select_handler_mode == mcs_select_handler_mode_t::AUTO) // columnstore_select_handler=AUTO + { + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, + "MCS select_handler execution failed. Falling back to server execution"); + restore_query_state(handler); + delete handler; + return nullptr; + } + + // error out + if (!thd->is_error()) + { + my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in handler->prepare()"); + } + + return handler; } - // error out - if (!thd->is_error()) - { - my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in handler->prepare()"); - } + // Prepare query execution + // This is taken from JOIN::exec_inner() + if (!select_lex->outer_select() && // (1) + select_lex != select_lex->master_unit()->fake_select_lex) // (2) + thd->lex->set_limit_rows_examined(); - return handler; - } - - // Prepare query execution - // This is taken from JOIN::exec_inner() - if (!select_lex->outer_select() && // (1) - select_lex != select_lex->master_unit()->fake_select_lex) // (2) - thd->lex->set_limit_rows_examined(); - - if (!join->tables_list && (join->table_count || !select_lex->with_sum_func) && - !select_lex->have_window_funcs()) - { - if (!thd->is_error()) - { - restore_query_state(handler); - delete handler; - return nullptr; - } - - return handler; - } - - if (!join->zero_result_cause && join->exec_const_cond && !join->exec_const_cond->val_int()) - join->zero_result_cause = "Impossible WHERE noticed after reading const tables"; - - // We've called exec_const_cond->val_int(). This may have caused an error. - if (unlikely(thd->is_error())) - { - // error out - handler->pushdown_init_rc = 1; - return handler; - } - - if (join->zero_result_cause) - { - if (join->select_lex->have_window_funcs() && join->send_row_on_empty_set()) - { - join->const_tables = join->table_count; - join->first_select = sub_select_postjoin_aggr; - } - else + if ((!sel_unit || sel_lex) && !join->tables_list && + (join->table_count || !select_lex->with_sum_func) && + !select_lex->have_window_funcs()) { if (!thd->is_error()) { @@ -913,23 +927,56 @@ select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_l return handler; } - } - if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && - get_schema_tables_result(join, PROCESSED_BY_JOIN_EXEC)) - { - if (!thd->is_error()) + if (!join->zero_result_cause && join->exec_const_cond && !join->exec_const_cond->val_int()) + join->zero_result_cause = "Impossible WHERE noticed after reading const tables"; + + // We've called exec_const_cond->val_int(). This may have caused an error. + if (unlikely(thd->is_error())) { - my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in get_schema_tables_result()"); + // error out + handler->pushdown_init_rc = 1; + return handler; } - return handler; + if (join->zero_result_cause) + { + if (join->select_lex->have_window_funcs() && join->send_row_on_empty_set()) + { + join->const_tables = join->table_count; + join->first_select = sub_select_postjoin_aggr; + } + else + { + if (!thd->is_error()) + { + restore_query_state(handler); + delete handler; + return nullptr; + } + + return handler; + } + } + + if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && + get_schema_tables_result(join, PROCESSED_BY_JOIN_EXEC)) + { + if (!thd->is_error()) + { + my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), "Error occured in get_schema_tables_result()"); + } + + return handler; + } } handler->scan_initialized = true; mcs_handler_info mhi(reinterpret_cast(handler), SELECT); - if ((handler->pushdown_init_rc = ha_mcs_impl_pushdown_init(&mhi, handler->table))) + bool isSelectLexUnit = (sel_unit && !sel_lex) ? true : false; + + if ((handler->pushdown_init_rc = ha_mcs_impl_pushdown_init(&mhi, handler->table, isSelectLexUnit))) { // check fallback if (select_handler_mode == mcs_select_handler_mode_t::AUTO) @@ -967,31 +1014,83 @@ select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_l return handler; } - // Unset select_lex::first_cond_optimization - if (select_lex->first_cond_optimization) + for (size_t i = 0; i < select_lex_vec.size(); i++) { - first_cond_optimization_flag_toggle(select_lex, &first_cond_optimization_flag_unset); + SELECT_LEX* select_lex = select_lex_vec[i]; + + // Unset select_lex::first_cond_optimization + if (select_lex->first_cond_optimization) + { + first_cond_optimization_flag_toggle(select_lex, &first_cond_optimization_flag_unset); + } } } return handler; } +select_handler* create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex, SELECT_LEX_UNIT* sel_unit) +{ + return create_columnstore_select_handler_(thd, select_lex, sel_unit); +} + +select_handler* create_columnstore_unit_handler(THD* thd, SELECT_LEX_UNIT* sel_unit) +{ + return create_columnstore_select_handler_(thd, 0, sel_unit); +} + /*********************************************************** * DESCRIPTION: * select_handler constructor * PARAMETERS: * thd - THD pointer. - * select_lex - sematic tree for the query. + * sel_lex - semantic tree for the query. ***********************************************************/ -ha_columnstore_select_handler::ha_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) - : select_handler(thd, mcs_hton) +ha_columnstore_select_handler::ha_columnstore_select_handler(THD* thd, SELECT_LEX* sel_lex) + : select_handler(thd, mcs_hton, sel_lex) + , prepared(false) + , scan_ended(false) + , scan_initialized(false) + , pushdown_init_rc(0) +{ + const char* timeZone = thd->variables.time_zone->get_name()->ptr(); + dataconvert::timeZoneToOffset(timeZone, strlen(timeZone), &time_zone); +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * PARAMETERS: + * thd - THD pointer. + * sel_unit - semantic tree for the query. + ***********************************************************/ +ha_columnstore_select_handler::ha_columnstore_select_handler(THD* thd, SELECT_LEX_UNIT* sel_unit) + : select_handler(thd, mcs_hton, sel_unit) + , prepared(false) + , scan_ended(false) + , scan_initialized(false) + , pushdown_init_rc(0) +{ + const char* timeZone = thd->variables.time_zone->get_name()->ptr(); + dataconvert::timeZoneToOffset(timeZone, strlen(timeZone), &time_zone); +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * PARAMETERS: + * thd - THD pointer. + * sel_lex - semantic tree for the query. + * sel_unit - unit containing SELECT_LEX's + ***********************************************************/ +ha_columnstore_select_handler::ha_columnstore_select_handler(THD* thd, SELECT_LEX* sel_lex, + SELECT_LEX_UNIT* sel_unit) + : select_handler(thd, mcs_hton, sel_lex, sel_unit) , prepared(false) , scan_ended(false) , scan_initialized(false) , pushdown_init_rc(0) { - select = select_lex; const char* timeZone = thd->variables.time_zone->get_name()->ptr(); dataconvert::timeZoneToOffset(timeZone, strlen(timeZone), &time_zone); } @@ -1074,7 +1173,7 @@ bool ha_columnstore_select_handler::prepare() prepared = true; - if ((!table && !(table = create_tmp_table(thd, select))) || table->fill_item_list(&result_columns)) + if ((!table && !(table = create_tmp_table(thd))) || table->fill_item_list(&result_columns)) { pushdown_init_rc = 1; DBUG_RETURN(true); diff --git a/dbcon/mysql/ha_mcs_pushdown.h b/dbcon/mysql/ha_mcs_pushdown.h index 80ca3cff8..e7b334a21 100644 --- a/dbcon/mysql/ha_mcs_pushdown.h +++ b/dbcon/mysql/ha_mcs_pushdown.h @@ -151,7 +151,9 @@ class ha_columnstore_select_handler : public select_handler // 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(THD* thd_arg, SELECT_LEX* sel_lex); + ha_columnstore_select_handler(THD* thd_arg, SELECT_LEX_UNIT* sel_unit); + ha_columnstore_select_handler(THD* thd_arg, SELECT_LEX* sel_lex, SELECT_LEX_UNIT* sel_unit); ~ha_columnstore_select_handler(); int init_scan() override; int next_row() override; diff --git a/mysql-test/columnstore/basic/r/mdev-25080.result b/mysql-test/columnstore/basic/r/mdev-25080.result new file mode 100644 index 000000000..b81b8a6e6 --- /dev/null +++ b/mysql-test/columnstore/basic/r/mdev-25080.result @@ -0,0 +1,114 @@ +# +# MDEV-25080: Allow pushdown of queries involving UNIONs +# in outer select to foreign engines +# +# Uncomment the actual SELECTs and add ORDER BY clause +# after MCOL-5222 is fixed +# +CREATE USER IF NOT EXISTS'cejuser'@'localhost' IDENTIFIED BY 'Vagrant1|0000001'; +GRANT ALL PRIVILEGES ON *.* TO 'cejuser'@'localhost'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mdev25080; +CREATE DATABASE mdev25080; +USE mdev25080; +CREATE TABLE t1 (a varchar(30)) ENGINE=ColumnStore; +CREATE TABLE t2 (a varchar(30)) ENGINE=ColumnStore; +CREATE TABLE t3 (a varchar(30)) ENGINE=MyISAM; +CREATE TABLE t4 (a varchar(30)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('abc'), ('bcd'), ('cde'); +INSERT INTO t2 VALUES ('bcd'), ('cde'), ('def'), ('efg'); +INSERT INTO t3 VALUES ('t3_myisam1'), ('t3_myisam2'), ('t3_myisam3'); +INSERT INTO t4 VALUES ('t4_myisam1'), ('t4_myisam2'), ('t4_myisam3'); +# Pushdown of the whole UNION +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +# UNION with a foreign engine +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t3; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +# More than two SELECTs in a UNIT: +EXPLAIN SELECT * FROM t1 UNION +SELECT * FROM t2 UNION ALL +SELECT * FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN (SELECT * FROM t1 UNION +SELECT * FROM t2) UNION ALL +SELECT * FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN SELECT * FROM t1 UNION +SELECT * FROM t2 UNION ALL +SELECT * FROM t3 UNION +SELECT * FROM t4; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN (SELECT * FROM t1 UNION +SELECT * FROM t2) UNION ALL +(SELECT * FROM t3 UNION +SELECT * FROM t4); +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN +SELECT count(*) FROM t1 UNION +SELECT count(*) FROM t2 UNION ALL +SELECT count(*)+20 FROM t2 UNION +SELECT count(*)+5 FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +# UNION inside a derived table: the whole derived table must be pushed +SELECT a FROM +(SELECT a FROM t1 UNION ALL SELECT a FROM t2) q ORDER BY a; +a +abc +bcd +bcd +cde +cde +def +efg +EXPLAIN +SELECT a FROM +(SELECT a FROM t1 UNION ALL SELECT a FROM t2) q ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +SELECT a FROM +(SELECT a FROM t1 UNION ALL SELECT a FROM t3) q ORDER BY a; +a +abc +bcd +cde +t3_myisam1 +t3_myisam2 +t3_myisam3 +EXPLAIN +SELECT a FROM +(SELECT a FROM t1 UNION ALL SELECT a FROM t3) q ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +# Prepared statements +PREPARE stmt FROM "EXPLAIN SELECT * FROM t1 UNION + SELECT * FROM t2"; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +PREPARE stmt FROM "EXPLAIN (SELECT * FROM t1 UNION + SELECT * FROM t2) UNION ALL + (SELECT * FROM t1 UNION + SELECT * FROM t2)"; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +DROP USER 'cejuser'@'localhost'; +DROP TABLE t1, t2, t3, t4; +DROP DATABASE mdev25080; diff --git a/mysql-test/columnstore/basic/r/union.result b/mysql-test/columnstore/basic/r/union.result index 867bccf76..22489fde6 100644 --- a/mysql-test/columnstore/basic/r/union.result +++ b/mysql-test/columnstore/basic/r/union.result @@ -5,6 +5,9 @@ USE mcs_union; # # MCOL-4700 Wrong result of a UNION for INT and INT UNSIGNED # +# Move the UNIONs from the subqueries to outer selects and add +# ORDER BY clause after MCOL-5222 is fixed +# CREATE TABLE t1 (a INT, b INT UNSIGNED); INSERT INTO t1 VALUES (-1, 1), (-1, 1), (-2, 2); SELECT * FROM (SELECT * FROM t1 UNION SELECT * FROM t1) tu ORDER BY b; @@ -862,4 +865,27 @@ a 16777213 9223372036854775807 DROP TABLE t1,t2; +# +# Union of tables containing different string data types +# +# Uncomment the actual SELECTs and add ORDER BY clause +# after MCOL-5222 is fixed +# +CREATE TABLE t1 (a CHAR(6)); +INSERT INTO t1 VALUES ('t13abc'), ('t13xx'), ('common'); +CREATE TABLE t2 (a VARCHAR(8)); +INSERT INTO t2 VALUES ('t14abcde'), ('t14xyzzz'), ('common'); +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN SELECT * FROM t2 UNION ALL SELECT * FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +EXPLAIN SELECT * FROM t1 UNION SELECT '123456789000' UNION SELECT * FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL +DROP TABLE t1,t2; DROP DATABASE mcs_union; diff --git a/mysql-test/columnstore/basic/t/mdev-25080.test b/mysql-test/columnstore/basic/t/mdev-25080.test new file mode 100644 index 000000000..883b62697 --- /dev/null +++ b/mysql-test/columnstore/basic/t/mdev-25080.test @@ -0,0 +1,154 @@ +--echo # +--echo # MDEV-25080: Allow pushdown of queries involving UNIONs +--echo # in outer select to foreign engines +--echo # +--echo # Uncomment the actual SELECTs and add ORDER BY clause +--echo # after MCOL-5222 is fixed +--echo # + +--source ../include/have_columnstore.inc + +# +# Enable cross engine join +# Configure user and password in Columnstore.xml file +# +--exec $MCS_MCSSETCONFIG CrossEngineSupport User 'cejuser' +--exec $MCS_MCSSETCONFIG CrossEngineSupport Password 'Vagrant1|0000001' +--exec $MCS_MCSSETCONFIG CrossEngineSupport Port $MASTER_MYPORT + +# +# Create corresponding in the server +# +--disable_warnings +CREATE USER IF NOT EXISTS'cejuser'@'localhost' IDENTIFIED BY 'Vagrant1|0000001'; +--enable_warnings +GRANT ALL PRIVILEGES ON *.* TO 'cejuser'@'localhost'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mdev25080; +--enable_warnings + +CREATE DATABASE mdev25080; + +USE mdev25080; + +CREATE TABLE t1 (a varchar(30)) ENGINE=ColumnStore; +CREATE TABLE t2 (a varchar(30)) ENGINE=ColumnStore; +CREATE TABLE t3 (a varchar(30)) ENGINE=MyISAM; +CREATE TABLE t4 (a varchar(30)) ENGINE=MyISAM; + +INSERT INTO t1 VALUES ('abc'), ('bcd'), ('cde'); +INSERT INTO t2 VALUES ('bcd'), ('cde'), ('def'), ('efg'); + +INSERT INTO t3 VALUES ('t3_myisam1'), ('t3_myisam2'), ('t3_myisam3'); +INSERT INTO t4 VALUES ('t4_myisam1'), ('t4_myisam2'), ('t4_myisam3'); + +--echo # Pushdown of the whole UNION +#SELECT * FROM t1 UNION SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; + +#SELECT * FROM t1 UNION ALL SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2; + +--echo # UNION with a foreign engine +#SELECT * FROM t1 UNION SELECT * FROM t3; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t3; + +--echo # More than two SELECTs in a UNIT: +#SELECT * FROM t1 UNION +# SELECT * FROM t2 UNION ALL +# SELECT * FROM t1; + +EXPLAIN SELECT * FROM t1 UNION + SELECT * FROM t2 UNION ALL + SELECT * FROM t1; + +#(SELECT * FROM t1 UNION +# SELECT * FROM t2) UNION ALL +# SELECT * FROM t1; + +EXPLAIN (SELECT * FROM t1 UNION + SELECT * FROM t2) UNION ALL + SELECT * FROM t1; + +#SELECT * FROM t1 UNION +# SELECT * FROM t2 UNION ALL +# SELECT * FROM t3 UNION +# SELECT * FROM t4; + +EXPLAIN SELECT * FROM t1 UNION + SELECT * FROM t2 UNION ALL + SELECT * FROM t3 UNION + SELECT * FROM t4; + +#(SELECT * FROM t1 UNION +# SELECT * FROM t2) UNION ALL +# (SELECT * FROM t3 UNION +# SELECT * FROM t4); + +EXPLAIN (SELECT * FROM t1 UNION + SELECT * FROM t2) UNION ALL + (SELECT * FROM t3 UNION + SELECT * FROM t4); + +#SELECT count(*) FROM t1 UNION +# SELECT count(*) FROM t2 UNION ALL +# SELECT count(*)+20 FROM t2 UNION +# SELECT count(*)+5 FROM t1; + +EXPLAIN + SELECT count(*) FROM t1 UNION + SELECT count(*) FROM t2 UNION ALL + SELECT count(*)+20 FROM t2 UNION + SELECT count(*)+5 FROM t1; + +--echo # UNION inside a derived table: the whole derived table must be pushed +SELECT a FROM + (SELECT a FROM t1 UNION ALL SELECT a FROM t2) q ORDER BY a; + +EXPLAIN + SELECT a FROM + (SELECT a FROM t1 UNION ALL SELECT a FROM t2) q ORDER BY a; + +SELECT a FROM + (SELECT a FROM t1 UNION ALL SELECT a FROM t3) q ORDER BY a; + +EXPLAIN + SELECT a FROM + (SELECT a FROM t1 UNION ALL SELECT a FROM t3) q ORDER BY a; + +--echo # Prepared statements +#PREPARE stmt FROM "SELECT * FROM t1 UNION +# SELECT * FROM t2"; + +#EXECUTE stmt; +#EXECUTE stmt; +#EXECUTE stmt; + +PREPARE stmt FROM "EXPLAIN SELECT * FROM t1 UNION + SELECT * FROM t2"; + +EXECUTE stmt; +EXECUTE stmt; + +#PREPARE stmt FROM "(SELECT * FROM t1 UNION +# SELECT * FROM t2) UNION ALL +# (SELECT * FROM t1 UNION +# SELECT * FROM t2)"; + +#EXECUTE stmt; +#EXECUTE stmt; +#EXECUTE stmt; + +PREPARE stmt FROM "EXPLAIN (SELECT * FROM t1 UNION + SELECT * FROM t2) UNION ALL + (SELECT * FROM t1 UNION + SELECT * FROM t2)"; + +EXECUTE stmt; +EXECUTE stmt; + +DROP USER 'cejuser'@'localhost'; +DROP TABLE t1, t2, t3, t4; +DROP DATABASE mdev25080; diff --git a/mysql-test/columnstore/basic/t/union.test b/mysql-test/columnstore/basic/t/union.test index eed88576a..1dce4454a 100644 --- a/mysql-test/columnstore/basic/t/union.test +++ b/mysql-test/columnstore/basic/t/union.test @@ -12,6 +12,9 @@ USE mcs_union; --echo # --echo # MCOL-4700 Wrong result of a UNION for INT and INT UNSIGNED --echo # +--echo # Move the UNIONs from the subqueries to outer selects and add +--echo # ORDER BY clause after MCOL-5222 is fixed +--echo # CREATE TABLE t1 (a INT, b INT UNSIGNED); INSERT INTO t1 VALUES (-1, 1), (-1, 1), (-2, 2); @@ -273,4 +276,25 @@ SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT a FROM t2) tu ORDER BY a; SELECT * FROM (SELECT a FROM t2 UNION ALL SELECT a FROM t1) tu ORDER BY a; DROP TABLE t1,t2; +--echo # +--echo # Union of tables containing different string data types +--echo # +--echo # Uncomment the actual SELECTs and add ORDER BY clause +--echo # after MCOL-5222 is fixed +--echo # + +CREATE TABLE t1 (a CHAR(6)); +INSERT INTO t1 VALUES ('t13abc'), ('t13xx'), ('common'); +CREATE TABLE t2 (a VARCHAR(8)); +INSERT INTO t2 VALUES ('t14abcde'), ('t14xyzzz'), ('common'); +#SELECT * FROM t1 UNION SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; +#SELECT * FROM t2 UNION ALL SELECT * FROM t1; +EXPLAIN SELECT * FROM t2 UNION ALL SELECT * FROM t1; +#SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +#SELECT * FROM t1 UNION SELECT '123456789000' UNION SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION SELECT '123456789000' UNION SELECT * FROM t2; +DROP TABLE t1,t2; + DROP DATABASE mcs_union;