From 13699f860c0178485d0579ca7e449ba444631ee9 Mon Sep 17 00:00:00 2001 From: WANG Xu Date: Wed, 18 Dec 2024 17:59:35 +0800 Subject: [PATCH 01/55] feat: add script to setup lcov --- tests/setup-lcov.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/setup-lcov.sh diff --git a/tests/setup-lcov.sh b/tests/setup-lcov.sh new file mode 100644 index 0000000000..16180736f4 --- /dev/null +++ b/tests/setup-lcov.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +function usage() { + echo "Usage: $0 -v " + echo "Example: $0 -v 1.14" +} + +function download_lcov() { + local version=$1 + local url="https://github.com/linux-test-project/lcov/releases/download/v${version}/lcov-${version}.tar.gz" + echo "Downloading lcov version ${version} from ${url}..." + curl -LO ${url} + tar -xzf lcov-${version}.tar.gz + echo "lcov version ${version} downloaded and extracted." +} + +function install_lcov() { + echo -e "\nInstalling..." + local version=$1 + cd lcov-${version} + sudo make install + cd .. + echo "lcov version ${version} installed." +} + +function verify_lcov() { + echo -e "\nVerify installation..." + lcov --version +} + +function main() { + if [[ "$#" -ne 2 ]]; then + usage + exit 1 + fi + + while getopts "v:h" opt; do + case ${opt} in + v) + version=${OPTARG} + download_lcov ${version} + install_lcov ${version} + verify_lcov + ;; + h) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; + esac + done +} + +main "$@" \ No newline at end of file From 81e98cc07f9305c4db3eecc02215156c89b75f8e Mon Sep 17 00:00:00 2001 From: WANG Xu Date: Wed, 18 Dec 2024 18:35:03 +0800 Subject: [PATCH 02/55] refactor: uninstall first --- tests/setup-lcov.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/setup-lcov.sh b/tests/setup-lcov.sh index 16180736f4..0d1861fc92 100644 --- a/tests/setup-lcov.sh +++ b/tests/setup-lcov.sh @@ -18,7 +18,7 @@ function install_lcov() { echo -e "\nInstalling..." local version=$1 cd lcov-${version} - sudo make install + sudo make uninstall && sudo make install cd .. echo "lcov version ${version} installed." } From 263a24ea1b6a11b634b966f6892b7a7c7b8f1c34 Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Thu, 19 Dec 2024 17:02:36 +0800 Subject: [PATCH 03/55] add lcov bin dir --- tests/run_local_coverage.sh | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/tests/run_local_coverage.sh b/tests/run_local_coverage.sh index b2413c4065..dfb0e8f9b7 100755 --- a/tests/run_local_coverage.sh +++ b/tests/run_local_coverage.sh @@ -17,9 +17,10 @@ function print_color() { TDENGINE_DIR="/root/TDinternal/community" BRANCH="" TDENGINE_GCDA_DIR="/root/TDinternal/community/debug/" +LCOV_DIR="/usr/local/bin" # Parse command line parameters -while getopts "hd:b:f:c:u:i:" arg; do +while getopts "hd:b:f:c:u:i:l:" arg; do case $arg in d) TDENGINE_DIR=$OPTARG @@ -39,14 +40,18 @@ while getopts "hd:b:f:c:u:i:" arg; do i) BRANCH_BUILD=$OPTARG ;; + l) + LCOV_DIR=$OPTARG + ;; h) - echo "Usage: $(basename $0) -d [TDengine dir] -b [Test branch] -i [Build test branch] -f [TDengine gcda dir] -c [Test single case/all cases] -u [Unit test case]" + echo "Usage: $(basename $0) -d [TDengine dir] -b [Test branch] -i [Build test branch] -f [TDengine gcda dir] -c [Test single case/all cases] -u [Unit test case] -l [Lcov dir]" echo " -d [TDengine dir] [default /root/TDinternal/community; eg: /home/TDinternal/community] " echo " -b [Test branch] [default local branch; eg:cover/3.0] " echo " -i [Build test branch] [default no:not build, but still install ;yes:will build and install ] " echo " -f [TDengine gcda dir] [default /root/TDinternal/community/debug; eg:/root/TDinternal/community/debug/community/source/dnode/vnode/CMakeFiles/vnode.dir/src/tq/] " echo " -c [Test single case/all cases] [default null; -c all : include parallel_test/longtimeruning_cases.task and all unit cases; -c task : include parallel_test/longtimeruning_cases.task; single case: eg: -c './test.sh -f tsim/stream/streamFwcIntervalFill.sim' ] " echo " -u [Unit test case] [default null; eg: './schedulerTest' ] " + echo " -l [Lcov bin dir] [default /usr/local/bin; eg: '/root/TDinternal/community/tests/lcov-1.14/bin' ] " exit 0 ;; ?) @@ -59,13 +64,14 @@ done # Check if the command name is provided if [ -z "$TDENGINE_DIR" ]; then echo "Error: TDengine dir is required." - echo "Usage: $(basename $0) -d [TDengine dir] -b [Test branch] -i [Build test branch] -f [TDengine gcda dir] -c [Test single case/all cases] -u [Unit test case] " + echo "Usage: $(basename $0) -d [TDengine dir] -b [Test branch] -i [Build test branch] -f [TDengine gcda dir] -c [Test single case/all cases] -u [Unit test case] -l [Lcov dir] " echo " -d [TDengine dir] [default /root/TDinternal/community; eg: /home/TDinternal/community] " echo " -b [Test branch] [default local branch; eg:cover/3.0] " echo " -i [Build test branch] [default no:not build, but still install ;yes:will build and install ] " echo " -f [TDengine gcda dir] [default /root/TDinternal/community/debug; eg:/root/TDinternal/community/debug/community/source/dnode/vnode/CMakeFiles/vnode.dir/src/tq/] " echo " -c [Test casingle case/all casesse] [default null; -c all : include parallel_test/longtimeruning_cases.task and all unit cases; -c task : include parallel_test/longtimeruning_cases.task; single case: eg: -c './test.sh -f tsim/stream/streamFwcIntervalFill.sim' ] " echo " -u [Unit test case] [default null; eg: './schedulerTest' ] " + echo " -l [Lcov bin dir] [default /usr/local/bin; eg: '/root/TDinternal/community/tests/lcov-1.14/bin' ] " exit 1 fi @@ -299,11 +305,18 @@ function lcovFunc { print_color "$GREEN" "Test gcda file dir is default: /root/TDinternal/community/debug" fi + if [ -n "$LCOV_DIR" ]; then + LCOV_DIR="$LCOV_DIR" + print_color "$GREEN" "Lcov bin dir: $LCOV_DIR " + else + print_color "$GREEN" "Lcov bin dir is default" + fi + # collect data - lcov -d "$TDENGINE_GCDA_DIR" -capture --rc lcov_branch_coverage=1 --rc genhtml_branch_coverage=1 --no-external -b $TDENGINE_DIR -o coverage.info + $LCOV_DIR/lcov -d "$TDENGINE_GCDA_DIR" -capture --rc lcov_branch_coverage=1 --rc genhtml_branch_coverage=1 --no-external -b $TDENGINE_DIR -o coverage.info # remove exclude paths - lcov --remove coverage.info \ + $LCOV_DIR/lcov --remove coverage.info \ '*/contrib/*' '*/test/*' '*/packaging/*' '*/taos-tools/*' '*/taosadapter/*' '*/TSZ/*' \ '*/AccessBridgeCalls.c' '*/ttszip.c' '*/dataInserter.c' '*/tlinearhash.c' '*/tsimplehash.c' '*/tsdbDiskData.c' '/*/enterprise/*' '*/docs/*' '*/sim/*'\ '*/texpr.c' '*/runUdf.c' '*/schDbg.c' '*/syncIO.c' '*/tdbOs.c' '*/pushServer.c' '*/osLz4.c'\ @@ -316,7 +329,7 @@ function lcovFunc { # generate result echo "generate result" - lcov -l --rc lcov_branch_coverage=1 coverage.info | tee -a $TDENGINE_COVERAGE_REPORT + $LCOV_DIR/lcov -l --rc lcov_branch_coverage=1 coverage.info | tee -a $TDENGINE_COVERAGE_REPORT } @@ -373,8 +386,14 @@ if [ ! -f "$COVERAGE_INFO" ]; then exit 1 fi +if [ -n "$LCOV_DIR" ]; then + LCOV_DIR="$LCOV_DIR" + print_color "$GREEN" "Lcov bin dir: $LCOV_DIR " +else + print_color "$GREEN" "Lcov bin dir is default" +fi # Generate local HTML reports -genhtml "$COVERAGE_INFO" --branch-coverage --function-coverage --output-directory "$OUTPUT_DIR" +$LCOV_DIR/genhtml "$COVERAGE_INFO" --branch-coverage --function-coverage --output-directory "$OUTPUT_DIR" # Check whether the report was generated successfully if [ $? -eq 0 ]; then From 8b90e0cd8fdca5468945206a2bcc3bf2efed6662 Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 19 Dec 2024 09:11:55 +0000 Subject: [PATCH 04/55] fix/TD-33284-compact-coverage-add-kill-compact --- tests/system-test/0-others/compact.py | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/system-test/0-others/compact.py diff --git a/tests/system-test/0-others/compact.py b/tests/system-test/0-others/compact.py new file mode 100644 index 0000000000..e51926cc28 --- /dev/null +++ b/tests/system-test/0-others/compact.py @@ -0,0 +1,84 @@ +from util.log import * +from util.cases import * +from util.dnodes import * +from util.sql import * + +import socket +import taos + +class TDTestCase: + def init(self, conn, logSql, replicaVar=1): + tdLog.debug(f"start to excute {__file__}") + self.replicaVar = int(replicaVar) + + def run(self): + + tdSql.query("CREATE DATABASE power KEEP 365 DURATION 10 BUFFER 16 WAL_LEVEL 1 vgroups 1 replica 1;") + + tdSql.query("CREATE DATABASE power1 KEEP 365 DURATION 10 BUFFER 16 WAL_LEVEL 1 vgroups 1 replica 1;") + + #first + tdSql.query("compact database power;") + + tdLog.info("compact id:%d"%tdSql.queryResult[0][1]) + + tdSql.query("show compact %d;"%tdSql.queryResult[0][1]) + + tdLog.info("detail:%d"%tdSql.queryRows) + + #second + tdSql.query("compact database power1;") + + tdLog.info("compact id:%d"%tdSql.queryResult[0][1]) + + tdSql.query("show compact %d;"%tdSql.queryResult[0][1]) + + tdLog.info("detail:%d"%tdSql.queryRows) + + + #kill + tdSql.query("show compacts;") + number1 = tdSql.queryResult[0][0] + number2 = tdSql.queryResult[1][0] + + #first + tdLog.info("kill compact %d;"%number1) + tdSql.query("kill compact %d;"%number1) + + #second + tdLog.info("kill compact %d;"%number2) + tdSql.query("kill compact %d;"%number2) + + + #show + count = 0 + tdLog.info("query progress") + while count < 50: + tdSql.query("show compact %d;"%number1) + + row1 = tdSql.queryRows + + tdSql.query("show compact %d;"%number2) + + row2 = tdSql.queryRows + + tdLog.info("compact%d:detail count:%d"%(number1, row1)) + tdLog.info("compact%d:detail count:%d"%(number2, row2)) + + if row1 == 0 and row2 == 0 : + break + + time.sleep(1) + + count +=1 + tdLog.info("loop%d"%count) + + #self.Fun.executeSQL("kill compact %d"%tdSql.queryResult[0][1]) + + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) \ No newline at end of file From 290fb82e61d378a1f53e24f49b592355de583c27 Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 19 Dec 2024 09:31:53 +0000 Subject: [PATCH 05/55] add-compact-coverage-case --- tests/parallel_test/cases.task | 2 +- tests/system-test/0-others/compact.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 00a17c8c96..dbcf002bf6 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -402,7 +402,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/persisit_config.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/qmemCtrl.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/compact_vgroups.py - +,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/compact.py -N 3 ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_create.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_insert.py diff --git a/tests/system-test/0-others/compact.py b/tests/system-test/0-others/compact.py index e51926cc28..eb2938e399 100644 --- a/tests/system-test/0-others/compact.py +++ b/tests/system-test/0-others/compact.py @@ -71,9 +71,10 @@ class TDTestCase: time.sleep(1) count +=1 - tdLog.info("loop%d"%count) + #tdLog.info("loop%d"%count) - #self.Fun.executeSQL("kill compact %d"%tdSql.queryResult[0][1]) + if row1 != 0 or row2 != 0: + tdLog.exit("compact failed") def stop(self): From 081ae0b30cb134f83e448b4afca3a2649c8ea1b5 Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 19 Dec 2024 10:09:56 +0000 Subject: [PATCH 06/55] fix/TD-33265-mndDump-coverage --- tests/system-test/0-others/dumpsdb.py | 98 +++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/system-test/0-others/dumpsdb.py diff --git a/tests/system-test/0-others/dumpsdb.py b/tests/system-test/0-others/dumpsdb.py new file mode 100644 index 0000000000..fd0fd2fcd9 --- /dev/null +++ b/tests/system-test/0-others/dumpsdb.py @@ -0,0 +1,98 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import os +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import * + + +class TDTestCase: + def caseDescription(self): + """ + dump sdb taosd -s + """ + + def init(self, conn, logSql, replicaVar=1): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + self.tmpdir = "tmp" + + def getPath(self, tool="taosd"): + if (platform.system().lower() == 'windows'): + tool = tool + ".exe" + selfPath = os.path.dirname(os.path.realpath(__file__)) + + if ("community" in selfPath): + projPath = selfPath[:selfPath.find("community")] + else: + projPath = selfPath[:selfPath.find("tests")] + + paths = [] + for root, dirs, files in os.walk(projPath): + if ((tool) in files): + rootRealPath = os.path.dirname(os.path.realpath(root)) + if ("packaging" not in rootRealPath): + paths.append(os.path.join(root, tool)) + break + if (len(paths) == 0): + tdLog.exit("%s not found!"%tool) + return + else: + tdLog.info("%s found in %s" % (tool, paths[0])) + return paths[0] + + def run(self): + tdSql.execute("create database db keep 3649 ") + + tdSql.execute("use db") + tdSql.execute( + "create table st(ts timestamp, c1 INT, c2 BOOL, c3 TINYINT, c4 SMALLINT, c5 BIGINT, c6 FLOAT, c7 DOUBLE, c8 TIMESTAMP, c9 BINARY(10), c10 NCHAR(10), c11 TINYINT UNSIGNED, c12 SMALLINT UNSIGNED, c13 INT UNSIGNED, c14 BIGINT UNSIGNED) tags(n1 INT, w2 BOOL, t3 TINYINT, t4 SMALLINT, t5 BIGINT, t6 FLOAT, t7 DOUBLE, t8 TIMESTAMP, t9 BINARY(10), t10 NCHAR(10), t11 TINYINT UNSIGNED, t12 SMALLINT UNSIGNED, t13 INT UNSIGNED, t14 BIGINT UNSIGNED)" + ) + tdSql.execute( + "create table t1 using st tags(1, true, 1, 1, 1, 1.0, 1.0, 1, '1', '一', 1, 1, 1, 1)" + ) + tdSql.execute( + "insert into t1 values(1640000000000, 1, true, 1, 1, 1, 1.0, 1.0, 1, '1', '一', 1, 1, 1, 1)" + ) + tdSql.execute( + "create table t2 using st tags(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)" + ) + tdSql.execute( + "insert into t2 values(1640000000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)" + ) + + # sys.exit(1) + + binPath = self.getPath() + if binPath == "": + tdLog.exit("taosd not found!") + else: + tdLog.info("taosd found in %s" % binPath) + + if os.path.exists("sdb.json"): + os.system("rm -f sdb.json") + + os.system("%s -s" % binPath) + + if not os.path.exists("sdb.json"): + tdLog.exit("taosd -s failed!") + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) From 74dfa8946e577625c3b538a7999e0570b5a09e8f Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 19 Dec 2024 10:30:17 +0000 Subject: [PATCH 07/55] fix/TD-33287-monitor-coverage --- tests/system-test/0-others/taosdNewMonitor.py | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 tests/system-test/0-others/taosdNewMonitor.py diff --git a/tests/system-test/0-others/taosdNewMonitor.py b/tests/system-test/0-others/taosdNewMonitor.py new file mode 100644 index 0000000000..9aafb122df --- /dev/null +++ b/tests/system-test/0-others/taosdNewMonitor.py @@ -0,0 +1,306 @@ +import taos +import sys +import time +import socket +# import pexpect +import os +import http.server +import gzip +import threading +import json +import pickle + +from util.log import * +from util.sql import * +from util.cases import * +from util.dnodes import * + +telemetryPort = '6043' +serverPort = '7080' +hostname = socket.gethostname() + +class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): + hostPort = hostname + ":" + serverPort + + def telemetryInfoCheck(self, infoDict=''): + if "ts" not in infoDict or len(infoDict["ts"]) == 0: + tdLog.exit("ts is null!") + + if "dnode_id" not in infoDict or infoDict["dnode_id"] != 1: + tdLog.exit("dnode_id is null!") + + if "dnode_ep" not in infoDict: + tdLog.exit("dnode_ep is null!") + + if "cluster_id" not in infoDict: + tdLog.exit("cluster_id is null!") + + if "protocol" not in infoDict or infoDict["protocol"] != 1: + tdLog.exit("protocol is null!") + + if "cluster_info" not in infoDict : + tdLog.exit("cluster_info is null!") + + # cluster_info ==================================== + + if "first_ep" not in infoDict["cluster_info"] or infoDict["cluster_info"]["first_ep"] == None: + tdLog.exit("first_ep is null!") + + if "first_ep_dnode_id" not in infoDict["cluster_info"] or infoDict["cluster_info"]["first_ep_dnode_id"] != 1: + tdLog.exit("first_ep_dnode_id is null!") + + if "version" not in infoDict["cluster_info"] or infoDict["cluster_info"]["version"] == None: + tdLog.exit("first_ep_dnode_id is null!") + + if "master_uptime" not in infoDict["cluster_info"] or infoDict["cluster_info"]["master_uptime"] == None: + tdLog.exit("master_uptime is null!") + + if "monitor_interval" not in infoDict["cluster_info"] or infoDict["cluster_info"]["monitor_interval"] !=5: + tdLog.exit("monitor_interval is null!") + + if "vgroups_total" not in infoDict["cluster_info"] or infoDict["cluster_info"]["vgroups_total"] < 0: + tdLog.exit("vgroups_total is null!") + + if "vgroups_alive" not in infoDict["cluster_info"] or infoDict["cluster_info"]["vgroups_alive"] < 0: + tdLog.exit("vgroups_alive is null!") + + if "connections_total" not in infoDict["cluster_info"] or infoDict["cluster_info"]["connections_total"] < 0 : + tdLog.exit("connections_total is null!") + + if "dnodes" not in infoDict["cluster_info"] or infoDict["cluster_info"]["dnodes"] == None : + tdLog.exit("dnodes is null!") + + dnodes_info = { "dnode_id": 1,"dnode_ep": self.hostPort,"status":"ready"} + + for k ,v in dnodes_info.items(): + if k not in infoDict["cluster_info"]["dnodes"][0] or v != infoDict["cluster_info"]["dnodes"][0][k] : + tdLog.exit("dnodes info is null!") + + mnodes_info = { "mnode_id":1, "mnode_ep": self.hostPort,"role": "leader" } + + for k ,v in mnodes_info.items(): + if k not in infoDict["cluster_info"]["mnodes"][0] or v != infoDict["cluster_info"]["mnodes"][0][k] : + tdLog.exit("mnodes info is null!") + + # vgroup_infos ==================================== + + if "vgroup_infos" not in infoDict or infoDict["vgroup_infos"]== None: + tdLog.exit("vgroup_infos is null!") + + vgroup_infos_nums = len(infoDict["vgroup_infos"]) + + for index in range(vgroup_infos_nums): + if "vgroup_id" not in infoDict["vgroup_infos"][index] or infoDict["vgroup_infos"][index]["vgroup_id"]<0: + tdLog.exit("vgroup_id is null!") + if "database_name" not in infoDict["vgroup_infos"][index] or len(infoDict["vgroup_infos"][index]["database_name"]) < 0: + tdLog.exit("database_name is null!") + if "tables_num" not in infoDict["vgroup_infos"][index]: + tdLog.exit("tables_num is null!") + if "status" not in infoDict["vgroup_infos"][index] or len(infoDict["vgroup_infos"][index]["status"]) < 0 : + tdLog.exit("status is null!") + if "vnodes" not in infoDict["vgroup_infos"][index] or infoDict["vgroup_infos"][index]["vnodes"] ==None : + tdLog.exit("vnodes is null!") + if "dnode_id" not in infoDict["vgroup_infos"][index]["vnodes"][0] or infoDict["vgroup_infos"][index]["vnodes"][0]["dnode_id"] < 0 : + tdLog.exit("vnodes is null!") + + # grant_info ==================================== + + if "grant_info" not in infoDict or infoDict["grant_info"]== None: + tdLog.exit("grant_info is null!") + + if "expire_time" not in infoDict["grant_info"] or not infoDict["grant_info"]["expire_time"] > 0: + tdLog.exit("expire_time is null!") + + if "timeseries_used" not in infoDict["grant_info"]:# or not infoDict["grant_info"]["timeseries_used"] > 0: + tdLog.exit("timeseries_used is null!") + + if "timeseries_total" not in infoDict["grant_info"] or not infoDict["grant_info"]["timeseries_total"] > 0: + tdLog.exit("timeseries_total is null!") + + # dnode_info ==================================== + + if "dnode_info" not in infoDict or infoDict["dnode_info"]== None: + tdLog.exit("dnode_info is null!") + + dnode_infos = ['uptime', 'cpu_engine', 'cpu_system', 'cpu_cores', 'mem_engine', 'mem_system', 'mem_total', 'disk_engine', + 'disk_used', 'disk_total', 'net_in', 'net_out', 'io_read', 'io_write', 'io_read_disk', 'io_write_disk', 'req_select', + 'req_select_rate', 'req_insert', 'req_insert_success', 'req_insert_rate', 'req_insert_batch', 'req_insert_batch_success', + 'req_insert_batch_rate', 'errors', 'vnodes_num', 'masters', 'has_mnode', 'has_qnode', 'has_snode'] + for elem in dnode_infos: + if elem not in infoDict["dnode_info"] or infoDict["dnode_info"][elem] < 0: + tdLog.exit(f"{elem} is null!") + + # dnode_info ==================================== + + if "disk_infos" not in infoDict or infoDict["disk_infos"]== None: + tdLog.exit("disk_infos is null!") + + # bug for data_dir + if "datadir" not in infoDict["disk_infos"] or len(infoDict["disk_infos"]["datadir"]) <=0 : + tdLog.exit("datadir is null!") + + if "name" not in infoDict["disk_infos"]["datadir"][0] or len(infoDict["disk_infos"]["datadir"][0]["name"]) <= 0: + tdLog.exit("name is null!") + + if "level" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["level"] < 0: + tdLog.exit("level is null!") + + if "avail" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["avail"] <= 0: + tdLog.exit("avail is null!") + + if "used" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["used"] <= 0: + tdLog.exit("used is null!") + + if "total" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["total"] <= 0: + tdLog.exit("total is null!") + + + if "logdir" not in infoDict["disk_infos"] or infoDict["disk_infos"]["logdir"]== None: + tdLog.exit("logdir is null!") + + if "name" not in infoDict["disk_infos"]["logdir"] or len(infoDict["disk_infos"]["logdir"]["name"]) <= 0: + tdLog.exit("name is null!") + + if "avail" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["avail"] <= 0: + tdLog.exit("avail is null!") + + if "used" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["used"] <= 0: + tdLog.exit("used is null!") + + if "total" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["total"] <= 0: + tdLog.exit("total is null!") + + if "tempdir" not in infoDict["disk_infos"] or infoDict["disk_infos"]["tempdir"]== None: + tdLog.exit("tempdir is null!") + + if "name" not in infoDict["disk_infos"]["tempdir"] or len(infoDict["disk_infos"]["tempdir"]["name"]) <= 0: + tdLog.exit("name is null!") + + if "avail" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["avail"] <= 0: + tdLog.exit("avail is null!") + + if "used" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["used"] <= 0: + tdLog.exit("used is null!") + + if "total" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["total"] <= 0: + tdLog.exit("total is null!") + + # log_infos ==================================== + + if "log_infos" not in infoDict or infoDict["log_infos"]== None: + tdLog.exit("log_infos is null!") + + if "summary" not in infoDict["log_infos"] or len(infoDict["log_infos"]["summary"])!= 4: + tdLog.exit("summary is null!") + + if "total" not in infoDict["log_infos"]["summary"][0] or infoDict["log_infos"]["summary"][0]["total"] < 0 : + tdLog.exit("total is null!") + + if "level" not in infoDict["log_infos"]["summary"][0] or infoDict["log_infos"]["summary"][0]["level"] not in ["error" ,"info" , "debug" ,"trace"]: + tdLog.exit("level is null!") + + def do_GET(self): + """ + process GET request + """ + + def do_POST(self): + """ + process POST request + """ + contentEncoding = self.headers["Content-Encoding"] + + if contentEncoding == 'gzip': + req_body = self.rfile.read(int(self.headers["Content-Length"])) + plainText = gzip.decompress(req_body).decode() + else: + plainText = self.rfile.read(int(self.headers["Content-Length"])).decode() + + print(plainText) + # 1. send response code and header + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.end_headers() + + # 2. send response content + #self.wfile.write(("Hello World: " + req_body + "\n").encode("utf-8")) + + # 3. check request body info + infoDict = json.loads(plainText) + #print("================") + # print(infoDict) + self.telemetryInfoCheck(infoDict) + + # 4. shutdown the server and exit case + assassin = threading.Thread(target=self.server.shutdown) + assassin.daemon = True + assassin.start() + print ("==== shutdown http server ====") + +class TDTestCase: + global hostname + global serverPort + if (platform.system().lower() == 'windows' and not tdDnodes.dnodes[0].remoteIP == ""): + try: + config = eval(tdDnodes.dnodes[0].remoteIP ) + hostname = config["host"] + except Exception: + hostname = tdDnodes.dnodes[0].remoteIP + rpcDebugFlagVal = '143' + clientCfgDict = {'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + clientCfgDict["serverPort"] = serverPort + clientCfgDict["firstEp"] = hostname + ':' + serverPort + clientCfgDict["secondEp"] = hostname + ':' + serverPort + clientCfgDict["rpcDebugFlag"] = rpcDebugFlagVal + clientCfgDict["fqdn"] = hostname + + updatecfgDict = {'clientCfg': {}, 'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + updatecfgDict["clientCfg"] = clientCfgDict + updatecfgDict["serverPort"] = serverPort + updatecfgDict["firstEp"] = hostname + ':' + serverPort + updatecfgDict["secondEp"] = hostname + ':' + serverPort + updatecfgDict["fqdn"] = hostname + + updatecfgDict["monitorFqdn"] = hostname + updatecfgDict["monitorPort"] = '6043' + updatecfgDict["monitor"] = '1' + updatecfgDict["monitorInterval"] = "5" + updatecfgDict["monitorMaxLogs"] = "10" + updatecfgDict["monitorComp"] = "1" + updatecfgDict["monitorForceV2"] = "1" + + updatecfgDict["audit"] = '0' + + print ("===================: ", updatecfgDict) + + def init(self, conn, logSql, replicaVar=1): + self.replicaVar = int(replicaVar) + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor()) + + def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring + tdSql.prepare() + # time.sleep(2) + vgroups = "4" + sql = "create database db3 vgroups " + vgroups + tdSql.query(sql) + sql = "create table db3.stb (ts timestamp, f int) tags (t int)" + tdSql.query(sql) + sql = "create table db3.tb using db3.stb tags (1)" + tdSql.query(sql) + + # create http server: bing ip/port , and request processor + if (platform.system().lower() == 'windows' and not tdDnodes.dnodes[0].remoteIP == ""): + RequestHandlerImplStr = base64.b64encode(pickle.dumps(RequestHandlerImpl)).decode() + cmdStr = "import pickle\nimport http\nRequestHandlerImpl=pickle.loads(base64.b64decode(\"%s\".encode()))\nclass NewRequestHandlerImpl(RequestHandlerImpl):\n hostPort = \'%s\'\nhttp.server.HTTPServer((\"\", %s), NewRequestHandlerImpl).serve_forever()"%(RequestHandlerImplStr,hostname+":"+serverPort,telemetryPort) + tdDnodes.dnodes[0].remoteExec({}, cmdStr) + else: + serverAddress = ("", int(telemetryPort)) + http.server.HTTPServer(serverAddress, RequestHandlerImpl).serve_forever() + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) From 36cd37c9e85225e30631ecb54beaa818a916c69f Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 19 Dec 2024 10:31:35 +0000 Subject: [PATCH 08/55] add case --- tests/parallel_test/cases.task | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 00a17c8c96..27b9e860e4 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -402,7 +402,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/persisit_config.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/qmemCtrl.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/compact_vgroups.py - +,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/dumpsdb.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_create.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_insert.py From a914943fc98c88cb209dffd8639118484cb2cc67 Mon Sep 17 00:00:00 2001 From: dmchen Date: Fri, 20 Dec 2024 02:07:40 +0000 Subject: [PATCH 09/55] no need asan check --- tests/parallel_test/cases.task | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 27b9e860e4..5cbf1722e7 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -402,7 +402,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/persisit_config.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/qmemCtrl.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/compact_vgroups.py -,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/dumpsdb.py +,,y,system-test,python3 ./test.py -f 0-others/dumpsdb.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_create.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_insert.py From 72652d7c2cea7be276898ae905cacf9f828a4a93 Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Fri, 20 Dec 2024 10:24:23 +0800 Subject: [PATCH 10/55] test: refine feishu report --- tests/pytest/auto_crash_gen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/pytest/auto_crash_gen.py b/tests/pytest/auto_crash_gen.py index f6b31b4691..316f2ead0f 100755 --- a/tests/pytest/auto_crash_gen.py +++ b/tests/pytest/auto_crash_gen.py @@ -384,7 +384,8 @@ Core dir: {core_dir} if text_result == "success": send_msg(notification_robot_url, get_msg(text)) else: - send_msg(alert_robot_url, get_msg(text)) + send_msg(alert_robot_url, get_msg(text)) + send_msg(notification_robot_url, get_msg(text)) #send_msg(get_msg(text)) except Exception as e: From 4b1a9d11a2f79fe50ecd11610d0b1f44ea1a08eb Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Fri, 20 Dec 2024 10:24:41 +0800 Subject: [PATCH 11/55] test: refine feishu report --- tests/pytest/auto_crash_gen_valgrind.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pytest/auto_crash_gen_valgrind.py b/tests/pytest/auto_crash_gen_valgrind.py index b346aca308..b7af68cd2f 100755 --- a/tests/pytest/auto_crash_gen_valgrind.py +++ b/tests/pytest/auto_crash_gen_valgrind.py @@ -419,6 +419,7 @@ Core dir: {core_dir} send_msg(notification_robot_url, get_msg(text)) else: send_msg(alert_robot_url, get_msg(text)) + send_msg(notification_robot_url, get_msg(text)) #send_msg(get_msg(text)) except Exception as e: From 0190adf620dbefb677c51543b02795a30cf2d208 Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Fri, 20 Dec 2024 10:24:56 +0800 Subject: [PATCH 12/55] test: refine feishu report --- tests/pytest/auto_crash_gen_valgrind_cluster.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/pytest/auto_crash_gen_valgrind_cluster.py b/tests/pytest/auto_crash_gen_valgrind_cluster.py index 522ad48640..df40b60967 100755 --- a/tests/pytest/auto_crash_gen_valgrind_cluster.py +++ b/tests/pytest/auto_crash_gen_valgrind_cluster.py @@ -406,7 +406,8 @@ Core dir: {core_dir} if text_result == "success": send_msg(notification_robot_url, get_msg(text)) else: - send_msg(alert_robot_url, get_msg(text)) + send_msg(alert_robot_url, get_msg(text)) + send_msg(notification_robot_url, get_msg(text)) #send_msg(get_msg(text)) except Exception as e: From 164cd03f8f9643bba03983664fc9479be85f279a Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Fri, 20 Dec 2024 10:38:13 +0800 Subject: [PATCH 13/55] test: add args --- tests/run_all_ci_cases.sh | 207 +++++++++++++++++++++++++++++++------- 1 file changed, 171 insertions(+), 36 deletions(-) diff --git a/tests/run_all_ci_cases.sh b/tests/run_all_ci_cases.sh index 959af66d19..11670800b8 100644 --- a/tests/run_all_ci_cases.sh +++ b/tests/run_all_ci_cases.sh @@ -7,12 +7,120 @@ GREEN_DARK='\033[0;32m' GREEN_UNDERLINE='\033[4;32m' NC='\033[0m' -TDENGINE_DIR=/root/TDinternal/community +function print_color() { + local color="$1" + local message="$2" + echo -e "${color}${message}${NC}" +} + +# 初始化参数 +TDENGINE_DIR="/root/TDinternal/community" +BRANCH="" +SAVE_LOG="notsave" + +# 解析命令行参数 +while getopts "hd:b:t:s:" arg; do + case $arg in + d) + TDENGINE_DIR=$OPTARG + ;; + b) + BRANCH=$OPTARG + ;; + s) + SAVE_LOG=$OPTARG + ;; + h) + echo "Usage: $(basename $0) -d [TDengine_dir] -b [branch] -s [save ci case log]" + echo " -d [TDengine_dir] [default /root/TDinternal/community] " + echo " -b [branch] [default local branch] " + echo " -s [save/notsave] [default save ci case log in TDengine_dir/tests/ci_bak] " + exit 0 + ;; + ?) + echo "Usage: ./$(basename $0) -h" + exit 1 + ;; + esac +done + +# 检查是否提供了命令名称 +if [ -z "$TDENGINE_DIR" ]; then + echo "Error: TDengine dir is required." + echo "Usage: $(basename $0) -d [TDengine_dir] -b [branch] -s [save ci case log] " + echo " -d [TDengine_dir] [default /root/TDinternal/community] " + echo " -b [branch] [default local branch] " + echo " -s [save/notsave] [default save ci case log in TDengine_dir/tests/ci_bak] " + exit 1 +fi -#echo "TDENGINE_DIR = $TDENGINE_DIR" +echo "TDENGINE_DIR = $TDENGINE_DIR" today=`date +"%Y%m%d"` -TDENGINE_ALLCI_REPORT=$TDENGINE_DIR/tests/all-ci-report-$today.log +TDENGINE_ALLCI_REPORT="$TDENGINE_DIR/tests/all-ci-report-$today.log" +BACKUP_DIR="$TDENGINE_DIR/tests/ci_bak" +mkdir -p "$BACKUP_DIR" +#cd $BACKUP_DIR && rm -rf * + + +function buildTDengine() { + print_color "$GREEN" "TDengine build start" + + # pull parent code + cd "$TDENGINE_DIR/../" + print_color "$GREEN" "git pull parent code..." + git remote prune origin > /dev/null + git remote update > /dev/null + + # pull tdengine code + cd $TDENGINE_DIR + print_color "$GREEN" "git pull tdengine code..." + git remote prune origin > /dev/null + git remote update > /dev/null + REMOTE_COMMIT=`git rev-parse --short remotes/origin/$branch` + LOCAL_COMMIT=`git rev-parse --short @` + print_color "$GREEN" " LOCAL: $LOCAL_COMMIT" + print_color "$GREEN" "REMOTE: $REMOTE_COMMIT" + + if [ "$LOCAL_COMMIT" == "$REMOTE_COMMIT" ]; then + print_color "$GREEN" "repo up-to-date" + else + print_color "$GREEN" "repo need to pull" + fi + + git reset --hard + git checkout -- . + git checkout $branch + git checkout -- . + git clean -f + git pull + + [ -d $TDENGINE_DIR/debug ] || mkdir $TDENGINE_DIR/debug + cd $TDENGINE_DIR/debug + + print_color "$GREEN" "rebuild.." + LOCAL_COMMIT=`git rev-parse --short @` + + rm -rf * + makecmd="cmake -DBUILD_TEST=false -DBUILD_HTTP=false -DBUILD_DEPENDENCY_TESTS=0 -DBUILD_TOOLS=true -DBUILD_GEOS=true -DBUILD_TEST=true -DBUILD_CONTRIB=false ../../" + print_color "$GREEN" "$makecmd" + $makecmd + + make -j 8 install + + print_color "$GREEN" "TDengine build end" +} + + +# 检查并获取分支名称 +if [ -n "$BRANCH" ]; then + branch="$BRANCH" + print_color "$GREEN" "Testing branch: $branch " + print_color "$GREEN" "Build is required for this test!" + buildTDengine +else + print_color "$GREEN" "Build is not required for this test!" +fi function runCasesOneByOne () { @@ -20,23 +128,50 @@ function runCasesOneByOne () { if [[ "$line" != "#"* ]]; then cmd=`echo $line | cut -d',' -f 5` if [[ "$2" == "sim" ]] && [[ $line == *"script"* ]]; then + echo $cmd case=`echo $cmd | cut -d' ' -f 3` + case_file=`echo $case | tr -d ' /' ` start_time=`date +%s` - date +%F\ %T | tee -a $TDENGINE_ALLCI_REPORT && timeout 20m $cmd > /dev/null 2>&1 && \ - echo -e "${GREEN}$case success${NC}" | tee -a $TDENGINE_ALLCI_REPORT \ - || echo -e "${RED}$case failed${NC}" | tee -a $TDENGINE_ALLCI_REPORT + date +%F\ %T | tee -a $TDENGINE_ALLCI_REPORT && timeout 20m $cmd > $TDENGINE_DIR/tests/$case_file.log 2>&1 && \ + echo -e "${GREEN}$case success${NC}" | tee -a $TDENGINE_ALLCI_REPORT || \ + echo -e "${RED}$case failed${NC}" | tee -a $TDENGINE_ALLCI_REPORT + + # # 记录日志和备份 + # mkdir -p "$BACKUP_DIR/$case_file" + # tar --exclude='*.sock*' -czf "$BACKUP_DIR/$case_file/sim.tar.gz" -C "$TDENGINE_DIR/.." sim + # mv "$TDENGINE_DIR/tests/$case_file.log" "$BACKUP_DIR/$case_file" + + if [ "$SAVE_LOG" == "save" ]; then + mkdir -p "$BACKUP_DIR/$case_file" + tar --exclude='*.sock*' -czf "$BACKUP_DIR/$case_file/sim.tar.gz" -C "$TDENGINE_DIR/.." sim + mv "$TDENGINE_DIR/tests/$case_file.log" "$BACKUP_DIR/$case_file" + else + echo "This case not save log!" + fi + end_time=`date +%s` echo execution time of $case was `expr $end_time - $start_time`s. | tee -a $TDENGINE_ALLCI_REPORT - + elif [[ "$line" == *"$2"* ]]; then + echo $cmd if [[ "$cmd" == *"pytest.sh"* ]]; then cmd=`echo $cmd | cut -d' ' -f 2-20` fi - case=`echo $cmd | cut -d' ' -f 4-20` + case=`echo $cmd | cut -d' ' -f 4-20` + case_file=`echo $case | tr -d ' /' ` start_time=`date +%s` - date +%F\ %T | tee -a $TDENGINE_ALLCI_REPORT && timeout 20m $cmd > /dev/null 2>&1 && \ + date +%F\ %T | tee -a $TDENGINE_ALLCI_REPORT && timeout 20m $cmd > $TDENGINE_DIR/tests/$case_file.log 2>&1 && \ echo -e "${GREEN}$case success${NC}" | tee -a $TDENGINE_ALLCI_REPORT || \ echo -e "${RED}$case failed${NC}" | tee -a $TDENGINE_ALLCI_REPORT + + if [ "$SAVE_LOG" == "save" ]; then + mkdir -p "$BACKUP_DIR/$case_file" + tar --exclude='*.sock*' -czf "$BACKUP_DIR/$case_file/sim.tar.gz" -C "$TDENGINE_DIR/.." sim + mv "$TDENGINE_DIR/tests/$case_file.log" "$BACKUP_DIR/$case_file" + else + echo "This case not save log!" + fi + end_time=`date +%s` echo execution time of $case was `expr $end_time - $start_time`s. | tee -a $TDENGINE_ALLCI_REPORT fi @@ -45,62 +180,62 @@ function runCasesOneByOne () { } function runUnitTest() { - echo "=== Run unit test case ===" - echo " $TDENGINE_DIR/debug" - cd $TDENGINE_DIR/debug + print_color "$GREEN" "=== Run unit test case ===" + print_color "$GREEN" " $TDENGINE_DIR/../debug" + cd $TDENGINE_DIR/../debug ctest -j12 - echo "3.0 unit test done" + print_color "$GREEN" "3.0 unit test done" } function runSimCases() { - echo "=== Run sim cases ===" + print_color "$GREEN" "=== Run sim cases ===" cd $TDENGINE_DIR/tests/script - runCasesOneByOne $TDENGINE_DIR/tests/parallel_test/cases-test.task sim + runCasesOneByOne $TDENGINE_DIR/tests/parallel_test/cases.task sim totalSuccess=`grep 'sim success' $TDENGINE_ALLCI_REPORT | wc -l` if [ "$totalSuccess" -gt "0" ]; then - echo "### Total $totalSuccess SIM test case(s) succeed! ###" | tee -a $TDENGINE_ALLCI_REPORT + print_color "$GREEN" "### Total $totalSuccess SIM test case(s) succeed! ###" | tee -a $TDENGINE_ALLCI_REPORT fi totalFailed=`grep 'sim failed\|fault' $TDENGINE_ALLCI_REPORT | wc -l` if [ "$totalFailed" -ne "0" ]; then - echo "### Total $totalFailed SIM test case(s) failed! ###" | tee -a $TDENGINE_ALLCI_REPORT + print_color "$RED" "### Total $totalFailed SIM test case(s) failed! ###" | tee -a $TDENGINE_ALLCI_REPORT fi } function runPythonCases() { - echo "=== Run python cases ===" + print_color "$GREEN" "=== Run python cases ===" cd $TDENGINE_DIR/tests/parallel_test - sed -i '/compatibility.py/d' cases-test.task + sed -i '/compatibility.py/d' cases.task # army cd $TDENGINE_DIR/tests/army - runCasesOneByOne ../parallel_test/cases-test.task army + runCasesOneByOne ../parallel_test/cases.task army # system-test cd $TDENGINE_DIR/tests/system-test - runCasesOneByOne ../parallel_test/cases-test.task system-test + runCasesOneByOne ../parallel_test/cases.task system-test # develop-test cd $TDENGINE_DIR/tests/develop-test - runCasesOneByOne ../parallel_test/cases-test.task develop-test + runCasesOneByOne ../parallel_test/cases.task develop-test totalSuccess=`grep 'py success' $TDENGINE_ALLCI_REPORT | wc -l` if [ "$totalSuccess" -gt "0" ]; then - echo "### Total $totalSuccess python test case(s) succeed! ###" | tee -a $TDENGINE_ALLCI_REPORT + print_color "$GREEN" "### Total $totalSuccess python test case(s) succeed! ###" | tee -a $TDENGINE_ALLCI_REPORT fi totalFailed=`grep 'py failed\|fault' $TDENGINE_ALLCI_REPORT | wc -l` if [ "$totalFailed" -ne "0" ]; then - echo "### Total $totalFailed python test case(s) failed! ###" | tee -a $TDENGINE_ALLCI_REPORT + print_color "$RED" "### Total $totalFailed python test case(s) failed! ###" | tee -a $TDENGINE_ALLCI_REPORT fi } function runTest() { - echo "run Test" + print_color "$GREEN" "run Test" cd $TDENGINE_DIR [ -d sim ] && rm -rf sim @@ -119,20 +254,20 @@ function runTest() { } function stopTaosd { - echo "Stop taosd start" - systemctl stop taosd - PID=`ps -ef|grep -w taosd | grep -v grep | awk '{print $2}'` + print_color "$GREEN" "Stop taosd start" + systemctl stop taosd + PID=`ps -ef|grep -w taosd | grep -v grep | awk '{print $2}'` while [ -n "$PID" ] do - pkill -TERM -x taosd - sleep 1 - PID=`ps -ef|grep -w taosd | grep -v grep | awk '{print $2}'` + pkill -TERM -x taosd + sleep 1 + PID=`ps -ef|grep -w taosd | grep -v grep | awk '{print $2}'` done - echo "Stop tasod end" + print_color "$GREEN" "Stop tasod end" } function stopTaosadapter { - echo "Stop taosadapter" + print_color "$GREEN" "Stop taosadapter" systemctl stop taosadapter.service PID=`ps -ef|grep -w taosadapter | grep -v grep | awk '{print $2}'` while [ -n "$PID" ] @@ -141,18 +276,18 @@ function stopTaosadapter { sleep 1 PID=`ps -ef|grep -w taosd | grep -v grep | awk '{print $2}'` done - echo "Stop tasoadapter end" + print_color "$GREEN" "Stop tasoadapter end" } WORK_DIR=/root/ date >> $WORK_DIR/date.log -echo "Run ALL CI Test Cases" | tee -a $WORK_DIR/date.log +print_color "$GREEN" "Run all ci test cases" | tee -a $WORK_DIR/date.log stopTaosd runTest date >> $WORK_DIR/date.log -echo "End of CI Test Cases" | tee -a $WORK_DIR/date.log \ No newline at end of file +print_color "$GREEN" "End of ci test cases" | tee -a $WORK_DIR/date.log \ No newline at end of file From 9715bb59fe9e3608fba7ab350f5ad1d728a50c6c Mon Sep 17 00:00:00 2001 From: dmchen Date: Fri, 20 Dec 2024 11:33:26 +0800 Subject: [PATCH 14/55] fix/TD-33294-compact-coverage-fix-case --- source/dnode/mnode/impl/src/mndCompact.c | 9 +++++++-- source/dnode/vnode/src/vnd/vnodeSvr.c | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndCompact.c b/source/dnode/mnode/impl/src/mndCompact.c index e8f7202986..33a6ddcc5d 100644 --- a/source/dnode/mnode/impl/src/mndCompact.c +++ b/source/dnode/mnode/impl/src/mndCompact.c @@ -348,6 +348,7 @@ static void *mndBuildKillCompactReq(SMnode *pMnode, SVgObj *pVgroup, int32_t *pC req.compactId = compactId; req.vgId = pVgroup->vgId; req.dnodeId = dnodeid; + terrno = 0; mInfo("vgId:%d, build compact vnode config req", pVgroup->vgId); int32_t contLen = tSerializeSVKillCompactReq(NULL, 0, &req); @@ -367,8 +368,10 @@ static void *mndBuildKillCompactReq(SMnode *pMnode, SVgObj *pVgroup, int32_t *pC pHead->contLen = htonl(contLen); pHead->vgId = htonl(pVgroup->vgId); - if ((contLen = tSerializeSVKillCompactReq((char *)pReq + sizeof(SMsgHead), contLen, &req)) < 0) { - terrno = contLen; + mTrace("vgId:%d, build compact vnode config req, contLen:%d", pVgroup->vgId, contLen); + int32_t ret = 0; + if ((ret = tSerializeSVKillCompactReq((char *)pReq + sizeof(SMsgHead), contLen, &req)) < 0) { + terrno = ret; return NULL; } *pContLen = contLen; @@ -401,6 +404,8 @@ static int32_t mndAddKillCompactAction(SMnode *pMnode, STrans *pTrans, SVgObj *p action.contLen = contLen; action.msgType = TDMT_VND_KILL_COMPACT; + mTrace("trans:%d, kill compact msg len:%d", pTrans->id, contLen); + if ((code = mndTransAppendRedoAction(pTrans, &action)) != 0) { taosMemoryFree(pReq); TAOS_RETURN(code); diff --git a/source/dnode/vnode/src/vnd/vnodeSvr.c b/source/dnode/vnode/src/vnd/vnodeSvr.c index e82209e03f..6291e0c9c7 100644 --- a/source/dnode/vnode/src/vnd/vnodeSvr.c +++ b/source/dnode/vnode/src/vnd/vnodeSvr.c @@ -607,9 +607,9 @@ int32_t vnodeProcessWriteMsg(SVnode *pVnode, SRpcMsg *pMsg, int64_t ver, SRpcMsg } vDebug("vgId:%d, start to process write request %s, index:%" PRId64 ", applied:%" PRId64 ", state.applyTerm:%" PRId64 - ", conn.applyTerm:%" PRId64, + ", conn.applyTerm:%" PRId64 ", contLen:%d", TD_VID(pVnode), TMSG_INFO(pMsg->msgType), ver, pVnode->state.applied, pVnode->state.applyTerm, - pMsg->info.conn.applyTerm); + pMsg->info.conn.applyTerm, pMsg->contLen); if (!(pVnode->state.applyTerm <= pMsg->info.conn.applyTerm)) { return terrno = TSDB_CODE_INTERNAL_ERROR; From 15a59e49cb2ac2fd7e6ac6d573eea89d4e43a93a Mon Sep 17 00:00:00 2001 From: dmchen Date: Fri, 20 Dec 2024 13:51:19 +0800 Subject: [PATCH 15/55] fix/TD-32265-mndDump-coverage-fix-case --- tests/parallel_test/cases.task | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 5cbf1722e7..17f809da79 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -402,7 +402,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/persisit_config.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/qmemCtrl.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/compact_vgroups.py -,,y,system-test,python3 ./test.py -f 0-others/dumpsdb.py +,,n,system-test,python3 ./test.py -f 0-others/dumpsdb.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_create.py ,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/composite_primary_key_insert.py From b1702132b485afccd2531f60f40d8099aeea1ef1 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Fri, 20 Dec 2024 13:52:53 +0800 Subject: [PATCH 16/55] fix: add ut cases --- source/libs/catalog/CMakeLists.txt | 6 +- source/libs/executor/src/hashjoin.c | 3 + source/libs/executor/src/hashjoinoperator.c | 2 +- source/libs/qcom/src/queryUtil.c | 2 + source/libs/scheduler/src/schRemote.c | 10 +- source/libs/scheduler/src/schTask.c | 5 + source/libs/scheduler/test/schedulerTests.cpp | 208 +++++++++++++++++- source/util/src/tworker.c | 2 + tests/script/tsim/join/join_explain.sim | 1 + 9 files changed, 228 insertions(+), 11 deletions(-) diff --git a/source/libs/catalog/CMakeLists.txt b/source/libs/catalog/CMakeLists.txt index 3bdb0a9b1d..dd7220da15 100644 --- a/source/libs/catalog/CMakeLists.txt +++ b/source/libs/catalog/CMakeLists.txt @@ -11,6 +11,6 @@ target_link_libraries( PRIVATE os util transport qcom nodes ) -#if(${BUILD_TEST}) -# ADD_SUBDIRECTORY(test) -#endif(${BUILD_TEST}) +if(${BUILD_TEST} AND NOT ${TD_WINDOWS}) + ADD_SUBDIRECTORY(test) +endif() diff --git a/source/libs/executor/src/hashjoin.c b/source/libs/executor/src/hashjoin.c index f63b4093db..da7686cce6 100755 --- a/source/libs/executor/src/hashjoin.c +++ b/source/libs/executor/src/hashjoin.c @@ -83,6 +83,8 @@ int32_t hInnerJoinDo(struct SOperatorInfo* pOperator) { return code; } +#ifdef HASH_JOIN_FULL + int32_t hLeftJoinHandleSeqRowRemains(struct SOperatorInfo* pOperator, SHJoinOperatorInfo* pJoin, bool* loopCont) { bool allFetched = false; SHJoinCtx* pCtx = &pJoin->ctx; @@ -346,4 +348,5 @@ int32_t hLeftJoinDo(struct SOperatorInfo* pOperator) { return TSDB_CODE_SUCCESS; } +#endif diff --git a/source/libs/executor/src/hashjoinoperator.c b/source/libs/executor/src/hashjoinoperator.c index 64ce62cb66..73a5139e43 100644 --- a/source/libs/executor/src/hashjoinoperator.c +++ b/source/libs/executor/src/hashjoinoperator.c @@ -89,7 +89,7 @@ int32_t hJoinSetImplFp(SHJoinOperatorInfo* pJoin) { case JOIN_TYPE_RIGHT: { switch (pJoin->subType) { case JOIN_STYPE_OUTER: - pJoin->joinFp = hLeftJoinDo; + //pJoin->joinFp = hLeftJoinDo; TOOPEN break; default: break; diff --git a/source/libs/qcom/src/queryUtil.c b/source/libs/qcom/src/queryUtil.c index 690d38aac0..6d637bee98 100644 --- a/source/libs/qcom/src/queryUtil.c +++ b/source/libs/qcom/src/queryUtil.c @@ -137,6 +137,8 @@ static void processTaskQueue(SQueueInfo *pInfo, SSchedMsg *pSchedMsg) { } int32_t initTaskQueue() { + memset(&taskQueue, 0, sizeof(taskQueue)); + taskQueue.wrokrerPool.name = "taskWorkPool"; taskQueue.wrokrerPool.min = tsNumOfTaskQueueThreads; taskQueue.wrokrerPool.max = tsNumOfTaskQueueThreads; diff --git a/source/libs/scheduler/src/schRemote.c b/source/libs/scheduler/src/schRemote.c index d15ac7a791..a031bc08de 100644 --- a/source/libs/scheduler/src/schRemote.c +++ b/source/libs/scheduler/src/schRemote.c @@ -531,8 +531,8 @@ int32_t schHandleNotifyCallback(void *param, SDataBuf *pMsg, int32_t code) { qDebug("QID:0x%" PRIx64 ",SID:0x%" PRIx64 ",CID:0x%" PRIx64 ",TID:0x%" PRIx64 " task notify rsp received, code:0x%x", pParam->queryId, pParam->seriousId, pParam->clientId, pParam->taskId, code); if (pMsg) { - taosMemoryFree(pMsg->pData); - taosMemoryFree(pMsg->pEpSet); + taosMemoryFreeClear(pMsg->pData); + taosMemoryFreeClear(pMsg->pEpSet); } return TSDB_CODE_SUCCESS; } @@ -545,8 +545,8 @@ int32_t schHandleLinkBrokenCallback(void *param, SDataBuf *pMsg, int32_t code) { qDebug("handle %p is broken", pMsg->handle); if (head->isHbParam) { - taosMemoryFree(pMsg->pData); - taosMemoryFree(pMsg->pEpSet); + taosMemoryFreeClear(pMsg->pData); + taosMemoryFreeClear(pMsg->pEpSet); SSchHbCallbackParam *hbParam = (SSchHbCallbackParam *)param; SSchTrans trans = {.pTrans = hbParam->pTrans, .pHandle = NULL, .pHandleId = 0}; @@ -1293,6 +1293,7 @@ int32_t schBuildAndSendMsg(SSchJob *pJob, SSchTask *pTask, SQueryNodeAddr *addr, } break; } +/* case TDMT_SCH_QUERY_HEARTBEAT: { SCH_ERR_RET(schMakeHbRpcCtx(pJob, pTask, &rpcCtx)); @@ -1320,6 +1321,7 @@ int32_t schBuildAndSendMsg(SSchJob *pJob, SSchTask *pTask, SQueryNodeAddr *addr, persistHandle = true; break; } +*/ case TDMT_SCH_TASK_NOTIFY: { ETaskNotifyType* pType = param; STaskNotifyReq qMsg; diff --git a/source/libs/scheduler/src/schTask.c b/source/libs/scheduler/src/schTask.c index cb8a68fe4f..cabaa65f19 100644 --- a/source/libs/scheduler/src/schTask.c +++ b/source/libs/scheduler/src/schTask.c @@ -452,6 +452,8 @@ void schResetTaskForRetry(SSchJob *pJob, SSchTask *pTask) { TAOS_MEMSET(&pTask->succeedAddr, 0, sizeof(pTask->succeedAddr)); } +#if 0 + int32_t schDoTaskRedirect(SSchJob *pJob, SSchTask *pTask, SDataBuf *pData, int32_t rspCode) { int32_t code = 0; @@ -593,6 +595,7 @@ _return: SCH_RET(schProcessOnTaskFailure(pJob, pTask, code)); } +#endif int32_t schPushTaskToExecList(SSchJob *pJob, SSchTask *pTask) { int32_t code = taosHashPut(pJob->execTasks, &pTask->taskId, sizeof(pTask->taskId), &pTask, POINTER_BYTES); @@ -869,6 +872,7 @@ int32_t schSetTaskCandidateAddrs(SSchJob *pJob, SSchTask *pTask) { return TSDB_CODE_SUCCESS; } +#if 0 int32_t schUpdateTaskCandidateAddr(SSchJob *pJob, SSchTask *pTask, SEpSet *pEpSet) { int32_t code = TSDB_CODE_SUCCESS; if (NULL == pTask->candidateAddrs || 1 != taosArrayGetSize(pTask->candidateAddrs)) { @@ -900,6 +904,7 @@ _return: return code; } +#endif int32_t schSwitchTaskCandidateAddr(SSchJob *pJob, SSchTask *pTask) { int32_t candidateNum = taosArrayGetSize(pTask->candidateAddrs); diff --git a/source/libs/scheduler/test/schedulerTests.cpp b/source/libs/scheduler/test/schedulerTests.cpp index a9878ec9a9..f112376299 100644 --- a/source/libs/scheduler/test/schedulerTests.cpp +++ b/source/libs/scheduler/test/schedulerTests.cpp @@ -57,6 +57,9 @@ namespace { extern "C" int32_t schHandleResponseMsg(SSchJob *pJob, SSchTask *pTask, uint64_t sId, int32_t execId, SDataBuf *pMsg, int32_t rspCode); extern "C" int32_t schHandleCallback(void *param, const SDataBuf *pMsg, int32_t rspCode); +extern "C" int32_t schHandleNotifyCallback(void *param, SDataBuf *pMsg, int32_t code); +extern "C" int32_t schHandleLinkBrokenCallback(void *param, SDataBuf *pMsg, int32_t code); +extern "C" int32_t schRescheduleTask(SSchJob *pJob, SSchTask *pTask); int64_t insertJobRefId = 0; int64_t queryJobRefId = 0; @@ -316,7 +319,7 @@ void schtBuildQueryFlowCtrlDag(SQueryPlan *dag) { scanPlan->execNode.nodeId = 1 + i; scanPlan->execNode.epSet.inUse = 0; - scanPlan->execNodeStat.tableNum = taosRand() % 30; + scanPlan->execNodeStat.tableNum = taosRand() % 100; addEpIntoEpSet(&scanPlan->execNode.epSet, "ep0", 6030); addEpIntoEpSet(&scanPlan->execNode.epSet, "ep1", 6030); addEpIntoEpSet(&scanPlan->execNode.epSet, "ep2", 6030); @@ -982,8 +985,157 @@ TEST(queryTest, normalCase) { schedulerFreeJob(&job, 0); (void)taosThreadJoin(thread1, NULL); + + schMgmt.jobRef = -1; } +TEST(queryTest, rescheduleCase) { + void *mockPointer = (void *)0x1; + char *clusterId = "cluster1"; + char *dbname = "1.db1"; + char *tablename = "table1"; + SVgroupInfo vgInfo = {0}; + int64_t job = 0; + SQueryPlan *dag = NULL; + int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN, (SNode**)&dag); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SArray *qnodeList = taosArrayInit(1, sizeof(SQueryNodeLoad)); + + SQueryNodeLoad load = {0}; + load.addr.epSet.numOfEps = 1; + TAOS_STRCPY(load.addr.epSet.eps[0].fqdn, "qnode0.ep"); + load.addr.epSet.eps[0].port = 6031; + assert(taosArrayPush(qnodeList, &load) != NULL); + + code = schedulerInit(); + ASSERT_EQ(code, 0); + + schtBuildQueryDag(dag); + + schtSetPlanToString(); + schtSetExecNode(); + schtSetAsyncSendMsgToServer(); + + int32_t queryDone = 0; + + SRequestConnInfo conn = {0}; + conn.pTrans = mockPointer; + SSchedulerReq req = {0}; + req.pConn = &conn; + req.pNodeList = qnodeList; + req.pDag = dag; + req.sql = "select * from tb"; + req.execFp = schtQueryCb; + req.cbParam = &queryDone; + + code = schedulerExecJob(&req, &job); + ASSERT_EQ(code, 0); + + SSchJob *pJob = NULL; + code = schAcquireJob(job, &pJob); + ASSERT_EQ(code, 0); + + schedulerEnableReSchedule(true); + + void *pIter = taosHashIterate(pJob->execTasks, NULL); + while (pIter) { + SSchTask *task = *(SSchTask **)pIter; + task->timeoutUsec = -1; + + code = schRescheduleTask(pJob, task); + ASSERT_EQ(code, 0); + + task->timeoutUsec = SCH_DEFAULT_TASK_TIMEOUT_USEC; + pIter = taosHashIterate(pJob->execTasks, pIter); + } + + pIter = taosHashIterate(pJob->execTasks, NULL); + while (pIter) { + SSchTask *task = *(SSchTask **)pIter; + + SDataBuf msg = {0}; + void *rmsg = NULL; + assert(0 == schtBuildQueryRspMsg(&msg.len, &rmsg)); + msg.msgType = TDMT_SCH_QUERY_RSP; + msg.pData = rmsg; + + code = schHandleResponseMsg(pJob, task, task->seriousId, task->execId, &msg, 0); + + ASSERT_EQ(code, 0); + pIter = taosHashIterate(pJob->execTasks, pIter); + } + + + pIter = taosHashIterate(pJob->execTasks, NULL); + while (pIter) { + SSchTask *task = *(SSchTask **)pIter; + task->timeoutUsec = -1; + + code = schRescheduleTask(pJob, task); + ASSERT_EQ(code, 0); + + task->timeoutUsec = SCH_DEFAULT_TASK_TIMEOUT_USEC; + pIter = taosHashIterate(pJob->execTasks, pIter); + } + + + pIter = taosHashIterate(pJob->execTasks, NULL); + while (pIter) { + SSchTask *task = *(SSchTask **)pIter; + if (JOB_TASK_STATUS_EXEC == task->status) { + SDataBuf msg = {0}; + void *rmsg = NULL; + assert(0 == schtBuildQueryRspMsg(&msg.len, &rmsg)); + msg.msgType = TDMT_SCH_QUERY_RSP; + msg.pData = rmsg; + + code = schHandleResponseMsg(pJob, task, task->seriousId, task->execId, &msg, 0); + + ASSERT_EQ(code, 0); + } + + pIter = taosHashIterate(pJob->execTasks, pIter); + } + + while (true) { + if (queryDone) { + break; + } + + taosUsleep(10000); + } + + TdThreadAttr thattr; + assert(0 == taosThreadAttrInit(&thattr)); + + TdThread thread1; + assert(0 == taosThreadCreate(&(thread1), &thattr, schtCreateFetchRspThread, &job)); + + void *data = NULL; + req.syncReq = true; + req.pFetchRes = &data; + + code = schedulerFetchRows(job, &req); + ASSERT_EQ(code, 0); + + SRetrieveTableRsp *pRsp = (SRetrieveTableRsp *)data; + ASSERT_EQ(pRsp->completed, 1); + ASSERT_EQ(pRsp->numOfRows, 10); + taosMemoryFreeClear(data); + + (void)schReleaseJob(job); + + schedulerDestroy(); + + schedulerFreeJob(&job, 0); + + (void)taosThreadJoin(thread1, NULL); + + schMgmt.jobRef = -1; +} + + TEST(queryTest, readyFirstCase) { void *mockPointer = (void *)0x1; char *clusterId = "cluster1"; @@ -1097,6 +1249,7 @@ TEST(queryTest, readyFirstCase) { schedulerFreeJob(&job, 0); (void)taosThreadJoin(thread1, NULL); + schMgmt.jobRef = -1; } TEST(queryTest, flowCtrlCase) { @@ -1196,6 +1349,9 @@ TEST(queryTest, flowCtrlCase) { schedulerFreeJob(&job, 0); (void)taosThreadJoin(thread1, NULL); + schMgmt.jobRef = -1; + + cleanupTaskQueue(); } TEST(insertTest, normalCase) { @@ -1260,6 +1416,7 @@ TEST(insertTest, normalCase) { schedulerDestroy(); (void)taosThreadJoin(thread1, NULL); + schMgmt.jobRef = -1; } TEST(multiThread, forceFree) { @@ -1282,9 +1439,11 @@ TEST(multiThread, forceFree) { schtTestStop = true; // taosSsleep(3); + + schMgmt.jobRef = -1; } -TEST(otherTest, otherCase) { +TEST(otherTest, function) { // excpet test (void)schReleaseJob(0); schFreeRpcCtx(NULL); @@ -1293,6 +1452,39 @@ TEST(otherTest, otherCase) { ASSERT_EQ(schDumpEpSet(NULL, &ep), TSDB_CODE_SUCCESS); ASSERT_EQ(strcmp(schGetOpStr(SCH_OP_NULL), "NULL"), 0); ASSERT_EQ(strcmp(schGetOpStr((SCH_OP_TYPE)100), "UNKNOWN"), 0); + + SSchTaskCallbackParam param = {0}; + SDataBuf dataBuf = {0}; + dataBuf.pData = taosMemoryMalloc(1); + dataBuf.pEpSet = (SEpSet*)taosMemoryMalloc(sizeof(*dataBuf.pEpSet)); + ASSERT_EQ(schHandleNotifyCallback(¶m, &dataBuf, TSDB_CODE_SUCCESS), TSDB_CODE_SUCCESS); + + SSchCallbackParamHeader param2 = {0}; + dataBuf.pData = taosMemoryMalloc(1); + dataBuf.pEpSet = (SEpSet*)taosMemoryMalloc(sizeof(*dataBuf.pEpSet)); + schHandleLinkBrokenCallback(¶m2, &dataBuf, TSDB_CODE_SUCCESS); + param2.isHbParam = true; + dataBuf.pData = taosMemoryMalloc(1); + dataBuf.pEpSet = (SEpSet*)taosMemoryMalloc(sizeof(*dataBuf.pEpSet)); + schHandleLinkBrokenCallback(¶m2, &dataBuf, TSDB_CODE_SUCCESS); + + schMgmt.jobRef = -1; +} + +void schtReset() { + insertJobRefId = 0; + queryJobRefId = 0; + + schtJobDone = false; + schtMergeTemplateId = 0x4; + schtFetchTaskId = 0; + schtQueryId = 1; + + schtTestStop = false; + schtTestDeadLoop = false; + schtTestMTRunSec = 1; + schtTestPrintNum = 1000; + schtStartFetch = 0; } int main(int argc, char **argv) { @@ -1302,7 +1494,17 @@ int main(int argc, char **argv) { } taosSeedRand(taosGetTimestampSec()); testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + + int code = 0; + for (int32_t i = 0; i < 10; ++i) { + schtReset(); + code = RUN_ALL_TESTS(); + if (code) { + break; + } + } + + return code; } #pragma GCC diagnostic pop diff --git a/source/util/src/tworker.c b/source/util/src/tworker.c index 6370e6ca50..dbd8cb159e 100644 --- a/source/util/src/tworker.c +++ b/source/util/src/tworker.c @@ -823,6 +823,8 @@ bool tQueryAutoQWorkerTryRecycleWorker(SQueryAutoQWorkerPool *pPool, SQueryAutoQ int32_t tQueryAutoQWorkerInit(SQueryAutoQWorkerPool *pool) { int32_t code; + pool->exit = false; + (void)taosThreadMutexInit(&pool->poolLock, NULL); (void)taosThreadMutexInit(&pool->backupLock, NULL); (void)taosThreadMutexInit(&pool->waitingAfterBlockLock, NULL); diff --git a/tests/script/tsim/join/join_explain.sim b/tests/script/tsim/join/join_explain.sim index f9d2f3eac1..2858999de5 100644 --- a/tests/script/tsim/join/join_explain.sim +++ b/tests/script/tsim/join/join_explain.sim @@ -39,6 +39,7 @@ sql explain analyze verbose true select a.ts from sta a join sta b on a.col1 = b sql explain analyze verbose true select a.ts from sta a join sta b where a.ts=b.ts; sql_error explain analyze verbose true select a.ts from sta a ,sta b on a.ts=b.ts; sql explain analyze verbose true select a.ts from sta a ,sta b where a.ts=b.ts; +sql explain analyze verbose true select a.ts from sta a ,sta b where a.t1 = b.t1 and a.ts=b.ts; sql explain analyze verbose true select a.ts from sta a ,sta b where a.ts=b.ts and a.col1 + 1 = b.col1; sql explain analyze verbose true select b.col1 from sta a ,sta b where a.ts=b.ts and a.col1 + 1 = b.col1 order by a.ts; sql explain analyze verbose true select b.col1 from sta a join sta b join sta c where a.ts=b.ts and b.ts = c.ts order by a.ts; From b071ab130462470aba676a090d801acd6185e855 Mon Sep 17 00:00:00 2001 From: tjuzyp Date: Fri, 20 Dec 2024 15:27:36 +0800 Subject: [PATCH 17/55] docs: add exception handling strategy for data migration tasks --- .../05-data-in/{07-mqtt.md => 07-mqtt.mdx} | 8 +++++- .../05-data-in/{08-kafka.md => 08-kafka.mdx} | 12 ++++++--- .../{09-influxdb.md => 09-influxdb.mdx} | 6 ++--- .../{10-opentsdb.md => 10-opentsdb.mdx} | 6 ++--- .../05-data-in/{11-csv.md => 11-csv.mdx} | 16 ++++++++++-- ...va-historian.md => 12-aveva-historian.mdx} | 8 +++++- .../05-data-in/{13-mysql.md => 13-mysql.mdx} | 12 +++++---- .../{14-postgres.md => 14-postgres.mdx} | 12 +++++---- .../{15-oracle.md => 15-oracle.mdx} | 12 +++++---- .../05-data-in/{16-mssql.md => 16-mssql.mdx} | 12 +++++---- .../{17-mongodb.md => 17-mongodb.mdx} | 12 +++++---- .../05-data-in/_02-advanced_options.mdx | 7 ++++++ .../_03-exception-handling-strategy.mdx | 23 ++++++++++++++++++ docs/zh/06-advanced/05-data-in/kafka-15.png | Bin 6819 -> 0 bytes docs/zh/06-advanced/05-data-in/kafka-16.png | Bin 13274 -> 0 bytes ...luxDB-09zh-AdvancedOptionsExpandButton.png | Bin 7359 -> 0 bytes .../InfluxDB-10zh-AdvancedOptionsExpand.png | Bin 100045 -> 0 bytes ...nTSDB-07zh-AdvancedOptionsExpandButton.png | Bin 7356 -> 0 bytes .../OpenTSDB-08zh-AdvancedOptionsExpand.png | Bin 99050 -> 0 bytes .../05-data-in/pic/advanced_options.png | Bin 0 -> 21207 bytes .../pic/exception-handling-strategy.png | Bin 0 -> 44166 bytes .../06-advanced/05-data-in/pic/mongodb-07.png | Bin 12979 -> 0 bytes .../06-advanced/05-data-in/pic/mssql-07.png | Bin 31515 -> 0 bytes .../06-advanced/05-data-in/pic/mysql-07.png | Bin 31515 -> 0 bytes .../06-advanced/05-data-in/pic/oracle-06.png | Bin 15052 -> 0 bytes .../05-data-in/pic/postgres-07.png | Bin 31515 -> 0 bytes 26 files changed, 107 insertions(+), 39 deletions(-) rename docs/zh/06-advanced/05-data-in/{07-mqtt.md => 07-mqtt.mdx} (98%) rename docs/zh/06-advanced/05-data-in/{08-kafka.md => 08-kafka.mdx} (97%) rename docs/zh/06-advanced/05-data-in/{09-influxdb.md => 09-influxdb.mdx} (94%) rename docs/zh/06-advanced/05-data-in/{10-opentsdb.md => 10-opentsdb.mdx} (92%) rename docs/zh/06-advanced/05-data-in/{11-csv.md => 11-csv.mdx} (95%) rename docs/zh/06-advanced/05-data-in/{12-aveva-historian.md => 12-aveva-historian.mdx} (97%) rename docs/zh/06-advanced/05-data-in/{13-mysql.md => 13-mysql.mdx} (93%) rename docs/zh/06-advanced/05-data-in/{14-postgres.md => 14-postgres.mdx} (93%) rename docs/zh/06-advanced/05-data-in/{15-oracle.md => 15-oracle.mdx} (93%) rename docs/zh/06-advanced/05-data-in/{16-mssql.md => 16-mssql.mdx} (94%) rename docs/zh/06-advanced/05-data-in/{17-mongodb.md => 17-mongodb.mdx} (94%) create mode 100644 docs/zh/06-advanced/05-data-in/_02-advanced_options.mdx create mode 100644 docs/zh/06-advanced/05-data-in/_03-exception-handling-strategy.mdx delete mode 100644 docs/zh/06-advanced/05-data-in/kafka-15.png delete mode 100644 docs/zh/06-advanced/05-data-in/kafka-16.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/InfluxDB-09zh-AdvancedOptionsExpandButton.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/InfluxDB-10zh-AdvancedOptionsExpand.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/OpenTSDB-07zh-AdvancedOptionsExpandButton.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/OpenTSDB-08zh-AdvancedOptionsExpand.png create mode 100644 docs/zh/06-advanced/05-data-in/pic/advanced_options.png create mode 100644 docs/zh/06-advanced/05-data-in/pic/exception-handling-strategy.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/mongodb-07.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/mssql-07.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/mysql-07.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/oracle-06.png delete mode 100644 docs/zh/06-advanced/05-data-in/pic/postgres-07.png diff --git a/docs/zh/06-advanced/05-data-in/07-mqtt.md b/docs/zh/06-advanced/05-data-in/07-mqtt.mdx similarity index 98% rename from docs/zh/06-advanced/05-data-in/07-mqtt.md rename to docs/zh/06-advanced/05-data-in/07-mqtt.mdx index a0e121f632..3ffab4dfbf 100644 --- a/docs/zh/06-advanced/05-data-in/07-mqtt.md +++ b/docs/zh/06-advanced/05-data-in/07-mqtt.mdx @@ -166,6 +166,12 @@ json 数据支持 JSONObject 或者 JSONArray,使用 json 解析器可以解 ![mqtt-14](./mqtt-14.png) -### 8. 创建完成 +### 8. 异常处理策略 + +import Contributing from './_03-exception-handling-strategy.mdx' + + + +### 9. 创建完成 点击 **提交** 按钮,完成创建 MQTT 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/08-kafka.md b/docs/zh/06-advanced/05-data-in/08-kafka.mdx similarity index 97% rename from docs/zh/06-advanced/05-data-in/08-kafka.md rename to docs/zh/06-advanced/05-data-in/08-kafka.mdx index b605f84c7a..71070b271c 100644 --- a/docs/zh/06-advanced/05-data-in/08-kafka.md +++ b/docs/zh/06-advanced/05-data-in/08-kafka.mdx @@ -196,12 +196,16 @@ json 数据支持 JSONObject 或者 JSONArray,使用 json 解析器可以解 ### 8. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -![kafka-15.png](./kafka-15.png) + -![kafka-16.png](./kafka-16.png) +### 9. 异常处理策略 -### 9. 创建完成 +import Contributing from './_03-exception-handling-strategy.mdx' + + + +### 10. 创建完成 点击 **提交** 按钮,完成创建 Kafka 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/09-influxdb.md b/docs/zh/06-advanced/05-data-in/09-influxdb.mdx similarity index 94% rename from docs/zh/06-advanced/05-data-in/09-influxdb.md rename to docs/zh/06-advanced/05-data-in/09-influxdb.mdx index d0b781667d..b88bcdf3c6 100644 --- a/docs/zh/06-advanced/05-data-in/09-influxdb.md +++ b/docs/zh/06-advanced/05-data-in/09-influxdb.mdx @@ -75,9 +75,9 @@ InfluxDB 是一种流行的开源时间序列数据库,它针对处理大量 ### 6. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: -![InfluxDB-09zh-AdvancedOptionsExpandButton.png](./pic/InfluxDB-09zh-AdvancedOptionsExpandButton.png "高级选项展开按钮") -![InfluxDB-10zh-AdvancedOptionsExpand.png](./pic/InfluxDB-10zh-AdvancedOptionsExpand.png "高级选项展开按钮") +import AdvancedOptions from './_02-advanced_options.mdx' + + ### 7. 创建完成 diff --git a/docs/zh/06-advanced/05-data-in/10-opentsdb.md b/docs/zh/06-advanced/05-data-in/10-opentsdb.mdx similarity index 92% rename from docs/zh/06-advanced/05-data-in/10-opentsdb.md rename to docs/zh/06-advanced/05-data-in/10-opentsdb.mdx index 3737f2a415..eeb4e37988 100644 --- a/docs/zh/06-advanced/05-data-in/10-opentsdb.md +++ b/docs/zh/06-advanced/05-data-in/10-opentsdb.mdx @@ -58,9 +58,9 @@ OpenTSDB 是一个架构在 HBase 系统之上的实时监控信息收集和展 ### 5. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: -![OpenTSDB-07zh-AdvancedOptionsExpandButton.png](./pic/OpenTSDB-07zh-AdvancedOptionsExpandButton.png "高级选项展开按钮") -![OpenTSDB-08zh-AdvancedOptionsExpand.png](./pic/OpenTSDB-08zh-AdvancedOptionsExpand.png "高级选项展开按钮") +import AdvancedOptions from './_02-advanced_options.mdx' + + ### 6. 创建完成 diff --git a/docs/zh/06-advanced/05-data-in/11-csv.md b/docs/zh/06-advanced/05-data-in/11-csv.mdx similarity index 95% rename from docs/zh/06-advanced/05-data-in/11-csv.md rename to docs/zh/06-advanced/05-data-in/11-csv.mdx index 4924ed2fbd..5737fc8b79 100644 --- a/docs/zh/06-advanced/05-data-in/11-csv.md +++ b/docs/zh/06-advanced/05-data-in/11-csv.mdx @@ -107,13 +107,25 @@ sidebar_label: "CSV" ![csv-09.png](./csv-09.png) -### 5. 创建完成 +### 5. 配置高级选项 + +import AdvancedOptions from './_02-advanced_options.mdx' + + + +### 6. 异常处理策略 + +import Contributing from './_03-exception-handling-strategy.mdx' + + + +### 7. 创建完成 点击 **提交** 按钮,完成创建 CSV 到 TDengine 的数据同步任务,回到数据写入任务列表页面,可查看任务执行情况,也可以进行任务的“启动/停止”操作与“查看/编辑/删除/复制”操作。 ![csv-10.png](./csv-10.png) -### 6. 查看运行指标 +### 8. 查看运行指标 点击 **查看** 按钮,查看任务的运行指标,同时也可以查看任务中所有文件的处理情况。 diff --git a/docs/zh/06-advanced/05-data-in/12-aveva-historian.md b/docs/zh/06-advanced/05-data-in/12-aveva-historian.mdx similarity index 97% rename from docs/zh/06-advanced/05-data-in/12-aveva-historian.md rename to docs/zh/06-advanced/05-data-in/12-aveva-historian.mdx index ee04194dea..e8ab4c839e 100644 --- a/docs/zh/06-advanced/05-data-in/12-aveva-historian.md +++ b/docs/zh/06-advanced/05-data-in/12-aveva-historian.mdx @@ -134,6 +134,12 @@ split 提取器,seperator 填写分割符 `,`, number 填写 2。 ![aveva-historian-08.png](pic/aveva-historian-08.png) -### 7. 创建完成 +### 7. 异常处理策略 + +import Contributing from './_03-exception-handling-strategy.mdx' + + + +### 8. 创建完成 点击 **提交** 按钮,完成创建任务。提交任务后,回到**数据写入**页面可以查看任务状态。 diff --git a/docs/zh/06-advanced/05-data-in/13-mysql.md b/docs/zh/06-advanced/05-data-in/13-mysql.mdx similarity index 93% rename from docs/zh/06-advanced/05-data-in/13-mysql.md rename to docs/zh/06-advanced/05-data-in/13-mysql.mdx index 4cc84fbfa2..f1894190cb 100644 --- a/docs/zh/06-advanced/05-data-in/13-mysql.md +++ b/docs/zh/06-advanced/05-data-in/13-mysql.mdx @@ -98,14 +98,16 @@ MySQL 是最流行的关系型数据库之一。很多系统都曾经或正在 ### 8. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + -**批次大小** 单次发送的最大消息数或行数。默认是 10000。 +### 9. 异常处理策略 -![mysql-07.png](pic/mysql-07.png) +import Contributing from './_03-exception-handling-strategy.mdx' -### 9. 创建完成 + + +### 10. 创建完成 点击 **提交** 按钮,完成创建 MySQL 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/14-postgres.md b/docs/zh/06-advanced/05-data-in/14-postgres.mdx similarity index 93% rename from docs/zh/06-advanced/05-data-in/14-postgres.md rename to docs/zh/06-advanced/05-data-in/14-postgres.mdx index af8297bfff..7651db68f2 100644 --- a/docs/zh/06-advanced/05-data-in/14-postgres.md +++ b/docs/zh/06-advanced/05-data-in/14-postgres.mdx @@ -99,14 +99,16 @@ TDengine 可以高效地从 PostgreSQL 读取数据并将其写入 TDengine, ### 8. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + -**批次大小** 单次发送的最大消息数或行数。默认是 10000。 +### 9. 异常处理策略 -![postgres-07.png](pic/postgres-07.png) +import Contributing from './_03-exception-handling-strategy.mdx' -### 9. 创建完成 + + +### 10. 创建完成 点击 **提交** 按钮,完成创建 PostgreSQL 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/15-oracle.md b/docs/zh/06-advanced/05-data-in/15-oracle.mdx similarity index 93% rename from docs/zh/06-advanced/05-data-in/15-oracle.md rename to docs/zh/06-advanced/05-data-in/15-oracle.mdx index 39bbab32d3..484365415e 100644 --- a/docs/zh/06-advanced/05-data-in/15-oracle.md +++ b/docs/zh/06-advanced/05-data-in/15-oracle.mdx @@ -91,14 +91,16 @@ TDengine 可以高效地从 Oracle 读取数据并将其写入 TDengine,以实 ### 7. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + -**批次大小** 单次发送的最大消息数或行数。默认是 10000。 +### 8. 异常处理策略 -![oracle-06.png](pic/oracle-06.png) +import Contributing from './_03-exception-handling-strategy.mdx' -### 8. 创建完成 + + +### 9. 创建完成 点击 **提交** 按钮,完成创建 Oracle 到 TDengine 的数据同步任务,回到**数据源列表****页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/16-mssql.md b/docs/zh/06-advanced/05-data-in/16-mssql.mdx similarity index 94% rename from docs/zh/06-advanced/05-data-in/16-mssql.md rename to docs/zh/06-advanced/05-data-in/16-mssql.mdx index 81e9e98013..1e6b9928be 100644 --- a/docs/zh/06-advanced/05-data-in/16-mssql.md +++ b/docs/zh/06-advanced/05-data-in/16-mssql.mdx @@ -105,14 +105,16 @@ Microsoft SQL Server 是最流行的关系型数据库之一。很多系统都 ### 8. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + -**批次大小** 单次发送的最大消息数或行数。默认是 10000。 +### 9. 异常处理策略 -![mssql-07.png](pic/mssql-07.png) +import Contributing from './_03-exception-handling-strategy.mdx' -### 9. 创建完成 + + +### 10. 创建完成 点击 **提交** 按钮,完成创建 Microsoft SQL Server 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/17-mongodb.md b/docs/zh/06-advanced/05-data-in/17-mongodb.mdx similarity index 94% rename from docs/zh/06-advanced/05-data-in/17-mongodb.md rename to docs/zh/06-advanced/05-data-in/17-mongodb.mdx index 5311bc43c6..e92f37a6f0 100644 --- a/docs/zh/06-advanced/05-data-in/17-mongodb.md +++ b/docs/zh/06-advanced/05-data-in/17-mongodb.mdx @@ -122,14 +122,16 @@ MongoDB 是一个介于关系型数据库与非关系型数据库之间的产品 ### 8. 配置高级选项 -**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: +import AdvancedOptions from './_02-advanced_options.mdx' -**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + -**批次大小** 单次发送的最大消息数或行数。默认是 10000。 +### 9. 异常处理策略 -![mongodb-07.png](pic/mongodb-07.png) +import Contributing from './_03-exception-handling-strategy.mdx' -### 9. 创建完成 + + +### 10. 创建完成 点击 **提交** 按钮,完成创建 MongoDB 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。 diff --git a/docs/zh/06-advanced/05-data-in/_02-advanced_options.mdx b/docs/zh/06-advanced/05-data-in/_02-advanced_options.mdx new file mode 100644 index 0000000000..f37de063c0 --- /dev/null +++ b/docs/zh/06-advanced/05-data-in/_02-advanced_options.mdx @@ -0,0 +1,7 @@ +**高级选项** 区域是默认折叠的,点击右侧 `>` 可以展开,如下图所示: + +**最大读取并发数** 数据源连接数或读取线程数限制,当默认参数不满足需要或需要调整资源使用量时修改此参数。 + +**批次大小** 单次发送的最大消息数或行数。默认是 10000。 + +![advanced_options.png](pic/advanced_options.png) \ No newline at end of file diff --git a/docs/zh/06-advanced/05-data-in/_03-exception-handling-strategy.mdx b/docs/zh/06-advanced/05-data-in/_03-exception-handling-strategy.mdx new file mode 100644 index 0000000000..470c304ff3 --- /dev/null +++ b/docs/zh/06-advanced/05-data-in/_03-exception-handling-strategy.mdx @@ -0,0 +1,23 @@ +异常处理策略区域是对数据异常时的处理策略进行配置,默认折叠的,点击右侧 `>` 可以展开,如下图所示: + +![exception-handling-strategy.png](pic/exception-handling-strategy.png) + +各异常项说明及相应可选处理策略如下: + +> 通用处理策略说明: +> 归档:将异常数据写入归档文件(默认路径为 `${data_dir}/tasks/_id/.datetime`),不写入目标库 +> 丢弃:将异常数据忽略,不写入目标库 +> 报错:任务报错 + +- **主键时间戳溢出** 检查数据中第一列时间戳是否在正确的时间范围内(now - keep1, now + 100y),可选处理策略:归档、丢弃、报错 +- **主键时间戳空** 检查数据中第一列时间戳是否为空,可选处理策略:归档、丢弃、报错、使用当前时间 + > 使用当前时间:使用当前时间填充到空的时间戳字段中 +- **表名长度溢出** 检查子表表名的长度是否超出限制(最大 192 字符),可选处理策略:归档、丢弃、报错、截断、截断且归档 + > 截断:截取原始表名的前 192 个字符作为新的表名 + > 截断且归档:截取原始表名的前 192 个字符作为新的表名,并且将此行记录写入归档文件 +- **表名非法字符** 检查子表表名中是否包含特殊字符(符号 `.` 等),可选处理策略:归档、丢弃、报错、非法字符替换为指定字符串 + > 非法字符替换为指定字符串:将原始表名中的特殊字符替换为后方输入框中的指定字符串,例如 `a.b` 替换为 `a_b` +- **表名模板变量空值** 检查子表表名模板中的变量是否为空,可选处理策略:丢弃、留空、变量替换为指定字符串 + > 留空:变量位置不做任何特殊处理,例如 `a_{x}` 转换为 `a_` + > 变量替换为指定字符串:变量位置使用后方输入框中的指定字符串,例如 `a_{x}` 转换为 `a_b` +- **列名长度溢出** 检查列名的长度是否超出限制(最大 64 字符),可选处理策略:归档、丢弃、报错 \ No newline at end of file diff --git a/docs/zh/06-advanced/05-data-in/kafka-15.png b/docs/zh/06-advanced/05-data-in/kafka-15.png deleted file mode 100644 index 96d593dad9a46b97d48915d61c887e6915270b2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6819 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 TUe$ASIn%DCuCInrv48zvA}mwB diff --git a/docs/zh/06-advanced/05-data-in/kafka-16.png b/docs/zh/06-advanced/05-data-in/kafka-16.png deleted file mode 100644 index 395453c410c632acdd77c4aa5446f44830a52cf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13274 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 diff --git a/docs/zh/06-advanced/05-data-in/pic/InfluxDB-09zh-AdvancedOptionsExpandButton.png b/docs/zh/06-advanced/05-data-in/pic/InfluxDB-09zh-AdvancedOptionsExpandButton.png deleted file mode 100644 index f12692c50678c0789e1d38b32e56904c33f3bfad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7359 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 diff --git a/docs/zh/06-advanced/05-data-in/pic/InfluxDB-10zh-AdvancedOptionsExpand.png b/docs/zh/06-advanced/05-data-in/pic/InfluxDB-10zh-AdvancedOptionsExpand.png deleted file mode 100644 index dbb188852c99a856cadcc14351e9cd773c61a06f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100045 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 w}Yb)E;I{&Fm%h2|5 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 Jdt&|e{{X7c^`Za( diff --git a/docs/zh/06-advanced/05-data-in/pic/OpenTSDB-07zh-AdvancedOptionsExpandButton.png b/docs/zh/06-advanced/05-data-in/pic/OpenTSDB-07zh-AdvancedOptionsExpandButton.png deleted file mode 100644 index 65d6344e56b5978a364169524cc917da386183b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7356 zcmbVxXIK+W^e^^8dldyyz(P@a2LT}>B3)_-NGM7#0WtIvR73?N(h;OeKujR?8k(SV z2m%Sc3BpTB0)!ACl)L!e=YIG<_qiYLe%PJeIc@gLoHKKNkw%ZTSkGTQ&&0&Us-ykT zgo){d5YTo!dm6acaL{2)Og!N_57o^A(n*tE9+&(x7uOBP!lZ)K#{w#-3(Q zcYi}iTA4>(ynUsJ|506u_Ig?Jt-C&=O0{R=4B>Fqs4BnP!9?v~4R@dRXE6?z$ax*U zlSPobkqOZieKNr}p1A%qe`zh1SK2e-(-no0wy-gJHo6Xj#vG1RxL%wp)~bO{9{AFW z6Q-*hrzypm7B)6EoPd2yiALE&Cyp9S$2pGff?9URfk*cIS^cBeL}*|mM{;s}T2|I@ zOUoCar7M)cZVx@`Yt%gc>Sb5gadg2Qh@)d(SC@J6iNIUqSg4+!PH$hID*~auLIk6~ ze1ZP?<9Pn0cG(frb3LJiCs61BAdEbn1@J`>i;G3>-d|_cUszc1rA&Q5V=xtnQ1Gua ztN{584(8|gSXLH3R+94s3{DEf7)V#_*2~aej5SEl2Y>T;e#0)5dXMR4f4~(eJ-|LZ~nx(<@ za{$rHFK16458CK-o5U&R=H;zkbIrRIJ36WahCt$kj{yWmW`IsK7CW%I3MImi$2SPB z9giUc9ZbX@yEJfGmTgCx{5kD`y}f#3QTMbk`%xFB($hL`VR1j$;COsRNl8IeR6YI4 zkxehbn1VY;f0jZq$%Aet9}!#V0UB!cYU4WvRJ@N=TA04Nf4|cK*?h#oq#OD7dB5|* zr=!<9O8~< zH|U*FFT}g+ZBb0}1DUQuq#LAvs}YB4HH)&Q20GnqZS75+!@r!#>F zgM~#Uyr{0-MTC6eN1M=CXKiOaHr}cHNUHSGSmD8LsO!7Mo{>Q6y~=~k+zEG#4dZ8e zW57NZ`(eUlnCR9JG}u?wvm66yGj+}k6wR02Vjov@n~|&*-n^l422jTr4|t{#tR5-u z>iGCYlJDipL{aOyq^$CjBI^fUy&gI%oDEfs{Kt)gu8c?f^Y@bwlm3u_!h`krOH-ky zhc1pzX;tR9thM0r&4j)hWl!Rry2YxxU4gu^>*kh_WD{(CWBMRhJW7VZ@e@#&{g4y1 z*Gz+tHjRIcLV_UK-d2&1=Dh-Ca(0>+Sxd{yS7 zP(a~5xz0oXNgDi5*q&j~m#ts87Y7ev+Lw95$mjLz?deZGH#^KHXI`%buPylrTZp)f zHX4W3Sq-Et!LcDhR*@7*i$9irFYOeX567eX^m~K$_u2=pd07hDUQJ2BB zVS%cK_G*B(lGFEaUaC>R-{g-@a9%9=a#|?oMDOmu&2HB-BnFjzMwS`cVkoY|Ve(Rz z2JjuGbo@m5v8g>AlBJz|y$(N4o=C;S^0vt2bqzhK{x>(poN@JN$!!ap*u|4)EmD1i z&3^9-%NCTB3vwsRy;yhWRbDewwi~s{se>9)SUjSBtin=7H_DIV?#Jp|DK9Rk#jI_5 zg#=oM!BU=C<1k3bGm{lgR*#Gn0eN4~A!H*?nYsiMWV@Gl&fOWC4;o7^eF~=B;8r5k}^6t8~T#JeAXrX<9^qw>FD}CY_Izc&Kf)i@`?*f~3p?)i zkDp{E%VN-!c!b6^g4_#;^OQ_@QhwhU5ANyYP-nH1DqT2G_Z^$z^1M~K@=j2XG9~$O zl?Tn^`aO)IO=PNN+E6L?WQ|a%wG<$`M1d$LWtmazyYRIsiOox@`gD~SYP$gzR4G5r zy8yGIjg4E;(&!~#O!K+E(O=F~>7GFiJ2*jl#9ycQY|v^pqn$LF1Nn~3JY_l9`~xTN z6&2e0z?oVnnro7;u}E2pLTQLQeFOjAuK}ll^Yh*H>IUdm8Kcxh0{-`^Wh&uX@efD^ zHM!Pc9hfhq=T4jp1B;nua&XM=xcYIHqZD~(DD9-s!T4z_6@OaH%8nZKeS`S(1p}@W zpEhq$!VraYz#;lxX=itF_xm`=Y?5KBJU2Egie(#)`KR1{*~4h4?qd`r2-=sA5Iwtm zZJ3%h<(C-sH@+9$PEJWl`I?^(HsuhbSwNpPMXlJ{xDnY8rdZgZ`ywX0e1b}3nI^Yy zs|HBxHsS{5$R0JPgL%ziJmGLnJ@S#sm8Ny4XjQ(^zscd{xWAIrxqF4`N8;}*{Ehw1 z_VzYehZIBFohg;{zf=JpX6SXg*K$hStd_*xn|~7pAAi#Lp_$jgC}ekB@p{qBoBt?# z%oO%h5nI<0UztpqdJV`okG_1BuLOPJ zpBis%-zCWIR^V5B_Ym4{@CG)DJGEXBy-j^c}`QmS)aeC7#51hTGwDxYmwd{5tJT`2_EUxrdlC2$MNH zaNJG#uTToO&{kDrPRXWWKlC}2~@BrZo%n-oEqZnI=Y4UG1h8 zT3D215q0s?P?hgDT(9>HVsYlL<9rtWMz^=<80Q=LWFcy7uzGC2&z!_`gjN1&e9N@c zDXDl=NhXXNob^jm6R8`oP9Y&~g5YeRcmRa&f3d{{(kap%DnR zi1)P5%sJ8;sv1kJv>4VpX(1hrWoe$KJ8dm4xAIp8S;x3+ezuH0sqk`B!jdJZ@GO>w z>?+Z(1lb$(5pz{gtMUNCQuS9kTHHm#5m`zJF@jxyi)r23nJ!*HzL&EraL%6OaVIv* z?uT~NXG>w#=3Wb|1RDoiDqf|pXd5q}l-eFNc8_xYUKgE1dnu=>NqL)7GP2BxN(&s> zqto>5ByR!*^kl@@)ZYl?7K!${k-xwLAEwiGY!W+$>THoa@%?#{`QRoHeKC{!ja-5F zMdNDPpzd*Bre^zPTl`9j7b2f{c);a`6{FcjUHY^wQKR?{HCqr=pL$70F^JWgg-p;> z!7fqohI&^a_)h{c?iTTFEUY45oNpH|^^KgOe`%%N)oFMup`cJ;Gj~;ig}ToDddz+w zQ&pswA;ZP(C-%oCJCDm5@x3o5r{K{8Yqz9^yUCZRVO9goXBJyrp{l>$DB~V1tjMzv zs9y<=bWCZUZN~G;+qb;0P&6Xv-Q$KiDk=Ap5w)-h^C zlCS=VdZ0xLu&Tf+Ip1@<9T94y5=@1apRh=ImqoaGBDm0oS2mk{pRlOl6-US5gjX^-mC6fU6{EcKSch=@%Y;V{2_;fW5s zDVy-y^lDkT!BPa;-T0ru?3*Md&Q38#d_{S$RaX)T?XY{^dso*ZrB3kYnHScbih3{s zhF4f#HfndPbpW@2byT`YCC%@oM&HY}C)&=n5AG@P5N?;o)<@TOeshJPEu+DPo~c<0 z@|o!nsQp#B{K3@J_i`?qqI^msmajD2Gf;IBq-*cp99rTCC0rjc!he8Z2DfJ&8@>=P zchmI=S1_x!e#TnTmgX(x-+OxkIyWo*G>4W0$UQQ$aKu$P?lbET*!ToQ&IT@@ z_TYPluCw!N1)e9XS1eZ+F())kf*(#ULq0xrF_kJ%8ARgw-*wI!Pj+mJm8TF=3&lp- zr7N+&B2EN1{y5V^F|6i&U!0vN%C9%S>zOE0aFXfX3#Z?^f5LVw@bx=cw0BLACP$gykSN<+%4cVhLIOryPHVG!ZDt@fYR--s)#jg`Dvf!+2TGbL^ zw|qWKKfHnKk_QN@XRHxgyBqO3m@s*_YER z`%B8DJQoO4E8@YIH%0%vNPb{(Sgyb|NO74@m4JC?e&)BAQIap(%`cI2vo=5$p|++H zF6$&E)D+Kfr6@+v@NZYFw6FewrV1J^m7z<#4qKzJYYYD>MY3N}Uc5S|Qdd)}P8*bA zfNtGny=rM*!Er9n#$ZxC<2{euAql-xEfYW*_YJ*MUK?0R9fVp0$tpzXx(FzvmXha` zFRxr5=xdLYa0_f69k;-%TgTr?pWtlqYqJ>5l>H<0Xe5H&3{t|mf~k4J!IdJ20>gq1C4z$R=F5$Y@HVC zwzA61&Vcav7(6x*9Wfh;cmtEvs`z8C5!!Z&P>t)xLaBmQ|BzTWnU@G6=E=-VYrLl4 zK=-CH4l6F+v9Y^_VPovYddiUv#nXE9yWT}rJ4&EdMZ>2ud`+S|BFmK(uMRp`X+zoz z#Xh7%uJGbu8Ti%PYm@5TrJs;`=ZSAoI)8dTq17tY`LioonQxRrvE}58G(T-30k53VZrFsx%>opwqwbdLe8SE^8GBj!6 zeOGC9lceTHytiPnR^*4M3!J(=&Bx&=hElw|b-sMOUQbIIxx3dQ0n^7Wyog<^(~tf=Vbm8 z%X3HG7_0r&67?E5rZwh8UHycb@JrOONKG_+W>P-wSN6@?k%!qVc>M_%Q6YmE{41M$ z6r-5sIasC)7 zE7g%Kty5lpnMS&hac30l>i)}|kwc(+8-d0yfNeJmzt)bBFKpnG9YUu(n9-LV^wU(3 zx=}lF^(uLvrxh!C6x(@M4CR+F{@S5$YlDAXSn=A-dp+?UDX`lcI5L7&U@dY()QwV1 z5BL(cU*4?L8d6GC(mKz%GCY&C*))kWkuMN`=FF?%MpBm0%s7U^8FtP0G$!S1<0G}1c%4rR;xXg3PLYpyojNQq|3zE!NNKkd zzFXI-rLdV_&91=fMk4=8T)(*2+m5nj@%Up*0Y5IwOGUD?EWNGFh9`Rws(g1mzl~3L zL#yw-dKu^_{?GHJE6x^$tP2VQLKhKJBbF@p|Bpho+oB`sKw5hgwxFt2*v^9BB*s<6n)w?suClVSr^02d zN*rzFN*FDxi%O0pi{v7G`K*ahfynefaKvYai7PTgvX_Q3lYRL6-1LTk6I#;mQ$nQ( z){lVyE}Byx-g4hb?*8$nsy+l7G;BOIFp@bI^C-&FDp{8czWO!+P08v~?0ATl4%;Yq zuj82Tv^G988usTQMk>2LjK4&@z&NO<>hB(Lg}Xl1o=IyB-8OtFen7J!dF;kLR4;cO6S*D?>bK6+9oD@_ZDMBrG-~Ro;p?iZi~%n zoU!p$1}SRU>d|GTGnQ40zK?})6OW@7qQSe1odODq@-6`#Y-_y+GA7*4i&yOT>$W2% z=mFfZb*h5Sn5pbzOfTil(wiNC(+g{=Rl9=TH%uHPw5uAr+~PF&)%VwAz3_DGW7gqR zLCvk0wJ}uOzpfBdPu-T%(AE1@3{wl{vdB+Z!!wnJ3x^de<3*yKxrQrR)(c2Y;n`d_ z+(l~~gL7M(vN1PtK2RQCQMN$u#ABC`xsrFrM;s_oPO$29C!4_OXVWvq&COk-&nZ1V z2105>!3}dxC!Y6ddStl09!%5KM#EE0<7ikg29OmqQkfwbx>SEz9fi%3wiw1v&e%PtnX?A&*K_ z-fqOL<-RM?b2jQvg{|Lm>yyx2*QHEwMX6Sx&xaY$>8^R*ii5|-)HCi10qL0HUcNl@ zL*7>6YZr_4-tO35nFNtY3T;@rAN=AjI@3n>IV{=4%Cj0ckDYki$9j86pK_jQ=7LdT zv%tansZ-;Vbaw3&k$|+YYvZOk%REW|pEv2byb=!>AIr!*S!8{I#HSF93Eg^d($UhWo3|;iw>;qexi@m(;fb-2&%UJ8X_Z~>JLqpS*C^~G375L zTUN$3Osp-&Uw@UYW>#}Lt&O954F@A(?hq%(UP@)(eg1kqng)V(Nu8vW9Q-GVyf4kO zuejx|TRz?7A?Q&#n@cX^Ztdrtwn>cjqnt&1bu2y#jPJpG-?E(1(i=}vDavqai9Mba#AsUa`M#G-rX zV;dV=9`Xf6{Pc8xXXY{wdmh~CvXb}K3ni|dCF@canp_nI*V@-*k#2dB;$I3lsv;~e z^FyKD>~9DURnXzglfdmBu3>uD`a$Zk+8sW+ermCoZEnufR->B~c_t?IZjNr?GBq7U ze>=ATy2fs~z$*Mot2Nw-20#LCJ$s$e*euN9Z1}|(loVpFmovDq7Yn@;|2vt%^mDGp zTNo&yTsWz#3KUY9m~Q;Pis{pw1OoPY%54tI$6^ihBfj)w_>qSH>Lgx~_vieE@zgMS zlgx>iTFn~{513EvW9_F(ga504t%(~Sv_z*h@fhycZ+;FN81Opy_J&^sy2C8Fu&2s> z1kKD?eW|Bup7N7V3A!T6IYKDhF#lWmpHayb*;uF+xqEKa%^W=6TfeAUT3=tEPO4fv zGMUdHn*X}Xdh1asU#PbyG3c%*fpA{V69R~Ka?maN$@d>Jz?bGxdM58Lu=77bg8x5+ z;go>zKWFcx>L&+@9of;?8sCXJe(Z2U`+htC8UYwkP(k=n$#X5h5(+i3v_v+e0H}zW zIhx(~FQCIG3A6!hiN0@rKVC#s)c5dUPlNXo!11!Zd!Io?7Zz^rTcZ;(Wn~Y_%i-+4 zc0d;sA3M+nx;m`81a(%1A+AnNNSnXNmS$y54JtKNsmRtgiI#3=XJXFT|CW_-1R44L zdt`{wrA`Nv=@8jm)@$f;Cp`gts6HAk0w6aLvC3j2?`=yQ_A|syXLcwKk#3iZYmJBxnEt08>s@QWXF|hJE0DP~l;B(7H-iVSnJ9 zRb|8h<)dVK000$0PEt(WBmHp6-Ggk#ll}R`+Z>&coT_tKuF75Yr=$j0`}LHWT-1>^ zTNQb~Te{I#=lHaP#YI}Bukn2LPPY99VRmwwNwdXVHcv zGfuamGN!O$iJmr6vO+a#yCNU3HwWxW_Zp+sh28RR6iguHFnW@{(pQ(##m(% z*zG>~zt*Yo`U?NM_?ic%{>sLh9&F2wJo?|=L;c2q*ERp^(AS(W=bW)hk6L5M1kG{f$XnC(+$)tD6hX7H2k95SF*wghINC37$eg_?PWbA-;^KpeXjBl z!b%pUQr1oe5#phZy+0&~?oUfggWKR!6cZEU7)XhD`Mrw>UHo8TV$qH#*ic19g^x@m zFDdKOEHhy^H*Z6jtf8TySf@@w%8Mc3UKRcN)m!n-NLe{1DQV_`$c^ZF|I$99O1t#e zFC>n;ySrFfZGu)4nwJV0?Bo)vj4v zz(WrT3W7v@%;@|?WiVrBZ;!03tlW|OKeM$2@9)@d!OG4Kf~CFvwL{fx9v7-w(&<-Z3(A z^fi_r5H+0`R&*Io=hkr}CqF)RIUiHJv^K88#KMC3XP%^{{^C_gN|5k($m3P+cu~lA z@f>AF$F`P_FB3Yc*J;c_hE)QltlV!DH#fmHVaHXO(q<_D$D$6+;{Ds;_^*7hUr>cM zi+S0R`A8-Mf8T}^0M-(YG5CMu{Yd>96;V7VCIn^!_S1*3RVm&N>h8Rl5q>eo+?t&+ z=R@sTk(PNa*n@1=n#(!q@zFA%Sg&7tp26P^fb4kkUy#+5_+H^$f25BGd=o41dij3b ztVikZd7xIt{@cT?W;TH4)qjl-g;7?%eB(*+|6s-2ISX1M+b6iGSGnBI51zQg4KN-uNeGI$5a4D^_KSK#zt_5T-X?sxZ` z;;8?JPnYA}a#8HYD7w)&x~B{@EJ%!sFDm=T|Z2sqkV{A_9DaRW_|MbpJL! zp1|l>Ea+(dxLE2^v~T;_O@~!GWG`Q5Br5329`C4SDqzG496Z%xAZOC-Yqvu#lEnHl zjlTH4Jza)7N(%}d6b1Z-=EMmvv$P)>tv!3N7%1Y0KF6=tWOrQ~sTh~*++cX%5e$X4Z%yp zS$etCy1RQN?V5Yls5;ahg=9AHyr39c(-8eaNsVPVIE)WXTS^UIW6IEVDt4|WIEm<* zM<5aj|5F#=T$@p96%fRH^0(fY=32LJ`puv;t%VEE>M3<)_&&EKcf&}+=B|} z4UiZ~&=~RG(>qp3ne69ZaE#X|syzS#G;Rfteo@|5-zffF|>wlc;TKTofxLk#wK9qJ=y3(qhk zV7uqj58oP#sHTH@s|f}Y+{vu2fNnW#F(kwDWrP@ z=bJk6b>AkTktmu%bLyXWgwj}TPHIaT`OPI6ji~^VlOQ7Ei+`;rm$~=X*!4MAj=CCW z>S70`aljkrzM-1BGt1fWSuo~Q!zk&_-JskaPC|a5jo)%SDj8>!l}^}1q;|`iWf!Ya zjh~U6it&BVJG8^uiE{|0$dOg3lyZ;CNT$-OkRTFVnGf3od+pER{S}!MqsKV_?;ASk zio4&^tp2?_w05%s+W+{<6h~Ab;@7D^K}odj!qny3D60dK4d}LeOi-**H+51(c_a6a z8u0q3z4F_=j+7OGsY9$fO3L2j!0VOvhx|f1!Znv97Jwb4hCu+xoN|9LBLa3UT}G?}rlre`g}-VH{f$gc>a=IK_+2#gv{2quu8`aCc8QYZb{pCVx|ihhMg;AEBtTQsJ9*kI)BrDcN^pn8bdd=xo@PNc_GH7wUi-_sSVB)}utzRi*hIJ1nv)32 z-RwNU;N+0HX;cgrTK=yd?J_{WPmF)8KV-|o7Y}4f@f~k7lga4QIQ7#;(sCJKWxune zA}>sMff<8$Y+q-YZz#e65j_$`L{%AmMvvbPo@q1^>gncsXPnWiP@H~SGArlq-36lA zF8u)S7bUdDgaSE0A4T8#;|^yMrgB~_Bc3i;D7H3x5cwCI%0st7is&D~{glTY(5D$* zR(K>_jQ!~A8V(cx?A1OScqybC-v^+PwKZ!fJ=*h;_t^81k?-d&4dq^D^y?;FYdXY) zK#ek#=nwGzBvRT0u7#(^``yTyUq|fGneoInffGg-j#Yu)p)so=R2_GPq%|Y%3e=lR*_G%z~ zk*rV44egsNyUG);rM2DGIw?l)=G@5@mW(+KUJv13GRw1`rCs5(w^nz43>cq1+@lG` z4nlpL3&L6jh>2d-%8Hwui=V|%85{fOub<{v2Uz&8b>F{<*UMeWN<{69kh{I85P5W1 z0rg&y1(3?$zU4Bgb4v>T8c5v3Rq2le&!osii$bgsLZBjw#M9E8!uWfrYl0p_;bV}^ zh1-!pdM$EC_A{OD17c(k3O2@f7{m?lN27tG@(r=_Xns7n+uD+HLfH~i)EjHOH(m&o z&4P&eFrnGZv?V5%vV;ls?O*n**1}n>pc~C;-LwkS{P0E6j(U*oMD&xFb|~Ppb44*R zFPfs4efA(2?c^PgU0uudG$XZV=e?3J&#Q0Ke9zBDNs6g_N7HG@n1?8Uam&RMZI0dB zH2IZZXN_IBvz&Rz=H`mlUPM0h34A|*&yOSRzWZ~~JBzFo4%|@M%-a!C3Tk*>;H1ya zQ4Rd-Ky4)&K{xURNV|px@^!q8g%VmaVJs~`%tv`8o96kuG;!zUAe|ch(kfG282j_! z^#to@TF)6fwPQ$22OL=dz_svfky%jxC%`|9z`3@0yzVZ>|J6_73;l4@T(o`l-J`rMXS1i>btG;UfDXey{e{V33HCPR-qgA$Vf$d2g@1_h#0mF3;q(t~NsO@;46nJM(_ zsA7AIhVav^JJ5x!una`_fSn0A2b_S%X%I#43*wL55pnoBj(8JC($5pZ-ZP#q@6Yd> z%8*^U-AgJOf>^O4se4a~Nh?|$ekD0V1lj`y(Rq}FZg-EZ$DWguhDzM<7>btw*mb~c2 zae_nY?+})lw4DSx8&B&@Q*G|`x1W2MLpoyljQ={Z)q*glzV%slOmLKzkc_er;ey1o z;Mpp@5Zov%HQycT5qhn5z6B^|_Q{9yH0vJ9UPxdMvorb^+RYi}D9hsG6iGSb_uDAy zZ3=cISG`3N5}mlwJN&RylDpVmOuN0LjjJ^5y?>WL7leepw7_orxbP9)pGKvFM3nXz z6&}8@?8a_mT*LVHEgo^rw0fj=BynS|oRoNkz^Up6`!pj9JfVrKwmM6f!3TvG{S?%A zNZJRVaQR z6ss=xU@tqZFOSYhCMAmFd-}X^E?$OKG7u<$GuA;sTejKW^7SOv)b%+P;tPD)xgx1- z; zx#3sqczN62sQ@$srN4<4L%TMjkr9g7>U-iuJG$;1A94z2)2mS>E1lgl3hy*C5*zPM z3TIH)rPtN^5=S$*I!^jVeaElT6dM_TUrvbC@&Ub89!u0u7tveXHFQhvU<_>mK<}q^ zxxBSfq5)iM);~`)V3UMCT;M#V-Vpen*0C$#4Q5Wxv7r`F6FNRNKih32IVx-*++=?M z8W9xgW}^j)iqYbrZ8mkZA$ZC})4k#yG)!Z(|kI{OXAi;~Ap7ZF*anM*M@2g;-AyCeU?vmiSEe z5&8TSM%E|y2rb{>$Tr7DrnxNZ!&N%mXv(BY#brvv7715oBfzov)5%OgV84-W?fjH# zUL^+;y?-LyR#nT65nY%s3YNpt@}YGVqdLZ9)iZ`HCpDJ;4{5tuRn|VPQvh?NKd%cF zOMxqIW-5saO|ecq7_ACx9gd1BMEb0*;yEdy3!n%+X@6d?mGcB(tm6z7y|{)?B8{>p z70U!l4e%S;bX0}eY_tH^C-|cb9!q?}LI3pE9#OS?f6*krYC8KD$Ny&jNIG=?6MJ{2 zu-0ey8o~;LOkBC21Pj2&z(Kem&QtuzGQK6^8ftI=ZP>K^qWgub77`Ng@EaaeFP!~G zMql@-*xz6hl<`-lg<{!%*)lCm@WpJpGdlwB=d^LOV(@7rJG#zrG!YTYJGfJ8sYNMz zs0c33G4w+iiru*07%q*uBMQ*AG==3~y4Ll?8>?Q-%QS2M&ivO_%YBmC`qT=-61zOY zUg62N-;J;r=UzB!6(VABGy>!Hp+p!|vI+fQ#%`tOjT(yVFt9a?e!X1JtF_4;;Dx9a zE)2&tl?^b%IVMFTtUZPjA)!4QogBx_rV&W^A>P`phxsZ56Yo7g7RxDdknxwUJh_j^ zSyy#TW>ue*&*z~si32b=PJZld^o158G0|rZd#@!-!IaEN(?Q=i_?L0S*)K!k(C z=fnoy&!y%wW3BU!ko#@a6(=XPhvxN{6~66gpUTAxH@TR;tl*-Rngzd(yAg%tiZ7hYQN0q7rDnmc+{de%H(B1BU zZ$ho@xzPD5K{7<-OD775(YH7U+7*!9P2HojWy1yG$eW-)FQ8J63L6hnkVb2(rIdtP zRUuLo?UMpKXc{J~)-5&l84OZ?gV7W;9c9VUH)Q2KO)ef=qzku+@5dPNZ;wu*$oRA^ zRQ^`B9bYjoJblDn=Xyyx&fS%jIvlxQ?|z1~~3G7S_aXLf`!Xsfd|INI=HZp|7qq z7W8=u^(4@v#0F@E8?HobspH!h|B>Jzjsac=3W6;fq1V90Bpj7>j+~{cv59ayvE~D) z6xZ%S3CUP!(_44*Z5;Vc6`EGnZCwG~5HEuYKE`Z?@6-MF;G3BZ1|>~s?+S}G+439u%4)EFgRAvo456>|zIjVE7CYNG?uplLa#ub5{pjLxh}pjN zdNl4ci~geH{)Y%_M&dMXUw;);FWKa{dK75_x!z3Qx-fq#5vwjn2ChIgf|N;~4mFQw z+Wyg8<7aEl$daIPY7?hhCyi>_mF@%N8YWU!{FR|o%VaL60LlNNp zhOEnI#6XV|N7(P~A_1(l^8Kx(o8Ku}7Wjeprjw||#tX*--{@4X4xG(Wk$CJxs*Lwg zoCK9|HIq~C^Cw%P5<_Uo@OVQcMxw|=7^E~Jd-|d~JKB=DoHu`8MSfxpSP^kQT?>|J zYjz1QM4}!~b4Z`BfR}C#_uSf6eOLN<@Zjus9%uMERVuv_*|zM0x+HGZv~Cdk<90DO z11W-Yd8XgUrKn%g1x!(p2}ChuTItt$8PHCi=Q#kg=XtzUkTP?t!B`y1dWLaYnuxXS zd-zHnsve68qmk{pu% z7KlPcbvtP~V?W!$@3%yVTzrlhFLjpGl~-gq=I(;dd*X7%Kd|@32 z4h|n2H8_im0w_nV!|UD&Wmkg@*Z9^kDHmtNT3GmB#<_x$By>0>(k&Ya*2UHE2%%Nk z&!M7<6rIE!V|T?S2=}Kx%+;Pc!?||2n|&Mj3V_JS)NxyKZevY~jClooBDbs@?kp&+i?MtHs)lela(ZJMwH zWEq%#A@HFw;zvz|NZpS2Q#4+apc>-?N<{-$Dc6aV%Kg9RbY4epzV3wH8C|S(0AeP2 z9zmoXF!L4vVkJoX<5n0 zL$9e4o0@Vv-C{!sQQ5LKDiI5D{lg+lLfaQX;W&gjGYX-nhDRa!sT-IGNPVk){X^LE zFP=?gs8Wg$a>pLyH&2c@j2uIS_f&-#$mtag(f?Aw?t7QcZbSa5Mu91_=bzdgtW47F zXdzwsVI2|y5_Hcsdv-44-{6r^QPkow;XM3H_&flVwnEjO6ZaL+If=3M=I)8lq7NGQ z5#$I6+5sB2&p3r?`XwfST*i0rt%8#K3zeiXOj-C837y4{fxF<#Kdz!@mq6_hi(qV2Zkx*C{{R6zp$W47@H34Y{)G+vB(eO9r-(0lqRgBW{gd* zwu7M2pBt^iW4|X(EDsk~sje(NX~YVvxJx^;iz$k%w=J;n`cSahYUsK7zLA=?GEJoC z7{T>VHqA)G@_VAa##wpvk}N+HiLOL6{QwP425ZHqqZP>g70}bT?+bt_2=%-}{Cl>XoAYvwXlF zj<1;iJ4}O%6*bM-*`M`bpM(?3Rl*x*+Dr@8CXDA=8i+Dg14&7TJ zdhG0WrfjZom<>P(p}bIiyl#4eab1HhmJ_DFjYP|J`fV`C_IY1xXH%-{0yqttjhWQe z3qk{gi2JwS-v2~lE-YP8UYd+kPR{N6Gs}r!{wWYH8%K=xd)8BbVc=U?uWLHmCn|E6 z3;Z+MWeTEU%T7JwKd{fV3YAjhc4m-=LzV z537%;XUE<+)Bay%%w_JU8+sU&yZX5F#6jNh{@a-;%Hq)veSFus?_siE50jteg5bbP z9x*t^PaVXMOvYhl3(W3^QFL|qIC*GJk$vYh@9p-7ErlLCw=)Pye%|`tEaIaXcdo~? zv-z~Y)7{Kb@4?KyOV#Oy?uN%3dj0a7JJ*oIXRsaQVlQ8AZ(reU`})ZV4g&^}4*eza zygHXEv=*PpeGXXh{GJvP>aNQAZQ?*T*x`K~|`&MYshI{$4pj3wES-Pk-c z16|%m_){eZ1EGC(Pe$dwXH(pAtoBjJZ4ZG&ZTG$2J4-PP96!{^|2<{cMRRRZaKAt> z^gA7buDEL5w3xdAkD4us@V&9uw|WqOR?2kqu zp0{K@jj=P(1NS5iO}aSU+6U2zWrPJJw$-iUATTGK2BQM~$j4RW{58B+{f&Tsa{-R^ zei#DX)p=>m2}*!`Py6ebE!SCYb~(Y~fWF4JYM}lRE#GT3HMH|pR4P;^k*BjT6N%&7 z@v#-#(4BsW2=MVP&hjArj*|4XLUcX&+NWLSg>s{#hNxhUMnG)7tU4{0M~pw5q`TB7_yz}GT-;cA;ohl;2=xM+1ci#+NMMb{u1^Qf+7aH;1UVAU#y)wlGAd(D+t-k@_ zFiMWw+ZRx0JJKs8|JkV2xMb#cJWaNF@In=g`w$XEu5mV~v-C`cLk`tol*%D>hQmg08V~c~wYUX&X5TA}lt$q*^7I|kw z`%TNccm|)li-~XWfXvTIbZu7|MoW%Mmt#KG=Ax^&u9t8nmbP7^!s9eDO4Cz3wbJn; zW#eDEuCk}aeaj1(G^wcf&L8_?`y8IPy0?BgHaE)s0>j54W_p`Epri93O2p1_NiR7q z9LjC1qUM(^@OY;i^rEDhuH1D_OcZ{)4X-drqCB+Q;(jrVA?2Ic5_!sNRjT4!V`nuM zTu#SAg<)pqeLKEBH8PPXwMb<#KMJP%Tn=nFgu;F;CV+?NhaWJ$10Yw1HLFz;`u^sE zV^1?!U&7Ai{y@$CO_ovPwIP9A_I)xdE4Nf^DJctB9MNy_liJNsg{h;YdXeN(+(Acw zf2$Jf6}JAeB~wWQ+r`EARv!bh%(i8(|NQFXzjzHTNL;vvDG>}QaR@Qpe|??(h2{P0 z`1S161R+OCItu{n&y|m0nsZiX{TDX4zq|s6v}&c{B419L^7SOVzI`c#{3*>gFh|mu zbulZAs`z^e)v;a>+j44BL9xyWY4gs8=g6p~=Z8k8%l%xs%9*+Q#P4YW@fEY4I`kdJ;&E*_$*}z; z;m~p@SJ6CcaxnbAvp?C2JjM1EHc`nCnwKMS7dV4bxu}eMdDnr#eM7g+;$W7t8ta-2 z#e26*Y9k_+`QG39FX089^5k?HZ z0A~vNh+Oi`3pY4cHP6@gVs%f;QI0+d2}}@<8b6^6^%9HDEDiE|wH#GT&Fpx$@Ob-T zxXjOb@_!%Q#mk#WVBa1-bOxSySweHO5-j%8ksGNl^MPD~3Qy%ZFRON@oc5p8?q&vO-*@cA}JApXHMM9LJZl(cKpfH@Vgi zr4Pj;F1F590NFz;(W8H)9vhXXxX3%AdkWwD^Yn~Zbjs`3=zCl2B}-4p-hC_2Ew?|) zQ$UFRa0*@{rDYaRj*AcModyQ4zpw+1+9Tary)gtMEWq3oXY>gvtvrK<^ESnwZNMB! zx70_6Y{MT8vMyMra;NO0j+QU)Fx*SyH|h@v1%Lw+%r|`WxybX~3~~-%>;B3MP?jvG z8O-%>wUR?u8T}3G>G;$Ismtt@=AzS^fiNG`y8X{!{h+ z1{ld9E>QQvLgcT&loqJa$%ljbq?4_bFYhwd?A7hlz9~YbWk<6p_SPy7`GzyFe28S) z;1rT{mXp-dWB-BN(eP-;`kA|Djrxn6MjWGW?B^$gJIOQC-de**-JYO8SfbjJDfZYd zWY>JlkV0Sy2-2ZfPS1*NL-!qaPw!un;G+AOqxy^06N_ zdE>0Wyzl%Vlb(o8{m5gFNdYyxUzk37V|gbDD{J+c{Ga2uoptKP!K$02q@}Wy``3q{ zz=Tpd3r1#6+MBJTZHc1mX90#1HOPWjg>F57%EHUZUO>ctp~SgK{Nzc|u#u20d9f$p zf_O-_Zt~$~+)W>70gmbtcXX4O8%+Ci^zb*$j`8u>_3wo`&C>Ac(U(Df#C+9^jzR(Z%|EAGS<@Z6n*o@gM<4)MZpvHy{*uNvn>nG-oy1>^XNyR3WWy2 zSDm#W9rLYp9%qYA_p?TCYOMKZ{bUML#W_~@rs&jXgn1{=9rl6d3a4O;v8SbxH+HcK zQ5!nGSd4%CPFsZF+4~XV|Cx2RkZ6T^t({V^MGKU_p$yS`KWU$>z;^ap%hKW}i?bWv z!Kn8~l|syGa~g~J*kgtO!73+ew$M|Ws;R$H>x8s=z zTJ~6q>x0J{jv1Z|5}Q}@(zE3neqoGJm6Q+heC>Nwh|VgXIk`+^x2Oq4=LzLz;9#OI zKWHAz-|^g;K5lZ0_-8QXw4*D~rxo`Lmk%TeFHiszawLj{ZyQYpdxy|7>bifJDM_B}?xIK+ikanh>bSBo?Vib-%mCMFF;<=N(-?;=RTtm*PW6(>kw` zNR{ni9Jye_SgJ5{9Xe#}M2&VMbjR=J61EmVui9oM&n(z*70^RH7MyU5cuk ziklkqB@v-l8O=&S1$`Gvg5?sQQFJV)K4+ zck0v~K~=QMP|)j``a)zi`_jdwsAQtZ?)Q{H)z({KdlLme#5*T-0w++Xa78Yqj0->9Kv!;Uu(STo98aktkBib)z{V6PvF4yx7D_%AusoVs<51_pvBV?TD{*CeEBo{a`AxGo2 zl8PVa=WW+@6+twfyQGgu9mfv&( zR1iACkmiL6nW@i{Kv!A;$~gXDHiK%9i|vt(KE+1p^F!cX$;wWquiMJAuym|qe@zNc zO<|l_18C;)Zo*SAGnO=M#Ohw&10 zYa5%Havf+8yH8Fos6DY@`^ozzEWg0=K4&oM0uhtL@pM&$fM711*M9MKKCU-FbhQnI zf`r$kwcT;=?=L+bhvQovM5=>i2SN7tS@H+d@&rn+b9neiFA|i)$ zWa0g+Y4jEmzU@LiD{gp}fR2%-=Ja6yEfU`fm#M0ThK6@;A7y+EdovbbS8d$=_H>QB z{yQrv@6^nU7P-iMq=Qd4C7IFtSnac8Z^OTKR#tD`TPoiOE>BKQ!f0jBO^UX?5|-Ud zz*Y(?CB}q5)|C4Rz82z$=d!X+O-=bjtREZe zUqw?Z!#ZX+wrl{1xX%hJHl;b>tOoKwL2LHTZf4F->^c3`zlY*6+%uON)NGINuCPSl zi=5Az1|nnr{#i>zm7>sA?~-!R92krR9o~qxAR#Cb1|@Dw3QZh9*LQ#pe4eTrE%z-c zPj^PT%Qr(tcN_M+6933xN>5nW+6<1Y7;J6JN4G~-q~I3=iUpb<-Wrb*d0E{g@M^q5 z+}G+lZ)X~VCEPDHyE51)9j?^aTsBtO*?14mB(W2W?{O9UxHtz)PEX&DUGBw)QKj3- zksKB}U3jOxFOMgl8`0MCBc*4C@~~p9XOV(+)cwA{#ZSGi0^)_m7OW$x>1|Eb0{4(!+|xAt#%<8 z0R<~v#8^L8m{yYt&_Hi()y=pXe9jn>2rAO&8E0Hl;4k2 z`E2kQAwCI8r!a&w{&Y=z&l$W(ai8K|U>7uO8UWs@_`}nn*sKdIk?XD6--kgqy#JKZ zcWR-l-LSx{${<(;Ud4UVgyF>=is|RZ~-=p~jX7={m$Bc`UOit&5_C@F- zPV8kstblT)>~`{)2)j?AV#ay20#Je7`iVh_OtAc$0%OmGP@UUMxdFiVYS8EzY?=jx zg*Axq2@JF6qP*QtbQ;VF9)WN=qwCwL6Xv7DB0h}9)!hog*yP}f3KS04{mEe^q-W;? z%?c|kYh;D@$IqMnz~9S7Aw|CzN$pQT!Tz5QwpmZwAKbLkGQBr2d6#^+03BrfUlB$5 z$kZ@4H$T8Yctc+nt37hAAlEWM!?&FyuAL1!AsE0=u!Crd@_dh6OV50#wlkBAycS-^6 zx$^j+psa^OqC^(mO4I(Rcm}2C>zVfF9tPkXr~?2(3=0o;fIMMA>z?l!lrnuzGTfy$ z=bL6Qi8(sjv#$=Yt|*g*BdeAOJeUON;j^oXRW$Ng%Va@IWBSeEZmK}Rv@}^Zk2?Yl z?!HBSsC~$XOo69ihpg&pHp9l#_^fA_h0RY>zF=2pm(%$AXmbG6AaEX z_##J)zUbE9PgZCLTJb!H9OnLV4Tqi2)+e%9{i~pWJ|QZ{kDm!$RFHWvNrB$|crhjF z^6mi}kdTm&GQR8KcL$>xn|*7pgT=20M}Fxn4@+~fL}sY*bg2#?kzFTMfnFx6&3dy) zMYdvb+SVe4#E$okLRRm{r%xwsH`l>w4I$L{7$T>C0`vMKM>4%XeBB&S61v|VVsFC< z?@eSk@_W2JgT0Bg@a5C?Z!+_;1p-XV#rV^>GpKYM-c7& zrFSv-**l)Rd#Tzg9y&Rk!c{ZhwJhwdS*E)MP1^B{jEv+buZj8ce$KZ|wV)vdt0!;# zzF7bc`JQq+1?YUF#_eq1PK5?ye^C?8^r=*25#@ zfss?ejHQ0-V%wzl^d2S)bqmj*nx5|uBovKD)A{GnEk;tenvXjI0ucf#+w%*y8;g)C zEjz`Xz9OJqoIpU6$>Vlc_J~bV)lWwGz2cl-24dc5jUfZL?Izg%R@m9vUUnOz9G;i@832aJ*oGMT4%}(kFW<8o16nZJq^rX zn>Ev)PGkZ+tZ;Kvs#Hmw!tsV->T@G3p?`YSV@gd06q zr-eM7C$-nI(JQ8V-1y!U)~9J~3=vOM7yrt6=oaQ zhZT?WGwsWqKCQNAU95WbMPOhA3|&d5%Z%!*HK=1l`Zq!)sbgh}tP7ahi#x8_~i@3~(+1MEU&U%T;T$9*fo|L-4=gom%;e?YjGvT@Q^_uvF zB#I(e2MkX{J-T@S$tst#E>XTO_;`g1Fb;Jqh=(T=aoPPvWT<=vJJg5zrtC_z!#x3S zg4nO=71ech!_x642YTL3oTG=sH20gai)F8ij8_{BcN2<%Yprr>g%37#x#NYIUTBpw z2JTC@a(+j&3yX`3Y=?A=?^w$OzV1q1aYD<^)CNn9PnIFDNrPfgaG6JV4K^%$V2aA= z>~YT+WbLC?x?O?q)iArIBT_j`#FvqZ&{N)IHSy{LP5UCsr}sWEZf7MkuYlb9>yHTU zZ+C!6M58D%Nt6M61Cqk{RB?VttD3rz2Nv|;v~{X<>K+29)GU5)w3yWi|ycUwtiX+CFn7L?E~N)2^&GVnk8{1T{J zf<-=RJ;KxQ;dlvxE^Yjj<*EQ%`5*}5-p}sg49ce-N09gS4^jvFgHR^P=`uqI2uw z2OL5}{Y*gPuU4oCXK8Kib(~@WP`^9@p498XO-@a*>fVBZb%kIs+Fn*;gZ+}%sWP2E z0t%B>skYM*=1eri+Lrzyk8XZG5xi=2f&Tc87$CCP?AncT5J5eino3)3dlsk6=y1B) zIkV)L(XMD?b5Q&P8F0k*%I7l|u*Tg3ZDu%w6fFqGR01&S67jwNLL@ui?qK949z0iP z%HS_cTW!B2pfuG1#w{9b)3ma(g59<-F)^{aZ$3C(>rUf!U}I$mZH~*3DrR2ZINhCZ zbv7)+D|{fi($cFm4uIl8kjQW~o&uG8!IgX(IzA)66BZgAhKJhrlZcqeTS$GatcX3Z+f%6~ws{$c;8h&(af-<+_&K6Sr-y~`(2)cx3UOgfNn z_KQs{lIq~At|UNa?M_}jCgs&nri;mERd9LvaT%-|Ffut#2PvsIo$VeiT%XLf*e%rS zXc=)C{}Bb!IPCt(X>mVk^IUFSk9#dU&h1>G_p}@alP3xp{3RQ|9865sh}tjds9X=r zU`mMK1cJTVi9&e@^iVeU6i`P4Fn~+4Jl0X$(_(wZV<|-+wXWzG6O-!y=3MCslCc~yv-S{@%l@m zfBlfPeQ&k!t#z;Q2PG9UhvjZesX^B$xgcTNJ-Cj|zoY_Uej9?DQY6iYPr^~;JG%V_ zH-eb^yfYfu`eiUq$@g3>z?j3vTz?<6b~=;K3BIzd%r0nCfd3W=<>qLm%~x=q0oi`O znm?Y4I8@T@cySK|4+|QOBy%E2XFJ9Z&KMbC{UexCm`r!dC&8hYmTDWY=t8vxJ4KnbVAy2M-U`(ult9vM z0sp#ub7yD8ZNaXBRd2od7$(AQ=f*%HWP>BiVf`C~OfkxglY>QWHAq({9x+(-;x(Vc z{W96VUUM?5;hHii+-l1Yoo~taN0GxU)X3(DbjawUd)kgutQV$I%A^=K@$t>qLje&R zwObye8G`Q9!+U^wySe7iy=X-ukEh)*m-|e80#x~d%UeYwnhcfz)~Q^SpWov}@wdN~ zv%qvU4Hn_uz3Hj9TL6Q>$1qEW9jiPh?y?sb7wa^;>{*Chya6h$(`>%}4iWIH7-b#8 z6jf1ELx4@8V9pDoYhuwC6@1>%quDm;D zt2*UsGhMDzQ(%hCCFQ9~lTD5+#$kGW`1kxAmqt1y|Geh$>ITM?o*O?7kLo4$v|4ZM zHCYo%E0c1!Z$n|e{?ST1^zrTn9$@R|x11@=jfu&yPef)oNPKFl{{fqf*d{WQ&&~G!5|;EF zna1bIgy^5*y@a{YVDE0w0P`a7uB}_7@?-@J6ZXF_5JaiNwL4_^D!PtuOxeedDYVoGD-c-DhSO`=nQ(7o2mN6hRKerN?pUK}3LK*yK~B zvb6nsmFG$$9hvTYvpIK|4y>)=V3Lh7nTU`N7RFbT zDA8_kE6bulN)Fm z#kHhap%oF$ClKi9C*BndP84j4OCcpm>4*Vg$uTKj*2~$pO(Dg|h$9ceFY|Ie8_ys5*4Nj^ zwG6I0@2~8s&5^o)V24Vg35}5gofZ>W^%ThjpNF}|gicQ-f~2HKr_22wMjDK1+3_=h zAV0mE>id}DT2!ix;DtmJuhUgO71DPDS&161RXI7G6`4FHfAiP>{>_a$G*(Vi5ZE8q zsR3h=!&I_`ukTYX61vFqtSNu6CXA&XaIk`F`dM4D465y(l<0KL8&=zKbw1VFeEP@y zzvbpunfAk1n>=~7XRbCn;Zb;P#wy?eVTUc;A3nfBo9pAiTm1R<#S=JV)ip&aKffH{ zkJzqnxzH@g4Mx<4Y>kwXCMh6NnwP}V!{L>~EBM-M2Fc&!gW-8^B5O%Tjz0jctqvdl6r4W|?C)D6#GL#8^+dn)#W9V(?=y=LcpBd9}!AtRW6NYJH!Z(Y2=saKv(LK5O6LOjgK?sQM8B9$woeN3(?W-Mcl$ zj{lFSs|<)DYS&9IB_Jt{bW3-tv~;(Cba#WKf`oL3lt@cTgLHRycX!_7jqe`!pP;id z=e+U6J0J+neF`TxAKP`d8XNCuARr{<=jAo8))p&w1?UBJrySOKSEjz6rlypP%v_~i z+0S|Kqt=vW+{}@YQ7}*pjO+7Jg12vjuF5r*#TSVyw{V+{YVP0d6j$LtHu<0gzh+=S zA(obsfnRw0K54aHzM#LS$G(?FfsKo6a%o9Ej~y`-R$dMrvDKUt5rJ^#s<5^;@#W3^ zeQ0QCrQNov>FgCHJAWVZ!TUm-d`al}Fb(95v)PQ6XbB1$+QhCiO{|59Np5XzZDl2P zX;64ws^?+6#)ao&eN4;*X93*-6703R5RaALwGYQVxlkY5Fl%<}BKK`uTblwI-`Lnf zT1G-|BmpeC$m6a;V1$G{vHxmY8;0}(24vr&)sX;6r5 zbq3$^#U^UN;6Rj>RaBH!U`S(X(nWj_A$iX8H6+t4-fySw?MM0fetUV)T*f5$S{&-? znpIl*Vg(1~_w^GJN9AwGg|l1B^HBq!`t#;%I%#R@G{5nQ=aMKb+22mjNB_n~(4n4Y zKVS~Hd8e)UZ)L%o_OrK~Szn%>B154`sn{2aPft&CkO=J(MBp6$$j-_FCQ2Y7VW6Yy zHE5HPkfbL?>+0*v(*sli*F|F4b%KDRgR`aeHCvN!{{gh~B1^fL>b%kZbm8GaFdK@F zjzDq1;)uiF^wgRi= z4m>E4R&cxS>4Czqv$M;%@zzO&h0JM7c-hSTrsn0H`EWw**~=#&UVi=gUQ$xBfYywk zpZ{0UFBGkXCODedXcgt0(Utx{Wqux>?)k&Cc0DiGYa-@SN|eC1tVzp3)AOrzfmw}% zVE=wt-6rAg+99N}3)$^^ii*;+l#?hlGS=_&tG9BDc>#Hheegpnn51qAxgno=GM&H#Z?D2>cV@C4>G3VgEIQ z9I(v8)pwt7h%{ZC-Q3hIVO~72`oi$~-RwEn9}2jBUOVeN@9*y)t#H7`#+D7=nw_03 zEiJv=pEfhy^j{af8848pP+`IgSA@gWb%BEm%&pPdO@6ie>J@~4eopvqhthw!*~-k? z8rDBJSW8`6U(8oR{RN~eP`9jZZgH_h`Bw01##nip4q-k~+1bU__iR)W(%0Ab`+R}q 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 literal 0 HcmV?d00001 diff --git a/docs/zh/06-advanced/05-data-in/pic/exception-handling-strategy.png b/docs/zh/06-advanced/05-data-in/pic/exception-handling-strategy.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1d55d85c329403afa71bd3d04225095e9951fe GIT binary patch literal 44166 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 Sxd(iSmmy~#wcn4 diff --git a/docs/zh/06-advanced/05-data-in/pic/mssql-07.png b/docs/zh/06-advanced/05-data-in/pic/mssql-07.png deleted file mode 100644 index 6c1668481c648c9954575b226f2d5f6c1165d56c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31515 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

6k6v^PrR3CK~keo#bW+DZ@a{k_O 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 KvP|6g)Bgd?FdlON diff --git a/docs/zh/06-advanced/05-data-in/pic/mysql-07.png b/docs/zh/06-advanced/05-data-in/pic/mysql-07.png deleted file mode 100644 index 6c1668481c648c9954575b226f2d5f6c1165d56c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31515 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

6k6v^PrR3CK~keo#bW+DZ@a{k_O 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 KvP|6g)Bgd?FdlON diff --git a/docs/zh/06-advanced/05-data-in/pic/oracle-06.png b/docs/zh/06-advanced/05-data-in/pic/oracle-06.png deleted file mode 100644 index 0de5443f08940abed618d89c809a17fa0404d12c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15052 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%0Aof$S`{S{^77aE6>+C{15IS|Gy0F&6{fQQS<&; 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 diff --git a/docs/zh/06-advanced/05-data-in/pic/postgres-07.png b/docs/zh/06-advanced/05-data-in/pic/postgres-07.png deleted file mode 100644 index 6c1668481c648c9954575b226f2d5f6c1165d56c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31515 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

6k6v^PrR3CK~keo#bW+DZ@a{k_O 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 KvP|6g)Bgd?FdlON From 4b72412e884a52fafe85bcd48940f8faaf82c1f9 Mon Sep 17 00:00:00 2001 From: dmchen Date: Fri, 20 Dec 2024 08:20:54 +0000 Subject: [PATCH 18/55] add content check --- tests/system-test/0-others/taosdNewMonitor.py | 88 +++++++------------ 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/tests/system-test/0-others/taosdNewMonitor.py b/tests/system-test/0-others/taosdNewMonitor.py index 9aafb122df..00db81c8d9 100644 --- a/tests/system-test/0-others/taosdNewMonitor.py +++ b/tests/system-test/0-others/taosdNewMonitor.py @@ -23,85 +23,63 @@ class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): hostPort = hostname + ":" + serverPort def telemetryInfoCheck(self, infoDict=''): - if "ts" not in infoDict or len(infoDict["ts"]) == 0: + if "ts" not in infoDict[0] or len(infoDict[0]["ts"]) == 0: tdLog.exit("ts is null!") - if "dnode_id" not in infoDict or infoDict["dnode_id"] != 1: - tdLog.exit("dnode_id is null!") - - if "dnode_ep" not in infoDict: - tdLog.exit("dnode_ep is null!") - - if "cluster_id" not in infoDict: - tdLog.exit("cluster_id is null!") - - if "protocol" not in infoDict or infoDict["protocol"] != 1: + if "protocol" not in infoDict[0] or infoDict[0]["protocol"] != 2: tdLog.exit("protocol is null!") - if "cluster_info" not in infoDict : - tdLog.exit("cluster_info is null!") + if "tables" not in infoDict[0]: + tdLog.exit("tables is null!") + + if infoDict[0]["tables"][0]["name"] != "taosd_dnodes_info": + tdLog.exit("taosd_dnodes_info is null!") + + if infoDict[0]["tables"][1]["name"] != "taosd_dnodes_log_dirs": + tdLog.exit("taosd_dnodes_log_dirs is null!") + + if infoDict[0]["tables"][2]["name"] != "taosd_dnodes_data_dirs": + tdLog.exit("taosd_dnodes_data_dirs is null!") + + if infoDict[0]["tables"][3]["name"] != "taosd_cluster_info": + tdLog.exit("taosd_cluster_info is null!") # cluster_info ==================================== - if "first_ep" not in infoDict["cluster_info"] or infoDict["cluster_info"]["first_ep"] == None: - tdLog.exit("first_ep is null!") - - if "first_ep_dnode_id" not in infoDict["cluster_info"] or infoDict["cluster_info"]["first_ep_dnode_id"] != 1: - tdLog.exit("first_ep_dnode_id is null!") - - if "version" not in infoDict["cluster_info"] or infoDict["cluster_info"]["version"] == None: - tdLog.exit("first_ep_dnode_id is null!") - - if "master_uptime" not in infoDict["cluster_info"] or infoDict["cluster_info"]["master_uptime"] == None: - tdLog.exit("master_uptime is null!") - - if "monitor_interval" not in infoDict["cluster_info"] or infoDict["cluster_info"]["monitor_interval"] !=5: - tdLog.exit("monitor_interval is null!") - - if "vgroups_total" not in infoDict["cluster_info"] or infoDict["cluster_info"]["vgroups_total"] < 0: + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][0]["name"] != "cluster_uptime": + tdLog.exit("cluster_uptime is null!") + + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][1]["name"] != "dbs_total": + tdLog.exit("dbs_total is null!") + + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][4]["name"] != "vgroups_total": tdLog.exit("vgroups_total is null!") - if "vgroups_alive" not in infoDict["cluster_info"] or infoDict["cluster_info"]["vgroups_alive"] < 0: + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][5]["name"] != "vgroups_alive": tdLog.exit("vgroups_alive is null!") - if "connections_total" not in infoDict["cluster_info"] or infoDict["cluster_info"]["connections_total"] < 0 : + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][10]["name"] != "connections_total": tdLog.exit("connections_total is null!") - if "dnodes" not in infoDict["cluster_info"] or infoDict["cluster_info"]["dnodes"] == None : - tdLog.exit("dnodes is null!") + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][13]["name"] != "dnodes_total": + tdLog.exit("dnodes_total is null!") - dnodes_info = { "dnode_id": 1,"dnode_ep": self.hostPort,"status":"ready"} - - for k ,v in dnodes_info.items(): - if k not in infoDict["cluster_info"]["dnodes"][0] or v != infoDict["cluster_info"]["dnodes"][0][k] : - tdLog.exit("dnodes info is null!") - - mnodes_info = { "mnode_id":1, "mnode_ep": self.hostPort,"role": "leader" } - - for k ,v in mnodes_info.items(): - if k not in infoDict["cluster_info"]["mnodes"][0] or v != infoDict["cluster_info"]["mnodes"][0][k] : - tdLog.exit("mnodes info is null!") + if infoDict[0]["tables"][4]["name"] != "taosd_vgroups_info": + tdLog.exit("taosd_vgroups_info is null!") # vgroup_infos ==================================== if "vgroup_infos" not in infoDict or infoDict["vgroup_infos"]== None: tdLog.exit("vgroup_infos is null!") - vgroup_infos_nums = len(infoDict["vgroup_infos"]) + vgroup_infos_nums = len(infoDict[0]["tables"][3]["metric_groups"][0]["metrics"]) for index in range(vgroup_infos_nums): - if "vgroup_id" not in infoDict["vgroup_infos"][index] or infoDict["vgroup_infos"][index]["vgroup_id"]<0: - tdLog.exit("vgroup_id is null!") - if "database_name" not in infoDict["vgroup_infos"][index] or len(infoDict["vgroup_infos"][index]["database_name"]) < 0: - tdLog.exit("database_name is null!") - if "tables_num" not in infoDict["vgroup_infos"][index]: + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][0]["metrics"][0]["name"] != "tables_num": tdLog.exit("tables_num is null!") - if "status" not in infoDict["vgroup_infos"][index] or len(infoDict["vgroup_infos"][index]["status"]) < 0 : + + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][0]["metrics"][0]["name"] != "status": tdLog.exit("status is null!") - if "vnodes" not in infoDict["vgroup_infos"][index] or infoDict["vgroup_infos"][index]["vnodes"] ==None : - tdLog.exit("vnodes is null!") - if "dnode_id" not in infoDict["vgroup_infos"][index]["vnodes"][0] or infoDict["vgroup_infos"][index]["vnodes"][0]["dnode_id"] < 0 : - tdLog.exit("vnodes is null!") # grant_info ==================================== From d927e8c31a35f719c66c9bab0f4887839b8fe132 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Fri, 20 Dec 2024 16:50:49 +0800 Subject: [PATCH 19/55] fix:[TD-33272]refactor code --- source/dnode/vnode/src/tq/tqOffset.c | 29 +- source/dnode/vnode/src/tq/tqSnapshot.c | 226 +++++++------- source/libs/parser/src/parInsertSml.c | 391 +++++++++---------------- source/os/src/osString.c | 2 - 4 files changed, 260 insertions(+), 388 deletions(-) diff --git a/source/dnode/vnode/src/tq/tqOffset.c b/source/dnode/vnode/src/tq/tqOffset.c index c42959971b..4d90091701 100644 --- a/source/dnode/vnode/src/tq/tqOffset.c +++ b/source/dnode/vnode/src/tq/tqOffset.c @@ -40,13 +40,11 @@ int32_t tqOffsetRestoreFromFile(STQ* pTq, char* name) { return TSDB_CODE_INVALID_MSG; } int32_t code = TDB_CODE_SUCCESS; + int32_t lino = 0; void* pMemBuf = NULL; TdFilePtr pFile = taosOpenFile(name, TD_FILE_READ); - if (pFile == NULL) { - code = TDB_CODE_SUCCESS; - goto END; - } + TSDB_CHECK_NULL(pFile, code, lino, END, TDB_CODE_SUCCESS); int64_t ret = 0; int32_t size = 0; @@ -60,24 +58,16 @@ int32_t tqOffsetRestoreFromFile(STQ* pTq, char* name) { } total += INT_BYTES; size = htonl(size); - if (size <= 0) { - code = TSDB_CODE_INVALID_MSG; - goto END; - } - pMemBuf = taosMemoryCalloc(1, size); - if (pMemBuf == NULL) { - code = terrno; - goto END; - } + TSDB_CHECK_CONDITION(size > 0, code, lino, END, TSDB_CODE_INVALID_MSG); - if (taosReadFile(pFile, pMemBuf, size) != size) { - terrno = TSDB_CODE_INVALID_MSG; - goto END; - } + pMemBuf = taosMemoryCalloc(1, size); + TSDB_CHECK_NULL(pMemBuf, code, lino, END, terrno); + TSDB_CHECK_CONDITION(taosReadFile(pFile, pMemBuf, size) == size, code, lino, END, TSDB_CODE_INVALID_MSG); total += size; STqOffset offset = {0}; - TQ_ERR_GO_TO_END(tqMetaDecodeOffsetInfo(&offset, pMemBuf, size)); + code = tqMetaDecodeOffsetInfo(&offset, pMemBuf, size); + TSDB_CHECK_CODE(code, lino, END); code = taosHashPut(pTq->pOffset, offset.subKey, strlen(offset.subKey), &offset, sizeof(STqOffset)); if (code != TDB_CODE_SUCCESS) { tDeleteSTqOffset(&offset); @@ -100,6 +90,9 @@ int32_t tqOffsetRestoreFromFile(STQ* pTq, char* name) { } END: + if (code != 0){ + tqError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } taosCloseFile(&pFile); taosMemoryFree(pMemBuf); diff --git a/source/dnode/vnode/src/tq/tqSnapshot.c b/source/dnode/vnode/src/tq/tqSnapshot.c index 219ea4b6b4..ddbbba57a0 100644 --- a/source/dnode/vnode/src/tq/tqSnapshot.c +++ b/source/dnode/vnode/src/tq/tqSnapshot.c @@ -27,18 +27,16 @@ struct STqSnapReader { }; int32_t tqSnapReaderOpen(STQ* pTq, int64_t sver, int64_t ever, int8_t type, STqSnapReader** ppReader) { - if (pTq == NULL || ppReader == NULL) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; STqSnapReader* pReader = NULL; + TSDB_CHECK_NULL(pTq, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(ppReader, code, lino, end, TSDB_CODE_INVALID_MSG); // alloc pReader = (STqSnapReader*)taosMemoryCalloc(1, sizeof(STqSnapReader)); - if (pReader == NULL) { - code = terrno; - goto _err; - } + TSDB_CHECK_NULL(pReader, code, lino, end, terrno); + pReader->pTq = pTq; pReader->sver = sver; pReader->ever = ever; @@ -54,28 +52,21 @@ int32_t tqSnapReaderOpen(STQ* pTq, int64_t sver, int64_t ever, int8_t type, STqS pTb = pTq->pOffsetStore; } else { code = TSDB_CODE_INVALID_MSG; - goto _err; + goto end; } code = tdbTbcOpen(pTb, &pReader->pCur, NULL); - if (code) { - taosMemoryFree(pReader); - goto _err; - } - + TSDB_CHECK_CODE(code, lino, end); code = tdbTbcMoveToFirst(pReader->pCur); - if (code) { - taosMemoryFree(pReader); - goto _err; + TSDB_CHECK_CODE(code, lino, end); + tqInfo("vgId:%d, vnode tq snapshot reader opene success", TD_VID(pTq->pVnode)); + *ppReader = pReader; + +end: + if (code != 0){ + tqError("%s failed at %d, vnode tq snapshot reader open failed since %s", __func__, lino, tstrerror(code)); + taosMemoryFreeClear(pReader); } - tqInfo("vgId:%d, vnode snapshot tq reader opened", TD_VID(pTq->pVnode)); - - *ppReader = pReader; - return code; - -_err: - tqError("vgId:%d, vnode snapshot tq reader open failed since %s", TD_VID(pTq->pVnode), tstrerror(code)); - *ppReader = NULL; return code; } @@ -84,45 +75,37 @@ void tqSnapReaderClose(STqSnapReader** ppReader) { return; } tdbTbcClose((*ppReader)->pCur); - taosMemoryFree(*ppReader); - *ppReader = NULL; + taosMemoryFreeClear(*ppReader); } int32_t tqSnapRead(STqSnapReader* pReader, uint8_t** ppData) { - if (pReader == NULL || ppData == NULL) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; - void* pKey = NULL; - void* pVal = NULL; - int32_t kLen = 0; - int32_t vLen = 0; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + void* pKey = NULL; + void* pVal = NULL; + int32_t kLen = 0; + int32_t vLen = 0; + TSDB_CHECK_NULL(pReader, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(ppData, code, lino, end, TSDB_CODE_INVALID_MSG); - if (tdbTbcNext(pReader->pCur, &pKey, &kLen, &pVal, &vLen)) { - goto _exit; - } + code = tdbTbcNext(pReader->pCur, &pKey, &kLen, &pVal, &vLen); + TSDB_CHECK_CODE(code, lino, end); *ppData = taosMemoryMalloc(sizeof(SSnapDataHdr) + vLen); - if (*ppData == NULL) { - code = TAOS_GET_TERRNO(TSDB_CODE_OUT_OF_MEMORY); - goto _err; - } + TSDB_CHECK_NULL(*ppData, code, lino, end, terrno); SSnapDataHdr* pHdr = (SSnapDataHdr*)(*ppData); pHdr->type = pReader->type; pHdr->size = vLen; (void)memcpy(pHdr->data, pVal, vLen); + tqInfo("vgId:%d, vnode tq snapshot read data, vLen:%d", TD_VID(pReader->pTq->pVnode), vLen); -_exit: +end: + if (code != 0) { + tqError("%s failed at %d, vnode tq snapshot read data failed since %s", __func__, lino, tstrerror(code)); + } tdbFree(pKey); tdbFree(pVal); - tqInfo("vgId:%d, vnode snapshot tq read data, vLen:%d", TD_VID(pReader->pTq->pVnode), vLen); - return code; - -_err: - tdbFree(pKey); - tdbFree(pVal); - tqError("vgId:%d, vnode snapshot tq read data failed since %s", TD_VID(pReader->pTq->pVnode), tstrerror(code)); return code; } @@ -135,135 +118,148 @@ struct STqSnapWriter { }; int32_t tqSnapWriterOpen(STQ* pTq, int64_t sver, int64_t ever, STqSnapWriter** ppWriter) { - if (pTq == NULL || ppWriter == NULL) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; STqSnapWriter* pWriter = NULL; + TSDB_CHECK_NULL(pTq, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(ppWriter, code, lino, end, TSDB_CODE_INVALID_MSG); + // alloc pWriter = (STqSnapWriter*)taosMemoryCalloc(1, sizeof(*pWriter)); - if (pWriter == NULL) { - code = TAOS_GET_TERRNO(TSDB_CODE_OUT_OF_MEMORY); - ; - goto _err; - } + TSDB_CHECK_NULL(pWriter, code, lino, end, terrno); pWriter->pTq = pTq; pWriter->sver = sver; pWriter->ever = ever; code = tdbBegin(pTq->pMetaDB, &pWriter->txn, tdbDefaultMalloc, tdbDefaultFree, NULL, 0); - if (code < 0) { - taosMemoryFree(pWriter); - goto _err; - } - + TSDB_CHECK_CODE(code, lino, end); + tqInfo("vgId:%d, tq snapshot writer opene success", TD_VID(pTq->pVnode)); *ppWriter = pWriter; - return code; -_err: - tqError("vgId:%d, tq snapshot writer open failed since %s", TD_VID(pTq->pVnode), tstrerror(code)); - *ppWriter = NULL; +end: + if (code != 0){ + tqError("%s failed at %d tq snapshot writer open failed since %s", __func__, lino, tstrerror(code)); + taosMemoryFreeClear(pWriter); + } return code; } int32_t tqSnapWriterClose(STqSnapWriter** ppWriter, int8_t rollback) { - if (ppWriter == NULL || *ppWriter == NULL) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; - STqSnapWriter* pWriter = *ppWriter; - STQ* pTq = pWriter->pTq; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + STqSnapWriter* pWriter = NULL; + + TSDB_CHECK_NULL(ppWriter, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(*ppWriter, code, lino, end, TSDB_CODE_INVALID_MSG); + pWriter = *ppWriter; if (rollback) { tdbAbort(pWriter->pTq->pMetaDB, pWriter->txn); } else { code = tdbCommit(pWriter->pTq->pMetaDB, pWriter->txn); - if (code) goto _err; + TSDB_CHECK_CODE(code, lino, end); + code = tdbPostCommit(pWriter->pTq->pMetaDB, pWriter->txn); - if (code) goto _err; + TSDB_CHECK_CODE(code, lino, end); } + tqInfo("vgId:%d, tq snapshot writer close success", TD_VID(pWriter->pTq->pVnode)); + taosMemoryFreeClear(*ppWriter); - taosMemoryFree(pWriter); - *ppWriter = NULL; - - return code; - -_err: - tqError("vgId:%d, tq snapshot writer close failed since %s", TD_VID(pTq->pVnode), tstrerror(code)); +end: + if (code != 0){ + tqError("%s failed at %d, tq snapshot writer close failed since %s", __func__, lino, tstrerror(code)); + } return code; } -int32_t tqSnapHandleWrite(STqSnapWriter* pWriter, uint8_t* pData, uint32_t nData) { - if (pWriter == NULL || pData == NULL || nData < sizeof(SSnapDataHdr)) { - return TSDB_CODE_INVALID_MSG; +static int32_t tqWriteCheck(STqSnapWriter* pWriter, uint8_t* pData, uint32_t nData){ + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + TSDB_CHECK_NULL(pWriter, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(pData, code, lino, end, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_CONDITION(nData >= sizeof(SSnapDataHdr), code, lino, end, TSDB_CODE_INVALID_MSG); +end: + if (code != 0){ + tqError("%s failed at %d failed since %s", __func__, lino, tstrerror(code)); } - int32_t code = 0; - STQ* pTq = pWriter->pTq; + return code; +} +int32_t tqSnapHandleWrite(STqSnapWriter* pWriter, uint8_t* pData, uint32_t nData) { + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; SDecoder decoder = {0}; SDecoder* pDecoder = &decoder; STqHandle handle = {0}; + code = tqWriteCheck(pWriter, pData, nData); + TSDB_CHECK_CODE(code, lino, end); + STQ* pTq = pWriter->pTq; tDecoderInit(pDecoder, pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); code = tDecodeSTqHandle(pDecoder, &handle); - if (code) goto end; + TSDB_CHECK_CODE(code, lino, end); + taosWLockLatch(&pTq->lock); code = tqMetaSaveInfo(pTq, pTq->pExecStore, handle.subKey, strlen(handle.subKey), pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); taosWUnLockLatch(&pTq->lock); + TSDB_CHECK_CODE(code, lino, end); + tqInfo("vgId:%d, vnode tq snapshot write success", TD_VID(pTq->pVnode)); end: tDecoderClear(pDecoder); tqDestroyTqHandle(&handle); - tqInfo("vgId:%d, vnode snapshot tq write result:%d", TD_VID(pTq->pVnode), code); + if (code != 0){ + tqError("%s failed at %d, vnode tq snapshot write failed since %s", __func__, lino, tstrerror(code)); + } return code; } int32_t tqSnapCheckInfoWrite(STqSnapWriter* pWriter, uint8_t* pData, uint32_t nData) { - if (pWriter == NULL || pData == NULL || nData < sizeof(SSnapDataHdr)) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + + code = tqWriteCheck(pWriter, pData, nData); + TSDB_CHECK_CODE(code, lino, end); + STQ* pTq = pWriter->pTq; STqCheckInfo info = {0}; code = tqMetaDecodeCheckInfo(&info, pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); - if (code != 0) { - goto _err; - } + TSDB_CHECK_CODE(code, lino, end); code = tqMetaSaveInfo(pTq, pTq->pCheckStore, &info.topic, strlen(info.topic), pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); tDeleteSTqCheckInfo(&info); - if (code) goto _err; + TSDB_CHECK_CODE(code, lino, end); + tqInfo("vgId:%d, vnode tq check info write success", TD_VID(pTq->pVnode)); - return code; - -_err: - tqError("vgId:%d, vnode check info tq write failed since %s", TD_VID(pTq->pVnode), tstrerror(code)); +end: + if (code != 0){ + tqError("%s failed at %d, vnode tq check info write failed since %s", __func__, lino, tstrerror(code)); + } return code; } int32_t tqSnapOffsetWrite(STqSnapWriter* pWriter, uint8_t* pData, uint32_t nData) { - if (pWriter == NULL || pData == NULL || nData < sizeof(SSnapDataHdr)) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = 0; - STQ* pTq = pWriter->pTq; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + code = tqWriteCheck(pWriter, pData, nData); + TSDB_CHECK_CODE(code, lino, end); + STQ* pTq = pWriter->pTq; STqOffset info = {0}; code = tqMetaDecodeOffsetInfo(&info, pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); - if (code != 0) { - goto _err; - } + TSDB_CHECK_CODE(code, lino, end); code = tqMetaSaveInfo(pTq, pTq->pOffsetStore, info.subKey, strlen(info.subKey), pData + sizeof(SSnapDataHdr), nData - sizeof(SSnapDataHdr)); tDeleteSTqOffset(&info); - if (code) goto _err; + TSDB_CHECK_CODE(code, lino, end); + tqInfo("vgId:%d, vnode tq offset write success", TD_VID(pTq->pVnode)); - return code; - -_err: - tqError("vgId:%d, vnode check info tq write failed since %s", TD_VID(pTq->pVnode), tstrerror(code)); +end: + if (code != 0){ + tqError("%s failed at %d, vnode tq offset write failed since %s", __func__, lino, tstrerror(code)); + } return code; } diff --git a/source/libs/parser/src/parInsertSml.c b/source/libs/parser/src/parInsertSml.c index 22d1f7edda..d56cf7916f 100644 --- a/source/libs/parser/src/parInsertSml.c +++ b/source/libs/parser/src/parInsertSml.c @@ -20,40 +20,32 @@ int32_t qCreateSName(SName* pName, const char* pTableName, int32_t acctId, char* dbName, char* msgBuf, int32_t msgBufLen) { - SMsgBuf msg = {.buf = msgBuf, .len = msgBufLen}; - SToken sToken; - int32_t code = 0; - char* tbName = NULL; + SMsgBuf msg = {.buf = msgBuf, .len = msgBufLen}; + SToken sToken = {0}; + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; NEXT_TOKEN(pTableName, sToken); - - if (sToken.n == 0) { - return buildInvalidOperationMsg(&msg, "empty table name"); - } - + TSDB_CHECK_CONDITION(sToken.n != 0, code, lino, end, TSDB_CODE_TSC_INVALID_OPERATION); code = insCreateSName(pName, &sToken, acctId, dbName, &msg); - if (code) { - return code; - } - + TSDB_CHECK_CODE(code, lino, end); NEXT_TOKEN(pTableName, sToken); + TSDB_CHECK_CONDITION(sToken.n <= 0, code, lino, end, TSDB_CODE_TSC_INVALID_OPERATION); - if (sToken.n > 0) { - return buildInvalidOperationMsg(&msg, "table name format is wrong"); +end: + if (code != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); } - return TSDB_CODE_SUCCESS; } static int32_t smlBoundColumnData(SArray* cols, SBoundColInfo* pBoundInfo, SSchema* pSchema, bool isTag) { + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; bool* pUseCols = taosMemoryCalloc(pBoundInfo->numOfCols, sizeof(bool)); - if (NULL == pUseCols) { - return terrno; - } - + TSDB_CHECK_NULL(pUseCols, code, lino, end, terrno); pBoundInfo->numOfBound = 0; int16_t lastColIdx = -1; // last column found - int32_t code = TSDB_CODE_SUCCESS; for (int i = 0; i < taosArrayGetSize(cols); ++i) { SSmlKv* kv = taosArrayGet(cols, i); @@ -65,16 +57,9 @@ static int32_t smlBoundColumnData(SArray* cols, SBoundColInfo* pBoundInfo, SSche index = insFindCol(&sToken, 0, t, pSchema); } - if (index < 0) { - uError("smlBoundColumnData. index:%d", index); - code = TSDB_CODE_SML_INVALID_DATA; - goto end; - } - if (pUseCols[index]) { - uError("smlBoundColumnData. already set. index:%d", index); - code = TSDB_CODE_SML_INVALID_DATA; - goto end; - } + TSDB_CHECK_CONDITION(index >= 0, code, lino, end, TSDB_CODE_SML_INVALID_DATA); + TSDB_CHECK_CONDITION(!pUseCols[index], code, lino, end, TSDB_CODE_SML_INVALID_DATA); + lastColIdx = index; pUseCols[index] = true; pBoundInfo->pColIndex[pBoundInfo->numOfBound] = index; @@ -82,11 +67,30 @@ static int32_t smlBoundColumnData(SArray* cols, SBoundColInfo* pBoundInfo, SSche } end: + if (code != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } taosMemoryFree(pUseCols); - return code; } +static int32_t smlMbsToUcs4(const char* mbs, size_t mbsLen, void** result, int32_t* resultLen, int32_t maxLen, void* charsetCxt){ + int code = TSDB_CODE_SUCCESS; + void* pUcs4 = NULL; + int32_t lino = 0; + pUcs4 = taosMemoryCalloc(1, maxLen); + TSDB_CHECK_NULL(pUcs4, code, lino, end, terrno); + TSDB_CHECK_CONDITION(taosMbsToUcs4(mbs, mbsLen, (TdUcs4*)pUcs4, maxLen, resultLen, charsetCxt), code, lino, end, terrno); + *result = pUcs4; + pUcs4 = NULL; + +end: + if (code != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } + taosMemoryFree(pUcs4); + return code; +} /** * @brief No json tag for schemaless * @@ -99,75 +103,39 @@ end: */ static int32_t smlBuildTagRow(SArray* cols, SBoundColInfo* tags, SSchema* pSchema, STag** ppTag, SArray** tagName, SMsgBuf* msg, void* charsetCxt) { - SArray* pTagArray = taosArrayInit(tags->numOfBound, sizeof(STagVal)); - if (!pTagArray) { - return terrno; - } + int code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SArray* pTagArray = taosArrayInit(tags->numOfBound, sizeof(STagVal)); + TSDB_CHECK_NULL(pTagArray, code, lino, end, terrno); *tagName = taosArrayInit(8, TSDB_COL_NAME_LEN); - if (!*tagName) { - return terrno; - } + TSDB_CHECK_NULL(*tagName, code, lino, end, terrno); - int32_t code = TSDB_CODE_SUCCESS; for (int i = 0; i < tags->numOfBound; ++i) { SSchema* pTagSchema = &pSchema[tags->pColIndex[i]]; SSmlKv* kv = taosArrayGet(cols, i); - if (kv == NULL){ - code = terrno; - uError("SML smlBuildTagRow error kv is null"); - goto end; - } - if (kv->keyLen != strlen(pTagSchema->name) || memcmp(kv->key, pTagSchema->name, kv->keyLen) != 0 || - kv->type != pTagSchema->type) { - code = TSDB_CODE_SML_INVALID_DATA; - uError("SML smlBuildTagRow error col not same %s", pTagSchema->name); - goto end; - } - - if (taosArrayPush(*tagName, pTagSchema->name) == NULL){ - code = terrno; - uError("SML smlBuildTagRow error push tag name"); - goto end; - } + TSDB_CHECK_NULL(kv, code, lino, end, terrno); + bool cond = (kv->keyLen == strlen(pTagSchema->name) && memcmp(kv->key, pTagSchema->name, kv->keyLen) == 0 && kv->type == pTagSchema->type); + TSDB_CHECK_CONDITION(cond, code, lino, end, TSDB_CODE_SML_INVALID_DATA); + TSDB_CHECK_NULL(taosArrayPush(*tagName, pTagSchema->name), code, lino, end, terrno); STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type}; - // strcpy(val.colName, pTagSchema->name); if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY || pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) { val.pData = (uint8_t*)kv->value; val.nData = kv->length; } else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) { - int32_t output = 0; - void* p = taosMemoryCalloc(1, kv->length * TSDB_NCHAR_SIZE); - if (p == NULL) { - code = terrno; - goto end; - } - if (!taosMbsToUcs4(kv->value, kv->length, (TdUcs4*)(p), kv->length * TSDB_NCHAR_SIZE, &output, charsetCxt)) { - if (terrno == TAOS_SYSTEM_ERROR(E2BIG)) { - taosMemoryFree(p); - code = generateSyntaxErrMsg(msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pTagSchema->name); - goto end; - } - char buf[512] = {0}; - (void)snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(terrno)); - taosMemoryFree(p); - code = buildSyntaxErrMsg(msg, buf, kv->value); - goto end; - } - val.pData = p; - val.nData = output; + code = smlMbsToUcs4(kv->value, kv->length, (void**)&val.pData, &val.nData, kv->length * TSDB_NCHAR_SIZE, charsetCxt); + TSDB_CHECK_CODE(code, lino, end); } else { (void)memcpy(&val.i64, &(kv->value), kv->length); } - if (taosArrayPush(pTagArray, &val) == NULL){ - code = terrno; - uError("SML smlBuildTagRow error push tag array"); - goto end; - } + TSDB_CHECK_NULL(taosArrayPush(pTagArray, &val), code, lino, end, terrno); } - code = tTagNew(pTagArray, 1, false, ppTag); + end: + if (code != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) { STagVal* p = (STagVal*)taosArrayGet(pTagArray, i); if (p->type == TSDB_DATA_TYPE_NCHAR) { @@ -179,18 +147,20 @@ end: } int32_t smlInitTableDataCtx(SQuery* query, STableMeta* pTableMeta, STableDataCxt** cxt) { + int ret = TSDB_CODE_SUCCESS; + int32_t lino = 0; SVCreateTbReq* pCreateTbReq = NULL; - int ret = insGetTableDataCxt(((SVnodeModifyOpStmt*)(query->pRoot))->pTableBlockHashObj, &pTableMeta->uid, + ret = insGetTableDataCxt(((SVnodeModifyOpStmt*)(query->pRoot))->pTableBlockHashObj, &pTableMeta->uid, sizeof(pTableMeta->uid), pTableMeta, &pCreateTbReq, cxt, false, false); - if (ret != TSDB_CODE_SUCCESS) { - return ret; - } - + TSDB_CHECK_CODE(ret, lino, end); ret = initTableColSubmitData(*cxt); - if (ret != TSDB_CODE_SUCCESS) { - return ret; + TSDB_CHECK_CODE(ret, lino, end); + +end: + if (ret != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(ret)); } - return TSDB_CODE_SUCCESS; + return ret; } void clearColValArraySml(SArray* pCols) { @@ -207,78 +177,51 @@ void clearColValArraySml(SArray* pCols) { } int32_t smlBuildRow(STableDataCxt* pTableCxt) { - SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1); - if (pRow == NULL){ - return terrno; - } - int ret = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow); - if (TSDB_CODE_SUCCESS != ret) { - return ret; - } + int ret = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1); + TSDB_CHECK_NULL(pRow, ret, lino, end, terrno); + ret = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow); + TSDB_CHECK_CODE(ret, lino, end); SRowKey key; tRowGetKey(*pRow, &key); insCheckTableDataOrder(pTableCxt, &key); - return TSDB_CODE_SUCCESS; +end: + if (ret != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(ret)); + } + return ret; } int32_t smlBuildCol(STableDataCxt* pTableCxt, SSchema* schema, void* data, int32_t index, void* charsetCxt) { int ret = TSDB_CODE_SUCCESS; + int32_t lino = 0; SSchema* pColSchema = schema + index; SColVal* pVal = taosArrayGet(pTableCxt->pValues, index); - if (pVal == NULL) { - return TSDB_CODE_SUCCESS; - } + TSDB_CHECK_NULL(pVal, ret, lino, end, TSDB_CODE_SUCCESS); SSmlKv* kv = (SSmlKv*)data; if (kv->keyLen != strlen(pColSchema->name) || memcmp(kv->key, pColSchema->name, kv->keyLen) != 0 || kv->type != pColSchema->type) { ret = TSDB_CODE_SML_INVALID_DATA; char* tmp = taosMemoryCalloc(kv->keyLen + 1, 1); - if (tmp) { - (void)memcpy(tmp, kv->key, kv->keyLen); - uInfo("SML data(name:%s type:%s) is not same like the db data(name:%s type:%s)", tmp, tDataTypes[kv->type].name, - pColSchema->name, tDataTypes[pColSchema->type].name); - taosMemoryFree(tmp); - } else { - uError("SML smlBuildCol out of memory"); - ret = terrno; - } + TSDB_CHECK_NULL(tmp, ret, lino, end, terrno); + (void)memcpy(tmp, kv->key, kv->keyLen); + uInfo("SML data(name:%s type:%s) is not same like the db data(name:%s type:%s)", tmp, tDataTypes[kv->type].name, + pColSchema->name, tDataTypes[pColSchema->type].name); + taosMemoryFree(tmp); goto end; } if (kv->type == TSDB_DATA_TYPE_NCHAR) { - int32_t len = 0; - int64_t size = pColSchema->bytes - VARSTR_HEADER_SIZE; - if (size <= 0) { - ret = TSDB_CODE_SML_INVALID_DATA; - goto end; - } - char* pUcs4 = taosMemoryCalloc(1, size); - if (NULL == pUcs4) { - ret = terrno; - goto end; - } - if (!taosMbsToUcs4(kv->value, kv->length, (TdUcs4*)pUcs4, size, &len, charsetCxt)) { - if (terrno == TAOS_SYSTEM_ERROR(E2BIG)) { - taosMemoryFree(pUcs4); - ret = TSDB_CODE_PAR_VALUE_TOO_LONG; - goto end; - } - taosMemoryFree(pUcs4); - ret = TSDB_CODE_TSC_INVALID_VALUE; - goto end; - } - pVal->value.pData = pUcs4; - pVal->value.nData = len; + ret = smlMbsToUcs4(kv->value, kv->length, (void**)&pVal->value.pData, &pVal->value.nData, pColSchema->bytes - VARSTR_HEADER_SIZE, charsetCxt); + TSDB_CHECK_CODE(ret, lino, end); } else if (kv->type == TSDB_DATA_TYPE_BINARY) { pVal->value.nData = kv->length; pVal->value.pData = (uint8_t*)kv->value; } else if (kv->type == TSDB_DATA_TYPE_GEOMETRY || kv->type == TSDB_DATA_TYPE_VARBINARY) { pVal->value.nData = kv->length; pVal->value.pData = taosMemoryMalloc(kv->length); - if (!pVal->value.pData) { - ret = terrno; - uError("SML smlBuildCol malloc failed %s:%d, err: %s", __func__, __LINE__, tstrerror(ret)); - goto end; - } + TSDB_CHECK_NULL(pVal->value.pData, ret, lino, end, terrno); + (void)memcpy(pVal->value.pData, (uint8_t*)kv->value, kv->length); } else { (void)memcpy(&pVal->value.val, &(kv->value), kv->length); @@ -286,12 +229,17 @@ int32_t smlBuildCol(STableDataCxt* pTableCxt, SSchema* schema, void* data, int32 pVal->flag = CV_FLAG_VALUE; end: + if (ret != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(ret)); + } return ret; } int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSchema, SArray* cols, STableMeta* pTableMeta, char* tableName, const char* sTableName, int32_t sTableNameLen, int32_t ttl, char* msgBuf, int32_t msgBufLen, void* charsetCxt) { + int32_t lino = 0; + int32_t ret = 0; SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; SSchema* pTagsSchema = getTableTagSchema(pTableMeta); @@ -299,50 +247,32 @@ int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSc SVCreateTbReq* pCreateTblReq = NULL; SArray* tagName = NULL; - int ret = insInitBoundColsInfo(getNumOfTags(pTableMeta), &bindTags); - if (ret != TSDB_CODE_SUCCESS) { - ret = buildInvalidOperationMsg(&pBuf, "init bound cols error"); - goto end; - } + ret = insInitBoundColsInfo(getNumOfTags(pTableMeta), &bindTags); + TSDB_CHECK_CODE(ret, lino, end); ret = smlBoundColumnData(tags, &bindTags, pTagsSchema, true); - if (ret != TSDB_CODE_SUCCESS) { - ret = buildInvalidOperationMsg(&pBuf, "bound tags error"); - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); STag* pTag = NULL; - ret = smlBuildTagRow(tags, &bindTags, pTagsSchema, &pTag, &tagName, &pBuf, charsetCxt); - if (ret != TSDB_CODE_SUCCESS) { - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); pCreateTblReq = taosMemoryCalloc(1, sizeof(SVCreateTbReq)); - if (NULL == pCreateTblReq) { - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(pCreateTblReq, ret, lino, end, terrno); + ret = insBuildCreateTbReq(pCreateTblReq, tableName, pTag, pTableMeta->suid, NULL, tagName, pTableMeta->tableInfo.numOfTags, ttl); - if (TSDB_CODE_SUCCESS != ret) { - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); pCreateTblReq->ctb.stbName = taosMemoryCalloc(1, sTableNameLen + 1); - if (pCreateTblReq->ctb.stbName == NULL){ - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(pCreateTblReq->ctb.stbName, ret, lino, end, terrno); + (void)memcpy(pCreateTblReq->ctb.stbName, sTableName, sTableNameLen); if (dataFormat) { STableDataCxt** pTableCxt = (STableDataCxt**)taosHashGet(((SVnodeModifyOpStmt*)(query->pRoot))->pTableBlockHashObj, &pTableMeta->uid, sizeof(pTableMeta->uid)); - if (NULL == pTableCxt) { - ret = buildInvalidOperationMsg(&pBuf, "dataformat true. get tableDataCtx error"); - goto end; - } + TSDB_CHECK_NULL(pTableCxt, ret, lino, end, TSDB_CODE_TSC_INVALID_OPERATION); (*pTableCxt)->pData->flags |= SUBMIT_REQ_AUTO_CREATE_TABLE; (*pTableCxt)->pData->pCreateTbReq = pCreateTblReq; (*pTableCxt)->pMeta->uid = pTableMeta->uid; @@ -354,86 +284,47 @@ int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSc STableDataCxt* pTableCxt = NULL; ret = insGetTableDataCxt(((SVnodeModifyOpStmt*)(query->pRoot))->pTableBlockHashObj, &pTableMeta->uid, sizeof(pTableMeta->uid), pTableMeta, &pCreateTblReq, &pTableCxt, false, false); - if (ret != TSDB_CODE_SUCCESS) { - ret = buildInvalidOperationMsg(&pBuf, "insGetTableDataCxt error"); - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); SSchema* pSchema = getTableColumnSchema(pTableMeta); ret = smlBoundColumnData(colsSchema, &pTableCxt->boundColsInfo, pSchema, false); - if (ret != TSDB_CODE_SUCCESS) { - ret = buildInvalidOperationMsg(&pBuf, "bound cols error"); - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); ret = initTableColSubmitData(pTableCxt); - if (ret != TSDB_CODE_SUCCESS) { - ret = buildInvalidOperationMsg(&pBuf, "initTableColSubmitData error"); - goto end; - } + TSDB_CHECK_CODE(ret, lino, end); int32_t rowNum = taosArrayGetSize(cols); - if (rowNum <= 0) { - ret = buildInvalidOperationMsg(&pBuf, "cols size <= 0"); - goto end; - } + TSDB_CHECK_CONDITION(rowNum > 0, ret, lino, end, TSDB_CODE_TSC_INVALID_OPERATION); for (int32_t r = 0; r < rowNum; ++r) { void* rowData = taosArrayGetP(cols, r); - if (rowData == NULL) { - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(rowData, ret, lino, end, terrno); + // 1. set the parsed value from sql string for (int c = 0; c < pTableCxt->boundColsInfo.numOfBound; ++c) { SSchema* pColSchema = &pSchema[pTableCxt->boundColsInfo.pColIndex[c]]; SColVal* pVal = taosArrayGet(pTableCxt->pValues, pTableCxt->boundColsInfo.pColIndex[c]); - if (pVal == NULL) { - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(pVal, ret, lino, end, terrno); void** p = taosHashGet(rowData, pColSchema->name, strlen(pColSchema->name)); if (p == NULL) { continue; } SSmlKv* kv = *(SSmlKv**)p; - if (kv->type != pColSchema->type) { - ret = buildInvalidOperationMsg(&pBuf, "kv type not equal to col type"); - goto end; - } + TSDB_CHECK_CONDITION(kv->type == pColSchema->type, ret, lino, end, TSDB_CODE_TSC_INVALID_OPERATION); + if (pColSchema->type == TSDB_DATA_TYPE_TIMESTAMP) { kv->i = convertTimePrecision(kv->i, TSDB_TIME_PRECISION_NANO, pTableMeta->tableInfo.precision); } if (kv->type == TSDB_DATA_TYPE_NCHAR) { - int32_t len = 0; - char* pUcs4 = taosMemoryCalloc(1, pColSchema->bytes - VARSTR_HEADER_SIZE); - if (NULL == pUcs4) { - ret = terrno; - goto end; - } - if (!taosMbsToUcs4(kv->value, kv->length, (TdUcs4*)pUcs4, pColSchema->bytes - VARSTR_HEADER_SIZE, &len, charsetCxt)) { - if (terrno == TAOS_SYSTEM_ERROR(E2BIG)) { - uError("sml bind taosMbsToUcs4 error, kv length:%d, bytes:%d, kv->value:%s", (int)kv->length, - pColSchema->bytes, kv->value); - (void)buildInvalidOperationMsg(&pBuf, "value too long"); - ret = TSDB_CODE_PAR_VALUE_TOO_LONG; - goto end; - } - ret = buildInvalidOperationMsg(&pBuf, strerror(terrno)); - goto end; - } - pVal->value.pData = pUcs4; - pVal->value.nData = len; + ret = smlMbsToUcs4(kv->value, kv->length, (void**)&pVal->value.pData, &pVal->value.nData, pColSchema->bytes - VARSTR_HEADER_SIZE, charsetCxt); + TSDB_CHECK_CODE(ret, lino, end); } else if (kv->type == TSDB_DATA_TYPE_BINARY) { pVal->value.nData = kv->length; pVal->value.pData = (uint8_t*)kv->value; } else if (kv->type == TSDB_DATA_TYPE_GEOMETRY || kv->type == TSDB_DATA_TYPE_VARBINARY) { pVal->value.nData = kv->length; pVal->value.pData = taosMemoryMalloc(kv->length); - if (NULL == pVal->value.pData) { - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(pVal->value.pData, ret, lino, end, terrno); (void)memcpy(pVal->value.pData, (uint8_t*)kv->value, kv->length); } else { (void)memcpy(&pVal->value.val, &(kv->value), kv->length); @@ -442,22 +333,20 @@ int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSc } SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1); - if (NULL == pRow) { - ret = terrno; - goto end; - } + TSDB_CHECK_NULL(pRow, ret, lino, end, terrno); ret = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow); - if (TSDB_CODE_SUCCESS != ret) { - ret = buildInvalidOperationMsg(&pBuf, "tRowBuild error"); - goto end; - } - SRowKey key; + TSDB_CHECK_CODE(ret, lino, end); + SRowKey key = {0}; tRowGetKey(*pRow, &key); insCheckTableDataOrder(pTableCxt, &key); clearColValArraySml(pTableCxt->pValues); } end: + if (ret != 0){ + uError("%s failed at %d since %s", __func__, lino, tstrerror(ret)); + buildInvalidOperationMsg(&pBuf, tstrerror(ret)); + } insDestroyBoundColInfo(&bindTags); tdDestroySVCreateTbReq(pCreateTblReq); taosMemoryFree(pCreateTblReq); @@ -466,29 +355,21 @@ end: } int32_t smlInitHandle(SQuery** query) { + int32_t lino = 0; + int32_t code = 0; *query = NULL; SQuery* pQuery = NULL; SVnodeModifyOpStmt* stmt = NULL; - int32_t code = nodesMakeNode(QUERY_NODE_QUERY, (SNode**)&pQuery); - if (code != 0) { - uError("SML create pQuery error"); - goto END; - } + code = nodesMakeNode(QUERY_NODE_QUERY, (SNode**)&pQuery); + TSDB_CHECK_CODE(code, lino, end); pQuery->execMode = QUERY_EXEC_MODE_SCHEDULE; pQuery->haveResultSet = false; pQuery->msgType = TDMT_VND_SUBMIT; code = nodesMakeNode(QUERY_NODE_VNODE_MODIFY_STMT, (SNode**)&stmt); - if (code != 0) { - uError("SML create SVnodeModifyOpStmt error"); - goto END; - } + TSDB_CHECK_CODE(code, lino, end); stmt->pTableBlockHashObj = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_NO_LOCK); - if (stmt->pTableBlockHashObj == NULL){ - uError("SML create pTableBlockHashObj error"); - code = terrno; - goto END; - } + TSDB_CHECK_NULL(stmt->pTableBlockHashObj, code, lino, end, terrno); stmt->freeHashFunc = insDestroyTableDataCxtHashMap; stmt->freeArrayFunc = insDestroyVgroupDataCxtList; @@ -496,24 +377,28 @@ int32_t smlInitHandle(SQuery** query) { *query = pQuery; return code; -END: +end: + if (code != 0) { + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } nodesDestroyNode((SNode*)stmt); qDestroyQuery(pQuery); return code; } int32_t smlBuildOutput(SQuery* handle, SHashObj* pVgHash) { + int32_t lino = 0; + int32_t code = 0; + SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)(handle)->pRoot; - // merge according to vgId - int32_t code = insMergeTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pVgDataBlocks, true); - if (code != TSDB_CODE_SUCCESS) { - uError("insMergeTableDataCxt failed"); - return code; - } + code = insMergeTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pVgDataBlocks, true); + TSDB_CHECK_CODE(code, lino, end); code = insBuildVgDataBlocks(pVgHash, pStmt->pVgDataBlocks, &pStmt->pDataBlocks, false); - if (code != TSDB_CODE_SUCCESS) { - uError("insBuildVgDataBlocks failed"); - return code; + TSDB_CHECK_CODE(code, lino, end); + +end: + if (code != 0) { + uError("%s failed at %d since %s", __func__, lino, tstrerror(code)); } return code; } diff --git a/source/os/src/osString.c b/source/os/src/osString.c index 380e9f84d3..1d07b64c70 100644 --- a/source/os/src/osString.c +++ b/source/os/src/osString.c @@ -405,8 +405,6 @@ bool taosMbsToUcs4(const char *mbs, size_t mbsLength, TdUcs4 *ucs4, int32_t ucs4 size_t ucs4_input_len = mbsLength; size_t outLeft = ucs4_max_len; if (iconv(conv, (char **)&mbs, &ucs4_input_len, (char **)&ucs4, &outLeft) == -1) { - char buf[512] = {0}; - snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s %d %d", strerror(terrno), errno, EILSEQ); terrno = TAOS_SYSTEM_ERROR(errno); taosReleaseConv(idx, conv, M2C, charsetCxt); return false; From a360b71f7c7919ef39debf6e962cb2ac1616c12c Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Fri, 20 Dec 2024 16:57:17 +0800 Subject: [PATCH 20/55] enh: udf exception test case --- source/libs/function/CMakeLists.txt | 44 ++++++++++ source/libs/function/test/change_udf.c | 108 +++++++++++++++++++++++++ tests/pytest/util/tserror.py | 10 +++ tests/system-test/0-others/udfTest.py | 97 ++++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 source/libs/function/test/change_udf.c create mode 100644 tests/pytest/util/tserror.py diff --git a/source/libs/function/CMakeLists.txt b/source/libs/function/CMakeLists.txt index 6891653981..fad0a749d5 100644 --- a/source/libs/function/CMakeLists.txt +++ b/source/libs/function/CMakeLists.txt @@ -142,6 +142,50 @@ target_link_libraries( udf2_dup PUBLIC os ${LINK_JEMALLOC} ) +set(TARGET_NAMES + change_udf_normal + change_udf_no_init + change_udf_no_process + change_udf_no_destroy + change_udf_init_failed + change_udf_process_failed + change_udf_destory_failed +) + +set(COMPILE_DEFINITIONS + CHANGE_UDF_NORMAL + CHANGE_UDF_NO_INIT + CHANGE_UDF_NO_PROCESS + CHANGE_UDF_NO_DESTROY + CHANGE_UDF_INIT_FAILED + CHANGE_UDF_PROCESS_FAILED + CHANGE_UDF_DESTORY_FAILED +) + +foreach(index RANGE 0 6) + list(GET TARGET_NAMES ${index} target_name) + list(GET COMPILE_DEFINITIONS ${index} compile_def) + + add_library(${target_name} STATIC MODULE test/change_udf.c) + target_include_directories( + ${target_name} + PUBLIC + "${TD_SOURCE_DIR}/include/libs/function" + "${TD_SOURCE_DIR}/include/util" + "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/client" + "${TD_SOURCE_DIR}/include/os" + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" + ) + target_compile_definitions(${target_name} PRIVATE ${compile_def}) + IF(TD_LINUX_64 AND JEMALLOC_ENABLED) + ADD_DEPENDENCIES(${target_name} jemalloc) + ENDIF() + target_link_libraries( + ${target_name} PUBLIC os ${LINK_JEMALLOC} + ) +endforeach() + # SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/bin) add_executable(udfd src/udfd.c) diff --git a/source/libs/function/test/change_udf.c b/source/libs/function/test/change_udf.c new file mode 100644 index 0000000000..822c4da892 --- /dev/null +++ b/source/libs/function/test/change_udf.c @@ -0,0 +1,108 @@ +#include +#include +#include +#ifdef LINUX +#include +#endif +#ifdef WINDOWS +#include +#endif +#include "taosudf.h" + +// rename function name +#ifdef CHANGE_UDF_NORMAL +#define UDFNAME change_udf_normal +#define UDFNAMEINIT change_udf_normal_init +#define UDFNAMEDESTROY change_udf_normal_destroy +#elif defined(CHANGE_UDF_NO_INIT) +#define UDFNAME change_udf_no_init +#define UDFNAMEINIT change_udf_no_init_init +#define UDFNAMEDESTROY change_udf_no_init_destroy +#elif defined(CHANGE_UDF_NO_PROCESS) +#define UDFNAME change_udf_no_process +#define UDFNAMEINIT change_udf_no_process_init +#define UDFNAMEDESTROY change_udf_no_process_destroy +#elif defined(CHANGE_UDF_NO_DESTROY) +#define UDFNAME change_udf_no_destroy +#define UDFNAMEINIT change_udf_no_destroy_init +#define UDFNAMEDESTROY change_udf_no_destroy_destroy +#elif defined(CHANGE_UDF_INIT_FAILED) +#define UDFNAME change_udf_init_failed +#define UDFNAMEINIT change_udf_init_failed_init +#define UDFNAMEDESTROY change_udf_init_failed_destroy +#elif defined(CHANGE_UDF_PROCESS_FAILED) +#define UDFNAME change_udf_process_failed +#define UDFNAMEINIT change_udf_process_failed_init +#define UDFNAMEDESTROY change_udf_process_failed_destroy +#elif defined(CHANGE_UDF_DESTORY_FAILED) +#define UDFNAME change_udf_destory_failed +#define UDFNAMEINIT change_udf_destory_failed_init +#define UDFNAMEDESTROY change_udf_destory_failed_destroy +#else +#define UDFNAME change_udf_normal +#define UDFNAMEINIT change_udf_normal_init +#define UDFNAMEDESTROY change_udf_normal_destroy +#endif + + +#ifdef CHANGE_UDF_NO_INIT +#else +DLL_EXPORT int32_t UDFNAMEINIT() { + #ifdef CHANGE_UDF_INIT_FAILED + return -1; + #else + return 0; + #endif // ifdef CHANGE_UDF_INIT_FAILED +} +#endif // ifdef CHANGE_UDF_NO_INIT + +#ifdef CHANGE_UDF_NO_DESTROY +#else +DLL_EXPORT int32_t UDFNAMEDESTROY() { + #ifdef CHANGE_UDF_DESTORY_FAILED + return -1; + #else + return 0; + #endif // ifdef CHANGE_UDF_DESTORY_FAILED + } +#endif // ifdef CHANGE_UDF_NO_DESTROY + +#ifdef CHANGE_UDF_NO_PROCESS +#else +DLL_EXPORT int32_t UDFNAME(SUdfDataBlock *block, SUdfColumn *resultCol) { + #ifdef CHANGE_UDF_PROCESS_FAILED + return -1; + #else + int32_t code = 0; + SUdfColumnData *resultData = &resultCol->colData; + for (int32_t i = 0; i < block->numOfRows; ++i) { + int j = 0; + for (; j < block->numOfCols; ++j) { + if (udfColDataIsNull(block->udfCols[j], i)) { + code = udfColDataSetNull(resultCol, i); + if (code != 0) { + return code; + } + break; + } + } + if (j == block->numOfCols) { + int32_t luckyNum = 1; + code = udfColDataSet(resultCol, i, (char *)&luckyNum, false); + if (code != 0) { + return code; + } + } + } + // to simulate actual processing delay by udf +#ifdef LINUX + usleep(1 * 1000); // usleep takes sleep time in us (1 millionth of a second) +#endif // ifdef LINUX +#ifdef WINDOWS + Sleep(1); +#endif // ifdef WINDOWS + resultData->numOfRows = block->numOfRows; + return 0; + #endif // ifdef CHANGE_UDF_PROCESS_FAILED +} +#endif // ifdef CHANGE_UDF_NO_PROCESS diff --git a/tests/pytest/util/tserror.py b/tests/pytest/util/tserror.py new file mode 100644 index 0000000000..c0f658209c --- /dev/null +++ b/tests/pytest/util/tserror.py @@ -0,0 +1,10 @@ +import ctypes + +TAOS_SYSTEM_ERROR = ctypes.c_int32(0x80ff0000).value +TAOS_DEF_ERROR_CODE = ctypes.c_int32(0x80000000).value + + +TSDB_CODE_MND_FUNC_NOT_EXIST = (TAOS_DEF_ERROR_CODE | 0x0374) + + +TSDB_CODE_UDF_FUNC_EXEC_FAILURE = (TAOS_DEF_ERROR_CODE | 0x290A) diff --git a/tests/system-test/0-others/udfTest.py b/tests/system-test/0-others/udfTest.py index d3efa61e04..9bc7d4360c 100644 --- a/tests/system-test/0-others/udfTest.py +++ b/tests/system-test/0-others/udfTest.py @@ -11,6 +11,7 @@ from util.log import * from util.sql import * from util.cases import * from util.dnodes import * +from util.tserror import * import subprocess class TDTestCase: @@ -56,8 +57,32 @@ class TDTestCase: else: self.libudf1 = subprocess.Popen('find %s -name "libudf1.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") self.libudf2 = subprocess.Popen('find %s -name "libudf2.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_no_init = subprocess.Popen('find %s -name "libchange_udf_no_init.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_no_process = subprocess.Popen('find %s -name "libchange_udf_no_process.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_no_destroy = subprocess.Popen('find %s -name "libchange_udf_no_destroy.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_init_failed = subprocess.Popen('find %s -name "libchange_udf_init_failed.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_process_failed = subprocess.Popen('find %s -name "libchange_udf_process_failed.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_destroy_failed = subprocess.Popen('find %s -name "libchange_udf_destory_failed.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libchange_udf_normal = subprocess.Popen('find %s -name "libchange_udf_normal.so"|grep lib|head -n1'%projPath , shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().decode("utf-8") + self.libudf1 = self.libudf1.replace('\r','').replace('\n','') self.libudf2 = self.libudf2.replace('\r','').replace('\n','') + self.libchange_udf_no_init = self.libchange_udf_no_init.replace('\r','').replace('\n','') + self.libchange_udf_no_process = self.libchange_udf_no_process.replace('\r','').replace('\n','') + self.libchange_udf_normal = self.libchange_udf_normal.replace('\r','').replace('\n','') + self.libchange_udf_no_destroy = self.libchange_udf_no_destroy.replace('\r','').replace('\n','') + self.libchange_udf_init_failed = self.libchange_udf_init_failed.replace('\r','').replace('\n','') + self.libchange_udf_process_failed = self.libchange_udf_process_failed.replace('\r','').replace('\n','') + self.libchange_udf_destroy_failed = self.libchange_udf_destroy_failed.replace('\r','').replace('\n','') + tdLog.info(f"udf1 so path is {self.libudf1}") + tdLog.info(f"udf2 so path is {self.libudf2}") + tdLog.info(f"change_udf_no_init so path is {self.libchange_udf_no_init}") + tdLog.info(f"change_udf_no_process so path is {self.libchange_udf_no_process}") + tdLog.info(f"change_udf_no_destroy so path is {self.libchange_udf_no_destroy}") + tdLog.info(f"change_udf_init_failed so path is {self.libchange_udf_init_failed}") + tdLog.info(f"change_udf_process_failed so path is {self.libchange_udf_process_failed}") + tdLog.info(f"change_udf_destroy_failed so path is {self.libchange_udf_destroy_failed}") + tdLog.info(f"change_udf_normal so path is {self.libchange_udf_normal}") def prepare_data(self): @@ -664,12 +689,84 @@ class TDTestCase: path = ''.join(random.choice(letters) for i in range(5000)) os.system(f"udfd -c {path}") + + def test_change_udf_normal(self, func_name): + # create function with normal file + tdSql.execute(f"create function {func_name} as '%s' outputtype int"%self.libchange_udf_normal) + functions = tdSql.getResult("show functions") + for function in functions: + if f"{func_name}" in function[0]: + tdLog.info(f"create {func_name} functions success, using {self.libchange_udf_normal}") + break + tdSql.query(f"select num1 , {func_name}(num1) ,num2 ,{func_name}(num2),num3 ,{func_name}(num3),num4 ,{func_name}(num4) from db.tb", TSDB_CODE_UDF_FUNC_EXEC_FAILURE) + tdSql.checkData(0,0,None) + tdSql.checkData(0,1,None) + tdSql.checkData(0,2,1) + tdSql.checkData(0,3,1) + tdSql.checkData(0,4,1.000000000) + tdSql.checkData(0,5,1) + tdSql.checkData(0,6,"binary1") + tdSql.checkData(0,7,1) + tdSql.query(f"select {func_name}(num1) from db.tb", TSDB_CODE_UDF_FUNC_EXEC_FAILURE) + tdSql.execute(f"drop function {func_name}") + tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) + tdLog.info(f"change udf test finished, using {self.libchange_udf_normal}") + + def test_change_udf_failed(self, func_name, lib_name): + tdLog.info(f"test change udf start: using {lib_name}") + tdSql.error(f"select num1 , {func_name}(num1) ,num2 ,{func_name}(num2),num3 ,{func_name}(num3),num4 ,{func_name}(num4) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) + tdSql.execute(f"create function {func_name} as '{lib_name}' outputtype int") + functions = tdSql.getResult("show functions") + for function in functions: + if f"{func_name}" in function[0]: + tdLog.info(f"create {func_name} functions success, using {lib_name}") + break + + tdSql.error(f"select num1 , {func_name}(num1) ,num2 ,{func_name}(num2),num3 ,{func_name}(num3),num4 ,{func_name}(num4) from db.tb", TSDB_CODE_UDF_FUNC_EXEC_FAILURE) + tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_UDF_FUNC_EXEC_FAILURE) + tdSql.execute(f"drop function {func_name}") + tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) + tdLog.info(f"change udf test finished, using {lib_name}") + + def unexpected_using_test(self): + tdSql.execute("use db ") + + # create function without wrong file path + tdSql.error("create function udf1 as '%s_wrongpath' outputtype int;"%self.libudf1, TAOS_SYSTEM_ERROR|2) + tdSql.error("create aggregate function udf2 as '%s_wrongpath' outputtype double;"%self.libudf2, TAOS_SYSTEM_ERROR|2) + + tdSql.execute("create function udf1 as '%s' outputtype int;"%self.libudf1) + tdSql.query("select num1 , udf1(num1) ,num2 ,udf1(num2),num3 ,udf1(num3),num4 ,udf1(num4) from tb") + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("change_udf_no_init", self.libchange_udf_no_init) + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("change_udf_no_process", self.libchange_udf_no_process) + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("change_udf_no_destroy", self.libchange_udf_no_destroy) + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("change_udf_init_failed", self.libchange_udf_init_failed) + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("change_udf_process_failed", self.libchange_udf_process_failed) + + self.test_change_udf_normal("change_udf_normal") + self.test_change_udf_failed("libchange_udf_destroy_failed", self.libchange_udf_destroy_failed) + + tdSql.query("select num1 , udf1(num1) ,num2 ,udf1(num2),num3 ,udf1(num3),num4 ,udf1(num4) from tb") + tdSql.execute(f"drop function udf1") + tdSql.error("select num1 , udf1(num1) ,num2 ,udf1(num2),num3 ,udf1(num3),num4 ,udf1(num4) from tb", TSDB_CODE_MND_FUNC_NOT_EXIST) def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring print(" env is ok for all ") self.test_udfd_cmd() self.prepare_udf_so() self.prepare_data() + + self.unexpected_using_test() self.create_udf_function() self.basic_udf_query() self.loop_kill_udfd() From e98e21553519a48a907a322edc5adbe0e9372e5d Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Sun, 22 Dec 2024 11:16:06 +0800 Subject: [PATCH 21/55] 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 65f7cd772f..6474a1ab30 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 4f71d4a3f52379a09dc145f3462f52474810fe4a Mon Sep 17 00:00:00 2001 From: Jinqing Kuang Date: Sat, 21 Dec 2024 19:09:01 +0800 Subject: [PATCH 22/55] enh(query)[TD-33268]. add unit tests to increase test coverage --- source/dnode/vnode/src/tsdb/tsdbRead2.c | 1 - source/libs/executor/test/CMakeLists.txt | 12 + source/libs/executor/test/execUtilTests.cpp | 35 +++ source/util/src/tdecompressavx.c | 230 ++++++-------------- source/util/test/CMakeLists.txt | 14 ++ source/util/test/utilTests.cpp | 65 ++++++ 6 files changed, 189 insertions(+), 168 deletions(-) create mode 100644 source/libs/executor/test/execUtilTests.cpp diff --git a/source/dnode/vnode/src/tsdb/tsdbRead2.c b/source/dnode/vnode/src/tsdb/tsdbRead2.c index 05ae4be74b..a9f3893b96 100644 --- a/source/dnode/vnode/src/tsdb/tsdbRead2.c +++ b/source/dnode/vnode/src/tsdb/tsdbRead2.c @@ -5791,7 +5791,6 @@ int32_t tsdbReaderSuspend2(STsdbReader* pReader) { // make sure only release once void* p = pReader->pReadSnap; - TSDB_CHECK_NULL(p, code, lino, _end, TSDB_CODE_INVALID_PARA); if ((p == atomic_val_compare_exchange_ptr((void**)&pReader->pReadSnap, p, NULL)) && (p != NULL)) { tsdbUntakeReadSnap2(pReader, p, false); pReader->pReadSnap = NULL; diff --git a/source/libs/executor/test/CMakeLists.txt b/source/libs/executor/test/CMakeLists.txt index cb1f951c94..4136640847 100644 --- a/source/libs/executor/test/CMakeLists.txt +++ b/source/libs/executor/test/CMakeLists.txt @@ -44,3 +44,15 @@ TARGET_INCLUDE_DIRECTORIES( PUBLIC "${TD_SOURCE_DIR}/include/common" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../inc" ) + +ADD_EXECUTABLE(execUtilTests execUtilTests.cpp) +TARGET_LINK_LIBRARIES( + execUtilTests + PRIVATE os util common executor gtest_main qcom function planner scalar nodes vnode +) + +TARGET_INCLUDE_DIRECTORIES( + execUtilTests + PUBLIC "${TD_SOURCE_DIR}/include/common" + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../inc" +) diff --git a/source/libs/executor/test/execUtilTests.cpp b/source/libs/executor/test/execUtilTests.cpp new file mode 100644 index 0000000000..61b69fb9cf --- /dev/null +++ b/source/libs/executor/test/execUtilTests.cpp @@ -0,0 +1,35 @@ +#include "gtest/gtest.h" + +#include "executil.h" + +TEST(execUtilTest, resRowTest) { + SDiskbasedBuf *pBuf = nullptr; + int32_t pageSize = 32; + int32_t numPages = 3; + int32_t code = createDiskbasedBuf(&pBuf, pageSize, pageSize * numPages, "test_buf", "/"); + EXPECT_EQ(code, TSDB_CODE_SUCCESS); + + std::vector pages(numPages); + std::vector pageIds(numPages); + for (int32_t i = 0; i < numPages; ++i) { + pages[i] = getNewBufPage(pBuf, &pageIds[i]); + EXPECT_NE(pages[i], nullptr); + EXPECT_EQ(pageIds[i], i); + } + + EXPECT_EQ(getNewBufPage(pBuf, nullptr), nullptr); + + SResultRowPosition pos; + pos.offset = 0; + for (int32_t i = 0; i < numPages; ++i) { + pos.pageId = pageIds[i]; + bool forUpdate = i & 0x1; + SResultRow *row = getResultRowByPos(pBuf, &pos, forUpdate); + EXPECT_EQ((void *)row, pages[i]); + } + + pos.pageId = numPages + 1; + EXPECT_EQ(getResultRowByPos(pBuf, &pos, true), nullptr); + + destroyDiskbasedBuf(pBuf); +} diff --git a/source/util/src/tdecompressavx.c b/source/util/src/tdecompressavx.c index 143867b783..5077950c5d 100644 --- a/source/util/src/tdecompressavx.c +++ b/source/util/src/tdecompressavx.c @@ -22,7 +22,7 @@ char tsSIMDEnable = 0; #endif int32_t tsDecompressIntImpl_Hw(const char *const input, const int32_t nelements, char *const output, const char type) { -#ifdef __AVX2__ +#ifdef __AVX512F__ int32_t word_length = getWordLength(type); // Selector value: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @@ -53,183 +53,79 @@ int32_t tsDecompressIntImpl_Hw(const char *const input, const int32_t nelements, int32_t gRemainder = (nelements - _pos); int32_t num = (gRemainder > elems) ? elems : gRemainder; - int32_t batch = 0; - int32_t remain = 0; - if (tsSIMDEnable && tsAVX512Supported && tsAVX512Enable) { -#ifdef __AVX512F__ - batch = num >> 3; - remain = num & 0x07; -#endif - } else if (tsSIMDEnable && tsAVX2Supported) { -#ifdef __AVX2__ - batch = num >> 2; - remain = num & 0x03; -#endif - } + int32_t batch = num >> 3; + int32_t remain = num & 0x07; if (selector == 0 || selector == 1) { - if (tsSIMDEnable && tsAVX512Supported && tsAVX512Enable) { -#ifdef __AVX512F__ - for (int32_t i = 0; i < batch; ++i) { - __m512i prev = _mm512_set1_epi64(prevValue); - _mm512_storeu_si512((__m512i *)&p[_pos], prev); - _pos += 8; // handle 64bit x 8 = 512bit - } - for (int32_t i = 0; i < remain; ++i) { - p[_pos++] = prevValue; - } -#endif - } else if (tsSIMDEnable && tsAVX2Supported) { - for (int32_t i = 0; i < batch; ++i) { - __m256i prev = _mm256_set1_epi64x(prevValue); - _mm256_storeu_si256((__m256i *)&p[_pos], prev); - _pos += 4; - } - - for (int32_t i = 0; i < remain; ++i) { - p[_pos++] = prevValue; - } - - } else { // alternative implementation without SIMD instructions. - for (int32_t i = 0; i < elems && count < nelements; i++, count++) { - p[_pos++] = prevValue; - v += bit; - } + for (int32_t i = 0; i < batch; ++i) { + __m512i prev = _mm512_set1_epi64(prevValue); + _mm512_storeu_si512((__m512i *)&p[_pos], prev); + _pos += 8; // handle 64bit x 8 = 512bit + } + for (int32_t i = 0; i < remain; ++i) { + p[_pos++] = prevValue; } } else { - if (tsSIMDEnable && tsAVX512Supported && tsAVX512Enable) { -#ifdef __AVX512F__ - __m512i sum_mask1 = _mm512_set_epi64(6, 6, 4, 4, 2, 2, 0, 0); - __m512i sum_mask2 = _mm512_set_epi64(5, 5, 5, 5, 1, 1, 1, 1); - __m512i sum_mask3 = _mm512_set_epi64(3, 3, 3, 3, 3, 3, 3, 3); - __m512i base = _mm512_set1_epi64(w); - __m512i maskVal = _mm512_set1_epi64(mask); - __m512i shiftBits = _mm512_set_epi64(bit * 7 + 4, bit * 6 + 4, bit * 5 + 4, bit * 4 + 4, bit * 3 + 4, - bit * 2 + 4, bit + 4, 4); - __m512i inc = _mm512_set1_epi64(bit << 3); + __m512i sum_mask1 = _mm512_set_epi64(6, 6, 4, 4, 2, 2, 0, 0); + __m512i sum_mask2 = _mm512_set_epi64(5, 5, 5, 5, 1, 1, 1, 1); + __m512i sum_mask3 = _mm512_set_epi64(3, 3, 3, 3, 3, 3, 3, 3); + __m512i base = _mm512_set1_epi64(w); + __m512i maskVal = _mm512_set1_epi64(mask); + __m512i shiftBits = _mm512_set_epi64(bit * 7 + 4, bit * 6 + 4, bit * 5 + 4, bit * 4 + 4, bit * 3 + 4, + bit * 2 + 4, bit + 4, 4); + __m512i inc = _mm512_set1_epi64(bit << 3); - for (int32_t i = 0; i < batch; ++i) { - __m512i after = _mm512_srlv_epi64(base, shiftBits); - __m512i zigzagVal = _mm512_and_si512(after, maskVal); + for (int32_t i = 0; i < batch; ++i) { + __m512i after = _mm512_srlv_epi64(base, shiftBits); + __m512i zigzagVal = _mm512_and_si512(after, maskVal); - // ZIGZAG_DECODE(T, v) (((v) >> 1) ^ -((T)((v)&1))) - __m512i signmask = _mm512_and_si512(_mm512_set1_epi64(1), zigzagVal); - signmask = _mm512_sub_epi64(_mm512_setzero_si512(), signmask); - __m512i delta = _mm512_xor_si512(_mm512_srli_epi64(zigzagVal, 1), signmask); + // ZIGZAG_DECODE(T, v) (((v) >> 1) ^ -((T)((v)&1))) + __m512i signmask = _mm512_and_si512(_mm512_set1_epi64(1), zigzagVal); + signmask = _mm512_sub_epi64(_mm512_setzero_si512(), signmask); + __m512i delta = _mm512_xor_si512(_mm512_srli_epi64(zigzagVal, 1), signmask); - // calculate the cumulative sum (prefix sum) for each number - // decode[0] = prevValue + final[0] - // decode[1] = decode[0] + final[1] -----> prevValue + final[0] + final[1] - // decode[2] = decode[1] + final[2] -----> prevValue + final[0] + final[1] + final[2] - // decode[3] = decode[2] + final[3] -----> prevValue + final[0] + final[1] + final[2] + final[3] + // calculate the cumulative sum (prefix sum) for each number + // decode[0] = prevValue + final[0] + // decode[1] = decode[0] + final[1] -----> prevValue + final[0] + final[1] + // decode[2] = decode[1] + final[2] -----> prevValue + final[0] + final[1] + final[2] + // decode[3] = decode[2] + final[3] -----> prevValue + final[0] + final[1] + final[2] + final[3] - // 7 6 5 4 3 2 1 - // 0 D7 D6 D5 D4 D3 D2 D1 - // D0 D6 0 D4 0 D2 0 D0 - // 0 D7+D6 D6 D5+D4 D4 D3+D2 D2 - // D1+D0 D0 13 6 9 4 5 2 - // 1 0 - __m512i prev = _mm512_set1_epi64(prevValue); - __m512i cum_sum = _mm512_add_epi64(delta, _mm512_maskz_permutexvar_epi64(0xaa, sum_mask1, delta)); - cum_sum = _mm512_add_epi64(cum_sum, _mm512_maskz_permutexvar_epi64(0xcc, sum_mask2, cum_sum)); - cum_sum = _mm512_add_epi64(cum_sum, _mm512_maskz_permutexvar_epi64(0xf0, sum_mask3, cum_sum)); + // 7 6 5 4 3 2 1 + // 0 D7 D6 D5 D4 D3 D2 D1 + // D0 D6 0 D4 0 D2 0 D0 + // 0 D7+D6 D6 D5+D4 D4 D3+D2 D2 + // D1+D0 D0 13 6 9 4 5 2 + // 1 0 + __m512i prev = _mm512_set1_epi64(prevValue); + __m512i cum_sum = _mm512_add_epi64(delta, _mm512_maskz_permutexvar_epi64(0xaa, sum_mask1, delta)); + cum_sum = _mm512_add_epi64(cum_sum, _mm512_maskz_permutexvar_epi64(0xcc, sum_mask2, cum_sum)); + cum_sum = _mm512_add_epi64(cum_sum, _mm512_maskz_permutexvar_epi64(0xf0, sum_mask3, cum_sum)); - // 13 6 9 4 5 2 1 - // 0 D7,D6 D6 D5,D4 D4 D3,D2 D2 - // D1,D0 D0 +D5,D4 D5,D4, 0 0 D1,D0 D1,D0 - // 0 0 D7~D4 D6~D4 D5~D4 D4 D3~D0 D2~D0 - // D1~D0 D0 22 15 9 4 6 3 - // 1 0 - // - // D3~D0 D3~D0 D3~D0 D3~D0 0 0 0 - // 0 28 21 15 10 6 3 1 - // 0 + // 13 6 9 4 5 2 1 + // 0 D7,D6 D6 D5,D4 D4 D3,D2 D2 + // D1,D0 D0 +D5,D4 D5,D4, 0 0 D1,D0 D1,D0 + // 0 0 D7~D4 D6~D4 D5~D4 D4 D3~D0 D2~D0 + // D1~D0 D0 22 15 9 4 6 3 + // 1 0 + // + // D3~D0 D3~D0 D3~D0 D3~D0 0 0 0 + // 0 28 21 15 10 6 3 1 + // 0 - cum_sum = _mm512_add_epi64(cum_sum, prev); - _mm512_storeu_si512((__m512i *)&p[_pos], cum_sum); + cum_sum = _mm512_add_epi64(cum_sum, prev); + _mm512_storeu_si512((__m512i *)&p[_pos], cum_sum); - shiftBits = _mm512_add_epi64(shiftBits, inc); - prevValue = p[_pos + 7]; - _pos += 8; - } - // handle the remain value - for (int32_t i = 0; i < remain; i++) { - zigzag_value = ((w >> (v + (batch * bit * 8))) & mask); - prevValue += ZIGZAG_DECODE(int64_t, zigzag_value); + shiftBits = _mm512_add_epi64(shiftBits, inc); + prevValue = p[_pos + 7]; + _pos += 8; + } + // handle the remain value + for (int32_t i = 0; i < remain; i++) { + zigzag_value = ((w >> (v + (batch * bit * 8))) & mask); + prevValue += ZIGZAG_DECODE(int64_t, zigzag_value); - p[_pos++] = prevValue; - v += bit; - } -#endif - } else if (tsSIMDEnable && tsAVX2Supported) { - __m256i base = _mm256_set1_epi64x(w); - __m256i maskVal = _mm256_set1_epi64x(mask); - - __m256i shiftBits = _mm256_set_epi64x(bit * 3 + 4, bit * 2 + 4, bit + 4, 4); - __m256i inc = _mm256_set1_epi64x(bit << 2); - - for (int32_t i = 0; i < batch; ++i) { - __m256i after = _mm256_srlv_epi64(base, shiftBits); - __m256i zigzagVal = _mm256_and_si256(after, maskVal); - - // ZIGZAG_DECODE(T, v) (((v) >> 1) ^ -((T)((v)&1))) - __m256i signmask = _mm256_and_si256(_mm256_set1_epi64x(1), zigzagVal); - signmask = _mm256_sub_epi64(_mm256_setzero_si256(), signmask); - - // get four zigzag values here - __m256i delta = _mm256_xor_si256(_mm256_srli_epi64(zigzagVal, 1), signmask); - - // calculate the cumulative sum (prefix sum) for each number - // decode[0] = prevValue + final[0] - // decode[1] = decode[0] + final[1] -----> prevValue + final[0] + final[1] - // decode[2] = decode[1] + final[2] -----> prevValue + final[0] + final[1] + final[2] - // decode[3] = decode[2] + final[3] -----> prevValue + final[0] + final[1] + final[2] + final[3] - - // 1, 2, 3, 4 - //+ 0, 1, 0, 3 - // 1, 3, 3, 7 - // shift and add for the first round - __m128i prev = _mm_set1_epi64x(prevValue); - __m256i x = _mm256_slli_si256(delta, 8); - - delta = _mm256_add_epi64(delta, x); - _mm256_storeu_si256((__m256i *)&p[_pos], delta); - - // 1, 3, 3, 7 - //+ 0, 0, 3, 3 - // 1, 3, 6, 10 - // shift and add operation for the second round - __m128i firstPart = _mm_loadu_si128((__m128i *)&p[_pos]); - __m128i secondItem = _mm_set1_epi64x(p[_pos + 1]); - __m128i secPart = _mm_add_epi64(_mm_loadu_si128((__m128i *)&p[_pos + 2]), secondItem); - firstPart = _mm_add_epi64(firstPart, prev); - secPart = _mm_add_epi64(secPart, prev); - - // save it in the memory - _mm_storeu_si128((__m128i *)&p[_pos], firstPart); - _mm_storeu_si128((__m128i *)&p[_pos + 2], secPart); - - shiftBits = _mm256_add_epi64(shiftBits, inc); - prevValue = p[_pos + 3]; - _pos += 4; - } - - // handle the remain value - for (int32_t i = 0; i < remain; i++) { - zigzag_value = ((w >> (v + (batch * bit * 4))) & mask); - prevValue += ZIGZAG_DECODE(int64_t, zigzag_value); - - p[_pos++] = prevValue; - v += bit; - } - } else { // alternative implementation without SIMD instructions. - for (int32_t i = 0; i < elems && count < nelements; i++, count++) { - zigzag_value = ((w >> v) & mask); - prevValue += ZIGZAG_DECODE(int64_t, zigzag_value); - - p[_pos++] = prevValue; - v += bit; - } + p[_pos++] = prevValue; + v += bit; } } } break; @@ -292,7 +188,7 @@ int32_t tsDecompressIntImpl_Hw(const char *const input, const int32_t nelements, return nelements * word_length; #else - uError("unable run %s without avx2 instructions", __func__); + uError("unable run %s without avx512 instructions", __func__); return -1; #endif } diff --git a/source/util/test/CMakeLists.txt b/source/util/test/CMakeLists.txt index 655557b180..cde1392216 100644 --- a/source/util/test/CMakeLists.txt +++ b/source/util/test/CMakeLists.txt @@ -138,6 +138,10 @@ add_test( COMMAND logTest ) +IF(COMPILER_SUPPORT_AVX2) + MESSAGE(STATUS "AVX2 instructions is ACTIVATED") + set_source_files_properties(decompressTest.cpp PROPERTIES COMPILE_FLAGS -mavx2) +ENDIF() add_executable(decompressTest "decompressTest.cpp") target_link_libraries(decompressTest os util common gtest_main) add_test( @@ -145,6 +149,16 @@ add_test( COMMAND decompressTest ) + +IF($TD_LINUX) + add_executable(utilTests "utilTests.cpp") + target_link_libraries(utilTests os util common gtest_main) + add_test( + NAME utilTests + COMMAND utilTests + ) +ENDIF() + if(${TD_LINUX}) # terrorTest add_executable(terrorTest "terrorTest.cpp") diff --git a/source/util/test/utilTests.cpp b/source/util/test/utilTests.cpp index cb78743018..9a42213929 100644 --- a/source/util/test/utilTests.cpp +++ b/source/util/test/utilTests.cpp @@ -6,6 +6,7 @@ #include "tarray.h" #include "tcompare.h" +#include "tdatablock.h" namespace { } // namespace @@ -474,3 +475,67 @@ TEST(tsma, reverse_unit) { ASSERT_FALSE(tsmaIntervalCheck(12, 'n', 1, 'y', TSDB_TIME_PRECISION_NANO)); ASSERT_TRUE(tsmaIntervalCheck(3, 'n', 1, 'y', TSDB_TIME_PRECISION_NANO)); } + +template +void dataBlockNullTest(const F& setValFunc) { + int32_t totalRows = 16; + SColumnInfoData columnInfoData = createColumnInfoData(type, tDataTypes[type].bytes, 0); + SColumnDataAgg columnDataAgg = {.numOfNull = 0}; + + auto checkNull = [totalRows, &columnInfoData, &columnDataAgg](uint32_t row, bool expected) { + EXPECT_EQ(colDataIsNull_s(&columnInfoData, row), expected); + EXPECT_EQ(colDataIsNull_t(&columnInfoData, row, IS_VAR_DATA_TYPE(columnInfoData.info.type)), expected); + EXPECT_EQ(colDataIsNull(&columnInfoData, totalRows, row, NULL), expected); + columnDataAgg.numOfNull = totalRows; + EXPECT_EQ(colDataIsNull(&columnInfoData, totalRows, row, &columnDataAgg), columnInfoData.hasNull); + columnDataAgg.numOfNull = 0; + EXPECT_EQ(colDataIsNull(&columnInfoData, totalRows, row, &columnDataAgg), false); + }; + + columnInfoData.hasNull = false; + checkNull(0, false); + checkNull(1, false); + checkNull(2, false); + checkNull(totalRows - 2, false); + checkNull(totalRows - 1, false); + + if (IS_VAR_DATA_TYPE(type)) { + columnInfoData.varmeta.offset = (int32_t*)taosMemoryCalloc(totalRows, sizeof(int32_t)); + } else { + columnInfoData.pData = (char*)taosMemoryCalloc(totalRows, tDataTypes[type].bytes); + columnInfoData.nullbitmap = (char*)taosMemoryCalloc(((totalRows - 1) >> NBIT) + 1, 1); + ValType val = 1; + setValFunc(&columnInfoData, 1, &val); + val = 2; + setValFunc(&columnInfoData, 2, &val); + } + colDataSetNULL(&columnInfoData, 0); + colDataSetNNULL(&columnInfoData, 3, totalRows - 3); + checkNull(0, true); + checkNull(1, false); + checkNull(2, false); + checkNull(totalRows - 2, true); + checkNull(totalRows - 1, true); + + if (IS_VAR_DATA_TYPE(type)) { + taosMemoryFreeClear(columnInfoData.varmeta.offset); + } else { + taosMemoryFreeClear(columnInfoData.pData); + taosMemoryFreeClear(columnInfoData.nullbitmap); + checkNull(0, false); + checkNull(1, false); + checkNull(2, false); + checkNull(totalRows - 2, false); + checkNull(totalRows - 1, false); + } +} + +TEST(utilTest, tdatablockTestNull) { + dataBlockNullTest(colDataSetInt8); + dataBlockNullTest(colDataSetInt16); + dataBlockNullTest(colDataSetInt32); + dataBlockNullTest(colDataSetInt64); + dataBlockNullTest(colDataSetFloat); + dataBlockNullTest(colDataSetDouble); + dataBlockNullTest(colDataSetInt64); +} From 3f6039d36bda906354220e0f1116bb255656b57d Mon Sep 17 00:00:00 2001 From: Jing Sima Date: Thu, 19 Dec 2024 17:29:46 +0800 Subject: [PATCH 23/55] enh:[TD-33274] Add more test cases --- source/libs/scalar/src/sclfunc.c | 348 ++++-------------- source/libs/scalar/src/sclvector.c | 217 +++-------- .../libs/scalar/test/scalar/scalarTests.cpp | 127 +++++++ .../army/query/function/ans/leastsquares.csv | 56 +++ tests/army/query/function/ans/max.csv | 55 +++ tests/army/query/function/ans/min.csv | 55 +++ tests/army/query/function/ans/round.csv | 50 +++ tests/army/query/function/ans/sign.csv | 128 +++++++ tests/army/query/function/ans/statecount.csv | 56 +++ tests/army/query/function/ans/sum.csv | 56 +++ tests/army/query/function/ans/trim.csv | 27 ++ tests/army/query/function/in/avg.in | 11 + tests/army/query/function/in/leastsquares.in | 11 + tests/army/query/function/in/max.in | 11 + tests/army/query/function/in/min.in | 11 + tests/army/query/function/in/round.in | 10 + tests/army/query/function/in/sign.in | 22 ++ tests/army/query/function/in/statecount.in | 11 + tests/army/query/function/in/sum.in | 11 + tests/army/query/function/in/trim.in | 3 + tests/army/query/function/test_function.py | 16 + 21 files changed, 853 insertions(+), 439 deletions(-) create mode 100644 tests/army/query/function/ans/leastsquares.csv create mode 100644 tests/army/query/function/ans/statecount.csv create mode 100644 tests/army/query/function/ans/sum.csv create mode 100644 tests/army/query/function/in/avg.in create mode 100644 tests/army/query/function/in/leastsquares.in create mode 100644 tests/army/query/function/in/statecount.in create mode 100644 tests/army/query/function/in/sum.in diff --git a/source/libs/scalar/src/sclfunc.c b/source/libs/scalar/src/sclfunc.c index 1da9a8f123..ce431c0b18 100644 --- a/source/libs/scalar/src/sclfunc.c +++ b/source/libs/scalar/src/sclfunc.c @@ -2985,279 +2985,93 @@ static int32_t doScalarFunction2(SScalarParam *pInput, int32_t inputNum, SScalar bool hasNullType = (IS_NULL_TYPE(GET_PARAM_TYPE(&pInput[0])) || IS_NULL_TYPE(GET_PARAM_TYPE(&pInput[1]))); int32_t numOfRows = TMAX(pInput[0].numOfRows, pInput[1].numOfRows); - if (pInput[0].numOfRows == pInput[1].numOfRows) { - for (int32_t i = 0; i < numOfRows; ++i) { - if (colDataIsNull_s(pInputData[0], i) || colDataIsNull_s(pInputData[1], i) || hasNullType) { - colDataSetNULL(pOutputData, i); - continue; - } - double in2; - GET_TYPED_DATA(in2, double, GET_PARAM_TYPE(&pInput[1]), colDataGetData(pInputData[1], i)); - switch (GET_PARAM_TYPE(&pInput[0])) { - case TSDB_DATA_TYPE_DOUBLE: { - double *in = (double *)pInputData[0]->pData; - double *out = (double *)pOutputData->pData; - double result = d1(in[i], in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_FLOAT: { - float *in = (float *)pInputData[0]->pData; - float *out = (float *)pOutputData->pData; - float result = f1(in[i], (float)in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_TINYINT: { - int8_t *in = (int8_t *)pInputData[0]->pData; - int8_t *out = (int8_t *)pOutputData->pData; - int8_t result = (int8_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_SMALLINT: { - int16_t *in = (int16_t *)pInputData[0]->pData; - int16_t *out = (int16_t *)pOutputData->pData; - int16_t result = (int16_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_INT: { - int32_t *in = (int32_t *)pInputData[0]->pData; - int32_t *out = (int32_t *)pOutputData->pData; - int32_t result = (int32_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_BIGINT: { - int64_t *in = (int64_t *)pInputData[0]->pData; - int64_t *out = (int64_t *)pOutputData->pData; - int64_t result = (int64_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UTINYINT: { - uint8_t *in = (uint8_t *)pInputData[0]->pData; - uint8_t *out = (uint8_t *)pOutputData->pData; - uint8_t result = (uint8_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_USMALLINT: { - uint16_t *in = (uint16_t *)pInputData[0]->pData; - uint16_t *out = (uint16_t *)pOutputData->pData; - uint16_t result = (uint16_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UINT: { - uint32_t *in = (uint32_t *)pInputData[0]->pData; - uint32_t *out = (uint32_t *)pOutputData->pData; - uint32_t result = (uint32_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UBIGINT: { - uint64_t *in = (uint64_t *)pInputData[0]->pData; - uint64_t *out = (uint64_t *)pOutputData->pData; - uint64_t result = (uint64_t)d1((double)in[i], in2); - out[i] = result; - break; - } - } + for (int32_t i = 0; i < numOfRows; ++i) { + int32_t colIdx1 = (pInput[0].numOfRows == 1) ? 0 : i; + int32_t colIdx2 = (pInput[1].numOfRows == 1) ? 0 : i; + if (colDataIsNull_s(pInputData[0], colIdx1) || colDataIsNull_s(pInputData[1], colIdx2) || hasNullType) { + colDataSetNULL(pOutputData, i); + continue; } - } else if (pInput[0].numOfRows == 1) { // left operand is constant - if (colDataIsNull_s(pInputData[0], 0) || hasNullType) { - colDataSetNNULL(pOutputData, 0, pInput[1].numOfRows); - } else { - for (int32_t i = 0; i < numOfRows; ++i) { - if (colDataIsNull_s(pInputData[1], i)) { + double in2; + GET_TYPED_DATA(in2, double, GET_PARAM_TYPE(&pInput[1]), colDataGetData(pInputData[1], colIdx2)); + switch (GET_PARAM_TYPE(&pInput[0])) { + case TSDB_DATA_TYPE_DOUBLE: { + double *in = (double *)pInputData[0]->pData; + double *out = (double *)pOutputData->pData; + double result = d1(in[colIdx1], in2); + if (isinf(result) || isnan(result)) { colDataSetNULL(pOutputData, i); - continue; - } - double in2; - GET_TYPED_DATA(in2, double, GET_PARAM_TYPE(&pInput[1]), colDataGetData(pInputData[1], i)); - switch (GET_PARAM_TYPE(&pInput[0])) { - case TSDB_DATA_TYPE_DOUBLE: { - double *in = (double *)pInputData[0]->pData; - double *out = (double *)pOutputData->pData; - double result = d1(in[0], in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_FLOAT: { - float *in = (float *)pInputData[0]->pData; - float *out = (float *)pOutputData->pData; - float result = f1(in[0], (float)in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_TINYINT: { - int8_t *in = (int8_t *)pInputData[0]->pData; - int8_t *out = (int8_t *)pOutputData->pData; - int8_t result = (int8_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_SMALLINT: { - int16_t *in = (int16_t *)pInputData[0]->pData; - int16_t *out = (int16_t *)pOutputData->pData; - int16_t result = (int16_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_INT: { - int32_t *in = (int32_t *)pInputData[0]->pData; - int32_t *out = (int32_t *)pOutputData->pData; - int32_t result = (int32_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_BIGINT: { - int64_t *in = (int64_t *)pInputData[0]->pData; - int64_t *out = (int64_t *)pOutputData->pData; - int64_t result = (int64_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UTINYINT: { - uint8_t *in = (uint8_t *)pInputData[0]->pData; - uint8_t *out = (uint8_t *)pOutputData->pData; - uint8_t result = (uint8_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_USMALLINT: { - uint16_t *in = (uint16_t *)pInputData[0]->pData; - uint16_t *out = (uint16_t *)pOutputData->pData; - uint16_t result = (uint16_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UINT: { - uint32_t *in = (uint32_t *)pInputData[0]->pData; - uint32_t *out = (uint32_t *)pOutputData->pData; - uint32_t result = (uint32_t)d1((double)in[0], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UBIGINT: { - uint64_t *in = (uint64_t *)pInputData[0]->pData; - uint64_t *out = (uint64_t *)pOutputData->pData; - uint64_t result = (uint64_t)d1((double)in[0], in2); - out[i] = result; - break; - } + } else { + out[i] = result; } + break; } - } - } else if (pInput[1].numOfRows == 1) { - if (colDataIsNull_s(pInputData[1], 0) || hasNullType) { - colDataSetNNULL(pOutputData, 0, pInput[0].numOfRows); - } else { - for (int32_t i = 0; i < numOfRows; ++i) { - if (colDataIsNull_s(pInputData[0], i)) { + case TSDB_DATA_TYPE_FLOAT: { + float *in = (float *)pInputData[0]->pData; + float *out = (float *)pOutputData->pData; + float result = f1(in[colIdx1], (float)in2); + if (isinf(result) || isnan(result)) { colDataSetNULL(pOutputData, i); - continue; - } - double in2; - GET_TYPED_DATA(in2, double, GET_PARAM_TYPE(&pInput[1]), colDataGetData(pInputData[1], 0)); - switch (GET_PARAM_TYPE(&pInput[0])) { - case TSDB_DATA_TYPE_DOUBLE: { - double *in = (double *)pInputData[0]->pData; - double *out = (double *)pOutputData->pData; - double result = d1(in[i], in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_FLOAT: { - float *in = (float *)pInputData[0]->pData; - float *out = (float *)pOutputData->pData; - float result = f1(in[i], in2); - if (isinf(result) || isnan(result)) { - colDataSetNULL(pOutputData, i); - } else { - out[i] = result; - } - break; - } - case TSDB_DATA_TYPE_TINYINT: { - int8_t *in = (int8_t *)pInputData[0]->pData; - int8_t *out = (int8_t *)pOutputData->pData; - int8_t result = (int8_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_SMALLINT: { - int16_t *in = (int16_t *)pInputData[0]->pData; - int16_t *out = (int16_t *)pOutputData->pData; - int16_t result = (int16_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_INT: { - int32_t *in = (int32_t *)pInputData[0]->pData; - int32_t *out = (int32_t *)pOutputData->pData; - int32_t result = (int32_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_BIGINT: { - int64_t *in = (int64_t *)pInputData[0]->pData; - int64_t *out = (int64_t *)pOutputData->pData; - int64_t result = (int64_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UTINYINT: { - uint8_t *in = (uint8_t *)pInputData[0]->pData; - uint8_t *out = (uint8_t *)pOutputData->pData; - uint8_t result = (uint8_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_USMALLINT: { - uint16_t *in = (uint16_t *)pInputData[0]->pData; - uint16_t *out = (uint16_t *)pOutputData->pData; - uint16_t result = (uint16_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UINT: { - uint32_t *in = (uint32_t *)pInputData[0]->pData; - uint32_t *out = (uint32_t *)pOutputData->pData; - uint32_t result = (uint32_t)d1((double)in[i], in2); - out[i] = result; - break; - } - case TSDB_DATA_TYPE_UBIGINT: { - uint64_t *in = (uint64_t *)pInputData[0]->pData; - uint64_t *out = (uint64_t *)pOutputData->pData; - uint64_t result = (uint64_t)d1((double)in[i], in2); - out[i] = result; - break; - } + } else { + out[i] = result; } + break; + } + case TSDB_DATA_TYPE_TINYINT: { + int8_t *in = (int8_t *)pInputData[0]->pData; + int8_t *out = (int8_t *)pOutputData->pData; + int8_t result = (int8_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_SMALLINT: { + int16_t *in = (int16_t *)pInputData[0]->pData; + int16_t *out = (int16_t *)pOutputData->pData; + int16_t result = (int16_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_INT: { + int32_t *in = (int32_t *)pInputData[0]->pData; + int32_t *out = (int32_t *)pOutputData->pData; + int32_t result = (int32_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_BIGINT: { + int64_t *in = (int64_t *)pInputData[0]->pData; + int64_t *out = (int64_t *)pOutputData->pData; + int64_t result = (int64_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_UTINYINT: { + uint8_t *in = (uint8_t *)pInputData[0]->pData; + uint8_t *out = (uint8_t *)pOutputData->pData; + uint8_t result = (uint8_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_USMALLINT: { + uint16_t *in = (uint16_t *)pInputData[0]->pData; + uint16_t *out = (uint16_t *)pOutputData->pData; + uint16_t result = (uint16_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_UINT: { + uint32_t *in = (uint32_t *)pInputData[0]->pData; + uint32_t *out = (uint32_t *)pOutputData->pData; + uint32_t result = (uint32_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; + } + case TSDB_DATA_TYPE_UBIGINT: { + uint64_t *in = (uint64_t *)pInputData[0]->pData; + uint64_t *out = (uint64_t *)pOutputData->pData; + uint64_t result = (uint64_t)d1((double)in[colIdx1], in2); + out[i] = result; + break; } } } diff --git a/source/libs/scalar/src/sclvector.c b/source/libs/scalar/src/sclvector.c index 5b432535fd..14dae1226d 100644 --- a/source/libs/scalar/src/sclvector.c +++ b/source/libs/scalar/src/sclvector.c @@ -121,19 +121,6 @@ _return: SCL_RET(code); } -int32_t convertBinaryToDouble(const void *inData, void *outData) { - char *tmp = taosMemoryCalloc(1, varDataTLen(inData)); - if (tmp == NULL) { - *((double *)outData) = 0.; - SCL_ERR_RET(terrno); - } - (void)memcpy(tmp, varDataVal(inData), varDataLen(inData)); - double ret = taosStr2Double(tmp, NULL); - taosMemoryFree(tmp); - *((double *)outData) = ret; - SCL_RET(TSDB_CODE_SUCCESS); -} - typedef int32_t (*_getBigintValue_fn_t)(void *src, int32_t index, int64_t *res); int32_t getVectorBigintValue_TINYINT(void *src, int32_t index, int64_t *res) { @@ -1129,17 +1116,11 @@ int32_t vectorConvertCols(SScalarParam *pLeft, SScalarParam *pRight, SScalarPara } if (type != GET_PARAM_TYPE(param1)) { - code = vectorConvertSingleCol(param1, paramOut1, type, startIndex, numOfRows); - if (code) { - return code; - } + SCL_ERR_RET(vectorConvertSingleCol(param1, paramOut1, type, startIndex, numOfRows)); } if (type != GET_PARAM_TYPE(param2)) { - code = vectorConvertSingleCol(param2, paramOut2, type, startIndex, numOfRows); - if (code) { - return code; - } + SCL_ERR_RET(vectorConvertSingleCol(param2, paramOut2, type, startIndex, numOfRows)); } return TSDB_CODE_SUCCESS; @@ -1208,22 +1189,16 @@ static int32_t vectorMathTsAddHelper(SColumnInfoData *pLeftCol, SColumnInfoData static int32_t vectorConvertVarToDouble(SScalarParam *pInput, int32_t *converted, SColumnInfoData **pOutputCol) { SScalarParam output = {0}; SColumnInfoData *pCol = pInput->columnData; - + int32_t code = TSDB_CODE_SUCCESS; + *pOutputCol = NULL; if (IS_VAR_DATA_TYPE(pCol->info.type) && pCol->info.type != TSDB_DATA_TYPE_JSON && pCol->info.type != TSDB_DATA_TYPE_VARBINARY) { - int32_t code = vectorConvertSingleCol(pInput, &output, TSDB_DATA_TYPE_DOUBLE, -1, -1); - if (code != TSDB_CODE_SUCCESS) { - *pOutputCol = NULL; - SCL_ERR_RET(code); - } - + SCL_ERR_RET(vectorConvertSingleCol(pInput, &output, TSDB_DATA_TYPE_DOUBLE, -1, -1)); *converted = VECTOR_DO_CONVERT; - *pOutputCol = output.columnData; SCL_RET(code); } *converted = VECTOR_UN_CONVERT; - *pOutputCol = pInput->columnData; SCL_RET(TSDB_CODE_SUCCESS); } @@ -1616,68 +1591,25 @@ int32_t vectorMathRemainder(SScalarParam *pLeft, SScalarParam *pRight, SScalarPa double *output = (double *)pOutputCol->pData; - if (pLeft->numOfRows == pRight->numOfRows) { - for (; i < pRight->numOfRows && i >= 0; i += step, output += 1) { - if (IS_NULL) { - colDataSetNULL(pOutputCol, i); - continue; - } - - double lx = 0; - double rx = 0; - SCL_ERR_JRET(getVectorDoubleValueFnLeft(LEFT_COL, i, &lx)); - SCL_ERR_JRET(getVectorDoubleValueFnRight(RIGHT_COL, i, &rx)); - if (isnan(lx) || isinf(lx) || isnan(rx) || isinf(rx) || FLT_EQUAL(rx, 0)) { - colDataSetNULL(pOutputCol, i); - continue; - } - - *output = lx - ((int64_t)(lx / rx)) * rx; + int32_t numOfRows = TMAX(pLeft->numOfRows, pRight->numOfRows); + for (; i < numOfRows && i >= 0; i += step, output += 1) { + int32_t leftidx = pLeft->numOfRows == 1 ? 0 : i; + int32_t rightidx = pRight->numOfRows == 1 ? 0 : i; + if (IS_HELPER_NULL(pLeftCol, leftidx) || IS_HELPER_NULL(pRightCol, rightidx)) { + colDataSetNULL(pOutputCol, i); + continue; } - } else if (pLeft->numOfRows == 1) { + double lx = 0; - SCL_ERR_JRET(getVectorDoubleValueFnLeft(LEFT_COL, 0, &lx)); - if (IS_HELPER_NULL(pLeftCol, 0)) { // Set pLeft->numOfRows NULL value - colDataSetNNULL(pOutputCol, 0, pRight->numOfRows); - } else { - for (; i >= 0 && i < pRight->numOfRows; i += step, output += 1) { - if (IS_HELPER_NULL(pRightCol, i)) { - colDataSetNULL(pOutputCol, i); - continue; - } - - double rx = 0; - SCL_ERR_JRET(getVectorDoubleValueFnRight(RIGHT_COL, i, &rx)); - if (isnan(rx) || isinf(rx) || FLT_EQUAL(rx, 0)) { - colDataSetNULL(pOutputCol, i); - continue; - } - - *output = lx - ((int64_t)(lx / rx)) * rx; - } - } - } else if (pRight->numOfRows == 1) { double rx = 0; - SCL_ERR_JRET(getVectorDoubleValueFnRight(RIGHT_COL, 0, &rx)); - if (IS_HELPER_NULL(pRightCol, 0) || FLT_EQUAL(rx, 0)) { // Set pLeft->numOfRows NULL value - colDataSetNNULL(pOutputCol, 0, pLeft->numOfRows); - } else { - for (; i >= 0 && i < pLeft->numOfRows; i += step, output += 1) { - if (IS_HELPER_NULL(pLeftCol, i)) { - colDataSetNULL(pOutputCol, i); - continue; - } - - double lx = 0; - SCL_ERR_JRET(getVectorDoubleValueFnLeft(LEFT_COL, i, &lx)); - if (isnan(lx) || isinf(lx)) { - colDataSetNULL(pOutputCol, i); - continue; - } - - *output = lx - ((int64_t)(lx / rx)) * rx; - } + SCL_ERR_JRET(getVectorDoubleValueFnLeft(LEFT_COL, leftidx, &lx)); + SCL_ERR_JRET(getVectorDoubleValueFnRight(RIGHT_COL, rightidx, &rx)); + if (isnan(lx) || isinf(lx) || isnan(rx) || isinf(rx) || FLT_EQUAL(rx, 0)) { + colDataSetNULL(pOutputCol, i); + continue; } + + *output = lx - ((int64_t)(lx / rx)) * rx; } _return: @@ -1739,33 +1671,6 @@ int32_t vectorAssign(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pO return TSDB_CODE_SUCCESS; } -static int32_t vectorBitAndHelper(SColumnInfoData *pLeftCol, SColumnInfoData *pRightCol, SColumnInfoData *pOutputCol, - int32_t numOfRows, int32_t step, int32_t i) { - _getBigintValue_fn_t getVectorBigintValueFnLeft; - _getBigintValue_fn_t getVectorBigintValueFnRight; - SCL_ERR_RET(getVectorBigintValueFn(pLeftCol->info.type, &getVectorBigintValueFnLeft)); - SCL_ERR_RET(getVectorBigintValueFn(pRightCol->info.type, &getVectorBigintValueFnRight)); - - int64_t *output = (int64_t *)pOutputCol->pData; - - if (IS_HELPER_NULL(pRightCol, 0)) { // Set pLeft->numOfRows NULL value - colDataSetNNULL(pOutputCol, 0, numOfRows); - } else { - for (; i >= 0 && i < numOfRows; i += step, output += 1) { - if (IS_HELPER_NULL(pLeftCol, i)) { - colDataSetNULL(pOutputCol, i); - continue; // TODO set null or ignore - } - int64_t leftRes = 0; - int64_t rightRes = 0; - SCL_ERR_RET(getVectorBigintValueFnLeft(LEFT_COL, i, &leftRes)); - SCL_ERR_RET(getVectorBigintValueFnRight(RIGHT_COL, 0, &rightRes)); - *output = leftRes & rightRes; - } - } - SCL_RET(TSDB_CODE_SUCCESS); -} - int32_t vectorBitAnd(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pOut, int32_t _ord) { SColumnInfoData *pOutputCol = pOut->columnData; pOut->numOfRows = TMAX(pLeft->numOfRows, pRight->numOfRows); @@ -1786,22 +1691,19 @@ int32_t vectorBitAnd(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pO SCL_ERR_JRET(getVectorBigintValueFn(pRightCol->info.type, &getVectorBigintValueFnRight)); int64_t *output = (int64_t *)pOutputCol->pData; - if (pLeft->numOfRows == pRight->numOfRows) { - for (; i < pRight->numOfRows && i >= 0; i += step, output += 1) { - if (IS_NULL) { - colDataSetNULL(pOutputCol, i); - continue; // TODO set null or ignore - } - int64_t leftRes = 0; - int64_t rightRes = 0; - SCL_ERR_JRET(getVectorBigintValueFnLeft(LEFT_COL, i, &leftRes)); - SCL_ERR_JRET(getVectorBigintValueFnRight(RIGHT_COL, i, &rightRes)); - *output = leftRes & rightRes; + int32_t numOfRows = TMAX(pLeft->numOfRows, pRight->numOfRows); + for (; i < numOfRows && i >= 0; i += step, output += 1) { + int32_t leftidx = pLeft->numOfRows == 1 ? 0 : i; + int32_t rightidx = pRight->numOfRows == 1 ? 0 : i; + if (IS_HELPER_NULL(pRightCol, rightidx) || IS_HELPER_NULL(pLeftCol, leftidx)) { + colDataSetNULL(pOutputCol, i); + continue; // TODO set null or ignore } - } else if (pLeft->numOfRows == 1) { - SCL_ERR_JRET(vectorBitAndHelper(pRightCol, pLeftCol, pOutputCol, pRight->numOfRows, step, i)); - } else if (pRight->numOfRows == 1) { - SCL_ERR_JRET(vectorBitAndHelper(pLeftCol, pRightCol, pOutputCol, pLeft->numOfRows, step, i)); + int64_t leftRes = 0; + int64_t rightRes = 0; + SCL_ERR_JRET(getVectorBigintValueFnLeft(LEFT_COL, leftidx, &leftRes)); + SCL_ERR_JRET(getVectorBigintValueFnRight(RIGHT_COL, rightidx, &rightRes)); + *output = leftRes & rightRes; } _return: @@ -1810,33 +1712,6 @@ _return: SCL_RET(code); } -static int32_t vectorBitOrHelper(SColumnInfoData *pLeftCol, SColumnInfoData *pRightCol, SColumnInfoData *pOutputCol, - int32_t numOfRows, int32_t step, int32_t i) { - _getBigintValue_fn_t getVectorBigintValueFnLeft; - _getBigintValue_fn_t getVectorBigintValueFnRight; - SCL_ERR_RET(getVectorBigintValueFn(pLeftCol->info.type, &getVectorBigintValueFnLeft)); - SCL_ERR_RET(getVectorBigintValueFn(pRightCol->info.type, &getVectorBigintValueFnRight)); - - int64_t *output = (int64_t *)pOutputCol->pData; - - if (IS_HELPER_NULL(pRightCol, 0)) { // Set pLeft->numOfRows NULL value - colDataSetNNULL(pOutputCol, 0, numOfRows); - } else { - int64_t rx = 0; - SCL_ERR_RET(getVectorBigintValueFnRight(RIGHT_COL, 0, &rx)); - for (; i >= 0 && i < numOfRows; i += step, output += 1) { - if (IS_HELPER_NULL(pLeftCol, i)) { - colDataSetNULL(pOutputCol, i); - continue; // TODO set null or ignore - } - int64_t lx = 0; - SCL_ERR_RET(getVectorBigintValueFnLeft(LEFT_COL, i, &lx)); - *output = lx | rx; - } - } - SCL_RET(TSDB_CODE_SUCCESS); -} - int32_t vectorBitOr(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pOut, int32_t _ord) { SColumnInfoData *pOutputCol = pOut->columnData; pOut->numOfRows = TMAX(pLeft->numOfRows, pRight->numOfRows); @@ -1857,22 +1732,20 @@ int32_t vectorBitOr(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pOu SCL_ERR_JRET(getVectorBigintValueFn(pRightCol->info.type, &getVectorBigintValueFnRight)); int64_t *output = (int64_t *)pOutputCol->pData; - if (pLeft->numOfRows == pRight->numOfRows) { - for (; i < pRight->numOfRows && i >= 0; i += step, output += 1) { - if (IS_NULL) { - colDataSetNULL(pOutputCol, i); - continue; // TODO set null or ignore - } - int64_t leftRes = 0; - int64_t rightRes = 0; - SCL_ERR_JRET(getVectorBigintValueFnLeft(LEFT_COL, i, &leftRes)); - SCL_ERR_JRET(getVectorBigintValueFnRight(RIGHT_COL, i, &rightRes)); - *output = leftRes | rightRes; + int32_t numOfRows = TMAX(pLeft->numOfRows, pRight->numOfRows); + for (; i < numOfRows && i >= 0; i += step, output += 1) { + int32_t leftidx = pLeft->numOfRows == 1 ? 0 : i; + int32_t rightidx = pRight->numOfRows == 1 ? 0 : i; + if (IS_HELPER_NULL(pRightCol, leftidx) || IS_HELPER_NULL(pLeftCol, rightidx)) { + colDataSetNULL(pOutputCol, i); + continue; // TODO set null or ignore } - } else if (pLeft->numOfRows == 1) { - SCL_ERR_JRET(vectorBitOrHelper(pRightCol, pLeftCol, pOutputCol, pRight->numOfRows, step, i)); - } else if (pRight->numOfRows == 1) { - SCL_ERR_JRET(vectorBitOrHelper(pLeftCol, pRightCol, pOutputCol, pLeft->numOfRows, step, i)); + + int64_t leftRes = 0; + int64_t rightRes = 0; + SCL_ERR_JRET(getVectorBigintValueFnLeft(LEFT_COL, leftidx, &leftRes)); + SCL_ERR_JRET(getVectorBigintValueFnRight(RIGHT_COL, rightidx, &rightRes)); + *output = leftRes | rightRes; } _return: diff --git a/source/libs/scalar/test/scalar/scalarTests.cpp b/source/libs/scalar/test/scalar/scalarTests.cpp index 865fb30814..fec9d14ae0 100644 --- a/source/libs/scalar/test/scalar/scalarTests.cpp +++ b/source/libs/scalar/test/scalar/scalarTests.cpp @@ -391,6 +391,26 @@ TEST(constantTest, bigint_add_bigint) { nodesDestroyNode(res); } +TEST(constantTest, ubigint_add_ubigint) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + int32_t code = TSDB_CODE_SUCCESS; + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_UBIGINT, &scltLeftV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_UBIGINT, &scltRightV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_ADD, TSDB_DATA_TYPE_UBIGINT, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_UBIGINT); + ASSERT_FLOAT_EQ(v->datum.d, (scltLeftV + scltRightV)); + nodesDestroyNode(res); +} + TEST(constantTest, double_sub_bigint) { SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; int32_t code = TSDB_CODE_SUCCESS; @@ -431,6 +451,66 @@ TEST(constantTest, tinyint_and_smallint) { nodesDestroyNode(res); } +TEST(constantTest, utinyint_and_usmallint) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + int32_t code = TSDB_CODE_SUCCESS; + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_UTINYINT, &scltLeftV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_USMALLINT, &scltRightV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_BIT_AND, TSDB_DATA_TYPE_BIGINT, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_BIGINT); + ASSERT_EQ(v->datum.i, (int64_t)scltLeftV & (int64_t)scltRightV); + nodesDestroyNode(res); +} + +TEST(constantTest, uint_and_usmallint) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + int32_t code = TSDB_CODE_SUCCESS; + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_UINT, &scltLeftV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_USMALLINT, &scltRightV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_BIT_AND, TSDB_DATA_TYPE_BIGINT, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_BIGINT); + ASSERT_EQ(v->datum.i, (int64_t)scltLeftV & (int64_t)scltRightV); + nodesDestroyNode(res); +} + +TEST(constantTest, ubigint_and_uint) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + int32_t code = TSDB_CODE_SUCCESS; + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_UBIGINT, &scltLeftV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_UINT, &scltRightV); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_BIT_AND, TSDB_DATA_TYPE_BIGINT, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_BIGINT); + ASSERT_EQ(v->datum.i, (int64_t)scltLeftV & (int64_t)scltRightV); + nodesDestroyNode(res); +} + TEST(constantTest, bigint_or_double) { SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; int32_t code = TSDB_CODE_SUCCESS; @@ -494,6 +574,53 @@ TEST(constantTest, int_greater_double) { nodesDestroyNode(res); } +TEST(constantTest, binary_greater_equal_varbinary) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + char binaryStr[64] = {0}; + int32_t code = TSDB_CODE_SUCCESS; + (void)sprintf(&binaryStr[2], "%d", scltRightV); + varDataSetLen(binaryStr, strlen(&binaryStr[2])); + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_VARBINARY, binaryStr); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_BINARY, binaryStr); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_GREATER_THAN, TSDB_DATA_TYPE_BOOL, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_BOOL); + ASSERT_EQ(v->datum.b, scltLeftV < scltRightVd); + nodesDestroyNode(res); +} + +TEST(constantTest, binary_equal_geo) { + SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; + char geoRawStr[64] = "POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))"; + char geoStr[64] = {0}; + int32_t code = TSDB_CODE_SUCCESS; + (void)sprintf(&geoStr[2], "%s", geoRawStr); + varDataSetLen(geoStr, strlen(&geoStr[2])); + code = scltMakeValueNode(&pLeft, TSDB_DATA_TYPE_GEOMETRY, geoStr); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeValueNode(&pRight, TSDB_DATA_TYPE_BINARY, geoStr); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + code = scltMakeOpNode(&opNode, OP_TYPE_EQUAL, TSDB_DATA_TYPE_BOOL, pLeft, pRight); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + code = scalarCalculateConstants(opNode, &res); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + ASSERT_TRUE(res); + ASSERT_EQ(nodeType(res), QUERY_NODE_VALUE); + SValueNode *v = (SValueNode *)res; + ASSERT_EQ(v->node.resType.type, TSDB_DATA_TYPE_BOOL); + ASSERT_EQ(v->datum.b, scltLeftV < scltRightVd); + nodesDestroyNode(res); +} + TEST(constantTest, int_greater_equal_binary) { SNode *pLeft = NULL, *pRight = NULL, *opNode = NULL, *res = NULL; char binaryStr[64] = {0}; diff --git a/tests/army/query/function/ans/leastsquares.csv b/tests/army/query/function/ans/leastsquares.csv new file mode 100644 index 0000000000..3d5cd33336 --- /dev/null +++ b/tests/army/query/function/ans/leastsquares.csv @@ -0,0 +1,56 @@ + +taos> select leastsquares(1, 1, 1) + leastsquares(1, 1, 1) | +================================= + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(1.1 as float), 1, 1) + leastsquares(cast(1.1 as float), 1, 1) | +========================================= + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(1.1 as double), 1, 1) + leastsquares(cast(1.1 as double), 1, 1) | +========================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(1 as tinyint), 1, 1) + leastsquares(cast(1 as tinyint), 1, 1) | +========================================= + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(100 as smallint), 1, 1) + leastsquares(cast(100 as smallint), 1, 1) | +============================================ + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(100000 as int), 1, 1) + leastsquares(cast(100000 as int), 1, 1) | +========================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(10000000000 as bigint), 1, 1) + leastsquares(cast(10000000000 as bigint), 1, 1) | +================================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(1 as tinyint unsigned), 1, 1) + leastsquares(cast(1 as tinyint unsigned), 1, 1) | +================================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(100 as smallint unsigned), 1, 1) + leastsquares(cast(100 as smallint unsigned), 1, 1) | +===================================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(100000 as int unsigned), 1, 1) + leastsquares(cast(100000 as int unsigned), 1, 1) | +=================================================== + {slop:-nan, intercept:-nan} | + +taos> select leastsquares(cast(10000000000 as bigint unsigned), 1, 1) + leastsquares(cast(10000000000 as bigint unsigned), 1, 1) | +=========================================================== + {slop:-nan, intercept:-nan} | + diff --git a/tests/army/query/function/ans/max.csv b/tests/army/query/function/ans/max.csv index f150ad1208..1570e1ebc9 100644 --- a/tests/army/query/function/ans/max.csv +++ b/tests/army/query/function/ans/max.csv @@ -603,3 +603,58 @@ taos> select location, max(current) from ts_4893.meters group by location order ============================================ beijing | 11.9989996 | +taos> select max(1) + max(1) | +======================== + 1 | + +taos> select max(cast(1 as tinyint)) + max(cast(1 as tinyint)) | +========================== + 1 | + +taos> select max(cast(100 as smallint)) + max(cast(100 as smallint)) | +============================= + 100 | + +taos> select max(cast(100000 as int)) + max(cast(100000 as int)) | +=========================== + 100000 | + +taos> select max(cast(10000000000 as bigint)) + max(cast(10000000000 as bigint)) | +=================================== + 10000000000 | + +taos> select max(cast(1 as tinyint unsigned)) + max(cast(1 as tinyint unsigned)) | +=================================== + 1 | + +taos> select max(cast(100 as smallint unsigned)) + max(cast(100 as smallint unsigned)) | +====================================== + 100 | + +taos> select max(cast(100000 as int unsigned)) + max(cast(100000 as int unsigned)) | +==================================== + 100000 | + +taos> select max(cast(10000000000 as bigint unsigned)) + max(cast(10000000000 as bigint unsigned)) | +============================================ + 10000000000 | + +taos> select max(cast(1.1 as float)) + max(cast(1.1 as float)) | +========================== + 1.1000000e+00 | + +taos> select max(cast(1.1 as double)) + max(cast(1.1 as double)) | +============================ + 1.100000000000000 | + diff --git a/tests/army/query/function/ans/min.csv b/tests/army/query/function/ans/min.csv index 9a8ba15287..1ea0c47e81 100644 --- a/tests/army/query/function/ans/min.csv +++ b/tests/army/query/function/ans/min.csv @@ -603,3 +603,58 @@ taos> select location, min(id) from ts_4893.meters group by location order by lo =================================== beijing | 0 | +taos> select min(1) + min(1) | +======================== + 1 | + +taos> select min(cast(1 as tinyint)) + min(cast(1 as tinyint)) | +========================== + 1 | + +taos> select min(cast(100 as smallint)) + min(cast(100 as smallint)) | +============================= + 100 | + +taos> select min(cast(100000 as int)) + min(cast(100000 as int)) | +=========================== + 100000 | + +taos> select min(cast(10000000000 as bigint)) + min(cast(10000000000 as bigint)) | +=================================== + 10000000000 | + +taos> select min(cast(1 as tinyint unsigned)) + min(cast(1 as tinyint unsigned)) | +=================================== + 1 | + +taos> select min(cast(100 as smallint unsigned)) + min(cast(100 as smallint unsigned)) | +====================================== + 100 | + +taos> select min(cast(100000 as int unsigned)) + min(cast(100000 as int unsigned)) | +==================================== + 100000 | + +taos> select min(cast(10000000000 as bigint unsigned)) + min(cast(10000000000 as bigint unsigned)) | +============================================ + 10000000000 | + +taos> select min(cast(1.1 as float)) + min(cast(1.1 as float)) | +========================== + 1.1000000e+00 | + +taos> select min(cast(1.1 as double)) + min(cast(1.1 as double)) | +============================ + 1.100000000000000 | + diff --git a/tests/army/query/function/ans/round.csv b/tests/army/query/function/ans/round.csv index 1b6ed548e7..4f9151c1ad 100644 --- a/tests/army/query/function/ans/round.csv +++ b/tests/army/query/function/ans/round.csv @@ -308,3 +308,53 @@ taos> select round(log(current), 2) from ts_4893.meters limit 1 ============================ 2.370000000000000 | +taos> select round(cast(1.0e+400 as float), 0); + round(cast(1.0e+400 as float), 0) | +==================================== + NULL | + +taos> select round(cast(1.0e+400 as double), 0); + round(cast(1.0e+400 as double), 0) | +===================================== + NULL | + +taos> select round(cast(5 as tinyint), 1); + round(cast(5 as tinyint), 1) | +=============================== + 5 | + +taos> select round(cast(50 as smallint), 1); + round(cast(50 as smallint), 1) | +================================= + 50 | + +taos> select round(cast(500 as int), 1); + round(cast(500 as int), 1) | +============================= + 500 | + +taos> select round(cast(50000 as bigint), 1); + round(cast(50000 as bigint), 1) | +================================== + 50000 | + +taos> select round(cast(5 as TINYINT UNSIGNED), 1); + round(cast(5 as tinyint unsigned), 1) | +======================================== + 5 | + +taos> select round(cast(50 as smallint unsigned), 1); + round(cast(50 as smallint unsigned), 1) | +========================================== + 50 | + +taos> select round(cast(500 as int unsigned), 1); + round(cast(500 as int unsigned), 1) | +====================================== + 500 | + +taos> select round(cast(50000 as bigint unsigned), 1) + round(cast(50000 as bigint unsigned), 1) | +=========================================== + 50000 | + diff --git a/tests/army/query/function/ans/sign.csv b/tests/army/query/function/ans/sign.csv index e15b4a74c7..45679af07f 100644 --- a/tests/army/query/function/ans/sign.csv +++ b/tests/army/query/function/ans/sign.csv @@ -121,6 +121,106 @@ taos> select SIGN(id) + id from ts_4893.meters order by ts limit 5 4.000000000000000 | 5.000000000000000 | +taos> select sign(cast(1 as tinyint)) + sign(cast(1 as tinyint)) | +=========================== + 1 | + +taos> select sign(cast(1 as smallint)) + sign(cast(1 as smallint)) | +============================ + 1 | + +taos> select sign(cast(1 as int)) + sign(cast(1 as int)) | +======================= + 1 | + +taos> select sign(cast(1 as bigint)) + sign(cast(1 as bigint)) | +========================== + 1 | + +taos> select sign(cast(1 as tinyint unsigned)) + sign(cast(1 as tinyint unsigned)) | +==================================== + 1 | + +taos> select sign(cast(1 as smallint unsigned)) + sign(cast(1 as smallint unsigned)) | +===================================== + 1 | + +taos> select sign(cast(1 as int unsigned)) + sign(cast(1 as int unsigned)) | +================================ + 1 | + +taos> select sign(cast(1 as bigint unsigned)) + sign(cast(1 as bigint unsigned)) | +=================================== + 1 | + +taos> select sign(cast(1 as float)) + sign(cast(1 as float)) | +========================= + 1.0000000e+00 | + +taos> select sign(cast(1 as double)) + sign(cast(1 as double)) | +============================ + 1.000000000000000 | + +taos> select sign(cast(NULL as tinyint)) + sign(cast(null as tinyint)) | +============================== + NULL | + +taos> select sign(cast(NULL as smallint)) + sign(cast(null as smallint)) | +=============================== + NULL | + +taos> select sign(cast(NULL as int)) + sign(cast(null as int)) | +========================== + NULL | + +taos> select sign(cast(NULL as bigint)) + sign(cast(null as bigint)) | +============================= + NULL | + +taos> select sign(cast(NULL as tinyint unsigned)) + sign(cast(null as tinyint unsigned)) | +======================================= + NULL | + +taos> select sign(cast(NULL as smallint unsigned)) + sign(cast(null as smallint unsigned)) | +======================================== + NULL | + +taos> select sign(cast(NULL as int unsigned)) + sign(cast(null as int unsigned)) | +=================================== + NULL | + +taos> select sign(cast(NULL as bigint unsigned)) + sign(cast(null as bigint unsigned)) | +====================================== + NULL | + +taos> select sign(cast(NULL as float)) + sign(cast(null as float)) | +============================ + NULL | + +taos> select sign(cast(NULL as double)) + sign(cast(null as double)) | +============================= + NULL | + taos> select SIGN(abs(10)) sign(abs(10)) | ======================== @@ -213,6 +313,34 @@ taos> select sign(current) from ts_4893.meters order by ts limit 10 1.0000000 | 1.0000000 | +taos> select sign(cast(current as float)) from ts_4893.d0 order by ts limit 10 + sign(cast(current as float)) | +=============================== + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + +taos> select sign(cast(current as float)) from ts_4893.meters order by ts limit 10 + sign(cast(current as float)) | +=============================== + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + 1.0000000e+00 | + taos> select sign(null) sign(null) | ======================== diff --git a/tests/army/query/function/ans/statecount.csv b/tests/army/query/function/ans/statecount.csv new file mode 100644 index 0000000000..d16b8443e2 --- /dev/null +++ b/tests/army/query/function/ans/statecount.csv @@ -0,0 +1,56 @@ + +taos> select statecount(1, 'GT', 1) + statecount(1, 'GT', 1) | +========================= + -1 | + +taos> select statecount(cast(1 as tinyint), 'GT', 1) + statecount(cast(1 as tinyint), 'GT', 1) | +========================================== + -1 | + +taos> select statecount(cast(100 as smallint), 'GT', 1) + statecount(cast(100 as smallint), 'GT', 1) | +============================================= + 1 | + +taos> select statecount(cast(100000 as int), 'GT', 1) + statecount(cast(100000 as int), 'GT', 1) | +=========================================== + 1 | + +taos> select statecount(cast(10000000000 as bigint), 'GT', 1) + statecount(cast(10000000000 as bigint), 'GT', 1) | +=================================================== + 1 | + +taos> select statecount(cast(1 as tinyint unsigned), 'GT', 1) + statecount(cast(1 as tinyint unsigned), 'GT', 1) | +=================================================== + -1 | + +taos> select statecount(cast(100 as smallint unsigned), 'GT', 1) + statecount(cast(100 as smallint unsigned), 'GT', 1) | +====================================================== + 1 | + +taos> select statecount(cast(100000 as int unsigned), 'GT', 1) + statecount(cast(100000 as int unsigned), 'GT', 1) | +==================================================== + 1 | + +taos> select statecount(cast(10000000000 as bigint unsigned), 'GT', 1) + statecount(cast(10000000000 as bigint unsigned), 'GT', 1) | +============================================================ + 1 | + +taos> select statecount(cast(1.1 as float), 'GT', 1) + statecount(cast(1.1 as float), 'GT', 1) | +========================================== + 1 | + +taos> select statecount(cast(1.1 as double), 'GT', 1) + statecount(cast(1.1 as double), 'GT', 1) | +=========================================== + 1 | + diff --git a/tests/army/query/function/ans/sum.csv b/tests/army/query/function/ans/sum.csv new file mode 100644 index 0000000000..3444b3f710 --- /dev/null +++ b/tests/army/query/function/ans/sum.csv @@ -0,0 +1,56 @@ + +taos> select sum(1) + sum(1) | +======================== + 1 | + +taos> select sum(cast(1 as tinyint)) + sum(cast(1 as tinyint)) | +========================== + 1 | + +taos> select sum(cast(100 as smallint)) + sum(cast(100 as smallint)) | +============================= + 100 | + +taos> select sum(cast(100000 as int)) + sum(cast(100000 as int)) | +=========================== + 100000 | + +taos> select sum(cast(10000000000 as bigint)) + sum(cast(10000000000 as bigint)) | +=================================== + 10000000000 | + +taos> select sum(cast(1 as tinyint unsigned)) + sum(cast(1 as tinyint unsigned)) | +=================================== + 1 | + +taos> select sum(cast(100 as smallint unsigned)) + sum(cast(100 as smallint unsigned)) | +====================================== + 100 | + +taos> select sum(cast(100000 as int unsigned)) + sum(cast(100000 as int unsigned)) | +==================================== + 100000 | + +taos> select sum(cast(10000000000 as bigint unsigned)) + sum(cast(10000000000 as bigint unsigned)) | +============================================ + 10000000000 | + +taos> select sum(cast(1.1 as float)) + sum(cast(1.1 as float)) | +============================ + 1.100000023841858 | + +taos> select sum(cast(1.1 as double)) + sum(cast(1.1 as double)) | +============================ + 1.100000000000000 | + diff --git a/tests/army/query/function/ans/trim.csv b/tests/army/query/function/ans/trim.csv index 6e2efbda51..eb821ffc91 100644 --- a/tests/army/query/function/ans/trim.csv +++ b/tests/army/query/function/ans/trim.csv @@ -179,6 +179,33 @@ taos> select trim(trailing '空格blank' from '空格blank空格中Tes空格blan =================================================================== 空格blank空格中Tes空格blank空 | +taos> select trim(both from nch1) from ts_4893.meters order by ts limit 5 + trim(both from nch1) | +================================= + novel | + 一二三四五六七八九十 | + update | + prision | + novel | + +taos> select trim(leading from nch1) from ts_4893.meters order by ts limit 5 + trim(leading from nch1) | +================================= + novel | + 一二三四五六七八九十 | + update | + prision | + novel | + +taos> select trim(trailing from nch1) from ts_4893.meters order by ts limit 5 + trim(trailing from nch1) | +================================= + novel | + 一二三四五六七八九十 | + update | + prision | + novel | + taos> select trim(nch2 from nch1) from ts_4893.meters where position(nch2 in nch1) != 0 order by ts limit 5 trim(nch2 from nch1) | ================================= diff --git a/tests/army/query/function/in/avg.in b/tests/army/query/function/in/avg.in new file mode 100644 index 0000000000..9284e8b1b7 --- /dev/null +++ b/tests/army/query/function/in/avg.in @@ -0,0 +1,11 @@ +select avg(1) +select avg(cast(1 as tinyint)) +select avg(cast(100 as smallint)) +select avg(cast(100000 as int)) +select avg(cast(10000000000 as bigint)) +select avg(cast(1 as tinyint unsigned)) +select avg(cast(100 as smallint unsigned)) +select avg(cast(100000 as int unsigned)) +select avg(cast(10000000000 as bigint unsigned)) +select avg(cast(1.1 as float)) +select avg(cast(1.1 as double)) \ No newline at end of file diff --git a/tests/army/query/function/in/leastsquares.in b/tests/army/query/function/in/leastsquares.in new file mode 100644 index 0000000000..2783a2a0c5 --- /dev/null +++ b/tests/army/query/function/in/leastsquares.in @@ -0,0 +1,11 @@ +select leastsquares(1, 1, 1) +select leastsquares(cast(1.1 as float), 1, 1) +select leastsquares(cast(1.1 as double), 1, 1) +select leastsquares(cast(1 as tinyint), 1, 1) +select leastsquares(cast(100 as smallint), 1, 1) +select leastsquares(cast(100000 as int), 1, 1) +select leastsquares(cast(10000000000 as bigint), 1, 1) +select leastsquares(cast(1 as tinyint unsigned), 1, 1) +select leastsquares(cast(100 as smallint unsigned), 1, 1) +select leastsquares(cast(100000 as int unsigned), 1, 1) +select leastsquares(cast(10000000000 as bigint unsigned), 1, 1) diff --git a/tests/army/query/function/in/max.in b/tests/army/query/function/in/max.in index efd4620f7b..336045afb5 100644 --- a/tests/army/query/function/in/max.in +++ b/tests/army/query/function/in/max.in @@ -26,3 +26,14 @@ select log(max(voltage) + 1) from ts_4893.meters select groupid, max(voltage) from ts_4893.meters group by groupid order by groupid select location, max(id) from ts_4893.meters group by location order by location select location, max(current) from ts_4893.meters group by location order by location +select max(1) +select max(cast(1 as tinyint)) +select max(cast(100 as smallint)) +select max(cast(100000 as int)) +select max(cast(10000000000 as bigint)) +select max(cast(1 as tinyint unsigned)) +select max(cast(100 as smallint unsigned)) +select max(cast(100000 as int unsigned)) +select max(cast(10000000000 as bigint unsigned)) +select max(cast(1.1 as float)) +select max(cast(1.1 as double)) diff --git a/tests/army/query/function/in/min.in b/tests/army/query/function/in/min.in index 910b8cc7bd..55d6853446 100644 --- a/tests/army/query/function/in/min.in +++ b/tests/army/query/function/in/min.in @@ -26,3 +26,14 @@ select log(min(voltage) + 1) from ts_4893.meters select groupid, min(voltage) from ts_4893.meters group by groupid order by groupid select location, min(current) from ts_4893.meters group by location order by location select location, min(id) from ts_4893.meters group by location order by location +select min(1) +select min(cast(1 as tinyint)) +select min(cast(100 as smallint)) +select min(cast(100000 as int)) +select min(cast(10000000000 as bigint)) +select min(cast(1 as tinyint unsigned)) +select min(cast(100 as smallint unsigned)) +select min(cast(100000 as int unsigned)) +select min(cast(10000000000 as bigint unsigned)) +select min(cast(1.1 as float)) +select min(cast(1.1 as double)) diff --git a/tests/army/query/function/in/round.in b/tests/army/query/function/in/round.in index bca293fc72..13dcb57117 100644 --- a/tests/army/query/function/in/round.in +++ b/tests/army/query/function/in/round.in @@ -47,3 +47,13 @@ select round(abs(voltage), 2) from ts_4893.meters limit 1 select round(pi() * phase, 3) from ts_4893.meters limit 1 select round(sqrt(voltage), 2) from ts_4893.meters limit 1 select round(log(current), 2) from ts_4893.meters limit 1 +select round(cast(1.0e+400 as float), 0); +select round(cast(1.0e+400 as double), 0); +select round(cast(5 as tinyint), 1); +select round(cast(50 as smallint), 1); +select round(cast(500 as int), 1); +select round(cast(50000 as bigint), 1); +select round(cast(5 as TINYINT UNSIGNED), 1); +select round(cast(50 as smallint unsigned), 1); +select round(cast(500 as int unsigned), 1); +select round(cast(50000 as bigint unsigned), 1); \ No newline at end of file diff --git a/tests/army/query/function/in/sign.in b/tests/army/query/function/in/sign.in index 436c884d36..25780eb31c 100644 --- a/tests/army/query/function/in/sign.in +++ b/tests/army/query/function/in/sign.in @@ -20,6 +20,26 @@ select SIGN(2) * SIGN(1) from ts_4893.meters limit 1 select SIGN(2) / SIGN(1) from ts_4893.meters limit 1 select SIGN(1) + id from ts_4893.meters order by ts limit 5 select SIGN(id) + id from ts_4893.meters order by ts limit 5 +select sign(cast(1 as tinyint)) +select sign(cast(1 as smallint)) +select sign(cast(1 as int)) +select sign(cast(1 as bigint)) +select sign(cast(1 as tinyint unsigned)) +select sign(cast(1 as smallint unsigned)) +select sign(cast(1 as int unsigned)) +select sign(cast(1 as bigint unsigned)) +select sign(cast(1 as float)) +select sign(cast(1 as double)) +select sign(cast(NULL as tinyint)) +select sign(cast(NULL as smallint)) +select sign(cast(NULL as int)) +select sign(cast(NULL as bigint)) +select sign(cast(NULL as tinyint unsigned)) +select sign(cast(NULL as smallint unsigned)) +select sign(cast(NULL as int unsigned)) +select sign(cast(NULL as bigint unsigned)) +select sign(cast(NULL as float)) +select sign(cast(NULL as double)) select SIGN(abs(10)) select SIGN(abs(-10)) select abs(SIGN(10)) @@ -34,6 +54,8 @@ select sign(-1) select sign(-10) select sign(current) from ts_4893.d0 order by ts limit 10 select sign(current) from ts_4893.meters order by ts limit 10 +select sign(cast(current as float)) from ts_4893.d0 order by ts limit 10 +select sign(cast(current as float)) from ts_4893.meters order by ts limit 10 select sign(null) select sign(25) select sign(-10) diff --git a/tests/army/query/function/in/statecount.in b/tests/army/query/function/in/statecount.in new file mode 100644 index 0000000000..df64918d61 --- /dev/null +++ b/tests/army/query/function/in/statecount.in @@ -0,0 +1,11 @@ +select statecount(1, 'GT', 1) +select statecount(cast(1 as tinyint), 'GT', 1) +select statecount(cast(100 as smallint), 'GT', 1) +select statecount(cast(100000 as int), 'GT', 1) +select statecount(cast(10000000000 as bigint), 'GT', 1) +select statecount(cast(1 as tinyint unsigned), 'GT', 1) +select statecount(cast(100 as smallint unsigned), 'GT', 1) +select statecount(cast(100000 as int unsigned), 'GT', 1) +select statecount(cast(10000000000 as bigint unsigned), 'GT', 1) +select statecount(cast(1.1 as float), 'GT', 1) +select statecount(cast(1.1 as double), 'GT', 1) diff --git a/tests/army/query/function/in/sum.in b/tests/army/query/function/in/sum.in new file mode 100644 index 0000000000..4caf5ecdbf --- /dev/null +++ b/tests/army/query/function/in/sum.in @@ -0,0 +1,11 @@ +select sum(1) +select sum(cast(1 as tinyint)) +select sum(cast(100 as smallint)) +select sum(cast(100000 as int)) +select sum(cast(10000000000 as bigint)) +select sum(cast(1 as tinyint unsigned)) +select sum(cast(100 as smallint unsigned)) +select sum(cast(100000 as int unsigned)) +select sum(cast(10000000000 as bigint unsigned)) +select sum(cast(1.1 as float)) +select sum(cast(1.1 as double)) diff --git a/tests/army/query/function/in/trim.in b/tests/army/query/function/in/trim.in index a0ad54dd7c..e96fb08675 100644 --- a/tests/army/query/function/in/trim.in +++ b/tests/army/query/function/in/trim.in @@ -34,6 +34,9 @@ select trim('空格blank' from '空格blank空格中Tes空格blank空') select trim(both '空格blank' from '空格blank空格中Tes空格blank空') select trim(leading '空格blank' from '空格blank空格中Tes空格blank空') select trim(trailing '空格blank' from '空格blank空格中Tes空格blank空') +select trim(both from nch1) from ts_4893.meters order by ts limit 5 +select trim(leading from nch1) from ts_4893.meters order by ts limit 5 +select trim(trailing from nch1) from ts_4893.meters order by ts limit 5 select trim(nch2 from nch1) from ts_4893.meters where position(nch2 in nch1) != 0 order by ts limit 5 select trim(both nch2 from nch1) from ts_4893.meters where position(nch2 in nch1) != 0 order by ts limit 5 select trim(leading nch2 from nch1) from ts_4893.meters where position(nch2 in nch1) != 0 order by ts limit 5 diff --git a/tests/army/query/function/test_function.py b/tests/army/query/function/test_function.py index d54460804a..c583d08cec 100644 --- a/tests/army/query/function/test_function.py +++ b/tests/army/query/function/test_function.py @@ -294,6 +294,18 @@ class TDTestCase(TBase): tdSql.error("select min(nonexistent_column) from ts_4893.meters;") + def test_sum(self): + self.test_normal_query_new("sum") + + def test_statecount(self): + self.test_normal_query_new("statecount") + + def test_avg(self): + self.test_normal_query_new("avg") + + def test_leastsquares(self): + self.test_normal_query_new("leastsquares") + def test_error(self): tdSql.error("select * from (select to_iso8601(ts, timezone()), timezone() from ts_4893.meters \ order by ts desc) limit 1000;", expectErrInfo="Invalid parameter data type : to_iso8601") # TS-5340 @@ -336,6 +348,10 @@ class TDTestCase(TBase): # agg function self.test_stddev_pop() self.test_varpop() + self.test_avg() + self.test_sum() + self.test_leastsquares() + self.test_statecount() # select function self.test_max() From 8892920ebcae4b6822b330ff5fdd481bbc6baa6d Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Mon, 23 Dec 2024 08:49:16 +0800 Subject: [PATCH 24/55] fix: task reschedule seriousId issue --- source/libs/scheduler/src/schTask.c | 2 +- source/libs/scheduler/test/schedulerTests.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/libs/scheduler/src/schTask.c b/source/libs/scheduler/src/schTask.c index cabaa65f19..c4a213bd7a 100644 --- a/source/libs/scheduler/src/schTask.c +++ b/source/libs/scheduler/src/schTask.c @@ -189,7 +189,6 @@ int32_t schProcessOnTaskFailure(SSchJob *pJob, SSchTask *pTask, int32_t errCode) } pTask->failedExecId = pTask->execId; - pTask->failedSeriousId = pTask->seriousId; int8_t jobStatus = 0; if (schJobNeedToStop(pJob, &jobStatus)) { @@ -1381,6 +1380,7 @@ int32_t schLaunchLevelTasks(SSchJob *pJob, SSchLevel *level) { for (int32_t i = 0; i < level->taskNum; ++i) { SSchTask *pTask = taosArrayGet(level->subTasks, i); + pTask->failedSeriousId = pJob->seriousId - 1; pTask->seriousId = pJob->seriousId; SCH_TASK_DLOG("task seriousId set to 0x%" PRIx64, pTask->seriousId); diff --git a/source/libs/scheduler/test/schedulerTests.cpp b/source/libs/scheduler/test/schedulerTests.cpp index f112376299..c13ea913f5 100644 --- a/source/libs/scheduler/test/schedulerTests.cpp +++ b/source/libs/scheduler/test/schedulerTests.cpp @@ -1008,6 +1008,9 @@ TEST(queryTest, rescheduleCase) { load.addr.epSet.eps[0].port = 6031; assert(taosArrayPush(qnodeList, &load) != NULL); + TAOS_STRCPY(load.addr.epSet.eps[0].fqdn, "qnode1.ep"); + assert(taosArrayPush(qnodeList, &load) != NULL); + code = schedulerInit(); ASSERT_EQ(code, 0); @@ -1079,7 +1082,6 @@ TEST(queryTest, rescheduleCase) { pIter = taosHashIterate(pJob->execTasks, pIter); } - pIter = taosHashIterate(pJob->execTasks, NULL); while (pIter) { SSchTask *task = *(SSchTask **)pIter; 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 25/55] 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 eb69017b11..e24a979b1e 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 6b7b46cfa7..a3b09dff22 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 d462873ab9..f87df22948 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -406,6 +406,14 @@ class TDTestCase: 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 @@ class TDTestCase: 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 a8a2b01f72f7ca5bcd2e05efad67d5d09b49625b Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Mon, 23 Dec 2024 10:00:46 +0800 Subject: [PATCH 26/55] fix: return code issue --- source/libs/scheduler/src/schTask.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/libs/scheduler/src/schTask.c b/source/libs/scheduler/src/schTask.c index c4a213bd7a..02fe04ed58 100644 --- a/source/libs/scheduler/src/schTask.c +++ b/source/libs/scheduler/src/schTask.c @@ -437,7 +437,7 @@ void schResetTaskForRetry(SSchJob *pJob, SSchTask *pTask) { pTask->waitRetry = true; if (pTask->delayTimer) { - taosTmrStop(pTask->delayTimer); + (void)taosTmrStop(pTask->delayTimer); } schDropTaskOnExecNode(pJob, pTask); @@ -761,7 +761,7 @@ int32_t schHandleTaskRetry(SSchJob *pJob, SSchTask *pTask) { (void)atomic_sub_fetch_32(&pTask->level->taskLaunchedNum, 1); if (pTask->delayTimer) { - taosTmrStop(pTask->delayTimer); + (void)taosTmrStop(pTask->delayTimer); } (void)schRemoveTaskFromExecList(pJob, pTask); // ignore error From 72dfc06f4402b41cd571ed7aa8d218e5579f0cd1 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Mon, 23 Dec 2024 10:06:37 +0800 Subject: [PATCH 27/55] fix: return code issue --- source/libs/scheduler/src/schTask.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/libs/scheduler/src/schTask.c b/source/libs/scheduler/src/schTask.c index 02fe04ed58..b31353e97f 100644 --- a/source/libs/scheduler/src/schTask.c +++ b/source/libs/scheduler/src/schTask.c @@ -437,7 +437,7 @@ void schResetTaskForRetry(SSchJob *pJob, SSchTask *pTask) { pTask->waitRetry = true; if (pTask->delayTimer) { - (void)taosTmrStop(pTask->delayTimer); + UNUSED(taosTmrStop(pTask->delayTimer)); } schDropTaskOnExecNode(pJob, pTask); @@ -761,7 +761,7 @@ int32_t schHandleTaskRetry(SSchJob *pJob, SSchTask *pTask) { (void)atomic_sub_fetch_32(&pTask->level->taskLaunchedNum, 1); if (pTask->delayTimer) { - (void)taosTmrStop(pTask->delayTimer); + UNUSED(taosTmrStop(pTask->delayTimer)); } (void)schRemoveTaskFromExecList(pJob, pTask); // ignore error From be3fea185cbc0049d62edb67faeb1aac4eede5cd Mon Sep 17 00:00:00 2001 From: dmchen Date: Mon, 23 Dec 2024 02:20:15 +0000 Subject: [PATCH 28/55] fix/TD-33287-monitor-coverage-add-case --- tests/parallel_test/cases.task | 1 + tests/system-test/0-others/taosdNewMonitor.py | 165 +++++++----------- 2 files changed, 63 insertions(+), 103 deletions(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 00a17c8c96..b9a616887c 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -361,6 +361,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/telemetry.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/backquote_check.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/taosdMonitor.py +,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/taosdNewMonitor.py ,,n,system-test,python3 ./test.py -f 0-others/taosdlog.py ,,n,system-test,python3 ./test.py -f 0-others/taosdShell.py -N 5 -M 3 -Q 3 ,,n,system-test,python3 ./test.py -f 0-others/udfTest.py diff --git a/tests/system-test/0-others/taosdNewMonitor.py b/tests/system-test/0-others/taosdNewMonitor.py index 00db81c8d9..a3ced155c5 100644 --- a/tests/system-test/0-others/taosdNewMonitor.py +++ b/tests/system-test/0-others/taosdNewMonitor.py @@ -23,6 +23,9 @@ class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): hostPort = hostname + ":" + serverPort def telemetryInfoCheck(self, infoDict=''): + if len(infoDict) == 0: + return + if "ts" not in infoDict[0] or len(infoDict[0]["ts"]) == 0: tdLog.exit("ts is null!") @@ -34,12 +37,51 @@ class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): if infoDict[0]["tables"][0]["name"] != "taosd_dnodes_info": tdLog.exit("taosd_dnodes_info is null!") + + # dnode_info ==================================== + + dnode_infos = ['disk_engine', 'system_net_in', 'vnodes_num', 'system_net_out', 'uptime', 'has_mnode', 'io_read_disk', 'error_log_count', + 'io_read', 'cpu_cores', 'has_qnode', 'has_snode', 'disk_total', 'mem_engine', 'info_log_count', 'cpu_engine', 'io_write_disk', + 'debug_log_count', 'disk_used', 'mem_total', 'io_write', 'masters', 'cpu_system', + 'trace_log_count', 'mem_free'] + index = 0 + for elem in dnode_infos: + tdLog.debug(f"elem: {index},{elem}") + if infoDict[0]["tables"][0]["metric_groups"][0]["metrics"][index]["name"] != elem: + tdLog.exit(f"{elem} is null!") + index += 1 if infoDict[0]["tables"][1]["name"] != "taosd_dnodes_log_dirs": tdLog.exit("taosd_dnodes_log_dirs is null!") + # logdir + if infoDict[0]["tables"][1]["metric_groups"][0]["tags"][3]["name"] != "data_dir_name": + tdLog.exit("data_dir_name is null!") + + if infoDict[0]["tables"][1]["metric_groups"][0]["metrics"][0]["name"] != "total": + tdLog.exit("total is null!") + + if infoDict[0]["tables"][1]["metric_groups"][0]["metrics"][1]["name"] != "used": + tdLog.exit("used is null!") + + if infoDict[0]["tables"][1]["metric_groups"][0]["metrics"][2]["name"] != "avail": + tdLog.exit("avail is null!") + if infoDict[0]["tables"][2]["name"] != "taosd_dnodes_data_dirs": tdLog.exit("taosd_dnodes_data_dirs is null!") + + # data_dir + if infoDict[0]["tables"][2]["metric_groups"][0]["tags"][3]["name"] != "data_dir_name": + tdLog.exit("data_dir_name is null!") + + if infoDict[0]["tables"][2]["metric_groups"][0]["metrics"][0]["name"] != "avail": + tdLog.exit("total is null!") + + if infoDict[0]["tables"][2]["metric_groups"][0]["metrics"][1]["name"] != "total": + tdLog.exit("used is null!") + + if infoDict[0]["tables"][2]["metric_groups"][0]["metrics"][2]["name"] != "used": + tdLog.exit("avail is null!") if infoDict[0]["tables"][3]["name"] != "taosd_cluster_info": tdLog.exit("taosd_cluster_info is null!") @@ -64,118 +106,35 @@ class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][13]["name"] != "dnodes_total": tdLog.exit("dnodes_total is null!") - if infoDict[0]["tables"][4]["name"] != "taosd_vgroups_info": - tdLog.exit("taosd_vgroups_info is null!") + # grant_info ==================================== + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][15]["name"] != "grants_expire_time": + tdLog.exit("grants_expire_time is null!") + + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][16]["name"] != "grants_timeseries_used": + tdLog.exit("grants_timeseries_used is null!") + + if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][17]["name"] != "grants_timeseries_total": + tdLog.exit("grants_timeseries_total is null!") # vgroup_infos ==================================== - if "vgroup_infos" not in infoDict or infoDict["vgroup_infos"]== None: - tdLog.exit("vgroup_infos is null!") - - vgroup_infos_nums = len(infoDict[0]["tables"][3]["metric_groups"][0]["metrics"]) - + vgroup_infos_nums = len(infoDict[0]["tables"][4]["metric_groups"]) + for index in range(vgroup_infos_nums): - if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][0]["metrics"][0]["name"] != "tables_num": + if infoDict[0]["tables"][4]["metric_groups"][index]["metrics"][0]["name"] != "tables_num": tdLog.exit("tables_num is null!") - if infoDict[0]["tables"][3]["metric_groups"][0]["metrics"][0]["metrics"][0]["name"] != "status": + if infoDict[0]["tables"][4]["metric_groups"][index]["metrics"][1]["name"] != "status": tdLog.exit("status is null!") + + if infoDict[0]["tables"][5]["name"] != "taosd_dnodes_status": + tdLog.exit("taosd_dnodes_status is null!") - # grant_info ==================================== + if infoDict[0]["tables"][6]["name"] != "taosd_mnodes_info": + tdLog.exit("taosd_mnodes_info is null!") - if "grant_info" not in infoDict or infoDict["grant_info"]== None: - tdLog.exit("grant_info is null!") - - if "expire_time" not in infoDict["grant_info"] or not infoDict["grant_info"]["expire_time"] > 0: - tdLog.exit("expire_time is null!") - - if "timeseries_used" not in infoDict["grant_info"]:# or not infoDict["grant_info"]["timeseries_used"] > 0: - tdLog.exit("timeseries_used is null!") - - if "timeseries_total" not in infoDict["grant_info"] or not infoDict["grant_info"]["timeseries_total"] > 0: - tdLog.exit("timeseries_total is null!") - - # dnode_info ==================================== - - if "dnode_info" not in infoDict or infoDict["dnode_info"]== None: - tdLog.exit("dnode_info is null!") - - dnode_infos = ['uptime', 'cpu_engine', 'cpu_system', 'cpu_cores', 'mem_engine', 'mem_system', 'mem_total', 'disk_engine', - 'disk_used', 'disk_total', 'net_in', 'net_out', 'io_read', 'io_write', 'io_read_disk', 'io_write_disk', 'req_select', - 'req_select_rate', 'req_insert', 'req_insert_success', 'req_insert_rate', 'req_insert_batch', 'req_insert_batch_success', - 'req_insert_batch_rate', 'errors', 'vnodes_num', 'masters', 'has_mnode', 'has_qnode', 'has_snode'] - for elem in dnode_infos: - if elem not in infoDict["dnode_info"] or infoDict["dnode_info"][elem] < 0: - tdLog.exit(f"{elem} is null!") - - # dnode_info ==================================== - - if "disk_infos" not in infoDict or infoDict["disk_infos"]== None: - tdLog.exit("disk_infos is null!") - - # bug for data_dir - if "datadir" not in infoDict["disk_infos"] or len(infoDict["disk_infos"]["datadir"]) <=0 : - tdLog.exit("datadir is null!") - - if "name" not in infoDict["disk_infos"]["datadir"][0] or len(infoDict["disk_infos"]["datadir"][0]["name"]) <= 0: - tdLog.exit("name is null!") - - if "level" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["level"] < 0: - tdLog.exit("level is null!") - - if "avail" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["avail"] <= 0: - tdLog.exit("avail is null!") - - if "used" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["used"] <= 0: - tdLog.exit("used is null!") - - if "total" not in infoDict["disk_infos"]["datadir"][0] or infoDict["disk_infos"]["datadir"][0]["total"] <= 0: - tdLog.exit("total is null!") - - - if "logdir" not in infoDict["disk_infos"] or infoDict["disk_infos"]["logdir"]== None: - tdLog.exit("logdir is null!") - - if "name" not in infoDict["disk_infos"]["logdir"] or len(infoDict["disk_infos"]["logdir"]["name"]) <= 0: - tdLog.exit("name is null!") - - if "avail" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["avail"] <= 0: - tdLog.exit("avail is null!") - - if "used" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["used"] <= 0: - tdLog.exit("used is null!") - - if "total" not in infoDict["disk_infos"]["logdir"] or infoDict["disk_infos"]["logdir"]["total"] <= 0: - tdLog.exit("total is null!") - - if "tempdir" not in infoDict["disk_infos"] or infoDict["disk_infos"]["tempdir"]== None: - tdLog.exit("tempdir is null!") - - if "name" not in infoDict["disk_infos"]["tempdir"] or len(infoDict["disk_infos"]["tempdir"]["name"]) <= 0: - tdLog.exit("name is null!") - - if "avail" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["avail"] <= 0: - tdLog.exit("avail is null!") - - if "used" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["used"] <= 0: - tdLog.exit("used is null!") - - if "total" not in infoDict["disk_infos"]["tempdir"] or infoDict["disk_infos"]["tempdir"]["total"] <= 0: - tdLog.exit("total is null!") - - # log_infos ==================================== - - if "log_infos" not in infoDict or infoDict["log_infos"]== None: - tdLog.exit("log_infos is null!") - - if "summary" not in infoDict["log_infos"] or len(infoDict["log_infos"]["summary"])!= 4: - tdLog.exit("summary is null!") - - if "total" not in infoDict["log_infos"]["summary"][0] or infoDict["log_infos"]["summary"][0]["total"] < 0 : - tdLog.exit("total is null!") - - if "level" not in infoDict["log_infos"]["summary"][0] or infoDict["log_infos"]["summary"][0]["level"] not in ["error" ,"info" , "debug" ,"trace"]: - tdLog.exit("level is null!") + if infoDict[0]["tables"][7]["name"] != "taosd_vnodes_info": + tdLog.exit("taosd_vnodes_info is null!") def do_GET(self): """ From 3ac04949da4b73bc63ee1f45fb36a284bfaa856b Mon Sep 17 00:00:00 2001 From: dmchen Date: Mon, 23 Dec 2024 02:50:51 +0000 Subject: [PATCH 29/55] fix/TS-5751-delete-audit-case --- tests/parallel_test/cases.task | 1 + tests/system-test/0-others/taosd_audit.py | 144 ++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 tests/system-test/0-others/taosd_audit.py diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index c9d28e0623..45009fe5f8 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -363,6 +363,7 @@ ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/telemetry.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/backquote_check.py ,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/taosdMonitor.py +,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/taosd_audit.py ,,n,system-test,python3 ./test.py -f 0-others/taosdlog.py ,,n,system-test,python3 ./test.py -f 0-others/taosdShell.py -N 5 -M 3 -Q 3 ,,n,system-test,python3 ./test.py -f 0-others/udfTest.py diff --git a/tests/system-test/0-others/taosd_audit.py b/tests/system-test/0-others/taosd_audit.py new file mode 100644 index 0000000000..65a25cbdec --- /dev/null +++ b/tests/system-test/0-others/taosd_audit.py @@ -0,0 +1,144 @@ +import taos +import sys +import time +import socket +# import pexpect +import os +import http.server +import gzip +import threading +import json +import pickle + +from util.log import * +from util.sql import * +from util.cases import * +from util.dnodes import * + +telemetryPort = '6043' +serverPort = '7080' +hostname = socket.gethostname() + +class RequestHandlerImpl(http.server.BaseHTTPRequestHandler): + hostPort = hostname + ":" + serverPort + + def telemetryInfoCheck(self, infoDict=''): + if "records" not in infoDict or len(infoDict["records"]) == 0: + tdLog.exit("records is null!") + + if "operation" not in infoDict["records"][0] or infoDict["records"][0]["operation"] != "delete": + tdLog.exit("operation is null!") + + if "details" not in infoDict["records"][0] or infoDict["records"][0]["details"] != "delete from db3.tb": + tdLog.exit("details is null!") + + def do_GET(self): + """ + process GET request + """ + + def do_POST(self): + """ + process POST request + """ + contentEncoding = self.headers["Content-Encoding"] + + if contentEncoding == 'gzip': + req_body = self.rfile.read(int(self.headers["Content-Length"])) + plainText = gzip.decompress(req_body).decode() + else: + plainText = self.rfile.read(int(self.headers["Content-Length"])).decode() + + print(plainText) + # 1. send response code and header + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.end_headers() + + # 2. send response content + #self.wfile.write(("Hello World: " + req_body + "\n").encode("utf-8")) + + # 3. check request body info + infoDict = json.loads(plainText) + #print("================") + # print(infoDict) + + self.telemetryInfoCheck(infoDict) + + # 4. shutdown the server and exit case + assassin = threading.Thread(target=self.server.shutdown) + assassin.daemon = True + assassin.start() + print ("==== shutdown http server ====") + +class TDTestCase: + global hostname + global serverPort + if (platform.system().lower() == 'windows' and not tdDnodes.dnodes[0].remoteIP == ""): + try: + config = eval(tdDnodes.dnodes[0].remoteIP ) + hostname = config["host"] + except Exception: + hostname = tdDnodes.dnodes[0].remoteIP + rpcDebugFlagVal = '143' + clientCfgDict = {'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + clientCfgDict["serverPort"] = serverPort + clientCfgDict["firstEp"] = hostname + ':' + serverPort + clientCfgDict["secondEp"] = hostname + ':' + serverPort + clientCfgDict["rpcDebugFlag"] = rpcDebugFlagVal + clientCfgDict["fqdn"] = hostname + + updatecfgDict = {'clientCfg': {}, 'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + updatecfgDict["clientCfg"] = clientCfgDict + updatecfgDict["serverPort"] = serverPort + updatecfgDict["firstEp"] = hostname + ':' + serverPort + updatecfgDict["secondEp"] = hostname + ':' + serverPort + updatecfgDict["fqdn"] = hostname + + updatecfgDict["monitorFqdn"] = hostname + updatecfgDict["monitorPort"] = '6043' + updatecfgDict["monitor"] = '0' + updatecfgDict["monitorInterval"] = "5" + updatecfgDict["monitorMaxLogs"] = "10" + updatecfgDict["monitorComp"] = "1" + updatecfgDict["monitorForceV2"] = "0" + + updatecfgDict["audit"] = '1' + + print ("===================: ", updatecfgDict) + + def init(self, conn, logSql, replicaVar=1): + self.replicaVar = int(replicaVar) + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor()) + + def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring + tdSql.prepare() + # time.sleep(2) + vgroups = "4" + sql = "create database db3 vgroups " + vgroups + tdSql.query(sql) + sql = "create table db3.stb (ts timestamp, f int) tags (t int)" + tdSql.query(sql) + sql = "create table db3.tb using db3.stb tags (1)" + tdSql.query(sql) + + sql = "delete from db3.tb" + tdSql.query(sql) + + # create http server: bing ip/port , and request processor + if (platform.system().lower() == 'windows' and not tdDnodes.dnodes[0].remoteIP == ""): + RequestHandlerImplStr = base64.b64encode(pickle.dumps(RequestHandlerImpl)).decode() + cmdStr = "import pickle\nimport http\nRequestHandlerImpl=pickle.loads(base64.b64decode(\"%s\".encode()))\nclass NewRequestHandlerImpl(RequestHandlerImpl):\n hostPort = \'%s\'\nhttp.server.HTTPServer((\"\", %s), NewRequestHandlerImpl).serve_forever()"%(RequestHandlerImplStr,hostname+":"+serverPort,telemetryPort) + tdDnodes.dnodes[0].remoteExec({}, cmdStr) + else: + serverAddress = ("", int(telemetryPort)) + http.server.HTTPServer(serverAddress, RequestHandlerImpl).serve_forever() + + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) 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 30/55] 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 f87df22948..380b7879c4 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -407,13 +407,11 @@ class TDTestCase: ##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 151a39448f4cfa7538c05f840a1e478494f111b8 Mon Sep 17 00:00:00 2001 From: dmchen Date: Mon, 23 Dec 2024 05:49:56 +0000 Subject: [PATCH 31/55] fix/D-33265-arbitrator-coverage --- tests/system-test/6-cluster/replica2.py | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/system-test/6-cluster/replica2.py diff --git a/tests/system-test/6-cluster/replica2.py b/tests/system-test/6-cluster/replica2.py new file mode 100644 index 0000000000..a90949c198 --- /dev/null +++ b/tests/system-test/6-cluster/replica2.py @@ -0,0 +1,28 @@ +################################################################### + # Copyright (c) 2016 by TAOS Technologies, Inc. + # All rights reserved. + # + # This file is proprietary and confidential to TAOS Technologies. + # No part of this file may be reproduced, stored, transmitted, + # disclosed or used in any form or by any means other than as + # expressly provided by the written permission from Jianhui Tao + # +################################################################### +from util.cases import * +from util.sql import * + +class TDTestCase: + def init(self, conn, logSql, replicaVar=1): + tdLog.debug(f"start to init {__file__}") + self.replicaVar = int(replicaVar) + tdSql.init(conn.cursor(), logSql) + + def run(self): + tdSql.execute('CREATE DATABASE db vgroups 1 replica 2;') + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) \ No newline at end of file From a1e20680f78a8bcf85975843f8052fbc329002ae Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 23 Dec 2024 15:57:49 +0800 Subject: [PATCH 32/55] fix:[TD-33272]add test case --- source/client/test/smlTest.cpp | 1 + source/common/src/msg/tmsg.c | 2 + source/dnode/vnode/src/tq/tq.c | 3 +- source/dnode/vnode/src/tq/tqOffset.c | 72 ++++++++++++----------- source/dnode/vnode/test/CMakeLists.txt | 38 ++++++------- source/dnode/vnode/test/tqTest.cpp | 79 ++++++++++++++++++++++++++ source/libs/parser/src/parInsertSml.c | 3 +- utils/test/c/sml_test.c | 25 ++++++++ 8 files changed, 166 insertions(+), 57 deletions(-) create mode 100644 source/dnode/vnode/test/tqTest.cpp diff --git a/source/client/test/smlTest.cpp b/source/client/test/smlTest.cpp index 338457bec4..968a4e7c75 100644 --- a/source/client/test/smlTest.cpp +++ b/source/client/test/smlTest.cpp @@ -276,6 +276,7 @@ TEST(testCase, smlParseCols_Test) { info->dataFormat = false; SSmlLineInfo elements = {0}; info->msgBuf = msgBuf; + ASSERT_EQ(smlInitHandle(NULL), const char *data = "st,t=1 cb\\=in=\"pass\\,it " diff --git a/source/common/src/msg/tmsg.c b/source/common/src/msg/tmsg.c index 2193c7983f..166c889947 100644 --- a/source/common/src/msg/tmsg.c +++ b/source/common/src/msg/tmsg.c @@ -11141,6 +11141,7 @@ void tOffsetCopy(STqOffsetVal *pLeft, const STqOffsetVal *pRight) { } void tOffsetDestroy(void *param) { + if (param == NULL) return; STqOffsetVal *pVal = (STqOffsetVal *)param; if (IS_VAR_DATA_TYPE(pVal->primaryKey.type)) { taosMemoryFreeClear(pVal->primaryKey.pData); @@ -11148,6 +11149,7 @@ void tOffsetDestroy(void *param) { } void tDeleteSTqOffset(void *param) { + if (param == NULL) return; STqOffset *pVal = (STqOffset *)param; tOffsetDestroy(&pVal->val); } diff --git a/source/dnode/vnode/src/tq/tq.c b/source/dnode/vnode/src/tq/tq.c index 03037e529b..37f3572f65 100644 --- a/source/dnode/vnode/src/tq/tq.c +++ b/source/dnode/vnode/src/tq/tq.c @@ -152,10 +152,9 @@ void tqClose(STQ* pTq) { taosMemoryFree(pTq->path); tqMetaClose(pTq); - int32_t vgId = pTq->pStreamMeta->vgId; streamMetaClose(pTq->pStreamMeta); - qDebug("vgId:%d end to close tq", vgId); + qDebug("vgId:%d end to close tq", pTq->pStreamMeta != NULL ? pTq->pStreamMeta->vgId : -1); taosMemoryFree(pTq); } diff --git a/source/dnode/vnode/src/tq/tqOffset.c b/source/dnode/vnode/src/tq/tqOffset.c index 4d90091701..57a901a2e1 100644 --- a/source/dnode/vnode/src/tq/tqOffset.c +++ b/source/dnode/vnode/src/tq/tqOffset.c @@ -17,33 +17,41 @@ #include "tq.h" int32_t tqBuildFName(char** data, const char* path, char* name) { - if (data == NULL || path == NULL || name == NULL) { - return TSDB_CODE_INVALID_MSG; - } + int32_t code = 0; + int32_t lino = 0; + char* fname = NULL; + TSDB_CHECK_NULL(data, code, lino, END, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(path, code, lino, END, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(name, code, lino, END, TSDB_CODE_INVALID_MSG); int32_t len = strlen(path) + strlen(name) + 2; - char* fname = taosMemoryCalloc(1, len); - if(fname == NULL) { - return terrno; - } - int32_t code = tsnprintf(fname, len, "%s%s%s", path, TD_DIRSEP, name); - if (code < 0){ - code = TAOS_SYSTEM_ERROR(errno); - taosMemoryFree(fname); - return code; - } + fname = taosMemoryCalloc(1, len); + TSDB_CHECK_NULL(fname, code, lino, END, terrno); + code = tsnprintf(fname, len, "%s%s%s", path, TD_DIRSEP, name); + TSDB_CHECK_CODE(code, lino, END); + *data = fname; - return TDB_CODE_SUCCESS; + fname = NULL; + +END: + if (code != 0){ + tqError("%s failed at %d since %s", __func__, lino, tstrerror(code)); + } + taosMemoryFree(fname); + return code; } int32_t tqOffsetRestoreFromFile(STQ* pTq, char* name) { - if (pTq == NULL || name == NULL) { - return TSDB_CODE_INVALID_MSG; - } - int32_t code = TDB_CODE_SUCCESS; - int32_t lino = 0; - void* pMemBuf = NULL; + int32_t code = TDB_CODE_SUCCESS; + int32_t lino = 0; + void* pMemBuf = NULL; + TdFilePtr pFile = NULL; + STqOffset *pOffset = NULL; + void *pIter = NULL; - TdFilePtr pFile = taosOpenFile(name, TD_FILE_READ); + TSDB_CHECK_NULL(pTq, code, lino, END, TSDB_CODE_INVALID_MSG); + TSDB_CHECK_NULL(name, code, lino, END, TSDB_CODE_INVALID_MSG); + + pFile = taosOpenFile(name, TD_FILE_READ); TSDB_CHECK_NULL(pFile, code, lino, END, TDB_CODE_SUCCESS); int64_t ret = 0; @@ -68,25 +76,20 @@ int32_t tqOffsetRestoreFromFile(STQ* pTq, char* name) { STqOffset offset = {0}; code = tqMetaDecodeOffsetInfo(&offset, pMemBuf, size); TSDB_CHECK_CODE(code, lino, END); - code = taosHashPut(pTq->pOffset, offset.subKey, strlen(offset.subKey), &offset, sizeof(STqOffset)); - if (code != TDB_CODE_SUCCESS) { - tDeleteSTqOffset(&offset); - goto END; - } + pOffset = &offset; + code = taosHashPut(pTq->pOffset, pOffset->subKey, strlen(pOffset->subKey), pOffset, sizeof(STqOffset)); + TSDB_CHECK_CODE(code, lino, END); + pOffset = NULL; tqInfo("tq: offset restore from file to tdb, size:%d, hash size:%d subkey:%s", total, taosHashGetSize(pTq->pOffset), offset.subKey); taosMemoryFree(pMemBuf); pMemBuf = NULL; } - void *pIter = NULL; while ((pIter = taosHashIterate(pTq->pOffset, pIter))) { - STqOffset* pOffset = (STqOffset*)pIter; - code = tqMetaSaveOffset(pTq, pOffset); - if(code != 0){ - taosHashCancelIterate(pTq->pOffset, pIter); - goto END; - } + STqOffset* offset = (STqOffset*)pIter; + code = tqMetaSaveOffset(pTq, offset); + TSDB_CHECK_CODE(code, lino, END); } END: @@ -96,5 +99,8 @@ END: taosCloseFile(&pFile); taosMemoryFree(pMemBuf); + tDeleteSTqOffset(pOffset); + taosHashCancelIterate(pTq->pOffset, pIter); + return code; } diff --git a/source/dnode/vnode/test/CMakeLists.txt b/source/dnode/vnode/test/CMakeLists.txt index 724eabc751..826296e99f 100644 --- a/source/dnode/vnode/test/CMakeLists.txt +++ b/source/dnode/vnode/test/CMakeLists.txt @@ -1,29 +1,25 @@ -MESSAGE(STATUS "vnode unit test") +MESSAGE(STATUS "tq unit test") # GoogleTest requires at least C++11 SET(CMAKE_CXX_STANDARD 11) -AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_LIST) -# add_executable(tqTest "") -# target_sources(tqTest -# PRIVATE -# "tqMetaTest.cpp" -# ) -# target_include_directories(tqTest -# PUBLIC -# "${TD_SOURCE_DIR}/include/server/vnode/tq" -# "${CMAKE_CURRENT_SOURCE_DIR}/../inc" -# ) +add_executable(tqTest tqTest.cpp) +target_include_directories(tqTest + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/../inc" +) -# target_link_libraries(tqTest -# tq -# gtest_main -# ) -# enable_testing() -# add_test( -# NAME tq_test -# COMMAND tqTest -# ) +TARGET_LINK_LIBRARIES( + tqTest + PUBLIC os util common vnode gtest_main +) + +enable_testing() + +add_test( + NAME tq_test + COMMAND tqTest +) # ADD_EXECUTABLE(tsdbSmaTest tsdbSmaTest.cpp) # TARGET_LINK_LIBRARIES( diff --git a/source/dnode/vnode/test/tqTest.cpp b/source/dnode/vnode/test/tqTest.cpp new file mode 100644 index 0000000000..1b5fe4fdcd --- /dev/null +++ b/source/dnode/vnode/test/tqTest.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" + +SDmNotifyHandle dmNotifyHdl = {.state = 0}; + +#include "tq.h" +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +STqOffset offset = {.subKey = "testtest", .val = {.type = TMQ_OFFSET__LOG, .version = 8923}}; + +void tqWriteOffset() { + TdFilePtr pFile = taosOpenFile(TQ_OFFSET_NAME, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND); + + int32_t bodyLen; + int32_t code; + tEncodeSize(tEncodeSTqOffset, &offset, bodyLen, code); + int32_t totLen = INT_BYTES + bodyLen; + void* buf = taosMemoryCalloc(1, totLen); + void* abuf = POINTER_SHIFT(buf, INT_BYTES); + + *(int32_t*)buf = htonl(bodyLen); + SEncoder encoder; + tEncoderInit(&encoder, (uint8_t*)abuf, bodyLen); + tEncodeSTqOffset(&encoder, &offset); + taosWriteFile(pFile, buf, totLen); + + taosMemoryFree(buf); + + taosCloseFile(&pFile); +} + +TEST(testCase, tqOffsetTest) { + STQ* pTq = (STQ*)taosMemoryCalloc(1, sizeof(STQ)); + pTq->path = taosStrdup("./"); + + pTq->pOffset = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_ENTRY_LOCK); + taosHashSetFreeFp(pTq->pOffset, (FDelete)tDeleteSTqOffset); + + tdbOpen(pTq->path, 16 * 1024, 1, &pTq->pMetaDB, 0, 0, NULL); + tdbTbOpen("tq.offset.db", -1, -1, NULL, pTq->pMetaDB, &pTq->pOffsetStore, 0); + + tqWriteOffset(); + tqOffsetRestoreFromFile(pTq, TQ_OFFSET_NAME); + taosRemoveFile(TQ_OFFSET_NAME); + tqClose(pTq); +} + +#pragma GCC diagnostic pop diff --git a/source/libs/parser/src/parInsertSml.c b/source/libs/parser/src/parInsertSml.c index d56cf7916f..bf86ef718e 100644 --- a/source/libs/parser/src/parInsertSml.c +++ b/source/libs/parser/src/parInsertSml.c @@ -357,10 +357,11 @@ end: int32_t smlInitHandle(SQuery** query) { int32_t lino = 0; int32_t code = 0; - *query = NULL; SQuery* pQuery = NULL; SVnodeModifyOpStmt* stmt = NULL; + TSDB_CHECK_NULL(query, code, lino, end, TSDB_CODE_INVALID_PARA); + *query = NULL; code = nodesMakeNode(QUERY_NODE_QUERY, (SNode**)&pQuery); TSDB_CHECK_CODE(code, lino, end); pQuery->execMode = QUERY_EXEC_MODE_SCHEDULE; diff --git a/utils/test/c/sml_test.c b/utils/test/c/sml_test.c index d922a6454e..0907c2a641 100644 --- a/utils/test/c/sml_test.c +++ b/utils/test/c/sml_test.c @@ -1939,6 +1939,20 @@ int sml_td24559_Test() { } taos_free_result(pRes); + const char *sql2[] = { + "stb,t1=1 f1=283i32,f2=g\"Point(4.343 89.342)\" 1632299375000", + }; + + pRes = taos_query(taos, "use td24559"); + taos_free_result(pRes); + + pRes = taos_schemaless_insert(taos, (char **)sql2, sizeof(sql2) / sizeof(sql2[0]), TSDB_SML_LINE_PROTOCOL, + TSDB_SML_TIMESTAMP_MILLI_SECONDS); + + code = taos_errno(pRes); + printf("%s result0:%s\n", __FUNCTION__, taos_errstr(pRes)); + taos_free_result(pRes); + pRes = taos_query(taos, "drop database if exists td24559"); taos_free_result(pRes); @@ -2325,6 +2339,17 @@ int sml_td17324_Test() { ASSERT(code == 0); taos_free_result(pRes); + const char *sql1[] = { + "st123456,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"pa3ssit\",c2=false,c4=4f64 1732700000394000000", + }; + + pRes = taos_schemaless_insert(taos, (char **)sql1, sizeof(sql1) / sizeof(sql1[0]), TSDB_SML_LINE_PROTOCOL, + TSDB_SML_TIMESTAMP_NANO_SECONDS); + code = taos_errno(pRes); + printf("%s result0:%s\n", __FUNCTION__, taos_errstr(pRes)); + ASSERT(code == 0); + taos_free_result(pRes); + taos_close(taos); return code; From 47394a6a0dbf54f8fa00cd2e3b1aa5f51b6267dd Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Mon, 23 Dec 2024 16:07:47 +0800 Subject: [PATCH 33/55] fix: add more UT cases --- source/libs/catalog/src/catalog.c | 7 +- source/libs/catalog/test/catalogTests.cpp | 1 + source/libs/qworker/src/qwMem.c | 2 + source/libs/scheduler/test/schedulerTests.cpp | 102 ++++++++ source/util/test/memPoolTest.cpp | 245 ++++++++++++++++++ 5 files changed, 356 insertions(+), 1 deletion(-) diff --git a/source/libs/catalog/src/catalog.c b/source/libs/catalog/src/catalog.c index 199bac5246..bc1462176a 100644 --- a/source/libs/catalog/src/catalog.c +++ b/source/libs/catalog/src/catalog.c @@ -424,6 +424,7 @@ int32_t ctgGetTbCfg(SCatalog* pCtg, SRequestConnInfo* pConn, SName* pTableName, CTG_RET(TSDB_CODE_SUCCESS); } +#if 0 int32_t ctgGetTbTag(SCatalog* pCtg, SRequestConnInfo* pConn, SName* pTableName, SArray** pRes) { SVgroupInfo vgroupInfo = {0}; STableCfg* pCfg = NULL; @@ -474,6 +475,7 @@ _return: CTG_RET(code); } +#endif int32_t ctgGetTbDistVgInfo(SCatalog* pCtg, SRequestConnInfo* pConn, SName* pTableName, SArray** pVgList) { STableMeta* tbMeta = NULL; @@ -1695,6 +1697,7 @@ _return: CTG_API_LEAVE(code); } +#if 0 int32_t catalogGetTableTag(SCatalog* pCtg, SRequestConnInfo* pConn, const SName* pTableName, SArray** pRes) { CTG_API_ENTER(); @@ -1709,6 +1712,7 @@ _return: CTG_API_LEAVE(code); } +#endif int32_t catalogRefreshGetTableCfg(SCatalog* pCtg, SRequestConnInfo* pConn, const SName* pTableName, STableCfg** pCfg) { CTG_API_ENTER(); @@ -1845,7 +1849,7 @@ _return: CTG_API_LEAVE(code); } - +#if 0 int32_t catalogAsyncUpdateViewMeta(SCatalog* pCtg, SViewMetaRsp* pMsg) { CTG_API_ENTER(); @@ -1860,6 +1864,7 @@ _return: CTG_API_LEAVE(code); } +#endif int32_t catalogGetViewMeta(SCatalog* pCtg, SRequestConnInfo* pConn, const SName* pViewName, STableMeta** pTableMeta) { CTG_API_ENTER(); diff --git a/source/libs/catalog/test/catalogTests.cpp b/source/libs/catalog/test/catalogTests.cpp index 7b0504504d..c2889f096b 100644 --- a/source/libs/catalog/test/catalogTests.cpp +++ b/source/libs/catalog/test/catalogTests.cpp @@ -2992,6 +2992,7 @@ TEST(apiTest, catalogGetTableIndex_test) { catalogDestroy(); } + TEST(apiTest, catalogGetDBCfg_test) { struct SCatalog *pCtg = NULL; SRequestConnInfo connInfo = {0}; diff --git a/source/libs/qworker/src/qwMem.c b/source/libs/qworker/src/qwMem.c index 69d4093221..6451e073c8 100644 --- a/source/libs/qworker/src/qwMem.c +++ b/source/libs/qworker/src/qwMem.c @@ -1,6 +1,7 @@ #include "qwInt.h" #include "qworker.h" +#if 0 void qwSetConcurrentTaskNumCb(int32_t taskNum) { int32_t finTaskNum = TMIN(taskNum, tsNumOfQueryThreads * QW_DEFAULT_THREAD_TASK_NUM); @@ -33,6 +34,7 @@ void qwIncConcurrentTaskNumCb(void) { //TODO } +#endif int32_t qwInitJobInfo(QW_FPARAMS_DEF, SQWJobInfo* pJob) { pJob->pSessions= taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); diff --git a/source/libs/scheduler/test/schedulerTests.cpp b/source/libs/scheduler/test/schedulerTests.cpp index c13ea913f5..50b2527802 100644 --- a/source/libs/scheduler/test/schedulerTests.cpp +++ b/source/libs/scheduler/test/schedulerTests.cpp @@ -60,6 +60,10 @@ extern "C" int32_t schHandleCallback(void *param, const SDataBuf *pMsg, int32_t extern "C" int32_t schHandleNotifyCallback(void *param, SDataBuf *pMsg, int32_t code); extern "C" int32_t schHandleLinkBrokenCallback(void *param, SDataBuf *pMsg, int32_t code); extern "C" int32_t schRescheduleTask(SSchJob *pJob, SSchTask *pTask); +extern "C" int32_t schValidateRspMsgType(SSchJob *pJob, SSchTask *pTask, int32_t msgType); +extern "C" int32_t schProcessFetchRsp(SSchJob *pJob, SSchTask *pTask, char *msg, int32_t rspCode); +extern "C" int32_t schProcessResponseMsg(SSchJob *pJob, SSchTask *pTask, SDataBuf *pMsg, int32_t rspCode); + int64_t insertJobRefId = 0; int64_t queryJobRefId = 0; @@ -1473,6 +1477,104 @@ TEST(otherTest, function) { schMgmt.jobRef = -1; } +TEST(otherTest, branch) { + SSchJob job = {0}; + SSchTask task = {0}; + schValidateRspMsgType(&job, &task, TDMT_SCH_MERGE_FETCH_RSP); + + task.lastMsgType = TDMT_SCH_MERGE_FETCH_RSP - 1; + schValidateRspMsgType(&job, &task, TDMT_SCH_MERGE_FETCH_RSP); + + schValidateRspMsgType(&job, &task, 0); + + schValidateRspMsgType(&job, &task, TDMT_SCH_QUERY_RSP); + + task.lastMsgType = TDMT_SCH_QUERY_RSP - 1; + schValidateRspMsgType(&job, &task, TDMT_SCH_QUERY_RSP); + + schProcessFetchRsp(&job, &task, NULL, -1); + schProcessFetchRsp(&job, &task, NULL, 0); + + job.fetchRes = (void*)0x1; + schProcessFetchRsp(&job, &task, (char*)taosMemoryMalloc(0), 0); + job.fetchRes = NULL; + + SDataBuf databuf = {0}; + databuf.msgType = TDMT_VND_ALTER_TABLE_RSP; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_VND_SUBMIT_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_VND_DELETE_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_SCH_QUERY_RSP; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_SCH_QUERY_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + + databuf.msgType = TDMT_SCH_EXPLAIN_RSP; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_SCH_EXPLAIN_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + job.attr.explainMode = EXPLAIN_MODE_ANALYZE; + databuf.msgType = TDMT_SCH_EXPLAIN_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + job.fetchRes = (void*)0x1; + schProcessResponseMsg(&job, &task, &databuf, 0); + job.fetchRes = NULL; + + job.attr.explainMode = EXPLAIN_MODE_ANALYZE; + databuf.msgType = TDMT_SCH_EXPLAIN_RSP; + databuf.pData = taosMemoryMalloc(0); + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_SCH_DROP_TASK_RSP; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = TDMT_SCH_LINK_BROKEN; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.msgType = 0; + job.status = JOB_TASK_STATUS_FAIL; + schProcessResponseMsg(&job, &task, &databuf, 0); + + databuf.pData = taosMemoryMalloc(0); + schHandleHbCallback(NULL, &databuf, 0); + + __async_send_cb_fn_t fp = NULL; + schGetCallbackFp(TDMT_SCH_TASK_NOTIFY, &fp); + schGetCallbackFp(0, &fp); + + SQueryNodeEpId ep = {0}; + schBuildAndSendHbMsg(&ep, NULL); + + schBuildAndSendMsg(&job, &task, NULL, 0, NULL); + + schMgmt.jobRef = -1; +} + + void schtReset() { insertJobRefId = 0; queryJobRefId = 0; diff --git a/source/util/test/memPoolTest.cpp b/source/util/test/memPoolTest.cpp index d0c08b1318..a8da96711d 100644 --- a/source/util/test/memPoolTest.cpp +++ b/source/util/test/memPoolTest.cpp @@ -2048,7 +2048,252 @@ TEST(DisablePoolFuncTest, MultiThreadTest) { } #endif +#if 1 +TEST(functionsTest, internalFunc) { + char* caseName = "functionsTest:internalFunc"; + int32_t code = 0; + int64_t msize = 10; + void* pSession = NULL; + void* pJob = NULL; + + mptInitPool(); + + memset(mptCtx.jobCtxs, 0, sizeof(*mptCtx.jobCtxs)); + + assert(0 == taosMemPoolCallocJob(0, 0, (void**)&pJob)); + assert(0 == taosMemPoolInitSession(gMemPoolHandle, &pSession, pJob, "id")); + + int32_t loopTimes = 1; + int64_t st = 0; + void **addrList = (void**)taosMemCalloc(loopTimes, POINTER_BYTES); + + + // MALLOC + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMalloc(msize); + } + mptFreeAddrList(addrList, loopTimes); + + + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMalloc(msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMalloc(msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + // CALLOC + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryCalloc(1, msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryCalloc(1, msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryCalloc(1, msize); + } + //mptFreeAddrList(addrList, loopTimes); NO FREE FOR REALLOC + + // REALLOC + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryRealloc(addrList[i], msize); + } + mptDisableMemoryPoolUsage(); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryRealloc(addrList[i], msize); + } + mptDisableMemoryPoolUsage(); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryRealloc(addrList[i], msize); + } + mptFreeAddrList(addrList, loopTimes); + + + // STRDUP + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrdup("abc"); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrdup("abc"); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrdup("abc"); + } + mptFreeAddrList(addrList, loopTimes); + + // STRNDUP + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrndup("abc", 3); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrndup("abc", 3); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptStrndup("abc", 3); + } + mptFreeAddrList(addrList, loopTimes); + + // ALIGNALLOC + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMallocAlign(8, msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMallocAlign(8, msize); + } + mptDisableMemoryPoolUsage(); + mptFreeAddrList(addrList, loopTimes); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMallocAlign(8, msize); + } + //mptFreeAddrList(addrList, loopTimes); NO FREE FOR GETSIZE + + + // GETSIZE + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemorySize(addrList[i]); + } + mptDisableMemoryPoolUsage(); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemorySize(addrList[i]); + } + mptDisableMemoryPoolUsage(); + + + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemorySize(addrList[i]); + } + + // FREE + + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemoryFree(addrList[i]); + } + mptDisableMemoryPoolUsage(); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMalloc(msize); + } + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemoryFree(addrList[i]); + } + mptDisableMemoryPoolUsage(); + + + for (int32_t i = 0; i < loopTimes; ++i) { + addrList[i] = (char*)mptMemoryMalloc(msize); + } + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemoryFree(addrList[i]); + } + + // TRIM + + bool trimed = false; + tsMemPoolFullFunc = 0; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemoryTrim(0, NULL); + mptMemoryTrim(0, &trimed); + } + mptDisableMemoryPoolUsage(); + + + tsMemPoolFullFunc = 1; + mptEnableMemoryPoolUsage(gMemPoolHandle, pSession); + for (int32_t i = 0; i < loopTimes; ++i) { + mptMemoryTrim(0, NULL); + mptMemoryTrim(0, &trimed); + } + mptDisableMemoryPoolUsage(); + + +} +#endif #endif From 4f77274af46e84514eeaeda017d3ac79371bde90 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 23 Dec 2024 16:15:44 +0800 Subject: [PATCH 34/55] fix:[TD-33272]add test case --- source/client/test/smlTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client/test/smlTest.cpp b/source/client/test/smlTest.cpp index 968a4e7c75..cbd13c6749 100644 --- a/source/client/test/smlTest.cpp +++ b/source/client/test/smlTest.cpp @@ -276,7 +276,7 @@ TEST(testCase, smlParseCols_Test) { info->dataFormat = false; SSmlLineInfo elements = {0}; info->msgBuf = msgBuf; - ASSERT_EQ(smlInitHandle(NULL), + ASSERT_EQ(smlInitHandle(NULL), 0), const char *data = "st,t=1 cb\\=in=\"pass\\,it " From 196ef024c534bb50b5b02cfccb5ad071d38e3556 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 23 Dec 2024 16:52:14 +0800 Subject: [PATCH 35/55] fix:[TD-33272]add test case --- source/client/test/smlTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client/test/smlTest.cpp b/source/client/test/smlTest.cpp index cbd13c6749..87be16e467 100644 --- a/source/client/test/smlTest.cpp +++ b/source/client/test/smlTest.cpp @@ -276,7 +276,7 @@ TEST(testCase, smlParseCols_Test) { info->dataFormat = false; SSmlLineInfo elements = {0}; info->msgBuf = msgBuf; - ASSERT_EQ(smlInitHandle(NULL), 0), + ASSERT_EQ(smlInitHandle(NULL), 0); const char *data = "st,t=1 cb\\=in=\"pass\\,it " From 6244712887e79015240bef5cf21f3398ae88d505 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 23 Dec 2024 18:12:47 +0800 Subject: [PATCH 36/55] fix:[TD-33272]add test case --- source/dnode/vnode/src/tq/tqOffset.c | 3 +- source/dnode/vnode/test/tqTest.cpp | 4 +- .../7-tmq/tmqVnodeSplit-ntb-select.py | 192 ++++++++++++++++++ 3 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 tests/system-test/7-tmq/tmqVnodeSplit-ntb-select.py diff --git a/source/dnode/vnode/src/tq/tqOffset.c b/source/dnode/vnode/src/tq/tqOffset.c index 57a901a2e1..a131f30a04 100644 --- a/source/dnode/vnode/src/tq/tqOffset.c +++ b/source/dnode/vnode/src/tq/tqOffset.c @@ -26,8 +26,7 @@ int32_t tqBuildFName(char** data, const char* path, char* name) { int32_t len = strlen(path) + strlen(name) + 2; fname = taosMemoryCalloc(1, len); TSDB_CHECK_NULL(fname, code, lino, END, terrno); - code = tsnprintf(fname, len, "%s%s%s", path, TD_DIRSEP, name); - TSDB_CHECK_CODE(code, lino, END); + (void)tsnprintf(fname, len, "%s%s%s", path, TD_DIRSEP, name); *data = fname; fname = NULL; diff --git a/source/dnode/vnode/test/tqTest.cpp b/source/dnode/vnode/test/tqTest.cpp index 1b5fe4fdcd..d757aa6d43 100644 --- a/source/dnode/vnode/test/tqTest.cpp +++ b/source/dnode/vnode/test/tqTest.cpp @@ -37,11 +37,11 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -STqOffset offset = {.subKey = "testtest", .val = {.type = TMQ_OFFSET__LOG, .version = 8923}}; - void tqWriteOffset() { TdFilePtr pFile = taosOpenFile(TQ_OFFSET_NAME, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND); + STqOffset offset = {.val = {.type = TMQ_OFFSET__LOG, .version = 8923}}; + strcpy(offset.subKey, "testtest"); int32_t bodyLen; int32_t code; tEncodeSize(tEncodeSTqOffset, &offset, bodyLen, code); diff --git a/tests/system-test/7-tmq/tmqVnodeSplit-ntb-select.py b/tests/system-test/7-tmq/tmqVnodeSplit-ntb-select.py new file mode 100644 index 0000000000..8f8eb7d4ea --- /dev/null +++ b/tests/system-test/7-tmq/tmqVnodeSplit-ntb-select.py @@ -0,0 +1,192 @@ + +import taos +import sys +import time +import socket +import os +import threading +import math + +from util.log import * +from util.sql import * +from util.cases import * +from util.dnodes import * +from util.common import * +from util.cluster import * +sys.path.append("./7-tmq") +from tmqCommon import * + +from util.cluster import * +sys.path.append("./6-cluster") +from clusterCommonCreate import * +from clusterCommonCheck import clusterComCheck + + + +class TDTestCase: + def __init__(self): + self.vgroups = 1 + self.ctbNum = 10 + self.rowsPerTbl = 1000 + + def init(self, conn, logSql, replicaVar=1): + self.replicaVar = int(replicaVar) + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor(), True) + + def getDataPath(self): + selfPath = tdCom.getBuildPath() + + return selfPath + '/../sim/dnode%d/data/vnode/vnode%d/wal/*'; + + def prepareTestEnv(self): + tdLog.printNoPrefix("======== prepare test env include database, stable, ctables, and insert data: ") + paraDict = {'dbName': 'dbt', + 'dropFlag': 1, + 'event': '', + 'vgroups': 1, + 'stbName': 'stb', + 'colPrefix': 'c', + 'tagPrefix': 't', + 'colSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'BINARY', 'len':32, 'count':1},{'type': 'NCHAR', 'len':32, 'count':1},{'type': 'TIMESTAMP', 'count':1}], + 'tagSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'BINARY', 'len':32, 'count':1},{'type': 'NCHAR', 'len':32, 'count':1}], + 'ctbPrefix': 'ctb', + 'ctbStartIdx': 0, + 'ctbNum': 10, + 'rowsPerTbl': 1000, + 'batchNum': 10, + 'startTs': 1640966400000, # 2022-01-01 00:00:00.000 + 'pollDelay': 120, + 'showMsg': 1, + 'showRow': 1, + 'snapshot': 0} + + paraDict['vgroups'] = self.vgroups + paraDict['ctbNum'] = self.ctbNum + paraDict['rowsPerTbl'] = self.rowsPerTbl + + tdCom.drop_all_db() + tmqCom.initConsumerTable() + tdCom.create_database(tdSql, paraDict["dbName"],paraDict["dropFlag"], wal_retention_period=36000,vgroups=paraDict["vgroups"],replica=self.replicaVar) + tdLog.info("create stb") + tdSql.query("create table dbt.t(ts timestamp, v int)") + tdSql.query("insert into dbt.t values('2022-01-01 00:00:00.000', 0)") + tdSql.query("insert into dbt.t values('2022-01-01 00:00:02.000', 0)") + tdSql.query("insert into dbt.t values('2022-01-01 00:00:03.000', 0)") + return + + def restartAndRemoveWal(self, deleteWal): + tdDnodes = cluster.dnodes + tdSql.query("select * from information_schema.ins_vnodes") + for result in tdSql.queryResult: + if result[2] == 'dbt': + tdLog.debug("dnode is %d"%(result[0])) + dnodeId = result[0] + vnodeId = result[1] + + tdDnodes[dnodeId - 1].stoptaosd() + time.sleep(1) + dataPath = self.getDataPath() + dataPath = dataPath%(dnodeId,vnodeId) + tdLog.debug("dataPath:%s"%dataPath) + if deleteWal: + if os.system('rm -rf ' + dataPath) != 0: + tdLog.exit("rm error") + + tdDnodes[dnodeId - 1].starttaosd() + time.sleep(1) + break + tdLog.debug("restart dnode ok") + + def splitVgroups(self): + tdSql.query("select * from information_schema.ins_vnodes") + vnodeId = 0 + for result in tdSql.queryResult: + if result[2] == 'dbt': + vnodeId = result[1] + tdLog.debug("vnode is %d"%(vnodeId)) + break + splitSql = "split vgroup %d" %(vnodeId) + tdLog.debug("splitSql:%s"%(splitSql)) + tdSql.query(splitSql) + tdLog.debug("splitSql ok") + + def tmqCase1(self, deleteWal=False): + tdLog.printNoPrefix("======== test case 1: ") + paraDict = {'dbName': 'dbt', + 'dropFlag': 1, + 'event': '', + 'vgroups': 1, + 'stbName': 'stb', + 'colPrefix': 'c', + 'tagPrefix': 't', + 'colSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'BINARY', 'len':32, 'count':1},{'type': 'NCHAR', 'len':32, 'count':1},{'type': 'TIMESTAMP', 'count':1}], + 'tagSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'BINARY', 'len':32, 'count':1},{'type': 'NCHAR', 'len':32, 'count':1}], + 'ctbPrefix': 'ctb1', + 'ctbStartIdx': 0, + 'ctbNum': 10, + 'rowsPerTbl': 1000, + 'batchNum': 10, + 'startTs': 1640966400000, # 2022-01-01 00:00:00.000 + 'pollDelay': 2, + 'showMsg': 1, + 'showRow': 1, + 'snapshot': 0} + + paraDict['vgroups'] = self.vgroups + paraDict['ctbNum'] = self.ctbNum + paraDict['rowsPerTbl'] = self.rowsPerTbl + + topicNameList = ['topic1'] + # expectRowsList = [] + tmqCom.initConsumerTable() + + tdLog.info("create topics from ntb with filter") + queryString = "select * from %s.t"%(paraDict['dbName']) + sqlString = "create topic %s as %s" %(topicNameList[0], queryString) + tdLog.info("create topic sql: %s"%sqlString) + tdSql.execute(sqlString) + + # init consume info, and start tmq_sim, then check consume result + tdLog.info("insert consume info to consume processor") + consumerId = 0 + expectrowcnt = paraDict["rowsPerTbl"] * paraDict["ctbNum"] * 2 + topicList = topicNameList[0] + ifcheckdata = 1 + ifManualCommit = 1 + keyList = 'group.id:cgrp1, enable.auto.commit:true, auto.commit.interval.ms:200, auto.offset.reset:earliest' + tmqCom.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + tmqCom.startTmqSimProcess(pollDelay=paraDict['pollDelay'],dbName=paraDict["dbName"],showMsg=paraDict['showMsg'], showRow=paraDict['showRow'],snapshot=paraDict['snapshot']) + tdLog.info("wait the consume result") + + + tmqCom.getStartConsumeNotifyFromTmqsim() + tmqCom.getStartCommitNotifyFromTmqsim() + + #restart dnode & remove wal + self.restartAndRemoveWal(deleteWal) + + # split vgroup + self.splitVgroups() + + clusterComCheck.check_vgroups_status(vgroup_numbers=2,db_replica=self.replicaVar,db_name="dbt",count_number=240) + + time.sleep(3) + for i in range(len(topicNameList)): + tdSql.query("drop topic %s"%topicNameList[i]) + tdLog.printNoPrefix("======== test case 1 end ...... ") + + def run(self): + self.prepareTestEnv() + self.tmqCase1(True) + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +event = threading.Event() + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) 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 37/55] 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 41ac0117f3..7af64c041d 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 0ec66cd2ce..ebde9fe50e 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 80dd3ec142..17d8b55560 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 38/55] 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 17d8b55560..c8297d56b7 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 4b62a9a5872ab49ed7a5afbf470101d90096bc95 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 23 Dec 2024 19:30:36 +0800 Subject: [PATCH 39/55] fix:[TD-33272]add test case --- source/dnode/vnode/src/tq/tqSnapshot.c | 2 +- tests/parallel_test/cases.task | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/dnode/vnode/src/tq/tqSnapshot.c b/source/dnode/vnode/src/tq/tqSnapshot.c index ddbbba57a0..ce5008e344 100644 --- a/source/dnode/vnode/src/tq/tqSnapshot.c +++ b/source/dnode/vnode/src/tq/tqSnapshot.c @@ -89,7 +89,7 @@ int32_t tqSnapRead(STqSnapReader* pReader, uint8_t** ppData) { TSDB_CHECK_NULL(ppData, code, lino, end, TSDB_CODE_INVALID_MSG); code = tdbTbcNext(pReader->pCur, &pKey, &kLen, &pVal, &vLen); - TSDB_CHECK_CODE(code, lino, end); + TSDB_CHECK_CONDITION(code == 0, code, lino, end, TDB_CODE_SUCCESS); *ppData = taosMemoryMalloc(sizeof(SSnapDataHdr) + vLen); TSDB_CHECK_NULL(*ppData, code, lino, end, terrno); diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index c9d28e0623..1a713bff5f 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -338,6 +338,7 @@ ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb-select-duplicatedata.py -N 3 -n 3 ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb-select-duplicatedata-false.py -N 3 -n 3 ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb-select.py -N 3 -n 3 +,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-ntb-select.py -N 3 -n 3 ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb-select-false.py -N 3 -n 3 ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb.py -N 3 -n 3 ,,y,system-test,./pytest.sh python3 test.py -f 7-tmq/tmqVnodeSplit-stb-false.py -N 3 -n 3 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 40/55] 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 584c4b5775..501f1cabc1 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 41/55] 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 11cf926081..7085c8dc7c 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 7b9209813d..3049865777 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 e3a04fc9c1..43b5b421ab 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; From e65a3802a23223b54d252d5dd1a289dded3797d7 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Tue, 24 Dec 2024 09:21:09 +0800 Subject: [PATCH 42/55] fix:[TD-33272]add test case --- source/client/test/smlTest.cpp | 2 +- source/dnode/vnode/src/tq/tqOffset.c | 2 +- source/dnode/vnode/test/CMakeLists.txt | 30 ++++++++++++++------------ source/libs/parser/src/parInsertSml.c | 6 +++--- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/source/client/test/smlTest.cpp b/source/client/test/smlTest.cpp index 87be16e467..d64cd9c971 100644 --- a/source/client/test/smlTest.cpp +++ b/source/client/test/smlTest.cpp @@ -276,7 +276,7 @@ TEST(testCase, smlParseCols_Test) { info->dataFormat = false; SSmlLineInfo elements = {0}; info->msgBuf = msgBuf; - ASSERT_EQ(smlInitHandle(NULL), 0); + ASSERT_EQ(smlInitHandle(NULL), TSDB_CODE_INVALID_PARA); const char *data = "st,t=1 cb\\=in=\"pass\\,it " diff --git a/source/dnode/vnode/src/tq/tqOffset.c b/source/dnode/vnode/src/tq/tqOffset.c index a131f30a04..6996f3578c 100644 --- a/source/dnode/vnode/src/tq/tqOffset.c +++ b/source/dnode/vnode/src/tq/tqOffset.c @@ -95,7 +95,7 @@ END: if (code != 0){ tqError("%s failed at %d since %s", __func__, lino, tstrerror(code)); } - taosCloseFile(&pFile); + (void)taosCloseFile(&pFile); taosMemoryFree(pMemBuf); tDeleteSTqOffset(pOffset); diff --git a/source/dnode/vnode/test/CMakeLists.txt b/source/dnode/vnode/test/CMakeLists.txt index 826296e99f..ff7e5a2196 100644 --- a/source/dnode/vnode/test/CMakeLists.txt +++ b/source/dnode/vnode/test/CMakeLists.txt @@ -3,23 +3,25 @@ MESSAGE(STATUS "tq unit test") # GoogleTest requires at least C++11 SET(CMAKE_CXX_STANDARD 11) -add_executable(tqTest tqTest.cpp) -target_include_directories(tqTest - PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/../inc" -) +IF(NOT TD_WINDOWS) + add_executable(tqTest tqTest.cpp) + target_include_directories(tqTest + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/../inc" + ) -TARGET_LINK_LIBRARIES( - tqTest - PUBLIC os util common vnode gtest_main -) + TARGET_LINK_LIBRARIES( + tqTest + PUBLIC os util common vnode gtest_main + ) -enable_testing() + enable_testing() -add_test( - NAME tq_test - COMMAND tqTest -) + add_test( + NAME tq_test + COMMAND tqTest + ) +ENDIF() # ADD_EXECUTABLE(tsdbSmaTest tsdbSmaTest.cpp) # TARGET_LINK_LIBRARIES( diff --git a/source/libs/parser/src/parInsertSml.c b/source/libs/parser/src/parInsertSml.c index bf86ef718e..676aed4464 100644 --- a/source/libs/parser/src/parInsertSml.c +++ b/source/libs/parser/src/parInsertSml.c @@ -123,7 +123,7 @@ static int32_t smlBuildTagRow(SArray* cols, SBoundColInfo* tags, SSchema* pSchem val.pData = (uint8_t*)kv->value; val.nData = kv->length; } else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) { - code = smlMbsToUcs4(kv->value, kv->length, (void**)&val.pData, &val.nData, kv->length * TSDB_NCHAR_SIZE, charsetCxt); + code = smlMbsToUcs4(kv->value, kv->length, (void**)&val.pData, (int32_t*)&val.nData, kv->length * TSDB_NCHAR_SIZE, charsetCxt); TSDB_CHECK_CODE(code, lino, end); } else { (void)memcpy(&val.i64, &(kv->value), kv->length); @@ -316,7 +316,7 @@ int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSc kv->i = convertTimePrecision(kv->i, TSDB_TIME_PRECISION_NANO, pTableMeta->tableInfo.precision); } if (kv->type == TSDB_DATA_TYPE_NCHAR) { - ret = smlMbsToUcs4(kv->value, kv->length, (void**)&pVal->value.pData, &pVal->value.nData, pColSchema->bytes - VARSTR_HEADER_SIZE, charsetCxt); + ret = smlMbsToUcs4(kv->value, kv->length, (void**)&pVal->value.pData, (int32_t*)&pVal->value.nData, pColSchema->bytes - VARSTR_HEADER_SIZE, charsetCxt); TSDB_CHECK_CODE(ret, lino, end); } else if (kv->type == TSDB_DATA_TYPE_BINARY) { pVal->value.nData = kv->length; @@ -345,7 +345,7 @@ int32_t smlBindData(SQuery* query, bool dataFormat, SArray* tags, SArray* colsSc end: if (ret != 0){ uError("%s failed at %d since %s", __func__, lino, tstrerror(ret)); - buildInvalidOperationMsg(&pBuf, tstrerror(ret)); + ret = buildInvalidOperationMsg(&pBuf, tstrerror(ret)); } insDestroyBoundColInfo(&bindTags); tdDestroySVCreateTbReq(pCreateTblReq); From f6bd86272bfb1329754210a7ae35737be866fc47 Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Tue, 24 Dec 2024 09:42:26 +0800 Subject: [PATCH 43/55] udf case: varchar --- include/libs/function/taosudf.h | 26 ++++++----- source/libs/function/test/change_udf.c | 64 ++++++++++++++++++++++++++ tests/pytest/util/tserror.py | 3 ++ tests/system-test/0-others/udfTest.py | 33 +++++++++++++ 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/include/libs/function/taosudf.h b/include/libs/function/taosudf.h index 91487e5d1d..fd6b42f61e 100644 --- a/include/libs/function/taosudf.h +++ b/include/libs/function/taosudf.h @@ -237,18 +237,20 @@ static FORCE_INLINE int32_t udfColDataSet(SUdfColumn *pColumn, uint32_t currentR (void)memcpy(data->fixLenCol.data + meta->bytes * currentRow, pData, meta->bytes); } else { int32_t dataLen = varDataTLen(pData); - if (meta->type == TSDB_DATA_TYPE_JSON) { - if (*pData == TSDB_DATA_TYPE_NULL) { - dataLen = 0; - } else if (*pData == TSDB_DATA_TYPE_NCHAR) { - dataLen = varDataTLen(pData + sizeof(char)); - } else if (*pData == TSDB_DATA_TYPE_BIGINT || *pData == TSDB_DATA_TYPE_DOUBLE) { - dataLen = sizeof(int64_t); - } else if (*pData == TSDB_DATA_TYPE_BOOL) { - dataLen = sizeof(char); - } - dataLen += sizeof(char); - } + // This is a piece of code to help users implement udf. It is only called during testing. + // Currently, the json type is not supported and will not be called. + // if (meta->type == TSDB_DATA_TYPE_JSON) { + // if (*pData == TSDB_DATA_TYPE_NULL) { + // dataLen = 0; + // } else if (*pData == TSDB_DATA_TYPE_NCHAR) { + // dataLen = varDataTLen(pData + sizeof(char)); + // } else if (*pData == TSDB_DATA_TYPE_BIGINT || *pData == TSDB_DATA_TYPE_DOUBLE) { + // dataLen = sizeof(int64_t); + // } else if (*pData == TSDB_DATA_TYPE_BOOL) { + // dataLen = sizeof(char); + // } + // dataLen += sizeof(char); + // } if (data->varLenCol.payloadAllocLen < data->varLenCol.payloadLen + dataLen) { uint32_t newSize = data->varLenCol.payloadAllocLen; diff --git a/source/libs/function/test/change_udf.c b/source/libs/function/test/change_udf.c index 822c4da892..f623a3194d 100644 --- a/source/libs/function/test/change_udf.c +++ b/source/libs/function/test/change_udf.c @@ -106,3 +106,67 @@ DLL_EXPORT int32_t UDFNAME(SUdfDataBlock *block, SUdfColumn *resultCol) { #endif // ifdef CHANGE_UDF_PROCESS_FAILED } #endif // ifdef CHANGE_UDF_NO_PROCESS + + + + +/********************************************************************************************************************/ +// udf revert functions +/********************************************************************************************************************/ +DLL_EXPORT int32_t udf_reverse_init() { return 0; } + +DLL_EXPORT int32_t udf_reverse_destroy() { return 0; } + +static void reverse_data(char* data, size_t len) { + size_t i, j; + char temp; + for (i = 0, j = len - 1; i < j; i++, j--) { + temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } +} + +DLL_EXPORT int32_t udf_reverse(SUdfDataBlock *block, SUdfColumn *resultCol) { + int32_t code = 0; + SUdfColumnData *resultData = &resultCol->colData; + for (int32_t i = 0; i < block->numOfRows; ++i) { + int j = 0; + for (; j < block->numOfCols; ++j) { + if (udfColDataIsNull(block->udfCols[j], i)) { + code = udfColDataSetNull(resultCol, i); + if (code != 0) { + return code; + } + break; + } else { + int32_t oldLen = udfColDataGetDataLen(block->udfCols[j], i); + char *pOldData = udfColDataGetData(block->udfCols[j], i); + + + char *buff = malloc(sizeof(VarDataLenT) + oldLen); + if (buff == NULL) { + return -1; + } + ((VarDataLenT *)buff)[0] = (VarDataLenT)oldLen; + memcpy(buff, pOldData, oldLen + sizeof(VarDataLenT)); + reverse_data(buff + sizeof(VarDataLenT), oldLen); + code = udfColDataSet(resultCol, i, buff, false); + if (code != 0) { + free(buff); + return code; + } + } + } + } + // to simulate actual processing delay by udf +#ifdef LINUX + usleep(1 * 1000); // usleep takes sleep time in us (1 millionth of a second) +#endif +#ifdef WINDOWS + Sleep(1); +#endif + resultData->numOfRows = block->numOfRows; + return 0; +} + diff --git a/tests/pytest/util/tserror.py b/tests/pytest/util/tserror.py index c0f658209c..35d74153c3 100644 --- a/tests/pytest/util/tserror.py +++ b/tests/pytest/util/tserror.py @@ -8,3 +8,6 @@ TSDB_CODE_MND_FUNC_NOT_EXIST = (TAOS_DEF_ERROR_CODE | 0x0374) TSDB_CODE_UDF_FUNC_EXEC_FAILURE = (TAOS_DEF_ERROR_CODE | 0x290A) + + +TSDB_CODE_TSC_INTERNAL_ERROR = (TAOS_DEF_ERROR_CODE | 0x02FF) diff --git a/tests/system-test/0-others/udfTest.py b/tests/system-test/0-others/udfTest.py index 9bc7d4360c..165ac5bc7d 100644 --- a/tests/system-test/0-others/udfTest.py +++ b/tests/system-test/0-others/udfTest.py @@ -728,6 +728,38 @@ class TDTestCase: tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) tdLog.info(f"change udf test finished, using {lib_name}") + def test_change_udf_reverse(self): + tdSql.execute("create database if not exists db duration 100") + tdSql.execute("use db") + + func_name = "udf_reverse" + tdSql.execute(f"create function {func_name} as '%s' outputtype nchar(256)"%self.libchange_udf_normal) + functions = tdSql.getResult("show functions") + for function in functions: + if f"{func_name}" in function[0]: + tdLog.info(f"create {func_name} functions success, using {self.libchange_udf_normal}") + break + + tdSql.query(f"select {func_name}(c8) from db.t1") + tdSql.execute(f"drop function {func_name}") + tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) + + self.test_change_udf_normal("change_udf_normal") + tdSql.execute(f"create function {func_name} as '%s' outputtype varchar(256)"%self.libchange_udf_normal) + functions = tdSql.getResult("show functions") + for function in functions: + if f"{func_name}" in function[0]: + tdLog.info(f"create {func_name} functions success, using {self.libchange_udf_normal}") + break + + tdSql.query(f"select {func_name}(c8) from db.t1 order by ts") + tdSql.checkData(0,0, None) + tdSql.checkData(1,0, "1yranib") + tdSql.checkData(2,0, "2yranib") + tdSql.checkData(3,0, "3yranib") + + + def unexpected_using_test(self): tdSql.execute("use db ") @@ -768,6 +800,7 @@ class TDTestCase: self.unexpected_using_test() self.create_udf_function() + self.test_change_udf_reverse() self.basic_udf_query() self.loop_kill_udfd() tdSql.execute(" drop function udf1 ") From 20c1e28d0c56707972f667c1c1bc21f83bc61023 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Tue, 24 Dec 2024 10:08:02 +0800 Subject: [PATCH 44/55] fix:[TD-33272]add test case --- source/dnode/vnode/src/tq/tq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/dnode/vnode/src/tq/tq.c b/source/dnode/vnode/src/tq/tq.c index 37f3572f65..73052c1e5e 100644 --- a/source/dnode/vnode/src/tq/tq.c +++ b/source/dnode/vnode/src/tq/tq.c @@ -151,10 +151,8 @@ void tqClose(STQ* pTq) { taosHashCleanup(pTq->pOffset); taosMemoryFree(pTq->path); tqMetaClose(pTq); - - streamMetaClose(pTq->pStreamMeta); - qDebug("vgId:%d end to close tq", pTq->pStreamMeta != NULL ? pTq->pStreamMeta->vgId : -1); + streamMetaClose(pTq->pStreamMeta); taosMemoryFree(pTq); } From 7e21747c4ff962fd1e4864fe3678514ba5596491 Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Tue, 24 Dec 2024 14:17:37 +0800 Subject: [PATCH 45/55] ci(test):add slice state ut --- source/libs/stream/src/streamSliceState.c | 2 + .../libs/stream/test/streamSliceStateTest.cpp | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 source/libs/stream/test/streamSliceStateTest.cpp diff --git a/source/libs/stream/src/streamSliceState.c b/source/libs/stream/src/streamSliceState.c index eefe046878..976f806032 100644 --- a/source/libs/stream/src/streamSliceState.c +++ b/source/libs/stream/src/streamSliceState.c @@ -112,6 +112,7 @@ void clearSearchBuff(SStreamFileState* pFileState) { } } +#ifdef BUILD_NO_CALL int32_t getStateFromRocksdbByCur(SStreamFileState* pFileState, SStreamStateCur* pCur, SWinKey* pResKey, SRowBuffPos** ppPos, int32_t* pVLen, int32_t* pWinCode) { int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; @@ -135,6 +136,7 @@ _end: } return code; } +#endif int32_t getHashSortNextRow(SStreamFileState* pFileState, const SWinKey* pKey, SWinKey* pResKey, void** ppVal, int32_t* pVLen, int32_t* pWinCode) { diff --git a/source/libs/stream/test/streamSliceStateTest.cpp b/source/libs/stream/test/streamSliceStateTest.cpp new file mode 100644 index 0000000000..1d62b8ca7b --- /dev/null +++ b/source/libs/stream/test/streamSliceStateTest.cpp @@ -0,0 +1,75 @@ +#include +#include "tstream.h" +#include "streamInt.h" +#include "tcs.h" +#include "tglobal.h" +#include "streamState.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-arith" + + +SStreamState *stateCreate2(const char *path) { + SStreamTask *pTask = (SStreamTask *)taosMemoryCalloc(1, sizeof(SStreamTask)); + pTask->ver = 1024; + pTask->id.streamId = 1023; + pTask->id.taskId = 1111111; + SStreamMeta *pMeta = NULL; + + int32_t code = streamMetaOpen((path), NULL, NULL, NULL, 0, 0, NULL, &pMeta); + pTask->pMeta = pMeta; + + SStreamState *p = streamStateOpen((char *)path, pTask, 0, 0); + ASSERT(p != NULL); + return p; +} +void *backendOpen2() { + streamMetaInit(); + const char *path = "/tmp/streamslicestate/"; + SStreamState *p = stateCreate2(path); + ASSERT(p != NULL); + return p; +} + +TSKEY compareTs1(void* pKey) { + SWinKey* pWinKey = (SWinKey*)pKey; + return pWinKey->ts; +} + +TEST(getHashSortNextRowFn, getHashSortNextRowTest) { + void *pState = backendOpen2(); + SStreamFileState *pFileState = NULL; + int32_t code = streamFileStateInit(1024, sizeof(SWinKey), 10, 0, compareTs1, pState, INT64_MAX, "aaa", 123, + STREAM_STATE_BUFF_HASH, &pFileState); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SWinKey key1; + key1.groupId = 123; + key1.ts = 456; + char str[] = "abc"; + code = streamStateFillPut_rocksdb((SStreamState*)pState, &key1, str, sizeof(str)); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SWinKey key2; + key2.groupId = 123; + key2.ts = 460; + code = streamStateFillPut_rocksdb((SStreamState*)pState, &key2, str, sizeof(str)); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + SWinKey key3; + key3.groupId = 123; + void* pVal = NULL; + int32_t len = 0; + int32_t wincode = 0; + code = getHashSortNextRow(pFileState, &key1, &key3, &pVal, &len, &wincode); + ASSERT_EQ(code, TSDB_CODE_SUCCESS); + + ASSERT_EQ(key3.ts, key2.ts); +} From efde801b7e94f7a558f6bb04e3a553b9ce4bafce Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Tue, 24 Dec 2024 14:26:07 +0800 Subject: [PATCH 46/55] fix:[TD-33285]gmtime return error in windows --- source/os/src/osTime.c | 3 ++- source/os/test/osTimeTests.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/source/os/src/osTime.c b/source/os/src/osTime.c index 75cb2b91a2..3bab3e7e25 100644 --- a/source/os/src/osTime.c +++ b/source/os/src/osTime.c @@ -454,7 +454,8 @@ struct tm *taosGmTimeR(const time_t *timep, struct tm *result) { return NULL; } #ifdef WINDOWS - return gmtime_s(result, timep); + errno_t code = gmtime_s(result, timep); + return (code == 0) ? result : NULL; #else return gmtime_r(timep, result); #endif diff --git a/source/os/test/osTimeTests.cpp b/source/os/test/osTimeTests.cpp index 1d34587ad8..d1ce654a76 100644 --- a/source/os/test/osTimeTests.cpp +++ b/source/os/test/osTimeTests.cpp @@ -94,6 +94,35 @@ TEST(osTimeTests, taosLocalTime) { #endif } +TEST(osTimeTests, taosGmTimeR) { + // Test 1: Test when both timep and result are not NULL + time_t timep = 1617531000; // 2021-04-04 18:10:00 + struct tm tmInfo; + ASSERT_NE(taosGmTimeR(&timep, &tmInfo), nullptr); + + char buf[128]; + taosStrfTime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tmInfo); + ASSERT_STREQ(buf, "2021-04-04T10:10:00"); +} + +TEST(osTimeTests, taosTimeGm) { + char *timestr= "2021-04-04T18:10:00"; + struct tm tm = {0}; + + taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm); + int64_t seconds = taosTimeGm(&tm); + ASSERT_EQ(seconds, 1617559800); +} + +TEST(osTimeTests, taosMktime) { + char *timestr= "2021-04-04T18:10:00"; + struct tm tm = {0}; + + taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm); + time_t seconds = taosMktime(&tm, NULL); + ASSERT_EQ(seconds, 1617531000); +} + TEST(osTimeTests, invalidParameter) { void *retp = NULL; int32_t reti = 0; From 78b5396f861393e4ecc00876689a88d81b333da4 Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Tue, 24 Dec 2024 14:45:18 +0800 Subject: [PATCH 47/55] fix: test error --- tests/pytest/util/sql.py | 7 +++---- tests/system-test/0-others/udfTest.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/pytest/util/sql.py b/tests/pytest/util/sql.py index 46b7e1f795..bb7b8411f9 100644 --- a/tests/pytest/util/sql.py +++ b/tests/pytest/util/sql.py @@ -155,6 +155,9 @@ class TDSql: try: self.cursor.execute(sql) + self.queryResult = self.cursor.fetchall() + self.queryRows = len(self.queryResult) + self.queryCols = len(self.cursor.description) except BaseException as e: tdLog.info("err:%s" % (e)) expectErrNotOccured = False @@ -165,10 +168,6 @@ class TDSql: if expectErrNotOccured: tdLog.exit("%s(%d) failed: sql:%s, expect error not occured" % (caller.filename, caller.lineno, sql)) else: - self.queryRows = 0 - self.queryCols = 0 - self.queryResult = None - if fullMatched: if expectedErrno != None: expectedErrno_rest = expectedErrno & 0x0000ffff diff --git a/tests/system-test/0-others/udfTest.py b/tests/system-test/0-others/udfTest.py index 165ac5bc7d..8134327b41 100644 --- a/tests/system-test/0-others/udfTest.py +++ b/tests/system-test/0-others/udfTest.py @@ -740,7 +740,7 @@ class TDTestCase: tdLog.info(f"create {func_name} functions success, using {self.libchange_udf_normal}") break - tdSql.query(f"select {func_name}(c8) from db.t1") + tdSql.error(f"select {func_name}(c8) from db.t1", TSDB_CODE_TSC_INTERNAL_ERROR) tdSql.execute(f"drop function {func_name}") tdSql.error(f"select {func_name}(num1) from db.tb", TSDB_CODE_MND_FUNC_NOT_EXIST) From 367bffd3f93144b7edcc2370e1287eec77f15227 Mon Sep 17 00:00:00 2001 From: dmchen Date: Tue, 24 Dec 2024 09:23:34 +0000 Subject: [PATCH 48/55] fix/TD-33265-arbitrator-covarage-add-case --- tests/army/cluster/arbitrator.py | 81 +++++++++++++++++++++++++ tests/parallel_test/cases.task | 1 + tests/system-test/6-cluster/replica2.py | 22 +++++++ 3 files changed, 104 insertions(+) create mode 100644 tests/army/cluster/arbitrator.py diff --git a/tests/army/cluster/arbitrator.py b/tests/army/cluster/arbitrator.py new file mode 100644 index 0000000000..9fd8e7b1f3 --- /dev/null +++ b/tests/army/cluster/arbitrator.py @@ -0,0 +1,81 @@ +import taos +import sys +import os +import subprocess +import glob +import shutil +import time + +from frame.log import * +from frame.cases import * +from frame.sql import * +from frame.srvCtl import * +from frame.caseBase import * +from frame import * +from frame.autogen import * +from frame import epath +# from frame.server.dnodes import * +# from frame.server.cluster import * + + +class TDTestCase(TBase): + + def init(self, conn, logSql, replicaVar=1): + updatecfgDict = {'dDebugFlag':131} + super(TDTestCase, self).init(conn, logSql, replicaVar=1, checkColName="c1") + + self.valgrind = 0 + self.db = "test" + self.stb = "meters" + self.childtable_count = 10 + tdSql.init(conn.cursor(), logSql) + + def run(self): + tdSql.execute('CREATE DATABASE db vgroups 1 replica 2;') + + time.sleep(1) + + count = 0 + + while count < 100: + tdSql.query("show arbgroups;") + + if tdSql.getData(0, 4) == 1: + break + + tdLog.info("wait 1 seconds for is sync") + time.sleep(1) + + count += 1 + + + tdSql.query("show db.vgroups;") + + if(tdSql.getData(0, 4) == "follower") and (tdSql.getData(0, 6) == "leader"): + tdLog.info("stop dnode2") + sc.dnodeStop(2) + + if(tdSql.getData(0, 6) == "follower") and (tdSql.getData(0, 4) == "leader"): + tdLog.info("stop dnode 3") + sc.dnodeStop(3) + + + count = 0 + while count < 100: + tdSql.query("show db.vgroups;") + + if(tdSql.getData(0, 4) == "assigned ") or (tdSql.getData(0, 6) == "assigned "): + break + + tdLog.info("wait 1 seconds for set assigned") + time.sleep(1) + + count += 1 + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index c9d28e0623..fe3fbbb711 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -11,6 +11,7 @@ # ,,y,army,./pytest.sh python3 ./test.py -f multi-level/mlevel_basic.py -N 3 -L 3 -D 2 ,,y,army,./pytest.sh python3 ./test.py -f db-encrypt/basic.py -N 3 -M 3 +,,y,army,./pytest.sh python3 ./test.py -f cluster/arbitrator.py -N 3 ,,n,army,python3 ./test.py -f storage/s3/s3Basic.py -N 3 ,,y,army,./pytest.sh python3 ./test.py -f cluster/snapshot.py -N 3 -L 3 -D 2 ,,y,army,./pytest.sh python3 ./test.py -f query/function/test_func_elapsed.py diff --git a/tests/system-test/6-cluster/replica2.py b/tests/system-test/6-cluster/replica2.py index a90949c198..1cda2bb4e8 100644 --- a/tests/system-test/6-cluster/replica2.py +++ b/tests/system-test/6-cluster/replica2.py @@ -10,6 +10,8 @@ ################################################################### from util.cases import * from util.sql import * +from util.dnodes import * +from util.log import * class TDTestCase: def init(self, conn, logSql, replicaVar=1): @@ -20,6 +22,26 @@ class TDTestCase: def run(self): tdSql.execute('CREATE DATABASE db vgroups 1 replica 2;') + time.sleep(1) + + tdSql.query("show db.vgroups;") + + if(tdSql.queryResult[0][4] == "follower") and (tdSql.queryResult[0][6] == "leader"): + tdLog.info("stop dnode2") + sc.dnodeStop(2) + + if(tdSql.queryResult[0][6] == "follower") and (tdSql.queryResult[0][4] == "leader"): + tdLog.info("stop dnode 3") + sc.dnodeStop(3) + + tdLog.info("wait 10 seconds") + time.sleep(10) + + tdSql.query("show db.vgroups;") + + if(tdSql.queryResult[0][4] != "assigned") and (tdSql.queryResult[0][6] != "assigned"): + tdLog.exit("failed to set aasigned") + def stop(self): tdSql.close() tdLog.success(f"{__file__} successfully executed") From 27af7478719fe0627748e8725a2c3498edabf086 Mon Sep 17 00:00:00 2001 From: yingzhao Date: Sun, 22 Dec 2024 21:22:29 +0800 Subject: [PATCH 49/55] docs(grafana): integrate in explorer --- docs/zh/08-operation/05-monitor.md | 44 ++++++++++++++++++ docs/zh/08-operation/pic/grafana-apikey.png | Bin 0 -> 62579 bytes .../zh/08-operation/pic/grafana-dashboard.png | Bin 0 -> 111836 bytes 3 files changed, 44 insertions(+) create mode 100644 docs/zh/08-operation/pic/grafana-apikey.png create mode 100644 docs/zh/08-operation/pic/grafana-dashboard.png diff --git a/docs/zh/08-operation/05-monitor.md b/docs/zh/08-operation/05-monitor.md index abbd54736b..897f813872 100644 --- a/docs/zh/08-operation/05-monitor.md +++ b/docs/zh/08-operation/05-monitor.md @@ -145,3 +145,47 @@ toasX 的配置文件(默认 /etc/taos/taosx.toml) 中与 monitor 相关的配 #### 限制 只有在以 server 模式运行 taosX 时,与监控相关的配置才生效。 + +## explorer 集成监控面板 + +explorer 支持集成已有的 grafana dashboard。 + +### 配置 grafana + +编辑 grafana.ini, 修改以下配置项。配置 root_url, 可能对现有的 grafana 使用习惯有所影响,为了集成到 explorer 是需要如此配置的, 方便通过 explorer 做服务代理。 + +``` toml +[server] +# If you use reverse proxy and sub path specify full url (with sub path) +root_url = http://ip:3000/grafana +# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons. +serve_from_sub_path = true + +[security] +# set to true if you want to allow browsers to render Grafana in a ,