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 #1912 from tntnatbry/MCOL-4680-dev
MCOL-4680 FROM subquery containing nested joins returns an error.
This commit is contained in:
@ -134,6 +134,15 @@ public:
|
||||
namespace cal_impl_if
|
||||
{
|
||||
|
||||
CalpontSystemCatalog::TableAliasName makeTableAliasName(TABLE_LIST* table)
|
||||
{
|
||||
return make_aliasview(
|
||||
(table->db.length ? table->db.str : ""),
|
||||
(table->table_name.length ? table->table_name.str : ""),
|
||||
(table->alias.length ? table->alias.str : ""),
|
||||
getViewName(table), true, lower_case_table_names);
|
||||
}
|
||||
|
||||
//@bug5228. need to escape backtick `
|
||||
string escapeBackTick(const char* str)
|
||||
{
|
||||
@ -1239,245 +1248,122 @@ void debug_walk(const Item* item, void* arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
void buildNestedTableOuterJoin(gp_walk_info& gwi, TABLE_LIST* table_ptr)
|
||||
void buildNestedJoinLeafTables(List<TABLE_LIST>& join_list,
|
||||
std::set<execplan::CalpontSystemCatalog::TableAliasName>& leafTables)
|
||||
{
|
||||
TABLE_LIST* table;
|
||||
List_iterator<TABLE_LIST> li(table_ptr->nested_join->join_list);
|
||||
TABLE_LIST *table;
|
||||
List_iterator<TABLE_LIST> li(join_list);
|
||||
|
||||
while ((table = li++))
|
||||
{
|
||||
gwi.innerTables.clear();
|
||||
|
||||
if (table->outer_join)
|
||||
{
|
||||
CalpontSystemCatalog::TableAliasName ta = make_aliasview(
|
||||
(table->db.length ? table->db.str : ""),
|
||||
(table->table_name.length ? table->table_name.str : ""),
|
||||
(table->alias.length ? table->alias.str : ""),
|
||||
getViewName(table), true, lower_case_table_names);
|
||||
gwi.innerTables.insert(ta);
|
||||
}
|
||||
|
||||
if (table->nested_join)
|
||||
buildNestedJoinLeafTables(table->nested_join->join_list, leafTables);
|
||||
else
|
||||
{
|
||||
TABLE_LIST* tab;
|
||||
List_iterator<TABLE_LIST> li(table->nested_join->join_list);
|
||||
|
||||
while ((tab = li++))
|
||||
{
|
||||
CalpontSystemCatalog::TableAliasName ta = make_aliasview(
|
||||
(tab->db.length ? tab->db.str : ""),
|
||||
(tab->table_name.length ? tab->table_name.str : ""),
|
||||
(tab->alias.length ? tab->alias.str : ""),
|
||||
getViewName(tab), true, lower_case_table_names);
|
||||
gwi.innerTables.insert(ta);
|
||||
}
|
||||
}
|
||||
|
||||
if (table->on_expr)
|
||||
{
|
||||
Item_cond* expr = reinterpret_cast<Item_cond*>(table->on_expr);
|
||||
#ifdef DEBUG_WALK_COND
|
||||
expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX);
|
||||
#endif
|
||||
expr->traverse_cond(gp_walk, &gwi, Item::POSTFIX);
|
||||
}
|
||||
|
||||
if (table->nested_join && &(table->nested_join->join_list))
|
||||
{
|
||||
buildNestedTableOuterJoin(gwi, table);
|
||||
CalpontSystemCatalog::TableAliasName tan = makeTableAliasName(table);
|
||||
leafTables.insert(tan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex)
|
||||
uint32_t buildJoin(gp_walk_info& gwi, List<TABLE_LIST>& join_list,
|
||||
std::stack<execplan::ParseTree*>& outerJoinStack)
|
||||
{
|
||||
// check non-collapsed outer join
|
||||
// this set contains all processed embedded joins. duplicate joins are ignored
|
||||
set<TABLE_LIST*> embeddingSet;
|
||||
TABLE_LIST* table_ptr = select_lex.get_table_list();
|
||||
gp_walk_info gwi_outer = gwi;
|
||||
gwi_outer.subQuery = NULL;
|
||||
gwi_outer.hasSubSelect = false;
|
||||
vector <Item_field*> tmpVec;
|
||||
TABLE_LIST *table;
|
||||
List_iterator<TABLE_LIST> li(join_list);
|
||||
|
||||
for (; table_ptr; table_ptr = table_ptr->next_local)
|
||||
while ((table = li++))
|
||||
{
|
||||
gwi_outer.innerTables.clear();
|
||||
clearStacks(gwi_outer);
|
||||
gwi_outer.subQuery = NULL;
|
||||
gwi_outer.hasSubSelect = false;
|
||||
// Make sure we don't process the derived table nests again,
|
||||
// they were already handled by FromSubQuery::transform()
|
||||
if (table->nested_join && !table->derived)
|
||||
buildJoin(gwi, table->nested_join->join_list, outerJoinStack);
|
||||
|
||||
// View is already processed in view::transform
|
||||
// @bug5319. view is sometimes treated as derived table and
|
||||
// fromSub::transform does not build outer join filters.
|
||||
if (!table_ptr->derived && table_ptr->view && !gwi.subQuery)
|
||||
continue;
|
||||
|
||||
CalpontSystemCatalog:: TableAliasName tan = make_aliasview(
|
||||
(table_ptr->db.length ? table_ptr->db.str : ""),
|
||||
(table_ptr->table_name.length ? table_ptr->table_name.str : ""),
|
||||
(table_ptr->alias.length ? table_ptr->alias.str : ""),
|
||||
getViewName(table_ptr), true, lower_case_table_names);
|
||||
|
||||
if ((table_ptr->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) && table_ptr->on_expr)
|
||||
if (table->on_expr)
|
||||
{
|
||||
// inner tables block
|
||||
Item_cond* expr = reinterpret_cast<Item_cond*>(table_ptr->on_expr);
|
||||
gwi_outer.innerTables.insert(tan);
|
||||
Item_cond* expr = reinterpret_cast<Item_cond*>(table->on_expr);
|
||||
|
||||
if (table_ptr->nested_join && &(table_ptr->nested_join->join_list))
|
||||
if (table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT))
|
||||
{
|
||||
TABLE_LIST* table;
|
||||
List_iterator<TABLE_LIST> li(table_ptr->nested_join->join_list);
|
||||
// inner tables block
|
||||
gp_walk_info gwi_outer = gwi;
|
||||
gwi_outer.subQuery = NULL;
|
||||
gwi_outer.hasSubSelect = false;
|
||||
gwi_outer.innerTables.clear();
|
||||
clearStacks(gwi_outer);
|
||||
|
||||
while ((table = li++))
|
||||
// recursively build the leaf tables for this nested join node
|
||||
if (table->nested_join)
|
||||
buildNestedJoinLeafTables(table->nested_join->join_list,
|
||||
gwi_outer.innerTables);
|
||||
else // this is a leaf table
|
||||
{
|
||||
CalpontSystemCatalog::TableAliasName ta = make_aliasview(
|
||||
(table->db.length ? table->db.str : ""),
|
||||
(table->table_name.length ? table->table_name.str : ""),
|
||||
(table->alias.length ? table->alias.str : ""),
|
||||
getViewName(table), true, lower_case_table_names);
|
||||
gwi_outer.innerTables.insert(ta);
|
||||
CalpontSystemCatalog::TableAliasName tan = makeTableAliasName(table);
|
||||
gwi_outer.innerTables.insert(tan);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WALK_COND
|
||||
cerr << "inner tables: " << endl;
|
||||
set<CalpontSystemCatalog::TableAliasName>::const_iterator it;
|
||||
for (it = gwi_outer.innerTables.begin(); it != gwi_outer.innerTables.end(); ++it)
|
||||
cerr << (*it) << " ";
|
||||
cerr << endl;
|
||||
|
||||
if (table_ptr->alias.length)
|
||||
cerr << table_ptr->alias.str;
|
||||
else if (table_ptr->alias.length)
|
||||
cerr << table_ptr->alias.str;
|
||||
|
||||
cerr << " outer table expression: " << endl;
|
||||
expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX);
|
||||
cerr << " outer table expression: " << endl;
|
||||
expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX);
|
||||
#endif
|
||||
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
||||
}
|
||||
else if (table_ptr->nested_join && &(table_ptr->nested_join->join_list))
|
||||
{
|
||||
buildNestedTableOuterJoin(gwi_outer, table_ptr);
|
||||
}
|
||||
// this part is ambiguous. Not quite sure how MySQL's lay out the outer join filters in the structure
|
||||
else if (table_ptr->embedding && table_ptr->embedding->outer_join && table_ptr->embedding->on_expr)
|
||||
{
|
||||
// all the tables in nested_join are inner tables.
|
||||
TABLE_LIST* table;
|
||||
List_iterator<TABLE_LIST> li(table_ptr->embedding->nested_join->join_list);
|
||||
gwi_outer.innerTables.clear();
|
||||
|
||||
while ((table = li++))
|
||||
{
|
||||
CalpontSystemCatalog:: TableAliasName ta = make_aliasview(
|
||||
(table->db.length ? table->db.str : ""),
|
||||
(table->table_name.length ? table->table_name.str : ""),
|
||||
(table->alias.length ? table->alias.str : ""),
|
||||
getViewName(table), true, lower_case_table_names);
|
||||
gwi_outer.innerTables.insert(ta);
|
||||
}
|
||||
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
||||
|
||||
if (embeddingSet.find(table_ptr->embedding) != embeddingSet.end())
|
||||
continue;
|
||||
|
||||
embeddingSet.insert(table_ptr->embedding);
|
||||
Item_cond* expr = reinterpret_cast<Item_cond*>(table_ptr->embedding->on_expr);
|
||||
|
||||
#ifdef DEBUG_WALK_COND
|
||||
cerr << "inner tables: " << endl;
|
||||
set<CalpontSystemCatalog::TableAliasName>::const_iterator it;
|
||||
|
||||
for (it = gwi_outer.innerTables.begin(); it != gwi_outer.innerTables.end(); ++it)
|
||||
cerr << (*it) << " ";
|
||||
|
||||
cerr << endl;
|
||||
expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX);
|
||||
#endif
|
||||
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
||||
}
|
||||
// *DRRTUY This part is to be removed in 1.4.3
|
||||
#if 0
|
||||
// @bug 2849
|
||||
/*else if (table_ptr->embedding && table_ptr->embedding->nested_join)
|
||||
{
|
||||
// if this is dervied table process phase, mysql may have not developed the plan
|
||||
// completely. Return and let it finish. It will come to rnd_init again.
|
||||
if (table_ptr->embedding->is_natural_join && table_ptr->derived)
|
||||
{
|
||||
if (gwi.thd->derived_tables_processing)
|
||||
// Error out subquery in outer join on filter for now
|
||||
if (gwi_outer.hasSubSelect)
|
||||
{
|
||||
// MCOL-2178 isUnion member only assigned, never used
|
||||
//MIGR::infinidb_vtable.isUnion = false;
|
||||
gwi.cs_vtable_is_update_with_derive = true;
|
||||
gwi.fatalParseError = true;
|
||||
gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_OUTER_JOIN_SUBSELECT);
|
||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (embeddingSet.find(table_ptr->embedding) != embeddingSet.end())
|
||||
continue;
|
||||
// build outerjoinon filter
|
||||
ParseTree* filters = NULL, *ptp = NULL, *rhs = NULL;
|
||||
|
||||
gwi_outer.innerTables.clear();
|
||||
gwi_outer.innerTables.insert(tan);
|
||||
embeddingSet.insert(table_ptr->embedding);
|
||||
List<TABLE_LIST>* inners = &(table_ptr->embedding->nested_join->join_list);
|
||||
List_iterator_fast<TABLE_LIST> li(*inners);
|
||||
TABLE_LIST* curr;
|
||||
|
||||
while ((curr = li++))
|
||||
{
|
||||
if (curr->on_expr)
|
||||
while (!gwi_outer.ptWorkStack.empty())
|
||||
{
|
||||
if (!curr->outer_join) // only handle nested JOIN for now
|
||||
{
|
||||
gwi_outer.innerTables.clear();
|
||||
Item_cond* expr = reinterpret_cast<Item_cond*>(curr->on_expr);
|
||||
filters = gwi_outer.ptWorkStack.top();
|
||||
gwi_outer.ptWorkStack.pop();
|
||||
|
||||
#ifdef DEBUG_WALK_COND
|
||||
expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX);
|
||||
#endif
|
||||
expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX);
|
||||
}
|
||||
if (gwi_outer.ptWorkStack.empty())
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->left(filters);
|
||||
rhs = gwi_outer.ptWorkStack.top();
|
||||
gwi_outer.ptWorkStack.pop();
|
||||
ptp->right(rhs);
|
||||
gwi_outer.ptWorkStack.push(ptp);
|
||||
}
|
||||
|
||||
// should have only 1 pt left in stack.
|
||||
if (filters)
|
||||
{
|
||||
SPTP on_sp(filters);
|
||||
OuterJoinOnFilter* onFilter = new OuterJoinOnFilter(on_sp);
|
||||
ParseTree* pt = new ParseTree(onFilter);
|
||||
outerJoinStack.push(pt);
|
||||
}
|
||||
}
|
||||
} */
|
||||
else // inner join
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
// 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
|
||||
ParseTree* filters = NULL, *ptp = NULL, *lhs = NULL;
|
||||
|
||||
while (!gwi_outer.ptWorkStack.empty())
|
||||
{
|
||||
filters = gwi_outer.ptWorkStack.top();
|
||||
gwi_outer.ptWorkStack.pop();
|
||||
|
||||
if (gwi_outer.ptWorkStack.empty())
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->right(filters);
|
||||
lhs = gwi_outer.ptWorkStack.top();
|
||||
gwi_outer.ptWorkStack.pop();
|
||||
ptp->left(lhs);
|
||||
gwi_outer.ptWorkStack.push(ptp);
|
||||
}
|
||||
|
||||
// should have only 1 pt left in stack.
|
||||
if (filters)
|
||||
{
|
||||
SPTP on_sp(filters);
|
||||
OuterJoinOnFilter* onFilter = new OuterJoinOnFilter(on_sp);
|
||||
ParseTree* pt = new ParseTree(onFilter);
|
||||
gwi.ptWorkStack.push(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
embeddingSet.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6289,16 +6175,13 @@ void setExecutionParams(gp_walk_info &gwi, SCSEP &csep)
|
||||
* FROM part of the query.
|
||||
* isUnion tells that CS processes FROM taken from UNION UNIT.
|
||||
* The notion is described in MDB code.
|
||||
* on_expr_list ON expressions used in OUTER JOINs. These are
|
||||
* later used in processWhere()
|
||||
* RETURNS
|
||||
* error id as an int
|
||||
***********************************************************/
|
||||
int processFrom(bool &isUnion,
|
||||
SELECT_LEX &select_lex,
|
||||
gp_walk_info &gwi,
|
||||
SCSEP &csep,
|
||||
List<Item> &on_expr_list)
|
||||
SCSEP &csep)
|
||||
{
|
||||
// populate table map and trigger syscolumn cache for all the tables (@bug 1637).
|
||||
// all tables on FROM list must have at least one col in colmap
|
||||
@ -6328,12 +6211,6 @@ int processFrom(bool &isUnion,
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Save on_expr to use it for WHERE processing
|
||||
if (!(table_ptr->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) && table_ptr->on_expr)
|
||||
{
|
||||
on_expr_list.push_back(table_ptr->on_expr);
|
||||
}
|
||||
|
||||
string viewName = getViewName(table_ptr);
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
@ -6483,15 +6360,12 @@ int processFrom(bool &isUnion,
|
||||
* DESCRIPTION:
|
||||
* This function processes conditions from either JOIN->conds
|
||||
* or SELECT_LEX->where|prep_where
|
||||
* on_expr_list ON expressions used in OUTER JOINs. These are
|
||||
* populated used in processFrom()
|
||||
* RETURNS
|
||||
* error id as an int
|
||||
***********************************************************/
|
||||
int processWhere(SELECT_LEX &select_lex,
|
||||
gp_walk_info &gwi,
|
||||
SCSEP &csep,
|
||||
List<Item> &on_expr_list,
|
||||
const std::vector<COND*>& condStack)
|
||||
{
|
||||
JOIN* join = select_lex.join;
|
||||
@ -6609,27 +6483,6 @@ int processWhere(SELECT_LEX &select_lex,
|
||||
(dynamic_cast<ConstantColumn*>(gwi.rcWorkStack.top()))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr());
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WALK_COND
|
||||
std::cerr << "------------------ ON_EXPR -----------------------" << endl;
|
||||
#endif
|
||||
// MCOL-3593 MDB now doesn't rewrite and/or consolidate ON and WHERE expressions
|
||||
// and CS handles INNER ON expressions here.
|
||||
if (!on_expr_list.is_empty())
|
||||
{
|
||||
List_iterator<Item> on_expr_it(on_expr_list);
|
||||
Item_cond *on_expr = NULL;
|
||||
while((on_expr = reinterpret_cast<Item_cond*>(on_expr_it++)))
|
||||
{
|
||||
on_expr->traverse_cond(gp_walk, &gwi, Item::POSTFIX);
|
||||
#ifdef DEBUG_WALK_COND
|
||||
on_expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_WALK_COND
|
||||
std::cerr << "-------------------------------------------------\n" << std::endl;
|
||||
#endif
|
||||
|
||||
// ZZ - the followinig debug shows the structure of nested outer join. should
|
||||
// use a recursive function.
|
||||
#ifdef OUTER_JOIN_DEBUG
|
||||
@ -6694,26 +6547,31 @@ int processWhere(SELECT_LEX &select_lex,
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t failed = buildOuterJoin(gwi, select_lex);
|
||||
uint32_t failed = 0;
|
||||
|
||||
if (failed) return failed;
|
||||
// InfiniDB bug5764 requires outer joins to be appended to the
|
||||
// end of the filter list. This causes outer join filters to
|
||||
// have a higher join id than inner join filters.
|
||||
// TODO MCOL-4680 Figure out why this is the case, and possibly
|
||||
// eliminate this requirement.
|
||||
std::stack<execplan::ParseTree*> outerJoinStack;
|
||||
|
||||
// @bug5764. build outer join for view, make sure outerjoin filter is appended
|
||||
// to the end of the filter list.
|
||||
for (uint i = 0; i < gwi.viewList.size(); i++)
|
||||
{
|
||||
failed = gwi.viewList[i]->processOuterJoin(gwi);
|
||||
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
|
||||
if (failed != 0)
|
||||
if ((failed = buildJoin(gwi, select_lex.top_join_list, outerJoinStack)))
|
||||
return failed;
|
||||
|
||||
if (gwi.subQuery)
|
||||
{
|
||||
for (uint i = 0; i < gwi.viewList.size(); i++)
|
||||
{
|
||||
if ((failed = gwi.viewList[i]->processJoin(gwi, outerJoinStack)))
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
|
||||
ParseTree* filters = NULL;
|
||||
ParseTree* outerJoinFilters = NULL;
|
||||
ParseTree* ptp = NULL;
|
||||
ParseTree* lhs = NULL;
|
||||
ParseTree* rhs = NULL;
|
||||
|
||||
// @bug 2932. for "select * from region where r_name" case. if icp not null and
|
||||
// ptWorkStack empty, the item is in rcWorkStack.
|
||||
@ -6734,13 +6592,45 @@ int processWhere(SELECT_LEX &select_lex,
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->right(filters);
|
||||
lhs = gwi.ptWorkStack.top();
|
||||
ptp->left(filters);
|
||||
rhs = gwi.ptWorkStack.top();
|
||||
gwi.ptWorkStack.pop();
|
||||
ptp->left(lhs);
|
||||
ptp->right(rhs);
|
||||
gwi.ptWorkStack.push(ptp);
|
||||
}
|
||||
|
||||
while (!outerJoinStack.empty())
|
||||
{
|
||||
outerJoinFilters = outerJoinStack.top();
|
||||
outerJoinStack.pop();
|
||||
|
||||
if (outerJoinStack.empty())
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->left(outerJoinFilters);
|
||||
rhs = outerJoinStack.top();
|
||||
outerJoinStack.pop();
|
||||
ptp->right(rhs);
|
||||
outerJoinStack.push(ptp);
|
||||
}
|
||||
|
||||
// Append outer join filters at the end of inner join filters.
|
||||
// JLF_ExecPlanToJobList::walkTree processes ParseTree::left
|
||||
// before ParseTree::right which is what we intend to do in the
|
||||
// below.
|
||||
if (filters && outerJoinFilters)
|
||||
{
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->left(filters);
|
||||
ptp->right(outerJoinFilters);
|
||||
filters = ptp;
|
||||
}
|
||||
else if (outerJoinFilters)
|
||||
{
|
||||
filters = outerJoinFilters;
|
||||
}
|
||||
|
||||
if (filters)
|
||||
{
|
||||
csep->filters(filters);
|
||||
@ -6928,15 +6818,15 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
CalpontSelectExecutionPlan::SelectList derivedTbList;
|
||||
// @bug 1796. Remember table order on the FROM list.
|
||||
gwi.clauseType = FROM;
|
||||
List<Item> on_expr_list;
|
||||
if ((rc = processFrom(isUnion, select_lex, gwi, csep, on_expr_list)))
|
||||
if ((rc = processFrom(isUnion, select_lex, gwi, csep)))
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool unionSel = (!isUnion && select_lex.master_unit()->is_unit_op()) ? true : false;
|
||||
|
||||
gwi.clauseType = WHERE;
|
||||
if ((rc = processWhere(select_lex, gwi, csep, on_expr_list, condStack)))
|
||||
if ((rc = processWhere(select_lex, gwi, csep, condStack)))
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
@ -8628,26 +8518,36 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
||||
|
||||
SELECT_LEX tmp_select_lex;
|
||||
tmp_select_lex.table_list.first = gi.groupByTables;
|
||||
uint32_t failed = buildOuterJoin(gwi, tmp_select_lex);
|
||||
|
||||
// InfiniDB bug5764 requires outer joins to be appended to the
|
||||
// end of the filter list. This causes outer join filters to
|
||||
// have a higher join id than inner join filters.
|
||||
// TODO MCOL-4680 Figure out why this is the case, and possibly
|
||||
// eliminate this requirement.
|
||||
std::stack<execplan::ParseTree*> outerJoinStack;
|
||||
|
||||
uint32_t failed = buildJoin(gwi, tmp_select_lex.top_join_list, outerJoinStack);
|
||||
|
||||
if (failed) return failed;
|
||||
|
||||
// @bug5764. build outer join for view, make sure outerjoin filter is appended
|
||||
// to the end of the filter list.
|
||||
for (uint i = 0; i < gwi.viewList.size(); i++)
|
||||
if (gwi.subQuery)
|
||||
{
|
||||
failed = gwi.viewList[i]->processOuterJoin(gwi);
|
||||
for (uint i = 0; i < gwi.viewList.size(); i++)
|
||||
{
|
||||
failed = gwi.viewList[i]->processJoin(gwi, outerJoinStack);
|
||||
|
||||
if (failed)
|
||||
break;
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed != 0)
|
||||
return failed;
|
||||
|
||||
ParseTree* filters = NULL;
|
||||
ParseTree* outerJoinFilters = NULL;
|
||||
ParseTree* ptp = NULL;
|
||||
ParseTree* lhs = NULL;
|
||||
ParseTree* rhs = NULL;
|
||||
|
||||
// @bug 2932. for "select * from region where r_name" case. if icp not null and
|
||||
// ptWorkStack empty, the item is in rcWorkStack.
|
||||
@ -8668,15 +8568,45 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
//ptp->left(filters);
|
||||
ptp->right(filters);
|
||||
lhs = gwi.ptWorkStack.top();
|
||||
ptp->left(filters);
|
||||
rhs = gwi.ptWorkStack.top();
|
||||
gwi.ptWorkStack.pop();
|
||||
//ptp->right(rhs);
|
||||
ptp->left(lhs);
|
||||
ptp->right(rhs);
|
||||
gwi.ptWorkStack.push(ptp);
|
||||
}
|
||||
|
||||
while (!outerJoinStack.empty())
|
||||
{
|
||||
outerJoinFilters = outerJoinStack.top();
|
||||
outerJoinStack.pop();
|
||||
|
||||
if (outerJoinStack.empty())
|
||||
break;
|
||||
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->left(outerJoinFilters);
|
||||
rhs = outerJoinStack.top();
|
||||
outerJoinStack.pop();
|
||||
ptp->right(rhs);
|
||||
outerJoinStack.push(ptp);
|
||||
}
|
||||
|
||||
// Append outer join filters at the end of inner join filters.
|
||||
// JLF_ExecPlanToJobList::walkTree processes ParseTree::left
|
||||
// before ParseTree::right which is what we intend to do in the
|
||||
// below.
|
||||
if (filters && outerJoinFilters)
|
||||
{
|
||||
ptp = new ParseTree(new LogicOperator("and"));
|
||||
ptp->left(filters);
|
||||
ptp->right(outerJoinFilters);
|
||||
filters = ptp;
|
||||
}
|
||||
else if (outerJoinFilters)
|
||||
{
|
||||
filters = outerJoinFilters;
|
||||
}
|
||||
|
||||
if (filters)
|
||||
{
|
||||
csep->filters(filters);
|
||||
|
@ -373,7 +373,7 @@ bool buildRowColumnFilter(gp_walk_info* gwip, execplan::RowColumn* rhs, execplan
|
||||
bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip);
|
||||
void collectAllCols(gp_walk_info& gwi, Item_field* ifp);
|
||||
void buildSubselectFunc(Item_func* ifp, gp_walk_info* gwip);
|
||||
uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex);
|
||||
uint32_t buildJoin(gp_walk_info& gwi, List<TABLE_LIST>& join_list, std::stack<execplan::ParseTree*>& outerJoinStack);
|
||||
std::string getViewName(TABLE_LIST* table_ptr);
|
||||
bool buildConstPredicate(Item_func* ifp, execplan::ReturnedColumn* rhs, gp_walk_info* gwip);
|
||||
execplan::CalpontSystemCatalog::ColType fieldType_MysqlToIDB (const Field* field);
|
||||
|
@ -44,7 +44,8 @@ using namespace execplan;
|
||||
|
||||
namespace cal_impl_if
|
||||
{
|
||||
extern uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex);
|
||||
extern uint32_t buildJoin(gp_walk_info& gwi, List<TABLE_LIST>& join_list,
|
||||
std::stack<execplan::ParseTree*>& outerJoinStack);
|
||||
extern string getViewName(TABLE_LIST* table_ptr);
|
||||
|
||||
CalpontSystemCatalog::TableAliasName& View::viewName()
|
||||
@ -182,9 +183,9 @@ void View::transform()
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t View::processOuterJoin(gp_walk_info& gwi)
|
||||
uint32_t View::processJoin(gp_walk_info& gwi, std::stack<execplan::ParseTree*>& outerJoinStack)
|
||||
{
|
||||
return buildOuterJoin(gwi, fSelect);
|
||||
return buildJoin(gwi, fSelect.top_join_list, outerJoinStack);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
parent select.
|
||||
*/
|
||||
void transform();
|
||||
uint32_t processOuterJoin(gp_walk_info& gwi);
|
||||
uint32_t processJoin(gp_walk_info& gwi, std::stack<execplan::ParseTree*>&);
|
||||
|
||||
private:
|
||||
SELECT_LEX fSelect;
|
||||
|
Reference in New Issue
Block a user