From 772c37b4d61d28c08703ebe75b1a5ce3c54f3c5b Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Wed, 1 Jan 2025 19:17:12 +0800 Subject: [PATCH] fix: empty block --- source/libs/executor/src/aggregateoperator.c | 6 + source/libs/function/src/builtinsimpl.c | 1 - source/libs/nodes/src/nodesMsgFuncs.c | 12 ++ source/libs/parser/src/parTranslater.c | 8 +- source/libs/planner/src/planOptimizer.c | 2 +- tests/system-test/2-query/cols_function.py | 175 ++++++++++++++++++- 6 files changed, 193 insertions(+), 11 deletions(-) diff --git a/source/libs/executor/src/aggregateoperator.c b/source/libs/executor/src/aggregateoperator.c index 5713726501..bec8bf7f6f 100644 --- a/source/libs/executor/src/aggregateoperator.c +++ b/source/libs/executor/src/aggregateoperator.c @@ -395,6 +395,12 @@ static int32_t createDataBlockForEmptyInput(SOperatorInfo* pOperator, SSDataBloc return TSDB_CODE_SUCCESS; } + // if the last expression is a tuple function, we don't need to create a empty data block + int32_t lastExprIndex = pOperator->exprSupp.numOfExprs - 1; + if(pOperator->exprSupp.pExprInfo[lastExprIndex].pExpr->tupleFuncIdx > 0) { + return TSDB_CODE_SUCCESS; + } + code = createDataBlock(&pBlock); if (code) { return code; diff --git a/source/libs/function/src/builtinsimpl.c b/source/libs/function/src/builtinsimpl.c index 3d1b04f223..91751c41ef 100644 --- a/source/libs/function/src/builtinsimpl.c +++ b/source/libs/function/src/builtinsimpl.c @@ -2403,7 +2403,6 @@ int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResIn } SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo); - SInputColumnInfoData* pInput = &pCtx->input; pRes->nullTupleSaved = false; pRes->nullTuplePos.pageId = -1; diff --git a/source/libs/nodes/src/nodesMsgFuncs.c b/source/libs/nodes/src/nodesMsgFuncs.c index b122c3fffd..5bd773796f 100644 --- a/source/libs/nodes/src/nodesMsgFuncs.c +++ b/source/libs/nodes/src/nodesMsgFuncs.c @@ -708,6 +708,12 @@ static int32_t columnNodeInlineToMsg(const void* pObj, STlvEncoder* pEncoder) { const SColumnNode* pNode = (const SColumnNode*)pObj; int32_t code = dataTypeInlineToMsg(&pNode->node.resType, pEncoder); + if (TSDB_CODE_SUCCESS == code) { + code = tlvEncodeValueI32(pEncoder, pNode->node.bindTupleFuncIdx); + } + if (TSDB_CODE_SUCCESS == code) { + code = tlvEncodeValueI32(pEncoder, pNode->node.tupleFuncIdx); + } if (TSDB_CODE_SUCCESS == code) { code = tlvEncodeValueU64(pEncoder, pNode->tableId); } @@ -758,6 +764,12 @@ static int32_t msgToColumnNodeInline(STlvDecoder* pDecoder, void* pObj) { SColumnNode* pNode = (SColumnNode*)pObj; int32_t code = msgToDataTypeInline(pDecoder, &pNode->node.resType); + if (TSDB_CODE_SUCCESS == code) { + code = tlvDecodeValueI32(pDecoder, &pNode->node.bindTupleFuncIdx); + } + if (TSDB_CODE_SUCCESS == code) { + code = tlvDecodeValueI32(pDecoder, &pNode->node.tupleFuncIdx); + } if (TSDB_CODE_SUCCESS == code) { code = tlvDecodeValueU64(pDecoder, &pNode->tableId); } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 1ccfce3e0a..4a5258c5fc 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -3825,9 +3825,6 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) { if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) { return DEAL_RES_IGNORE_CHILD; } - if (isColsFunctionResult(*pNode)) { - return DEAL_RES_IGNORE_CHILD; - } SNode* pGroupNode = NULL; FOREACH(pGroupNode, getGroupByList(pCxt)) { SNode* pActualNode = getGroupByNode(pGroupNode); @@ -3865,7 +3862,8 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) { } if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) { - if (pSelect->selectFuncNum > 1 || (isDistinctOrderBy(pCxt) && pCxt->currClause == SQL_CLAUSE_ORDER_BY)) { + if ((pSelect->selectFuncNum > 1 || (isDistinctOrderBy(pCxt) && pCxt->currClause == SQL_CLAUSE_ORDER_BY)) && + ((SExprNode*)*pNode)->bindTupleFuncIdx == 0) { return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias); } if (isWindowJoinStmt(pSelect) && @@ -3874,7 +3872,7 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) { return rewriteExprToGroupKeyFunc(pCxt, pNode); } - if (pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) { + if ((pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) && ((SExprNode*)*pNode)->bindTupleFuncIdx == 0) { return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias); } diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 63554e3a4e..761b6d43b7 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -3604,7 +3604,7 @@ static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* FOREACH(pProjection, pProjectNode->pProjections) { FOREACH(pChildTarget, pChild->pTargets) { if (0 == strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName) - && ((SColumnNode*)pProjection)->node.bindTupleFuncIdx == 0) { + && ((SColumnNode*)pProjection)->node.tupleFuncIdx == 0) { SNode* pNew = NULL; code = nodesCloneNode(pChildTarget, &pNew); if (TSDB_CODE_SUCCESS == code) { diff --git a/tests/system-test/2-query/cols_function.py b/tests/system-test/2-query/cols_function.py index f049f52480..a9b0d7349e 100644 --- a/tests/system-test/2-query/cols_function.py +++ b/tests/system-test/2-query/cols_function.py @@ -26,12 +26,14 @@ class TDTestCase: tdSql.execute(f'create table {self.dbname}.meters (ts timestamp, c0 int, c1 float, c2 nchar(30), c3 bool) tags (t1 nchar(30))') tdSql.execute(f'create table {self.dbname}.d0 using {self.dbname}.meters tags("st1")') - tdSql.execute(f'create table {self.dbname}.d1 using {self.dbname}.meters tags("st1")') + tdSql.execute(f'create table {self.dbname}.d1 using {self.dbname}.meters tags("st2")') tdSql.execute(f'insert into {self.dbname}.d0 values(1734574929000, 1, 1, "a1", true)') tdSql.execute(f'insert into {self.dbname}.d0 values(1734574929001, 2, 2, "bbbbbbbbb1", false)') tdSql.execute(f'insert into {self.dbname}.d0 values(1734574929002, 3, 3, "a2", true)') tdSql.execute(f'insert into {self.dbname}.d0 values(1734574929003, 4, 4, "bbbbbbbbb2", false)') + tdSql.execute(f'insert into {self.dbname}.d1 values(1734574929000, 1, 1, "a1", true)') + tdSql.execute(f'use {self.dbname}') tdSql.execute(f'Create table {self.dbname}.normal_table (ts timestamp, c0 int, c1 float, c2 nchar(30), c3 bool)') tdSql.execute(f'insert into {self.dbname}.normal_table (select * from {self.dbname}.d0)') @@ -53,16 +55,173 @@ class TDTestCase: def one_cols_multi_output_test(self): tdLog.info("one_cols_1output_test") tdSql.query(f'select cols(last(ts), ts, c0) from {self.dbname}.meters') - tdSql.query(f'select cols(last(ts), ts, c0) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(2) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) tdSql.query(f'select cols(last(ts), ts as time, c0 cc) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(2) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) tdSql.query(f'select cols(last(ts), c0, c1, c2, c3) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(4) + tdSql.checkData(0, 0, 4) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 'bbbbbbbbb2') + tdSql.checkData(0, 3, False) + tdSql.query(f'select cols(last(ts), c0, t1) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 4) + tdSql.checkData(0, 1, 'st1') tdSql.query(f'select cols(last(c1), ts) from {self.dbname}.meters group by tbname') - - + tdSql.checkRows(2) + tdSql.checkCols(1) + tdSql.query(f'select cols(last(c1), ts) from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkCols(1) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(1, 0, 1734574929000) + tdSql.query(f'select cols(last(c1), ts) from {self.dbname}.meters group by tbname order by ts') + tdSql.checkCols(1) + tdSql.checkData(0, 0, 1734574929000) + tdSql.checkData(1, 0, 1734574929003) + tdSql.query(f'select cols(last(c1), ts), tbname from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkCols(2) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 'd0') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 'd1') + tdSql.query(f'select cols(last(c1), ts), tbname, t1 from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 'd0') + tdSql.checkData(0, 2, 'st1') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 'd1') + tdSql.checkData(1, 2, 'st2') + tdSql.query(f'select cols(last(c1), ts), tbname, t1 from {self.dbname}.meters group by tbname order by t1') + tdSql.checkRows(2) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 'd0') + tdSql.checkData(0, 2, 'st1') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 'd1') + tdSql.checkData(1, 2, 'st2') tdSql.query(f'select cols(max(c0), ts) from {self.dbname}.meters') + tdSql.checkCols(1) + tdSql.checkData(0, 0, 1734574929003) tdSql.query(f'select cols(min(c1), ts, c0) from {self.dbname}.meters') + tdSql.checkCols(2) + tdSql.checkData(0, 0, 1734574929000) + tdSql.checkData(0, 1, 1) + tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 1) + tdSql.checkData(1, 2, 1) + tdSql.query(f'select cols(last(ts), ts, c0), count(1), tbname from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkCols(4) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + tdSql.checkData(0, 3, 'd0') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 1) + tdSql.checkData(1, 2, 1) + tdSql.checkData(1, 3, 'd1') + tdSql.query(f'select cols(last(ts), ts, c0), count(1), tbname, t1 from {self.dbname}.meters group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkCols(5) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + tdSql.checkData(0, 3, 'd0') + tdSql.checkData(0, 4, 'st1') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 1) + tdSql.checkData(1, 2, 1) + tdSql.checkData(1, 3, 'd1') + tdSql.checkData(1, 4, 'st2') + tdSql.query(f'select cols(last(ts), ts, c0), count(1), t1 from {self.dbname}.meters group by t1 order by t1') + tdSql.checkRows(2) + tdSql.checkCols(4) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + tdSql.checkData(0, 3, 'st1') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 1) + tdSql.checkData(1, 2, 1) + tdSql.checkData(1, 3, 'st2') + tdSql.error(f'select cols(last(ts), ts, c0), count(1), t1 from {self.dbname}.meters group by t1 order by tbname') + tdSql.query(f'select cols(last(ts), ts, c0), sum(c0), t1 from {self.dbname}.meters group by t1 order by t1') + tdSql.checkRows(2) + tdSql.checkCols(4) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 10) + tdSql.checkData(0, 3, 'st1') + tdSql.checkData(1, 0, 1734574929000) + tdSql.checkData(1, 1, 1) + tdSql.checkData(1, 2, 1) + tdSql.checkData(1, 3, 'st2') + + tdSql.query(f'select cols(max(c0), ts, c0), count(1) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 5) + tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.d0') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.d1') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929000) + tdSql.checkData(0, 1, 1) + tdSql.checkData(0, 2, 1) + tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.normal_table') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 4) + + tdSql.query(f'select cols(last(ts), ts, c0), avg(c0) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 2.2) tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 5) + + tdSql.query(f'select cols(last(ts), ts, c0), sum(c0) from {self.dbname}.meters') + tdSql.checkRows(1) + tdSql.checkCols(3) + tdSql.checkData(0, 0, 1734574929003) + tdSql.checkData(0, 1, 4) + tdSql.checkData(0, 2, 11) + + tdSql.query(f'select count(1), cols(last(ts), ts, c0), min(c0) from {self.dbname}.meters') tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.meters') tdSql.query(f'select cols(last(ts), ts as time, c0 cc), count(1) from {self.dbname}.meters') @@ -207,7 +366,14 @@ class TDTestCase: tdSql.checkData(0, 2, 1734574929000) tdSql.checkData(0, 3, 6) + def subquery_test(self): + tdSql.query(f'select count(1), cols(last(c0),c0) from (select * from test.d0)') + tdSql.query(f'select count(1), cols(last(c0),c0) from (select *, tbname from test.meters) group by tbname') + def window_test(self): + tdSql.query(f'select tbname, _wstart,_wend, max(c0), max(c1), cols( max(c0), c1) from test.meters partition \ + by tbname count_window(2) order by tbname') + def parse_test(self): tdLog.info("parse test") @@ -250,6 +416,7 @@ class TDTestCase: self.one_cols_1output_test() self.one_cols_multi_output_test() self.multi_cols_output_test() + self.subquery_test() def stop(self):