1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

chore(plugin): move order by processing

This commit is contained in:
drrtuy
2025-05-29 18:40:05 +00:00
parent bb13688ccf
commit 600f10c259

View File

@ -7674,7 +7674,6 @@ void buildInToExistsFilter(gp_walk_info& gwi, SELECT_LEX& select_lex)
}
}
/*@brief Process SELECT part of a query or sub-query */
/***********************************************************
* DESCRIPTION:
@ -8182,6 +8181,240 @@ void buildInToExistsFilter(gp_walk_info& gwi, SELECT_LEX& select_lex)
return 0;
}
/*@brief Process ORDER BY part of a query or sub-query */
/***********************************************************
* DESCRIPTION:
* Processes ORDER BY part of a query or sub-query
* RETURNS
* error id as an int
***********************************************************/
int processOrderBy(SELECT_LEX& select_lex,
gp_walk_info& gwi,
SCSEP& csep,
boost::shared_ptr<CalpontSystemCatalog>& csc,
SRCP& minSc,
const bool isUnion,
const bool unionSel)
{
SQL_I_List<ORDER> order_list = select_lex.order_list;
ORDER* ordercol = static_cast<ORDER*>(order_list.first);
// check if window functions are in order by. InfiniDB process order by list if
// window functions are involved, either in order by or projection.
for (; ordercol; ordercol = ordercol->next)
{
if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM)
gwi.hasWindowFunc = true;
// XXX: TODO: implement a proper analysis of what we support.
// 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 (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;
getColNameFromItem(osr, *ordercol->item);
Message::Args args;
args.add(ostream.str());
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NOT_SUPPORTED_GROUPBY_ORDERBY_EXPRESSION, args);
gwi.parseErrorText = emsg;
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
return ERR_NOT_SUPPORTED_GROUPBY_ORDERBY_EXPRESSION;
}
}
// re-visit the first of ordercol list
ordercol = static_cast<ORDER*>(order_list.first);
for (; ordercol; ordercol = ordercol->next)
{
ReturnedColumn* rc = NULL;
if (ordercol->in_field_list && ordercol->counter_used)
{
rc = gwi.returnedCols[ordercol->counter - 1]->clone();
rc->orderPos(ordercol->counter - 1);
// can not be optimized off if used in order by with counter.
// set with self derived table alias if it's derived table
gwi.returnedCols[ordercol->counter - 1]->incRefCount();
}
else
{
Item* ord_item = *(ordercol->item);
// ignore not_used column on order by.
if ((ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT) &&
ord_item->full_name() && !strcmp(ord_item->full_name(), "Not_used"))
{
continue;
}
else if (ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT)
{
// DRRTUY This section looks useless b/c there is no
// way to put constant INT into an ORDER BY list
rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone();
}
else if (ord_item->type() == Item::SUBSELECT_ITEM)
{
gwi.fatalParseError = true;
}
else if ((ord_item->type() == Item::FUNC_ITEM) &&
(((Item_func*)ord_item)->functype() == Item_func::COLLATE_FUNC))
{
push_warning(gwi.thd, Sql_condition::WARN_LEVEL_NOTE, WARN_OPTION_IGNORED,
"COLLATE is ignored in ColumnStore");
continue;
}
else
{
rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError);
rc = wrapIntoAggregate(rc, gwi, ord_item);
}
// @bug5501 try item_ptr if item can not be fixed. For some
// weird dml statement state, item can not be fixed but the
// infomation is available in item_ptr.
if (!rc || gwi.fatalParseError)
{
Item* item_ptr = ordercol->item_ptr;
while (item_ptr->type() == Item::REF_ITEM)
item_ptr = *(((Item_ref*)item_ptr)->ref);
rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError);
}
if (!rc)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY);
gwi.parseErrorText = emsg;
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi);
return ER_CHECK_NOT_IMPLEMENTED;
}
}
if (ordercol->direction == ORDER::ORDER_ASC)
rc->asc(true);
else
rc->asc(false);
gwi.orderByCols.push_back(SRCP(rc));
}
// make sure columnmap, returnedcols and count(*) arg_list are not empty
TableMap::iterator tb_iter = gwi.tableMap.begin();
try
{
for (; tb_iter != gwi.tableMap.end(); tb_iter++)
{
if ((*tb_iter).second.first == 1)
continue;
CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first;
CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table);
SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi);
SRCP srcp(sc);
gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp));
(*tb_iter).second.first = 1;
}
}
catch (runtime_error& e)
{
setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi);
return ER_INTERNAL_ERROR;
}
catch (...)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR);
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
return ER_INTERNAL_ERROR;
}
if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || gwi.returnedCols.empty())
{
// get the smallest column from colmap
CalpontSelectExecutionPlan::ColumnMap::const_iterator iter;
int minColWidth = 0;
CalpontSystemCatalog::ColType ct;
try
{
for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter)
{
// should always not null
SimpleColumn* sc = dynamic_cast<SimpleColumn*>(iter->second.get());
if (sc && !(sc->joinInfo() & JOIN_CORRELATED))
{
ct = csc->colType(sc->oid());
if (minColWidth == 0)
{
minColWidth = ct.colWidth;
minSc = iter->second;
}
else if (ct.colWidth < minColWidth)
{
minColWidth = ct.colWidth;
minSc = iter->second;
}
}
}
}
catch (...)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR);
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
return ER_INTERNAL_ERROR;
}
if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty() && minSc)
gwi.returnedCols.push_back(minSc);
}
// ORDER BY translation part
if (!isUnion && !gwi.hasWindowFunc && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT)
{
{
if (unionSel)
order_list = select_lex.master_unit()->global_parameters()->order_list;
ordercol = static_cast<ORDER*>(order_list.first);
for (; ordercol; ordercol = ordercol->next)
{
Item* ord_item = *(ordercol->item);
if (ord_item->name.length)
{
// for union order by 1 case. For unknown reason, it doesn't show in_field_list
if (ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT)
{
}
else if (ord_item->type() == Item::SUBSELECT_ITEM)
{
}
else
{
}
}
}
}
if (gwi.orderByCols.size()) // has order by
{
csep->hasOrderBy(true);
// To activate LimitedOrderBy
csep->orderByThreads(get_orderby_threads(gwi.thd));
csep->specHandlerProcessed(true);
}
}
return 0;
}
/*@brief Translates SELECT_LEX into CSEP */
/***********************************************************
* DESCRIPTION:
@ -8709,238 +8942,20 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
}
}
// ORDER BY processing
if ((rc = processOrderBy(select_lex, gwi, csep, csc, minSc, isUnion, unionSel)))
{
SQL_I_List<ORDER> order_list = select_lex.order_list;
ORDER* ordercol = static_cast<ORDER*>(order_list.first);
CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID);
return rc;
}
// check if window functions are in order by. InfiniDB process order by list if
// window functions are involved, either in order by or projection.
for (; ordercol; ordercol = ordercol->next)
{
if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM)
gwi.hasWindowFunc = true;
// XXX: TODO: implement a proper analysis of what we support.
// 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 (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;
getColNameFromItem(osr, *ordercol->item);
Message::Args args;
args.add(ostream.str());
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NOT_SUPPORTED_GROUPBY_ORDERBY_EXPRESSION, args);
gwi.parseErrorText = emsg;
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
return ERR_NOT_SUPPORTED_GROUPBY_ORDERBY_EXPRESSION;
}
}
// json dictionary for debug and testing options
csep->pron(get_pron(gwi.thd));
// re-visit the first of ordercol list
ordercol = static_cast<ORDER*>(order_list.first);
{
for (; ordercol; ordercol = ordercol->next)
{
ReturnedColumn* rc = NULL;
if (ordercol->in_field_list && ordercol->counter_used)
{
rc = gwi.returnedCols[ordercol->counter - 1]->clone();
rc->orderPos(ordercol->counter - 1);
// can not be optimized off if used in order by with counter.
// set with self derived table alias if it's derived table
gwi.returnedCols[ordercol->counter - 1]->incRefCount();
}
else
{
Item* ord_item = *(ordercol->item);
// ignore not_used column on order by.
if ((ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT) &&
ord_item->full_name() && !strcmp(ord_item->full_name(), "Not_used"))
{
continue;
}
else if (ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT)
{
// DRRTUY This section looks useless b/c there is no
// way to put constant INT into an ORDER BY list
rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone();
}
else if (ord_item->type() == Item::SUBSELECT_ITEM)
{
gwi.fatalParseError = true;
}
else if ((ord_item->type() == Item::FUNC_ITEM) &&
(((Item_func*)ord_item)->functype() == Item_func::COLLATE_FUNC))
{
push_warning(gwi.thd, Sql_condition::WARN_LEVEL_NOTE, WARN_OPTION_IGNORED,
"COLLATE is ignored in ColumnStore");
continue;
}
else
{
rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError);
rc = wrapIntoAggregate(rc, gwi, ord_item);
}
// @bug5501 try item_ptr if item can not be fixed. For some
// weird dml statement state, item can not be fixed but the
// infomation is available in item_ptr.
if (!rc || gwi.fatalParseError)
{
Item* item_ptr = ordercol->item_ptr;
while (item_ptr->type() == Item::REF_ITEM)
item_ptr = *(((Item_ref*)item_ptr)->ref);
rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError);
}
if (!rc)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY);
gwi.parseErrorText = emsg;
setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi);
return ER_CHECK_NOT_IMPLEMENTED;
}
}
if (ordercol->direction == ORDER::ORDER_ASC)
rc->asc(true);
else
rc->asc(false);
gwi.orderByCols.push_back(SRCP(rc));
}
}
// make sure columnmap, returnedcols and count(*) arg_list are not empty
TableMap::iterator tb_iter = gwi.tableMap.begin();
try
{
for (; tb_iter != gwi.tableMap.end(); tb_iter++)
{
if ((*tb_iter).second.first == 1)
continue;
CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first;
CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table);
SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi);
SRCP srcp(sc);
gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp));
(*tb_iter).second.first = 1;
}
}
catch (runtime_error& e)
{
setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi);
CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID);
return ER_INTERNAL_ERROR;
}
catch (...)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR);
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID);
return ER_INTERNAL_ERROR;
}
if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || gwi.returnedCols.empty())
{
// get the smallest column from colmap
CalpontSelectExecutionPlan::ColumnMap::const_iterator iter;
int minColWidth = 0;
CalpontSystemCatalog::ColType ct;
try
{
for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter)
{
// should always not null
SimpleColumn* sc = dynamic_cast<SimpleColumn*>(iter->second.get());
if (sc && !(sc->joinInfo() & JOIN_CORRELATED))
{
ct = csc->colType(sc->oid());
if (minColWidth == 0)
{
minColWidth = ct.colWidth;
minSc = iter->second;
}
else if (ct.colWidth < minColWidth)
{
minColWidth = ct.colWidth;
minSc = iter->second;
}
}
}
}
catch (...)
{
string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR);
setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi);
CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID);
return ER_INTERNAL_ERROR;
}
if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty() && minSc)
gwi.returnedCols.push_back(minSc);
}
// ORDER BY translation part
if (!isUnion && !gwi.hasWindowFunc && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT)
{
{
if (unionSel)
order_list = select_lex.master_unit()->global_parameters()->order_list;
ordercol = static_cast<ORDER*>(order_list.first);
for (; ordercol; ordercol = ordercol->next)
{
Item* ord_item = *(ordercol->item);
if (ord_item->name.length)
{
// for union order by 1 case. For unknown reason, it doesn't show in_field_list
if (ord_item->type() == Item::CONST_ITEM && ord_item->cmp_type() == INT_RESULT)
{
}
else if (ord_item->type() == Item::SUBSELECT_ITEM)
{
}
else
{
}
}
}
}
if (gwi.orderByCols.size()) // has order by
{
csep->hasOrderBy(true);
// To activate LimitedOrderBy
csep->orderByThreads(get_orderby_threads(gwi.thd));
csep->specHandlerProcessed(true);
}
}
// json dictionary for debug and testing options
csep->pron(get_pron(gwi.thd));
// We don't currently support limit with correlated subquery
if ((rc = processLimitAndOffset(select_lex, gwi, csep, unionSel, isUnion, isSelectHandlerTop)))
{
return rc;
}
} // ORDER BY end
// We don't currently support limit with correlated subquery
if ((rc = processLimitAndOffset(select_lex, gwi, csep, unionSel, isUnion, isSelectHandlerTop)))
{
return rc;
}
if (select_lex.options & SELECT_DISTINCT)
csep->distinct(true);
@ -9017,7 +9032,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
gwi.select_lex = originalSelectLex;
// append additionalRetCols to returnedCols
gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(),
gwi.additionalRetCols.end());
gwi.additionalRetCols.end(
));
csep->groupByCols(gwi.groupByCols);
csep->withRollup(withRollup);