diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index b08e0aff3d..298dffcc83 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -351,9 +351,6 @@ bool nodesIsComparisonOp(const SOperatorNode* pOp); bool nodesIsJsonOp(const SOperatorNode* pOp); bool nodesIsRegularOp(const SOperatorNode* pOp); -bool nodesIsTimeorderQuery(const SNode* pQuery); -bool nodesIsTimelineQuery(const SNode* pQuery); - void* nodesGetValueFromNode(SValueNode* pNode); int32_t nodesSetValueNodeValue(SValueNode* pNode, void* value); char* nodesGetStrValueFromNode(SValueNode* pNode); diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 5c251e7a27..66287099cd 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -650,6 +650,7 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_INVALID_FUNCTION_NAME TAOS_DEF_ERROR_CODE(0, 0x264D) #define TSDB_CODE_PAR_COMMENT_TOO_LONG TAOS_DEF_ERROR_CODE(0, 0x264E) #define TSDB_CODE_PAR_NOT_ALLOWED_FUNC TAOS_DEF_ERROR_CODE(0, 0x264F) +#define TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY TAOS_DEF_ERROR_CODE(0, 0x2650) //planner #define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700) diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index bc49f36afe..0e8f530b0e 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -1771,6 +1771,7 @@ static const char* jkSubplanId = "Id"; static const char* jkSubplanType = "SubplanType"; static const char* jkSubplanMsgType = "MsgType"; static const char* jkSubplanLevel = "Level"; +static const char* jkSubplanDbFName = "DbFName"; static const char* jkSubplanNodeAddr = "NodeAddr"; static const char* jkSubplanRootNode = "RootNode"; static const char* jkSubplanDataSink = "DataSink"; @@ -1788,6 +1789,9 @@ static int32_t subplanToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = tjsonAddIntegerToObject(pJson, jkSubplanLevel, pNode->level); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddStringToObject(pJson, jkSubplanDbFName, pNode->dbFName); + } if (TSDB_CODE_SUCCESS == code) { code = tjsonAddObject(pJson, jkSubplanNodeAddr, queryNodeAddrToJson, &pNode->execNode); } @@ -1815,6 +1819,9 @@ static int32_t jsonToSubplan(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = tjsonGetIntValue(pJson, jkSubplanLevel, &pNode->level); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetStringValue(pJson, jkSubplanDbFName, pNode->dbFName); + } if (TSDB_CODE_SUCCESS == code) { code = tjsonToObject(pJson, jkSubplanNodeAddr, jsonToQueryNodeAddr, &pNode->execNode); } diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 476b3b2786..9fb9d8e551 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -1137,10 +1137,6 @@ bool nodesIsRegularOp(const SOperatorNode* pOp) { return false; } -bool nodesIsTimeorderQuery(const SNode* pQuery) { return false; } - -bool nodesIsTimelineQuery(const SNode* pQuery) { return false; } - typedef struct SCollectColumnsCxt { int32_t errCode; const char* pTableAlias; diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index cd1c91f84c..dbb29699fc 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -382,6 +382,35 @@ static bool isInternalPrimaryKey(const SColumnNode* pCol) { return PRIMARYKEY_TIMESTAMP_COL_ID == pCol->colId && 0 == strcmp(pCol->colName, PK_TS_COL_INTERNAL_NAME); } +static bool isTimeOrderQuery(SNode* pStmt) { + if (QUERY_NODE_SELECT_STMT == nodeType(pStmt)) { + return ((SSelectStmt*)pStmt)->isTimeOrderQuery; + } else { + return false; + } +} + +static bool isPrimaryKeyImpl(STempTableNode* pTable, SNode* pExpr) { + if (QUERY_NODE_COLUMN == nodeType(pExpr)) { + return (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId); + } else if (QUERY_NODE_FUNCTION == nodeType(pExpr)) { + SFunctionNode* pFunc = (SFunctionNode*)pExpr; + if (FUNCTION_TYPE_SELECT_VALUE == pFunc->funcType) { + return isPrimaryKeyImpl(pTable, nodesListGetNode(pFunc->pParameterList, 0)); + } else if (FUNCTION_TYPE_WSTARTTS == pFunc->funcType || FUNCTION_TYPE_WENDTS == pFunc->funcType) { + return true; + } + } + return false; +} + +static bool isPrimaryKey(STempTableNode* pTable, SNode* pExpr) { + if (!isTimeOrderQuery(pTable->pSubquery)) { + return false; + } + return isPrimaryKeyImpl(pTable, pExpr); +} + static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) { bool found = false; if (QUERY_NODE_REAL_TABLE == nodeType(pTable)) { @@ -404,8 +433,7 @@ static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) { FOREACH(pNode, pProjectList) { SExprNode* pExpr = (SExprNode*)pNode; if (0 == strcmp(pCol->colName, pExpr->aliasName) || - ((QUERY_NODE_COLUMN == nodeType(pExpr) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId) && - isInternalPrimaryKey(pCol))) { + (isPrimaryKey((STempTableNode*)pTable, pNode) && isInternalPrimaryKey(pCol))) { setColumnInfoByExpr(pTable, pExpr, pCol); found = true; break; @@ -454,6 +482,9 @@ static EDealRes translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNod } if (!found) { if (isInternalPk) { + if (NULL != pCxt->pCurrStmt->pWindow) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY); + } return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_INTERNAL_PK); } else { return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName); @@ -781,7 +812,6 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc) } pCxt->pCurrStmt->hasAggFuncs = true; - pCxt->pCurrStmt->isTimeOrderQuery = false; if (isCountStar(pFunc)) { pCxt->errCode = rewriteCountStar(pCxt, pFunc); } diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 6a9d868cf5..fe21915b1a 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -167,6 +167,8 @@ static char* getSyntaxErrFormat(int32_t errCode) { case TSDB_CODE_PAR_NOT_ALLOWED_FUNC: return "Some functions are allowed only in the SELECT list of a query. " "And, cannot be mixed with other non scalar functions or columns."; + case TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY: + return "Window query not supported, since the result of subquery not include valid timestamp column"; case TSDB_CODE_OUT_OF_MEMORY: return "Out of memory"; default: diff --git a/source/libs/parser/test/parSelectTest.cpp b/source/libs/parser/test/parSelectTest.cpp index ca72d8e8b6..9f8d5b4802 100644 --- a/source/libs/parser/test/parSelectTest.cpp +++ b/source/libs/parser/test/parSelectTest.cpp @@ -125,8 +125,6 @@ TEST_F(ParserSelectTest, nonstdFunc) { useDb("root", "test"); run("SELECT DIFF(c1) FROM t1"); - - // run("SELECT DIFF(c1) FROM t1 INTERVAL(10s)"); } TEST_F(ParserSelectTest, nonstdFuncSemanticCheck) { @@ -139,12 +137,13 @@ TEST_F(ParserSelectTest, nonstdFuncSemanticCheck) { run("SELECT DIFF(c1), count(*) FROM t1", TSDB_CODE_PAR_NOT_ALLOWED_FUNC, PARSER_STAGE_TRANSLATE); run("SELECT DIFF(c1), CSUM(c1) FROM t1", TSDB_CODE_PAR_NOT_ALLOWED_FUNC, PARSER_STAGE_TRANSLATE); + + // run("SELECT DIFF(c1) FROM t1 INTERVAL(10s)"); } -TEST_F(ParserSelectTest, clause) { +TEST_F(ParserSelectTest, groupBy) { useDb("root", "test"); - // GROUP BY clause run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0"); run("SELECT COUNT(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2"); @@ -154,13 +153,19 @@ TEST_F(ParserSelectTest, clause) { run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2, c1"); run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c1 + 10, c2"); +} + +TEST_F(ParserSelectTest, orderBy) { + useDb("root", "test"); - // order by clause run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 order by cnt"); run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 order by 1"); +} + +TEST_F(ParserSelectTest, distinct) { + useDb("root", "test"); - // distinct clause // run("SELECT distinct c1, c2 FROM t1 WHERE c1 > 0 order by c1"); // run("SELECT distinct c1 + 10, c2 FROM t1 WHERE c1 > 0 order by c1 + 10, c2"); @@ -194,6 +199,25 @@ TEST_F(ParserSelectTest, intervalSemanticCheck) { PARSER_STAGE_TRANSLATE); } +TEST_F(ParserSelectTest, subquery) { + useDb("root", "test"); + + run("SELECT SUM(a) FROM (SELECT MAX(c1) a, ts FROM st1s1 INTERVAL(1m)) INTERVAL(1n)"); + + run("SELECT SUM(a) FROM (SELECT MAX(c1) a, _wstartts FROM st1s1 INTERVAL(1m)) INTERVAL(1n)"); + + run("SELECT SUM(a) FROM (SELECT MAX(c1) a, ts FROM st1s1 PARTITION BY TBNAME INTERVAL(1m)) INTERVAL(1n)"); + + run("SELECT SUM(a) FROM (SELECT MAX(c1) a, _wstartts FROM st1s1 PARTITION BY TBNAME INTERVAL(1m)) INTERVAL(1n)"); +} + +TEST_F(ParserSelectTest, subquerySemanticError) { + useDb("root", "test"); + + run("SELECT SUM(a) FROM (SELECT MAX(c1) a FROM st1s1 INTERVAL(1m)) INTERVAL(1n)", TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY, + PARSER_STAGE_TRANSLATE); +} + TEST_F(ParserSelectTest, semanticError) { useDb("root", "test");