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