From cdfe9929c8aa8f82ed80213cd2843a7a341c48eb Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Sat, 30 Apr 2022 14:07:44 +0800 Subject: [PATCH] feat: fill physical plan --- include/common/taosdef.h | 15 +- include/libs/nodes/plannodes.h | 20 ++- include/libs/nodes/querynodes.h | 9 +- include/util/taoserror.h | 3 + source/libs/executor/src/executorimpl.c | 2 - source/libs/nodes/src/nodesCodeFuncs.c | 42 +++++ source/libs/parser/src/parTranslater.c | 162 +++++++++++++++--- source/libs/parser/src/parUtil.c | 3 +- source/libs/parser/test/parSelectTest.cpp | 45 ++--- source/libs/planner/inc/planInt.h | 3 + source/libs/planner/src/planLogicCreater.c | 1 + source/libs/planner/src/planOptimizer.c | 12 +- source/libs/planner/src/planPhysiCreater.c | 3 + source/libs/planner/src/planUtil.c | 36 ++++ source/libs/planner/test/planBasicTest.cpp | 26 +-- source/libs/planner/test/planIntervalTest.cpp | 7 +- 16 files changed, 295 insertions(+), 94 deletions(-) create mode 100644 source/libs/planner/src/planUtil.c diff --git a/include/common/taosdef.h b/include/common/taosdef.h index 85d11be817..dd1661f871 100644 --- a/include/common/taosdef.h +++ b/include/common/taosdef.h @@ -28,15 +28,16 @@ typedef int64_t tb_uid_t; #define TSWINDOW_INITIALIZER ((STimeWindow){INT64_MIN, INT64_MAX}) #define TSWINDOW_DESC_INITIALIZER ((STimeWindow){INT64_MAX, INT64_MIN}) #define IS_TSWINDOW_SPECIFIED(win) (((win).skey != INT64_MIN) || ((win).ekey != INT64_MAX)) +#define TSWINDOW_IS_EQUAL(t1, t2) (((t1).skey == (t2).skey) && ((t1).ekey == (t2).ekey)) typedef enum { - TSDB_SUPER_TABLE = 1, // super table - TSDB_CHILD_TABLE = 2, // table created from super table - TSDB_NORMAL_TABLE = 3, // ordinary table - TSDB_STREAM_TABLE = 4, // table created from stream computing - TSDB_TEMP_TABLE = 5, // temp table created by nest query + TSDB_SUPER_TABLE = 1, // super table + TSDB_CHILD_TABLE = 2, // table created from super table + TSDB_NORMAL_TABLE = 3, // ordinary table + TSDB_STREAM_TABLE = 4, // table created from stream computing + TSDB_TEMP_TABLE = 5, // temp table created by nest query TSDB_SYSTEM_TABLE = 6, - TSDB_TABLE_MAX = 7 + TSDB_TABLE_MAX = 7 } ETableType; typedef enum { @@ -86,7 +87,7 @@ typedef enum { extern char *qtypeStr[]; -#define TSDB_PORT_HTTP 11 +#define TSDB_PORT_HTTP 11 #undef TD_DEBUG_PRINT_ROW diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h index 10688ce239..a756217c7a 100644 --- a/include/libs/nodes/plannodes.h +++ b/include/libs/nodes/plannodes.h @@ -110,10 +110,11 @@ typedef struct SWindowLogicNode { } SWindowLogicNode; typedef struct SFillLogicNode { - SLogicNode node; - EFillMode mode; - SNode* pWStartTs; - SNode* pValues; // SNodeListNode + SLogicNode node; + EFillMode mode; + SNode* pWStartTs; + SNode* pValues; // SNodeListNode + STimeWindow timeRange; } SFillLogicNode; typedef struct SSortLogicNode { @@ -274,11 +275,12 @@ typedef struct SIntervalPhysiNode { } SIntervalPhysiNode; typedef struct SFillPhysiNode { - SPhysiNode node; - EFillMode mode; - SNode* pWStartTs; // SColumnNode - SNode* pValues; // SNodeListNode - SNodeList* pTargets; + SPhysiNode node; + EFillMode mode; + SNode* pWStartTs; // SColumnNode + SNode* pValues; // SNodeListNode + SNodeList* pTargets; + STimeWindow timeRange; } SFillPhysiNode; typedef struct SMultiTableIntervalPhysiNode { diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 29f31f25a0..91c80f6cf5 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -209,10 +209,11 @@ typedef enum EFillMode { } EFillMode; typedef struct SFillNode { - ENodeType type; // QUERY_NODE_FILL - EFillMode mode; - SNode* pValues; // SNodeListNode - SNode* pWStartTs; // _wstartts pseudo column + ENodeType type; // QUERY_NODE_FILL + EFillMode mode; + SNode* pValues; // SNodeListNode + SNode* pWStartTs; // _wstartts pseudo column + STimeWindow timeRange; } SFillNode; typedef struct SSelectStmt { diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 00708f0933..27af7eb27e 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -619,9 +619,12 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY TAOS_DEF_ERROR_CODE(0, 0x2638) #define TSDB_CODE_PAR_INVALID_TOPIC_QUERY TAOS_DEF_ERROR_CODE(0, 0x2639) #define TSDB_CODE_PAR_INVALID_DROP_STABLE TAOS_DEF_ERROR_CODE(0, 0x263A) +#define TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE TAOS_DEF_ERROR_CODE(0, 0x263B) //planner #define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700) +#define TSDB_CODE_PLAN_EXPECTED_TS_EQUAL TAOS_DEF_ERROR_CODE(0, 0x2701) +#define TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN TAOS_DEF_ERROR_CODE(0, 0x2702) //function #define TSDB_CODE_FUNC_FUNTION_ERROR TAOS_DEF_ERROR_CODE(0, 0x2800) diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 9f17a4cc7b..a88873dbd5 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -41,8 +41,6 @@ #define SET_MAIN_SCAN_FLAG(runtime) ((runtime)->scanFlag = MAIN_SCAN) #define SET_REVERSE_SCAN_FLAG(runtime) ((runtime)->scanFlag = REVERSE_SCAN) -#define TSWINDOW_IS_EQUAL(t1, t2) (((t1).skey == (t2).skey) && ((t1).ekey == (t2).ekey)) - #define SDATA_BLOCK_INITIALIZER \ (SDataBlockInfo) { {0}, 0 } diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index e1ea23226b..e1f9a9f6a4 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -571,6 +571,8 @@ static int32_t jsonToLogicProjectNode(const SJson* pJson, void* pObj) { static const char* jkFillLogicPlanMode = "Mode"; static const char* jkFillLogicPlanWStartTs = "WStartTs"; static const char* jkFillLogicPlanValues = "Values"; +static const char* jkFillLogicPlanStartTime = "StartTime"; +static const char* jkFillLogicPlanEndTime = "EndTime"; static int32_t logicFillNodeToJson(const void* pObj, SJson* pJson) { const SFillLogicNode* pNode = (const SFillLogicNode*)pObj; @@ -585,6 +587,12 @@ static int32_t logicFillNodeToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = tjsonAddObject(pJson, jkFillLogicPlanValues, nodeToJson, pNode->pValues); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillLogicPlanStartTime, pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillLogicPlanEndTime, pNode->timeRange.ekey); + } return code; } @@ -602,6 +610,12 @@ static int32_t jsonToLogicFillNode(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeObject(pJson, jkFillLogicPlanValues, &pNode->pValues); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillLogicPlanStartTime, &pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillLogicPlanEndTime, &pNode->timeRange.ekey); + } return code; } @@ -1475,6 +1489,8 @@ static const char* jkFillPhysiPlanMode = "Mode"; static const char* jkFillPhysiPlanWStartTs = "WStartTs"; static const char* jkFillPhysiPlanValues = "Values"; static const char* jkFillPhysiPlanTargets = "Targets"; +static const char* jkFillPhysiPlanStartTime = "StartTime"; +static const char* jkFillPhysiPlanEndTime = "EndTime"; static int32_t physiFillNodeToJson(const void* pObj, SJson* pJson) { const SFillPhysiNode* pNode = (const SFillPhysiNode*)pObj; @@ -1492,6 +1508,12 @@ static int32_t physiFillNodeToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = nodeListToJson(pJson, jkFillPhysiPlanTargets, pNode->pTargets); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillPhysiPlanStartTime, pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillPhysiPlanEndTime, pNode->timeRange.ekey); + } return code; } @@ -1512,6 +1534,12 @@ static int32_t jsonToPhysiFillNode(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeList(pJson, jkFillPhysiPlanTargets, &pNode->pTargets); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillPhysiPlanStartTime, &pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillPhysiPlanEndTime, &pNode->timeRange.ekey); + } return code; } @@ -2409,6 +2437,8 @@ static int32_t jsonToNodeListNode(const SJson* pJson, void* pObj) { static const char* jkFillMode = "Mode"; static const char* jkFillValues = "Values"; static const char* jkFillWStartTs = "WStartTs"; +static const char* jkFillStartTime = "StartTime"; +static const char* jkFillEndTime = "EndTime"; static int32_t fillNodeToJson(const void* pObj, SJson* pJson) { const SFillNode* pNode = (const SFillNode*)pObj; @@ -2420,6 +2450,12 @@ static int32_t fillNodeToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = tjsonAddObject(pJson, jkFillWStartTs, nodeToJson, pNode->pWStartTs); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillStartTime, pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkFillEndTime, pNode->timeRange.ekey); + } return code; } @@ -2434,6 +2470,12 @@ static int32_t jsonToFillNode(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeObject(pJson, jkFillWStartTs, &pNode->pWStartTs); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillStartTime, &pNode->timeRange.skey); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetBigIntValue(pJson, jkFillEndTime, &pNode->timeRange.ekey); + } return code; } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 2d08342214..d9b250998e 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -17,6 +17,7 @@ #include "catalog.h" #include "cmdnodes.h" +#include "filter.h" #include "functionMgt.h" #include "parUtil.h" #include "scalar.h" @@ -468,19 +469,19 @@ static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) { pVal->datum.b = (0 == strcasecmp(pVal->literal, "true")); *(bool*)&pVal->typeData = pVal->datum.b; break; - case TSDB_DATA_TYPE_TINYINT:{ + case TSDB_DATA_TYPE_TINYINT: { char* endPtr = NULL; pVal->datum.i = strtoll(pVal->literal, &endPtr, 10); *(int8_t*)&pVal->typeData = pVal->datum.i; break; } - case TSDB_DATA_TYPE_SMALLINT:{ + case TSDB_DATA_TYPE_SMALLINT: { char* endPtr = NULL; pVal->datum.i = strtoll(pVal->literal, &endPtr, 10); *(int16_t*)&pVal->typeData = pVal->datum.i; break; } - case TSDB_DATA_TYPE_INT:{ + case TSDB_DATA_TYPE_INT: { char* endPtr = NULL; pVal->datum.i = strtoll(pVal->literal, &endPtr, 10); *(int32_t*)&pVal->typeData = pVal->datum.i; @@ -489,43 +490,43 @@ static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) { case TSDB_DATA_TYPE_BIGINT: { char* endPtr = NULL; pVal->datum.i = strtoll(pVal->literal, &endPtr, 10); - *(int64_t*)&pVal->typeData = pVal->datum.i; + *(int64_t*)&pVal->typeData = pVal->datum.i; break; } - case TSDB_DATA_TYPE_UTINYINT:{ + case TSDB_DATA_TYPE_UTINYINT: { char* endPtr = NULL; pVal->datum.u = strtoull(pVal->literal, &endPtr, 10); - *(uint8_t*)&pVal->typeData = pVal->datum.u; + *(uint8_t*)&pVal->typeData = pVal->datum.u; break; } - case TSDB_DATA_TYPE_USMALLINT:{ + case TSDB_DATA_TYPE_USMALLINT: { char* endPtr = NULL; pVal->datum.u = strtoull(pVal->literal, &endPtr, 10); - *(uint16_t*)&pVal->typeData = pVal->datum.u; + *(uint16_t*)&pVal->typeData = pVal->datum.u; break; } - case TSDB_DATA_TYPE_UINT:{ + case TSDB_DATA_TYPE_UINT: { char* endPtr = NULL; pVal->datum.u = strtoull(pVal->literal, &endPtr, 10); - *(uint32_t*)&pVal->typeData = pVal->datum.u; + *(uint32_t*)&pVal->typeData = pVal->datum.u; break; } case TSDB_DATA_TYPE_UBIGINT: { char* endPtr = NULL; pVal->datum.u = strtoull(pVal->literal, &endPtr, 10); - *(uint64_t*)&pVal->typeData = pVal->datum.u; + *(uint64_t*)&pVal->typeData = pVal->datum.u; break; } - case TSDB_DATA_TYPE_FLOAT:{ + case TSDB_DATA_TYPE_FLOAT: { char* endPtr = NULL; pVal->datum.d = strtold(pVal->literal, &endPtr); - *(float*)&pVal->typeData = pVal->datum.d; + *(float*)&pVal->typeData = pVal->datum.d; break; } case TSDB_DATA_TYPE_DOUBLE: { char* endPtr = NULL; pVal->datum.d = strtold(pVal->literal, &endPtr); - *(double*)&pVal->typeData = pVal->datum.d; + *(double*)&pVal->typeData = pVal->datum.d; break; } case TSDB_DATA_TYPE_VARCHAR: @@ -543,7 +544,7 @@ static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) { TSDB_CODE_SUCCESS) { return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal); } - *(int64_t*)&pVal->typeData = pVal->datum.i; + *(int64_t*)&pVal->typeData = pVal->datum.i; break; } case TSDB_DATA_TYPE_NCHAR: @@ -1244,6 +1245,113 @@ static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) { return TSDB_CODE_SUCCESS; } +static EDealRes isPrimaryKeyCondImpl(SNode* pNode, void* pContext) { + if (QUERY_NODE_COLUMN == nodeType(pNode)) { + *((bool*)pContext) = ((PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) ? true : false); + return *((bool*)pContext) ? DEAL_RES_CONTINUE : DEAL_RES_END; + } + return DEAL_RES_CONTINUE; +} + +static bool isPrimaryKeyCond(SNode* pNode) { + bool isPrimaryKeyCond = false; + nodesWalkExpr(pNode, isPrimaryKeyCondImpl, &isPrimaryKeyCond); + return isPrimaryKeyCond; +} + +static int32_t getTimeRangeFromLogicCond(STranslateContext* pCxt, SLogicConditionNode* pLogicCond, + STimeWindow* pTimeRange) { + SNodeList* pPrimaryKeyConds = NULL; + SNode* pCond = NULL; + FOREACH(pCond, pLogicCond->pParameterList) { + if (isPrimaryKeyCond(pCond)) { + if (TSDB_CODE_SUCCESS != nodesListMakeAppend(&pPrimaryKeyConds, pCond)) { + nodesClearList(pPrimaryKeyConds); + return TSDB_CODE_OUT_OF_MEMORY; + } + } + } + + if (NULL == pPrimaryKeyConds) { + *pTimeRange = TSWINDOW_INITIALIZER; + return TSDB_CODE_SUCCESS; + } + + SLogicConditionNode* pPrimaryKeyLogicCond = nodesMakeNode(QUERY_NODE_LOGIC_CONDITION); + if (NULL == pPrimaryKeyLogicCond) { + nodesClearList(pPrimaryKeyConds); + return TSDB_CODE_OUT_OF_MEMORY; + } + pPrimaryKeyLogicCond->condType = LOGIC_COND_TYPE_AND; + pPrimaryKeyLogicCond->pParameterList = pPrimaryKeyConds; + bool isStrict = false; + int32_t code = filterGetTimeRange((SNode*)pPrimaryKeyLogicCond, pTimeRange, &isStrict); + nodesClearList(pPrimaryKeyConds); + pPrimaryKeyLogicCond->pParameterList = NULL; + nodesDestroyNode(pPrimaryKeyLogicCond); + return code; +} + +static int32_t getTimeRange(STranslateContext* pCxt, SNode* pWhere, STimeWindow* pTimeRange) { + if (NULL == pWhere) { + *pTimeRange = TSWINDOW_INITIALIZER; + return TSDB_CODE_SUCCESS; + } + + if (QUERY_NODE_LOGIC_CONDITION == nodeType(pWhere) && + LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)pWhere)->condType) { + return getTimeRangeFromLogicCond(pCxt, (SLogicConditionNode*)pWhere, pTimeRange); + } + + if (isPrimaryKeyCond(pWhere)) { + bool isStrict = false; + return filterGetTimeRange(pWhere, pTimeRange, &isStrict); + } else { + *pTimeRange = TSWINDOW_INITIALIZER; + } + return TSDB_CODE_SUCCESS; +} + +static int32_t checkFill(STranslateContext* pCxt, SIntervalWindowNode* pInterval) { + SFillNode* pFill = (SFillNode*)pInterval->pFill; + if (TSWINDOW_IS_EQUAL(pFill->timeRange, TSWINDOW_INITIALIZER) || + TSWINDOW_IS_EQUAL(pFill->timeRange, TSWINDOW_DESC_INITIALIZER)) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE); + } + + int64_t timeRange = TABS(pFill->timeRange.skey - pFill->timeRange.ekey); + int64_t intervalRange = 0; + SValueNode* pInter = (SValueNode*)pInterval->pInterval; + if (TIME_IS_VAR_DURATION(pInter->unit)) { + int64_t f = 1; + if (pInter->unit == 'n') { + f = 30L * MILLISECOND_PER_DAY; + } else if (pInter->unit == 'y') { + f = 365L * MILLISECOND_PER_DAY; + } + intervalRange = pInter->datum.i * f; + } else { + intervalRange = pInter->datum.i; + } + if ((timeRange == 0) || (timeRange / intervalRange) >= MAX_INTERVAL_TIME_WINDOW) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE); + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t translateFill(STranslateContext* pCxt, SNode* pWhere, SIntervalWindowNode* pInterval) { + if (NULL == pInterval->pFill) { + return TSDB_CODE_SUCCESS; + } + + int32_t code = getTimeRange(pCxt, pWhere, &(((SFillNode*)pInterval->pFill)->timeRange)); + if (TSDB_CODE_SUCCESS == code) { + code = checkFill(pCxt, pInterval); + } + return code; +} + static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char unit) { int64_t days = convertTimeFromPrecisionToUnit(val, fromPrecision, 'd'); switch (unit) { @@ -1266,7 +1374,7 @@ static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char uni return -1; } -static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* pInterval) { +static int32_t checkIntervalWindow(STranslateContext* pCxt, SNode* pWhere, SIntervalWindowNode* pInterval) { uint8_t precision = ((SColumnNode*)pInterval->pCol)->node.resType.precision; SValueNode* pInter = (SValueNode*)pInterval->pInterval; @@ -1308,7 +1416,7 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* } } - return TSDB_CODE_SUCCESS; + return translateFill(pCxt, pWhere, pInterval); } static EDealRes checkStateExpr(SNode* pNode, void* pContext) { @@ -1345,28 +1453,28 @@ static int32_t checkSessionWindow(STranslateContext* pCxt, SSessionWindowNode* p return TSDB_CODE_SUCCESS; } -static int32_t checkWindow(STranslateContext* pCxt, SNode* pWindow) { - switch (nodeType(pWindow)) { +static int32_t checkWindow(STranslateContext* pCxt, SSelectStmt* pSelect) { + switch (nodeType(pSelect->pWindow)) { case QUERY_NODE_STATE_WINDOW: - return checkStateWindow(pCxt, (SStateWindowNode*)pWindow); + return checkStateWindow(pCxt, (SStateWindowNode*)pSelect->pWindow); case QUERY_NODE_SESSION_WINDOW: - return checkSessionWindow(pCxt, (SSessionWindowNode*)pWindow); + return checkSessionWindow(pCxt, (SSessionWindowNode*)pSelect->pWindow); case QUERY_NODE_INTERVAL_WINDOW: - return checkIntervalWindow(pCxt, (SIntervalWindowNode*)pWindow); + return checkIntervalWindow(pCxt, pSelect->pWhere, (SIntervalWindowNode*)pSelect->pWindow); default: break; } return TSDB_CODE_SUCCESS; } -static int32_t translateWindow(STranslateContext* pCxt, SNode* pWindow) { - if (NULL == pWindow) { +static int32_t translateWindow(STranslateContext* pCxt, SSelectStmt* pSelect) { + if (NULL == pSelect->pWindow) { return TSDB_CODE_SUCCESS; } pCxt->currClause = SQL_CLAUSE_WINDOW; - int32_t code = translateExpr(pCxt, pWindow); + int32_t code = translateExpr(pCxt, pSelect->pWindow); if (TSDB_CODE_SUCCESS == code) { - code = checkWindow(pCxt, pWindow); + code = checkWindow(pCxt, pSelect); } return code; } @@ -1485,7 +1593,7 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) { code = translatePartitionBy(pCxt, pSelect->pPartitionByList); } if (TSDB_CODE_SUCCESS == code) { - code = translateWindow(pCxt, pSelect->pWindow); + code = translateWindow(pCxt, pSelect); } if (TSDB_CODE_SUCCESS == code) { code = translateGroupBy(pCxt, pSelect); diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 2bf4071d33..e839536218 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -128,6 +128,8 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "Invalid topic query"; case TSDB_CODE_PAR_INVALID_DROP_STABLE: return "Cannot drop super table in batch"; + case TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE: + return "start(end) time of query range required or time range too large"; case TSDB_CODE_OUT_OF_MEMORY: return "Out of memory"; default: @@ -140,7 +142,6 @@ int32_t generateSyntaxErrMsg(SMsgBuf* pBuf, int32_t errCode, ...) { va_start(vArgList, errCode); vsnprintf(pBuf->buf, pBuf->len, getSyntaxErrFormat(errCode), vArgList); va_end(vArgList); - terrno = errCode; return errCode; } diff --git a/source/libs/parser/test/parSelectTest.cpp b/source/libs/parser/test/parSelectTest.cpp index e765728cdf..c80a0341d2 100644 --- a/source/libs/parser/test/parSelectTest.cpp +++ b/source/libs/parser/test/parSelectTest.cpp @@ -32,7 +32,7 @@ TEST_F(ParserSelectTest, basic) { run("SELECT ts, t.c1 FROM (SELECT * FROM t1) t"); - run("SELECT * FROM t1 tt1, t1 tt2 where tt1.c1 = tt2.c1"); + run("SELECT * FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1"); } TEST_F(ParserSelectTest, constant) { @@ -43,7 +43,7 @@ TEST_F(ParserSelectTest, constant) { run("SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", " "timestamp '2022-02-09 17:30:20', true, false, 15s FROM t1"); - run("SELECT 123 + 45 FROM t1 where 2 - 1"); + run("SELECT 123 + 45 FROM t1 WHERE 2 - 1"); } TEST_F(ParserSelectTest, expression) { @@ -59,9 +59,9 @@ TEST_F(ParserSelectTest, expression) { TEST_F(ParserSelectTest, condition) { useDb("root", "test"); - run("SELECT c1 FROM t1 where ts in (true, false)"); + run("SELECT c1 FROM t1 WHERE ts in (true, false)"); - run("SELECT * FROM t1 where c1 > 10 and c1 is not null"); + run("SELECT * FROM t1 WHERE c1 > 10 and c1 is not null"); } TEST_F(ParserSelectTest, pseudoColumn) { @@ -77,7 +77,7 @@ TEST_F(ParserSelectTest, multiResFunc) { run("SELECT last(c1, c2), first(t1.*), last_row(c3) FROM t1"); - run("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 where t1.ts = t2.ts"); + run("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts"); } TEST_F(ParserSelectTest, timelineFunc) { @@ -96,29 +96,29 @@ TEST_F(ParserSelectTest, clause) { useDb("root", "test"); // group by clause - run("SELECT COUNT(*) cnt FROM t1 where c1 > 0"); + run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0"); - run("SELECT COUNT(*), c2 cnt FROM t1 where c1 > 0 group by c2"); + run("SELECT COUNT(*), c2 cnt FROM t1 WHERE c1 > 0 group by c2"); - run("SELECT COUNT(*) cnt FROM t1 where c1 > 0 group by c2 having COUNT(c1) > 10"); + run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 having COUNT(c1) > 10"); - run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 where c1 > 0 group by c2, c1"); + 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"); + run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 group by c1 + 10, c2"); // 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 cnt"); - run("SELECT COUNT(*) cnt FROM t1 where c1 > 0 group by c2 order by 1"); + run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 order by 1"); // distinct clause - // run("SELECT distinct c1, c2 FROM t1 where c1 > 0 order by c1"); + // 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"); + // run("SELECT distinct c1 + 10, c2 FROM t1 WHERE c1 > 0 order by c1 + 10, c2"); - // run("SELECT distinct c1 + 10 cc1, c2 cc2 FROM t1 where c1 > 0 order by cc1, c2"); + // run("SELECT distinct c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 order by cc1, c2"); - // run("SELECT distinct COUNT(c2) FROM t1 where c1 > 0 group by c1 order by COUNT(c2)"); + // run("SELECT distinct COUNT(c2) FROM t1 WHERE c1 > 0 group by c1 order by COUNT(c2)"); } // INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)] @@ -133,7 +133,8 @@ TEST_F(ParserSelectTest, interval) { // INTERVAL(interval_val, interval_offset) SLIDING (sliding_val) run("SELECT COUNT(*) FROM t1 INTERVAL(10s, 5s) SLIDING(7s)"); // INTERVAL(interval_val) FILL(NONE) - run("SELECT COUNT(*) FROM t1 INTERVAL(10s) FILL(NONE)"); + run("SELECT COUNT(*) FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' " + "INTERVAL(10s) FILL(NONE)"); } TEST_F(ParserSelectTest, semanticError) { @@ -152,7 +153,7 @@ TEST_F(ParserSelectTest, semanticError) { run("SELECT t2.c1 FROM t1", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE); // TSDB_CODE_PAR_AMBIGUOUS_COLUMN - run("SELECT c2 FROM t1 tt1, t1 tt2 where tt1.c1 = tt2.c1", TSDB_CODE_PAR_AMBIGUOUS_COLUMN, PARSER_STAGE_TRANSLATE); + run("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1", TSDB_CODE_PAR_AMBIGUOUS_COLUMN, PARSER_STAGE_TRANSLATE); // TSDB_CODE_PAR_WRONG_VALUE_TYPE run("SELECT timestamp '2010' FROM t1", TSDB_CODE_PAR_WRONG_VALUE_TYPE, PARSER_STAGE_TRANSLATE); @@ -161,7 +162,7 @@ TEST_F(ParserSelectTest, semanticError) { run("SELECT c2 FROM t1 tt1 join t1 tt2 on COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE); - run("SELECT c2 FROM t1 where COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE); + run("SELECT c2 FROM t1 WHERE COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE); run("SELECT c2 FROM t1 group by COUNT(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE); @@ -190,13 +191,13 @@ TEST_F(ParserSelectTest, semanticError) { run("SELECT c1 FROM t1 order by COUNT(*)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE); // TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION - run("SELECT distinct c1, c2 FROM t1 where c1 > 0 order by ts", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, + run("SELECT distinct c1, c2 FROM t1 WHERE c1 > 0 order by ts", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, PARSER_STAGE_TRANSLATE); - run("SELECT distinct c1 FROM t1 where c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, + run("SELECT distinct c1 FROM t1 WHERE c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, PARSER_STAGE_TRANSLATE); - run("SELECT distinct c2 FROM t1 where c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, + run("SELECT distinct c2 FROM t1 WHERE c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION, PARSER_STAGE_TRANSLATE); } diff --git a/source/libs/planner/inc/planInt.h b/source/libs/planner/inc/planInt.h index e6534f710d..4640ed99bd 100644 --- a/source/libs/planner/inc/planInt.h +++ b/source/libs/planner/inc/planInt.h @@ -21,6 +21,7 @@ extern "C" { #endif #include "planner.h" +#include "taoserror.h" #define QUERY_POLICY_VNODE 1 #define QUERY_POLICY_HYBRID 2 @@ -33,6 +34,8 @@ extern "C" { #define planDebug(param, ...) qDebug("PLAN: " param, __VA_ARGS__) #define planTrace(param, ...) qTrace("PLAN: " param, __VA_ARGS__) +int32_t generateUsageErrMsg(char* pBuf, int32_t len, int32_t errCode, ...); + int32_t createLogicPlan(SPlanContext* pCxt, SLogicNode** pLogicNode); int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode); int32_t splitLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode, SLogicSubplan** pLogicSubplan); diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index fc0c5d5431..0bc700696b 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -597,6 +597,7 @@ static int32_t createFillLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect int32_t code = nodesCollectColumns(pSelect, SQL_CLAUSE_WINDOW, NULL, COLLECT_COL_TYPE_ALL, &pFill->node.pTargets); pFill->mode = pFillNode->mode; + pFill->timeRange = pFillNode->timeRange; pFill->pValues = nodesCloneNode(pFillNode->pValues); pFill->pWStartTs = nodesCloneNode(pFillNode->pWStartTs); if ((NULL != pFillNode->pValues && NULL == pFill->pValues) || NULL == pFill->pWStartTs) { diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 47dcd9ce86..67609355d7 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -554,22 +554,19 @@ static bool cpdIsPrimaryKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) { static int32_t cpdCheckOpCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode* pOnCond) { if (!cpdIsPrimaryKeyEqualCond(pJoin, pOnCond)) { - snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression"); - return TSDB_CODE_FAILED; + return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL); } return TSDB_CODE_SUCCESS; } static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SLogicConditionNode* pOnCond) { if (LOGIC_COND_TYPE_AND != pOnCond->condType) { - snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression"); - return TSDB_CODE_FAILED; + return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL); } SNode* pCond = NULL; FOREACH(pCond, pOnCond->pParameterList) { if (!cpdIsPrimaryKeyEqualCond(pJoin, pCond)) { - snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression"); - return TSDB_CODE_FAILED; + return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL); } } return TSDB_CODE_SUCCESS; @@ -577,8 +574,7 @@ static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, static int32_t cpdCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) { if (NULL == pJoin->pOnConditions) { - snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "not support cross join"); - return TSDB_CODE_FAILED; + return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN); } if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pOnConditions)) { return cpdCheckLogicCond(pCxt, pJoin, (SLogicConditionNode*)pJoin->pOnConditions); diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index 10dac9422a..05b48d2d6a 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -1037,6 +1037,9 @@ static int32_t createFillPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren return TSDB_CODE_OUT_OF_MEMORY; } + pFill->mode = pFillNode->mode; + pFill->timeRange = pFillNode->timeRange; + SDataBlockDescNode* pChildTupe = (((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc); int32_t code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->node.pTargets, &pFill->pTargets); if (TSDB_CODE_SUCCESS == code) { diff --git a/source/libs/planner/src/planUtil.c b/source/libs/planner/src/planUtil.c new file mode 100644 index 0000000000..36625b28fb --- /dev/null +++ b/source/libs/planner/src/planUtil.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "planInt.h" + +static char* getUsageErrFormat(int32_t errCode) { + switch (errCode) { + case TSDB_CODE_PLAN_EXPECTED_TS_EQUAL: + return "l.ts = r.ts is expected in join expression"; + case TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN: + return "not support cross join"; + default: + break; + } + return "Unknown error"; +} + +int32_t generateUsageErrMsg(char* pBuf, int32_t len, int32_t errCode, ...) { + va_list vArgList; + va_start(vArgList, errCode); + vsnprintf(pBuf, len, getUsageErrFormat(errCode), vArgList); + va_end(vArgList); + return errCode; +} diff --git a/source/libs/planner/test/planBasicTest.cpp b/source/libs/planner/test/planBasicTest.cpp index 05a009d79d..639af2875e 100644 --- a/source/libs/planner/test/planBasicTest.cpp +++ b/source/libs/planner/test/planBasicTest.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2019 TAOS Data, Inc. * - * This program is free software: you can use, redistribute, and/or modify + * This program is free software: you can use, redistribute, AND/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * @@ -20,30 +20,32 @@ using namespace std; class PlanBasicTest : public PlannerTestBase {}; -TEST_F(PlanBasicTest, select) { +TEST_F(PlanBasicTest, selectClause) { useDb("root", "test"); - run("select * from t1"); - run("select 1 from t1"); - run("select * from st1"); - run("select 1 from st1"); + run("SELECT * FROM t1"); + run("SELECT 1 FROM t1"); + run("SELECT * FROM st1"); + run("SELECT 1 FROM st1"); } -TEST_F(PlanBasicTest, where) { +TEST_F(PlanBasicTest, whereClause) { useDb("root", "test"); - run("select * from t1 where c1 > 10"); + run("SELECT * FROM t1 WHERE c1 > 10"); + + run("SELECT * FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59'"); } -TEST_F(PlanBasicTest, join) { +TEST_F(PlanBasicTest, joinClause) { useDb("root", "test"); - run("select t1.c1, t2.c2 from st1s1 t1, st1s2 t2 where t1.ts = t2.ts"); - run("select t1.c1, t2.c2 from st1s1 t1 join st1s2 t2 on t1.ts = t2.ts"); + run("SELECT t1.c1, t2.c2 FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts"); + run("SELECT t1.c1, t2.c2 FROM st1s1 t1 JOIN st1s2 t2 ON t1.ts = t2.ts"); } TEST_F(PlanBasicTest, func) { useDb("root", "test"); - run("select diff(c1) from t1"); + run("SELECT DIFF(c1) FROM t1"); } diff --git a/source/libs/planner/test/planIntervalTest.cpp b/source/libs/planner/test/planIntervalTest.cpp index 88810a0eb8..f1bcd747c0 100644 --- a/source/libs/planner/test/planIntervalTest.cpp +++ b/source/libs/planner/test/planIntervalTest.cpp @@ -35,7 +35,10 @@ TEST_F(PlanIntervalTest, pseudoCol) { TEST_F(PlanIntervalTest, fill) { useDb("root", "test"); - run("SELECT COUNT(*) FROM t1 INTERVAL(10s) FILL(LINEAR)"); + run("SELECT COUNT(*) FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' " + "INTERVAL(10s) FILL(LINEAR)"); - run("SELECT COUNT(*), sum(c1) FROM t1 INTERVAL(10s) FILL(VALUE, 10, 20)"); + run("SELECT COUNT(*), SUM(c1) FROM t1 " + "WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' " + "INTERVAL(10s) FILL(VALUE, 10, 20)"); } -- GitLab