diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h index 25ff18a8fc1a5b6f35e82c2323ed6a4023285d76..c57e9718b26d428f986f48f6945c687a0286acac 100644 --- a/include/libs/nodes/plannodes.h +++ b/include/libs/nodes/plannodes.h @@ -99,6 +99,7 @@ typedef struct SScanLogicNode { int8_t cacheLastMode; bool hasNormalCols; // neither tag column nor primary key tag column bool sortPrimaryKey; + bool igLastNull; } SScanLogicNode; typedef struct SJoinLogicNode { @@ -115,6 +116,7 @@ typedef struct SAggLogicNode { SNodeList* pGroupKeys; SNodeList* pAggFuncs; bool hasLastRow; + bool hasLast; bool hasTimeLineFunc; bool onlyHasKeepOrderFunc; } SAggLogicNode; @@ -317,6 +319,7 @@ typedef struct SLastRowScanPhysiNode { SScanPhysiNode scan; SNodeList* pGroupTags; bool groupSort; + bool ignoreNull; } SLastRowScanPhysiNode; typedef struct SSystemTableScanPhysiNode { diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index e1acf0dd6ac74954c3be320e9792b7a78206a4bf..8d85c139df03853c3fa70b6d860f6821b364fe1f 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -291,6 +291,7 @@ typedef struct SSelectStmt { bool hasTailFunc; bool hasInterpFunc; bool hasLastRowFunc; + bool hasLastFunc; bool hasTimeLineFunc; bool hasUdaf; bool hasStateKey; diff --git a/source/libs/nodes/src/nodesCloneFuncs.c b/source/libs/nodes/src/nodesCloneFuncs.c index 7cad5df3a19339aab6fb96ec9fef5fdc6fb05f46..dac9b857404d202ec56e9d2e7b57c954d1a3c143 100644 --- a/source/libs/nodes/src/nodesCloneFuncs.c +++ b/source/libs/nodes/src/nodesCloneFuncs.c @@ -383,6 +383,7 @@ static int32_t logicScanCopy(const SScanLogicNode* pSrc, SScanLogicNode* pDst) { COPY_SCALAR_FIELD(groupSort); CLONE_NODE_LIST_FIELD(pTags); CLONE_NODE_FIELD(pSubtable); + COPY_SCALAR_FIELD(igLastNull); return TSDB_CODE_SUCCESS; } diff --git a/source/libs/parser/src/parAstParser.c b/source/libs/parser/src/parAstParser.c index b2f31d88d8830c23fac637fd7f3321c1cd9429c2..64aa017a68f7cfb04d0b69c5b526ebeea179b251 100644 --- a/source/libs/parser/src/parAstParser.c +++ b/source/libs/parser/src/parAstParser.c @@ -97,7 +97,7 @@ typedef struct SCollectMetaKeyCxt { typedef struct SCollectMetaKeyFromExprCxt { SCollectMetaKeyCxt* pComCxt; - bool hasLastRow; + bool hasLastRowOrLast; int32_t errCode; } SCollectMetaKeyFromExprCxt; @@ -106,7 +106,8 @@ static int32_t collectMetaKeyFromQuery(SCollectMetaKeyCxt* pCxt, SNode* pStmt); static EDealRes collectMetaKeyFromFunction(SCollectMetaKeyFromExprCxt* pCxt, SFunctionNode* pFunc) { switch (fmGetFuncType(pFunc->functionName)) { case FUNCTION_TYPE_LAST_ROW: - pCxt->hasLastRow = true; + case FUNCTION_TYPE_LAST: + pCxt->hasLastRowOrLast = true; break; case FUNCTION_TYPE_UDF: pCxt->errCode = reserveUdfInCache(pFunc->functionName, pCxt->pComCxt->pMetaCache); @@ -221,9 +222,9 @@ static int32_t reserveDbCfgForLastRow(SCollectMetaKeyCxt* pCxt, SNode* pTable) { } static int32_t collectMetaKeyFromSelect(SCollectMetaKeyCxt* pCxt, SSelectStmt* pStmt) { - SCollectMetaKeyFromExprCxt cxt = {.pComCxt = pCxt, .hasLastRow = false, .errCode = TSDB_CODE_SUCCESS}; + SCollectMetaKeyFromExprCxt cxt = {.pComCxt = pCxt, .hasLastRowOrLast = false, .errCode = TSDB_CODE_SUCCESS}; nodesWalkSelectStmt(pStmt, SQL_CLAUSE_FROM, collectMetaKeyFromExprImpl, &cxt); - if (TSDB_CODE_SUCCESS == cxt.errCode && cxt.hasLastRow) { + if (TSDB_CODE_SUCCESS == cxt.errCode && cxt.hasLastRowOrLast) { cxt.errCode = reserveDbCfgForLastRow(pCxt, pStmt->pFromTable); } return cxt.errCode; diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 1445962d74b3138a83d5aa77c03cf22d8af36289..77047568b6ace502e0d3aa8cd581112350198903 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -1609,6 +1609,7 @@ static void setFuncClassification(SNode* pCurrStmt, SFunctionNode* pFunc) { pSelect->hasTailFunc = pSelect->hasTailFunc ? true : (FUNCTION_TYPE_TAIL == pFunc->funcType); pSelect->hasInterpFunc = pSelect->hasInterpFunc ? true : (FUNCTION_TYPE_INTERP == pFunc->funcType); pSelect->hasLastRowFunc = pSelect->hasLastRowFunc ? true : (FUNCTION_TYPE_LAST_ROW == pFunc->funcType); + pSelect->hasLastFunc = pSelect->hasLastFunc ? true : (FUNCTION_TYPE_LAST == pFunc->funcType); pSelect->hasTimeLineFunc = pSelect->hasTimeLineFunc ? true : fmIsTimelineFunc(pFunc->funcId); pSelect->hasUdaf = pSelect->hasUdaf ? true : fmIsUserDefinedFunc(pFunc->funcId) && fmIsAggFunc(pFunc->funcId); pSelect->onlyHasKeepOrderFunc = pSelect->onlyHasKeepOrderFunc ? fmIsKeepOrderFunc(pFunc->funcId) : false; @@ -2349,7 +2350,7 @@ static int32_t setTableIndex(STranslateContext* pCxt, SName* pName, SRealTableNo } static int32_t setTableCacheLastMode(STranslateContext* pCxt, SSelectStmt* pSelect) { - if (!pSelect->hasLastRowFunc || QUERY_NODE_REAL_TABLE != nodeType(pSelect->pFromTable)) { + if ((!pSelect->hasLastRowFunc && !pSelect->hasLastFunc) || QUERY_NODE_REAL_TABLE != nodeType(pSelect->pFromTable)) { return TSDB_CODE_SUCCESS; } diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index 8c87f60b9f1e874d09e1e975a81d58c4fdbf04c9..e6868f0cebfb5de7bf7321822c5928a6f67cdac7 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -514,6 +514,7 @@ static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, } pAgg->hasLastRow = pSelect->hasLastRowFunc; + pAgg->hasLast = pSelect->hasLastFunc; pAgg->hasTimeLineFunc = pSelect->hasTimeLineFunc; pAgg->onlyHasKeepOrderFunc = pSelect->onlyHasKeepOrderFunc; pAgg->node.groupAction = getGroupAction(pCxt, pSelect); diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index e6d349962ebf141acaa3a4d9057493fff20433ba..50f1f4b3691d4cdf474a9ecad3ac445e0e0a6af9 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -124,8 +124,9 @@ static void optSetParentOrder(SLogicNode* pNode, EOrder order) { EDealRes scanPathOptHaveNormalColImpl(SNode* pNode, void* pContext) { if (QUERY_NODE_COLUMN == nodeType(pNode)) { - *((bool*)pContext) = - (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType); + // *((bool*)pContext) = + // (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType); + *((bool*)pContext) = true; return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD; } return DEAL_RES_CONTINUE; @@ -2195,14 +2196,16 @@ static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode) { SAggLogicNode* pAgg = (SAggLogicNode*)pNode; SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0); - if (!pAgg->hasLastRow || NULL != pAgg->pGroupKeys || NULL != pScan->node.pConditions || 0 == pScan->cacheLastMode || - IS_TSWINDOW_SPECIFIED(pScan->scanRange)) { + // Only one of LAST and LASTROW can appear + if (pAgg->hasLastRow == pAgg->hasLast || NULL != pAgg->pGroupKeys || NULL != pScan->node.pConditions || + 0 == pScan->cacheLastMode || IS_TSWINDOW_SPECIFIED(pScan->scanRange)) { return false; } SNode* pFunc = NULL; FOREACH(pFunc, ((SAggLogicNode*)pNode)->pAggFuncs) { if (FUNCTION_TYPE_LAST_ROW != ((SFunctionNode*)pFunc)->funcType && + // FUNCTION_TYPE_LAST != ((SFunctionNode*)pFunc)->funcType && FUNCTION_TYPE_SELECT_VALUE != ((SFunctionNode*)pFunc)->funcType && FUNCTION_TYPE_GROUP_KEY != ((SFunctionNode*)pFunc)->funcType) { return false; @@ -2222,7 +2225,7 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic SNode* pNode = NULL; FOREACH(pNode, pAgg->pAggFuncs) { SFunctionNode* pFunc = (SFunctionNode*)pNode; - if (FUNCTION_TYPE_LAST_ROW == pFunc->funcType) { + if (FUNCTION_TYPE_LAST_ROW == pFunc->funcType || FUNCTION_TYPE_LAST == pFunc->funcType) { int32_t len = snprintf(pFunc->functionName, sizeof(pFunc->functionName), "_cache_last_row"); pFunc->functionName[len] = '\0'; int32_t code = fmGetFuncInfo(pFunc, NULL, 0); @@ -2231,9 +2234,12 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic } } } - pAgg->hasLastRow = false; - ((SScanLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0))->scanType = SCAN_TYPE_LAST_ROW; + SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0); + pScan->scanType = SCAN_TYPE_LAST_ROW; + pScan->igLastNull = pAgg->hasLast ? true : false; + pAgg->hasLastRow = false; + pAgg->hasLast = false; pCxt->optimized = true; return TSDB_CODE_SUCCESS; @@ -2405,8 +2411,8 @@ static const SOptimizeRule optimizeRuleSet[] = { {.pName = "EliminateSetOperator", .optimizeFunc = eliminateSetOpOptimize}, {.pName = "RewriteTail", .optimizeFunc = rewriteTailOptimize}, {.pName = "RewriteUnique", .optimizeFunc = rewriteUniqueOptimize}, - {.pName = "LastRowScan", .optimizeFunc = lastRowScanOptimize}, - {.pName = "TagScan", .optimizeFunc = tagScanOptimize} + {.pName = "LastRowScan", .optimizeFunc = lastRowScanOptimize}, + {.pName = "TagScan", .optimizeFunc = tagScanOptimize} }; // clang-format on diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index 810b82b9fc21d2c311266f36575297f9543797b7..2935c647aa571f7d29445c3f3cded18fae58eebb 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -521,6 +521,7 @@ static int32_t createLastRowScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSu } pScan->groupSort = pScanLogicNode->groupSort; + pScan->ignoreNull = pScanLogicNode->igLastNull; vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode);