From f8111bbf2d39d0a46d5f19da516965fe529ae340 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:56:28 +0000 Subject: [PATCH 01/14] build(deps): bump golang.org/x/crypto in /tools/keeper Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.31.0. - [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.31.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] --- tools/keeper/go.mod | 6 +++--- tools/keeper/go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/keeper/go.mod b/tools/keeper/go.mod index f8edf2709b4f..00a399768dee 100644 --- a/tools/keeper/go.mod +++ b/tools/keeper/go.mod @@ -70,10 +70,10 @@ require ( github.com/ugorji/go/codec v1.2.12 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/tools/keeper/go.sum b/tools/keeper/go.sum index 8f6e9bd13afd..f879c731ba46 100644 --- a/tools/keeper/go.sum +++ b/tools/keeper/go.sum @@ -424,8 +424,8 @@ golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -573,8 +573,8 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -583,8 +583,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From e98e21553519a48a907a322edc5adbe0e9372e5d Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Sun, 22 Dec 2024 11:16:06 +0800 Subject: [PATCH 02/14] fix: lock debug invalid read issue --- source/libs/qworker/inc/qwInt.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/libs/qworker/inc/qwInt.h b/source/libs/qworker/inc/qwInt.h index 65f7cd772fc7..6474a1ab3037 100644 --- a/source/libs/qworker/inc/qwInt.h +++ b/source/libs/qworker/inc/qwInt.h @@ -477,6 +477,8 @@ extern SQueryMgmt gQueryMgmt; } \ } while (0) + +#if 0 #define QW_UNLOCK(type, _lock) \ do { \ if (QW_READ == (type)) { \ @@ -505,6 +507,16 @@ extern SQueryMgmt gQueryMgmt; } \ } \ } while (0) +#else +#define QW_UNLOCK(type, _lock) \ + do { \ + if (QW_READ == (type)) { \ + taosRUnLockLatch(_lock); \ + } else { \ + taosWUnLockLatch(_lock); \ + } \ + } while (0) +#endif extern SQWorkerMgmt gQwMgmt; From 868701c01fd9f211253cb05009dfada724f0e2e7 Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Mon, 23 Dec 2024 09:39:25 +0800 Subject: [PATCH 03/14] test coverage for planner/nodes --- source/libs/nodes/test/nodesTestMain.cpp | 80 ++++++++++++++++++++++++ source/libs/planner/src/planValidator.c | 29 +-------- tests/system-test/2-query/union.py | 9 +++ 3 files changed, 92 insertions(+), 26 deletions(-) diff --git a/source/libs/nodes/test/nodesTestMain.cpp b/source/libs/nodes/test/nodesTestMain.cpp index eb69017b116c..e24a979b1e71 100644 --- a/source/libs/nodes/test/nodesTestMain.cpp +++ b/source/libs/nodes/test/nodesTestMain.cpp @@ -128,6 +128,86 @@ TEST(NodesTest, sort) { nodesDestroyList(l); } +TEST(NodesTest, match) { + SNode* pOperator = NULL; + int32_t code = nodesMakeNode(QUERY_NODE_OPERATOR, (SNode**)&pOperator); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + SOperatorNode* pOp = (SOperatorNode*)pOperator; + SOperatorNode* pLeft = NULL; + ASSERT_EQ(TSDB_CODE_SUCCESS, nodesMakeNode(QUERY_NODE_OPERATOR, (SNode**)&pLeft)); + ASSERT_EQ(TSDB_CODE_SUCCESS, nodesMakeNode(QUERY_NODE_VALUE, &pLeft->pLeft)); + ((SValueNode*)(pLeft->pLeft))->literal = taosStrdup("10"); + ASSERT_EQ(TSDB_CODE_SUCCESS, nodesMakeNode(QUERY_NODE_VALUE, &pLeft->pRight)); + ((SValueNode*)(pLeft->pRight))->literal = taosStrdup("5"); + pOp->pLeft = (SNode*)pLeft; + ASSERT_EQ(TSDB_CODE_SUCCESS, nodesMakeNode(QUERY_NODE_VALUE, &pOp->pRight)); + ((SValueNode*)(pOp->pRight))->literal = taosStrdup("3"); + pOp->opType = OP_TYPE_GREATER_THAN; + + SNode* pOperatorClone = NULL; + code = nodesCloneNode(pOperator, &pOperatorClone); + ASSERT_TRUE(nodesMatchNode(pOperator, pOperatorClone)); + + SNode* pValue = NULL; + code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pValue); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ((SValueNode*)pValue)->literal = taosStrdup("10"); + ASSERT_FALSE(nodesMatchNode(pOperator, pValue)); + + SNode* pValueClone = NULL; + code = nodesCloneNode(pValue, &pValueClone); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(nodesMatchNode(pValue, pValueClone)); + nodesDestroyNode(pValue); + nodesDestroyNode(pValueClone); + + SNode* pColumn = NULL, *pColumnClone = NULL; + code = nodesMakeNode(QUERY_NODE_COLUMN, &pColumn); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + strcpy(((SColumnNode*)pColumn)->colName, "column"); + strcpy(((SColumnNode*)pColumn)->tableName, "table"); + strcpy(((SColumnNode*)pColumn)->dbName, "db"); + strcpy(((SColumnNode*)pColumn)->node.aliasName, "column"); + ASSERT_FALSE(nodesMatchNode(pOperator, pColumn)); + code = nodesCloneNode(pColumn, &pColumnClone); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(nodesMatchNode(pColumn, pColumnClone)); + nodesDestroyNode(pColumn); + nodesDestroyNode(pColumnClone); + + SNode* pFunction = NULL, *pFunctionClone = NULL; + code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunction); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ((SFunctionNode*)pFunction)->funcId = 1; + strcpy(((SFunctionNode*)pFunction)->functionName, "now"); + ASSERT_FALSE(nodesMatchNode(pOperator, pFunction)); + code = nodesCloneNode(pFunction, &pFunctionClone); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(nodesMatchNode(pFunction, pFunctionClone)); + nodesDestroyNode(pFunctionClone); + nodesDestroyNode(pFunction); + + SNode* pLogicCondition = NULL, *pLogicConditionClone = NULL; + code = nodesMakeNode(QUERY_NODE_LOGIC_CONDITION, (SNode**)&pLogicCondition); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ((SLogicConditionNode*)pLogicCondition)->condType = LOGIC_COND_TYPE_AND; + ((SLogicConditionNode*)pLogicCondition)->pParameterList = NULL; + code = nodesMakeList(&((SLogicConditionNode*)pLogicCondition)->pParameterList); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = nodesListAppend((SNodeList*)((SLogicConditionNode*)pLogicCondition)->pParameterList, pOperator); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = nodesListAppend(((SLogicConditionNode*)pLogicCondition)->pParameterList, pOperatorClone); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = nodesCloneNode(pLogicCondition, &pLogicConditionClone); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(nodesMatchNode(pLogicCondition, pLogicConditionClone)); + ASSERT_FALSE(nodesMatchNode(pLogicCondition, pFunctionClone)); + + nodesDestroyNode(pLogicCondition); + nodesDestroyNode(pLogicConditionClone); +} + int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/source/libs/planner/src/planValidator.c b/source/libs/planner/src/planValidator.c index 6b7b46cfa762..a3b09dff228b 100755 --- a/source/libs/planner/src/planValidator.c +++ b/source/libs/planner/src/planValidator.c @@ -55,16 +55,10 @@ int32_t validateQueryPlanNode(SValidatePlanContext* pCxt, SQueryPlan* pPlan) { SNode* pSubNode = NULL; SNodeListNode* pSubplans = (SNodeListNode*)pNode; FOREACH(pSubNode, pSubplans->pNodeList) { - if (QUERY_NODE_PHYSICAL_SUBPLAN != nodeType(pNode)) { - code = TSDB_CODE_PLAN_INTERNAL_ERROR; - break; - } - code = doValidatePhysiNode(pCxt, pSubNode); - if (code) { - break; - } + if (code) break; } + if (code) break; } return code; @@ -142,24 +136,7 @@ int32_t validateQueryPlan(SPlanContext* pCxt, SQueryPlan* pPlan) { int32_t code = TSDB_CODE_SUCCESS; SNode* pNode = NULL; - FOREACH(pNode, pPlan->pSubplans) { - if (QUERY_NODE_NODE_LIST != nodeType(pNode)) { - code = TSDB_CODE_PLAN_INTERNAL_ERROR; - break; - } - - SNode* pSubNode = NULL; - SNodeListNode* pSubplans = (SNodeListNode*)pNode; - FOREACH(pSubNode, pSubplans->pNodeList) { - code = doValidatePhysiNode(&cxt, pSubNode); - if (code) { - break; - } - } - if (code) { - break; - } - } + code = validateQueryPlanNode(&cxt, pPlan); destoryValidatePlanContext(&cxt); return code; diff --git a/tests/system-test/2-query/union.py b/tests/system-test/2-query/union.py index d462873ab9eb..f87df22948ec 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -406,6 +406,14 @@ def test_TS_5630(self): tdSql.checkRows(6) ##tdSql.execute("drop database ep_iot") + def test_case_for_nodes_match_node(self): + sql = "create table nt (ts timestamp, c1 int primary key, c2 int)" + tdSql.execute(sql, queryTimes=1) + sql = 'select diff (ts) from (select * from tt union select * from tt order by c1, case when ts < now - 1h then ts + 1h else ts end) partition by c1, case when ts < now - 1h then ts + 1h else ts end' + tdSql.error(sql, -2147473917) + + pass + def run(self): tdSql.prepare() self.test_TS_5630() @@ -427,6 +435,7 @@ def run(self): tdLog.printNoPrefix("==========step4:after wal, all check again ") self.all_test() self.test_TD_33137() + self.test_case_for_nodes_match_node() def test_TD_33137(self): sql = "select 'asd' union all select 'asdasd'" From aa9bab4f3d57cf0a4aec160b999beb88f105262e Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Mon, 23 Dec 2024 10:29:05 +0800 Subject: [PATCH 04/14] Update 02-management.md --- docs/zh/06-advanced/06-TDgpt/02-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/06-advanced/06-TDgpt/02-management.md b/docs/zh/06-advanced/06-TDgpt/02-management.md index b37c39944f92..6803c5d35618 100644 --- a/docs/zh/06-advanced/06-TDgpt/02-management.md +++ b/docs/zh/06-advanced/06-TDgpt/02-management.md @@ -110,7 +110,7 @@ SHOW ANODES; taos> show anodes; id | url | status | create_time | update_time | ================================================================================================================== - 1 | 192.168.0.1:6090 | ready | 2024-11-28 18:44:27.089 | 2024-11-28 18:44:27.089 | + 1 | 192.168.0.1:6090 | ready | 2024-11-28 18:44:27.089 | 2024-11-28 18:44:27.089 | Query OK, 1 row(s) in set (0.037205s) ``` From 0ca9054e60d09ca7b485e4269509a1139307bf54 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Mon, 23 Dec 2024 10:34:21 +0800 Subject: [PATCH 05/14] Update 02-management.md --- docs/zh/06-advanced/06-TDgpt/02-management.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/zh/06-advanced/06-TDgpt/02-management.md b/docs/zh/06-advanced/06-TDgpt/02-management.md index 6803c5d35618..d977e25dc346 100644 --- a/docs/zh/06-advanced/06-TDgpt/02-management.md +++ b/docs/zh/06-advanced/06-TDgpt/02-management.md @@ -66,7 +66,7 @@ pidfile = /usr/local/taos/taosanode/taosanode.pid # uWSGI log files logto = /var/log/taos/taosanode/taosanode.log -# wWSGI monitor port +# uWSGI monitor port stats = 127.0.0.1:8387 # python virtual environment directory, used by Anode @@ -86,7 +86,7 @@ log-level = DEBUG **提示** 请勿设置 `daemonize` 参数,该参数会导致 uWSGI 与 systemctl 冲突,从而导致 Anode 无法正常启动。 -上面的示例配置文件 `taosanode.ini` 只包含了使用 Anode 提供服务的基础配置参数,对于 uWSGI 的其他配置参数的设置及其说明请参考 [uWSGIS官方文档](https://uwsgi-docs-zh.readthedocs.io/zh-cn/latest/Options.html)。 +上面的示例配置文件 `taosanode.ini` 只包含了使用 Anode 提供服务的基础配置参数,对于 uWSGI 的其他配置参数的设置及其说明请参考 [uWSGI 官方文档](https://uwsgi-docs-zh.readthedocs.io/zh-cn/latest/Options.html)。 Anode 运行配置主要是以下: - app-log: Anode 服务运行产生的日志,用户可以调整其到需要的位置 From 589b36d7fc44de76631a3d909516f4beb1e73556 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Mon, 23 Dec 2024 10:38:06 +0800 Subject: [PATCH 06/14] Update index.md --- docs/zh/06-advanced/06-TDgpt/04-forecast/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md index 3981fff8c619..71b97aa996a7 100644 --- a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md +++ b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md @@ -41,7 +41,7 @@ algo=expr1 "} ``` -1. `column_expr`:预测的时序数据列。与异常检测相同,只支持数值类型列输入。 +1. `column_expr`:预测的时序数据列,只支持数值类型列输入。 2. `options`:预测函数的参数。字符串类型,其中使用 K=V 方式调用算法及相关参数。采用逗号分隔的 K=V 字符串表示,其中的字符串不需要使用单引号、双引号、或转义号等符号,不能使用中文及其他宽字符。预测支持 `conf`, `every`, `rows`, `start`, `rows` 几个控制参数,其含义如下: ### 参数说明 From 6a0206d3171daa3990407e649b3763f05e8d21cb Mon Sep 17 00:00:00 2001 From: "pengrongkun94@qq.com" Date: Mon, 23 Dec 2024 10:57:35 +0800 Subject: [PATCH 07/14] fix some case error --- source/libs/parser/src/parInsertStmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 37d7b2f43104..74fac463f125 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -509,6 +509,9 @@ int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const c STag* pTag = NULL; for (int c = 0; c < tags->numOfBound; ++c) { + if (bind == NULL) { + break; + } if (bind[c].is_null && bind[c].is_null[0]) { continue; } From 6523f977b42bc9810f96577ecea3b4cd304e3318 Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Mon, 23 Dec 2024 12:12:32 +0800 Subject: [PATCH 08/14] fix test case union.py --- tests/system-test/2-query/union.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/system-test/2-query/union.py b/tests/system-test/2-query/union.py index f87df22948ec..380b7879c407 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -407,13 +407,11 @@ def test_TS_5630(self): ##tdSql.execute("drop database ep_iot") def test_case_for_nodes_match_node(self): - sql = "create table nt (ts timestamp, c1 int primary key, c2 int)" + sql = "create table db.nt (ts timestamp, c1 int primary key, c2 int)" tdSql.execute(sql, queryTimes=1) - sql = 'select diff (ts) from (select * from tt union select * from tt order by c1, case when ts < now - 1h then ts + 1h else ts end) partition by c1, case when ts < now - 1h then ts + 1h else ts end' + sql = 'select diff (ts) from (select * from db.tt union select * from db.tt order by c1, case when ts < now - 1h then ts + 1h else ts end) partition by c1, case when ts < now - 1h then ts + 1h else ts end' tdSql.error(sql, -2147473917) - pass - def run(self): tdSql.prepare() self.test_TS_5630() From 5ba7de5844867bd2e978506bfba5a56991d20b84 Mon Sep 17 00:00:00 2001 From: xiao-77 Date: Mon, 23 Dec 2024 15:37:26 +0800 Subject: [PATCH 09/14] Doc(cfg):support dyn alter disable create file. --- docs/en/26-tdinternal/01-arch.md | 33 +++++++++++++++++++-- docs/zh/26-tdinternal/01-arch.md | 50 +++++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/docs/en/26-tdinternal/01-arch.md b/docs/en/26-tdinternal/01-arch.md index 55c56a768122..ef689e0b74ac 100644 --- a/docs/en/26-tdinternal/01-arch.md +++ b/docs/en/26-tdinternal/01-arch.md @@ -328,8 +328,35 @@ In addition to precomputation, TDengine also supports various downsampling stora ### Multi-Level Storage and Object Storage -By default, TDengine stores all data in the /var/lib/taos directory. To expand storage capacity, reduce potential bottlenecks caused by file reading, and enhance data throughput, TDengine allows the use of the configuration parameter `dataDir` to enable the cluster to utilize multiple mounted hard drives simultaneously. +By default, TDengine saves all data in /var/lib/taos directory, and the data files of each vnode are saved in a different directory under this directory. In order to expand the storage space, minimize the bottleneck of file reading and improve the data throughput rate, TDengine can configure the system parameter "dataDir" to allow multiple mounted hard disks to be used by system at the same time. In addition, TDengine also provides the function of tiered data storage, i.e. storage on different storage media according to the time stamps of data files. For example, the latest data is stored on SSD, the data older than a week is stored on local hard disk, and data older than four weeks is stored on network storage device. This reduces storage costs and ensures efficient data access. The movement of data on different storage media is automatically done by the system and is completely transparent to applications. Tiered storage of data is also configured through the system parameter "dataDir". + +dataDir format is as follows: + +``` +dataDir data_path [tier_level] [primary] [disable_create_new_file] +``` + +Where `data_path` is the folder path of mount point, and `tier_level` is the media storage-tier. The higher the media storage-tier, means the older the data file. Multiple hard disks can be mounted at the same storage-tier, and data files on the same storage-tier are distributed on all hard disks within the tier. TDengine supports up to 3 tiers of storage, so tier_level values are 0, 1, and 2. When configuring dataDir, there must be only one mount path without specifying tier_level, which is called special mount disk (path). The mount path defaults to level 0 storage media and contains special file links, which cannot be removed, otherwise it will have a devastating impact on the written data. And `primary` means whether the data dir is the primary mount point. Enter 0 for false or 1 for true. The default value is 1. A TDengine cluster can have only one `primary` mount point, which must be on tier 0. And `disable_create_new_file` means whether to prohibit the creation of new file sets on the specified mount point. Enter 0 for false and 1 for true. The default value is 0. Tier 0 storage must have at least one mount point with disable_create_new_file set to 0. Tier 1 and tier 2 storage do not have this restriction. + +Suppose there is a physical node with six mountable hard disks/mnt/disk1,/mnt/disk2, ..., /mnt/disk6, where disk1 and disk2 need to be designated as level 0 storage media, disk3 and disk4 are level 1 storage media, and disk5 and disk6 are level 2 storage media. Disk1 is a special mount disk, you can configure it in/etc/taos/taos.cfg as follows: + +``` +dataDir /mnt/disk1/taos 0 1 0 +dataDir /mnt/disk2/taos 0 0 0 +dataDir /mnt/disk3/taos 1 0 0 +dataDir /mnt/disk4/taos 1 0 1 +dataDir /mnt/disk5/taos 2 0 0 +dataDir /mnt/disk6/taos 2 0 0 +``` + +Mounted disks can also be a non-local network disk, as long as the system can access it. + +You can use the following command to dynamically modify dataDir to control whether disable_create_new_file is enabled for the current directory. + +``` +alter dnode 1 "/mnt/disk2/taos 1"; +``` + +Note: Tiered Storage is only supported in Enterprise Edition -Additionally, TDengine offers tiered data storage functionality, allowing users to store data from different time periods in directories on different storage devices. This facilitates the separation of "hot" data (frequently accessed) and "cold" data (less frequently accessed), making full use of various storage resources while saving costs. For example, data that is recently collected and requires frequent access can be stored on high-performance solid-state drives due to their high read performance requirements. Data that exceeds a certain age and has lower query demands can be stored on mechanically driven hard disks, which are relatively cheaper. -To further reduce storage costs, TDengine also supports storing time-series data in object storage systems. Through its innovative design, in most cases, the performance of querying time-series data from object storage systems is close to half that of local disks, and in some scenarios, the performance can even be comparable to local disks. Additionally, TDengine allows users to perform delete and update operations on time-series data stored in object storage. diff --git a/docs/zh/26-tdinternal/01-arch.md b/docs/zh/26-tdinternal/01-arch.md index 7091ca96615b..242adb11b0e7 100644 --- a/docs/zh/26-tdinternal/01-arch.md +++ b/docs/zh/26-tdinternal/01-arch.md @@ -323,10 +323,52 @@ TDengine 采用了一种数据驱动的策略来实现缓存数据的持久化 除了预计算功能以外,TDengine 还支持对原始数据进行多种降采样存储。一种降采样存储方式是 Rollup SMA,它能够自动对原始数据进行降采样存储,并支持 3 个不同的数据保存层级,用户可以指定每层数据的聚合周期和保存时长。这对于那些关注数据趋势的场景尤为适用,其核心目的是减少存储开销并提高查询速度。另一种降采样存储方式是 Time-Range-Wise SMA,它可以根据聚合结果进行降采样存储,非常适合于高频的 interval 查询场景。该功能采用与普通流计算相同的逻辑,并允许用户通过设置watermark 来处理延时数据,相应地,实际的查询结果也会有一定的时间延迟。 -### 多级存储与对象存储 +### 多级存储 -在默认情况下,TDengine 将所有数据存储在 /var/lib/taos 目录中。为了扩展存储容量,减少文件读取可能导致的瓶颈,并提升数据吞吐量,TDengine 允许通过配置参数dataDir,使得集群能够同时利用挂载的多块硬盘。 +说明:多级存储功能仅企业版支持,从 2.0.16.0 版本开始提供。 -此外,TDengine 还提供了数据分级存储的功能,允许用户将不同时间段的数据存储在不同存储设备的目录中,以此实现将“热”数据和“冷”数据分开存储。这样做可以充分利用各种存储资源,同时节约成本。例如,对于最新采集且需要频繁访问的数据,由于其读取性能要求较高,用户可以配置将这些数据存储在高性能的固态硬盘上。而对于超过一定期限、查询需求较低的数据,则可以将其存储在成本相对较低的机械硬盘上。 +在默认配置下,TDengine 会将所有数据保存在 /var/lib/taos 目录下,而且每个 vnode 的数据文件保存在该目录下的不同目录。为扩大存储空间,尽量减少文件读取的瓶颈,提高数据吞吐率 TDengine 可通过配置系统参数 dataDir 让多个挂载的硬盘被系统同时使用。 -为了进一步降低存储成本,TDengine 还支持将时序数据存储在对象存储系统中。通过其创新性的设计,在大多数情况下,从对象存储系统中查询时序数据的性能接近本地硬盘的一半,而在某些场景下,性能甚至可以与本地硬盘相媲美。同时,TDengine 还允许用户对存储在对象存储中的时序数据执行删除和更新操作。 +除此之外,TDengine 也提供了数据分级存储的功能,将不同时间段的数据存储在挂载的不同介质上的目录里,从而实现不同“热度”的数据存储在不同的存储介质上,充分利用存储,节约成本。比如,最新采集的数据需要经常访问,对硬盘的读取性能要求高,那么用户可以配置将这些数据存储在 SSD 盘上。超过一定期限的数据,查询需求量没有那么高,那么可以存储在相对便宜的 HDD 盘上。 + +多级存储支持 3 级,每级最多可配置 128 个挂载点。 + +TDengine 多级存储配置方式如下(在配置文件/etc/taos/taos.cfg 中): + +``` +dataDir [path] +``` + +- path: 挂载点的文件夹路径 +- level: 介质存储等级,取值为 0,1,2。 + 0 级存储最新的数据,1 级存储次新的数据,2 级存储最老的数据,省略默认为 0。 + 各级存储之间的数据流向:0 级存储 -> 1 级存储 -> 2 级存储。 + 同一存储等级可挂载多个硬盘,同一存储等级上的数据文件分布在该存储等级的所有硬盘上。 + 需要说明的是,数据在不同级别的存储介质上的移动,是由系统自动完成的,用户无需干预。 +- primary: 是否为主挂载点,0(否)或 1(是),省略默认为 1。 +- disable_create_new_file: 是否禁止创建新文件组,0(否)或 1(是),省略默认为 0。 + +在配置中,只允许一个主挂载点的存在(level=0,primary=1),例如采用如下的配置方式: + +``` +dataDir /mnt/data1 0 1 0 +dataDir /mnt/data2 0 0 0 +dataDir /mnt/data3 1 0 0 +dataDir /mnt/data4 1 0 1 +dataDir /mnt/data5 2 0 0 +dataDir /mnt/data6 2 0 0 +``` + +您可以使用以下命令动态修改 dataDir 的 disable 来控制当前目录是否开启 disable_create_new_file 。 +``` +alter dnode 1 "/mnt/disk2/taos 1"; +``` + +:::note + +1. 多级存储不允许跨级配置,合法的配置方案有:仅 0 级,仅 0 级+ 1 级,以及 0 级+ 1 级+ 2 级。而不允许只配置 level=0 和 level=2,而不配置 level=1。 +2. 禁止手动移除使用中的挂载盘,挂载盘目前不支持非本地的网络盘。 +3. 多级存储目前不支持删除已经挂载的硬盘的功能。 +4. 0 级存储至少存在一个 disable_create_new_file 为 0 的挂载点,1 级 和 2 级存储没有该限制。 + +::: \ No newline at end of file From 112754d2c5a20cd540339fb49675a6ff55fabd69 Mon Sep 17 00:00:00 2001 From: xiao-77 Date: Mon, 23 Dec 2024 15:39:16 +0800 Subject: [PATCH 10/14] Fix merge errors. --- docs/zh/26-tdinternal/01-arch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/26-tdinternal/01-arch.md b/docs/zh/26-tdinternal/01-arch.md index 242adb11b0e7..9cc1ef6f024e 100644 --- a/docs/zh/26-tdinternal/01-arch.md +++ b/docs/zh/26-tdinternal/01-arch.md @@ -323,7 +323,7 @@ TDengine 采用了一种数据驱动的策略来实现缓存数据的持久化 除了预计算功能以外,TDengine 还支持对原始数据进行多种降采样存储。一种降采样存储方式是 Rollup SMA,它能够自动对原始数据进行降采样存储,并支持 3 个不同的数据保存层级,用户可以指定每层数据的聚合周期和保存时长。这对于那些关注数据趋势的场景尤为适用,其核心目的是减少存储开销并提高查询速度。另一种降采样存储方式是 Time-Range-Wise SMA,它可以根据聚合结果进行降采样存储,非常适合于高频的 interval 查询场景。该功能采用与普通流计算相同的逻辑,并允许用户通过设置watermark 来处理延时数据,相应地,实际的查询结果也会有一定的时间延迟。 -### 多级存储 +### 多级存储与对象存储 说明:多级存储功能仅企业版支持,从 2.0.16.0 版本开始提供。 From 4adf24b466bba5999ced38929f92397eee7df96a Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Mon, 23 Dec 2024 18:25:25 +0800 Subject: [PATCH 11/14] ci(stream):add stream unit test --- source/libs/stream/inc/streamInt.h | 2 + source/libs/stream/src/streamCheckpoint.c | 3 +- .../libs/stream/test/streamCheckPointTest.cpp | 125 ++++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/source/libs/stream/inc/streamInt.h b/source/libs/stream/inc/streamInt.h index 41ac0117f362..7af64c041d71 100644 --- a/source/libs/stream/inc/streamInt.h +++ b/source/libs/stream/inc/streamInt.h @@ -252,6 +252,8 @@ void chkptFailedByRetrieveReqToSource(SStreamTask* pTask, int64_t checkpointId); int32_t uploadCheckpointData(SStreamTask* pTask, int64_t checkpointId, int64_t dbRefId, ECHECKPOINT_BACKUP_TYPE type); int32_t chkptTriggerRecvMonitorHelper(SStreamTask* pTask, void* param, SArray** ppNotSendList); +int32_t downloadCheckpointByNameS3(const char* id, const char* fname, const char* dstName); +int32_t uploadCheckpointToS3(const char* id, const char* path); #ifdef __cplusplus } diff --git a/source/libs/stream/src/streamCheckpoint.c b/source/libs/stream/src/streamCheckpoint.c index 0ec66cd2ce27..ebde9fe50ed3 100644 --- a/source/libs/stream/src/streamCheckpoint.c +++ b/source/libs/stream/src/streamCheckpoint.c @@ -24,7 +24,6 @@ static int32_t streamTaskUploadCheckpoint(const char* id, const char* path, int6 #ifdef BUILD_NO_CALL static int32_t deleteCheckpoint(const char* id); #endif -static int32_t downloadCheckpointByNameS3(const char* id, const char* fname, const char* dstName); static int32_t continueDispatchCheckpointTriggerBlock(SStreamDataBlock* pBlock, SStreamTask* pTask); static int32_t appendCheckpointIntoInputQ(SStreamTask* pTask, int32_t checkpointType, int64_t checkpointId, int32_t transId, int32_t srcTaskId); @@ -1355,7 +1354,7 @@ void streamTaskSetTriggerDispatchConfirmed(SStreamTask* pTask, int32_t vgId) { } } -static int32_t uploadCheckpointToS3(const char* id, const char* path) { +int32_t uploadCheckpointToS3(const char* id, const char* path) { int32_t code = 0; int32_t nBytes = 0; /* diff --git a/source/libs/stream/test/streamCheckPointTest.cpp b/source/libs/stream/test/streamCheckPointTest.cpp index 80dd3ec1421a..17d8b5556065 100644 --- a/source/libs/stream/test/streamCheckPointTest.cpp +++ b/source/libs/stream/test/streamCheckPointTest.cpp @@ -1,6 +1,7 @@ #include #include "tstream.h" #include "streamInt.h" +#include "tcs.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wwrite-strings" @@ -217,6 +218,10 @@ TEST(StreamTaskAlreadySendTriggerTest, AlreadySendTrigger) { taosArrayDestroy(array); } +int32_t sendReq1111(const SEpSet *pEpSet, SRpcMsg *pMsg) { + return TSDB_CODE_SUCCESS; +} + TEST(ChkptTriggerRecvMonitorHelperTest, chkptTriggerRecvMonitorHelper) { SStreamTask* pTask = NULL; int64_t uid = 2222222222222; @@ -239,6 +244,11 @@ TEST(ChkptTriggerRecvMonitorHelperTest, chkptTriggerRecvMonitorHelper) { pTask->chkInfo.pActiveInfo->transId = 4561111; pTask->chkInfo.startTs = 11111; + SStreamTask upTask; + upTask = *pTask; + streamTaskSetUpstreamInfo(pTask, &upTask); + + streamTaskSetStatusReady(pTask); code = streamTaskHandleEvent(pTask->status.pSM, TASK_EVENT_GEN_CHECKPOINT); ASSERT_EQ(code, TSDB_CODE_SUCCESS); @@ -254,7 +264,21 @@ TEST(ChkptTriggerRecvMonitorHelperTest, chkptTriggerRecvMonitorHelper) { taosArrayPush(pTask->chkInfo.pActiveInfo->pDispatchTriggerList, &triggerInfo); + STaskCheckpointReadyInfo readyInfo; + readyInfo.upstreamNodeId = 789111; + void* pBuf = rpcMallocCont(sizeof(SMsgHead) + 1); + + initRpcMsg(&readyInfo.msg, 0, pBuf, sizeof(SMsgHead) + 1); + taosArrayPush(pTask->chkInfo.pActiveInfo->pReadyMsgList, &readyInfo); + + pTask->chkInfo.pActiveInfo->dispatchTrigger = true; + + SMsgCb msgCb = {0}; + msgCb.sendReqFp = sendReq1111; + msgCb.mgmt = (SMgmtWrapper*)(&msgCb); // hack + tmsgSetDefault(&msgCb); + SArray* array1 = NULL; code = chkptTriggerRecvMonitorHelper(pTask, NULL, &array1); EXPECT_EQ(code, TSDB_CODE_SUCCESS); @@ -268,3 +292,104 @@ TEST(ChkptTriggerRecvMonitorHelperTest, chkptTriggerRecvMonitorHelper) { taosArrayDestroy(array); taosArrayDestroy(array1); } + +TEST(StreamTaskSendCheckpointTriggerMsgTest, SendCheckpointTriggerMsgSuccessTest) { + SStreamTask* pTask = NULL; + int64_t uid = 2222222222222; + SArray* array = taosArrayInit(4, POINTER_BYTES); + int32_t code = tNewStreamTask(uid, TASK_LEVEL__SINK, NULL, false, 0, 0, array, + false, 1, &pTask); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + initTaskLock(pTask); + + const char *path = "/tmp/SendCheckpointTriggerMsgSuccessTest/stream"; + code = streamMetaOpen((path), NULL, NULL, NULL, 0, 0, NULL, &pTask->pMeta); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = streamTaskCreateActiveChkptInfo(&pTask->chkInfo.pActiveInfo); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SRpcHandleInfo rpcInfo; + + int32_t ret = streamTaskSendCheckpointTriggerMsg(pTask, 123, 456, &rpcInfo, code); + + EXPECT_EQ(ret, TSDB_CODE_SUCCESS); +} + +TEST(streamTaskBuildCheckpointTest, streamTaskBuildCheckpointFnTest) { + SStreamTask* pTask = NULL; + int64_t uid = 2222222222222; + SArray* array = taosArrayInit(4, POINTER_BYTES); + int32_t code = tNewStreamTask(uid, TASK_LEVEL__SINK, NULL, false, 0, 0, array, + false, 1, &pTask); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + initTaskLock(pTask); + + const char *path = "/tmp/streamTaskBuildCheckpoinTest/stream"; + code = streamMetaOpen((path), NULL, NULL, NULL, 0, 0, NULL, &pTask->pMeta); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SStreamState *pState = streamStateOpen((char *)path, pTask, 0, 0); + ASSERT(pState != NULL); + + pTask->pBackend = pState->pTdbState->pOwner->pBackend; + + code = streamTaskCreateActiveChkptInfo(&pTask->chkInfo.pActiveInfo); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + char a[] = "localhost"; + memcpy(tsSnodeAddress, a, sizeof(a)); + + int32_t ret = streamTaskBuildCheckpoint(pTask); + + EXPECT_NE(ret, TSDB_CODE_SUCCESS); +} + +int32_t s3GetObjectToFileTest(const char *object_name, const char *fileName) { + return TSDB_CODE_SUCCESS; +} + +TEST(sstreamTaskGetTriggerRecvStatusTest, streamTaskGetTriggerRecvStatusFnTest) { + SStreamTask* pTask = NULL; + int64_t uid = 2222222222222; + SArray* array = taosArrayInit(4, POINTER_BYTES); + int32_t code = tNewStreamTask(uid, TASK_LEVEL__SINK, NULL, false, 0, 0, array, + false, 1, &pTask); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + initTaskLock(pTask); + + SStreamTask upTask; + upTask = *pTask; + code = streamTaskSetUpstreamInfo(pTask, &upTask); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = streamTaskSetUpstreamInfo(pTask, &upTask); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = streamTaskCreateActiveChkptInfo(&pTask->chkInfo.pActiveInfo); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + int32_t recv = 0; + int32_t total = 0; + pTask->info.taskLevel = TASK_LEVEL__SOURCE; + streamTaskGetTriggerRecvStatus(pTask, &recv, &total); + EXPECT_EQ(total, 1); + + pTask->info.taskLevel = TASK_LEVEL__AGG; + streamTaskGetTriggerRecvStatus(pTask, &recv, &total); + EXPECT_EQ(total, 2); + + code = streamTaskDownloadCheckpointData("123", "/root/download", 123); + EXPECT_NE(code, TSDB_CODE_SUCCESS); + + tcsInit(); + + code = uploadCheckpointToS3("123", "/tmp/backend5/stream"); + EXPECT_EQ(code, TSDB_CODE_SUCCESS); + + code = downloadCheckpointByNameS3("123", "/root/download", "123"); + EXPECT_EQ(code, TSDB_CODE_SUCCESS); +} From 0452c21ff600926e6936861444bffbe25c24ebc3 Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Mon, 23 Dec 2024 19:10:10 +0800 Subject: [PATCH 12/14] ci(stream):add stream unit test --- source/libs/stream/test/streamCheckPointTest.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/libs/stream/test/streamCheckPointTest.cpp b/source/libs/stream/test/streamCheckPointTest.cpp index 17d8b5556065..c8297d56b7a0 100644 --- a/source/libs/stream/test/streamCheckPointTest.cpp +++ b/source/libs/stream/test/streamCheckPointTest.cpp @@ -2,6 +2,7 @@ #include "tstream.h" #include "streamInt.h" #include "tcs.h" +#include "tglobal.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wwrite-strings" @@ -386,10 +387,12 @@ TEST(sstreamTaskGetTriggerRecvStatusTest, streamTaskGetTriggerRecvStatusFnTest) EXPECT_NE(code, TSDB_CODE_SUCCESS); tcsInit(); + extern int8_t tsS3EpNum; + tsS3EpNum = 1; code = uploadCheckpointToS3("123", "/tmp/backend5/stream"); EXPECT_EQ(code, TSDB_CODE_SUCCESS); - code = downloadCheckpointByNameS3("123", "/root/download", "123"); - EXPECT_EQ(code, TSDB_CODE_SUCCESS); + code = downloadCheckpointByNameS3("123", "/root/download", ""); + EXPECT_NE(code, TSDB_CODE_OUT_OF_RANGE); } From 0497642545e6b3894e8fc57d8bf340fa6a29bf2f Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Mon, 23 Dec 2024 19:38:13 +0800 Subject: [PATCH 13/14] fix issue --- include/common/tglobal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/common/tglobal.h b/include/common/tglobal.h index 584c4b577566..501f1cabc1fb 100644 --- a/include/common/tglobal.h +++ b/include/common/tglobal.h @@ -293,6 +293,7 @@ extern int32_t tsMaxStreamBackendCache; extern int32_t tsPQSortMemThreshold; extern int32_t tsResolveFQDNRetryTime; extern bool tsStreamCoverage; +extern int8_t tsS3EpNum; extern bool tsExperimental; // #define NEEDTO_COMPRESSS_MSG(size) (tsCompressMsgSize != -1 && (size) > tsCompressMsgSize) From c1b92bc24fb1e2ca7a73e2b5f89335f0f6a4f330 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 24 Dec 2024 08:57:15 +0800 Subject: [PATCH 14/14] fix: stable inner join for single vgroup plan issue --- source/libs/planner/src/planOptimizer.c | 22 ++++++++++++++ tests/script/tsim/join/inner_join.sim | 38 +++++++++++++++++++++++++ tests/script/tsim/join/join.sim | 16 +++++++++++ 3 files changed, 76 insertions(+) diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 11cf9260816a..7085c8dc7ca5 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -6060,11 +6060,22 @@ static int32_t stbJoinOptCreateTagScanNode(SLogicNode* pJoin, SNodeList** ppList } SNode* pNode = NULL; + SName* pPrev = NULL; FOREACH(pNode, pList) { code = stbJoinOptRewriteToTagScan(pJoin, pNode); if (code) { break; } + + SScanLogicNode* pScan = (SScanLogicNode*)pNode; + if (pScan->pVgroupList && 1 == pScan->pVgroupList->numOfVgroups) { + if (NULL == pPrev || 0 == strcmp(pPrev->dbname, pScan->tableName.dbname)) { + pPrev = &pScan->tableName; + continue; + } + + pScan->needSplit = true; + } } if (TSDB_CODE_SUCCESS == code) { @@ -6156,6 +6167,7 @@ static int32_t stbJoinOptCreateTableScanNodes(SLogicNode* pJoin, SNodeList** ppL } int32_t i = 0; + SName* pPrev = NULL; SNode* pNode = NULL; FOREACH(pNode, pList) { SScanLogicNode* pScan = (SScanLogicNode*)pNode; @@ -6173,6 +6185,16 @@ static int32_t stbJoinOptCreateTableScanNodes(SLogicNode* pJoin, SNodeList** ppL *(srcScan + i++) = pScan->pVgroupList->numOfVgroups <= 1; pScan->scanType = SCAN_TYPE_TABLE; + + if (pScan->pVgroupList && 1 == pScan->pVgroupList->numOfVgroups) { + if (NULL == pPrev || 0 == strcmp(pPrev->dbname, pScan->tableName.dbname)) { + pPrev = &pScan->tableName; + continue; + } + + pScan->needSplit = true; + *(srcScan + i - 1) = false; + } } *ppList = pList; diff --git a/tests/script/tsim/join/inner_join.sim b/tests/script/tsim/join/inner_join.sim index 7b9209813d32..304986577727 100644 --- a/tests/script/tsim/join/inner_join.sim +++ b/tests/script/tsim/join/inner_join.sim @@ -203,3 +203,41 @@ sql select a.ts, b.ts from sta a join sta b on a.ts = b.ts and a.t1 = b.t1; if $rows != 8 then return -1 endi + +sql select * from testb.stb1 a join testb.st2 b where a.ts = b.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 a join testb1.stb21 b where a.ts = b.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 b join testb1.stb21 a where a.ts = b.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 a join testb1.stb21 b where b.ts = a.ts and b.t = a.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 b join testb1.stb21 a where b.ts = a.ts and b.t = a.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 b join testb1.stb21 a where a.ts = b.ts and b.t = a.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 b join testb1.stb21 a where b.ts = a.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 a, testb1.stb21 b where a.ts = b.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi +sql select * from testb.stb1 a join testb1.stb21 b on a.ts = b.ts and a.t = b.t; +if $rows != 4 then + return -1 +endi + diff --git a/tests/script/tsim/join/join.sim b/tests/script/tsim/join/join.sim index e3a04fc9c155..43b5b421ab13 100644 --- a/tests/script/tsim/join/join.sim +++ b/tests/script/tsim/join/join.sim @@ -57,6 +57,22 @@ sql insert into ctb22 using st2 tags(2) values('2023-10-16 09:10:12', 110222, 11 sql insert into ctb23 using st2 tags(3) values('2023-10-16 09:10:13', 110223, 1102230); sql insert into ctb24 using st2 tags(4) values('2023-10-16 09:10:14', 110224, 1102240); +sql drop database if exists testb1; +sql create database testb1 vgroups 1 PRECISION 'us'; +sql use testb1; + +sql create table stb21(ts timestamp, f int,g int) tags (t int); +sql insert into ctb11 using stb21 tags(1) values('2023-10-16 09:10:11', 110111, 1101110); +sql insert into ctb12 using stb21 tags(2) values('2023-10-16 09:10:12', 110112, 1101120); +sql insert into ctb13 using stb21 tags(3) values('2023-10-16 09:10:13', 110113, 1101130); +sql insert into ctb14 using stb21 tags(4) values('2023-10-16 09:10:14', 110114, 1101140); + +sql create table st22(ts timestamp, f int, g int) tags (t int); +sql insert into ctb21 using st22 tags(1) values('2023-10-16 09:10:11', 110221, 1102210); +sql insert into ctb22 using st22 tags(2) values('2023-10-16 09:10:12', 110222, 1102220); +sql insert into ctb23 using st22 tags(3) values('2023-10-16 09:10:13', 110223, 1102230); +sql insert into ctb24 using st22 tags(4) values('2023-10-16 09:10:14', 110224, 1102240); + sql drop database if exists testc; sql create database testc vgroups 3; sql use testc;