diff --git a/.drone.jsonnet b/.drone.jsonnet index 11e1fbfa5..3d881a7aa 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -1,8 +1,8 @@ local events = ['pull_request', 'cron']; local servers = { - develop: ['10.6-enterprise'], - 'develop-22.08': ['10.6-enterprise'], + develop: ['10.6-MENT-1667'], + 'develop-22.08': ['10.6-MENT-1667'], }; local platforms = { @@ -108,7 +108,7 @@ local testPreparation(platform) = platform_map[platform]; -local Pipeline(branch, platform, event, arch='amd64', server='10.6-enterprise') = { +local Pipeline(branch, platform, event, arch='amd64', server='10.6-MENT-1667') = { local pkg_format = if (std.split(platform, ':')[0] == 'centos' || std.split(platform, ':')[0] == 'rockylinux') then 'rpm' else 'deb', local init = if (pkg_format == 'rpm') then '/usr/lib/systemd/systemd' else 'systemd', local mtr_path = if (pkg_format == 'rpm') then '/usr/share/mysql-test' else '/usr/share/mysql/mysql-test', @@ -125,7 +125,7 @@ local Pipeline(branch, platform, event, arch='amd64', server='10.6-enterprise') local container_tags = if (event == 'cron') then [brancht + std.strReplace(event, '_', '-') + '${DRONE_BUILD_NUMBER}', brancht] else [brancht + std.strReplace(event, '_', '-') + '${DRONE_BUILD_NUMBER}'], local container_version = branchp + event + '/${DRONE_BUILD_NUMBER}/' + server + '/' + arch, - local server_remote = if (std.endsWith(server, 'enterprise')) then 'https://github.com/mariadb-corporation/MariaDBEnterprise' else 'https://github.com/MariaDB/server', + local server_remote = if (std.endsWith(server, 'enterprise') || std.endsWith(server, '10.6-MENT-1667')) then 'https://github.com/mariadb-corporation/MariaDBEnterprise' else 'https://github.com/MariaDB/server', local sccache_arch = if (arch == 'amd64') then 'x86_64' else 'aarch64', local get_sccache = 'curl -L -o sccache.tar.gz https://github.com/mozilla/sccache/releases/download/v0.3.0/sccache-v0.3.0-' + sccache_arch + '-unknown-linux-musl.tar.gz ' + @@ -693,8 +693,8 @@ local FinalPipeline(branch, event) = { 'failure', ], } + (if event == 'cron' then { cron: ['nightly-' + std.strReplace(branch, '.', '-')] } else {}), - depends_on: std.map(function(p) std.join(' ', [branch, p, event, 'amd64', '10.6-enterprise']), platforms.develop) + - std.map(function(p) std.join(' ', [branch, p, event, 'arm64', '10.6-enterprise']), platforms_arm.develop), + depends_on: std.map(function(p) std.join(' ', [branch, p, event, 'amd64', '10.6-MENT-1667']), platforms.develop) + + std.map(function(p) std.join(' ', [branch, p, event, 'arm64', '10.6-MENT-1667']), platforms_arm.develop), }; @@ -719,10 +719,10 @@ local FinalPipeline(branch, event) = { ] + [ - Pipeline(any_branch, p, 'custom', 'amd64', '10.6-enterprise') + Pipeline(any_branch, p, 'custom', 'amd64', '10.6-MENT-1667') for p in platforms_custom ] + [ - Pipeline(any_branch, p, 'custom', 'arm64', '10.6-enterprise') + Pipeline(any_branch, p, 'custom', 'arm64', '10.6-MENT-1667') for p in platforms_arm_custom ] diff --git a/dbcon/execplan/calpontsystemcatalog.cpp b/dbcon/execplan/calpontsystemcatalog.cpp index 17e09d857..b7ecfc09a 100644 --- a/dbcon/execplan/calpontsystemcatalog.cpp +++ b/dbcon/execplan/calpontsystemcatalog.cpp @@ -6393,12 +6393,13 @@ boost::any CalpontSystemCatalog::ColType::convertColumnData(const std::string& d } CalpontSystemCatalog::ColType CalpontSystemCatalog::ColType::convertUnionColType( - vector& types) + vector& types, + unsigned int& rc) { idbassert(types.size()); CalpontSystemCatalog::ColType unionedType = types[0]; for (uint64_t i = 1; i < types.size(); i++) - dataconvert::DataConvert::joinColTypeForUnion(unionedType, types[i]); + dataconvert::DataConvert::joinColTypeForUnion(unionedType, types[i], rc); return unionedType; } diff --git a/dbcon/execplan/calpontsystemcatalog.h b/dbcon/execplan/calpontsystemcatalog.h index edd9aecd3..44f38be11 100644 --- a/dbcon/execplan/calpontsystemcatalog.h +++ b/dbcon/execplan/calpontsystemcatalog.h @@ -306,7 +306,7 @@ class CalpontSystemCatalog : public datatypes::SystemCatalog return !(*this == t); } - static ColType convertUnionColType(std::vector&); + static ColType convertUnionColType(std::vector&, unsigned int&); }; /** the structure of a table infomation diff --git a/dbcon/joblist/jlf_tuplejoblist.cpp b/dbcon/joblist/jlf_tuplejoblist.cpp index 857566973..56a3ac2ee 100644 --- a/dbcon/joblist/jlf_tuplejoblist.cpp +++ b/dbcon/joblist/jlf_tuplejoblist.cpp @@ -5102,11 +5102,18 @@ SJSTEP unionQueries(JobStepVector& queries, uint64_t distinctUnionNum, JobInfo& unionStep->inputAssociation(jsaToUnion); unionStep->outputAssociation(jsa); + // This return code in the call to convertUnionColType() below would + // always be 0. This is because convertUnionColType() is also called + // in the connector code in getSelectPlan()/getGroupPlan() which handle + // the non-zero return code scenarios from this function call and error + // out, in which case, the execution does not even get to ExeMgr. + unsigned int dummyUnionedTypeRc = 0; + // get unioned column types for (uint64_t j = 0; j < colCount; ++j) { CalpontSystemCatalog::ColType colType = - CalpontSystemCatalog::ColType::convertUnionColType(queryColTypes[j]); + CalpontSystemCatalog::ColType::convertUnionColType(queryColTypes[j], dummyUnionedTypeRc); types.push_back(colType.colDataType); csNums.push_back(colType.charsetNumber); scale.push_back(colType.scale); diff --git a/dbcon/joblist/tupleunion.cpp b/dbcon/joblist/tupleunion.cpp index 2c01bbf19..895c1e954 100644 --- a/dbcon/joblist/tupleunion.cpp +++ b/dbcon/joblist/tupleunion.cpp @@ -1766,12 +1766,14 @@ void TupleUnion::writeNull(Row* out, uint32_t col) { case 1: out->setUintField<1>(joblist::TINYINTNULL, col); break; - case 2: out->setUintField<1>(joblist::SMALLINTNULL, col); break; + case 2: out->setUintField<2>(joblist::SMALLINTNULL, col); break; case 4: out->setUintField<4>(joblist::INTNULL, col); break; case 8: out->setUintField<8>(joblist::BIGINTNULL, col); break; + case 16: out->setInt128Field(datatypes::Decimal128Null, col); break; + default: { } 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 b221a4a28..88ebe0830 100644 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -6682,7 +6682,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 @@ -6819,9 +6820,9 @@ int processFrom(bool& isUnion, SELECT_LEX& select_lex, gp_walk_info& gwi, SCSEP& bool unionSel = false; // UNION master unit check // Existed pushdown handlers won't get in this scope - // except UNION pushdown that is to come. + // MDEV-25080 Union pushdown would enter this scope // 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; @@ -7383,7 +7384,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; @@ -7411,13 +7413,12 @@ 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; } - bool unionSel = (!isUnion && select_lex.master_unit()->is_unit_op()) ? true : false; - gwi.clauseType = WHERE; if ((rc = processWhere(select_lex, gwi, csep, condStack))) { @@ -7860,25 +7861,32 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // @bug4388 normalize the project coltypes for union main select list if (!csep->unionVec().empty()) { + unsigned int unionedTypeRc = 0; + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) { vector coltypes; for (uint32_t j = 0; j < csep->unionVec().size(); j++) { - coltypes.push_back(dynamic_cast(csep->unionVec()[j].get()) - ->returnedCols()[i] - ->resultType()); + CalpontSelectExecutionPlan* unionCsep = + dynamic_cast(csep->unionVec()[j].get()); + coltypes.push_back(unionCsep->returnedCols()[i]->resultType()); // @bug5976. set hasAggregate true for the main column if // one corresponding union column has aggregate - if (dynamic_cast(csep->unionVec()[j].get()) - ->returnedCols()[i] - ->hasAggregate()) + if (unionCsep->returnedCols()[i]->hasAggregate()) gwi.returnedCols[i]->hasAggregate(true); } - gwi.returnedCols[i]->resultType(CalpontSystemCatalog::ColType::convertUnionColType(coltypes)); + gwi.returnedCols[i]->resultType(CalpontSystemCatalog::ColType::convertUnionColType(coltypes, unionedTypeRc)); + + if (unionedTypeRc != 0) + { + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(unionedTypeRc); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } } } @@ -8047,6 +8055,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i SRCP minSc; // min width projected column. for count(*) use + bool unionSel = (!isUnion && select_lex.master_unit()->is_unit_op()) ? true : false; + // Group by list. not valid for union main query if (!unionSel) { @@ -8805,9 +8815,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) { @@ -8819,7 +8830,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; @@ -9683,25 +9694,32 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // @bug4388 normalize the project coltypes for union main select list if (!csep->unionVec().empty()) { + unsigned int unionedTypeRc = 0; + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) { vector coltypes; for (uint32_t j = 0; j < csep->unionVec().size(); j++) { - coltypes.push_back(dynamic_cast(csep->unionVec()[j].get()) - ->returnedCols()[i] - ->resultType()); + CalpontSelectExecutionPlan* unionCsep = + dynamic_cast(csep->unionVec()[j].get()); + coltypes.push_back(unionCsep->returnedCols()[i]->resultType()); // @bug5976. set hasAggregate true for the main column if // one corresponding union column has aggregate - if (dynamic_cast(csep->unionVec()[j].get()) - ->returnedCols()[i] - ->hasAggregate()) + if (unionCsep->returnedCols()[i]->hasAggregate()) gwi.returnedCols[i]->hasAggregate(true); } - gwi.returnedCols[i]->resultType(CalpontSystemCatalog::ColType::convertUnionColType(coltypes)); + gwi.returnedCols[i]->resultType(CalpontSystemCatalog::ColType::convertUnionColType(coltypes, unionedTypeRc)); + + if (unionedTypeRc != 0) + { + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(unionedTypeRc); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } } } 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..b57147d00 100644 --- a/dbcon/mysql/ha_mcs_pushdown.cpp +++ b/dbcon/mysql/ha_mcs_pushdown.cpp @@ -728,20 +728,21 @@ 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. * 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 +779,105 @@ 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) + // MCOL-5432 Disable partial pushdown of the UNION operation if the query + // involves an order by or a limit clause. + if (sel_lex && sel_unit && + (sel_unit->global_parameters()->limit_params.explicit_limit == true || + sel_unit->global_parameters()->order_list.elements != 0)) { - if (check_user_var(table_ptr->select_lex)) + return nullptr; + } + + std::vector select_lex_vec; + + if (sel_unit && !sel_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) // partial pushdown of the SELECT_LEX_UNIT { - 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) // complete pushdown of the SELECT_LEX_UNIT + { + handler = new ha_columnstore_select_handler(thd, sel_unit); + } + else // Query only has a SELECT_LEX, no SELECT_LEX_UNIT + { + 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 +886,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 +935,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 +1022,101 @@ 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) +{ + if (thd->lex->sql_command == SQLCOM_CREATE_VIEW) + { + return nullptr; + } + + if (thd->stmt_arena && thd->stmt_arena->is_stmt_prepare()) + { + return nullptr; + } + + // MCOL-5432 Disable UNION pushdown if the query involves an order by + // or a limit clause. + if (sel_unit->global_parameters()->limit_params.explicit_limit == true || + sel_unit->global_parameters()->order_list.elements != 0) + { + return nullptr; + } + + 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 +1199,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/mcol641-union.result b/mysql-test/columnstore/basic/r/mcol641-union.result index d3dce7444..fa798dd8e 100644 --- a/mysql-test/columnstore/basic/r/mcol641-union.result +++ b/mysql-test/columnstore/basic/r/mcol641-union.result @@ -1,3 +1,5 @@ +# MCOL-641 Union Test Cases +# Once MCOL-5417 is supported, the errored out queries below should be fixed. DROP DATABASE IF EXISTS mcol641_union_db; CREATE DATABASE mcol641_union_db; USE mcol641_union_db; @@ -11,63 +13,52 @@ INSERT INTO cs1 values (99999999999999999999999999999999999999, 9999999999999999 INSERT INTO cs1 values (-99999999999999999999999999999999999998, -9999999999999999999999999999.9999999998, -0.99999999999999999999999999999999999998); INSERT INTO cs1 values (-99999999999999999999999999999999999999, -9999999999999999999999999999.9999999999, -0.99999999999999999999999999999999999999); SELECT d1, d1, d2 FROM cs1 UNION SELECT d2, d3, d3 FROM cs1; -d1 d1 d2 -125.0000000000 125.00000000000000000000000000000000000000 1.25000000000000000000000000000000000000 --125.0000000000 -125.00000000000000000000000000000000000000 -1.25000000000000000000000000000000000000 -99999999999999999999999999999999999998.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 -99999999999999999999999999999999999999.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 --99999999999999999999999999999999999998.0000000000 -999999999999999999999999999.99999999999999999999999999999999999999 -999999999999999999999999999.99999999999999999999999999999999999999 --99999999999999999999999999999999999999.0000000000 -999999999999999999999999999.99999999999999999999999999999999999999 -999999999999999999999999999.99999999999999999999999999999999999999 -1.2500000000 0.12500000000000000000000000000000000000 0.12500000000000000000000000000000000000 --1.2500000000 -0.12500000000000000000000000000000000000 -0.12500000000000000000000000000000000000 -9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 0.99999999999999999999999999999999999998 -9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 0.99999999999999999999999999999999999999 --9999999999999999999999999999.9999999998 -0.99999999999999999999999999999999999998 -0.99999999999999999999999999999999999998 --9999999999999999999999999999.9999999999 -0.99999999999999999999999999999999999999 -0.99999999999999999999999999999999999999 +ERROR 42000: The storage engine for the table doesn't support MCS-2060: Union operation exceeds maximum DECIMAL precision of 38. SELECT d2, d3, d3 FROM cs1 UNION SELECT d1, d1, d2 FROM cs1; -d2 d3 d3 -1.2500000000 0.12500000000000000000000000000000000000 0.12500000000000000000000000000000000000 --1.2500000000 -0.12500000000000000000000000000000000000 -0.12500000000000000000000000000000000000 -9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 0.99999999999999999999999999999999999998 -9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 0.99999999999999999999999999999999999999 --9999999999999999999999999999.9999999998 -0.99999999999999999999999999999999999998 -0.99999999999999999999999999999999999998 --9999999999999999999999999999.9999999999 -0.99999999999999999999999999999999999999 -0.99999999999999999999999999999999999999 -125.0000000000 125.00000000000000000000000000000000000000 1.25000000000000000000000000000000000000 --125.0000000000 -125.00000000000000000000000000000000000000 -1.25000000000000000000000000000000000000 -99999999999999999999999999999999999998.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 -99999999999999999999999999999999999999.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 --99999999999999999999999999999999999998.0000000000 -999999999999999999999999999.99999999999999999999999999999999999999 -999999999999999999999999999.99999999999999999999999999999999999999 --99999999999999999999999999999999999999.0000000000 -999999999999999999999999999.99999999999999999999999999999999999999 -999999999999999999999999999.99999999999999999999999999999999999999 +ERROR 42000: The storage engine for the table doesn't support MCS-2060: Union operation exceeds maximum DECIMAL precision of 38. SELECT d1, d2, d3 FROM cs1 UNION SELECT d1, d2, d3 FROM cs1; d1 d2 d3 -125 1.2500000000 0.12500000000000000000000000000000000000 -125 -1.2500000000 -0.12500000000000000000000000000000000000 -99999999999999999999999999999999999998 9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 -99999999999999999999999999999999999999 9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 -99999999999999999999999999999999999998 -9999999999999999999999999999.9999999998 -0.99999999999999999999999999999999999998 -99999999999999999999999999999999999999 -9999999999999999999999999999.9999999999 -0.99999999999999999999999999999999999999 +125 1.2500000000 0.12500000000000000000000000000000000000 +99999999999999999999999999999999999998 9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 +99999999999999999999999999999999999999 9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 INSERT INTO cs2 VALUES (125, 1.25, 0.125); INSERT INTO cs2 values (99999999999999999999999999999999999998, 9999999999999999999999999999.9999999998, 0.99999999999999999999999999999999999998); INSERT INTO cs2 values (99999999999999999999999999999999999999, 9999999999999999999999999999.9999999999, 0.99999999999999999999999999999999999999); SELECT d1, d1, d2 FROM cs2 UNION SELECT d2, d3, d3 FROM cs2; -d1 d1 d2 -125.0000000000 125.00000000000000000000000000000000000000 1.25000000000000000000000000000000000000 -99999999999999999999999999999999999998.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 -99999999999999999999999999999999999999.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 -1.2500000000 0.12500000000000000000000000000000000000 0.12500000000000000000000000000000000000 -9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 0.99999999999999999999999999999999999998 -9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 0.99999999999999999999999999999999999999 +ERROR 42000: The storage engine for the table doesn't support MCS-2060: Union operation exceeds maximum DECIMAL precision of 38. SELECT d2, d3, d3 FROM cs2 UNION SELECT d1, d1, d2 FROM cs2; -d2 d3 d3 -1.2500000000 0.12500000000000000000000000000000000000 0.12500000000000000000000000000000000000 -9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 0.99999999999999999999999999999999999998 -9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 0.99999999999999999999999999999999999999 -125.0000000000 125.00000000000000000000000000000000000000 1.25000000000000000000000000000000000000 -99999999999999999999999999999999999998.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 -99999999999999999999999999999999999999.0000000000 999999999999999999999999999.99999999999999999999999999999999999999 999999999999999999999999999.99999999999999999999999999999999999999 +ERROR 42000: The storage engine for the table doesn't support MCS-2060: Union operation exceeds maximum DECIMAL precision of 38. SELECT d1, d2, d3 FROM cs2 UNION SELECT d1, d2, d3 FROM cs2; d1 d2 d3 125 1.2500000000 0.12500000000000000000000000000000000000 99999999999999999999999999999999999998 9999999999999999999999999999.9999999998 0.99999999999999999999999999999999999998 99999999999999999999999999999999999999 9999999999999999999999999999.9999999999 0.99999999999999999999999999999999999999 +DROP TABLE cs1, cs2; +CREATE TABLE cs1 (d1 DECIMAL(20, 0), d2 DECIMAL(20, 18), d3 DECIMAL(18, 18)) ENGINE=columnstore; +CREATE TABLE cs2 (d1 DECIMAL(20, 0) UNSIGNED, d2 DECIMAL(20, 18) UNSIGNED, d3 DECIMAL(18, 18) UNSIGNED) ENGINE=columnstore; +INSERT INTO cs1 VALUES (12345678901234567890, 12.345678901234567891, 0.123456789012345678); +INSERT INTO cs1 VALUES (-12345678901234567890, -12.345678901234567891, -0.123456789012345678); +INSERT INTO cs1 VALUES (99999999999999999999, 99.999999999999999999, 0.999999999999999999); +INSERT INTO cs1 VALUES (-99999999999999999999, -99.999999999999999999, -0.999999999999999999); +INSERT INTO cs2 VALUES (12345678901234567890, 12.345678901234567891, 0.123456789012345678); +INSERT INTO cs2 VALUES (99999999999999999999, 99.999999999999999999, 0.999999999999999999); +SELECT d1, d1, d2 FROM cs1 UNION SELECT d2, d3, d3 FROM cs1; +d1 d1 d2 +-12.345678901234567891 -0.123456789012345678 -0.123456789012345678 +-12345678901234567890.000000000000000000 -12345678901234567890.000000000000000000 -12.345678901234567891 +-99.999999999999999999 -0.999999999999999999 -0.999999999999999999 +-99999999999999999999.000000000000000000 -99999999999999999999.000000000000000000 -99.999999999999999999 +12.345678901234567891 0.123456789012345678 0.123456789012345678 +12345678901234567890.000000000000000000 12345678901234567890.000000000000000000 12.345678901234567891 +99.999999999999999999 0.999999999999999999 0.999999999999999999 +99999999999999999999.000000000000000000 99999999999999999999.000000000000000000 99.999999999999999999 +SELECT d1, d1, d2 FROM cs2 UNION SELECT d2, d3, d3 FROM cs2; +d1 d1 d2 +12.345678901234567891 0.123456789012345678 0.123456789012345678 +12345678901234567890.000000000000000000 12345678901234567890.000000000000000000 12.345678901234567891 +99.999999999999999999 0.999999999999999999 0.999999999999999999 +99999999999999999999.000000000000000000 99999999999999999999.000000000000000000 99.999999999999999999 DROP DATABASE mcol641_union_db; 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..e69b3ad30 --- /dev/null +++ b/mysql-test/columnstore/basic/r/mdev-25080.result @@ -0,0 +1,313 @@ +# +# MDEV-25080: Allow pushdown of queries involving UNIONs +# in outer select to foreign engines +# +# Remove the sorted_result MTR qualifier 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 +SELECT * FROM t1 UNION SELECT * FROM t2; +a +abc +bcd +cde +def +efg +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 +SELECT * FROM t1 UNION ALL SELECT * FROM t2; +a +abc +bcd +bcd +cde +cde +def +efg +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 +SELECT * FROM t1 UNION SELECT * FROM t3; +a +abc +bcd +cde +t3_myisam1 +t3_myisam2 +t3_myisam3 +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: +SELECT * FROM t1 UNION +SELECT * FROM t2 UNION ALL +SELECT * FROM t1; +a +abc +abc +bcd +bcd +cde +cde +def +efg +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 +(SELECT * FROM t1 UNION +SELECT * FROM t2) UNION ALL +SELECT * FROM t1; +a +abc +abc +bcd +bcd +cde +cde +def +efg +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 +SELECT * FROM t1 UNION +SELECT * FROM t2 UNION ALL +SELECT * FROM t3 UNION +SELECT * FROM t4; +a +abc +bcd +cde +def +efg +t3_myisam1 +t3_myisam2 +t3_myisam3 +t4_myisam1 +t4_myisam2 +t4_myisam3 +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 +(SELECT * FROM t1 UNION +SELECT * FROM t2) UNION ALL +(SELECT * FROM t3 UNION +SELECT * FROM t4); +a +abc +bcd +cde +def +efg +t3_myisam1 +t3_myisam2 +t3_myisam3 +t4_myisam1 +t4_myisam2 +t4_myisam3 +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 +SELECT count(*) FROM t1 UNION +SELECT count(*) FROM t2 UNION ALL +SELECT count(*)+20 FROM t2 UNION +SELECT count(*)+5 FROM t1; +count(*) +24 +3 +4 +8 +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 "SELECT * FROM t1 UNION + SELECT * FROM t2"; +EXECUTE stmt; +a +abc +bcd +cde +def +efg +EXECUTE stmt; +a +abc +bcd +cde +def +efg +EXECUTE stmt; +a +abc +bcd +cde +def +efg +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 "(SELECT * FROM t1 UNION + SELECT * FROM t2) UNION ALL + (SELECT * FROM t1 UNION + SELECT * FROM t2)"; +EXECUTE stmt; +a +abc +abc +bcd +bcd +cde +cde +def +def +efg +efg +EXECUTE stmt; +a +abc +abc +bcd +bcd +cde +cde +def +def +efg +efg +EXECUTE stmt; +a +abc +abc +bcd +bcd +cde +cde +def +def +efg +efg +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 +# MCOL-5432 Disable UNION pushdown if an ORDER BY or a LIMIT +# clause is involved, until MCOL-5222 is fixed. +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a; +a +abc +bcd +bcd +cde +cde +def +efg +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2000 +2 UNION t2 ALL NULL NULL NULL NULL 2000 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL Using filesort +SELECT * FROM t1 UNION ALL SELECT * FROM t2 LIMIT 3; +a +abc +bcd +cde +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 LIMIT 3; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2000 +2 UNION t2 ALL NULL NULL NULL NULL 2000 +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a DESC LIMIT 5; +a +efg +def +cde +cde +bcd +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a DESC LIMIT 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2000 +2 UNION t2 ALL NULL NULL NULL NULL 2000 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL Using filesort +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a LIMIT 3 OFFSET 2; +a +bcd +cde +cde +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a LIMIT 3 OFFSET 2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2000 +2 UNION t2 ALL NULL NULL NULL NULL 2000 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL Using filesort +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..8f0875839 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,58 @@ a 16777213 9223372036854775807 DROP TABLE t1,t2; +# +# Union of tables containing different string data types +# +# Remove the sorted_result MTR qualifier 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'); +SELECT * FROM t1 UNION SELECT * FROM t2; +a +common +t13abc +t13xx +t14abcde +t14xyzzz +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 +SELECT * FROM t2 UNION ALL SELECT * FROM t1; +a +common +common +t13abc +t13xx +t14abcde +t14xyzzz +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 +SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +a +123456789000 +common +t13abc +t13xx +t14abcde +t14xyzzz +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 +SELECT * FROM t1 UNION SELECT '123456789000' UNION SELECT * FROM t2; +a +123456789000 +common +t13abc +t13xx +t14abcde +t14xyzzz +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/mcol641-union.test b/mysql-test/columnstore/basic/t/mcol641-union.test index 5b2ab1aad..5f58a9cd0 100644 --- a/mysql-test/columnstore/basic/t/mcol641-union.test +++ b/mysql-test/columnstore/basic/t/mcol641-union.test @@ -1,5 +1,8 @@ -- source ../include/have_columnstore.inc +--echo # MCOL-641 Union Test Cases +--echo # Once MCOL-5417 is supported, the errored out queries below should be fixed. + --disable_warnings DROP DATABASE IF EXISTS mcol641_union_db; --enable_warnings @@ -19,17 +22,38 @@ INSERT INTO cs1 values (99999999999999999999999999999999999999, 9999999999999999 INSERT INTO cs1 values (-99999999999999999999999999999999999998, -9999999999999999999999999999.9999999998, -0.99999999999999999999999999999999999998); INSERT INTO cs1 values (-99999999999999999999999999999999999999, -9999999999999999999999999999.9999999999, -0.99999999999999999999999999999999999999); +--error ER_CHECK_NOT_IMPLEMENTED SELECT d1, d1, d2 FROM cs1 UNION SELECT d2, d3, d3 FROM cs1; +--error ER_CHECK_NOT_IMPLEMENTED SELECT d2, d3, d3 FROM cs1 UNION SELECT d1, d1, d2 FROM cs1; +--sorted_result SELECT d1, d2, d3 FROM cs1 UNION SELECT d1, d2, d3 FROM cs1; INSERT INTO cs2 VALUES (125, 1.25, 0.125); INSERT INTO cs2 values (99999999999999999999999999999999999998, 9999999999999999999999999999.9999999998, 0.99999999999999999999999999999999999998); INSERT INTO cs2 values (99999999999999999999999999999999999999, 9999999999999999999999999999.9999999999, 0.99999999999999999999999999999999999999); +--error ER_CHECK_NOT_IMPLEMENTED SELECT d1, d1, d2 FROM cs2 UNION SELECT d2, d3, d3 FROM cs2; +--error ER_CHECK_NOT_IMPLEMENTED SELECT d2, d3, d3 FROM cs2 UNION SELECT d1, d1, d2 FROM cs2; +--sorted_result SELECT d1, d2, d3 FROM cs2 UNION SELECT d1, d2, d3 FROM cs2; +DROP TABLE cs1, cs2; +CREATE TABLE cs1 (d1 DECIMAL(20, 0), d2 DECIMAL(20, 18), d3 DECIMAL(18, 18)) ENGINE=columnstore; +CREATE TABLE cs2 (d1 DECIMAL(20, 0) UNSIGNED, d2 DECIMAL(20, 18) UNSIGNED, d3 DECIMAL(18, 18) UNSIGNED) ENGINE=columnstore; +INSERT INTO cs1 VALUES (12345678901234567890, 12.345678901234567891, 0.123456789012345678); +INSERT INTO cs1 VALUES (-12345678901234567890, -12.345678901234567891, -0.123456789012345678); +INSERT INTO cs1 VALUES (99999999999999999999, 99.999999999999999999, 0.999999999999999999); +INSERT INTO cs1 VALUES (-99999999999999999999, -99.999999999999999999, -0.999999999999999999); +INSERT INTO cs2 VALUES (12345678901234567890, 12.345678901234567891, 0.123456789012345678); +INSERT INTO cs2 VALUES (99999999999999999999, 99.999999999999999999, 0.999999999999999999); + +--sorted_result +SELECT d1, d1, d2 FROM cs1 UNION SELECT d2, d3, d3 FROM cs1; +--sorted_result +SELECT d1, d1, d2 FROM cs2 UNION SELECT d2, d3, d3 FROM cs2; + # Clean UP DROP DATABASE mcol641_union_db; 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..98ac13802 --- /dev/null +++ b/mysql-test/columnstore/basic/t/mdev-25080.test @@ -0,0 +1,185 @@ +--echo # +--echo # MDEV-25080: Allow pushdown of queries involving UNIONs +--echo # in outer select to foreign engines +--echo # +--echo # Remove the sorted_result MTR qualifier and add ORDER BY +--echo # clause after MCOL-5222 is fixed +--echo # + +--source ../include/have_columnstore.inc + +if (!$MASTER_MYPORT) +{ + # Running with --extern + let $MASTER_MYPORT=`SELECT @@port`; +} + +# +# 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 +--sorted_result +SELECT * FROM t1 UNION SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; + +--sorted_result +SELECT * FROM t1 UNION ALL SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2; + +--echo # UNION with a foreign engine +--sorted_result +SELECT * FROM t1 UNION SELECT * FROM t3; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t3; + +--echo # More than two SELECTs in a UNIT: +--sorted_result +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; + +--sorted_result +(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; + +--sorted_result +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; + +--sorted_result +(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); + +--sorted_result +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"; + +--sorted_result +EXECUTE stmt; +--sorted_result +EXECUTE stmt; +--sorted_result +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)"; + +--sorted_result +EXECUTE stmt; +--sorted_result +EXECUTE stmt; +--sorted_result +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; + +--echo # MCOL-5432 Disable UNION pushdown if an ORDER BY or a LIMIT +--echo # clause is involved, until MCOL-5222 is fixed. +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a; +SELECT * FROM t1 UNION ALL SELECT * FROM t2 LIMIT 3; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 LIMIT 3; +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a DESC LIMIT 5; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a DESC LIMIT 5; +SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a LIMIT 3 OFFSET 2; +EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY a LIMIT 3 OFFSET 2; + +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..0ae580161 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,29 @@ 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 # Remove the sorted_result MTR qualifier 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'); +--sorted_result +SELECT * FROM t1 UNION SELECT * FROM t2; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2; +--sorted_result +SELECT * FROM t2 UNION ALL SELECT * FROM t1; +EXPLAIN SELECT * FROM t2 UNION ALL SELECT * FROM t1; +--sorted_result +SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT '123456789000'; +--sorted_result +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; diff --git a/utils/dataconvert/dataconvert.cpp b/utils/dataconvert/dataconvert.cpp index 147417aaf..c439a2cbc 100644 --- a/utils/dataconvert/dataconvert.cpp +++ b/utils/dataconvert/dataconvert.cpp @@ -2934,7 +2934,8 @@ int64_t DataConvert::stringToTime(const string& data) } void DataConvert::joinColTypeForUnion(datatypes::SystemCatalog::TypeHolderStd& unionedType, - const datatypes::SystemCatalog::TypeHolderStd& type) + const datatypes::SystemCatalog::TypeHolderStd& type, + unsigned int& rc) { // limited support for VARBINARY, no implicit conversion. if (type.colDataType == datatypes::SystemCatalog::VARBINARY || @@ -2974,7 +2975,31 @@ void DataConvert::joinColTypeForUnion(datatypes::SystemCatalog::TypeHolderStd& u case datatypes::SystemCatalog::UBIGINT: case datatypes::SystemCatalog::UDECIMAL: - unionedType.precision = std::max(type.precision, unionedType.precision); + if (type.scale != 0 && (unionedType.scale != 0 || isDecimal(unionedType.colDataType))) + { + const unsigned int digitsBeforeDecimal = type.precision - type.scale; + const unsigned int digitsBeforeDecimalUnion = unionedType.precision - unionedType.scale; + + if ((std::max(digitsBeforeDecimal, digitsBeforeDecimalUnion) + + std::max(type.scale, unionedType.scale)) > datatypes::INT128MAXPRECISION) + { + rc = logging::ERR_UNION_DECIMAL_OVERFLOW; + return; + } + } + + // Handle the scenario where the upstream code assigns special values of 9999 + // and -1 as the precision of the unionedType. + if ((unionedType.precision == 9999 || unionedType.precision == -1) && + (type.precision != 9999 && type.precision != -1)) + { + unionedType.precision = type.precision; + } + else + { + unionedType.precision = std::max(type.precision, unionedType.precision); + } + unionedType.scale = std::max(type.scale, unionedType.scale); if (datatypes::Decimal::isWideDecimalTypeByPrecision(unionedType.precision)) @@ -3042,6 +3067,10 @@ void DataConvert::joinColTypeForUnion(datatypes::SystemCatalog::TypeHolderStd& u case datatypes::SystemCatalog::UFLOAT: case datatypes::SystemCatalog::UDOUBLE: case datatypes::SystemCatalog::LONGDOUBLE: + if (datatypes::isWideDecimalType(type.colDataType, type.colWidth)) + unionedType = type; + break; + default: break; } diff --git a/utils/dataconvert/dataconvert.h b/utils/dataconvert/dataconvert.h index e42514ce7..d77ec57d7 100644 --- a/utils/dataconvert/dataconvert.h +++ b/utils/dataconvert/dataconvert.h @@ -1290,7 +1290,8 @@ class DataConvert EXPORT static int64_t stringToTime(const std::string& data); // bug4388, union type conversion EXPORT static void joinColTypeForUnion(datatypes::SystemCatalog::TypeHolderStd& unionedType, - const datatypes::SystemCatalog::TypeHolderStd& type); + const datatypes::SystemCatalog::TypeHolderStd& type, + unsigned int& rc); static boost::any StringToBit(const datatypes::SystemCatalog::TypeAttributesStd& colType, const datatypes::ConvertFromStringParam& prm, const std::string& dataOrig, diff --git a/utils/loggingcpp/ErrorMessage.txt b/utils/loggingcpp/ErrorMessage.txt index f90366206..64c519865 100755 --- a/utils/loggingcpp/ErrorMessage.txt +++ b/utils/loggingcpp/ErrorMessage.txt @@ -106,6 +106,8 @@ 2058 ERR_DISKAGG_OVERFLOW1 The hash function used produces a lot of hash collisions (1). 2059 ERR_DISKAGG_OVERFLOW2 The hash function used produces a lot of hash collisions (2). +2060 ERR_UNION_DECIMAL_OVERFLOW Union operation exceeds maximum DECIMAL precision of 38. + # Sub-query errors 3001 ERR_NON_SUPPORT_SUB_QUERY_TYPE This subquery type is not supported yet. 3002 ERR_MORE_THAN_1_ROW Subquery returns more than 1 row.