1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-18 21:44:02 +03:00

fix(group by, having): MCOL-5776: GROUP BY/HAVING closer to server's (#3257)

This patch introduces an internal aggregate operator SELECT_SOME that
is automatically added to columns that are not in GROUP BY. It
"computes" some plausible value of the column (actually, last one
passed).

Along the way it fixes incorrect handling of HAVING being transferred
into WHERE, window function handling and a bit of other inconsistencies.
This commit is contained in:
Sergey Zefirov 2024-12-20 22:12:32 +03:00 committed by GitHub
parent 8f8620210b
commit 3bc8bd8cc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 601 additions and 131 deletions

View File

@ -46,6 +46,7 @@ using namespace joblist;
namespace execplan
{
void getAggCols(execplan::ParseTree* n, void* obj)
{
vector<AggregateColumn*>* list = reinterpret_cast<vector<AggregateColumn*>*>(obj);

View File

@ -300,12 +300,12 @@ const string ArithmeticColumn::toString() const
if (fAlias.length() > 0)
oss << "Alias: " << fAlias << endl;
if (fExpression != 0)
fExpression->walk(walkfn, oss);
oss << "expressionId=" << fExpressionId << endl;
oss << "joinInfo=" << fJoinInfo << " returnAll=" << fReturnAll << " sequence#=" << fSequence << endl;
oss << "resultType=" << colDataTypeToString(fResultType.colDataType) << "|" << fResultType.colWidth << endl;
if (fExpression != 0)
fExpression->walk(walkfn, oss);
return oss.str();
}

View File

@ -261,6 +261,10 @@ inline void ArithmeticOperator::evaluate(rowgroup::Row& row, bool& isNull, Parse
case execplan::CalpontSystemCatalog::SMALLINT:
case execplan::CalpontSystemCatalog::TINYINT:
fResult.intVal = execute(lop->getIntVal(row, isNull), rop->getIntVal(row, isNull), isNull);
if (isNull)
{
fResult.intVal = joblist::INTNULL;
}
break;
case execplan::CalpontSystemCatalog::UBIGINT:
@ -282,6 +286,10 @@ inline void ArithmeticOperator::evaluate(rowgroup::Row& row, bool& isNull, Parse
case execplan::CalpontSystemCatalog::USMALLINT:
case execplan::CalpontSystemCatalog::UTINYINT:
fResult.uintVal = execute(lop->getUintVal(row, isNull), rop->getUintVal(row, isNull), isNull);
if (isNull)
{
fResult.uintVal = joblist::UBIGINTNULL;
}
break;
case execplan::CalpontSystemCatalog::DOUBLE:

View File

@ -62,16 +62,14 @@ ConstantFilter::ConstantFilter(const SOP& op, ReturnedColumn* lhs, ReturnedColum
{
SSFP ssfp(new SimpleFilter(op, lhs, rhs));
fFilterList.push_back(ssfp);
SimpleColumn* sc = dynamic_cast<SimpleColumn*>(lhs);
fCol.reset(sc->clone());
fCol.reset(lhs->clone());
}
ConstantFilter::ConstantFilter(SimpleFilter* sf)
{
SSFP ssfp(sf);
fFilterList.push_back(ssfp);
const SimpleColumn* sc = dynamic_cast<const SimpleColumn*>(sf->lhs());
fCol.reset(sc->clone());
fCol.reset(sf->lhs()->clone());
}
ConstantFilter::ConstantFilter(const ConstantFilter& rhs) : Filter(rhs), fOp(rhs.fOp), fCol(rhs.fCol)

View File

@ -412,7 +412,7 @@ bool PredicateOperator::getBoolVal(rowgroup::Row& row, bool& isNull, ReturnedCol
int64_t val2 = rop->getIntVal(row, isNull);
return numericCompare(val1, val2) && !isNull;
return !isNull && numericCompare(val1, val2);
}
case execplan::CalpontSystemCatalog::UBIGINT:

View File

@ -208,6 +208,13 @@ SimpleColumn::SimpleColumn(const SimpleColumn& rhs, const uint32_t sessionID)
{
}
SimpleColumn::SimpleColumn(const ReturnedColumn& rhs, const uint32_t sessionID)
: ReturnedColumn(rhs, sessionID)
, fData(rhs.data())
, fisColumnStore(true)
{
}
SimpleColumn::~SimpleColumn()
{
}
@ -270,7 +277,9 @@ const string SimpleColumn::toString() const
<< returnAll() << delim << sequence() << delim << cardinality() << delim << joinInfo() << delim
<< colSource() << delim << (isColumnStore() ? "ColumnStore" : "ForeignEngine") << delim
<< colPosition() << delim << cs.getCharset().cs_name.str << delim << cs.getCharset().coll_name.str
<< delim << endl;
<< " inputindex/outputindex: " << fInputIndex << delim << fOutputIndex
<< " eid " << fExpressionId
<< endl;
return output.str();
}

View File

@ -70,6 +70,7 @@ class SimpleColumn : public ReturnedColumn
SimpleColumn(const std::string& schema, const std::string& table, const std::string& col,
const bool isColumnStore, const uint32_t sessionID = 0, const int lower_case_table_names = 0);
SimpleColumn(const SimpleColumn& rhs, const uint32_t sessionID = 0);
SimpleColumn(const ReturnedColumn& rhs, const uint32_t sessionID = 0);
/**
* Destructor

View File

@ -53,6 +53,7 @@ using namespace rowgroup;
#include "expressionstep.h"
namespace joblist
{
ExpressionStep::ExpressionStep()

View File

@ -354,7 +354,6 @@ void checkHavingClause(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
}
}
bool aggInHaving = false;
const vector<ReturnedColumn*>& columns = ths->columns();
for (vector<ReturnedColumn*>::const_iterator i = columns.begin(); i != columns.end(); i++)
@ -365,7 +364,6 @@ void checkHavingClause(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
if (agc)
{
addAggregateColumn(agc, -1, jobInfo.nonConstCols, jobInfo);
aggInHaving = true;
}
else
{
@ -387,26 +385,6 @@ void checkHavingClause(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
}
}
if (aggInHaving == false)
{
// treated the same as where clause if no aggregate column in having.
jobInfo.havingStep.reset();
// parse the having expression
ParseTree* filters = csep->having();
if (filters != 0)
{
JLF_ExecPlanToJobList::walkTree(filters, jobInfo);
}
if (!jobInfo.stack.empty())
{
idbassert(jobInfo.stack.size() == 1);
jobInfo.havingStepVec = jobInfo.stack.top();
jobInfo.stack.pop();
}
}
}
void preProcessFunctionOnAggregation(const vector<SimpleColumn*>& scs, const vector<AggregateColumn*>& aggs,

View File

@ -87,7 +87,9 @@ void TupleHavingStep::initialize(const RowGroup& rgIn, const JobInfo& jobInfo)
for (uint64_t i = 0; i < fRowGroupIn.getKeys().size(); ++i)
if (keyToIndexMap.find(fRowGroupIn.getKeys()[i]) == keyToIndexMap.end())
{
keyToIndexMap.insert(make_pair(fRowGroupIn.getKeys()[i], i));
}
updateInputIndex(keyToIndexMap, jobInfo);
@ -125,9 +127,11 @@ void TupleHavingStep::expressionFilter(const ParseTree* filter, JobInfo& jobInfo
ExpressionStep::expressionFilter(filter, jobInfo);
// extract simple columns from parse tree
#if 01
vector<AggregateColumn*> acv;
fExpressionFilter->walk(getAggCols, &acv);
fColumns.insert(fColumns.end(), acv.begin(), acv.end());
#endif
}
void TupleHavingStep::run()

View File

@ -96,6 +96,7 @@ const uint64_t SUB_BIT = 0x02;
const uint64_t AF_BIT = 0x04;
const uint64_t CORRELATED = 0x08;
// In certain cases, gp_walk is called recursively. When done so,
// we need to bookmark the rcWorkStack for those cases where a constant
// expression such as 1=1 is used in an if statement or function call.
@ -161,6 +162,51 @@ void calculateNotNullTables(const std::vector<COND*>& condList, table_map& not_n
}
}
bool itemDisablesWrapping(Item* item, gp_walk_info& gwi);
void pushReturnedCol(gp_walk_info& gwi, Item* from, SRCP rc)
{
uint32_t i;
for ( i = 0; i < gwi.processed.size(); i++)
{
Item* ith = gwi.processed[i].first;
bool same = ith->eq(from, false);
if (same && ith->type() == Item::FUNC_ITEM)
{
// an exception for cast(column as decimal(X,Y)) - they are equal (in the eq() call sense)
// even if Xs and Ys are different.
string funcName = ((Item_func*)ith)->func_name();
if (funcName == "decimal_typecast")
{
Item_decimal_typecast* ithdtc = (Item_decimal_typecast*)ith;
Item_decimal_typecast* fromdtc = (Item_decimal_typecast*)from;
same = ithdtc->decimals == fromdtc->decimals && ithdtc->max_length == fromdtc->max_length;
}
}
if (same)
{
break;
}
}
bool needChange = true;
if (dynamic_cast<SimpleColumn*>(rc.get()) == nullptr && gwi.select_lex && !itemDisablesWrapping(from, gwi))
{
needChange = false;
}
if (needChange && i < gwi.processed.size())
{
rc->expressionId(gwi.processed[i].second);
}
else
{
gwi.processed.push_back(std::make_pair(from, rc->expressionId()));
}
gwi.returnedCols.push_back(rc);
}
// 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().
@ -605,7 +651,6 @@ ReturnedColumn* buildAggFrmTempField(Item* item, gp_walk_info& gwi)
Item_field* ifip = NULL;
Item_ref* irip;
Item_func_or_sum* isfp;
switch (item->type())
{
case Item::FIELD_ITEM: ifip = static_cast<Item_field*>(item); break;
@ -2069,15 +2114,18 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip)
}
sop.reset(new PredicateOperator(eqop));
sop->setOpType(gwip->scsp->resultType(), rhs->resultType());
SRCP scsp = gwip->scsp;
idbassert(scsp.get() != nullptr);
//sop->setOpType(gwip->scsp->resultType(), rhs->resultType());
sop->setOpType(scsp->resultType(), rhs->resultType());
ConstantFilter* cf = 0;
cf = new ConstantFilter(sop, gwip->scsp->clone(), rhs);
cf = new ConstantFilter(sop, scsp->clone(), lhs);
sop.reset(new LogicOperator(cmbop));
cf->op(sop);
sop.reset(new PredicateOperator(eqop));
sop->setOpType(gwip->scsp->resultType(), lhs->resultType());
cf->pushFilter(new SimpleFilter(sop, gwip->scsp->clone(), lhs, gwip->timeZone));
sop->setOpType(scsp->resultType(), rhs->resultType());
cf->pushFilter(new SimpleFilter(sop, scsp->clone(), rhs->clone(), gwip->timeZone));
while (!gwip->rcWorkStack.empty())
{
@ -2088,8 +2136,8 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip)
gwip->rcWorkStack.pop();
sop.reset(new PredicateOperator(eqop));
sop->setOpType(gwip->scsp->resultType(), lhs->resultType());
cf->pushFilter(new SimpleFilter(sop, gwip->scsp->clone(), lhs, gwip->timeZone));
sop->setOpType(scsp->resultType(), lhs->resultType());
cf->pushFilter(new SimpleFilter(sop, scsp->clone(), lhs->clone(), gwip->timeZone));
}
if (!gwip->rcWorkStack.empty())
@ -2414,7 +2462,9 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip)
RowColumn* rlhs = dynamic_cast<RowColumn*>(lhs);
if (rrhs && rlhs)
{
return buildRowColumnFilter(gwip, rrhs, rlhs, ifp);
}
vector<Item*> itemList;
@ -3326,6 +3376,78 @@ CalpontSystemCatalog::ColType colType_MysqlToIDB(const Item* item)
return ct;
}
bool itemDisablesWrapping(Item* item, gp_walk_info& gwi)
{
if (gwi.select_lex == nullptr)
{
return true;
}
ORDER* groupcol = static_cast<ORDER*>(gwi.select_lex->group_list.first);
while (groupcol)
{
Item* gci = *groupcol->item;
while (gci->type() == Item::REF_ITEM)
{
if (item->eq(gci, false))
{
return true;
}
Item_ref* ref = (Item_ref*)gci;
gci = *(ref->ref);
}
if (item->eq(gci, false))
{
return true;
}
groupcol = groupcol->next;
}
return false;
}
ReturnedColumn* wrapIntoAggregate(ReturnedColumn* rc, gp_walk_info& gwi, Item* baseItem)
{
if (!gwi.implicitExplicitGroupBy || gwi.disableWrapping || !gwi.select_lex)
{
return rc;
}
if (dynamic_cast<AggregateColumn*>(rc) != nullptr || dynamic_cast<ConstantColumn*>(rc) != nullptr)
{
return rc;
}
if (itemDisablesWrapping(baseItem, gwi))
{
return rc;
}
cal_connection_info* ci = static_cast<cal_connection_info*>(get_fe_conn_info_ptr());
AggregateColumn* ac = new AggregateColumn(gwi.sessionid);
ac->timeZone(gwi.timeZone);
ac->alias(rc->alias());
ac->aggOp(AggregateColumn::SELECT_SOME);
ac->asc(rc->asc());
ac->charsetNumber(rc->charsetNumber());
ac->orderPos(rc->orderPos());
uint32_t i;
for(i=0; i < gwi.processed.size() && !gwi.processed[i].first->eq(baseItem, false);i++)
{ }
if (i < gwi.processed.size())
{
ac->expressionId(gwi.processed[i].second);
}
else
{
ac->expressionId(ci->expressionId++);
}
ac->aggParms().push_back(SRCP(rc));
ac->resultType(rc->resultType());
return ac;
}
ReturnedColumn* buildReturnedColumnNull(gp_walk_info& gwi)
{
if (gwi.condPush)
@ -3492,7 +3614,7 @@ static ConstantColumn* buildConstantColumnNotNullUsingValNative(Item* item, gp_w
return rc;
}
ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem)
ReturnedColumn* buildReturnedColumnBody(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem)
{
ReturnedColumn* rc = NULL;
@ -3514,12 +3636,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp
{
Item_field* ifp = (Item_field*)item;
if (isRefItem && gwi.isGroupByHandler && !gwi.extSelAggColsItems.empty())
{
return buildAggFrmTempField(ifp, gwi);
}
return buildSimpleColumn(ifp, gwi);
return wrapIntoAggregate(buildSimpleColumn(ifp, gwi), gwi, ifp);
}
case Item::NULL_ITEM: return buildReturnedColumnNull(gwi);
case Item::CONST_ITEM:
@ -3560,7 +3677,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);
else
{
return buildFunctionColumn(ifp, gwi, nonSupport);
}
}
case Item::SUM_FUNC_ITEM:
@ -3681,6 +3800,14 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp
return rc;
}
ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem)
{
bool disableWrapping = gwi.disableWrapping;
gwi.disableWrapping = gwi.disableWrapping || itemDisablesWrapping(item, gwi);
ReturnedColumn* rc = buildReturnedColumnBody(item, gwi, nonSupport, isRefItem);
gwi.disableWrapping = disableWrapping;
return rc;
}
// parse the boolean fields to string "true" or "false"
ReturnedColumn* buildBooleanConstantColumn(Item* item, gp_walk_info& gwi, bool& nonSupport)
@ -3711,7 +3838,7 @@ ReturnedColumn* buildBooleanConstantColumn(Item* item, gp_walk_info& gwi, bool&
return cc;
}
ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport)
ReturnedColumn* buildArithmeticColumnBody(Item_func* item, gp_walk_info& gwi, bool& nonSupport)
{
if (get_fe_conn_info_ptr() == NULL)
{
@ -3754,7 +3881,8 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool
// Could have it set if there are aggregation funcs as this function arguments.
gwi.fatalParseError = false;
ReturnedColumn* rc = buildAggFrmTempField(sfitempp[0], gwi);
//ReturnedColumn* rc = buildAggFrmTempField(sfitempp[0], gwi);
ReturnedColumn* rc = buildReturnedColumn(sfitempp[0], gwi, nonSupport);
if (rc)
lhs = new ParseTree(rc);
}
@ -3773,12 +3901,13 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool
// Could have it set if there are aggregation funcs as this function arguments.
gwi.fatalParseError = false;
ReturnedColumn* rc = buildAggFrmTempField(sfitempp[1], gwi);
//ReturnedColumn* rc = buildAggFrmTempField(sfitempp[1], gwi);
ReturnedColumn* rc = buildReturnedColumn(sfitempp[1], gwi, nonSupport);
if (rc)
rhs = new ParseTree(rc);
}
}
else // where clause
else // where clause SZ: XXX: is it also HAVING clause??? it appears so judging from condition above.
{
if (isPredicateFunction(sfitempp[1], &gwi))
{
@ -3945,7 +4074,8 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool
ac->expressionId(ci->expressionId++);
// @3391. optimization. try to associate expression ID to the expression on the select list
if (gwi.clauseType != SELECT)
bool isOnSelectList = false;
if (gwi.clauseType != SELECT || gwi.havingDespiteSelect)
{
for (uint32_t i = 0; i < gwi.returnedCols.size(); i++)
{
@ -3953,6 +4083,7 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool
strcasecmp(ac->alias().c_str(), gwi.returnedCols[i]->alias().c_str()) == 0)
{
ac->expressionId(gwi.returnedCols[i]->expressionId());
isOnSelectList = true;
break;
}
}
@ -3971,10 +4102,24 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool
}
}
if (isOnSelectList && gwi.havingDespiteSelect)
{
SimpleColumn* sc = new SimpleColumn(*ac);
delete ac;
return sc;
}
return ac;
}
ReturnedColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport)
{
bool disableWrapping = gwi.disableWrapping;
gwi.disableWrapping = gwi.disableWrapping || itemDisablesWrapping(item, gwi);
ReturnedColumn* rc = buildArithmeticColumnBody(item, gwi, nonSupport);
gwi.disableWrapping = disableWrapping;
return rc;
}
ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& nonSupport, bool selectBetweenIn)
ReturnedColumn* buildFunctionColumnBody(Item_func* ifp, gp_walk_info& gwi, bool& nonSupport, bool selectBetweenIn)
{
if (get_fe_conn_info_ptr() == NULL)
{
@ -4037,8 +4182,7 @@ ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& non
// Arithmetic exp
if (funcName == "+" || funcName == "-" || funcName == "*" || funcName == "/")
{
ArithmeticColumn* ac = buildArithmeticColumn(ifp, gwi, nonSupport);
return ac;
return buildArithmeticColumn(ifp, gwi, nonSupport);
}
else if (funcName == "case")
@ -4217,7 +4361,9 @@ ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& non
if (mayHasBoolArg && isBoolType)
rc = buildBooleanConstantColumn(ifp->arguments()[i], gwi, nonSupport);
else
{
rc = buildReturnedColumn(ifp->arguments()[i], gwi, nonSupport);
}
// MCOL-1510 It must be a temp table field, so find the corresponding column.
if (!rc && ifp->arguments()[i]->type() == Item::REF_ITEM)
@ -4583,6 +4729,14 @@ ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& non
return fc;
}
ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& nonSupport, bool selectBetweenIn)
{
bool disableWrapping = gwi.disableWrapping;
gwi.disableWrapping = gwi.disableWrapping || itemDisablesWrapping(ifp, gwi);
ReturnedColumn* rc = buildFunctionColumnBody(ifp, gwi, nonSupport, selectBetweenIn);
gwi.disableWrapping = disableWrapping;
return rc;
}
FunctionColumn* buildCaseFunction(Item_func* item, gp_walk_info& gwi, bool& nonSupport)
{
@ -5041,44 +5195,7 @@ void analyzeForImplicitGroupBy(Item* item, gp_walk_info& gwi)
}
}
ReturnedColumn* wrapIntoAggregate(ReturnedColumn* rc, gp_walk_info& gwi, SELECT_LEX& select_lex, Item* baseItem)
{
if (!gwi.implicitExplicitGroupBy)
{
return rc;
}
if (dynamic_cast<AggregateColumn*>(rc) != nullptr || dynamic_cast<ConstantColumn*>(rc) != nullptr)
{
return rc;
}
ORDER* groupcol = static_cast<ORDER*>(select_lex.group_list.first);
while (groupcol)
{
if (baseItem->eq(*groupcol->item, false))
{
return rc;
}
groupcol = groupcol->next;
}
cal_connection_info* ci = static_cast<cal_connection_info*>(get_fe_conn_info_ptr());
AggregateColumn* ac = new AggregateColumn(gwi.sessionid);
ac->timeZone(gwi.timeZone);
ac->alias(rc->alias());
ac->aggOp(AggregateColumn::SELECT_SOME);
ac->asc(rc->asc());
ac->charsetNumber(rc->charsetNumber());
ac->expressionId(ci->expressionId++);
ac->aggParms().push_back(SRCP(rc));
return ac;
}
ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi)
ReturnedColumn* buildAggregateColumnBody(Item* item, gp_walk_info& gwi)
{
// MCOL-1201 For UDAnF multiple parameters
vector<SRCP> selCols;
@ -5378,6 +5495,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi)
{
//@bug5229. handle constant function on aggregate argument
ac->constCol(SRCP(rc));
// XXX: this skips restoration of clauseType.
break;
}
// the "rc" can be in gwi.no_parm_func_list. erase it from that list and
@ -5759,6 +5877,14 @@ because it has multiple arguments.";
ac->charsetNumber(item->collation.collation->number);
return ac;
}
ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi)
{
bool disableWrapping = gwi.disableWrapping;
gwi.disableWrapping = true;
ReturnedColumn* rc = buildAggregateColumnBody(item, gwi);
gwi.disableWrapping = disableWrapping;
return rc;
}
void addIntervalArgs(gp_walk_info* gwip, Item_func* ifp, FunctionParm& functionParms)
{
@ -5890,6 +6016,7 @@ void gp_walk(const Item* item, void* arg)
if (ifp)
{
// XXX: this looks awfuly wrong.
SimpleColumn* scp = buildSimpleColumn(ifp, *gwip);
if (!scp)
@ -5898,7 +6025,7 @@ void gp_walk(const Item* item, void* arg)
string aliasTableName(scp->tableAlias());
scp->tableAlias(aliasTableName);
gwip->rcWorkStack.push(scp->clone());
boost::shared_ptr<SimpleColumn> scsp(scp);
boost::shared_ptr<SimpleColumn> scsp(scp);
gwip->scsp = scsp;
gwip->funcName.clear();
@ -5993,7 +6120,7 @@ void gp_walk(const Item* item, void* arg)
}
ostringstream oss;
oss << "Unhandled Item type: " << item->type();
oss << "Unhandled Item type(): " << item->type();
gwip->parseErrorText = oss.str();
gwip->fatalParseError = true;
break;
@ -6343,7 +6470,7 @@ void gp_walk(const Item* item, void* arg)
gwip->fatalParseError = false;
}
SimpleColumn* sc = dynamic_cast<SimpleColumn*>(rc);
SimpleColumn* sc = clauseType == HAVING ? nullptr : dynamic_cast<SimpleColumn*>(rc);
if (sc)
{
@ -6437,19 +6564,27 @@ void gp_walk(const Item* item, void* arg)
}
else if (col->type() == Item::FIELD_ITEM && gwip->clauseType == HAVING)
{
ReturnedColumn* rc = buildAggFrmTempField(const_cast<Item*>(item), *gwip);
//ReturnedColumn* rc = buildAggFrmTempField(const_cast<Item*>(item), *gwip);
ReturnedColumn* rc = buildReturnedColumn(const_cast<Item*>(item), *gwip, gwip->fatalParseError);
if (rc)
gwip->rcWorkStack.push(rc);
break;
}
else
{
cando = false;
}
if (!cando)
SimpleColumn* thisSC = dynamic_cast<SimpleColumn*>(rc);
if (thisSC)
{
gwip->scsp.reset(thisSC->clone());
}
if (!rc && !cando)
{
ostringstream oss;
oss << "Unhandled Item type: " << item->type();
oss << "Unhandled Item type(): " << item->type();
gwip->parseErrorText = oss.str();
gwip->fatalParseError = true;
}
@ -6502,7 +6637,6 @@ void gp_walk(const Item* item, void* arg)
vector<SRCP> cols;
// temp change clause type because the elements of row column are not walked yet
gwip->clauseType = SELECT;
for (uint32_t i = 0; i < row->cols(); i++)
cols.push_back(SRCP(buildReturnedColumn(row->element_index(i), *gwip, gwip->fatalParseError)));
@ -6561,7 +6695,7 @@ void gp_walk(const Item* item, void* arg)
}
ostringstream oss;
oss << "Unhandled Item type: " << item->type();
oss << "Unhandled Item type (2): " << item->type();
gwip->parseErrorText = oss.str();
gwip->fatalParseError = true;
break;
@ -6664,15 +6798,15 @@ void parse_item(Item* item, vector<Item_field*>& field_vec, bool& hasNonSupportI
// MCOL-1510. This could be a non-supported function
// argument in form of a temp_table_field, so check
// and set hasNonSupportItem if it is so.
ReturnedColumn* rc = NULL;
if (gwi)
rc = buildAggFrmTempField(ref, *gwi);
//ReturnedColumn* rc = NULL;
//if (gwi)
// rc = buildAggFrmTempField(ref, *gwi);
if (!rc)
{
//if (!rc)
//{
Item_field* ifp = static_cast<Item_field*>(*(ref->ref));
field_vec.push_back(ifp);
}
//}
break;
}
else if ((*(ref->ref))->type() == Item::FUNC_ITEM)
@ -7599,6 +7733,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
}
gwi.clauseType = SELECT;
SELECT_LEX* oldSelectLex = gwi.select_lex; // XXX: SZ: should it be restored in case of error return?
gwi.select_lex = &select_lex;
#ifdef DEBUG_WALK_COND
{
cerr << "------------------- SELECT --------------------" << endl;
@ -7707,10 +7843,10 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
}
// We need to look into GROUP BY columns to decide if we need to wrap a column.
ReturnedColumn* rc = wrapIntoAggregate(sc, gwi, select_lex, baseItem);
ReturnedColumn* rc = wrapIntoAggregate(sc, gwi, baseItem);
SRCP sprc(rc);
gwi.returnedCols.push_back(sprc);
pushReturnedCol(gwi, baseItem, sprc);
gwi.columnMap.insert(
CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name.str), sprc));
@ -7747,7 +7883,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
// add this agg col to returnedColumnList
boost::shared_ptr<ReturnedColumn> spac(ac);
gwi.returnedCols.push_back(spac);
pushReturnedCol(gwi, item, spac);
break;
}
@ -7806,7 +7942,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
if (!hasNonSupportItem && ifp->const_item() && !(parseInfo & AF_BIT) && tmpVec.size() == 0)
{
srcp.reset(buildReturnedColumn(item, gwi, gwi.fatalParseError));
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, item, srcp);
if (ifp->name.length)
srcp->alias(ifp->name.str);
@ -7814,7 +7950,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
continue;
}
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, item, srcp);
}
else // This was a vtable post-process block
{
@ -7836,7 +7972,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
if (ifp->name.length)
cc->alias(ifp->name.str);
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, ifp, srcp);
// clear the error set by buildFunctionColumn
gwi.fatalParseError = false;
@ -7914,7 +8050,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
if (item->name.length)
srcp->alias(item->name.str);
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, item, srcp);
}
break;
@ -7938,7 +8074,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
else
{
SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError));
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, item, srcp);
if (item->name.length)
srcp->alias(item->name.str);
@ -8034,7 +8170,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
return ER_CHECK_NOT_IMPLEMENTED;
}
gwi.returnedCols.push_back(srcp);
pushReturnedCol(gwi, item, srcp);
break;
}
case Item::TYPE_HOLDER:
@ -8095,12 +8231,16 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
// Having clause handling
gwi.clauseType = HAVING;
gwi.havingDespiteSelect = true;
clearStacks(gwi, false, true);
std::unique_ptr<ParseTree> havingFilter;
// clear fatalParseError that may be left from post process functions
gwi.fatalParseError = false;
gwi.parseErrorText = "";
gwi.disableWrapping = false;
gwi.havingDespiteSelect = true;
if (select_lex.having != 0)
{
#ifdef DEBUG_WALK_COND
@ -8142,6 +8282,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
gwi.ptWorkStack.push(ptp);
}
}
gwi.havingDespiteSelect = false;
gwi.disableWrapping = false;
// MCOL-4617 If this is an IN subquery, then create the in-to-exists
// predicate and inject it into the csep
@ -8227,7 +8369,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
funcFieldVec[i]->print(&str, QT_ORDINARY);
sc->alias(string(str.c_ptr()));
sc->tableAlias(sc->tableAlias());
SRCP srcp(sc);
SRCP srcp(wrapIntoAggregate(sc, gwi, funcFieldVec[i]));
uint32_t j = 0;
for (; j < gwi.returnedCols.size(); j++)
@ -8244,6 +8386,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
if (j == gwi.returnedCols.size())
{
gwi.returnedCols.push_back(srcp);
// XXX: SZ: deduplicate here?
gwi.columnMap.insert(
CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name.str), srcp));
@ -8288,6 +8431,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
gwi.hasWindowFunc = hasWindowFunc;
groupcol = static_cast<ORDER*>(select_lex.group_list.first);
gwi.disableWrapping = true;
for (; groupcol; groupcol = groupcol->next)
{
Item* groupItem = *(groupcol->item);
@ -8511,6 +8655,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
nonSupportItem = groupItem;
}
}
gwi.disableWrapping = false;
// @bug 4756. Add internal groupby column for correlated join to the groupby list
if (gwi.aggOnSelect && !gwi.subGroupByCols.empty())
@ -8629,7 +8774,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
{
rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError);
rc = wrapIntoAggregate(rc, gwi, select_lex, ord_item);
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
@ -8856,6 +9001,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i
for (uint32_t i = 0; i < gwi.localCols.size(); i++)
gwi.localCols[i]->sequence(i);
gwi.select_lex = oldSelectLex;
// append additionalRetCols to returnedCols
gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(),
gwi.additionalRetCols.end());
@ -9000,6 +9146,7 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi)
gp_walk_info gwi(timeZoneOffset, &chain);
gwi.thd = thd;
gwi.isGroupByHandler = true;
idbassert(0);
int status = getGroupPlan(gwi, *select_lex, csep, gi);
#ifdef DEBUG_WALK_COND

View File

@ -117,7 +117,7 @@ struct gp_walk_info
std::vector<execplan::ReturnedColumn*> localCols;
std::stack<execplan::ReturnedColumn*> rcWorkStack;
std::stack<execplan::ParseTree*> ptWorkStack;
boost::shared_ptr<execplan::SimpleColumn> scsp;
boost::shared_ptr<execplan::SimpleColumn> scsp; // while defined as SSCP, it is used as SRCP, nothing specific to SimpleColumn is used in use sites.
uint32_t sessionid;
bool fatalParseError;
std::string parseErrorText;
@ -144,6 +144,7 @@ struct gp_walk_info
// we can have explicit GROUP BY and implicit one, triggered by aggregate in pojection or ORDER BY.
// this flag tells us whether we have either case.
bool implicitExplicitGroupBy;
bool disableWrapping;
bool aggOnSelect;
bool hasWindowFunc;
bool hasSubSelect;
@ -179,6 +180,15 @@ struct gp_walk_info
TableOnExprList tableOnExprList;
std::vector<COND*> condList;
// Item* associated with returnedCols.
std::vector<std::pair<Item*, uint32_t>> processed;
// SELECT_LEX is needed for aggergate wrapping
SELECT_LEX* select_lex;
// we are processing HAVING despite having (pun not intented) clauseType equal to SELECT.
bool havingDespiteSelect;
// All SubQuery allocations are single-linked into this chain.
// At the end of gp_walk_info processing we can free whole chain at once.
// This is done so because the juggling of SubQuery pointers in the
@ -198,6 +208,7 @@ struct gp_walk_info
, subQuery(0)
, clauseType(INIT)
, implicitExplicitGroupBy(false)
, disableWrapping(false)
, aggOnSelect(false)
, hasWindowFunc(false)
, hasSubSelect(false)
@ -212,6 +223,8 @@ struct gp_walk_info
, timeZone(timeZone_)
, inSubQueryLHS(nullptr)
, inSubQueryLHSItem(nullptr)
, select_lex(nullptr)
, havingDespiteSelect(false)
, subQueriesChain(subQueriesChain_)
{
}
@ -424,7 +437,7 @@ execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, boo
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::ReturnedColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport);
execplan::ConstantColumn* buildDecimalColumn(const Item* item, const std::string& str, 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);

View File

@ -26,6 +26,9 @@ SELECT col1, col2, SUM(LENGTH(col2)) FROM t1 GROUP BY col1 HAVING col1 > 1 AND c
col1 col2 SUM(LENGTH(col2))
2 oooooooooooooooooooo 40
4 ooo 6
SELECT 'some output';
some output
some output
CREATE TABLE t2(col1 INT, col2 DATETIME)ENGINE=Columnstore;
INSERT INTO t2 VALUES(1, '2020-2-2'),(2, '2020-3-3'),(5,'2020-6-6'),(6, '2020-7-7');
SELECT t1.col1, SUM(t1.col1*t2.col1) AS a FROM t1 JOIN t2 ON t1.col1 = t2.col1 GROUP BY t1.col1 HAVING a>1 ORDER BY t1.col1;

View File

@ -21,6 +21,7 @@ SELECT col1, col2 FROM t1 GROUP BY col1, col2 HAVING col1 > 1 OR col2 LIKE '%o%'
--sorted_result
SELECT col1, col2, SUM(LENGTH(col2)) FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
SELECT 'some output';
CREATE TABLE t2(col1 INT, col2 DATETIME)ENGINE=Columnstore;
INSERT INTO t2 VALUES(1, '2020-2-2'),(2, '2020-3-3'),(5,'2020-6-6'),(6, '2020-7-7');
SELECT t1.col1, SUM(t1.col1*t2.col1) AS a FROM t1 JOIN t2 ON t1.col1 = t2.col1 GROUP BY t1.col1 HAVING a>1 ORDER BY t1.col1;

View File

@ -0,0 +1,214 @@
DROP DATABASE IF EXISTS MCOL5776;
CREATE DATABASE MCOL5776;
USE MCOL5776;
CREATE TABLE t(x INTEGER, y INTEGER) ENGINE=Columnstore;
INSERT INTO t(x,y) VALUES (1,2), (2,3), (3,3);
SELECT COUNT(y) OVER (PARTITION BY y) FROM t GROUP BY x;
COUNT(y) OVER (PARTITION BY y)
1
2
2
SELECT COUNT(y) OVER (PARTITION BY LEFT(y, 10)) FROM t GROUP BY x;
COUNT(y) OVER (PARTITION BY LEFT(y, 10))
1
2
2
DROP TABLE t;
CREATE TABLE t(ci1 integer, ci2 integer) engine=Columnstore;
INSERT INTO t(ci1, ci2) VALUES (NULL, 1), (NULL, 2), (1,3), (1,4), (2,5), (2,6), (3,7), (3,8);
SELECT ci1+ci2, ci1+ci2, SUM(ci2), AVG(ci2) FROM t GROUP BY ci1+ci2, ci1+ci2;
ci1+ci2 ci1+ci2 SUM(ci2) AVG(ci2)
10 10 7 7.0000
11 11 8 8.0000
4 4 3 3.0000
5 5 4 4.0000
7 7 5 5.0000
8 8 6 6.0000
NULL NULL 3 1.5000
SELECT CONCAT(ci1,ci2), CONCAT(ci1,ci2), SUM(ci2), AVG(ci2) FROM t GROUP BY ci1;
CONCAT(ci1,ci2) CONCAT(ci1,ci2) SUM(ci2) AVG(ci2)
14 14 7 3.5000
26 26 11 5.5000
38 38 15 7.5000
NULL NULL 3 1.5000
SELECT sum(ci1), abs(ci1) FROM t GROUP BY abs(ci1), abs(ci1);
sum(ci1) abs(ci1)
2 1
4 2
6 3
NULL NULL
SELECT sum(ci1), abs(ci1) FROM t GROUP BY abs(ci1);
sum(ci1) abs(ci1)
2 1
4 2
6 3
NULL NULL
DROP TABLE t;
CREATE TABLE t1(col1 INT, col2 TEXT)ENGINE=Columnstore;
INSERT INTO t1 VALUES(1, repeat('s',20)),(2, repeat('o',20)),(3, 'sss'),(4, 'ooo');
INSERT INTO t1 SELECT * FROM t1;
SELECT * FROM t1;
col1 col2
1 ssssssssssssssssssss
2 oooooooooooooooooooo
3 sss
4 ooo
1 ssssssssssssssssssss
2 oooooooooooooooooooo
3 sss
4 ooo
SELECT col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' ORDER BY col2;
col2
ooo
oooooooooooooooooooo
SELECT col1 FROM t1 GROUP BY col1 HAVING col1 > 1 ORDER BY col1;
col1
2
3
4
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col2, col1 FROM t1 GROUP BY col2 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
ooo 4
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
ooo 4
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
col1 col2
2 oooooooooooooooooooo
4 ooo
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 = 'ooo' ORDER BY col1;
col2 col1
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 = 'ooo' AND col1 > 1 ORDER BY col1;
col2 col1
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 >= 'ooo' ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
sss 3
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 >= 'ooo' AND col1 > 1 ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
sss 3
ooo 4
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 < 'ooo' ORDER BY col1;
col2 col1
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 < 'ooo' AND col1 > 1 ORDER BY col1;
col2 col1
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND 'ooo' < col2 ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
sss 3
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING 'ooo' < col2 AND col1 > 1 ORDER BY col1;
col2 col1
oooooooooooooooooooo 2
sss 3
SELECT col1, col2, SUM(LENGTH(col2)) FROM t1 GROUP BY col1 HAVING SUM(LENGTH(col2)) > 10 ORDER BY col1;
col1 col2 SUM(LENGTH(col2))
1 ssssssssssssssssssss 40
2 oooooooooooooooooooo 40
SELECT col1, col2, SUM(LENGTH(col2)) a FROM t1 GROUP BY col1 HAVING a > 1 AND col2 LIKE '%o%' ORDER BY col1;
col1 col2 a
2 oooooooooooooooooooo 40
4 ooo 6
DROP TABLE t1;
CREATE TABLE empsalary (
depname VARCHAR(100),
empno BIGINT,
salary INT,
enroll_date DATE
) ENGINE=Columnstore;
INSERT INTO empsalary VALUES ('develop' , 10, 5200, '2007-08-01');
INSERT INTO empsalary VALUES ('sales' , 1, 5000, '2006-10-01');
INSERT INTO empsalary VALUES ('personnel', 5, 3500, '2007-12-10');
INSERT INTO empsalary VALUES ('sales' , 4, 4800, '2007-08-08');
INSERT INTO empsalary VALUES ('personnel', 2, 3900, '2006-12-23');
INSERT INTO empsalary VALUES ('develop' , 7, 4200, '2008-01-01');
INSERT INTO empsalary VALUES ('develop' , 9, 4500, '2008-01-01');
INSERT INTO empsalary VALUES ('sales' , 3, 4800, '2007-08-01');
INSERT INTO empsalary VALUES ('develop' , 8, 6000, '2006-10-01');
INSERT INTO empsalary VALUES ('develop' , 11, 5200, '2007-08-15');
INSERT INTO empsalary VALUES ('develop' , 12, null, '2008-08-09');
SELECT depname, empno, MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date) FROM empsalary ORDER BY depname, empno, enroll_date;
depname empno MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date)
develop 7 5200
develop 8 6000
develop 9 5200
develop 10 5200
develop 11 5200
develop 12 5200
personnel 2 3900
personnel 5 3500
sales 1 5000
sales 3 4800
sales 4 4800
SELECT AVG(salary),depname, MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date) FROM empsalary GROUP BY depname ORDER BY depname, AVG(salary);
AVG(salary) depname MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date)
5020.0000 develop 0
3700.0000 personnel 3900
4866.6667 sales 4800
DROP TABLE empsalary;
CREATE TABLE orders(o_custkey INT) ENGINE=Columnstore;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) < 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) <= 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) > 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) >= 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) = 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) <> 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IN (15, 20) ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) NOT IN (15, 20) ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) BETWEEN 15 AND 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) NOT BETWEEN 15 and 20 ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IS NULL ORDER BY 1;
o_custkey COUNT(*)
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IS NOT NULL ORDER BY 1;
o_custkey COUNT(*)
DROP TABLE orders;
CREATE TABLE t(k INT) ENGINE = Columnstore;
INSERT INTO t(k) VALUES (1), (2), (2), (3), (3), (4), (4),(4),(4),(4),(995), (NULL);
SELECT k + k a FROM t GROUP BY a HAVING a >= 8;
a
1990
8
DROP DATABASE MCOL5776;

View File

@ -0,0 +1,99 @@
--disable_warnings
DROP DATABASE IF EXISTS MCOL5776;
--enable_warnings
CREATE DATABASE MCOL5776;
USE MCOL5776;
CREATE TABLE t(x INTEGER, y INTEGER) ENGINE=Columnstore;
INSERT INTO t(x,y) VALUES (1,2), (2,3), (3,3);
SELECT COUNT(y) OVER (PARTITION BY y) FROM t GROUP BY x;
SELECT COUNT(y) OVER (PARTITION BY LEFT(y, 10)) FROM t GROUP BY x;
DROP TABLE t;
CREATE TABLE t(ci1 integer, ci2 integer) engine=Columnstore;
INSERT INTO t(ci1, ci2) VALUES (NULL, 1), (NULL, 2), (1,3), (1,4), (2,5), (2,6), (3,7), (3,8);
--sorted_result
SELECT ci1+ci2, ci1+ci2, SUM(ci2), AVG(ci2) FROM t GROUP BY ci1+ci2, ci1+ci2;
--sorted_result
SELECT CONCAT(ci1,ci2), CONCAT(ci1,ci2), SUM(ci2), AVG(ci2) FROM t GROUP BY ci1;
--sorted_result
SELECT sum(ci1), abs(ci1) FROM t GROUP BY abs(ci1), abs(ci1);
--sorted_result
SELECT sum(ci1), abs(ci1) FROM t GROUP BY abs(ci1);
DROP TABLE t;
CREATE TABLE t1(col1 INT, col2 TEXT)ENGINE=Columnstore;
INSERT INTO t1 VALUES(1, repeat('s',20)),(2, repeat('o',20)),(3, 'sss'),(4, 'ooo');
INSERT INTO t1 SELECT * FROM t1;
SELECT * FROM t1;
SELECT col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' ORDER BY col2;
SELECT col1 FROM t1 GROUP BY col1 HAVING col1 > 1 ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col2 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col2 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 LIKE '%o%' ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col1, col2 FROM t1 GROUP BY col1 HAVING col2 LIKE '%o%' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 = 'ooo' ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 = 'ooo' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 >= 'ooo' ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 >= 'ooo' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND col2 < 'ooo' ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col2 < 'ooo' AND col1 > 1 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING col1 > 1 AND 'ooo' < col2 ORDER BY col1;
SELECT col2, col1 FROM t1 GROUP BY col1 HAVING 'ooo' < col2 AND col1 > 1 ORDER BY col1;
SELECT col1, col2, SUM(LENGTH(col2)) FROM t1 GROUP BY col1 HAVING SUM(LENGTH(col2)) > 10 ORDER BY col1;
SELECT col1, col2, SUM(LENGTH(col2)) a FROM t1 GROUP BY col1 HAVING a > 1 AND col2 LIKE '%o%' ORDER BY col1;
DROP TABLE t1;
CREATE TABLE empsalary (
depname VARCHAR(100),
empno BIGINT,
salary INT,
enroll_date DATE
) ENGINE=Columnstore;
INSERT INTO empsalary VALUES ('develop' , 10, 5200, '2007-08-01');
INSERT INTO empsalary VALUES ('sales' , 1, 5000, '2006-10-01');
INSERT INTO empsalary VALUES ('personnel', 5, 3500, '2007-12-10');
INSERT INTO empsalary VALUES ('sales' , 4, 4800, '2007-08-08');
INSERT INTO empsalary VALUES ('personnel', 2, 3900, '2006-12-23');
INSERT INTO empsalary VALUES ('develop' , 7, 4200, '2008-01-01');
INSERT INTO empsalary VALUES ('develop' , 9, 4500, '2008-01-01');
INSERT INTO empsalary VALUES ('sales' , 3, 4800, '2007-08-01');
INSERT INTO empsalary VALUES ('develop' , 8, 6000, '2006-10-01');
INSERT INTO empsalary VALUES ('develop' , 11, 5200, '2007-08-15');
INSERT INTO empsalary VALUES ('develop' , 12, null, '2008-08-09');
SELECT depname, empno, MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date) FROM empsalary ORDER BY depname, empno, enroll_date;
SELECT AVG(salary),depname, MODA(salary) OVER(PARTITION BY depname ORDER BY enroll_date) FROM empsalary GROUP BY depname ORDER BY depname, AVG(salary);
DROP TABLE empsalary;
CREATE TABLE orders(o_custkey INT) ENGINE=Columnstore;
# These checks for absence of exceptions and SIGSEGV's
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) < 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) <= 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) > 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) >= 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) = 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) <> 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IN (15, 20) ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) NOT IN (15, 20) ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) BETWEEN 15 AND 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) NOT BETWEEN 15 and 20 ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IS NULL ORDER BY 1;
SELECT o_custkey, COUNT(*) FROM orders WHERE o_custkey < 100 GROUP BY o_custkey HAVING COUNT(*) IS NOT NULL ORDER BY 1;
DROP TABLE orders;
CREATE TABLE t(k INT) ENGINE = Columnstore;
INSERT INTO t(k) VALUES (1), (2), (2), (3), (3), (4), (4),(4),(4),(4),(995), (NULL);
--sorted_result
SELECT k + k a FROM t GROUP BY a HAVING a >= 8;
DROP DATABASE MCOL5776;

View File

@ -14,14 +14,6 @@ sales 3 4800
sales 4 4800
select avg(salary),depname, moda(salary) over(partition by depname order by enroll_date) from empsalary group by depname order by depname, avg(salary);
avg(salary) depname moda(salary) over(partition by depname order by enroll_date)
NULL develop 5200
4200.0000 develop 5200
4500.0000 develop 5200
5200.0000 develop 5200
5200.0000 develop 5200
6000.0000 develop 6000
3500.0000 personnel 3500
3900.0000 personnel 3900
4800.0000 sales 4800
4800.0000 sales 4800
5000.0000 sales 5000
5020.0000 develop 0
3700.0000 personnel 3900
4866.6667 sales 4800

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(storagemanager)
include_directories(include ${CMAKE_BINARY_DIR}/include ${ENGINE_UTILS_COMMON_INCLUDE} ${S3API_DIR})
include_directories(include ${CMAKE_BINARY_DIR}/include ${ENGINE_COMMON_INCLUDES} ${S3API_DIR})
set(storagemanager_SRCS
src/AppendTask.cpp

View File

@ -25,7 +25,7 @@ fi
run_suite()
{
ls /core >$CURRENT_DIR/mtr.$1.cores-before
./mtr --force --max-test-fail=0 --testcase-timeout=60 --suite=columnstore/$1 $2 | tee $CURRENT_DIR/mtr.$1.log 2>&1
./mtr --force --extern=socket=/run/mysqld/mysqld.sock --max-test-fail=0 --testcase-timeout=60 --suite=columnstore/$1 $2 | tee $CURRENT_DIR/mtr.$1.log 2>&1
# dump analyses.
systemctl stop mariadb
systemctl start mariadb

View File

@ -1252,6 +1252,7 @@ inline void Row::setUintField(uint64_t val, uint32_t colIndex)
template <int len>
inline void Row::setIntField(int64_t val, uint32_t colIndex)
{
// idbassert(getColumnWidth(colIndex) == len);
switch (len)
{
case 1: *((int8_t*)&data[offsets[colIndex]]) = val; break;