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
Merge pull request #1935 from tntnatbry/MCOL-4665
MCOL-4665 Move outer join to inner join conversion into the engine.
This commit is contained in:
@ -59,6 +59,7 @@ using namespace logging;
|
|||||||
#include "ha_mcs_impl_if.h"
|
#include "ha_mcs_impl_if.h"
|
||||||
#include "ha_mcs_sysvars.h"
|
#include "ha_mcs_sysvars.h"
|
||||||
#include "ha_subquery.h"
|
#include "ha_subquery.h"
|
||||||
|
#include "ha_mcs_pushdown.h"
|
||||||
using namespace cal_impl_if;
|
using namespace cal_impl_if;
|
||||||
|
|
||||||
#include "calpontselectexecutionplan.h"
|
#include "calpontselectexecutionplan.h"
|
||||||
@ -136,6 +137,142 @@ public:
|
|||||||
namespace cal_impl_if
|
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)
|
CalpontSystemCatalog::TableAliasName makeTableAliasName(TABLE_LIST* table)
|
||||||
{
|
{
|
||||||
return make_aliasview(
|
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)
|
if (table->nested_join && !table->derived)
|
||||||
buildJoin(gwi, table->nested_join->join_list, outerJoinStack);
|
buildJoin(gwi, table->nested_join->join_list, outerJoinStack);
|
||||||
|
|
||||||
if (table->on_expr)
|
std::vector<COND*> tableOnExprList;
|
||||||
{
|
|
||||||
Item_cond* expr = reinterpret_cast<Item_cond*>(table->on_expr);
|
|
||||||
|
|
||||||
|
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))
|
if (table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT))
|
||||||
{
|
{
|
||||||
// inner tables block
|
// inner tables block
|
||||||
@ -1312,18 +1463,23 @@ uint32_t buildJoin(gp_walk_info& gwi, List<TABLE_LIST>& join_list,
|
|||||||
cerr << endl;
|
cerr << endl;
|
||||||
|
|
||||||
cerr << " outer table expression: " << 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
|
#endif
|
||||||
|
|
||||||
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
for (Item* expr : tableOnExprList)
|
||||||
|
|
||||||
// Error out subquery in outer join on filter for now
|
|
||||||
if (gwi_outer.hasSubSelect)
|
|
||||||
{
|
{
|
||||||
gwi.fatalParseError = true;
|
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
||||||
gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_OUTER_JOIN_SUBSELECT);
|
|
||||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText);
|
// Error out subquery in outer join on filter for now
|
||||||
return -1;
|
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
|
// build outerjoinon filter
|
||||||
@ -1356,11 +1512,15 @@ uint32_t buildJoin(gp_walk_info& gwi, List<TABLE_LIST>& join_list,
|
|||||||
}
|
}
|
||||||
else // inner join
|
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
|
#ifdef DEBUG_WALK_COND
|
||||||
cerr << " inner join expression: " << endl;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2667,6 +2827,22 @@ void setError(THD* thd, uint32_t errcode, string errmsg, gp_walk_info& gwi)
|
|||||||
clearStacks(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)
|
const string bestTableName(const Item_field* ifp)
|
||||||
{
|
{
|
||||||
idbassert(ifp);
|
idbassert(ifp);
|
||||||
@ -6364,7 +6540,6 @@ int processFrom(bool &isUnion,
|
|||||||
csep->distinctUnionNum(distUnionNum);
|
csep->distinctUnionNum(distUnionNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6382,24 +6557,24 @@ int processWhere(SELECT_LEX &select_lex,
|
|||||||
const std::vector<COND*>& condStack)
|
const std::vector<COND*>& condStack)
|
||||||
{
|
{
|
||||||
JOIN* join = select_lex.join;
|
JOIN* join = select_lex.join;
|
||||||
Item_cond* icp = 0;
|
Item* icp = 0;
|
||||||
bool isUpdateDelete = false;
|
bool isUpdateDelete = false;
|
||||||
|
|
||||||
// Flag to indicate if this is a prepared statement
|
// Flag to indicate if this is a prepared statement
|
||||||
bool isPS = gwi.thd->stmt_arena && gwi.thd->stmt_arena->is_stmt_execute();
|
bool isPS = gwi.thd->stmt_arena && gwi.thd->stmt_arena->is_stmt_execute();
|
||||||
|
|
||||||
if (join != 0 && !isPS)
|
if (join != 0 && !isPS)
|
||||||
icp = reinterpret_cast<Item_cond*>(join->conds);
|
icp = join->conds;
|
||||||
else if (isPS && select_lex.prep_where)
|
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 icp is null, try to find the where clause other where
|
||||||
if (!join && gwi.thd->lex->derived_tables)
|
if (!join && gwi.thd->lex->derived_tables)
|
||||||
{
|
{
|
||||||
if (select_lex.prep_where)
|
if (select_lex.prep_where)
|
||||||
icp = (Item_cond*)(select_lex.prep_where);
|
icp = select_lex.prep_where;
|
||||||
else if (select_lex.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 ) ||
|
else if (!join && ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) ||
|
||||||
((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) ||
|
((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) ||
|
||||||
@ -6429,20 +6604,7 @@ int processWhere(SELECT_LEX &select_lex,
|
|||||||
|
|
||||||
if (gwi.fatalParseError)
|
if (gwi.fatalParseError)
|
||||||
{
|
{
|
||||||
// if this is dervied table process phase, mysql may have not developed the plan
|
return setErrorAndReturn(gwi);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isUpdateDelete)
|
else if (isUpdateDelete)
|
||||||
@ -6460,33 +6622,19 @@ int processWhere(SELECT_LEX &select_lex,
|
|||||||
|
|
||||||
if (gwi.fatalParseError)
|
if (gwi.fatalParseError)
|
||||||
{
|
{
|
||||||
if (gwi.thd->derived_tables_processing)
|
return setErrorAndReturn(gwi);
|
||||||
{
|
|
||||||
gwi.cs_vtable_is_update_with_derive = true;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi);
|
|
||||||
return ER_INTERNAL_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if condStack is empty(), check the select_lex for where conditions
|
// if condStack is empty(), check the select_lex for where conditions
|
||||||
// as a last resort
|
// 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);
|
icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX);
|
||||||
|
|
||||||
if (gwi.fatalParseError)
|
if (gwi.fatalParseError)
|
||||||
{
|
{
|
||||||
if (gwi.thd->derived_tables_processing)
|
return setErrorAndReturn(gwi);
|
||||||
{
|
|
||||||
gwi.cs_vtable_is_update_with_derive = true;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi);
|
|
||||||
return ER_INTERNAL_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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());
|
(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
|
// ZZ - the followinig debug shows the structure of nested outer join. should
|
||||||
// use a recursive function.
|
// use a recursive function.
|
||||||
#ifdef OUTER_JOIN_DEBUG
|
#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;
|
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);
|
int status = getSelectPlan(gwi, select_lex, csep, false);
|
||||||
|
|
||||||
if (status > 0)
|
if (status > 0)
|
||||||
@ -8372,9 +8533,20 @@ int cs_get_derived_plan(derived_handler* handler, THD* thd, SCSEP& csep, gp_walk
|
|||||||
return 0;
|
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);
|
int status = getSelectPlan(gwi, select_lex, csep, false, true);
|
||||||
|
|
||||||
if (status > 0)
|
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;
|
sm::cpsm_conhdl_t* hndl;
|
||||||
SCSEP csep;
|
SCSEP csep;
|
||||||
// Declare handlers ptrs in this scope for future use.
|
// Declare handlers ptrs in this scope for future use.
|
||||||
select_handler* sh = nullptr;
|
ha_columnstore_select_handler* sh = nullptr;
|
||||||
derived_handler* dh = nullptr;
|
ha_columnstore_derived_handler* dh = nullptr;
|
||||||
|
|
||||||
// update traceFlags according to the autoswitch state.
|
// update traceFlags according to the autoswitch state.
|
||||||
ci->traceFlags = (ci->traceFlags | CalpontSelectExecutionPlan::TRACE_TUPLE_OFF)^
|
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;
|
int status = 42;
|
||||||
if (handler_info->hndl_type == mcs_handler_types_t::SELECT)
|
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);
|
status = cs_get_select_plan(sh, thd, csep, gwi);
|
||||||
}
|
}
|
||||||
else if (handler_info->hndl_type == DERIVED)
|
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);
|
status = cs_get_derived_plan(dh, thd, csep, gwi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "idb_mysql.h"
|
#include "idb_mysql.h"
|
||||||
|
|
||||||
struct st_ha_create_information;
|
struct st_ha_create_information;
|
||||||
|
class ha_columnstore_select_handler;
|
||||||
|
class ha_columnstore_derived_handler;
|
||||||
|
|
||||||
#include "configcpp.h"
|
#include "configcpp.h"
|
||||||
#include "idberrorinfo.h"
|
#include "idberrorinfo.h"
|
||||||
@ -89,7 +91,8 @@ enum ClauseType
|
|||||||
|
|
||||||
typedef std::vector<JoinInfo> JoinInfoVec;
|
typedef std::vector<JoinInfo> JoinInfoVec;
|
||||||
typedef std::map<execplan::CalpontSystemCatalog::TableAliasName, std::pair<int, TABLE_LIST*> > TableMap;
|
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
|
struct gp_walk_info
|
||||||
{
|
{
|
||||||
@ -164,6 +167,10 @@ struct gp_walk_info
|
|||||||
execplan::ReturnedColumn* inSubQueryLHS;
|
execplan::ReturnedColumn* inSubQueryLHS;
|
||||||
Item* inSubQueryLHSItem;
|
Item* inSubQueryLHSItem;
|
||||||
|
|
||||||
|
// The below 2 fields are required for MCOL-4525.
|
||||||
|
TableOnExprList tableOnExprList;
|
||||||
|
std::vector<COND*> condList;
|
||||||
|
|
||||||
gp_walk_info() : sessionid(0),
|
gp_walk_info() : sessionid(0),
|
||||||
fatalParseError(false),
|
fatalParseError(false),
|
||||||
condPush(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_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_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 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_derived_plan(ha_columnstore_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_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 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);
|
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);
|
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"
|
#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*/
|
/*@brief in_subselect_rewrite_walk - Rewrites Item_in_subselect*/
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -367,27 +139,3 @@ bool in_subselect_rewrite(SELECT_LEX *select_lex)
|
|||||||
|
|
||||||
return result;
|
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);
|
bool in_subselect_rewrite(SELECT_LEX *select_lex);
|
||||||
void opt_flag_unset_PS(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
|
#endif
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
void check_walk(const Item* item, void* arg);
|
void check_walk(const Item* item, void* arg);
|
||||||
|
|
||||||
|
|
||||||
void disable_indices_for_CEJ(THD *thd_)
|
void disable_indices_for_CEJ(THD *thd_)
|
||||||
{
|
{
|
||||||
TABLE_LIST* global_list;
|
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
|
// MCOL-652 - doing this with derived tables can cause bad things to happen
|
||||||
if (!global_list->derived)
|
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)
|
global_list->index_hints->push_front(new (thd_->mem_root)
|
||||||
Index_hint(INDEX_HINT_USE,
|
Index_hint(INDEX_HINT_USE,
|
||||||
@ -84,8 +83,8 @@ void find_tables(const Item* item, void* arg)
|
|||||||
{
|
{
|
||||||
if (typeid(*item) == typeid(Item_field))
|
if (typeid(*item) == typeid(Item_field))
|
||||||
{
|
{
|
||||||
Item_field *ifp= (Item_field*)item;
|
Item_field *ifp = (Item_field*)item;
|
||||||
List<TABLE> *tables_list= (List<TABLE>*)arg;
|
List<TABLE> *tables_list = (List<TABLE>*)arg;
|
||||||
tables_list->push_back(ifp->field->table);
|
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 &&
|
if (ifp->arguments()[0]->type() == Item::FIELD_ITEM &&
|
||||||
ifp->arguments()[1]->type() == Item::FIELD_ITEM)
|
ifp->arguments()[1]->type() == Item::FIELD_ITEM)
|
||||||
{
|
{
|
||||||
Item_field* left= reinterpret_cast<Item_field*>(ifp->arguments()[0]);
|
Item_field* left = reinterpret_cast<Item_field*>(ifp->arguments()[0]);
|
||||||
Item_field* right= reinterpret_cast<Item_field*>(ifp->arguments()[1]);
|
Item_field* right = reinterpret_cast<Item_field*>(ifp->arguments()[1]);
|
||||||
|
|
||||||
// If MDB crashes here with non-fixed Item_field and field == NULL
|
// 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.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
List<TABLE>llt; List<TABLE>rlt;
|
List<TABLE>llt; List<TABLE>rlt;
|
||||||
Item *left= ifp->arguments()[0];
|
Item *left = ifp->arguments()[0];
|
||||||
Item *right= ifp->arguments()[1];
|
Item *right = ifp->arguments()[1];
|
||||||
// Search for tables inside left and right expressions
|
// Search for tables inside left and right expressions
|
||||||
// and compare them
|
// and compare them
|
||||||
left->traverse_cond(find_tables, (void*)&llt, Item::POSTFIX);
|
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.
|
// the idea is useless.
|
||||||
if (llt.elements && rlt.elements && (llt.elem(0) != rlt.elem(0)))
|
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)
|
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 )
|
if ( *unsupported_feature )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -184,7 +183,7 @@ void find_nonequi_join(const Item* item, void *arg)
|
|||||||
***********************************************************/
|
***********************************************************/
|
||||||
void find_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 )
|
if ( *unsupported_feature )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -219,10 +218,10 @@ void save_join_predicates(const Item* item, void* arg)
|
|||||||
{
|
{
|
||||||
if (item->type() == Item::FUNC_ITEM)
|
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))
|
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));
|
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)
|
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 )
|
if ( *unsupported_feature )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -307,7 +306,7 @@ void check_walk(const Item* item, void* arg)
|
|||||||
***********************************************************/
|
***********************************************************/
|
||||||
void check_user_var_func(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)
|
if (*unsupported_feature)
|
||||||
return;
|
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())
|
if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute())
|
||||||
return handler;
|
return handler;
|
||||||
|
|
||||||
SELECT_LEX_UNIT *unit= table_ptr->derived;
|
SELECT_LEX_UNIT *unit = table_ptr->derived;
|
||||||
SELECT_LEX *sl= unit->first_select();
|
SELECT_LEX *sl = unit->first_select();
|
||||||
|
|
||||||
bool unsupported_feature = false;
|
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 expression from WHERE, ON expressions
|
||||||
JOIN* join= sl->join;
|
JOIN* join = sl->join;
|
||||||
//TODO DRRTUY Make a proper tree traverse
|
//TODO DRRTUY Make a proper tree traverse
|
||||||
//To search for CROSS JOIN-s we use tree invariant
|
//To search for CROSS JOIN-s we use tree invariant
|
||||||
//G(V,E) where [V] = [E]+1
|
//G(V,E) where [V] = [E]+1
|
||||||
@ -533,7 +532,7 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr)
|
|||||||
{
|
{
|
||||||
if (tl->where)
|
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(check_walk, &unsupported_feature, Item::POSTFIX);
|
||||||
where_icp->traverse_cond(save_join_predicates, &join_preds_list, 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
|
// TABLE_LIST in FROM until CS meets unsupported feature
|
||||||
if (tl->on_expr)
|
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(check_walk, &unsupported_feature, Item::POSTFIX);
|
||||||
on_icp->traverse_cond(save_join_predicates, &join_preds_list, 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
|
if (!unsupported_feature && !join_preds_list.elements
|
||||||
&& join && join->conds)
|
&& 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(check_walk, &unsupported_feature, Item::POSTFIX);
|
||||||
conds->traverse_cond(save_join_predicates, &join_preds_list, 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
|
if (!unsupported_feature && join
|
||||||
&& join->table_count >= 2 && !join_preds_list.elements)
|
&& join->table_count >= 2 && !join_preds_list.elements)
|
||||||
{
|
{
|
||||||
unsupported_feature= true;
|
unsupported_feature = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CROSS JOIN with not enough JOIN predicates
|
// CROSS JOIN with not enough JOIN predicates
|
||||||
if(!unsupported_feature && join
|
if(!unsupported_feature && join
|
||||||
&& join_preds_list.elements < join->table_count-1)
|
&& join_preds_list.elements < join->table_count-1)
|
||||||
{
|
{
|
||||||
unsupported_feature= true;
|
unsupported_feature = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !unsupported_feature )
|
if (!unsupported_feature)
|
||||||
handler= new ha_columnstore_derived_handler(thd, table_ptr);
|
handler = new ha_columnstore_derived_handler(thd, table_ptr);
|
||||||
|
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
@ -619,7 +618,7 @@ int ha_columnstore_derived_handler::init_scan()
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("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
|
// this::table is the place for the result set
|
||||||
int rc = ha_mcs_impl_pushdown_init(&mhi, table);
|
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
|
* More details in server/sql/select_handler.h
|
||||||
* PARAMETERS:
|
* PARAMETERS:
|
||||||
* thd - THD pointer.
|
* thd - THD pointer.
|
||||||
* sel - SELECT_LEX* that describes the query.
|
* select_lex - SELECT_LEX* that describes the query.
|
||||||
* RETURN:
|
* RETURN:
|
||||||
* select_handler if possible
|
* select_handler if possible
|
||||||
* NULL in other case
|
* 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
|
// 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
|
// becomes dirty and CS has to raise an error in case of any problem
|
||||||
// or unsupported feature.
|
// or unsupported feature.
|
||||||
handler= new ha_columnstore_select_handler(thd, select_lex);
|
handler = new ha_columnstore_select_handler(thd, select_lex);
|
||||||
JOIN *join= select_lex->join;
|
JOIN *join = select_lex->join;
|
||||||
bool unsupported_feature = false;
|
bool unsupported_feature = false;
|
||||||
{
|
{
|
||||||
Query_arena *arena, backup;
|
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);
|
disable_indices_for_CEJ(thd);
|
||||||
|
|
||||||
if (arena)
|
if (arena)
|
||||||
@ -822,25 +820,20 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex)
|
|||||||
COND *conds = nullptr;
|
COND *conds = nullptr;
|
||||||
if (!unsupported_feature)
|
if (!unsupported_feature)
|
||||||
{
|
{
|
||||||
SELECT_LEX *sel= select_lex;
|
|
||||||
// Rewrite once for PS
|
// Rewrite once for PS
|
||||||
// Refer to JOIN::optimize_inner() in sql/sql_select.cc
|
// Refer to JOIN::optimize_inner() in sql/sql_select.cc
|
||||||
// for details on the optimizations performed in this block.
|
// 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);
|
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
|
||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
arena = thd->activate_stmt_arena_if_needed(&backup);
|
||||||
sel->first_cond_optimization= false;
|
select_lex->first_cond_optimization= false;
|
||||||
|
conds = join->conds;
|
||||||
conds= simplify_joins_mcs(join, select_lex->join_list,
|
select_lex->where = conds;
|
||||||
join->conds, true, false);
|
|
||||||
|
|
||||||
build_bitmap_for_nested_joins_mcs(select_lex->join_list, 0);
|
|
||||||
sel->where= conds;
|
|
||||||
|
|
||||||
if (isPS)
|
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();
|
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);
|
thd->restore_active_arena(arena, &backup);
|
||||||
|
|
||||||
// Unset SL::first_cond_optimization
|
// Unset SL::first_cond_optimization
|
||||||
opt_flag_unset_PS(sel);
|
opt_flag_unset_PS(select_lex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!unsupported_feature && conds)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_WALK_COND
|
#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
|
#endif
|
||||||
join->conds = conds;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We shouldn't raise error now so set an error to raise it later in init_SH.
|
// We shouldn't raise error now so set an error to raise it later in init_SH.
|
||||||
handler->rewrite_error= unsupported_feature;
|
handler->rewrite_error = unsupported_feature;
|
||||||
// Return SH even if init fails b/c CS changed SELECT_LEX structures
|
// Return SH even if init fails
|
||||||
// with simplify_joins_mcs()
|
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,8 +871,8 @@ ha_columnstore_select_handler::ha_columnstore_select_handler(THD *thd,
|
|||||||
SELECT_LEX* select_lex)
|
SELECT_LEX* select_lex)
|
||||||
: select_handler(thd, mcs_hton)
|
: select_handler(thd, mcs_hton)
|
||||||
{
|
{
|
||||||
select= select_lex;
|
select = select_lex;
|
||||||
rewrite_error= false;
|
rewrite_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************
|
/***********************************************************
|
||||||
@ -913,16 +904,15 @@ int ha_columnstore_select_handler::init_scan()
|
|||||||
// Skip execution for EXPLAIN queries
|
// Skip execution for EXPLAIN queries
|
||||||
if (!thd->lex->describe)
|
if (!thd->lex->describe)
|
||||||
{
|
{
|
||||||
mcs_handler_info mhi= mcs_handler_info(
|
mcs_handler_info mhi(reinterpret_cast<void*>(this), SELECT);
|
||||||
reinterpret_cast<void*>(this), SELECT);
|
rc = ha_mcs_impl_pushdown_init(&mhi, this->table);
|
||||||
rc= ha_mcs_impl_pushdown_init(&mhi, this->table);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), err_msg.c_str());
|
my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), err_msg.c_str());
|
||||||
sql_print_error("%s", err_msg.c_str());
|
sql_print_error("%s", err_msg.c_str());
|
||||||
rc= ER_INTERNAL_ERROR;
|
rc = ER_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(rc);
|
DBUG_RETURN(rc);
|
||||||
@ -942,7 +932,7 @@ int ha_columnstore_select_handler::next_row()
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("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);
|
DBUG_RETURN(rc);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
bool rewrite_error;
|
bool rewrite_error;
|
||||||
std::string err_msg;
|
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(THD* thd_arg, SELECT_LEX* sel);
|
||||||
~ha_columnstore_select_handler();
|
~ha_columnstore_select_handler();
|
||||||
int init_scan() override;
|
int init_scan() override;
|
||||||
|
223
mysql-test/columnstore/basic/r/mcol-4665.result
Normal file
223
mysql-test/columnstore/basic/r/mcol-4665.result
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#
|
||||||
|
# MCOL-4665 Move outer join to inner join conversion into the engine.
|
||||||
|
#
|
||||||
|
DROP DATABASE IF EXISTS mcol4665;
|
||||||
|
CREATE DATABASE mcol4665;
|
||||||
|
USE mcol4665;
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
create table t3 (a int);
|
||||||
|
create table t4 (a int);
|
||||||
|
insert into t1 values (1), (2), (3), (4);
|
||||||
|
insert into t2 values (2), (3), (4);
|
||||||
|
insert into t3 values (3), (4);
|
||||||
|
insert into t4 values (4);
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a order by 1,2;
|
||||||
|
a a
|
||||||
|
1 NULL
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a where t2.a < 100 order by 1,2;
|
||||||
|
a a
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a where t2.a is null order by 1,2;
|
||||||
|
a a
|
||||||
|
1 NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 NULL NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 NULL NULL
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
2 2 NULL
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a < 100 order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
3 3 3
|
||||||
|
4 4 4
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a is null order by 1,2,3;
|
||||||
|
a a a
|
||||||
|
1 NULL NULL
|
||||||
|
2 2 NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
3 3 3 NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 3 NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
4 4 4 4
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a is null order by 1,2,3,4;
|
||||||
|
a a a a
|
||||||
|
1 NULL NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
3 3 NULL NULL
|
||||||
|
DROP DATABASE mcol4665;
|
84
mysql-test/columnstore/basic/t/mcol-4665.test
Normal file
84
mysql-test/columnstore/basic/t/mcol-4665.test
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
--source ../include/have_columnstore.inc
|
||||||
|
--source ctype_cmp_combinations.inc
|
||||||
|
--source default_storage_engine_by_combination.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MCOL-4665 Move outer join to inner join conversion into the engine.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
DROP DATABASE IF EXISTS mcol4665;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
CREATE DATABASE mcol4665;
|
||||||
|
USE mcol4665;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
create table t3 (a int);
|
||||||
|
create table t4 (a int);
|
||||||
|
insert into t1 values (1), (2), (3), (4);
|
||||||
|
insert into t2 values (2), (3), (4);
|
||||||
|
insert into t3 values (3), (4);
|
||||||
|
insert into t4 values (4);
|
||||||
|
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a order by 1,2;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a where t2.a < 100 order by 1,2;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a where t2.a is null order by 1,2;
|
||||||
|
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t2.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t1.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t2.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 on t2.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a < 100 order by 1,2,3;
|
||||||
|
# Below query is disabled until MCOL-4715 is fixed
|
||||||
|
# select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t2.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t3.a where t3.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t2.a is null order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a < 100 order by 1,2,3;
|
||||||
|
select * from t1 left join t2 left join t3 on t2.a=t3.a on t1.a=t2.a where t3.a is null order by 1,2,3;
|
||||||
|
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t2.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t3.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t3.a where t4.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t2.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
# Below query is disabled until MCOL-4715 is fixed
|
||||||
|
# select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t3.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t1.a=t4.a where t4.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t2.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t3.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t3.a where t4.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t2.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a < 100 order by 1,2,3,4;
|
||||||
|
# Below query is disabled until MCOL-4715 is fixed
|
||||||
|
# select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t3.a is null order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a < 100 order by 1,2,3,4;
|
||||||
|
select * from t1 left join t2 on t1.a=t2.a left join t3 left join t4 on t3.a=t4.a on t2.a=t4.a where t4.a is null order by 1,2,3,4;
|
||||||
|
|
||||||
|
DROP DATABASE mcol4665;
|
Reference in New Issue
Block a user