Merge pull request #10230 from taosdata/feature/3.0_wxy
TD-13338 SELECT statement translate code
This commit is contained in:
commit
bf40ca8935
|
@ -457,6 +457,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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue