From 84c37d501a5edf18cb3a7255feebc73589cae0d7 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Wed, 22 Jan 2025 11:45:12 +0800 Subject: [PATCH] enh: support ? in limit clause --- include/libs/nodes/querynodes.h | 7 ++- source/client/test/stmt2Test.cpp | 57 +++++++++++++++++++ source/libs/command/src/explain.c | 4 +- source/libs/executor/src/executil.c | 4 +- source/libs/executor/src/hashjoinoperator.c | 2 +- source/libs/executor/src/mergejoin.c | 6 +- source/libs/executor/src/mergejoinoperator.c | 4 +- source/libs/executor/src/sortoperator.c | 6 +- source/libs/executor/src/timewindowoperator.c | 8 +-- source/libs/executor/test/joinTests.cpp | 6 +- source/libs/executor/test/queryPlanTests.cpp | 21 +++++-- source/libs/nodes/src/nodesCloneFuncs.c | 6 +- source/libs/nodes/src/nodesCodeFuncs.c | 10 ++-- source/libs/nodes/src/nodesMsgFuncs.c | 10 ++-- source/libs/nodes/src/nodesUtilFuncs.c | 25 +++++++- source/libs/parser/inc/parAst.h | 2 +- source/libs/parser/inc/sql.y | 19 ++++--- source/libs/parser/src/parAstCreater.c | 6 +- source/libs/parser/src/parTranslater.c | 26 ++++++--- source/libs/planner/src/planOptimizer.c | 10 +++- source/libs/planner/src/planPhysiCreater.c | 4 +- source/libs/planner/src/planSpliter.c | 32 ++++++++--- source/libs/planner/src/planUtil.c | 16 ++++-- 23 files changed, 218 insertions(+), 73 deletions(-) mode change 100644 => 100755 source/libs/parser/inc/sql.y diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 5e4e8b6292..ec3e37b7e5 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -313,9 +313,9 @@ typedef struct SOrderByExprNode { } SOrderByExprNode; typedef struct SLimitNode { - ENodeType type; // QUERY_NODE_LIMIT - int64_t limit; - int64_t offset; + ENodeType type; // QUERY_NODE_LIMIT + SValueNode* limit; + SValueNode* offset; } SLimitNode; typedef struct SStateWindowNode { @@ -681,6 +681,7 @@ int32_t nodesValueNodeToVariant(const SValueNode* pNode, SVariant* pVal); int32_t nodesMakeValueNodeFromString(char* literal, SValueNode** ppValNode); int32_t nodesMakeValueNodeFromBool(bool b, SValueNode** ppValNode); int32_t nodesMakeValueNodeFromInt32(int32_t value, SNode** ppNode); +int32_t nodesMakeValueNodeFromInt64(int64_t value, SNode** ppNode); char* nodesGetFillModeString(EFillMode mode); int32_t nodesMergeConds(SNode** pDst, SNodeList** pSrc); diff --git a/source/client/test/stmt2Test.cpp b/source/client/test/stmt2Test.cpp index 91f884941f..0f721d6a6b 100644 --- a/source/client/test/stmt2Test.cpp +++ b/source/client/test/stmt2Test.cpp @@ -237,6 +237,63 @@ int main(int argc, char** argv) { return RUN_ALL_TESTS(); } +TEST(stmt2Case, stmt2_test_limit) { + TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0); + ASSERT_NE(taos, nullptr); + do_query(taos, "drop database if exists stmt2_testdb_7"); + do_query(taos, "create database IF NOT EXISTS stmt2_testdb_7"); + do_query(taos, "create stable stmt2_testdb_7.stb (ts timestamp, b binary(10)) tags(t1 int, t2 binary(10))"); + do_query(taos, + "insert into stmt2_testdb_7.tb2 using stmt2_testdb_7.stb tags(2,'xyz') values(1591060628000, " + "'abc'),(1591060628001,'def'),(1591060628004, 'hij')"); + do_query(taos, "use stmt2_testdb_7"); + + + TAOS_STMT2_OPTION option = {0, true, true, NULL, NULL}; + + + TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); + ASSERT_NE(stmt, nullptr); + + + const char* sql = "select * from stmt2_testdb_7.tb2 where ts > ? and ts < ? limit ?"; + int code = taos_stmt2_prepare(stmt, sql, 0); + checkError(stmt, code); + + + int t64_len[1] = {sizeof(int64_t)}; + int b_len[1] = {3}; + int x = 2; + int x_len = sizeof(int); + int64_t ts[2] = {1591060627000, 1591060628005}; + TAOS_STMT2_BIND params[3] = {{TSDB_DATA_TYPE_TIMESTAMP, &ts[0], t64_len, NULL, 1}, + {TSDB_DATA_TYPE_TIMESTAMP, &ts[1], t64_len, NULL, 1}, + {TSDB_DATA_TYPE_INT, &x, &x_len, NULL, 1}}; + TAOS_STMT2_BIND* paramv = ¶ms[0]; + TAOS_STMT2_BINDV bindv = {1, NULL, NULL, ¶mv}; + code = taos_stmt2_bind_param(stmt, &bindv, -1); + checkError(stmt, code); + + + taos_stmt2_exec(stmt, NULL); + checkError(stmt, code); + + + TAOS_RES* pRes = taos_stmt2_result(stmt); + ASSERT_NE(pRes, nullptr); + + + int getRecordCounts = 0; + while ((taos_fetch_row(pRes))) { + getRecordCounts++; + } + ASSERT_EQ(getRecordCounts, 2); + taos_stmt2_close(stmt); + do_query(taos, "drop database if exists stmt2_testdb_7"); + taos_close(taos); +} + + TEST(stmt2Case, insert_stb_get_fields_Test) { TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT_NE(taos, nullptr); diff --git a/source/libs/command/src/explain.c b/source/libs/command/src/explain.c index 0778d5d5f8..f863ff1455 100644 --- a/source/libs/command/src/explain.c +++ b/source/libs/command/src/explain.c @@ -676,9 +676,9 @@ static int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx EXPLAIN_ROW_APPEND(EXPLAIN_WIN_OFFSET_FORMAT, pStart->literal, pEnd->literal); EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT); } - if (NULL != pJoinNode->pJLimit) { + if (NULL != pJoinNode->pJLimit && NULL != ((SLimitNode*)pJoinNode->pJLimit)->limit) { SLimitNode* pJLimit = (SLimitNode*)pJoinNode->pJLimit; - EXPLAIN_ROW_APPEND(EXPLAIN_JLIMIT_FORMAT, pJLimit->limit); + EXPLAIN_ROW_APPEND(EXPLAIN_JLIMIT_FORMAT, pJLimit->limit->datum.i); EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT); } if (IS_WINDOW_JOIN(pJoinNode->subType)) { diff --git a/source/libs/executor/src/executil.c b/source/libs/executor/src/executil.c index cce754a8c8..5a1e8ad3c2 100644 --- a/source/libs/executor/src/executil.c +++ b/source/libs/executor/src/executil.c @@ -54,8 +54,8 @@ static int32_t optimizeTbnameInCondImpl(void* metaHandle, SArray* list, SNode* p static int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, SNode* pTagIndexCond, STableListInfo* pListInfo, uint8_t* digest, const char* idstr, SStorageAPI* pStorageAPI); -static int64_t getLimit(const SNode* pLimit) { return NULL == pLimit ? -1 : ((SLimitNode*)pLimit)->limit; } -static int64_t getOffset(const SNode* pLimit) { return NULL == pLimit ? -1 : ((SLimitNode*)pLimit)->offset; } +static int64_t getLimit(const SNode* pLimit) { return (NULL == pLimit || NULL == ((SLimitNode*)pLimit)->limit) ? -1 : ((SLimitNode*)pLimit)->limit->datum.i; } +static int64_t getOffset(const SNode* pLimit) { return (NULL == pLimit || NULL == ((SLimitNode*)pLimit)->offset) ? -1 : ((SLimitNode*)pLimit)->offset->datum.i; } static void releaseColInfoData(void* pCol); void initResultRowInfo(SResultRowInfo* pResultRowInfo) { diff --git a/source/libs/executor/src/hashjoinoperator.c b/source/libs/executor/src/hashjoinoperator.c index 73a5139e43..42e99e5fef 100644 --- a/source/libs/executor/src/hashjoinoperator.c +++ b/source/libs/executor/src/hashjoinoperator.c @@ -1185,7 +1185,7 @@ int32_t createHashJoinOperatorInfo(SOperatorInfo** pDownstream, int32_t numOfDow pInfo->tblTimeRange.skey = pJoinNode->timeRange.skey; pInfo->tblTimeRange.ekey = pJoinNode->timeRange.ekey; - pInfo->ctx.limit = pJoinNode->node.pLimit ? ((SLimitNode*)pJoinNode->node.pLimit)->limit : INT64_MAX; + pInfo->ctx.limit = (pJoinNode->node.pLimit && ((SLimitNode*)pJoinNode->node.pLimit)->limit) ? ((SLimitNode*)pJoinNode->node.pLimit)->limit->datum.i : INT64_MAX; setOperatorInfo(pOperator, "HashJoinOperator", QUERY_NODE_PHYSICAL_PLAN_HASH_JOIN, false, OP_NOT_OPENED, pInfo, pTaskInfo); diff --git a/source/libs/executor/src/mergejoin.c b/source/libs/executor/src/mergejoin.c index adf1b4f0d1..f133c68410 100755 --- a/source/libs/executor/src/mergejoin.c +++ b/source/libs/executor/src/mergejoin.c @@ -3592,7 +3592,7 @@ int32_t mJoinInitWindowCtx(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* p switch (pJoinNode->subType) { case JOIN_STYPE_ASOF: pCtx->asofOpType = pJoinNode->asofOpType; - pCtx->jLimit = pJoinNode->pJLimit ? ((SLimitNode*)pJoinNode->pJLimit)->limit : 1; + pCtx->jLimit = (pJoinNode->pJLimit && ((SLimitNode*)pJoinNode->pJLimit)->limit) ? ((SLimitNode*)pJoinNode->pJLimit)->limit->datum.i : 1; pCtx->eqRowsAcq = ASOF_EQ_ROW_INCLUDED(pCtx->asofOpType); pCtx->lowerRowsAcq = (JOIN_TYPE_RIGHT != pJoin->joinType) ? ASOF_LOWER_ROW_INCLUDED(pCtx->asofOpType) : ASOF_GREATER_ROW_INCLUDED(pCtx->asofOpType); pCtx->greaterRowsAcq = (JOIN_TYPE_RIGHT != pJoin->joinType) ? ASOF_GREATER_ROW_INCLUDED(pCtx->asofOpType) : ASOF_LOWER_ROW_INCLUDED(pCtx->asofOpType); @@ -3609,7 +3609,7 @@ int32_t mJoinInitWindowCtx(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* p SWindowOffsetNode* pOffsetNode = (SWindowOffsetNode*)pJoinNode->pWindowOffset; SValueNode* pWinBegin = (SValueNode*)pOffsetNode->pStartOffset; SValueNode* pWinEnd = (SValueNode*)pOffsetNode->pEndOffset; - pCtx->jLimit = pJoinNode->pJLimit ? ((SLimitNode*)pJoinNode->pJLimit)->limit : INT64_MAX; + pCtx->jLimit = (pJoinNode->pJLimit && ((SLimitNode*)pJoinNode->pJLimit)->limit) ? ((SLimitNode*)pJoinNode->pJLimit)->limit->datum.i : INT64_MAX; pCtx->winBeginOffset = pWinBegin->datum.i; pCtx->winEndOffset = pWinEnd->datum.i; pCtx->eqRowsAcq = (pCtx->winBeginOffset <= 0 && pCtx->winEndOffset >= 0); @@ -3662,7 +3662,7 @@ int32_t mJoinInitMergeCtx(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* pJ pCtx->hashCan = pJoin->probe->keyNum > 0; if (JOIN_STYPE_ASOF == pJoinNode->subType || JOIN_STYPE_WIN == pJoinNode->subType) { - pCtx->jLimit = pJoinNode->pJLimit ? ((SLimitNode*)pJoinNode->pJLimit)->limit : 1; + pCtx->jLimit = (pJoinNode->pJLimit && ((SLimitNode*)pJoinNode->pJLimit)->limit) ? ((SLimitNode*)pJoinNode->pJLimit)->limit->datum.i : 1; pJoin->subType = JOIN_STYPE_OUTER; pJoin->build->eqRowLimit = pCtx->jLimit; pJoin->grpResetFp = mLeftJoinGroupReset; diff --git a/source/libs/executor/src/mergejoinoperator.c b/source/libs/executor/src/mergejoinoperator.c index e007504ffb..3edef48ed1 100644 --- a/source/libs/executor/src/mergejoinoperator.c +++ b/source/libs/executor/src/mergejoinoperator.c @@ -986,7 +986,7 @@ static int32_t mJoinInitTableInfo(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysi pTable->multiEqGrpRows = !((JOIN_STYPE_SEMI == pJoin->subType || JOIN_STYPE_ANTI == pJoin->subType) && NULL == pJoin->pFPreFilter); pTable->multiRowsGrp = !((JOIN_STYPE_SEMI == pJoin->subType || JOIN_STYPE_ANTI == pJoin->subType) && NULL == pJoin->pPreFilter); if (JOIN_STYPE_ASOF == pJoinNode->subType) { - pTable->eqRowLimit = pJoinNode->pJLimit ? ((SLimitNode*)pJoinNode->pJLimit)->limit : 1; + pTable->eqRowLimit = (pJoinNode->pJLimit && ((SLimitNode*)pJoinNode->pJLimit)->limit) ? ((SLimitNode*)pJoinNode->pJLimit)->limit->datum.i : 1; } } else { pTable->multiEqGrpRows = true; @@ -1169,7 +1169,7 @@ static FORCE_INLINE SSDataBlock* mJoinRetrieveImpl(SMJoinOperatorInfo* pJoin, SM static int32_t mJoinInitCtx(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* pJoinNode) { pJoin->ctx.mergeCtx.groupJoin = pJoinNode->grpJoin; - pJoin->ctx.mergeCtx.limit = pJoinNode->node.pLimit ? ((SLimitNode*)pJoinNode->node.pLimit)->limit : INT64_MAX; + pJoin->ctx.mergeCtx.limit = (pJoinNode->node.pLimit && ((SLimitNode*)pJoinNode->node.pLimit)->limit) ? ((SLimitNode*)pJoinNode->node.pLimit)->limit->datum.i : INT64_MAX; pJoin->retrieveFp = pJoinNode->grpJoin ? mJoinGrpRetrieveImpl : mJoinRetrieveImpl; pJoin->outBlkId = pJoinNode->node.pOutputDataBlockDesc->dataBlockId; diff --git a/source/libs/executor/src/sortoperator.c b/source/libs/executor/src/sortoperator.c index ed073d21a0..2bb8c4403e 100644 --- a/source/libs/executor/src/sortoperator.c +++ b/source/libs/executor/src/sortoperator.c @@ -84,9 +84,11 @@ int32_t createSortOperatorInfo(SOperatorInfo* downstream, SSortPhysiNode* pSortN calcSortOperMaxTupleLength(pInfo, pSortNode->pSortKeys); pInfo->maxRows = -1; - if (pSortNode->node.pLimit) { + if (pSortNode->node.pLimit && ((SLimitNode*)pSortNode->node.pLimit)->limit) { SLimitNode* pLimit = (SLimitNode*)pSortNode->node.pLimit; - if (pLimit->limit > 0) pInfo->maxRows = pLimit->limit + pLimit->offset; + if (pLimit->limit->datum.i > 0) { + pInfo->maxRows = pLimit->limit->datum.i + (pLimit->offset ? pLimit->offset->datum.i : 0); + } } pOperator->exprSupp.pCtx = diff --git a/source/libs/executor/src/timewindowoperator.c b/source/libs/executor/src/timewindowoperator.c index 25716be0f8..71c71a547e 100644 --- a/source/libs/executor/src/timewindowoperator.c +++ b/source/libs/executor/src/timewindowoperator.c @@ -1417,15 +1417,15 @@ int32_t createIntervalOperatorInfo(SOperatorInfo* downstream, SIntervalPhysiNode pInfo->interval = interval; pInfo->twAggSup = as; pInfo->binfo.mergeResultBlock = pPhyNode->window.mergeDataBlock; - if (pPhyNode->window.node.pLimit) { + if (pPhyNode->window.node.pLimit && ((SLimitNode*)pPhyNode->window.node.pLimit)->limit) { SLimitNode* pLimit = (SLimitNode*)pPhyNode->window.node.pLimit; pInfo->limited = true; - pInfo->limit = pLimit->limit + pLimit->offset; + pInfo->limit = pLimit->limit->datum.i + (pLimit->offset ? pLimit->offset->datum.i : 0); } - if (pPhyNode->window.node.pSlimit) { + if (pPhyNode->window.node.pSlimit && ((SLimitNode*)pPhyNode->window.node.pSlimit)->limit) { SLimitNode* pLimit = (SLimitNode*)pPhyNode->window.node.pSlimit; pInfo->slimited = true; - pInfo->slimit = pLimit->limit + pLimit->offset; + pInfo->slimit = pLimit->limit->datum.i + (pLimit->offset ? pLimit->offset->datum.i : 0); pInfo->curGroupId = UINT64_MAX; } diff --git a/source/libs/executor/test/joinTests.cpp b/source/libs/executor/test/joinTests.cpp index efbe1fcc83..09d5753f78 100755 --- a/source/libs/executor/test/joinTests.cpp +++ b/source/libs/executor/test/joinTests.cpp @@ -864,7 +864,11 @@ SSortMergeJoinPhysiNode* createDummySortMergeJoinPhysiNode(SJoinTestParam* param SLimitNode* limitNode = NULL; code = nodesMakeNode(QUERY_NODE_LIMIT, (SNode**)&limitNode); assert(limitNode); - limitNode->limit = param->jLimit; + code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&limitNode->limit); + assert(limitNode->limit); + limitNode->limit->node.resType.type = TSDB_DATA_TYPE_BIGINT; + limitNode->limit->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes; + limitNode->limit->datum.i = param->jLimit; p->pJLimit = (SNode*)limitNode; } diff --git a/source/libs/executor/test/queryPlanTests.cpp b/source/libs/executor/test/queryPlanTests.cpp index 8126e53bd6..3815dab444 100755 --- a/source/libs/executor/test/queryPlanTests.cpp +++ b/source/libs/executor/test/queryPlanTests.cpp @@ -1418,6 +1418,7 @@ SNode* qptMakeExprNode(SNode** ppNode) { SNode* qptMakeLimitNode(SNode** ppNode) { SNode* pNode = NULL; + int32_t code = 0; if (QPT_NCORRECT_LOW_PROB()) { return qptMakeRandNode(&pNode); } @@ -1429,15 +1430,27 @@ SNode* qptMakeLimitNode(SNode** ppNode) { if (!qptCtx.param.correctExpected) { if (taosRand() % 2) { - pLimit->limit = taosRand() * ((taosRand() % 2) ? 1 : -1); + code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pLimit->limit); + assert(pLimit->limit); + pLimit->limit->node.resType.type = TSDB_DATA_TYPE_BIGINT; + pLimit->limit->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes; + pLimit->limit->datum.i = taosRand() * ((taosRand() % 2) ? 1 : -1); } if (taosRand() % 2) { - pLimit->offset = taosRand() * ((taosRand() % 2) ? 1 : -1); + code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pLimit->offset); + assert(pLimit->offset); + pLimit->offset->node.resType.type = TSDB_DATA_TYPE_BIGINT; + pLimit->offset->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes; + pLimit->offset->datum.i = taosRand() * ((taosRand() % 2) ? 1 : -1); } } else { - pLimit->limit = taosRand(); + pLimit->limit->datum.i = taosRand(); if (taosRand() % 2) { - pLimit->offset = taosRand(); + code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pLimit->offset); + assert(pLimit->offset); + pLimit->offset->node.resType.type = TSDB_DATA_TYPE_BIGINT; + pLimit->offset->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes; + pLimit->offset->datum.i = taosRand(); } } diff --git a/source/libs/nodes/src/nodesCloneFuncs.c b/source/libs/nodes/src/nodesCloneFuncs.c index 6d245ebd61..161c5f7ca7 100644 --- a/source/libs/nodes/src/nodesCloneFuncs.c +++ b/source/libs/nodes/src/nodesCloneFuncs.c @@ -52,7 +52,7 @@ if (NULL == (pSrc)->fldname) { \ break; \ } \ - int32_t code = nodesCloneNode((pSrc)->fldname, &((pDst)->fldname)); \ + int32_t code = nodesCloneNode((SNode*)(pSrc)->fldname, (SNode**)&((pDst)->fldname)); \ if (NULL == (pDst)->fldname) { \ return code; \ } \ @@ -346,8 +346,8 @@ static int32_t orderByExprNodeCopy(const SOrderByExprNode* pSrc, SOrderByExprNod } static int32_t limitNodeCopy(const SLimitNode* pSrc, SLimitNode* pDst) { - COPY_SCALAR_FIELD(limit); - COPY_SCALAR_FIELD(offset); + CLONE_NODE_FIELD(limit); + CLONE_NODE_FIELD(offset); return TSDB_CODE_SUCCESS; } diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index 6d4d89607f..9dcb2e67d4 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -4933,9 +4933,9 @@ static const char* jkLimitOffset = "Offset"; static int32_t limitNodeToJson(const void* pObj, SJson* pJson) { const SLimitNode* pNode = (const SLimitNode*)pObj; - int32_t code = tjsonAddIntegerToObject(pJson, jkLimitLimit, pNode->limit); - if (TSDB_CODE_SUCCESS == code) { - code = tjsonAddIntegerToObject(pJson, jkLimitOffset, pNode->offset); + int32_t code = tjsonAddObject(pJson, jkLimitLimit, nodeToJson, pNode->limit); + if (TSDB_CODE_SUCCESS == code && pNode->offset) { + code = tjsonAddObject(pJson, jkLimitOffset, nodeToJson, pNode->offset); } return code; @@ -4944,9 +4944,9 @@ static int32_t limitNodeToJson(const void* pObj, SJson* pJson) { static int32_t jsonToLimitNode(const SJson* pJson, void* pObj) { SLimitNode* pNode = (SLimitNode*)pObj; - int32_t code = tjsonGetBigIntValue(pJson, jkLimitLimit, &pNode->limit); + int32_t code = jsonToNodeObject(pJson, jkLimitLimit, (SNode**)&pNode->limit); if (TSDB_CODE_SUCCESS == code) { - code = tjsonGetBigIntValue(pJson, jkLimitOffset, &pNode->offset); + code = jsonToNodeObject(pJson, jkLimitOffset, (SNode**)&pNode->offset); } return code; diff --git a/source/libs/nodes/src/nodesMsgFuncs.c b/source/libs/nodes/src/nodesMsgFuncs.c index 930a88aea0..1becd07aba 100644 --- a/source/libs/nodes/src/nodesMsgFuncs.c +++ b/source/libs/nodes/src/nodesMsgFuncs.c @@ -1246,9 +1246,9 @@ enum { LIMIT_CODE_LIMIT = 1, LIMIT_CODE_OFFSET }; static int32_t limitNodeToMsg(const void* pObj, STlvEncoder* pEncoder) { const SLimitNode* pNode = (const SLimitNode*)pObj; - int32_t code = tlvEncodeI64(pEncoder, LIMIT_CODE_LIMIT, pNode->limit); - if (TSDB_CODE_SUCCESS == code) { - code = tlvEncodeI64(pEncoder, LIMIT_CODE_OFFSET, pNode->offset); + int32_t code = tlvEncodeObj(pEncoder, LIMIT_CODE_LIMIT, nodeToMsg, pNode->limit); + if (TSDB_CODE_SUCCESS == code && pNode->offset) { + code = tlvEncodeObj(pEncoder, LIMIT_CODE_OFFSET, nodeToMsg, pNode->offset); } return code; @@ -1262,10 +1262,10 @@ static int32_t msgToLimitNode(STlvDecoder* pDecoder, void* pObj) { tlvForEach(pDecoder, pTlv, code) { switch (pTlv->type) { case LIMIT_CODE_LIMIT: - code = tlvDecodeI64(pTlv, &pNode->limit); + code = msgToNodeFromTlv(pTlv, (void**)&pNode->limit); break; case LIMIT_CODE_OFFSET: - code = tlvDecodeI64(pTlv, &pNode->offset); + code = msgToNodeFromTlv(pTlv, (void**)&pNode->offset); break; default: break; diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 7beaeaa46c..47c6292a9a 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -1106,8 +1106,12 @@ void nodesDestroyNode(SNode* pNode) { case QUERY_NODE_ORDER_BY_EXPR: nodesDestroyNode(((SOrderByExprNode*)pNode)->pExpr); break; - case QUERY_NODE_LIMIT: // no pointer field + case QUERY_NODE_LIMIT: { + SLimitNode* pLimit = (SLimitNode*)pNode; + nodesDestroyNode((SNode*)pLimit->limit); + nodesDestroyNode((SNode*)pLimit->offset); break; + } case QUERY_NODE_STATE_WINDOW: { SStateWindowNode* pState = (SStateWindowNode*)pNode; nodesDestroyNode(pState->pCol); @@ -3097,6 +3101,25 @@ int32_t nodesMakeValueNodeFromInt32(int32_t value, SNode** ppNode) { return code; } +int32_t nodesMakeValueNodeFromInt64(int64_t value, SNode** ppNode) { + SValueNode* pValNode = NULL; + int32_t code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pValNode); + if (TSDB_CODE_SUCCESS == code) { + pValNode->node.resType.type = TSDB_DATA_TYPE_BIGINT; + pValNode->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes; + code = nodesSetValueNodeValue(pValNode, &value); + if (TSDB_CODE_SUCCESS == code) { + pValNode->translate = true; + pValNode->isNull = false; + *ppNode = (SNode*)pValNode; + } else { + nodesDestroyNode((SNode*)pValNode); + } + } + return code; +} + + bool nodesIsStar(SNode* pNode) { return (QUERY_NODE_COLUMN == nodeType(pNode)) && ('\0' == ((SColumnNode*)pNode)->tableAlias[0]) && (0 == strcmp(((SColumnNode*)pNode)->colName, "*")); diff --git a/source/libs/parser/inc/parAst.h b/source/libs/parser/inc/parAst.h index e69a3da4a9..293649e06e 100644 --- a/source/libs/parser/inc/parAst.h +++ b/source/libs/parser/inc/parAst.h @@ -152,7 +152,7 @@ SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, SToken SNode* createJoinTableNode(SAstCreateContext* pCxt, EJoinType type, EJoinSubType stype, SNode* pLeft, SNode* pRight, SNode* pJoinCond); SNode* createViewNode(SAstCreateContext* pCxt, SToken* pDbName, SToken* pViewName); -SNode* createLimitNode(SAstCreateContext* pCxt, const SToken* pLimit, const SToken* pOffset); +SNode* createLimitNode(SAstCreateContext* pCxt, SNode* pLimit, SNode* pOffset); SNode* createOrderByExprNode(SAstCreateContext* pCxt, SNode* pExpr, EOrder order, ENullOrder nullOrder); SNode* createSessionWindowNode(SAstCreateContext* pCxt, SNode* pCol, SNode* pGap); SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr); diff --git a/source/libs/parser/inc/sql.y b/source/libs/parser/inc/sql.y old mode 100644 new mode 100755 index fda49e7ee2..5c16da8665 --- a/source/libs/parser/inc/sql.y +++ b/source/libs/parser/inc/sql.y @@ -1078,6 +1078,10 @@ signed_integer(A) ::= NK_MINUS(B) NK_INTEGER(C). A = createValueNode(pCxt, TSDB_DATA_TYPE_BIGINT, &t); } + +unsigned_integer(A) ::= NK_INTEGER(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_BIGINT, &B); } +unsigned_integer(A) ::= NK_QUESTION(B). { A = releaseRawExprNode(pCxt, createRawExprNode(pCxt, &B, createPlaceholderValueNode(pCxt, &B))); } + signed_float(A) ::= NK_FLOAT(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_DOUBLE, &B); } signed_float(A) ::= NK_PLUS NK_FLOAT(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_DOUBLE, &B); } signed_float(A) ::= NK_MINUS(B) NK_FLOAT(C). { @@ -1098,6 +1102,7 @@ signed_literal(A) ::= NULL(B). signed_literal(A) ::= literal_func(B). { A = releaseRawExprNode(pCxt, B); } signed_literal(A) ::= NK_QUESTION(B). { A = createPlaceholderValueNode(pCxt, &B); } + %type literal_list { SNodeList* } %destructor literal_list { nodesDestroyList($$); } literal_list(A) ::= signed_literal(B). { A = createNodeList(pCxt, B); } @@ -1480,7 +1485,7 @@ window_offset_literal(A) ::= NK_MINUS(B) NK_VARIABLE(C). } jlimit_clause_opt(A) ::= . { A = NULL; } -jlimit_clause_opt(A) ::= JLIMIT NK_INTEGER(B). { A = createLimitNode(pCxt, &B, NULL); } +jlimit_clause_opt(A) ::= JLIMIT unsigned_integer(B). { A = createLimitNode(pCxt, B, NULL); } /************************************************ query_specification *************************************************/ query_specification(A) ::= @@ -1660,14 +1665,14 @@ order_by_clause_opt(A) ::= . order_by_clause_opt(A) ::= ORDER BY sort_specification_list(B). { A = B; } slimit_clause_opt(A) ::= . { A = NULL; } -slimit_clause_opt(A) ::= SLIMIT NK_INTEGER(B). { A = createLimitNode(pCxt, &B, NULL); } -slimit_clause_opt(A) ::= SLIMIT NK_INTEGER(B) SOFFSET NK_INTEGER(C). { A = createLimitNode(pCxt, &B, &C); } -slimit_clause_opt(A) ::= SLIMIT NK_INTEGER(C) NK_COMMA NK_INTEGER(B). { A = createLimitNode(pCxt, &B, &C); } +slimit_clause_opt(A) ::= SLIMIT unsigned_integer(B). { A = createLimitNode(pCxt, B, NULL); } +slimit_clause_opt(A) ::= SLIMIT unsigned_integer(B) SOFFSET unsigned_integer(C). { A = createLimitNode(pCxt, B, C); } +slimit_clause_opt(A) ::= SLIMIT unsigned_integer(C) NK_COMMA unsigned_integer(B). { A = createLimitNode(pCxt, B, C); } limit_clause_opt(A) ::= . { A = NULL; } -limit_clause_opt(A) ::= LIMIT NK_INTEGER(B). { A = createLimitNode(pCxt, &B, NULL); } -limit_clause_opt(A) ::= LIMIT NK_INTEGER(B) OFFSET NK_INTEGER(C). { A = createLimitNode(pCxt, &B, &C); } -limit_clause_opt(A) ::= LIMIT NK_INTEGER(C) NK_COMMA NK_INTEGER(B). { A = createLimitNode(pCxt, &B, &C); } +limit_clause_opt(A) ::= LIMIT unsigned_integer(B). { A = createLimitNode(pCxt, B, NULL); } +limit_clause_opt(A) ::= LIMIT unsigned_integer(B) OFFSET unsigned_integer(C). { A = createLimitNode(pCxt, B, C); } +limit_clause_opt(A) ::= LIMIT unsigned_integer(C) NK_COMMA unsigned_integer(B). { A = createLimitNode(pCxt, B, C); } /************************************************ subquery ************************************************************/ subquery(A) ::= NK_LP(B) query_expression(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, C); } diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index fa656667af..708c8aa6eb 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -1287,14 +1287,14 @@ _err: return NULL; } -SNode* createLimitNode(SAstCreateContext* pCxt, const SToken* pLimit, const SToken* pOffset) { +SNode* createLimitNode(SAstCreateContext* pCxt, SNode* pLimit, SNode* pOffset) { CHECK_PARSER_STATUS(pCxt); SLimitNode* limitNode = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_LIMIT, (SNode**)&limitNode); CHECK_MAKE_NODE(limitNode); - limitNode->limit = taosStr2Int64(pLimit->z, NULL, 10); + limitNode->limit = (SValueNode*)pLimit; if (NULL != pOffset) { - limitNode->offset = taosStr2Int64(pOffset->z, NULL, 10); + limitNode->offset = (SValueNode*)pOffset; } return (SNode*)limitNode; _err: diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 86490ce4c8..4cb0145138 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -4729,16 +4729,20 @@ static int32_t translateJoinTable(STranslateContext* pCxt, SJoinTableNode* pJoin return buildInvalidOperationMsg(&pCxt->msgBuf, "WINDOW_OFFSET required for WINDOW join"); } - if (TSDB_CODE_SUCCESS == code && NULL != pJoinTable->pJLimit) { + if (TSDB_CODE_SUCCESS == code && NULL != pJoinTable->pJLimit && NULL != ((SLimitNode*)pJoinTable->pJLimit)->limit) { if (*pSType != JOIN_STYPE_ASOF && *pSType != JOIN_STYPE_WIN) { return buildInvalidOperationMsgExt(&pCxt->msgBuf, "JLIMIT not supported for %s join", getFullJoinTypeString(type, *pSType)); } SLimitNode* pJLimit = (SLimitNode*)pJoinTable->pJLimit; - if (pJLimit->limit > JOIN_JLIMIT_MAX_VALUE || pJLimit->limit < 0) { + code = translateExpr(pCxt, &pJoinTable->pJLimit); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + if (pJLimit->limit->datum.i > JOIN_JLIMIT_MAX_VALUE || pJLimit->limit->datum.i < 0) { return buildInvalidOperationMsg(&pCxt->msgBuf, "JLIMIT value is out of valid range [0, 1024]"); } - if (0 == pJLimit->limit) { + if (0 == pJLimit->limit->datum.i) { pCurrSmt->isEmptyResult = true; } } @@ -6994,16 +6998,22 @@ static int32_t translateFrom(STranslateContext* pCxt, SNode** pTable) { } static int32_t checkLimit(STranslateContext* pCxt, SSelectStmt* pSelect) { - if ((NULL != pSelect->pLimit && pSelect->pLimit->offset < 0) || - (NULL != pSelect->pSlimit && pSelect->pSlimit->offset < 0)) { + int32_t code = translateExpr(pCxt, (SNode**)&pSelect->pLimit); + if (TSDB_CODE_SUCCESS == code) { + code = translateExpr(pCxt, (SNode**)&pSelect->pSlimit); + } + + if ((TSDB_CODE_SUCCESS == code) && + ((NULL != pSelect->pLimit && pSelect->pLimit->offset && pSelect->pLimit->offset->datum.i < 0) || + (NULL != pSelect->pSlimit && pSelect->pSlimit->offset && pSelect->pSlimit->offset->datum.i < 0))) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_OFFSET_LESS_ZERO); } - if (NULL != pSelect->pSlimit && (NULL == pSelect->pPartitionByList && NULL == pSelect->pGroupByList)) { + if ((TSDB_CODE_SUCCESS == code) && NULL != pSelect->pSlimit && (NULL == pSelect->pPartitionByList && NULL == pSelect->pGroupByList)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_GROUP_BY); } - return TSDB_CODE_SUCCESS; + return code; } static int32_t createPrimaryKeyColByTable(STranslateContext* pCxt, STableNode* pTable, SNode** pPrimaryKey) { @@ -7482,7 +7492,7 @@ static int32_t translateSetOperOrderBy(STranslateContext* pCxt, SSetOperator* pS } static int32_t checkSetOperLimit(STranslateContext* pCxt, SLimitNode* pLimit) { - if ((NULL != pLimit && pLimit->offset < 0)) { + if ((NULL != pLimit && NULL != pLimit->offset && pLimit->offset->datum.i < 0)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_OFFSET_LESS_ZERO); } return TSDB_CODE_SUCCESS; diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index b9f5d42604..e7ea028e5a 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -3705,8 +3705,14 @@ static int32_t rewriteTailOptCreateLimit(SNode* pLimit, SNode* pOffset, SNode** if (NULL == pLimitNode) { return code; } - pLimitNode->limit = NULL == pLimit ? -1 : ((SValueNode*)pLimit)->datum.i; - pLimitNode->offset = NULL == pOffset ? 0 : ((SValueNode*)pOffset)->datum.i; + code = nodesMakeValueNodeFromInt64(NULL == pLimit ? -1 : ((SValueNode*)pLimit)->datum.i, (SNode**)&pLimitNode->limit); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + code = nodesMakeValueNodeFromInt64(NULL == pOffset ? 0 : ((SValueNode*)pOffset)->datum.i, (SNode**)&pLimitNode->offset); + if (TSDB_CODE_SUCCESS != code) { + return code; + } *pOutput = (SNode*)pLimitNode; return TSDB_CODE_SUCCESS; } diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index 31d51fad9b..9513e90c50 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -1823,9 +1823,9 @@ static int32_t createAggPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, if (NULL == pAgg) { return terrno; } - if (pAgg->node.pSlimit) { + if (pAgg->node.pSlimit && ((SLimitNode*)pAgg->node.pSlimit)->limit) { pSubPlan->dynamicRowThreshold = true; - pSubPlan->rowsThreshold = ((SLimitNode*)pAgg->node.pSlimit)->limit; + pSubPlan->rowsThreshold = ((SLimitNode*)pAgg->node.pSlimit)->limit->datum.i; } pAgg->mergeDataBlock = (GROUP_ACTION_KEEP == pAggLogicNode->node.groupAction ? false : true); diff --git a/source/libs/planner/src/planSpliter.c b/source/libs/planner/src/planSpliter.c index fe66023332..03de345936 100644 --- a/source/libs/planner/src/planSpliter.c +++ b/source/libs/planner/src/planSpliter.c @@ -133,8 +133,12 @@ static int32_t splCreateExchangeNode(SSplitContext* pCxt, SLogicNode* pChild, SE nodesDestroyNode((SNode*)pExchange); return code; } - ((SLimitNode*)pChild->pLimit)->limit += ((SLimitNode*)pChild->pLimit)->offset; - ((SLimitNode*)pChild->pLimit)->offset = 0; + if (((SLimitNode*)pChild->pLimit)->limit && ((SLimitNode*)pChild->pLimit)->offset) { + ((SLimitNode*)pChild->pLimit)->limit->datum.i += ((SLimitNode*)pChild->pLimit)->offset->datum.i; + } + if (((SLimitNode*)pChild->pLimit)->offset) { + ((SLimitNode*)pChild->pLimit)->offset->datum.i = 0; + } } *pOutput = pExchange; @@ -679,8 +683,12 @@ static int32_t stbSplCreateMergeNode(SSplitContext* pCxt, SLogicSubplan* pSubpla if (TSDB_CODE_SUCCESS == code && NULL != pSplitNode->pLimit) { pMerge->node.pLimit = NULL; code = nodesCloneNode(pSplitNode->pLimit, &pMerge->node.pLimit); - ((SLimitNode*)pSplitNode->pLimit)->limit += ((SLimitNode*)pSplitNode->pLimit)->offset; - ((SLimitNode*)pSplitNode->pLimit)->offset = 0; + if (((SLimitNode*)pSplitNode->pLimit)->limit && ((SLimitNode*)pSplitNode->pLimit)->offset) { + ((SLimitNode*)pSplitNode->pLimit)->limit->datum.i += ((SLimitNode*)pSplitNode->pLimit)->offset->datum.i; + } + if (((SLimitNode*)pSplitNode->pLimit)->offset) { + ((SLimitNode*)pSplitNode->pLimit)->offset->datum.i = 0; + } } if (TSDB_CODE_SUCCESS == code) { code = stbSplRewriteFromMergeNode(pMerge, pSplitNode); @@ -1427,8 +1435,12 @@ static int32_t stbSplGetSplitNodeForScan(SStableSplitInfo* pInfo, SLogicNode** p if (NULL == (*pSplitNode)->pLimit) { return code; } - ((SLimitNode*)pInfo->pSplitNode->pLimit)->limit += ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset; - ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset = 0; + if (((SLimitNode*)pInfo->pSplitNode->pLimit)->limit && ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset) { + ((SLimitNode*)pInfo->pSplitNode->pLimit)->limit->datum.i += ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset->datum.i; + } + if (((SLimitNode*)pInfo->pSplitNode->pLimit)->offset) { + ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset->datum.i = 0; + } } } return TSDB_CODE_SUCCESS; @@ -1579,8 +1591,12 @@ static int32_t stbSplSplitMergeScanNode(SSplitContext* pCxt, SLogicSubplan* pSub int32_t code = stbSplCreateMergeScanNode(pScan, &pMergeScan, &pMergeKeys); if (TSDB_CODE_SUCCESS == code) { if (NULL != pMergeScan->pLimit) { - ((SLimitNode*)pMergeScan->pLimit)->limit += ((SLimitNode*)pMergeScan->pLimit)->offset; - ((SLimitNode*)pMergeScan->pLimit)->offset = 0; + if (((SLimitNode*)pMergeScan->pLimit)->limit && ((SLimitNode*)pMergeScan->pLimit)->offset) { + ((SLimitNode*)pMergeScan->pLimit)->limit->datum.i += ((SLimitNode*)pMergeScan->pLimit)->offset->datum.i; + } + if (((SLimitNode*)pMergeScan->pLimit)->offset) { + ((SLimitNode*)pMergeScan->pLimit)->offset->datum.i = 0; + } } code = stbSplCreateMergeNode(pCxt, pSubplan, (SLogicNode*)pScan, pMergeKeys, pMergeScan, groupSort, true); } diff --git a/source/libs/planner/src/planUtil.c b/source/libs/planner/src/planUtil.c index f03e2d8ab0..1cc8c93d29 100644 --- a/source/libs/planner/src/planUtil.c +++ b/source/libs/planner/src/planUtil.c @@ -592,8 +592,12 @@ int32_t cloneLimit(SLogicNode* pParent, SLogicNode* pChild, uint8_t cloneWhat, b if (pParent->pLimit && (cloneWhat & CLONE_LIMIT)) { code = nodesCloneNode(pParent->pLimit, (SNode**)&pLimit); if (TSDB_CODE_SUCCESS == code) { - pLimit->limit += pLimit->offset; - pLimit->offset = 0; + if (pLimit->limit && pLimit->offset) { + pLimit->limit->datum.i += pLimit->offset->datum.i; + } + if (pLimit->offset) { + pLimit->offset->datum.i = 0; + } cloned = true; } } @@ -601,8 +605,12 @@ int32_t cloneLimit(SLogicNode* pParent, SLogicNode* pChild, uint8_t cloneWhat, b if (pParent->pSlimit && (cloneWhat & CLONE_SLIMIT)) { code = nodesCloneNode(pParent->pSlimit, (SNode**)&pSlimit); if (TSDB_CODE_SUCCESS == code) { - pSlimit->limit += pSlimit->offset; - pSlimit->offset = 0; + if (pSlimit->limit && pSlimit->offset) { + pSlimit->limit->datum.i += pSlimit->offset->datum.i; + } + if (pSlimit->offset) { + pSlimit->offset->datum.i = 0; + } cloned = true; } }