From bd8de1e8fdc70d5edb0ec6d1c7955eb647e70703 Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Wed, 3 Aug 2022 16:59:27 +0800 Subject: [PATCH 1/2] fix: timeline function validity check --- include/libs/nodes/plannodes.h | 1 + include/libs/nodes/querynodes.h | 1 + source/libs/nodes/src/nodesEqualFuncs.c | 4 +- source/libs/parser/src/parAstCreater.c | 1 + source/libs/parser/src/parTranslater.c | 104 ++++++++++++++++++--- source/libs/planner/src/planLogicCreater.c | 1 + source/libs/planner/src/planUtil.c | 12 +-- 7 files changed, 97 insertions(+), 27 deletions(-) diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h index fbdb520bf3..40879de3bc 100644 --- a/include/libs/nodes/plannodes.h +++ b/include/libs/nodes/plannodes.h @@ -114,6 +114,7 @@ typedef struct SAggLogicNode { SNodeList* pAggFuncs; bool hasLastRow; bool hasTimeLineFunc; + bool onlyHasKeepOrderFunc; } SAggLogicNode; typedef struct SProjectLogicNode { diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index cd2a7d3f9f..db87bde521 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -269,6 +269,7 @@ typedef struct SSelectStmt { bool hasInterpFunc; bool hasLastRowFunc; bool hasTimeLineFunc; + bool onlyHasKeepOrderFunc; bool groupSort; } SSelectStmt; diff --git a/source/libs/nodes/src/nodesEqualFuncs.c b/source/libs/nodes/src/nodesEqualFuncs.c index 2442bd8c16..9cb7e8b66d 100644 --- a/source/libs/nodes/src/nodesEqualFuncs.c +++ b/source/libs/nodes/src/nodesEqualFuncs.c @@ -82,7 +82,9 @@ static bool columnNodeEqual(const SColumnNode* a, const SColumnNode* b) { COMPARE_STRING_FIELD(dbName); COMPARE_STRING_FIELD(tableName); COMPARE_STRING_FIELD(colName); - COMPARE_STRING_FIELD(tableAlias); + if (0 == a->tableId) { + COMPARE_STRING_FIELD(tableAlias); + } return true; } diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index 7b115ad2c7..b2006f8fc9 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -767,6 +767,7 @@ SNode* createSelectStmt(SAstCreateContext* pCxt, bool isDistinct, SNodeList* pPr select->pFromTable = pTable; sprintf(select->stmtName, "%p", select); select->isTimeLineResult = true; + select->onlyHasKeepOrderFunc = true; select->timeRange = TSWINDOW_INITIALIZER; return (SNode*)select; } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index ae408556bd..0fd02d5404 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -1171,6 +1171,44 @@ static int32_t translateMultiRowsFunc(STranslateContext* pCxt, SFunctionNode* pF return TSDB_CODE_SUCCESS; } +static int32_t translateInterpFunc(STranslateContext* pCxt, SFunctionNode* pFunc) { + if (!fmIsInterpFunc(pFunc->funcId)) { + return TSDB_CODE_SUCCESS; + } + if (!isSelectStmt(pCxt->pCurrStmt) || SQL_CLAUSE_SELECT != pCxt->currClause) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC); + } + SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt; + if (pSelect->hasAggFuncs || pSelect->hasMultiRowsFunc || pSelect->hasIndefiniteRowsFunc) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC); + } + if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) { + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "%s function is not supported in window query or group query", pFunc->functionName); + } + if (hasInvalidFuncNesting(pFunc->pParameterList)) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING); + } + return TSDB_CODE_SUCCESS; +} + +static int32_t translateTimelineFunc(STranslateContext* pCxt, SFunctionNode* pFunc) { + if (!fmIsTimelineFunc(pFunc->funcId)) { + return TSDB_CODE_SUCCESS; + } + if (!isSelectStmt(pCxt->pCurrStmt)) { + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "%s function must be used in select statements", pFunc->functionName); + } + SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt; + if (QUERY_NODE_TEMP_TABLE == nodeType(pSelect->pFromTable) && + !isTimeLineQuery(((STempTableNode*)pSelect->pFromTable)->pSubquery)) { + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "%s function requires valid time series input", pFunc->functionName); + } + return TSDB_CODE_SUCCESS; +} + static bool hasFillClause(SNode* pCurrStmt) { if (!isSelectStmt(pCurrStmt)) { return false; @@ -1291,6 +1329,7 @@ static void setFuncClassification(SNode* pCurrStmt, SFunctionNode* pFunc) { pSelect->hasInterpFunc = pSelect->hasInterpFunc ? true : (FUNCTION_TYPE_INTERP == pFunc->funcType); pSelect->hasLastRowFunc = pSelect->hasLastRowFunc ? true : (FUNCTION_TYPE_LAST_ROW == pFunc->funcType); pSelect->hasTimeLineFunc = pSelect->hasTimeLineFunc ? true : fmIsTimelineFunc(pFunc->funcId); + pSelect->onlyHasKeepOrderFunc = pSelect->onlyHasKeepOrderFunc ? fmIsKeepOrderFunc(pFunc->funcId) : false; } } @@ -1409,6 +1448,12 @@ static int32_t translateNoramlFunction(STranslateContext* pCxt, SFunctionNode* p if (TSDB_CODE_SUCCESS == code) { code = translateMultiRowsFunc(pCxt, pFunc); } + if (TSDB_CODE_SUCCESS == code) { + code = translateInterpFunc(pCxt, pFunc); + } + if (TSDB_CODE_SUCCESS == code) { + code = translateTimelineFunc(pCxt, pFunc); + } if (TSDB_CODE_SUCCESS == code) { setFuncClassification(pCxt->pCurrStmt, pFunc); } @@ -1685,6 +1730,9 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect) (!pSelect->hasAggFuncs && !pSelect->hasIndefiniteRowsFunc && !pSelect->hasInterpFunc)) { return TSDB_CODE_SUCCESS; } + if (!pSelect->onlyHasKeepOrderFunc) { + pSelect->isTimeLineResult = false; + } CheckAggColCoexistCxt cxt = {.pTranslateCxt = pCxt, .existCol = false}; nodesRewriteExprs(pSelect->pProjectionList, doCheckAggColCoexist, &cxt); if (!pSelect->isDistinct) { @@ -2181,9 +2229,9 @@ static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) { } pCxt->currClause = SQL_CLAUSE_ORDER_BY; code = translateExprList(pCxt, pSelect->pOrderByList); - if (TSDB_CODE_SUCCESS == code) { - code = checkExprListForGroupBy(pCxt, pSelect, pSelect->pOrderByList); - } + } + if (TSDB_CODE_SUCCESS == code) { + code = checkExprListForGroupBy(pCxt, pSelect, pSelect->pOrderByList); } return code; } @@ -2264,15 +2312,15 @@ static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) { } static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) { - if (NULL != pSelect->pGroupByList && NULL != pSelect->pWindow) { + if (NULL == pSelect->pGroupByList) { + return TSDB_CODE_SUCCESS; + } + if (NULL != pSelect->pWindow) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_GROUPBY_WINDOW_COEXIST); } - if (NULL != pSelect->pGroupByList) { - pCxt->currClause = SQL_CLAUSE_GROUP_BY; - pSelect->isTimeLineResult = false; - return translateExprList(pCxt, pSelect->pGroupByList); - } - return TSDB_CODE_SUCCESS; + pCxt->currClause = SQL_CLAUSE_GROUP_BY; + pSelect->isTimeLineResult = false; + return translateExprList(pCxt, pSelect->pGroupByList); } static int32_t getTimeRange(SNode** pPrimaryKeyCond, STimeWindow* pTimeRange, bool* pIsStrict) { @@ -2561,12 +2609,13 @@ static int32_t translateInterp(STranslateContext* pCxt, SSelectStmt* pSelect) { return code; } -static int32_t translatePartitionBy(STranslateContext* pCxt, SNodeList* pPartitionByList) { - if (NULL == pPartitionByList) { +static int32_t translatePartitionBy(STranslateContext* pCxt, SSelectStmt* pSelect) { + if (NULL == pSelect->pPartitionByList) { return TSDB_CODE_SUCCESS; } + pSelect->isTimeLineResult = false; pCxt->currClause = SQL_CLAUSE_PARTITION_BY; - return translateExprList(pCxt, pPartitionByList); + return translateExprList(pCxt, pSelect->pPartitionByList); } static int32_t translateWhere(STranslateContext* pCxt, SSelectStmt* pSelect) { @@ -2669,11 +2718,36 @@ static EDealRes replaceOrderByAliasImpl(SNode** pNode, void* pContext) { } static int32_t replaceOrderByAlias(STranslateContext* pCxt, SNodeList* pProjectionList, SNodeList* pOrderByList) { + if (NULL == pOrderByList) { + return TSDB_CODE_SUCCESS; + } SReplaceOrderByAliasCxt cxt = {.pTranslateCxt = pCxt, .pProjectionList = pProjectionList}; nodesRewriteExprsPostOrder(pOrderByList, replaceOrderByAliasImpl, &cxt); return pCxt->errCode; } +static void resetResultTimeline(SSelectStmt* pSelect) { + if (NULL == pSelect->pOrderByList) { + return; + } + SNode* pOrder = ((SOrderByExprNode*)nodesListGetNode(pSelect->pOrderByList, 0))->pExpr; + if ((QUERY_NODE_TEMP_TABLE == nodeType(pSelect->pFromTable) && + isPrimaryKey((STempTableNode*)pSelect->pFromTable, pOrder)) || + (QUERY_NODE_TEMP_TABLE != nodeType(pSelect->pFromTable) && isPrimaryKeyImpl(pOrder))) { + pSelect->isTimeLineResult = true; + } else { + pSelect->isTimeLineResult = false; + } +} + +static int32_t replaceOrderByAliasForSelect(STranslateContext* pCxt, SSelectStmt* pSelect) { + int32_t code = replaceOrderByAlias(pCxt, pSelect->pProjectionList, pSelect->pOrderByList); + if (TSDB_CODE_SUCCESS == pCxt->errCode) { + resetResultTimeline(pSelect); + } + return code; +} + static int32_t translateSelectWithoutFrom(STranslateContext* pCxt, SSelectStmt* pSelect) { pCxt->pCurrStmt = (SNode*)pSelect; pCxt->currClause = SQL_CLAUSE_SELECT; @@ -2688,7 +2762,7 @@ static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect code = translateWhere(pCxt, pSelect); } if (TSDB_CODE_SUCCESS == code) { - code = translatePartitionBy(pCxt, pSelect->pPartitionByList); + code = translatePartitionBy(pCxt, pSelect); } if (TSDB_CODE_SUCCESS == code) { code = translateWindow(pCxt, pSelect); @@ -2721,7 +2795,7 @@ static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect code = appendTsForImplicitTsFunc(pCxt, pSelect); } if (TSDB_CODE_SUCCESS == code) { - code = replaceOrderByAlias(pCxt, pSelect->pProjectionList, pSelect->pOrderByList); + code = replaceOrderByAliasForSelect(pCxt, pSelect); } return code; } diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index b51624336b..0762b28188 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -480,6 +480,7 @@ static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, pAgg->hasLastRow = pSelect->hasLastRowFunc; pAgg->hasTimeLineFunc = pSelect->hasTimeLineFunc; + pAgg->onlyHasKeepOrderFunc = pSelect->onlyHasKeepOrderFunc; pAgg->node.groupAction = GROUP_ACTION_SET; pAgg->node.requireDataOrder = pAgg->hasTimeLineFunc ? DATA_ORDER_LEVEL_IN_GROUP : DATA_ORDER_LEVEL_NONE; pAgg->node.resultDataOrder = DATA_ORDER_LEVEL_NONE; diff --git a/source/libs/planner/src/planUtil.c b/source/libs/planner/src/planUtil.c index 6ec9fecfdb..d7310892de 100644 --- a/source/libs/planner/src/planUtil.c +++ b/source/libs/planner/src/planUtil.c @@ -146,19 +146,9 @@ static int32_t adjustJoinDataRequirement(SJoinLogicNode* pJoin, EDataOrderLevel return TSDB_CODE_SUCCESS; } -static bool isKeepOrderAggFunc(SNodeList* pFuncs) { - SNode* pFunc = NULL; - FOREACH(pFunc, pFuncs) { - if (!fmIsKeepOrderFunc(((SFunctionNode*)pFunc)->funcId)) { - return false; - } - } - return true; -} - static int32_t adjustAggDataRequirement(SAggLogicNode* pAgg, EDataOrderLevel requirement) { // The sort level of agg with group by output data can only be DATA_ORDER_LEVEL_NONE - if (requirement > DATA_ORDER_LEVEL_NONE && (NULL != pAgg->pGroupKeys || !isKeepOrderAggFunc(pAgg->pAggFuncs))) { + if (requirement > DATA_ORDER_LEVEL_NONE && (NULL != pAgg->pGroupKeys || !pAgg->onlyHasKeepOrderFunc)) { planError( "The output of aggregate cannot meet the requirements(%s) of the upper operator. " "Illegal statement, should be intercepted in parser", From 335c8b4d8a1e38eaeb7e5da890aac86127787ed1 Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Wed, 3 Aug 2022 18:17:12 +0800 Subject: [PATCH 2/2] fix: timeline function validity check --- source/libs/function/src/builtins.c | 19 +++++++++++-------- source/libs/parser/src/parTranslater.c | 1 + source/libs/parser/test/parSelectTest.cpp | 3 ++- tests/system-test/2-query/csum.py | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index 6383179fee..dd84535eac 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -2246,7 +2246,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "derivative", .type = FUNCTION_TYPE_DERIVATIVE, - .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | FUNC_MGT_IMPLICIT_TS_FUNC | FUNC_MGT_CUMULATIVE_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, + .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | FUNC_MGT_IMPLICIT_TS_FUNC | + FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_CUMULATIVE_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, .translateFunc = translateDerivative, .getEnvFunc = getDerivativeFuncEnv, .initFunc = derivativeFuncSetup, @@ -2453,7 +2454,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "diff", .type = FUNCTION_TYPE_DIFF, - .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_CUMULATIVE_FUNC, + .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | + FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_CUMULATIVE_FUNC, .translateFunc = translateDiff, .getEnvFunc = getDiffFuncEnv, .initFunc = diffFunctionSetup, @@ -2487,7 +2489,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "csum", .type = FUNCTION_TYPE_CSUM, - .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_CUMULATIVE_FUNC, + .classification = FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_TIMELINE_FUNC | + FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_CUMULATIVE_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateCsum, .getEnvFunc = getCsumFuncEnv, .initFunc = functionSetup, @@ -2856,7 +2859,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "tbname", .type = FUNCTION_TYPE_TBNAME, - .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_SCAN_PC_FUNC, + .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_SCAN_PC_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateTbnameColumn, .getEnvFunc = NULL, .initFunc = NULL, @@ -2896,7 +2899,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "_wstart", .type = FUNCTION_TYPE_WSTART, - .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC, + .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateTimePseudoColumn, .getEnvFunc = getTimePseudoFuncEnv, .initFunc = NULL, @@ -2906,7 +2909,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "_wend", .type = FUNCTION_TYPE_WEND, - .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC, + .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateTimePseudoColumn, .getEnvFunc = getTimePseudoFuncEnv, .initFunc = NULL, @@ -2916,7 +2919,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "_wduration", .type = FUNCTION_TYPE_WDURATION, - .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC, + .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC | FUNC_MGT_WINDOW_PC_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateWduration, .getEnvFunc = getTimePseudoFuncEnv, .initFunc = NULL, @@ -2964,7 +2967,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "_group_key", .type = FUNCTION_TYPE_GROUP_KEY, - .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateGroupKey, .getEnvFunc = getGroupKeyFuncEnv, .initFunc = functionSetup, diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 0fd02d5404..f53f1f27b7 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -2543,6 +2543,7 @@ static int32_t translateWindow(STranslateContext* pCxt, SSelectStmt* pSelect) { if (NULL == pSelect->pWindow) { return TSDB_CODE_SUCCESS; } + pSelect->isTimeLineResult = true; pCxt->currClause = SQL_CLAUSE_WINDOW; int32_t code = translateExpr(pCxt, &pSelect->pWindow); if (TSDB_CODE_SUCCESS == code) { diff --git a/source/libs/parser/test/parSelectTest.cpp b/source/libs/parser/test/parSelectTest.cpp index 02a82f7602..5b222a8dec 100644 --- a/source/libs/parser/test/parSelectTest.cpp +++ b/source/libs/parser/test/parSelectTest.cpp @@ -316,7 +316,8 @@ TEST_F(ParserSelectTest, subquery) { 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, _wstart FROM st1s1 PARTITION BY TBNAME INTERVAL(1m)) INTERVAL(1n)"); + run("SELECT SUM(a) FROM (SELECT MAX(c1) a, _wstart FROM st1s1 PARTITION BY TBNAME INTERVAL(1m) ORDER BY _WSTART) " + "INTERVAL(1n)"); run("SELECT _C0 FROM (SELECT _ROWTS, ts FROM st1s1)"); diff --git a/tests/system-test/2-query/csum.py b/tests/system-test/2-query/csum.py index f38a99d809..953dd1e491 100644 --- a/tests/system-test/2-query/csum.py +++ b/tests/system-test/2-query/csum.py @@ -162,9 +162,9 @@ class TDTestCase: self.checkcsum(**case6) # case7~8: nested query - case7 = {"table_expr": "(select c1 from db.stb1 order by tbname ,ts )"} + case7 = {"table_expr": "(select c1 from db.stb1 order by ts, tbname )"} self.checkcsum(**case7) - case8 = {"table_expr": "(select csum(c1) c1 from db.t1 partition by tbname)"} + case8 = {"table_expr": "(select csum(c1) c1 from db.t1)"} self.checkcsum(**case8) # case9~10: mix with tbname/ts/tag/col not support , must partition by alias ,such as select tbname ,csum(c1) partition by tbname