diff --git a/include/libs/function/functionMgt.h b/include/libs/function/functionMgt.h index d55adcb63cb6f1b847265acfde9059516e16e6b7..f1f60cb8e5e39d5c55eac192bca799a04a17b59f 100644 --- a/include/libs/function/functionMgt.h +++ b/include/libs/function/functionMgt.h @@ -197,6 +197,7 @@ bool fmIsSystemInfoFunc(int32_t funcId); bool fmIsImplicitTsFunc(int32_t funcId); bool fmIsClientPseudoColumnFunc(int32_t funcId); bool fmIsMultiRowsFunc(int32_t funcId); +bool fmIsKeepOrderFunc(int32_t funcId); int32_t fmGetDistMethod(const SFunctionNode* pFunc, SFunctionNode** pPartialFunc, SFunctionNode** pMergeFunc); diff --git a/source/libs/function/inc/functionMgtInt.h b/source/libs/function/inc/functionMgtInt.h index 0b4fdefec45189b833a52575e55f82144a211534..c79306f1e48bc44ea370a3b0290e940d29f69b0b 100644 --- a/source/libs/function/inc/functionMgtInt.h +++ b/source/libs/function/inc/functionMgtInt.h @@ -47,6 +47,7 @@ extern "C" { #define FUNC_MGT_SYSTEM_INFO_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(18) #define FUNC_MGT_CLIENT_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(19) #define FUNC_MGT_MULTI_ROWS_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(20) +#define FUNC_MGT_KEEP_ORDER_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(21) #define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0) diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index ec8e6b038e5cd389a12e3dfeb0ff21cfc3637a87..28f244a18cb0f0b684042ca2b93b81a39fb5d3b8 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -2097,7 +2097,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "top", .type = FUNCTION_TYPE_TOP, - .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, .translateFunc = translateTopBot, .getEnvFunc = getTopBotFuncEnv, .initFunc = topBotFunctionSetup, @@ -2112,7 +2112,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "bottom", .type = FUNCTION_TYPE_BOTTOM, - .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, .translateFunc = translateTopBot, .getEnvFunc = getTopBotFuncEnv, .initFunc = topBotFunctionSetup, @@ -2480,7 +2480,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "sample", .type = FUNCTION_TYPE_SAMPLE, - .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_ROWS_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_FORBID_STREAM_FUNC, .translateFunc = translateSample, .getEnvFunc = getSampleFuncEnv, .initFunc = sampleFunctionSetup, @@ -2906,7 +2906,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "_select_value", .type = FUNCTION_TYPE_SELECT_VALUE, - .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_KEEP_ORDER_FUNC, .translateFunc = translateSelectValue, .getEnvFunc = getSelectivityFuncEnv, // todo remove this function later. .initFunc = functionSetup, diff --git a/source/libs/function/src/functionMgt.c b/source/libs/function/src/functionMgt.c index ff74c880e3fc960bb5f655d7696733c92c8d397d..c173522683c7403950d915a9d1fa2d82eb828d1f 100644 --- a/source/libs/function/src/functionMgt.c +++ b/source/libs/function/src/functionMgt.c @@ -183,6 +183,8 @@ bool fmIsClientPseudoColumnFunc(int32_t funcId) { return isSpecificClassifyFunc( bool fmIsMultiRowsFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_MULTI_ROWS_FUNC); } +bool fmIsKeepOrderFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_KEEP_ORDER_FUNC); } + bool fmIsInterpFunc(int32_t funcId) { if (funcId < 0 || funcId >= funcMgtBuiltinsNum) { return false; diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index b7b8cfce3356cc9f2be6240ac5d1cec79e660af4..2c93a3921ea70150310587edbfdc083b93da57ba 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -2010,15 +2010,16 @@ static int32_t rewriteUniqueOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* } if (TSDB_CODE_SUCCESS == code) { code = nodesListMakeAppend(&pProject->pChildren, (SNode*)pAgg); - pAgg->pParent = pProject; - pAgg = NULL; } if (TSDB_CODE_SUCCESS == code) { + pAgg->pParent = pProject; + pAgg = NULL; code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pIndef, pProject); } if (TSDB_CODE_SUCCESS == code) { code = adjustLogicNodeDataRequirement( pProject, NULL == pProject->pParent ? DATA_ORDER_LEVEL_NONE : pProject->pParent->requireDataOrder); + pProject = NULL; } if (TSDB_CODE_SUCCESS == code) { nodesDestroyNode((SNode*)pIndef); diff --git a/source/libs/planner/src/planUtil.c b/source/libs/planner/src/planUtil.c index 42143771013c63a291cd588adca524204f6b4fab..d4bd7e51622c7c021c5102d2babe1bb50b412dc3 100644 --- a/source/libs/planner/src/planUtil.c +++ b/source/libs/planner/src/planUtil.c @@ -13,6 +13,7 @@ * along with this program. If not, see . */ +#include "functionMgt.h" #include "planInt.h" static char* getUsageErrFormat(int32_t errCode) { @@ -140,13 +141,27 @@ static int32_t adjustScanDataRequirement(SScanLogicNode* pScan, EDataOrderLevel } static int32_t adjustJoinDataRequirement(SJoinLogicNode* pJoin, EDataOrderLevel requirement) { + // The lowest sort level of join input and output data is DATA_ORDER_LEVEL_GLOBAL 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) { - if (requirement > DATA_ORDER_LEVEL_NONE) { + // 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))) { return TSDB_CODE_PLAN_INTERNAL_ERROR; } + pAgg->node.resultDataOrder = requirement; + pAgg->node.requireDataOrder = requirement; return TSDB_CODE_SUCCESS; } @@ -157,11 +172,12 @@ static int32_t adjustProjectDataRequirement(SProjectLogicNode* pProject, EDataOr } static int32_t adjustIntervalDataRequirement(SWindowLogicNode* pWindow, EDataOrderLevel requirement) { - if (requirement <= pWindow->node.resultDataOrder) { - return TSDB_CODE_SUCCESS; + // The lowest sort level of interval output data is DATA_ORDER_LEVEL_IN_GROUP + if (requirement < DATA_ORDER_LEVEL_IN_GROUP) { + requirement = DATA_ORDER_LEVEL_IN_GROUP; } + // The sort level of interval input data is always DATA_ORDER_LEVEL_IN_BLOCK pWindow->node.resultDataOrder = requirement; - pWindow->node.requireDataOrder = requirement; return TSDB_CODE_SUCCESS; } diff --git a/source/libs/planner/test/planSubqueryTest.cpp b/source/libs/planner/test/planSubqueryTest.cpp index fde373c66dc8d62646ce7b1ca66388784a66f3ce..16dd91846c6b0cca12135238f73dc382be490dfc 100644 --- a/source/libs/planner/test/planSubqueryTest.cpp +++ b/source/libs/planner/test/planSubqueryTest.cpp @@ -70,4 +70,6 @@ TEST_F(PlanSubqeuryTest, outerInterval) { run("SELECT COUNT(*) FROM (SELECT * FROM st1) INTERVAL(5s)"); run("SELECT COUNT(*) + SUM(c1) FROM (SELECT * FROM st1) INTERVAL(5s)"); + + run("SELECT COUNT(*) FROM (SELECT ts, TOP(c1, 10) FROM st1s1) INTERVAL(5s)"); }