From 8ef6b184f2a41b0ba5d6708a8854c34a2a68ef1d Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Fri, 8 Apr 2022 19:44:15 +0800 Subject: [PATCH] first(*)/last(*) rewrite --- include/libs/nodes/nodes.h | 16 +++- source/libs/nodes/src/nodesUtilFuncs.c | 45 ++++++++- source/libs/parser/src/parTranslater.c | 124 ++++++++++++++++++++----- 3 files changed, 157 insertions(+), 28 deletions(-) diff --git a/include/libs/nodes/nodes.h b/include/libs/nodes/nodes.h index 28e5483552..39448ceef3 100644 --- a/include/libs/nodes/nodes.h +++ b/include/libs/nodes/nodes.h @@ -30,11 +30,19 @@ extern "C" { #define FOREACH(node, list) \ for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)); cell = cell->pNext) -// only be use in FOREACH -#define ERASE_NODE(list) cell = nodesListErase(list, cell); - #define REPLACE_NODE(newNode) cell->pNode = (SNode*)(newNode) +#define INSERT_LIST(target, src) nodesListInsertList((target), cell, src) + +#define WHERE_EACH(node, list) \ + SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \ + while (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)) + +#define WHERE_NEXT cell = cell->pNext + +// only be use in WHERE_EACH +#define ERASE_NODE(list) cell = nodesListErase((list), cell) + #define FORBOTH(node1, list1, node2, list2) \ for (SListCell* cell1 = (NULL != (list1) ? (list1)->pHead : NULL), *cell2 = (NULL != (list2) ? (list2)->pHead : NULL); \ (NULL == cell1 ? (node1 = NULL, false) : (node1 = cell1->pNode, true)), (NULL == cell2 ? (node2 = NULL, false) : (node2 = cell2->pNode, true)), (node1 != NULL && node2 != NULL); \ @@ -202,7 +210,9 @@ int32_t nodesListStrictAppend(SNodeList* pList, SNodeptr pNode); int32_t nodesListMakeAppend(SNodeList** pList, SNodeptr pNode); int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc); int32_t nodesListStrictAppendList(SNodeList* pTarget, SNodeList* pSrc); +int32_t nodesListPushFront(SNodeList* pList, SNodeptr pNode); SListCell* nodesListErase(SNodeList* pList, SListCell* pCell); +void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* pSrc); SNodeptr nodesListGetNode(SNodeList* pList, int32_t index); void nodesDestroyList(SNodeList* pList); // Only clear the linked list structure, without releasing the elements inside diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 95a3280fc2..074ec4dcae 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -644,7 +644,7 @@ SNodeList* nodesMakeList() { int32_t nodesListAppend(SNodeList* pList, SNodeptr pNode) { if (NULL == pList || NULL == pNode) { - return TSDB_CODE_SUCCESS; + return TSDB_CODE_FAILED; } SListCell* p = taosMemoryCalloc(1, sizeof(SListCell)); if (NULL == p) { @@ -688,7 +688,7 @@ int32_t nodesListMakeAppend(SNodeList** pList, SNodeptr pNode) { int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc) { if (NULL == pTarget || NULL == pSrc) { - return TSDB_CODE_SUCCESS; + return TSDB_CODE_FAILED; } if (NULL == pTarget->pHead) { @@ -717,11 +717,34 @@ int32_t nodesListStrictAppendList(SNodeList* pTarget, SNodeList* pSrc) { return code; } +int32_t nodesListPushFront(SNodeList* pList, SNodeptr pNode) { + if (NULL == pList || NULL == pNode) { + return TSDB_CODE_FAILED; + } + SListCell* p = taosMemoryCalloc(1, sizeof(SListCell)); + if (NULL == p) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + return TSDB_CODE_OUT_OF_MEMORY; + } + p->pNode = pNode; + if (NULL != pList->pHead) { + pList->pHead->pPrev = p; + p->pNext = pList->pHead; + } + pList->pHead = p; + ++(pList->length); + return TSDB_CODE_SUCCESS; +} + SListCell* nodesListErase(SNodeList* pList, SListCell* pCell) { if (NULL == pCell->pPrev) { pList->pHead = pCell->pNext; } else { pCell->pPrev->pNext = pCell->pNext; + } + if (NULL == pCell->pNext) { + pList->pTail = pCell->pPrev; + } else { pCell->pNext->pPrev = pCell->pPrev; } SListCell* pNext = pCell->pNext; @@ -731,6 +754,24 @@ SListCell* nodesListErase(SNodeList* pList, SListCell* pCell) { return pNext; } +void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* pSrc) { + if (NULL == pTarget || NULL == pPos || NULL == pSrc) { + return; + } + + if (NULL == pPos->pPrev) { + pTarget->pHead = pSrc->pHead; + } else { + pPos->pPrev->pNext = pSrc->pHead; + } + pSrc->pHead->pPrev = pPos->pPrev; + pSrc->pTail->pNext = pPos; + pPos->pPrev = pSrc->pTail; + + pTarget->length += pSrc->length; + taosMemoryFreeClear(pSrc); +} + SNodeptr nodesListGetNode(SNodeList* pList, int32_t index) { SNode* node; FOREACH(node, pList) { diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 88c3d5b549..cad6de719e 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -743,24 +743,99 @@ static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) { return code; } -static int32_t translateStar(STranslateContext* pCxt, SSelectStmt* pSelect, bool* pIsSelectStar) { - if (NULL == pSelect->pProjectionList) { // select * ... - SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel); - size_t nums = taosArrayGetSize(pTables); - pSelect->pProjectionList = nodesMakeList(); - if (NULL == pSelect->pProjectionList) { - return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_OUT_OF_MEMORY); - } - for (size_t i = 0; i < nums; ++i) { - STableNode* pTable = taosArrayGetP(pTables, i); - int32_t code = createColumnNodeByTable(pCxt, pTable, pSelect->pProjectionList); - if (TSDB_CODE_SUCCESS != code) { - return code; - } +static int32_t createAllColumns(STranslateContext* pCxt, SNodeList** pCols) { + *pCols = nodesMakeList(); + if (NULL == *pCols) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_OUT_OF_MEMORY); + } + SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel); + size_t nums = taosArrayGetSize(pTables); + for (size_t i = 0; i < nums; ++i) { + STableNode* pTable = taosArrayGetP(pTables, i); + int32_t code = createColumnNodeByTable(pCxt, pTable, *pCols); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + return TSDB_CODE_SUCCESS; +} + +static bool isFirstLastFunc(SFunctionNode* pFunc) { + return (FUNCTION_TYPE_FIRST == pFunc->funcType || FUNCTION_TYPE_LAST == pFunc->funcType); +} + +static bool isFirstLastStar(SNode* pNode) { + if (QUERY_NODE_FUNCTION != nodeType(pNode) || !isFirstLastFunc((SFunctionNode*)pNode)) { + return false; + } + SNodeList* pParameterList = ((SFunctionNode*)pNode)->pParameterList; + if (LIST_LENGTH(pParameterList) != 1) { + return false; + } + SNode* pParam = nodesListGetNode(pParameterList, 0); + return (QUERY_NODE_COLUMN == nodeType(pParam) ? 0 == strcmp(((SColumnNode*)pParam)->colName, "*") : false); +} + +static SNode* createFirstLastFunc(SFunctionNode* pSrcFunc, SColumnNode* pCol) { + SFunctionNode* pFunc = nodesMakeNode(QUERY_NODE_FUNCTION); + if (NULL == pFunc) { + return NULL; + } + pFunc->pParameterList = nodesMakeList(); + if (NULL == pFunc->pParameterList || TSDB_CODE_SUCCESS != nodesListAppend(pFunc->pParameterList, pCol)) { + nodesDestroyNode(pFunc); + return NULL; + } + + pFunc->node.resType = pCol->node.resType; + pFunc->funcId = pSrcFunc->funcId; + pFunc->funcType = pSrcFunc->funcType; + strcpy(pFunc->functionName, pSrcFunc->functionName); + snprintf(pFunc->node.aliasName, sizeof(pFunc->node.aliasName), (FUNCTION_TYPE_FIRST == pSrcFunc->funcType ? "first(%s)" : "last(%s)"), pCol->colName); + + return (SNode*)pFunc; +} + +static int32_t createFirstLastAllCols(STranslateContext* pCxt, SFunctionNode* pSrcFunc, SNodeList** pOutput) { + SNodeList* pCols = NULL; + if (TSDB_CODE_SUCCESS != createAllColumns(pCxt, &pCols)) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + SNodeList* pFuncs = nodesMakeList(); + if (NULL == pFuncs) { + return TSDB_CODE_OUT_OF_MEMORY; + } + SNode* pCol = NULL; + FOREACH(pCol, pCols) { + if (TSDB_CODE_SUCCESS != nodesListStrictAppend(pFuncs, createFirstLastFunc(pSrcFunc, (SColumnNode*)pCol))) { + nodesDestroyNode(pFuncs); + return TSDB_CODE_OUT_OF_MEMORY; } - *pIsSelectStar = true; + } + + *pOutput = pFuncs; + return TSDB_CODE_SUCCESS; +} + +static int32_t translateStar(STranslateContext* pCxt, SSelectStmt* pSelect) { + if (NULL == pSelect->pProjectionList) { // select * ... + return createAllColumns(pCxt, &pSelect->pProjectionList); } else { // todo : t.* + SNode* pNode = NULL; + WHERE_EACH(pNode, pSelect->pProjectionList) { + if (isFirstLastStar(pNode)) { + SNodeList* pFuncs = NULL; + if (TSDB_CODE_SUCCESS != createFirstLastAllCols(pCxt, (SFunctionNode*)pNode, &pFuncs)) { + return TSDB_CODE_OUT_OF_MEMORY; + } + INSERT_LIST(pSelect->pProjectionList, pFuncs); + ERASE_NODE(pSelect->pProjectionList); + continue; + } + WHERE_NEXT; + } } return TSDB_CODE_SUCCESS; } @@ -797,8 +872,8 @@ static int32_t getPositionValue(const SValueNode* pVal) { static int32_t translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjectionList, SNodeList* pOrderByList, bool* pOther) { *pOther = false; - SNode* pNode; - FOREACH(pNode, pOrderByList) { + SNode* pNode = NULL; + WHERE_EACH(pNode, pOrderByList) { SNode* pExpr = ((SOrderByExprNode*)pNode)->pExpr; if (QUERY_NODE_VALUE == nodeType(pExpr)) { SValueNode* pVal = (SValueNode*)pExpr; @@ -823,6 +898,7 @@ static int32_t translateOrderByPosition(STranslateContext* pCxt, SNodeList* pPro } else { *pOther = true; } + WHERE_NEXT; } return TSDB_CODE_SUCCESS; } @@ -845,11 +921,10 @@ static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) { } static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect) { - bool isSelectStar = false; - int32_t code = translateStar(pCxt, pSelect, &isSelectStar); - if (TSDB_CODE_SUCCESS == code && !isSelectStar) { - pCxt->currClause = SQL_CLAUSE_SELECT; - code = translateExprList(pCxt, pSelect->pProjectionList); + pCxt->currClause = SQL_CLAUSE_SELECT; + int32_t code = translateExprList(pCxt, pSelect->pProjectionList); + if (TSDB_CODE_SUCCESS == code) { + code = translateStar(pCxt, pSelect); } if (TSDB_CODE_SUCCESS == code) { code = checkExprListForGroupBy(pCxt, pSelect->pProjectionList); @@ -1829,10 +1904,13 @@ static int32_t getSmaIndexBuildAst(STranslateContext* pCxt, SCreateIndexStmt* pS pSelect->pFromTable = (SNode*)pTable; pSelect->pProjectionList = nodesCloneList(pStmt->pOptions->pFuncs); - if (NULL == pTable) { + SFunctionNode* pFunc = nodesMakeNode(QUERY_NODE_FUNCTION); + if (NULL == pSelect->pProjectionList || NULL == pFunc) { nodesDestroyNode(pSelect); return TSDB_CODE_OUT_OF_MEMORY; } + strcpy(pFunc->functionName, "_wstartts"); + nodesListPushFront(pSelect->pProjectionList, pFunc); SNode* pProject = NULL; FOREACH(pProject, pSelect->pProjectionList) { sprintf(((SExprNode*)pProject)->aliasName, "#sma_%p", pProject); -- GitLab