From e16b96db723ff5b1c4564ce271c56b8cd60dd168 Mon Sep 17 00:00:00 2001 From: facetosea <285808407@qq.com> Date: Thu, 13 Feb 2025 03:21:27 +0000 Subject: [PATCH] enh: translate cols in clauses --- docs/en/14-reference/09-error-code.md | 2 +- docs/zh/14-reference/09-error-code.md | 2 +- source/libs/parser/src/parTranslater.c | 124 +++++++++++++++++-------- 3 files changed, 85 insertions(+), 43 deletions(-) diff --git a/docs/en/14-reference/09-error-code.md b/docs/en/14-reference/09-error-code.md index c35df8ebc0..857f84da34 100644 --- a/docs/en/14-reference/09-error-code.md +++ b/docs/en/14-reference/09-error-code.md @@ -461,7 +461,7 @@ This document details the server error codes that may be encountered when using | 0x80002687 | Invalid using cols function | Illegal using cols function | Check and correct the SQL statement | | 0x80002688 | Cols function's first param must be a select function | The first parameter of the cols function should be a selection function | Check and correct the SQL statement | | 0x80002689 | Invalid using cols function with multiple output columns | Illegal using the cols function for multiple column output | Check and correct the SQL statement | -| 0x80002690 | Invalid using alias for cols function | Illegal cols function alias | Check and correct the SQL statement | +| 0x8000268A | Invalid using alias for cols function | Illegal cols function alias | Check and correct the SQL statement | | 0x800026FF | Parser internal error | Internal error in parser | Preserve the scene and logs, report issue on GitHub | | 0x80002700 | Planner internal error | Internal error in planner | Preserve the scene and logs, report issue on GitHub | | 0x80002701 | Expect ts equal | JOIN condition validation failed | Preserve the scene and logs, report issue on GitHub | diff --git a/docs/zh/14-reference/09-error-code.md b/docs/zh/14-reference/09-error-code.md index a1a3fa050d..74fe39421d 100644 --- a/docs/zh/14-reference/09-error-code.md +++ b/docs/zh/14-reference/09-error-code.md @@ -478,7 +478,7 @@ description: TDengine 服务端的错误码列表和详细说明 | 0x80002687 | Invalid using cols function | cols函数使用错误 | 检查并修正SQL语句 | | 0x80002688 | Cols function's first param must be a select function | cols函数第一个参数应该为选择函数 | 检查并修正SQL语句 | | 0x80002689 | Invalid using cols function with multiple output columns | 多列输出的 cols 函数使用错误 | 检查并修正SQL语句 | -| 0x80002690 | Invalid using alias for cols function | cols 函数输出列重命名错误 | 检查并修正SQL语句 | +| 0x8000268A | Invalid using alias for cols function | cols 函数输出列重命名错误 | 检查并修正SQL语句 | | 0x800026FF | Parser internal error | 解析器内部错误 | 保留现场和日志,github上报issue | | 0x80002700 | Planner internal error | 计划期内部错误 | 保留现场和日志,github上报issue | | 0x80002701 | Expect ts equal | JOIN条件校验失败 | 保留现场和日志,github上报issue | diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 3fedf49ac9..7ab0261458 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -5460,9 +5460,83 @@ static int32_t translateClausePosition(STranslateContext* pCxt, SNodeList* pProj return TSDB_CODE_SUCCESS; } +static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList, SNodeList** selectFuncList); +static int32_t translateSelectColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) { + SNodeList* selectFuncList = NULL; + int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &selectFuncList); + if (TSDB_CODE_SUCCESS != code) { + goto _end; + } + if (selectFuncList != NULL) { + code = nodesListAppendList(pSelect->pProjectionList, selectFuncList); + if (TSDB_CODE_SUCCESS != code) { + goto _end; + } + selectFuncList = NULL; + } +_end: + if (selectFuncList) { + nodesDestroyList(selectFuncList); + } + return code; +} + +static int32_t getBindedExprList(STranslateContext* pCxt, SNodeList* projectionList, SNodeList** selectFuncList) { + int32_t code = TSDB_CODE_SUCCESS; + for (int32_t i = 0; i < LIST_LENGTH(projectionList); ++i) { + SNode* pNode = nodesListGetNode(projectionList, i); + if (((SExprNode*)pNode)->bindTupleFuncIdx > 0) { + if (NULL == *selectFuncList) { + code = nodesMakeList(selectFuncList); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + code = nodesListStrictAppend(*selectFuncList, pNode); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + } + return code; +} + +static int32_t translateOrderbyColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) { + SNodeList* selectFuncList = NULL; + int32_t code = getBindedExprList(pCxt, pSelect->pProjectionList, &selectFuncList); + if (TSDB_CODE_SUCCESS != code) { + goto _end; + } + int len = LIST_LENGTH(selectFuncList); + code = rewriteColsFunction(pCxt, &pSelect->pOrderByList, &selectFuncList); + if (TSDB_CODE_SUCCESS != code) { + goto _end; + } + if(LIST_LENGTH(selectFuncList) - len > 0) { + for (int i = len; i < LIST_LENGTH(selectFuncList); ++i) { + SNode* pNode = nodesListGetNode(selectFuncList, i); + int32_t code = nodesListStrictAppend(pSelect->pProjectionList, pNode); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + } + nodesClearList(selectFuncList); + return code; +_end: + if (selectFuncList) { + nodesDestroyList(selectFuncList); + } + return code; +} + static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) { bool other; - int32_t code = translateClausePosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other); + int32_t code = translateOrderbyColsFunction(pCxt, pSelect); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + code = translateClausePosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other); if (TSDB_CODE_SUCCESS == code) { if (0 == LIST_LENGTH(pSelect->pOrderByList)) { NODES_DESTORY_LIST(pSelect->pOrderByList); @@ -5681,7 +5755,11 @@ static int32_t translatePartitionByList(STranslateContext* pCxt, SSelectStmt* pS static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect) { pCxt->currClause = SQL_CLAUSE_SELECT; - int32_t code = translateExprList(pCxt, pSelect->pProjectionList); + int32_t code = translateSelectColsFunction(pCxt, pSelect); + code = translateOrderbyColsFunction(pCxt, pSelect); + if (TSDB_CODE_SUCCESS == code) { + code = translateExprList(pCxt, pSelect->pProjectionList); + } if (TSDB_CODE_SUCCESS == code) { code = translateStar(pCxt, pSelect); } @@ -7432,7 +7510,7 @@ static int32_t checkMultColsFuncParam(SNodeList* pParameterList) { SNode* pNode = NULL; FOREACH(pNode, pParameterList) { if (index == 0) { // the first parameter is select function - if (QUERY_NODE_FUNCTION != nodeType(pNode)) { + if (QUERY_NODE_FUNCTION != nodeType(pNode) || isColsFuncByName((SFunctionNode*)pNode)) { return TSDB_CODE_PAR_INVALID_COLS_FUNCTION; } SFunctionNode* pFunc = (SFunctionNode*)pNode; @@ -7474,7 +7552,7 @@ static EDealRes rewriteSingleColsFunc(SNode** pNode, void* pContext) { } SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0); SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 1); - if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION) { + if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION || isColsFuncByName((SFunctionNode*)pSelectFunc)) { pCxt->status = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC; parserError("%s Invalid cols function, the first parameter must be a select function", __func__); return DEAL_RES_ERROR; @@ -7625,46 +7703,10 @@ static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList return code; } -static int32_t translateColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) { - if (pSelect->pFromTable && QUERY_NODE_TEMP_TABLE == nodeType(pSelect->pFromTable)) { - SNode* pSubquery = ((STempTableNode*)pSelect->pFromTable)->pSubquery; - if (QUERY_NODE_SELECT_STMT == nodeType(pSubquery)) { - SSelectStmt* pSubSelect = (SSelectStmt*)pSubquery; - int32_t code = translateColsFunction(pCxt, pSubSelect); - if (TSDB_CODE_SUCCESS != code) { - return code; - } - } - } - SNodeList* selectFuncList = NULL; - int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &selectFuncList); - if (code == TSDB_CODE_SUCCESS) { - code = rewriteColsFunction(pCxt, &pSelect->pOrderByList, &selectFuncList); - } - if (TSDB_CODE_SUCCESS != code) { - goto _end; - } - - if (selectFuncList != NULL) { - nodesListAppendList(pSelect->pProjectionList, selectFuncList); - selectFuncList = NULL; - } - -_end: - if (selectFuncList) { - nodesDestroyList(selectFuncList); - } - - return code; -} - static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) { pCxt->pCurrStmt = (SNode*)pSelect; pCxt->dual = false; - int32_t code = translateColsFunction(pCxt, pSelect); - if (TSDB_CODE_SUCCESS == code) { - code = translateFrom(pCxt, &pSelect->pFromTable); - } + int32_t code = translateFrom(pCxt, &pSelect->pFromTable); if (TSDB_CODE_SUCCESS == code) { pSelect->precision = ((STableNode*)pSelect->pFromTable)->precision; code = translateWhere(pCxt, pSelect);