From 2fb4acaaf6b39520a07dda7af4d0defed7963015 Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Wed, 9 Feb 2022 14:34:46 -0500 Subject: [PATCH] TD-13338 SELECT statement translate code --- include/util/taoserror.h | 2 + source/libs/function/src/functionMgt.c | 5 +- source/libs/parser/src/parserImpl.c | 88 ++++++++++++++++++++--- source/libs/parser/test/newParserTest.cpp | 31 +++++++- 4 files changed, 113 insertions(+), 13 deletions(-) diff --git a/include/util/taoserror.h b/include/util/taoserror.h index bf6e101633..f2fe3603f2 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -455,6 +455,8 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2608) //There mustn't be aggregation #define TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT TAOS_DEF_ERROR_CODE(0, 0x2609) //ORDER BY item must be the number of a SELECT-list expression #define TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION TAOS_DEF_ERROR_CODE(0, 0x260A) //Not a GROUP BY expression +#define TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION TAOS_DEF_ERROR_CODE(0, 0x260B) //Not SELECTed expression +#define TSDB_CODE_PAR_NOT_SINGLE_GROUP TAOS_DEF_ERROR_CODE(0, 0x260C) //Not a single-group group function #ifdef __cplusplus } diff --git a/source/libs/function/src/functionMgt.c b/source/libs/function/src/functionMgt.c index 2138e58ccc..78d2feaa83 100644 --- a/source/libs/function/src/functionMgt.c +++ b/source/libs/function/src/functionMgt.c @@ -47,10 +47,11 @@ int32_t fmGetHandle(FuncMgtHandle* pHandle) { int32_t fmGetFuncInfo(FuncMgtHandle handle, const char* pFuncName, int32_t* pFuncId, int32_t* pFuncType) { SFuncMgtService* pService = (SFuncMgtService*)handle; - pFuncId = taosHashGet(pService->pFuncNameHashTable, pFuncName, strlen(pFuncName)); - if (NULL == pFuncId) { + void* pVal = taosHashGet(pService->pFuncNameHashTable, pFuncName, strlen(pFuncName)); + if (NULL == pVal) { return TSDB_CODE_FAILED; } + *pFuncId = *(int32_t*)pVal; if (*pFuncId < 0 || *pFuncId >= funcMgtBuiltinsNum) { return TSDB_CODE_FAILED; } diff --git a/source/libs/parser/src/parserImpl.c b/source/libs/parser/src/parserImpl.c index 85554d62a6..5c30813215 100644 --- a/source/libs/parser/src/parserImpl.c +++ b/source/libs/parser/src/parserImpl.c @@ -288,6 +288,10 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "ORDER BY item must be the number of a SELECT-list expression"; case TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION: return "Not a GROUP BY expression"; + case TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION: + return "Not SELECTed expression"; + case TSDB_CODE_PAR_NOT_SINGLE_GROUP: + return "Not a single-group group function"; default: return "Unknown error"; } @@ -333,7 +337,7 @@ static bool belongTable(const char* currentDb, const SColumnNode* pCol, const ST if ('\0' != pCol->dbName[0]) { cmp = strcmp(pCol->dbName, pTable->dbName); } else { - cmp = strcmp(currentDb, pTable->dbName); + cmp = (QUERY_NODE_REAL_TABLE == nodeType(pTable) ? strcmp(currentDb, pTable->dbName) : 0); } if (0 == cmp) { cmp = strcmp(pCol->tableAlias, pTable->tableAlias); @@ -422,9 +426,11 @@ static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) { static EDealRes translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol) { SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel); size_t nums = taosArrayGetSize(pTables); + bool foundTable = false; for (size_t i = 0; i < nums; ++i) { STableNode* pTable = taosArrayGetP(pTables, i); if (belongTable(pCxt->pParseCxt->db, pCol, pTable)) { + foundTable = true; if (findAndSetColumn(pCol, pTable)) { break; } @@ -432,6 +438,10 @@ static EDealRes translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* return DEAL_RES_ERROR; } } + if (!foundTable) { + generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_TABLE_NOT_EXIST, pCol->tableAlias); + return DEAL_RES_ERROR; + } return DEAL_RES_CONTINUE; } @@ -651,7 +661,28 @@ static bool isAliasColumn(SColumnNode* pCol) { return ('\0' == pCol->tableAlias[0]); } -static EDealRes doCheckkExprForGroupBy(SNode* pNode, void* pContext) { +static SNodeList* getGroupByList(STranslateContext* pCxt) { + if (SQL_CLAUSE_ORDER_BY == pCxt->currClause && pCxt->pCurrStmt->isDistinct) { + return pCxt->pCurrStmt->pProjectionList; + } + return pCxt->pCurrStmt->pGroupByList; +} + +static SNode* getGroupByNode(SNode* pNode) { + if (QUERY_NODE_GROUPING_SET == nodeType(pNode)) { + return nodesListGetNode(((SGroupingSetNode*)pNode)->pParameterList, 0); + } + return pNode; +} + +static int32_t getGroupByErrorCode(STranslateContext* pCxt) { + if (SQL_CLAUSE_ORDER_BY == pCxt->currClause && pCxt->pCurrStmt->isDistinct) { + return TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION; + } + return TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION; +} + +static EDealRes doCheckExprForGroupBy(SNode* pNode, void* pContext) { STranslateContext* pCxt = (STranslateContext*)pContext; if (!nodesIsExprNode(pNode) || (QUERY_NODE_COLUMN == nodeType(pNode) && isAliasColumn((SColumnNode*)pNode))) { return DEAL_RES_CONTINUE; @@ -660,28 +691,64 @@ static EDealRes doCheckkExprForGroupBy(SNode* pNode, void* pContext) { return DEAL_RES_IGNORE_CHILD; } SNode* pGroupNode; - FOREACH(pGroupNode, pCxt->pCurrStmt->pGroupByList) { - if (nodesEqualNode(nodesListGetNode(((SGroupingSetNode*)pGroupNode)->pParameterList, 0), pNode)) { + FOREACH(pGroupNode, getGroupByList(pCxt)) { + if (nodesEqualNode(getGroupByNode(pGroupNode), pNode)) { return DEAL_RES_IGNORE_CHILD; } } if (QUERY_NODE_COLUMN == nodeType(pNode)) { - generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION); + generateSyntaxErrMsg(pCxt, getGroupByErrorCode(pCxt)); return DEAL_RES_ERROR; } return DEAL_RES_CONTINUE; } static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode* pNode) { - nodesWalkNode(pNode, doCheckkExprForGroupBy, pCxt); + nodesWalkNode(pNode, doCheckExprForGroupBy, pCxt); return pCxt->errCode; } static int32_t checkExprListForGroupBy(STranslateContext* pCxt, SNodeList* pList) { - nodesWalkList(pList, doCheckkExprForGroupBy, pCxt); + if (NULL == getGroupByList(pCxt)) { + return TSDB_CODE_SUCCESS; + } + nodesWalkList(pList, doCheckExprForGroupBy, pCxt); return pCxt->errCode; } +typedef struct CheckAggColCoexistCxt { + STranslateContext* pTranslateCxt; + bool existAggFunc; + bool existCol; +} CheckAggColCoexistCxt; + +static EDealRes doCheckAggColCoexist(SNode* pNode, void* pContext) { + CheckAggColCoexistCxt* pCxt = (CheckAggColCoexistCxt*)pContext; + if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId)) { + pCxt->existAggFunc = true; + return DEAL_RES_IGNORE_CHILD; + } + if (QUERY_NODE_COLUMN == nodeType(pNode)) { + pCxt->existCol = true; + } + return DEAL_RES_CONTINUE; +} + +static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect) { + if (NULL != pSelect->pGroupByList) { + return TSDB_CODE_SUCCESS; + } + CheckAggColCoexistCxt cxt = { .pTranslateCxt = pCxt, .existAggFunc = false, .existCol = false }; + nodesWalkList(pSelect->pProjectionList, doCheckAggColCoexist, &cxt); + if (!pSelect->isDistinct) { + nodesWalkList(pSelect->pOrderByList, doCheckAggColCoexist, &cxt); + } + if (cxt.existAggFunc && cxt.existCol) { + return generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_NOT_SINGLE_GROUP); + } + return TSDB_CODE_SUCCESS; +} + static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) { int32_t code = TSDB_CODE_SUCCESS; switch (nodeType(pTable)) { @@ -809,7 +876,7 @@ static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) { } pCxt->currClause = SQL_CLAUSE_ORDER_BY; int32_t code = translateExprList(pCxt, pSelect->pOrderByList); - if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) { + if (TSDB_CODE_SUCCESS == code) { code = checkExprListForGroupBy(pCxt, pSelect->pOrderByList); } return code; @@ -822,7 +889,7 @@ static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect pCxt->currClause = SQL_CLAUSE_SELECT; code = translateExprList(pCxt, pSelect->pProjectionList); } - if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) { + if (TSDB_CODE_SUCCESS == code) { code = checkExprListForGroupBy(pCxt, pSelect->pProjectionList); } return code; @@ -895,6 +962,9 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) { if (TSDB_CODE_SUCCESS == code) { code = translateOrderBy(pCxt, pSelect); } + if (TSDB_CODE_SUCCESS == code) { + code = checkAggColCoexist(pCxt, pSelect); + } return code; } diff --git a/source/libs/parser/test/newParserTest.cpp b/source/libs/parser/test/newParserTest.cpp index 2414b7c15f..c91427f03f 100644 --- a/source/libs/parser/test/newParserTest.cpp +++ b/source/libs/parser/test/newParserTest.cpp @@ -517,7 +517,7 @@ TEST_F(NewParserTest, selectClause) { setDatabase("root", "test"); // GROUP BY clause - bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0"); + bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0"); ASSERT_TRUE(run()); bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2"); @@ -538,6 +538,16 @@ TEST_F(NewParserTest, selectClause) { bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY 1"); ASSERT_TRUE(run()); + + // DISTINCT clause + bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY c1"); + ASSERT_TRUE(run()); + + bind("SELECT DISTINCT c1 + 10, c2 FROM t1 WHERE c1 > 0 ORDER BY c1 + 10, c2"); + ASSERT_TRUE(run()); + + bind("SELECT DISTINCT c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 ORDER BY cc1, c2"); + ASSERT_TRUE(run()); } TEST_F(NewParserTest, selectSyntaxError) { @@ -573,6 +583,9 @@ TEST_F(NewParserTest, selectSemanticError) { bind("SELECT * FROM test.t10"); ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST)); + bind("SELECT t2.c1 FROM t1"); + ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST)); + // TSDB_CODE_PAR_AMBIGUOUS_COLUMN bind("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1"); ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_AMBIGUOUS_COLUMN)); @@ -608,7 +621,7 @@ TEST_F(NewParserTest, selectSemanticError) { bind("SELECT c2 FROM t1 ORDER BY 2"); ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT)); - //TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION + // TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION bind("SELECT count(*) cnt FROM t1 HAVING c1 > 0"); ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION)); @@ -620,4 +633,18 @@ TEST_F(NewParserTest, selectSemanticError) { bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c2 > 0 ORDER BY c1"); ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION)); + + // TSDB_CODE_PAR_NOT_SINGLE_GROUP + bind("SELECT count(*), c1 FROM t1"); + ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP)); + + bind("SELECT count(*) FROM t1 ORDER BY c1"); + ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP)); + + bind("SELECT c1 FROM t1 ORDER BY count(*)"); + ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP)); + + // TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION + bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY ts"); + ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION)); }