From c40b590ad8914e8a2b435865abcac6646d9d07de Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Sat, 16 Apr 2022 17:27:54 +0800 Subject: [PATCH] enh: window clause validity check --- include/libs/nodes/plannodes.h | 11 +- include/libs/nodes/querynodes.h | 5 +- include/util/taoserror.h | 13 +- source/libs/command/src/explain.c | 11 +- source/libs/executor/src/executorimpl.c | 2 +- source/libs/function/src/builtins.c | 2 +- source/libs/nodes/src/nodesCodeFuncs.c | 42 +++++-- source/libs/nodes/src/nodesTraverseFuncs.c | 8 +- source/libs/parser/src/parAstCreater.c | 4 +- source/libs/parser/src/parTranslater.c | 134 ++++++++++++++++++--- source/libs/parser/src/parUtil.c | 26 +++- source/libs/planner/src/planOptimizer.c | 12 ++ source/libs/planner/src/planPhysiCreater.c | 6 +- source/libs/scalar/src/sclfunc.c | 8 +- 14 files changed, 236 insertions(+), 48 deletions(-) diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h index 9d4f554c2c..5a156704c2 100644 --- a/include/libs/nodes/plannodes.h +++ b/include/libs/nodes/plannodes.h @@ -53,6 +53,11 @@ typedef struct SScanLogicNode { double ratio; SNodeList* pDynamicScanFuncs; int32_t dataRequired; + int64_t interval; + int64_t offset; + int64_t sliding; + int8_t intervalUnit; + int8_t slidingUnit; } SScanLogicNode; typedef struct SJoinLogicNode { @@ -208,6 +213,11 @@ typedef struct STableScanPhysiNode { double ratio; int32_t dataRequired; SNodeList* pDynamicScanFuncs; + int64_t interval; + int64_t offset; + int64_t sliding; + int8_t intervalUnit; + int8_t slidingUnit; } STableScanPhysiNode; typedef STableScanPhysiNode STableSeqScanPhysiNode; @@ -264,7 +274,6 @@ typedef struct SIntervalPhysiNode { int64_t sliding; int8_t intervalUnit; int8_t slidingUnit; - uint8_t precision; SFillNode* pFill; } SIntervalPhysiNode; diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 3e78da63de..6d805a3226 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -57,6 +57,7 @@ typedef enum EColumnType { typedef struct SColumnNode { SExprNode node; // QUERY_NODE_COLUMN uint64_t tableId; + int8_t tableType; col_id_t colId; EColumnType colType; // column or tag char dbName[TSDB_DB_NAME_LEN]; @@ -196,8 +197,8 @@ typedef struct SStateWindowNode { typedef struct SSessionWindowNode { ENodeType type; // QUERY_NODE_SESSION_WINDOW - SNode* pCol; // timestamp primary key - SNode* pGap; // gap between two session window(in microseconds) + SColumnNode* pCol; // timestamp primary key + SValueNode* pGap; // gap between two session window(in microseconds) } SSessionWindowNode; typedef struct SIntervalWindowNode { diff --git a/include/util/taoserror.h b/include/util/taoserror.h index d51217874a..c5b477343d 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -579,7 +579,7 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_INVALID_PORT TAOS_DEF_ERROR_CODE(0, 0x2612) #define TSDB_CODE_PAR_INVALID_ENDPOINT TAOS_DEF_ERROR_CODE(0, 0x2613) #define TSDB_CODE_PAR_EXPRIE_STATEMENT TAOS_DEF_ERROR_CODE(0, 0x2614) -#define TSDB_CODE_PAR_INTERVAL_VALUE_TOO_SMALL TAOS_DEF_ERROR_CODE(0, 0x2615) +#define TSDB_CODE_PAR_INTER_VALUE_TOO_SMALL TAOS_DEF_ERROR_CODE(0, 0x2615) #define TSDB_CODE_PAR_DB_NOT_SPECIFIED TAOS_DEF_ERROR_CODE(0, 0x2616) #define TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME TAOS_DEF_ERROR_CODE(0, 0x2617) #define TSDB_CODE_PAR_CORRESPONDING_STABLE_ERR TAOS_DEF_ERROR_CODE(0, 0x2618) @@ -598,6 +598,17 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_INVALID_OPTION_UNIT TAOS_DEF_ERROR_CODE(0, 0x2625) #define TSDB_CODE_PAR_INVALID_KEEP_UNIT TAOS_DEF_ERROR_CODE(0, 0x2626) #define TSDB_CODE_PAR_AGG_FUNC_NESTING TAOS_DEF_ERROR_CODE(0, 0x2627) +#define TSDB_CODE_PAR_INVALID_STATE_WIN_TYPE TAOS_DEF_ERROR_CODE(0, 0x2628) +#define TSDB_CODE_PAR_INVALID_STATE_WIN_COL TAOS_DEF_ERROR_CODE(0, 0x2629) +#define TSDB_CODE_PAR_INVALID_STATE_WIN_TABLE TAOS_DEF_ERROR_CODE(0, 0x262A) +#define TSDB_CODE_PAR_INTER_SESSION_GAP TAOS_DEF_ERROR_CODE(0, 0x262B) +#define TSDB_CODE_PAR_INTER_SESSION_COL TAOS_DEF_ERROR_CODE(0, 0x262C) +#define TSDB_CODE_PAR_INTER_OFFSET_NEGATIVE TAOS_DEF_ERROR_CODE(0, 0x262D) +#define TSDB_CODE_PAR_INTER_OFFSET_UNIT TAOS_DEF_ERROR_CODE(0, 0x262E) +#define TSDB_CODE_PAR_INTER_OFFSET_TOO_BIG TAOS_DEF_ERROR_CODE(0, 0x262F) +#define TSDB_CODE_PAR_INTER_SLIDING_UNIT TAOS_DEF_ERROR_CODE(0, 0x2630) +#define TSDB_CODE_PAR_INTER_SLIDING_TOO_BIG TAOS_DEF_ERROR_CODE(0, 0x2631) +#define TSDB_CODE_PAR_INTER_SLIDING_TOO_SMALL TAOS_DEF_ERROR_CODE(0, 0x2632) //planner #define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700) diff --git a/source/libs/command/src/explain.c b/source/libs/command/src/explain.c index e08e9cf276..4853bb4eb3 100644 --- a/source/libs/command/src/explain.c +++ b/source/libs/command/src/explain.c @@ -316,6 +316,9 @@ int32_t qExplainResAppendRow(SExplainCtx *ctx, char *tbuf, int32_t len, int32_t return TSDB_CODE_SUCCESS; } +static uint8_t getIntervalPrecision(SIntervalPhysiNode* pIntNode) { + return ((SColumnNode*)pIntNode->window.pTspk)->node.resType.precision; +} int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, int32_t level) { int32_t tlen = 0; @@ -658,10 +661,10 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pIntNode->window.node.pOutputDataBlockDesc->outputRowSize); EXPLAIN_ROW_END(); QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1)); - - EXPLAIN_ROW_NEW(level + 1, EXPLAIN_TIME_WINDOWS_FORMAT, INVERAL_TIME_FROM_PRECISION_TO_UNIT(pIntNode->interval, pIntNode->intervalUnit, pIntNode->precision), - pIntNode->intervalUnit, pIntNode->offset, getPrecisionUnit(pIntNode->precision), - INVERAL_TIME_FROM_PRECISION_TO_UNIT(pIntNode->sliding, pIntNode->slidingUnit, pIntNode->precision), pIntNode->slidingUnit); + uint8_t precision = getIntervalPrecision(pIntNode); + EXPLAIN_ROW_NEW(level + 1, EXPLAIN_TIME_WINDOWS_FORMAT, INVERAL_TIME_FROM_PRECISION_TO_UNIT(pIntNode->interval, pIntNode->intervalUnit, precision), + pIntNode->intervalUnit, pIntNode->offset, getPrecisionUnit(precision), + INVERAL_TIME_FROM_PRECISION_TO_UNIT(pIntNode->sliding, pIntNode->slidingUnit, precision), pIntNode->slidingUnit); EXPLAIN_ROW_END(); QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1)); diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 3e2f95a27c..8272c59eea 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -6831,7 +6831,7 @@ SOperatorInfo* createOperatorTree(SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo .intervalUnit = pIntervalPhyNode->intervalUnit, .slidingUnit = pIntervalPhyNode->slidingUnit, .offset = pIntervalPhyNode->offset, - .precision = pIntervalPhyNode->precision + .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision }; int32_t primaryTsSlotId = ((SColumnNode*) pIntervalPhyNode->window.pTspk)->slotId; diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index bba5145812..d58c0e166f 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -399,7 +399,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { { .name = "sum", .type = FUNCTION_TYPE_SUM, - .classification = FUNC_MGT_AGG_FUNC, + .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SPECIAL_DATA_REQUIRED, .translateFunc = translateSum, .getEnvFunc = getSumFuncEnv, .initFunc = functionSetup, diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index 2c8a938a5a..7eb472dad8 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -748,6 +748,11 @@ static const char* jkTableScanPhysiPlanEndKey = "EndKey"; static const char* jkTableScanPhysiPlanRatio = "Ratio"; static const char* jkTableScanPhysiPlanDataRequired = "DataRequired"; static const char* jkTableScanPhysiPlanDynamicScanFuncs = "DynamicScanFuncs"; +static const char* jkTableScanPhysiPlanInterval = "Interval"; +static const char* jkTableScanPhysiPlanOffset = "Offset"; +static const char* jkTableScanPhysiPlanSliding = "Sliding"; +static const char* jkTableScanPhysiPlanIntervalUnit = "intervalUnit"; +static const char* jkTableScanPhysiPlanSlidingUnit = "slidingUnit"; static int32_t physiTableScanNodeToJson(const void* pObj, SJson* pJson) { const STableScanPhysiNode* pNode = (const STableScanPhysiNode*)pObj; @@ -771,6 +776,21 @@ static int32_t physiTableScanNodeToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = nodeListToJson(pJson, jkTableScanPhysiPlanDynamicScanFuncs, pNode->pDynamicScanFuncs); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanInterval, pNode->interval); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanOffset, pNode->offset); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanSliding, pNode->sliding); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanIntervalUnit, pNode->intervalUnit); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanSlidingUnit, pNode->slidingUnit); + } return code; } @@ -797,6 +817,21 @@ static int32_t jsonToPhysiTableScanNode(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeList(pJson, jkTableScanPhysiPlanDynamicScanFuncs, &pNode->pDynamicScanFuncs); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetNumberValue(pJson, jkTableScanPhysiPlanInterval, pNode->interval); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetNumberValue(pJson, jkTableScanPhysiPlanOffset, pNode->offset); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetNumberValue(pJson, jkTableScanPhysiPlanSliding, pNode->sliding); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetNumberValue(pJson, jkTableScanPhysiPlanIntervalUnit, pNode->intervalUnit); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonGetNumberValue(pJson, jkTableScanPhysiPlanSlidingUnit, pNode->slidingUnit); + } return code; } @@ -1159,7 +1194,6 @@ static const char* jkIntervalPhysiPlanSliding = "Sliding"; static const char* jkIntervalPhysiPlanIntervalUnit = "intervalUnit"; static const char* jkIntervalPhysiPlanSlidingUnit = "slidingUnit"; static const char* jkIntervalPhysiPlanFill = "Fill"; -static const char* jkIntervalPhysiPlanPrecision = "Precision"; static int32_t physiIntervalNodeToJson(const void* pObj, SJson* pJson) { const SIntervalPhysiNode* pNode = (const SIntervalPhysiNode*)pObj; @@ -1183,9 +1217,6 @@ static int32_t physiIntervalNodeToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = tjsonAddObject(pJson, jkIntervalPhysiPlanFill, nodeToJson, pNode->pFill); } - if (TSDB_CODE_SUCCESS == code) { - code = tjsonAddIntegerToObject(pJson, jkIntervalPhysiPlanPrecision, pNode->precision); - } return code; } @@ -1212,9 +1243,6 @@ static int32_t jsonToPhysiIntervalNode(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeObject(pJson, jkIntervalPhysiPlanFill, (SNode**)&pNode->pFill); } - if (TSDB_CODE_SUCCESS == code) { - code = tjsonGetUTinyIntValue(pJson, jkIntervalPhysiPlanPrecision, &pNode->precision); - } return code; } diff --git a/source/libs/nodes/src/nodesTraverseFuncs.c b/source/libs/nodes/src/nodesTraverseFuncs.c index 99a08923bb..1830d15f69 100644 --- a/source/libs/nodes/src/nodesTraverseFuncs.c +++ b/source/libs/nodes/src/nodesTraverseFuncs.c @@ -87,9 +87,9 @@ static EDealRes walkNode(SNode* pNode, ETraversalOrder order, FNodeWalker walker } case QUERY_NODE_SESSION_WINDOW: { SSessionWindowNode* pSession = (SSessionWindowNode*)pNode; - res = walkNode(pSession->pCol, order, walker, pContext); + res = walkNode((SNode*)pSession->pCol, order, walker, pContext); if (DEAL_RES_ERROR != res && DEAL_RES_END != res) { - res = walkNode(pSession->pGap, order, walker, pContext); + res = walkNode((SNode*)pSession->pGap, order, walker, pContext); } break; } @@ -227,9 +227,9 @@ static EDealRes rewriteNode(SNode** pRawNode, ETraversalOrder order, FNodeRewrit } case QUERY_NODE_SESSION_WINDOW: { SSessionWindowNode* pSession = (SSessionWindowNode*)pNode; - res = rewriteNode(&pSession->pCol, order, rewriter, pContext); + res = rewriteNode((SNode**)&pSession->pCol, order, rewriter, pContext); if (DEAL_RES_ERROR != res && DEAL_RES_END != res) { - res = rewriteNode(&pSession->pGap, order, rewriter, pContext); + res = rewriteNode((SNode**)&pSession->pGap, order, rewriter, pContext); } break; } diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index f2b8b73a87..6d60410e51 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -499,8 +499,8 @@ SNode* createOrderByExprNode(SAstCreateContext* pCxt, SNode* pExpr, EOrder order SNode* createSessionWindowNode(SAstCreateContext* pCxt, SNode* pCol, SNode* pGap) { SSessionWindowNode* session = (SSessionWindowNode*)nodesMakeNode(QUERY_NODE_SESSION_WINDOW); CHECK_OUT_OF_MEM(session); - session->pCol = pCol; - session->pGap = pGap; + session->pCol = (SColumnNode*)pCol; + session->pGap = (SValueNode*)pGap; return (SNode*)session; } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 324f9c17d2..8dce86728e 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -19,6 +19,7 @@ #include "cmdnodes.h" #include "functionMgt.h" #include "parUtil.h" +#include "tglobal.h" #include "ttime.h" #define GET_OPTION_VAL(pVal, defaultVal) (NULL == (pVal) ? (defaultVal) : getBigintFromValueNode((SValueNode*)(pVal))) @@ -227,6 +228,7 @@ static void setColumnInfoBySchema(const SRealTableNode* pTable, const SSchema* p strcpy(pCol->node.aliasName, pColSchema->name); } pCol->tableId = pTable->pMeta->uid; + pCol->tableType = pTable->pMeta->tableType; pCol->colId = pColSchema->colId; pCol->colType = isTag ? COLUMN_TYPE_TAG : COLUMN_TYPE_COLUMN; pCol->node.resType.type = pColSchema->type; @@ -364,18 +366,38 @@ static bool translateColumnUseAlias(STranslateContext* pCxt, SColumnNode* pCol) } static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode* pCol) { - // count(*)/first(*)/last(*) + // count(*)/first(*)/last(*) and so on if (0 == strcmp(pCol->colName, "*")) { return DEAL_RES_CONTINUE; } + + EDealRes res = DEAL_RES_CONTINUE; if ('\0' != pCol->tableAlias[0]) { - return translateColumnWithPrefix(pCxt, pCol); + res = translateColumnWithPrefix(pCxt, pCol); + } else { + bool found = false; + if (SQL_CLAUSE_ORDER_BY == pCxt->currClause) { + found = translateColumnUseAlias(pCxt, pCol); + } + res = (found ? DEAL_RES_CONTINUE : translateColumnWithoutPrefix(pCxt, pCol)); } - bool found = false; - if (SQL_CLAUSE_ORDER_BY == pCxt->currClause) { - found = translateColumnUseAlias(pCxt, pCol); + + if (DEAL_RES_ERROR == res) { + return res; + } + + if (SQL_CLAUSE_WINDOW == pCxt->currClause && QUERY_NODE_STATE_WINDOW == nodeType(pCxt->pCurrStmt->pWindow)) { + if (!IS_INTEGER_TYPE(pCol->node.resType.type)) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_STATE_WIN_TYPE); + } + if (COLUMN_TYPE_TAG == pCol->colType) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_STATE_WIN_COL); + } + if (TSDB_SUPER_TABLE == pCol->tableType) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_STATE_WIN_TABLE); + } } - return found ? DEAL_RES_CONTINUE : translateColumnWithoutPrefix(pCxt, pCol); + return DEAL_RES_CONTINUE; } static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) { @@ -639,7 +661,7 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect) if (!pSelect->isDistinct) { nodesWalkExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt); } - if (cxt.existAggFunc && cxt.existCol) { + if ((cxt.existAggFunc || NULL != pSelect->pWindow) && cxt.existCol) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP); } return TSDB_CODE_SUCCESS; @@ -1091,20 +1113,100 @@ static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) { return translateExprList(pCxt, pSelect->pGroupByList); } -static int32_t translateIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* pInterval) { - SValueNode* pIntervalVal = (SValueNode*)pInterval->pInterval; - SValueNode* pIntervalOffset = (SValueNode*)pInterval->pOffset; - SValueNode* pSliding = (SValueNode*)pInterval->pSliding; - if (pIntervalVal->datum.i <= 0) { - return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTERVAL_VALUE_TOO_SMALL, pIntervalVal->literal); +static bool isValTimeUnit(char unit) { + return ('n' == unit || 'y' == unit); +} + +static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char unit) { + int64_t days = convertTimeFromPrecisionToUnit(val, fromPrecision, 'd'); + switch (unit) { + case 'b': + case 'u': + case 'a': + case 's': + case 'm': + case 'h': + case 'd': + case 'w': + return days / 28; + case 'n': + return val; + case 'y': + return val * 12; + default: + break; + } + return -1; +} + +static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* pInterval) { + uint8_t precision = ((SColumnNode*)pInterval->pCol)->node.resType.precision; + + SValueNode* pInter = (SValueNode*)pInterval->pInterval; + bool valInter = isValTimeUnit(pInter->unit); + if (pInter->datum.i <= 0 || + (!valInter && convertTimePrecision(pInter->datum.i, precision, TSDB_TIME_PRECISION_MICRO) < tsMinIntervalTime)) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_VALUE_TOO_SMALL, tsMinIntervalTime); + } + + if (NULL != pInterval->pOffset) { + SValueNode* pOffset = (SValueNode*)pInterval->pOffset; + bool valOffset = isValTimeUnit(pOffset->unit); + if (pOffset->datum.i <= 0) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_OFFSET_NEGATIVE); + } + if (pInter->unit == 'n' && pOffset->unit == 'y') { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_OFFSET_UNIT); + } + if ((!valInter && !valOffset && pOffset->datum.i >= pInter->datum.i) || + (getMonthsFromTimeVal(pOffset->datum.i, precision, pOffset->unit) >= getMonthsFromTimeVal(pInter->datum.i, precision, pInter->unit))) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_OFFSET_TOO_BIG); + } + } + + if (NULL != pInterval->pSliding) { + const static int32_t INTERVAL_SLIDING_FACTOR = 100; + + SValueNode* pSliding = (SValueNode*)pInterval->pSliding; + if (pInter->unit == 'n' || pInter->unit == 'y') { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SLIDING_UNIT); + } + if ((pSliding->datum.i < convertTimePrecision(tsMinSlidingTime, TSDB_TIME_PRECISION_MILLI, precision)) || + (pInter->datum.i / pSliding->datum.i > INTERVAL_SLIDING_FACTOR)) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SLIDING_TOO_SMALL); + } + if (pSliding->datum.i > pInter->datum.i) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SLIDING_TOO_BIG); + } + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t checkStateWindow(STranslateContext* pCxt, SStateWindowNode* pState) { + // todo check for "function not support for state_window" + return TSDB_CODE_SUCCESS; +} + +static int32_t checkSessionWindow(STranslateContext* pCxt, SSessionWindowNode* pSession) { + if ('y' == pSession->pGap->unit || 'n' == pSession->pGap->unit || 0 == pSession->pGap->datum.i) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SESSION_GAP); + } + if (PRIMARYKEY_TIMESTAMP_COL_ID != pSession->pCol->colId) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SESSION_COL); } + // todo check for "function not support for session" return TSDB_CODE_SUCCESS; } -static int32_t doTranslateWindow(STranslateContext* pCxt, SNode* pWindow) { +static int32_t checkWindow(STranslateContext* pCxt, SNode* pWindow) { switch (nodeType(pWindow)) { + case QUERY_NODE_STATE_WINDOW: + return checkStateWindow(pCxt, (SStateWindowNode*)pWindow); + case QUERY_NODE_SESSION_WINDOW: + return checkSessionWindow(pCxt, (SSessionWindowNode*)pWindow); case QUERY_NODE_INTERVAL_WINDOW: - return translateIntervalWindow(pCxt, (SIntervalWindowNode*)pWindow); + return checkIntervalWindow(pCxt, (SIntervalWindowNode*)pWindow); default: break; } @@ -1118,7 +1220,7 @@ static int32_t translateWindow(STranslateContext* pCxt, SNode* pWindow) { pCxt->currClause = SQL_CLAUSE_WINDOW; int32_t code = translateExpr(pCxt, pWindow); if (TSDB_CODE_SUCCESS == code) { - code = doTranslateWindow(pCxt, pWindow); + code = checkWindow(pCxt, pWindow); } return code; } diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 549f448ff4..51e0b2a328 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -55,8 +55,8 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "Endpoint should be in the format of 'fqdn:port'"; case TSDB_CODE_PAR_EXPRIE_STATEMENT: return "This statement is no longer supported"; - case TSDB_CODE_PAR_INTERVAL_VALUE_TOO_SMALL: - return "This interval value is too small : %s"; + case TSDB_CODE_PAR_INTER_VALUE_TOO_SMALL: + return "Interval cannot be less than %d us"; case TSDB_CODE_PAR_DB_NOT_SPECIFIED: return "Database not specified"; case TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME: @@ -93,6 +93,28 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "Invalid option keep unit: %c, %c, %c, only m, h, d allowed"; case TSDB_CODE_PAR_AGG_FUNC_NESTING: return "Aggregate functions do not support nesting"; + case TSDB_CODE_PAR_INVALID_STATE_WIN_TYPE: + return "Only support STATE_WINDOW on integer column"; + case TSDB_CODE_PAR_INVALID_STATE_WIN_COL: + return "Not support STATE_WINDOW on tag column"; + case TSDB_CODE_PAR_INVALID_STATE_WIN_TABLE: + return "STATE_WINDOW not support for super table query"; + case TSDB_CODE_PAR_INTER_SESSION_GAP: + return "SESSION gap should be fixed time window, and greater than 0"; + case TSDB_CODE_PAR_INTER_SESSION_COL: + return "Only support SESSION on primary timestamp column"; + case TSDB_CODE_PAR_INTER_OFFSET_NEGATIVE: + return "Interval offset cannot be negative"; + case TSDB_CODE_PAR_INTER_OFFSET_UNIT: + return "Cannot use 'year' as offset when interval is 'month'"; + case TSDB_CODE_PAR_INTER_OFFSET_TOO_BIG: + return "Interval offset should be shorter than interval"; + case TSDB_CODE_PAR_INTER_SLIDING_UNIT: + return "Does not support sliding when interval is natural month/year"; + case TSDB_CODE_PAR_INTER_SLIDING_TOO_BIG: + return "sliding value no larger than the interval value"; + case TSDB_CODE_PAR_INTER_SLIDING_TOO_SMALL: + return "sliding value can not less than 1% of interval value"; case TSDB_CODE_OUT_OF_MEMORY: return "Out of memory"; default: diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 656caaf645..6fcfc7df07 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -166,12 +166,24 @@ static int32_t osdGetDataRequired(SNodeList* pFuncs) { return dataRequired; } +static void setScanWindowInfo(SScanLogicNode* pScan) { + if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pScan->node.pParent) && + WINDOW_TYPE_INTERVAL == ((SWindowLogicNode*)pScan->node.pParent)->winType) { + pScan->interval = ((SWindowLogicNode*)pScan->node.pParent)->interval; + pScan->offset = ((SWindowLogicNode*)pScan->node.pParent)->offset; + pScan->sliding = ((SWindowLogicNode*)pScan->node.pParent)->sliding; + pScan->intervalUnit = ((SWindowLogicNode*)pScan->node.pParent)->intervalUnit; + pScan->slidingUnit = ((SWindowLogicNode*)pScan->node.pParent)->slidingUnit; + } +} + static int32_t osdOptimize(SOptimizeContext* pCxt, SLogicNode* pLogicNode) { SOsdInfo info = {0}; int32_t code = osdMatch(pCxt, pLogicNode, &info); if (TSDB_CODE_SUCCESS == code && (NULL != info.pDsoFuncs || NULL != info.pSdrFuncs)) { info.pScan->dataRequired = osdGetDataRequired(info.pSdrFuncs); info.pScan->pDynamicScanFuncs = info.pDsoFuncs; + setScanWindowInfo((SScanLogicNode*)info.pScan); OPTIMIZE_FLAG_SET_MASK(info.pScan->node.optimizedFlag, OPTIMIZE_FLAG_OSD); pCxt->optimized = true; } diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index f9f6d503a1..caeab20970 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -443,6 +443,11 @@ static int32_t createTableScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubp nodesDestroyNode(pTableScan); return TSDB_CODE_OUT_OF_MEMORY; } + pTableScan->interval = pScanLogicNode->interval; + pTableScan->offset = pScanLogicNode->offset; + pTableScan->sliding = pScanLogicNode->sliding; + pTableScan->intervalUnit = pScanLogicNode->intervalUnit; + pTableScan->slidingUnit = pScanLogicNode->slidingUnit; return createScanPhysiNodeFinalize(pCxt, pScanLogicNode, (SScanPhysiNode*)pTableScan, pPhyNode); } @@ -819,7 +824,6 @@ static int32_t createIntervalPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChil pInterval->sliding = pWindowLogicNode->sliding; pInterval->intervalUnit = pWindowLogicNode->intervalUnit; pInterval->slidingUnit = pWindowLogicNode->slidingUnit; - pInterval->precision = ((SColumnNode*)pWindowLogicNode->pTspk)->node.resType.precision; pInterval->pFill = nodesCloneNode(pWindowLogicNode->pFill); if (NULL != pWindowLogicNode->pFill && NULL == pInterval->pFill) { diff --git a/source/libs/scalar/src/sclfunc.c b/source/libs/scalar/src/sclfunc.c index 97cc80b946..b263e50974 100644 --- a/source/libs/scalar/src/sclfunc.c +++ b/source/libs/scalar/src/sclfunc.c @@ -666,18 +666,14 @@ int32_t substrFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOu } int32_t castFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) { - if (inputNum!= 3) { - return TSDB_CODE_FAILED; - } - int16_t inputType = pInput[0].columnData->info.type; - int16_t outputType = *(int16_t *)pInput[1].columnData->pData; + int16_t outputType = pOutput[0].columnData->info.type; if (outputType != TSDB_DATA_TYPE_BIGINT && outputType != TSDB_DATA_TYPE_UBIGINT && outputType != TSDB_DATA_TYPE_VARCHAR && outputType != TSDB_DATA_TYPE_NCHAR && outputType != TSDB_DATA_TYPE_TIMESTAMP) { return TSDB_CODE_FAILED; } - int64_t outputLen = *(int64_t *)pInput[2].columnData->pData; + int64_t outputLen = pOutput[0].columnData->info.bytes; char *input = NULL; char *outputBuf = taosMemoryCalloc(outputLen * pInput[0].numOfRows, 1); -- GitLab