You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-02 17:22:27 +03:00
Merge pull request #1126 from drrtuy/MCOL-3903_1_4
MCOL-3903 Enable Select Handler to run query part of INSERT..SELECT. Conflicts: dbcon/mysql/ha_mcs_pushdown.cpp
This commit is contained in:
committed by
Patrick LeBlanc
parent
3d5d113a84
commit
6d9544a15e
@ -112,7 +112,7 @@ execplan::ParseTree* ExistsSub::transform()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false, true) != 0)
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false) != 0)
|
||||
{
|
||||
fGwip.fatalParseError = true;
|
||||
|
||||
|
@ -323,8 +323,7 @@ FromSubQuery::FromSubQuery(gp_walk_info& gwip) : SubQuery(gwip)
|
||||
{}
|
||||
|
||||
FromSubQuery::FromSubQuery(gp_walk_info& gwip,
|
||||
SELECT_LEX* sub,
|
||||
bool isPushdownHandler) :
|
||||
SELECT_LEX* sub) :
|
||||
SubQuery(gwip),
|
||||
fFromSub(sub)
|
||||
{}
|
||||
@ -348,7 +347,7 @@ SCSEP FromSubQuery::transform()
|
||||
csep->derivedTbAlias(fAlias); // always lower case
|
||||
csep->derivedTbView(fGwip.viewName.alias);
|
||||
|
||||
if (getSelectPlan(gwi, *fFromSub, csep, false, true) != 0)
|
||||
if (getSelectPlan(gwi, *fFromSub, csep, false) != 0)
|
||||
{
|
||||
fGwip.fatalParseError = true;
|
||||
|
||||
|
@ -148,7 +148,7 @@ execplan::ParseTree* InSub::transform()
|
||||
gwi.tbList.insert(gwi.tbList.begin(), fGwip.tbList.begin(), fGwip.tbList.end());
|
||||
gwi.derivedTbList.insert(gwi.derivedTbList.begin(), fGwip.derivedTbList.begin(), fGwip.derivedTbList.end());
|
||||
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false, true) != 0)
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false) != 0)
|
||||
{
|
||||
fGwip.fatalParseError = true;
|
||||
|
||||
|
@ -3117,7 +3117,10 @@ CalpontSystemCatalog::ColType colType_MysqlToIDB (const Item* item)
|
||||
return ct;
|
||||
}
|
||||
|
||||
ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand, bool isRefItem)
|
||||
ReturnedColumn* buildReturnedColumn(
|
||||
Item* item, gp_walk_info& gwi,
|
||||
bool& nonSupport,
|
||||
bool isRefItem)
|
||||
{
|
||||
ReturnedColumn* rc = NULL;
|
||||
|
||||
@ -3275,9 +3278,9 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp
|
||||
}
|
||||
|
||||
if (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" )
|
||||
return buildArithmeticColumn(ifp, gwi, nonSupport, pushdownHand);
|
||||
return buildArithmeticColumn(ifp, gwi, nonSupport);
|
||||
else
|
||||
return buildFunctionColumn(ifp, gwi, nonSupport, pushdownHand);
|
||||
return buildFunctionColumn(ifp, gwi, nonSupport);
|
||||
}
|
||||
|
||||
case Item::SUM_FUNC_ITEM:
|
||||
@ -3410,8 +3413,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp
|
||||
ArithmeticColumn* buildArithmeticColumn(
|
||||
Item_func* item,
|
||||
gp_walk_info& gwi,
|
||||
bool& nonSupport,
|
||||
bool pushdownHand)
|
||||
bool& nonSupport)
|
||||
{
|
||||
if (get_fe_conn_info_ptr() == NULL)
|
||||
set_fe_conn_info_ptr((void*)new cal_connection_info());
|
||||
@ -3435,7 +3437,7 @@ ArithmeticColumn* buildArithmeticColumn(
|
||||
{
|
||||
if (gwi.clauseType == SELECT || /*gwi.clauseType == HAVING || */gwi.clauseType == GROUP_BY || gwi.clauseType == FROM) // select list
|
||||
{
|
||||
lhs = new ParseTree(buildReturnedColumn(sfitempp[0], gwi, nonSupport, pushdownHand));
|
||||
lhs = new ParseTree(buildReturnedColumn(sfitempp[0], gwi, nonSupport));
|
||||
|
||||
if (!lhs->data() && (sfitempp[0]->type() == Item::FUNC_ITEM))
|
||||
{
|
||||
@ -3443,7 +3445,7 @@ ArithmeticColumn* buildArithmeticColumn(
|
||||
Item_func* ifp = (Item_func*)sfitempp[0];
|
||||
lhs = buildParseTree(ifp, gwi, nonSupport);
|
||||
}
|
||||
else if(pushdownHand && !lhs->data() && (sfitempp[0]->type() == Item::REF_ITEM))
|
||||
else if(!lhs->data() && (sfitempp[0]->type() == Item::REF_ITEM))
|
||||
{
|
||||
// There must be an aggregation column in extended SELECT
|
||||
// list so find the corresponding column.
|
||||
@ -3454,7 +3456,7 @@ ArithmeticColumn* buildArithmeticColumn(
|
||||
if(rc)
|
||||
lhs = new ParseTree(rc);
|
||||
}
|
||||
rhs = new ParseTree(buildReturnedColumn(sfitempp[1], gwi, nonSupport, pushdownHand));
|
||||
rhs = new ParseTree(buildReturnedColumn(sfitempp[1], gwi, nonSupport));
|
||||
|
||||
if (!rhs->data() && (sfitempp[1]->type() == Item::FUNC_ITEM))
|
||||
{
|
||||
@ -3462,7 +3464,7 @@ ArithmeticColumn* buildArithmeticColumn(
|
||||
Item_func* ifp = (Item_func*)sfitempp[1];
|
||||
rhs = buildParseTree(ifp, gwi, nonSupport);
|
||||
}
|
||||
else if(pushdownHand && !rhs->data() && (sfitempp[1]->type() == Item::REF_ITEM))
|
||||
else if(!rhs->data() && (sfitempp[1]->type() == Item::REF_ITEM))
|
||||
{
|
||||
// There must be an aggregation column in extended SELECT
|
||||
// list so find the corresponding column.
|
||||
@ -3638,7 +3640,6 @@ ReturnedColumn* buildFunctionColumn(
|
||||
Item_func* ifp,
|
||||
gp_walk_info& gwi,
|
||||
bool& nonSupport,
|
||||
bool pushdownHand,
|
||||
bool selectBetweenIn)
|
||||
{
|
||||
if (get_fe_conn_info_ptr() == NULL)
|
||||
@ -3680,7 +3681,7 @@ ReturnedColumn* buildFunctionColumn(
|
||||
// Arithmetic exp
|
||||
if (funcName == "+" || funcName == "-" || funcName == "*" || funcName == "/" )
|
||||
{
|
||||
ArithmeticColumn* ac = buildArithmeticColumn(ifp, gwi, nonSupport, pushdownHand);
|
||||
ArithmeticColumn* ac = buildArithmeticColumn(ifp, gwi, nonSupport);
|
||||
return ac;
|
||||
}
|
||||
|
||||
@ -3834,11 +3835,10 @@ ReturnedColumn* buildFunctionColumn(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReturnedColumn* rc = buildReturnedColumn(ifp->arguments()[i], gwi, nonSupport, pushdownHand);
|
||||
ReturnedColumn* rc = buildReturnedColumn(ifp->arguments()[i], gwi, nonSupport);
|
||||
|
||||
// MCOL-1510 It must be a temp table field, so find the corresponding column.
|
||||
if (!rc && pushdownHand
|
||||
&& ifp->arguments()[i]->type() == Item::REF_ITEM)
|
||||
if (!rc && ifp->arguments()[i]->type() == Item::REF_ITEM)
|
||||
{
|
||||
gwi.fatalParseError = false;
|
||||
rc = buildAggFrmTempField(ifp->arguments()[i], gwi);
|
||||
@ -5652,7 +5652,7 @@ void gp_walk(const Item* item, void* arg)
|
||||
|
||||
if (col->type() != Item::COND_ITEM)
|
||||
{
|
||||
rc = buildReturnedColumn(col, *gwip, gwip->fatalParseError, false, true);
|
||||
rc = buildReturnedColumn(col, *gwip, gwip->fatalParseError, false);
|
||||
|
||||
if ( col->type() == Item::FIELD_ITEM )
|
||||
gwip->fatalParseError = false;
|
||||
@ -6191,7 +6191,7 @@ int processFrom(bool &isUnion,
|
||||
if (table_ptr->derived)
|
||||
{
|
||||
SELECT_LEX* select_cursor = table_ptr->derived->first_select();
|
||||
FromSubQuery fromSub(gwi, select_cursor, true);
|
||||
FromSubQuery fromSub(gwi, select_cursor);
|
||||
string alias(table_ptr->alias.str);
|
||||
fromSub.alias(lower(alias));
|
||||
|
||||
@ -6303,7 +6303,7 @@ int processFrom(bool &isUnion,
|
||||
union_gwi.thd = gwi.thd;
|
||||
uint32_t err = 0;
|
||||
|
||||
if ((err = getSelectPlan(union_gwi, *sl, plan, unionSel, true)) != 0)
|
||||
if ((err = getSelectPlan(union_gwi, *sl, plan, unionSel)) != 0)
|
||||
return err;
|
||||
|
||||
unionVec.push_back(SCEP(plan));
|
||||
@ -6543,25 +6543,176 @@ int processWhere(SELECT_LEX &select_lex,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@brief Process LIMIT part of a query or sub-query */
|
||||
/***********************************************************
|
||||
* DESCRIPTION:
|
||||
* Processes LIMIT and OFFSET parts
|
||||
* RETURNS
|
||||
* error id as an int
|
||||
***********************************************************/
|
||||
int processLimitAndOffset(
|
||||
SELECT_LEX& select_lex,
|
||||
gp_walk_info& gwi,
|
||||
SCSEP& csep,
|
||||
bool unionSel,
|
||||
bool isUnion,
|
||||
bool isSelectHandlerTop
|
||||
)
|
||||
{
|
||||
// LIMIT processing part
|
||||
uint64_t limitNum = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
// non-MAIN union branch
|
||||
if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT)
|
||||
{
|
||||
/* Consider the following query:
|
||||
"select a from t1 where exists (select b from t2 where a=b);"
|
||||
CS first builds a hash table for t2, then pushes down the hash to
|
||||
PrimProc for a distributed hash join execution, with t1 being the
|
||||
large-side table. However, the server applies an optimization in
|
||||
Item_exists_subselect::fix_length_and_dec in sql/item_subselect.cc
|
||||
(see server commit ae476868a5394041a00e75a29c7d45917e8dfae8)
|
||||
where it sets explicit_limit to true, which causes csep->limitNum set to 1.
|
||||
This causes the hash table for t2 to only contain a single record for the
|
||||
hash join, giving less number of rows in the output result set than expected.
|
||||
We therefore do not allow limit set to 1 here for such queries.
|
||||
*/
|
||||
if (gwi.subSelectType != CalpontSelectExecutionPlan::IN_SUBS
|
||||
&& gwi.subSelectType != CalpontSelectExecutionPlan::EXISTS_SUBS
|
||||
&& select_lex.master_unit()->global_parameters()->explicit_limit)
|
||||
{
|
||||
if (select_lex.master_unit()->global_parameters()->offset_limit)
|
||||
{
|
||||
Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit;
|
||||
csep->limitStart(offset->val_int());
|
||||
}
|
||||
|
||||
if (select_lex.master_unit()->global_parameters()->select_limit)
|
||||
{
|
||||
Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit;
|
||||
csep->limitNum(select->val_int());
|
||||
// MCOL-894 Activate parallel ORDER BY
|
||||
csep->orderByThreads(get_orderby_threads(gwi.thd));
|
||||
}
|
||||
}
|
||||
}
|
||||
// union with explicit select at the top level
|
||||
else if (isUnion && select_lex.explicit_limit)
|
||||
{
|
||||
if (select_lex.braces)
|
||||
{
|
||||
if (select_lex.offset_limit)
|
||||
csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int());
|
||||
|
||||
if (select_lex.select_limit)
|
||||
csep->limitNum(((Item_int*)select_lex.select_limit)->val_int());
|
||||
}
|
||||
}
|
||||
// other types of queries that have explicit LIMIT
|
||||
else if (select_lex.explicit_limit)
|
||||
{
|
||||
uint32_t limitOffset = 0;
|
||||
|
||||
if (select_lex.join)
|
||||
{
|
||||
JOIN* join = select_lex.join;
|
||||
#if MYSQL_VERSION_ID >= 50172
|
||||
|
||||
// @bug5729. After upgrade, join->unit sometimes is uninitialized pointer
|
||||
// (not null though) and will cause seg fault. Prefer checking
|
||||
// select_lex->offset_limit if not null.
|
||||
if (join->select_lex &&
|
||||
join->select_lex->offset_limit &&
|
||||
join->select_lex->offset_limit->is_fixed() &&
|
||||
join->select_lex->select_limit &&
|
||||
join->select_lex->select_limit->is_fixed())
|
||||
{
|
||||
limitOffset = join->select_lex->offset_limit->val_int();
|
||||
limitNum = join->select_lex->select_limit->val_int();
|
||||
}
|
||||
else if (join->unit)
|
||||
{
|
||||
limitOffset = join->unit->offset_limit_cnt;
|
||||
limitNum = join->unit->select_limit_cnt - limitOffset;
|
||||
}
|
||||
|
||||
#else
|
||||
limitOffset = (join->unit)->offset_limit_cnt;
|
||||
limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (select_lex.master_unit()->global_parameters()->offset_limit)
|
||||
{
|
||||
Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit;
|
||||
limitOffset = offset->val_int();
|
||||
}
|
||||
|
||||
if (select_lex.master_unit()->global_parameters()->select_limit)
|
||||
{
|
||||
Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit;
|
||||
limitNum = select->val_int();
|
||||
}
|
||||
}
|
||||
|
||||
csep->limitStart(limitOffset);
|
||||
csep->limitNum(limitNum);
|
||||
}
|
||||
// If an explicit limit is not specified, use the system variable value
|
||||
else
|
||||
{
|
||||
csep->limitNum(gwi.thd->variables.select_limit);
|
||||
}
|
||||
|
||||
// We don't currently support limit with correlated subquery
|
||||
if (gwi.subQuery && !gwi.correlatedTbNameVec.empty() && csep->hasOrderBy())
|
||||
{
|
||||
gwi.fatalParseError = true;
|
||||
gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB);
|
||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// MDB applies OFFSET on its own for SH processing.
|
||||
// See related MDEV-16327 for details.
|
||||
if (isSelectHandlerTop && csep->limitStart())
|
||||
{
|
||||
if (std::numeric_limits<uint64_t>::max()-csep->limitStart()
|
||||
< csep->limitNum())
|
||||
{
|
||||
csep->limitNum(std::numeric_limits<uint64_t>::max());
|
||||
csep->limitStart(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
csep->limitNum(csep->limitNum()+csep->limitStart());
|
||||
csep->limitStart(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@brief Translates SELECT_LEX into CSEP */
|
||||
/***********************************************************
|
||||
* DESCRIPTION:
|
||||
* This function takes SELECT_LEX and tries to produce
|
||||
* a corresponding CSEP out of it. It is made of parts that
|
||||
* process parts of the query, e.g. FROM, WHERE, SELECT,
|
||||
* HAVING, GROUP BY, ORDER BY. FROM and WHERE are processed
|
||||
* by processFrom(), processWhere(). CS calls getSelectPlan()
|
||||
* HAVING, GROUP BY, ORDER BY. FROM, WHERE, LIMIT are processed
|
||||
* by corresponding methods. CS calls getSelectPlan()
|
||||
* recursively to process subqueries.
|
||||
* ARGS
|
||||
* isUnion if true CS processes UNION unit now
|
||||
* isPushdownHand legacy to be removed
|
||||
* isSelectHandlerTop removes offset at the top of SH query.
|
||||
* RETURNS
|
||||
* error id as an int
|
||||
***********************************************************/
|
||||
int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
SCSEP& csep,
|
||||
bool isUnion,
|
||||
bool isPushdownHand)
|
||||
bool isSelectHandlerTop)
|
||||
{
|
||||
#ifdef DEBUG_WALK_COND
|
||||
cerr << "getSelectPlan()" << endl;
|
||||
@ -6769,7 +6920,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
ReturnedColumn* rc;
|
||||
if (funcName == "in" || funcName == " IN " || funcName == "between")
|
||||
{
|
||||
rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem, false, true);
|
||||
rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6801,15 +6952,11 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo, &gwi);
|
||||
uint32_t after_size = funcFieldVec.size();
|
||||
|
||||
// group by func and func in subquery can not be post processed
|
||||
// pushdown handler projection functions
|
||||
// @bug3881. set_user_var can not be treated as constant function
|
||||
// @bug5716. Try to avoid post process function for union query.
|
||||
if ((gwi.subQuery || select_lex.group_list.elements != 0 ||
|
||||
!csep->unionVec().empty() || isUnion || isPushdownHand ) &&
|
||||
!hasNonSupportItem && (after_size - before_size) == 0 &&
|
||||
!(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT)
|
||||
)
|
||||
if (!hasNonSupportItem && (after_size - before_size) == 0 &&
|
||||
!(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT))
|
||||
{
|
||||
String val, *str = ifp->val_str(&val);
|
||||
string valStr;
|
||||
@ -7490,6 +7637,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
}
|
||||
}
|
||||
|
||||
// ORDER BY processing
|
||||
{
|
||||
SQL_I_List<ORDER> order_list = select_lex.order_list;
|
||||
ORDER* ordercol = reinterpret_cast<ORDER*>(order_list.first);
|
||||
@ -7503,9 +7651,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
// MCOL-2166 Looking for this sorting item in GROUP_BY items list.
|
||||
// Shouldn't look into this if query doesn't have GROUP BY or
|
||||
// aggregations
|
||||
if(isPushdownHand
|
||||
&& select_lex.agg_func_used() && select_lex.group_list.first
|
||||
&& !sortItemIsInGrouping(*ordercol->item, select_lex.group_list.first))
|
||||
if(select_lex.agg_func_used() && select_lex.group_list.first
|
||||
&& !sortItemIsInGrouping(*ordercol->item,
|
||||
select_lex.group_list.first))
|
||||
{
|
||||
std::ostringstream ostream;
|
||||
std::ostringstream& osr = ostream;
|
||||
@ -7522,10 +7670,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
// re-visit the first of ordercol list
|
||||
ordercol = reinterpret_cast<ORDER*>(order_list.first);
|
||||
|
||||
// for subquery or pushdown query, order+limit by will be supported in CS
|
||||
// union order by and limit are supported
|
||||
if (gwi.hasWindowFunc || isPushdownHand || ( isUnion && ordercol )
|
||||
|| gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT )
|
||||
{
|
||||
for (; ordercol; ordercol = ordercol->next)
|
||||
{
|
||||
@ -7601,158 +7745,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
gwi.orderByCols.push_back(SRCP(rc));
|
||||
}
|
||||
}
|
||||
// DRRTUY The whole block is marked for removal in 1.4.1
|
||||
#if 0
|
||||
else if (!isUnion)
|
||||
{
|
||||
vector <Item_field*> fieldVec;
|
||||
|
||||
// the following order by is just for redo phase
|
||||
if (!unionSel)
|
||||
{
|
||||
for (; ordercol; ordercol = ordercol->next)
|
||||
{
|
||||
Item* ord_item = *(ordercol->item);
|
||||
|
||||
// @bug5993. Could be nested ref.
|
||||
while (ord_item->type() == Item::REF_ITEM)
|
||||
ord_item = (*((Item_ref*)ord_item)->ref);
|
||||
|
||||
//ReturnedColumn* rc = 0;
|
||||
// check if this order by column is on the select list
|
||||
//Item_func* ifp = (Item_func*)(*(ordercol->item));
|
||||
//rc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError);
|
||||
|
||||
if (ord_item->type() == Item::FUNC_ITEM)
|
||||
{
|
||||
//FunctionColumn* fc = dynamic_cast<FunctionColumn*>(rc);
|
||||
}
|
||||
else if (ord_item->type() == Item::SUBSELECT_ITEM)
|
||||
{
|
||||
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY);
|
||||
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (ord_item->type() == Item::SUM_FUNC_ITEM)
|
||||
{
|
||||
ReturnedColumn* ac = 0;
|
||||
|
||||
Item_sum* ifp = (Item_sum*)(*(ordercol->item));
|
||||
// @bug3477. add aggregate column to the select list of the create phase.
|
||||
ac = buildAggregateColumn(ifp, gwi);
|
||||
|
||||
if (!ac)
|
||||
{
|
||||
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED,
|
||||
IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY), gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// check if this order by column is on the select list
|
||||
for (uint32_t i = 0; i < gwi.returnedCols.size(); i++)
|
||||
{
|
||||
AggregateColumn* ret = dynamic_cast<AggregateColumn*>(gwi.returnedCols[i].get());
|
||||
|
||||
if (!ret)
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (ac || !gwi.groupByCols.empty())
|
||||
{
|
||||
SRCP srcp(ac);
|
||||
gwi.returnedCols.push_back(srcp);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ord_item->name.length && ord_item->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
Item_field* field = reinterpret_cast<Item_field*>(ord_item);
|
||||
ReturnedColumn* rc = buildSimpleColumn(field, gwi);
|
||||
|
||||
for (uint32_t i = 0; i < gwi.returnedCols.size(); i++)
|
||||
{
|
||||
SimpleColumn* sc = dynamic_cast<SimpleColumn*>(gwi.returnedCols[i].get());
|
||||
|
||||
if (sc && ((Item_field*)ord_item)->cached_table &&
|
||||
(strcasecmp(getViewName(((Item_field*)ord_item)->cached_table).c_str(), sc->viewName().c_str()) != 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sc && sc->sameColumn(rc))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// @bug 2719. Error out order by not on the distinct select list.
|
||||
if (select_lex.options & SELECT_DISTINCT)
|
||||
{
|
||||
gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ORDERBY_NOT_IN_DISTINCT);
|
||||
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
bool hasNonSupportItem = false;
|
||||
uint16_t parseInfo = 0;
|
||||
parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo, &gwi);
|
||||
|
||||
if (hasNonSupportItem)
|
||||
{
|
||||
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY);
|
||||
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate string to be added to the select list for order by
|
||||
for (uint32_t i = 0; i < fieldVec.size(); i++)
|
||||
{
|
||||
SimpleColumn* sc = buildSimpleColumn(fieldVec[i], gwi);
|
||||
|
||||
if (!sc)
|
||||
{
|
||||
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY);
|
||||
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
String str;
|
||||
fieldVec[i]->print(&str, QT_ORDINARY);
|
||||
sc->alias(string(str.c_ptr()));
|
||||
SRCP srcp(sc);
|
||||
uint32_t j = 0;
|
||||
|
||||
for (; j < gwi.returnedCols.size(); j++)
|
||||
{
|
||||
if (sc->sameColumn(gwi.returnedCols[j].get()))
|
||||
{
|
||||
SimpleColumn* field = dynamic_cast<SimpleColumn*>(gwi.returnedCols[j].get());
|
||||
|
||||
if (field && field->alias() == sc->alias())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == gwi.returnedCols.size())
|
||||
{
|
||||
gwi.returnedCols.push_back(srcp);
|
||||
gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(fieldVec[i]->field_name.str), srcp));
|
||||
TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0);
|
||||
gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isColumnStore())] =
|
||||
make_pair(1, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// make sure columnmap, returnedcols and count(*) arg_list are not empty
|
||||
TableMap::iterator tb_iter = gwi.tableMap.begin();
|
||||
|
||||
@ -7878,129 +7870,16 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
||||
{
|
||||
csep->hasOrderBy(true);
|
||||
// To activate LimitedOrderBy
|
||||
if(isPushdownHand)
|
||||
{
|
||||
csep->orderByThreads(get_orderby_threads(gwi.thd));
|
||||
csep->specHandlerProcessed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LIMIT processing part
|
||||
uint64_t limitNum = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
// non-MAIN union branch
|
||||
if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT)
|
||||
if ((rc = processLimitAndOffset(select_lex, gwi, csep, unionSel, isUnion, isSelectHandlerTop)))
|
||||
{
|
||||
/* Consider the following query:
|
||||
"select a from t1 where exists (select b from t2 where a=b);"
|
||||
CS first builds a hash table for t2, then pushes down the hash to
|
||||
PrimProc for a distributed hash join execution, with t1 being the
|
||||
large-side table. However, the server applies an optimization in
|
||||
Item_exists_subselect::fix_length_and_dec in sql/item_subselect.cc
|
||||
(see server commit ae476868a5394041a00e75a29c7d45917e8dfae8)
|
||||
where it sets explicit_limit to true, which causes csep->limitNum set to 1.
|
||||
This causes the hash table for t2 to only contain a single record for the
|
||||
hash join, giving less number of rows in the output result set than expected.
|
||||
We therefore do not allow limit set to 1 here for such queries.
|
||||
*/
|
||||
if (gwi.subSelectType != CalpontSelectExecutionPlan::IN_SUBS
|
||||
&& gwi.subSelectType != CalpontSelectExecutionPlan::EXISTS_SUBS
|
||||
&& select_lex.master_unit()->global_parameters()->explicit_limit)
|
||||
{
|
||||
if (select_lex.master_unit()->global_parameters()->offset_limit)
|
||||
{
|
||||
Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit;
|
||||
csep->limitStart(offset->val_int());
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (select_lex.master_unit()->global_parameters()->select_limit)
|
||||
{
|
||||
Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit;
|
||||
csep->limitNum(select->val_int());
|
||||
// MCOL-894 Activate parallel ORDER BY
|
||||
csep->orderByThreads(get_orderby_threads(gwi.thd));
|
||||
}
|
||||
}
|
||||
}
|
||||
// union with explicit select at the top level
|
||||
else if (isUnion && select_lex.explicit_limit)
|
||||
{
|
||||
if (select_lex.braces)
|
||||
{
|
||||
if (select_lex.offset_limit)
|
||||
csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int());
|
||||
|
||||
if (select_lex.select_limit)
|
||||
csep->limitNum(((Item_int*)select_lex.select_limit)->val_int());
|
||||
}
|
||||
}
|
||||
// other types of queries that have explicit LIMIT
|
||||
else if (select_lex.explicit_limit)
|
||||
{
|
||||
uint32_t limitOffset = 0;
|
||||
|
||||
if (select_lex.join)
|
||||
{
|
||||
JOIN* join = select_lex.join;
|
||||
#if MYSQL_VERSION_ID >= 50172
|
||||
|
||||
// @bug5729. After upgrade, join->unit sometimes is uninitialized pointer
|
||||
// (not null though) and will cause seg fault. Prefer checking
|
||||
// select_lex->offset_limit if not null.
|
||||
if (join->select_lex &&
|
||||
join->select_lex->offset_limit &&
|
||||
join->select_lex->offset_limit->is_fixed() &&
|
||||
join->select_lex->select_limit &&
|
||||
join->select_lex->select_limit->is_fixed())
|
||||
{
|
||||
limitOffset = join->select_lex->offset_limit->val_int();
|
||||
limitNum = join->select_lex->select_limit->val_int();
|
||||
}
|
||||
else if (join->unit)
|
||||
{
|
||||
limitOffset = join->unit->offset_limit_cnt;
|
||||
limitNum = join->unit->select_limit_cnt - limitOffset;
|
||||
}
|
||||
|
||||
#else
|
||||
limitOffset = (join->unit)->offset_limit_cnt;
|
||||
limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (select_lex.master_unit()->global_parameters()->offset_limit)
|
||||
{
|
||||
Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit;
|
||||
limitOffset = offset->val_int();
|
||||
}
|
||||
|
||||
if (select_lex.master_unit()->global_parameters()->select_limit)
|
||||
{
|
||||
Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit;
|
||||
limitNum = select->val_int();
|
||||
}
|
||||
}
|
||||
|
||||
csep->limitStart(limitOffset);
|
||||
csep->limitNum(limitNum);
|
||||
}
|
||||
// If an explicit limit is not specified, use the system variable value
|
||||
else
|
||||
{
|
||||
csep->limitNum(gwi.thd->variables.select_limit);
|
||||
}
|
||||
|
||||
// We don't currently support limit with correlated subquery
|
||||
if (gwi.subQuery && !gwi.correlatedTbNameVec.empty() && csep->hasOrderBy())
|
||||
{
|
||||
gwi.fatalParseError = true;
|
||||
gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB);
|
||||
setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi);
|
||||
return ER_CHECK_NOT_IMPLEMENTED;
|
||||
}
|
||||
} // LIMIT processing finishes here
|
||||
} // ORDER BY end
|
||||
|
||||
if (select_lex.options & SELECT_DISTINCT)
|
||||
csep->distinct(true);
|
||||
@ -8214,7 +8093,7 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi)
|
||||
int cs_get_derived_plan(derived_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi)
|
||||
{
|
||||
SELECT_LEX select_lex = *handler->select;
|
||||
int status = getSelectPlan(gwi, select_lex, csep, false, true);
|
||||
int status = getSelectPlan(gwi, select_lex, csep, false);
|
||||
|
||||
if (status > 0)
|
||||
return ER_INTERNAL_ERROR;
|
||||
@ -8412,7 +8291,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
||||
|
||||
SELECT_LEX* select_cursor = table_ptr->derived->first_select();
|
||||
// Use Pushdown handler for subquery processing
|
||||
FromSubQuery fromSub(gwi, select_cursor, true);
|
||||
FromSubQuery fromSub(gwi, select_cursor);
|
||||
string alias(table_ptr->alias.str);
|
||||
fromSub.alias(lower(alias));
|
||||
|
||||
|
@ -1780,7 +1780,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi)
|
||||
|
||||
gwi.clauseType = WHERE;
|
||||
|
||||
if (getSelectPlan(gwi, select_lex, updateCP, false, true) != 0) //@Bug 3030 Modify the error message for unsupported functions
|
||||
if (getSelectPlan(gwi, select_lex, updateCP, false) != 0) //@Bug 3030 Modify the error message for unsupported functions
|
||||
{
|
||||
if (gwi.cs_vtable_is_update_with_derive)
|
||||
{
|
||||
|
@ -342,7 +342,7 @@ int cp_get_table_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_table_in
|
||||
int cp_get_group_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_group_info& gi);
|
||||
int cs_get_derived_plan(derived_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi);
|
||||
int cs_get_select_plan(select_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi);
|
||||
int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false, bool isPushdownHand = false);
|
||||
int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false, bool isSelectHandlerTop = 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);
|
||||
@ -352,9 +352,9 @@ const std::string bestTableName(const Item_field* ifp);
|
||||
bool isMCSTable(TABLE* table_ptr);
|
||||
|
||||
// execution plan util functions prototypes
|
||||
execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false, bool isRefItem = false);
|
||||
execplan::ReturnedColumn* buildFunctionColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false, bool selectBetweenIn = false);
|
||||
execplan::ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false);
|
||||
execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem = false);
|
||||
execplan::ReturnedColumn* buildFunctionColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport, bool selectBetweenIn = false);
|
||||
execplan::ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport);
|
||||
execplan::ConstantColumn* buildDecimalColumn(Item* item, gp_walk_info& gwi);
|
||||
execplan::SimpleColumn* buildSimpleColumn(Item_field* item, gp_walk_info& gwi);
|
||||
execplan::FunctionColumn* buildCaseFunction(Item_func* item, gp_walk_info& gwi, bool& nonSupport);
|
||||
|
@ -787,21 +787,9 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex)
|
||||
return handler;
|
||||
}
|
||||
|
||||
// Remove this in 1.4.3
|
||||
// Save the original group_list as it can be mutated by the
|
||||
// optimizer which calls the remove_const() function
|
||||
Group_list_ptrs *group_list_ptrs = NULL;
|
||||
if (save_group_list(thd, select_lex, &group_list_ptrs))
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
// Select_handler use the short-cut that effectively disables
|
||||
// INSERT..SELECT, LDI, SELECT..INTO OUTFILE
|
||||
// Select_handler couldn't properly process UPSERT..SELECT
|
||||
if ((thd->lex)->sql_command == SQLCOM_INSERT_SELECT
|
||||
|| (thd->lex)->sql_command == SQLCOM_CREATE_TABLE
|
||||
|| (thd->lex)->exchange)
|
||||
|
||||
&& thd->lex->duplicates == DUP_UPDATE)
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ execplan::ParseTree* ScalarSub::buildParseTree(PredicateOperator* op)
|
||||
gwi.tbList.insert(gwi.tbList.begin(), fGwip.tbList.begin(), fGwip.tbList.end());
|
||||
gwi.derivedTbList.insert(gwi.derivedTbList.begin(), fGwip.derivedTbList.begin(), fGwip.derivedTbList.end());
|
||||
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false, true) != 0)
|
||||
if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep, false) != 0)
|
||||
{
|
||||
//@todo more in error handling
|
||||
if (!gwi.fatalParseError)
|
||||
|
@ -77,7 +77,7 @@ SCSEP SelectSubQuery::transform()
|
||||
gwi.tbList.insert(gwi.tbList.begin(), fGwip.tbList.begin(), fGwip.tbList.end());
|
||||
gwi.derivedTbList.insert(gwi.derivedTbList.begin(), fGwip.derivedTbList.begin(), fGwip.derivedTbList.end());
|
||||
|
||||
if (getSelectPlan(gwi, *(fSelSub->get_select_lex()), csep, false, true) != 0)
|
||||
if (getSelectPlan(gwi, *(fSelSub->get_select_lex()), csep, false) != 0)
|
||||
{
|
||||
if (!gwi.fatalParseError)
|
||||
{
|
||||
|
@ -181,7 +181,7 @@ class FromSubQuery : public SubQuery
|
||||
{
|
||||
public:
|
||||
FromSubQuery(gp_walk_info&);
|
||||
FromSubQuery(gp_walk_info&, SELECT_LEX* fromSub, bool isPushdownHand=false);
|
||||
FromSubQuery(gp_walk_info&, SELECT_LEX* fromSub);
|
||||
~FromSubQuery();
|
||||
const SELECT_LEX* fromSub() const
|
||||
{
|
||||
|
@ -17,7 +17,7 @@
|
||||
# Non support errors 1000 ~ 2000.
|
||||
# The query will go through the optimizer again with some optimization turned off
|
||||
1000 ERR_MISS_JOIN %1% not joined.
|
||||
1001 ERR_NON_SUPPORTED_FUNCTION Function '%1%' can only be used in the outermost select or order by clause and cannot be used in conjunction with an aggregate function.
|
||||
1001 ERR_NON_SUPPORTED_FUNCTION Function '%1%' isn't supported.
|
||||
1002 ERR_INCOMPATIBLE_JOIN %1% incompatible column type specified for join condition.
|
||||
1003 ERR_CIRCULAR_JOIN Circular joins are not supported.
|
||||
1004 ERR_MIX_JOIN Mixed %1% JOIN is not supported.
|
||||
|
Reference in New Issue
Block a user