From 7d6cdcae85ad0007b2769dde9f74c3a46fc2a977 Mon Sep 17 00:00:00 2001 From: Feng Chao Date: Thu, 20 Mar 2025 16:12:34 +0800 Subject: [PATCH 01/28] ci: add tdgpt .c file into TDengine and TDgpt workflow --- .github/workflows/tdengine-test.yml | 1 + .github/workflows/tdgpt-test.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/tdengine-test.yml b/.github/workflows/tdengine-test.yml index 436eedd0e2..b981d005c4 100644 --- a/.github/workflows/tdengine-test.yml +++ b/.github/workflows/tdengine-test.yml @@ -12,6 +12,7 @@ on: - 'tools/tdgpt/**' - 'source/libs/executor/src/forecastoperator.c' - 'source/libs/executor/src/anomalywindowoperator.c' + - 'source/dnode/mnode/impl/src/mndAnode.c' - 'include/common/tanalytics.h' - 'source/common/src/tanalytics.c' - 'tests/parallel/tdgpt_cases.task' diff --git a/.github/workflows/tdgpt-test.yml b/.github/workflows/tdgpt-test.yml index 4bdebdad32..0db9cee11d 100644 --- a/.github/workflows/tdgpt-test.yml +++ b/.github/workflows/tdgpt-test.yml @@ -12,6 +12,7 @@ on: - 'tools/tdgpt/**' - 'source/libs/executor/src/forecastoperator.c' - 'source/libs/executor/src/anomalywindowoperator.c' + - 'source/dnode/mnode/impl/src/mndAnode.c' - 'include/common/tanalytics.h' - 'source/common/src/tanalytics.c' - 'tests/parallel/tdgpt_cases.task' From c1334899177e02a40f9995b6c16fa3d4edbfbcd2 Mon Sep 17 00:00:00 2001 From: Alex Duan <51781608+DuanKuanJun@users.noreply.github.com> Date: Thu, 20 Mar 2025 22:54:29 +0800 Subject: [PATCH 02/28] new-libtaos-with-ws (#29971) * enh: rename libtaos.so to libtaosinternal.so * enh: let python system-test work * enh: shell for libinternal.so * enh: refact script * enh: wrapper for libtaosinternal * enh: rename some files * enh: let shell support internal driver * enh: minor changes * enh: minor changes * add intenal.h * enh: remove unused codes * enh: minor changs * feat: mac os issues * enh: let python test use internal connection * enh: let nettest work * enh: let taosc -C work * enh: test shell in mac os * enh: minor changes * enh: let libtaosinternal.so work in linux * enh: update install script * enh: for ci * enh: for windows compile * enh: minor changes * enh: compile in windows * enh: minor changes * enh: taosinternal work in windows * enh: add taos_internal_static * enh: rollback os_for_wrapper * fix: conflicts * fix: conflicts * fix: compile errors * fix: conflicts * enh: rename taosinternal to taosnative * enh: rename taosinternal to taosnative * fix: compile error * enh: remove taosnative.h * fix: compile errors * enh: set default shell options * fix: compile errors * fix: compile errors * debug: switch taosws branch to feat/new-libtaos-with-ws * enh: taosBenchmark remove WEBSOCKET finished * fix: CMakeLists.txt remove WEBSOCKET * fix: compile errors * fix: taosBenchmark delete restful code * .gitignore remove taos-tools folder * fix: remove taosdump WEBSOCKET MACRO * fix: build error for taosdump * fix: build project passed * fix: support -Z for connect mode * fix: build error * fix: build error fixed * fix: add -Z options * fix: native and websocket with string * fix: -Z option core * fix: build unit test * fix: build error * fix: add colon for array * fix: unit test can not include fun * fix: CTest pointer null is nullptr * fix: include pub.h * fix: taosdump add -Z --driver options * fix: taosdump support -Z with pub.h pub.c * fix: toolsGetTimeDay move to pub.c * fix: restore pub.c only simple fun * fix: add error tips * fix: tmfree remove from taosdump * fix: remove double declare taos variant * fix: taos support -Z option * enh: configDir set with main fun * fix: add g_arguments.configDir * fix: show tips add cfgdir * fix: g_argument is pointer * fix: configDir is global var * fix: declare g_configDir in benchMain.c * fix: taos version not show on websocket * stmt2 websocket prepare with supertable * stmt2 websocket prepare build * fix: stmt and stmt2 prepare add db name * fix: remove -R --restful test case * fix: taosBenchmark adjust priority cmd > json > evn * fix: add connect mode test case connMode.py * fix: clear evn and add host port check * fix: army/test.py modify start taosAdapter is default * change: system-test/test.py default start taosAdapter * fix: add taosAdapter variant to system-test/test.py * fix: -y must put behind other options * fix: remove rest sml and add -N normal case * fix: add -c work cfg test case * del: queryMain.py remove rest query * fix: remove groups have a blank append bug * fix: caseBase.py add db in sql query * fix: query_json.py remove rest test * fix: taosBenchmark uniform dsn describe * fix: add pub.h pub.c to tools public * fix: case remove restful interface * fix: build error * fix: taosDriverCleanup no arg call * fix: taosdump add test conn mode case taosdumpCommandline.py * fix: modify insertFullType.json db name * fix: taosdump connMode test case taosDumpCommandline.py passed * enh: priority cmd > env > json * fix: taosCli remove is_native variant * fix: password is not pointer * fix: comment -o test case * fix: solve fun return code check * fix: windows unresolved strcasecmp * fix: remove coverHostToServAddr * fix: forbid check ODR violation * ci: trigger pr run * fix: build error not del >>>>>3.0 * fix: support json dbinfo->vgroups have blank space * fix: solve conflict with merge * fix: with TrimCaseCmp fun to compare vgroups * fix: del vgroups support blank code * feat: wrapper add taos_fetch_fields_e * fix: move jni from libtaosnative.so to libtaos.so * fix: move clientTmqConnector.c for jni * fix: fix assert check with del comment code * fix: taosBenchmark add prepare stmt debug log * fix: stmt2 already have debug log on preapare * fix: (double)LLONG_MAX force covert * fix: stmt insert normal table with websocket * fix: normal table with stmt too many ? * fix: taosdump stmt_prepare with child tbname * fix: build error add int code * feat: stmtPrepare with child table to do * taos -a options move to native test case * fix:unit test benchmarkTest passed * fix: query_json-with-sqlfile.py case no check results * fix: queryMain.py case lost, put in tasks again --------- Co-authored-by: Shengliang Guan --- .gitignore | 1 - Jenkinsfile2 | 3 + cmake/cmake.define | 10 +- cmake/taosws_CMakeLists.txt.in | 2 +- docs/en/14-reference/05-connector/10-cpp.md | 2 +- docs/en/14-reference/09-error-code.md | 2 + docs/zh/14-reference/05-connector/10-cpp.mdx | 2 +- docs/zh/14-reference/09-error-code.md | 2 + examples/c/CMakeLists.txt | 12 +- include/client/taos.h | 31 +- include/os/os.h | 1 + include/os/osDir.h | 4 +- include/os/osSystem.h | 4 +- include/util/taoserror.h | 2 + packaging/check_package.sh | 4 + packaging/deb/DEBIAN/preinst | 1 + packaging/deb/DEBIAN/prerm | 2 + packaging/deb/makedeb.sh | 4 +- packaging/rpm/tdengine.spec | 6 +- packaging/tools/install.sh | 6 + packaging/tools/install_client.sh | 11 +- packaging/tools/make_install.bat | 5 + packaging/tools/make_install.sh | 21 + packaging/tools/makeclient.sh | 3 + packaging/tools/makepkg.sh | 4 +- packaging/tools/post.sh | 6 + packaging/tools/preun.sh | 2 + packaging/tools/remove.sh | 2 + packaging/tools/remove_client.sh | 2 + source/client/CMakeLists.txt | 34 +- source/client/src/clientEnv.c | 2 +- source/client/src/taos.rc.in | 4 +- source/client/src/taosnative.rc.in | 31 + source/client/test/CMakeLists.txt | 16 +- source/client/wrapper/CMakeLists.txt | 67 + source/client/wrapper/inc/wrapper.h | 232 ++ .../jni/com_taosdata_jdbc_TSDBJNIConnector.h | 0 .../jni/com_taosdata_jdbc_tmq_TMQConnector.h | 0 source/client/{ => wrapper}/jni/jniCommon.h | 0 .../jni/linux/AWTCocoaComponent.h | 0 source/client/{ => wrapper}/jni/linux/JDWP.h | 0 .../{ => wrapper}/jni/linux/JDWPCommands.h | 0 .../client/{ => wrapper}/jni/linux/JavaVM.h | 0 .../jni/linux/NSJavaConfiguration.h | 0 .../jni/linux/NSJavaVirtualMachine.h | 0 source/client/{ => wrapper}/jni/linux/jawt.h | 101 - .../client/{ => wrapper}/jni/linux/jawt_md.h | 0 .../{ => wrapper}/jni/linux/jdwpTransport.h | 0 source/client/{ => wrapper}/jni/linux/jni.h | 0 .../client/{ => wrapper}/jni/linux/jni_md.h | 0 source/client/{ => wrapper}/jni/linux/jvmti.h | 0 .../jni/windows/classfile_constants.h | 0 .../client/{ => wrapper}/jni/windows/jawt.h | 81 - .../{ => wrapper}/jni/windows/jdwpTransport.h | 0 source/client/{ => wrapper}/jni/windows/jni.h | 0 .../client/{ => wrapper}/jni/windows/jvmti.h | 0 .../{ => wrapper}/jni/windows/jvmticmlr.h | 0 .../win32/bridge/AccessBridgeCallbacks.h | 0 .../windows/win32/bridge/AccessBridgeCalls.c | 0 .../windows/win32/bridge/AccessBridgeCalls.h | 0 .../win32/bridge/AccessBridgePackages.h | 0 .../{ => wrapper}/jni/windows/win32/jawt_md.h | 0 .../{ => wrapper}/jni/windows/win32/jni_md.h | 0 .../{ => wrapper}/src/clientJniConnector.c | 0 .../{ => wrapper}/src/clientTmqConnector.c | 0 source/client/wrapper/src/wrapperDriver.c | 271 +++ source/client/wrapper/src/wrapperFunc.c | 870 ++++++++ source/client/wrapper/src/wrapperVariable.c | 205 ++ source/dnode/mgmt/node_util/CMakeLists.txt | 2 +- source/libs/catalog/test/CMakeLists.txt | 6 +- source/libs/executor/test/CMakeLists.txt | 2 +- source/libs/scheduler/test/CMakeLists.txt | 11 +- source/os/CMakeLists.txt | 2 + source/os/src/osDir.c | 75 +- source/os/src/osSystem.c | 32 - source/util/src/terror.c | 3 +- source/util/src/tlog.c | 4 + source/util/test/errorCodeTable.ini | 2 + tests/army/cmdline/taosCli.py | 199 +- tests/army/frame/caseBase.py | 88 +- tests/army/frame/etool.py | 8 + tests/army/pytest.sh | 4 + tests/army/test.py | 6 +- .../benchmark/basic/commandline-sml-rest.py | 75 - .../tools/benchmark/basic/commandline-sml.py | 10 + .../army/tools/benchmark/basic/commandline.py | 19 +- tests/army/tools/benchmark/basic/connMode.py | 158 ++ .../tools/benchmark/basic/json/TD-31490.json | 2 +- .../tools/benchmark/basic/json/TS-5002.json | 2 +- .../basic/json/connModePriority.json | 65 + .../basic/json/connModePriorityErrDsn.json | 60 + .../basic/json/connModePriorityErrHost.json | 64 + .../basic/json/queryInsertrestdata.json | 73 - .../benchmark/basic/json/queryRestful.json | 27 - .../benchmark/basic/json/queryRestful1.json | 24 - .../basic/json/taosc_query-sqlfile.json | 2 +- tests/army/tools/benchmark/basic/queryMain.py | 22 +- .../basic/query_json-with-sqlfile.py | 10 +- .../army/tools/benchmark/basic/query_json.py | 42 +- .../taosdemoTestQueryWithJson-mixed-query.py | 43 - .../basic/taosdemoTestQueryWithJson.py | 39 - .../taosdump/native/json/insertFullType.json | 8 +- .../taosdump/native/json/insertOther.json | 70 - .../taosdump/native/taosdumpCommandline.py | 109 +- tests/develop-test/test.py | 2 + tests/parallel_test/cases.task | 21 +- tests/parallel_test/run_case.sh | 8 + tests/pytest/auto_run_regular.sh | 2 + tests/pytest/auto_run_valgrind.sh | 2 + tests/pytest/auto_run_valgrind_cluster.sh | 2 + tests/pytest/dockerCluster/Dockerfile | 1 + tests/system-test/pytest.sh | 3 + tests/system-test/test.py | 18 +- tests/taosc_test/CMakeLists.txt | 2 +- tools/inc/pub.h | 74 + tools/shell/CMakeLists.txt | 46 +- tools/shell/inc/shellAuto.h | 5 +- tools/shell/inc/shellInt.h | 51 +- tools/shell/inc/shellTire.h | 4 +- tools/shell/src/shellArguments.c | 149 +- tools/shell/src/shellAuto.c | 4 +- tools/shell/src/shellEngine.c | 161 +- tools/shell/src/shellMain.c | 70 +- tools/shell/src/shellNettest.c | 28 +- tools/shell/src/shellUtil.c | 63 +- tools/shell/src/shellWebsocket.c | 396 ---- tools/src/pub.c | 91 + .../deps/toolscJson/src/toolscJson.c | 6 +- tools/taos-tools/inc/bench.h | 52 +- tools/taos-tools/inc/benchData.h | 4 +- tools/taos-tools/inc/benchLog.h | 1 - tools/taos-tools/inc/dump.h | 20 +- tools/taos-tools/inc/dumpUtil.h | 14 - tools/taos-tools/inc/wsdump.h | 42 - tools/taos-tools/src/CMakeLists.txt | 85 +- tools/taos-tools/src/benchCommandOpt.c | 122 +- tools/taos-tools/src/benchData.c | 50 +- tools/taos-tools/src/benchInsert.c | 590 +---- tools/taos-tools/src/benchJsonOpt.c | 132 +- tools/taos-tools/src/benchMain.c | 129 +- tools/taos-tools/src/benchQuery.c | 65 +- tools/taos-tools/src/benchSys.c | 57 +- tools/taos-tools/src/benchUtil.c | 737 +------ tools/taos-tools/src/dumpUtil.c | 222 +- tools/taos-tools/src/taosdump.c | 1133 +++------- tools/taos-tools/src/wsdump.c | 1939 ----------------- tools/taos-tools/test/CMakeLists.txt | 5 +- tools/taos-tools/test/benchmarkTest.cpp | 48 +- utils/test/c/CMakeLists.txt | 37 +- utils/tsim/CMakeLists.txt | 2 +- utils/tsim/src/simEntry.c | 2 + 151 files changed, 4007 insertions(+), 6129 deletions(-) create mode 100644 source/client/src/taosnative.rc.in create mode 100644 source/client/wrapper/CMakeLists.txt create mode 100644 source/client/wrapper/inc/wrapper.h rename source/client/{ => wrapper}/jni/com_taosdata_jdbc_TSDBJNIConnector.h (100%) rename source/client/{ => wrapper}/jni/com_taosdata_jdbc_tmq_TMQConnector.h (100%) rename source/client/{ => wrapper}/jni/jniCommon.h (100%) rename source/client/{ => wrapper}/jni/linux/AWTCocoaComponent.h (100%) rename source/client/{ => wrapper}/jni/linux/JDWP.h (100%) rename source/client/{ => wrapper}/jni/linux/JDWPCommands.h (100%) rename source/client/{ => wrapper}/jni/linux/JavaVM.h (100%) rename source/client/{ => wrapper}/jni/linux/NSJavaConfiguration.h (100%) rename source/client/{ => wrapper}/jni/linux/NSJavaVirtualMachine.h (100%) rename source/client/{ => wrapper}/jni/linux/jawt.h (63%) rename source/client/{ => wrapper}/jni/linux/jawt_md.h (100%) rename source/client/{ => wrapper}/jni/linux/jdwpTransport.h (100%) rename source/client/{ => wrapper}/jni/linux/jni.h (100%) rename source/client/{ => wrapper}/jni/linux/jni_md.h (100%) rename source/client/{ => wrapper}/jni/linux/jvmti.h (100%) rename source/client/{ => wrapper}/jni/windows/classfile_constants.h (100%) rename source/client/{ => wrapper}/jni/windows/jawt.h (73%) rename source/client/{ => wrapper}/jni/windows/jdwpTransport.h (100%) rename source/client/{ => wrapper}/jni/windows/jni.h (100%) rename source/client/{ => wrapper}/jni/windows/jvmti.h (100%) rename source/client/{ => wrapper}/jni/windows/jvmticmlr.h (100%) rename source/client/{ => wrapper}/jni/windows/win32/bridge/AccessBridgeCallbacks.h (100%) rename source/client/{ => wrapper}/jni/windows/win32/bridge/AccessBridgeCalls.c (100%) rename source/client/{ => wrapper}/jni/windows/win32/bridge/AccessBridgeCalls.h (100%) rename source/client/{ => wrapper}/jni/windows/win32/bridge/AccessBridgePackages.h (100%) rename source/client/{ => wrapper}/jni/windows/win32/jawt_md.h (100%) rename source/client/{ => wrapper}/jni/windows/win32/jni_md.h (100%) rename source/client/{ => wrapper}/src/clientJniConnector.c (100%) rename source/client/{ => wrapper}/src/clientTmqConnector.c (100%) create mode 100644 source/client/wrapper/src/wrapperDriver.c create mode 100644 source/client/wrapper/src/wrapperFunc.c create mode 100644 source/client/wrapper/src/wrapperVariable.c delete mode 100644 tests/army/tools/benchmark/basic/commandline-sml-rest.py create mode 100644 tests/army/tools/benchmark/basic/connMode.py create mode 100644 tests/army/tools/benchmark/basic/json/connModePriority.json create mode 100644 tests/army/tools/benchmark/basic/json/connModePriorityErrDsn.json create mode 100644 tests/army/tools/benchmark/basic/json/connModePriorityErrHost.json delete mode 100644 tests/army/tools/benchmark/basic/json/queryInsertrestdata.json delete mode 100644 tests/army/tools/benchmark/basic/json/queryRestful.json delete mode 100644 tests/army/tools/benchmark/basic/json/queryRestful1.json delete mode 100644 tests/army/tools/taosdump/native/json/insertOther.json create mode 100644 tools/inc/pub.h delete mode 100644 tools/shell/src/shellWebsocket.c create mode 100644 tools/src/pub.c delete mode 100644 tools/taos-tools/inc/wsdump.h delete mode 100644 tools/taos-tools/src/wsdump.c diff --git a/.gitignore b/.gitignore index aa1f567bf7..6a7a631e78 100644 --- a/.gitignore +++ b/.gitignore @@ -59,7 +59,6 @@ tools/upx* html/ /.vs /CMakeFiles/3.10.2 -/CMakeCache.txt /Makefile /*.cmake /src/cq/test/CMakeFiles/cqtest.dir/*.cmake diff --git a/Jenkinsfile2 b/Jenkinsfile2 index 8853d068cb..aa9d5e0701 100644 --- a/Jenkinsfile2 +++ b/Jenkinsfile2 @@ -361,6 +361,7 @@ def pre_test_build_win() { pip3 install taospy==2.7.21 pip3 install taos-ws-py==0.3.8 xcopy /e/y/i/f %WIN_INTERNAL_ROOT%\\debug\\build\\lib\\taos.dll C:\\Windows\\System32 + xcopy /e/y/i/f %WIN_INTERNAL_ROOT%\\debug\\build\\lib\\taosnative.dll C:\\Windows\\System32 ''' return 1 } @@ -379,7 +380,9 @@ def run_win_test() { bat ''' echo "windows test ..." xcopy /e/y/i/f %WIN_INTERNAL_ROOT%\\debug\\build\\lib\\taos.dll C:\\Windows\\System32 + xcopy /e/y/i/f %WIN_INTERNAL_ROOT%\\debug\\build\\lib\\taosnative.dll C:\\Windows\\System32 ls -l C:\\Windows\\System32\\taos.dll + ls -l C:\\Windows\\System32\\taosnative.dll time /t cd %WIN_SYSTEM_TEST_ROOT% echo "testing ..." diff --git a/cmake/cmake.define b/cmake/cmake.define index 3770f1f3b0..043a6f6263 100644 --- a/cmake/cmake.define +++ b/cmake/cmake.define @@ -97,14 +97,10 @@ ELSE() SET(TD_TAOS_TOOLS TRUE) ENDIF() -SET(TAOS_LIB taos) +SET(TAOS_LIB taos) SET(TAOS_LIB_STATIC taos_static) - -IF(${TD_WINDOWS}) - SET(TAOS_LIB_PLATFORM_SPEC taos_static) -ELSE() - SET(TAOS_LIB_PLATFORM_SPEC taos) -ENDIF() +SET(TAOS_NATIVE_LIB taosnative) +SET(TAOS_NATIVE_LIB_STATIC taosnative_static) # build TSZ by default IF("${TSZ_ENABLED}" MATCHES "false") diff --git a/cmake/taosws_CMakeLists.txt.in b/cmake/taosws_CMakeLists.txt.in index b013d45911..b23c92cef9 100644 --- a/cmake/taosws_CMakeLists.txt.in +++ b/cmake/taosws_CMakeLists.txt.in @@ -2,7 +2,7 @@ # taosws-rs ExternalProject_Add(taosws-rs GIT_REPOSITORY https://github.com/taosdata/taos-connector-rust.git - GIT_TAG main + GIT_TAG feat/new-libtaos-with-ws SOURCE_DIR "${TD_SOURCE_DIR}/tools/taosws-rs" BINARY_DIR "" #BUILD_IN_SOURCE TRUE diff --git a/docs/en/14-reference/05-connector/10-cpp.md b/docs/en/14-reference/05-connector/10-cpp.md index fc8f0168d2..ade5d58963 100644 --- a/docs/en/14-reference/05-connector/10-cpp.md +++ b/docs/en/14-reference/05-connector/10-cpp.md @@ -682,7 +682,7 @@ The basic API is used to establish database connections and provide a runtime en - **Interface Description**: Cleans up the runtime environment, should be called before the application exits. - `int taos_options(TSDB_OPTION option, const void * arg, ...)` - - **Interface Description**: Sets client options, currently supports locale (`TSDB_OPTION_LOCALE`), character set (`TSDB_OPTION_CHARSET`), timezone (`TSDB_OPTION_TIMEZONE`), and configuration file path (`TSDB_OPTION_CONFIGDIR`). Locale, character set, and timezone default to the current settings of the operating system. + - **Interface Description**: Sets client options, currently supports locale (`TSDB_OPTION_LOCALE`), character set (`TSDB_OPTION_CHARSET`), timezone (`TSDB_OPTION_TIMEZONE`), configuration file path (`TSDB_OPTION_CONFIGDIR`), and driver type (`TSDB_OPTION_DRIVER`). Locale, character set, and timezone default to the current settings of the operating system. The driver type can be either the native interface(`native`) or the WebSocket interface(`websocket`), with the default being `websocket`. - **Parameter Description**: - `option`: [Input] Setting item type. - `arg`: [Input] Setting item value. diff --git a/docs/en/14-reference/09-error-code.md b/docs/en/14-reference/09-error-code.md index 9307b7f240..139f8d38d7 100644 --- a/docs/en/14-reference/09-error-code.md +++ b/docs/en/14-reference/09-error-code.md @@ -41,6 +41,8 @@ This document details the server error codes that may be encountered when using | 0x80000107 | Ref ID is removed | The referenced ref resource has been released | Preserve the scene and logs, report issue on github | | 0x80000108 | Invalid Ref ID | Invalid ref ID | Preserve the scene and logs, report issue on github | | 0x8000010A | Ref is not there | ref information does not exist | Preserve the scene and logs, report issue on github | +| 0x8000010B | Driver was not loaded | libtaosnative.so or libtaosws.so was not found in the system path | Reinstall the client driver | +| 0x8000010C | Function was not loaded from the driver | some function defined in libtaos.so are not implemented in libtaosnative.so or libtaosws.so | Reinstall the client driver | | 0x80000110 | Unexpected generic error | System internal error | Preserve the scene and logs, report issue on github | | 0x80000111 | Action in progress | Operation in progress | 1. Wait for the operation to complete 2. Cancel the operation if necessary 3. If it exceeds a reasonable time and still not completed, preserve the scene and logs, or contact customer support | | 0x80000112 | Out of range | Configuration parameter exceeds allowed value range | Change the parameter | diff --git a/docs/zh/14-reference/05-connector/10-cpp.mdx b/docs/zh/14-reference/05-connector/10-cpp.mdx index 14dfe45a6c..977c259b49 100644 --- a/docs/zh/14-reference/05-connector/10-cpp.mdx +++ b/docs/zh/14-reference/05-connector/10-cpp.mdx @@ -680,7 +680,7 @@ TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一 - **接口说明**:清理运行环境,应用退出前应调用。 - `int taos_options(TSDB_OPTION option, const void * arg, ...)` - - **接口说明**:设置客户端选项,支持区域设置(`TSDB_OPTION_LOCALE`)、字符集设置(`TSDB_OPTION_CHARSET`)、时区设置(`TSDB_OPTION_TIMEZONE`)、配置文件路径设置(`TSDB_OPTION_CONFIGDIR`)。区域设置、字符集、时区默认为操作系统当前设置。 + - **接口说明**:设置客户端选项,支持区域设置(`TSDB_OPTION_LOCALE`)、字符集设置(`TSDB_OPTION_CHARSET`)、时区设置(`TSDB_OPTION_TIMEZONE`)、配置文件路径设置(`TSDB_OPTION_CONFIGDIR`)、驱动类型设置(`TSDB_OPTION_DRIVER`)。区域设置、字符集、时区默认为操作系统当前设置。驱动类型可选内部原生接口(`native`)和 WebSocket 接口(`websocket`),默认为 `websocket`。 - **参数说明**: - `option`:[入参] 设置项类型。 - `arg`:[入参] 设置项值。 diff --git a/docs/zh/14-reference/09-error-code.md b/docs/zh/14-reference/09-error-code.md index e2bf5b2776..7a87e1ddfb 100644 --- a/docs/zh/14-reference/09-error-code.md +++ b/docs/zh/14-reference/09-error-code.md @@ -44,6 +44,8 @@ description: TDengine 服务端的错误码列表和详细说明 | 0x80000107 | Ref ID is removed | 引用的 ref 资源已经释放 | 保留现场和日志,github 上报 issue | | 0x80000108 | Invalid Ref ID | 无效 ref ID | 保留现场和日志,github 上报 issue | | 0x8000010A | Ref is not there | ref 信息不存在 | 保留现场和日志,github 上报 issue | +| 0x8000010B | Driver was not loaded | 未在系统路径中找到 libtaosnative.so 或 libtaosws.so | 重新安装客户端驱动 | +| 0x8000010C | Function was not loaded from the driver | 在 libtaos.so 中定义的一些函数在 libtaosnative.so 或 libtaosws.so 中未实现 | 保留现场和日志,github 上报 issue | | 0x80000110 | Unexpected generic error | 系统内部错误 | 保留现场和日志,github 上报 issue | | 0x80000111 | Action in progress | 操作进行中 | 1.等待操作完成 2.根据需要取消操作 3.当超出合理时间仍然未完成可保留现场和日志,或联系客户支持 | | 0x80000112 | Out of range | 配置参数超出允许值范围 | 更改参数 | diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index e3c992f53f..94297272f7 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -42,27 +42,27 @@ IF(TD_LINUX) ) target_link_libraries(tmq - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) target_link_libraries(stream_demo - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) target_link_libraries(schemaless - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) target_link_libraries(prepare - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) target_link_libraries(demo - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) target_link_libraries(asyncdemo - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} ) SET_TARGET_PROPERTIES(tmq PROPERTIES OUTPUT_NAME tmq) diff --git a/include/client/taos.h b/include/client/taos.h index 919ace9fc4..1120bd1d97 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -62,6 +62,7 @@ typedef enum { TSDB_OPTION_CONFIGDIR, TSDB_OPTION_SHELL_ACTIVITY_TIMER, TSDB_OPTION_USE_ADAPTER, + TSDB_OPTION_DRIVER, TSDB_MAX_OPTIONS } TSDB_OPTION; @@ -155,11 +156,14 @@ typedef enum { TAOS_NOTIFY_USER_DROPPED = 2, } TAOS_NOTIFY_TYPE; +/* -- implemented in the native interface, for internal component only, the API may change -- */ #define RET_MSG_LENGTH 1024 typedef struct setConfRet { SET_CONF_RET_CODE retCode; char retMsg[RET_MSG_LENGTH]; } setConfRet; +DLL_EXPORT setConfRet taos_set_config(const char *config); // implemented in the native interface +/* -- end -- */ typedef struct TAOS_VGROUP_HASH_INFO { int32_t vgId; @@ -182,14 +186,13 @@ typedef struct TAOS_STMT_OPTIONS { bool singleTableBindOnce; } TAOS_STMT_OPTIONS; -DLL_EXPORT void taos_cleanup(void); -DLL_EXPORT int taos_options(TSDB_OPTION option, const void *arg, ...); -DLL_EXPORT int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...); -DLL_EXPORT setConfRet taos_set_config(const char *config); -DLL_EXPORT int taos_init(void); -DLL_EXPORT TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port); -DLL_EXPORT TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port); -DLL_EXPORT void taos_close(TAOS *taos); +DLL_EXPORT int taos_init(void); +DLL_EXPORT void taos_cleanup(void); +DLL_EXPORT int taos_options(TSDB_OPTION option, const void *arg, ...); +DLL_EXPORT int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...); +DLL_EXPORT TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port); +DLL_EXPORT TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port); +DLL_EXPORT void taos_close(TAOS *taos); DLL_EXPORT const char *taos_data_type(int type); @@ -220,6 +223,7 @@ DLL_EXPORT char *taos_stmt_errstr(TAOS_STMT *stmt); DLL_EXPORT int taos_stmt_affected_rows(TAOS_STMT *stmt); DLL_EXPORT int taos_stmt_affected_rows_once(TAOS_STMT *stmt); +/* -- implemented in the native interface, for internal component only, the API may change -- */ typedef void TAOS_STMT2; typedef struct TAOS_STMT2_OPTION { @@ -257,6 +261,7 @@ DLL_EXPORT int taos_stmt2_get_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_AL DLL_EXPORT void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields); DLL_EXPORT TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt); DLL_EXPORT char *taos_stmt2_error(TAOS_STMT2 *stmt); +/* -- end -- */ DLL_EXPORT TAOS_RES *taos_query(TAOS *taos, const char *sql); DLL_EXPORT TAOS_RES *taos_query_with_reqid(TAOS *taos, const char *sql, int64_t reqId); @@ -313,9 +318,11 @@ DLL_EXPORT void taos_set_hb_quit(int8_t quitByKill); DLL_EXPORT int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type); +/* -- implemented in the native interface, for internal component only, the API may change -- */ typedef void (*__taos_async_whitelist_fn_t)(void *param, int code, TAOS *taos, int numOfWhiteLists, uint64_t *pWhiteLists); DLL_EXPORT void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param); +/* ---- end ---- */ typedef enum { TAOS_CONN_MODE_BI = 0, @@ -414,7 +421,7 @@ DLL_EXPORT int32_t tmq_get_vgroup_id(TAOS_RES *res); DLL_EXPORT int64_t tmq_get_vgroup_offset(TAOS_RES *res); DLL_EXPORT const char *tmq_err2str(int32_t code); -/* ------------------------------ TAOSX INTERFACE -----------------------------------*/ +/* -- implemented in the native interface, for internal component(TAOSX) only, the API may change -- */ typedef struct tmq_raw_data { void *raw; uint32_t raw_len; @@ -435,8 +442,9 @@ DLL_EXPORT void tmq_free_raw(tmq_raw_data raw); // Returning null means error. Returned result need to be freed by tmq_free_json_meta DLL_EXPORT char *tmq_get_json_meta(TAOS_RES *res); DLL_EXPORT void tmq_free_json_meta(char *jsonMeta); -/* ---------------------------- TAOSX END -------------------------------- */ +/* ---- end ---- */ +/* -- implemented in the native interface, for internal component only, the API may change -- */ typedef enum { TSDB_SRV_STATUS_UNAVAILABLE = 0, TSDB_SRV_STATUS_NETWORK_OK = 1, @@ -446,7 +454,10 @@ typedef enum { } TSDB_SERVER_STATUS; DLL_EXPORT TSDB_SERVER_STATUS taos_check_server_status(const char *fqdn, int port, char *details, int maxlen); +DLL_EXPORT void taos_write_crashinfo(int signum, void *sigInfo, void *context); DLL_EXPORT char *getBuildInfo(); +/* ---- end ---- */ + #ifdef __cplusplus } #endif diff --git a/include/os/os.h b/include/os/os.h index 94edcdad75..98ff17359a 100644 --- a/include/os/os.h +++ b/include/os/os.h @@ -54,6 +54,7 @@ extern "C" { #include #if defined(DARWIN) +#include #else #if !defined(TD_ASTRA) #include diff --git a/include/os/osDir.h b/include/os/osDir.h index 6d32ab36ce..6ebfad72be 100644 --- a/include/os/osDir.h +++ b/include/os/osDir.h @@ -112,7 +112,9 @@ bool taosDirEntryIsDir(TdDirEntryPtr pDirEntry); char *taosGetDirEntryName(TdDirEntryPtr pDirEntry); int32_t taosCloseDir(TdDirPtr *ppDir); -int taosGetDirSize(const char *path, int64_t *size); +int32_t taosAppPath(char *path, int32_t maxLen); +int32_t taosGetDirSize(const char *path, int64_t *size); + #ifdef __cplusplus } #endif diff --git a/include/os/osSystem.h b/include/os/osSystem.h index 06f23eec0f..694bbf4085 100644 --- a/include/os/osSystem.h +++ b/include/os/osSystem.h @@ -46,10 +46,12 @@ int32_t taosEOFCmd(TdCmdPtr pCmd); void taosCloseCmd(TdCmdPtr *ppCmd); -void *taosLoadDll(const char *filename); +void *taosLoadDll(const char *fileName); void taosCloseDll(void *handle); +void *taosLoadDllFunc(void *handle, const char *funcName); + int32_t taosSetConsoleEcho(bool on); int32_t taosSetTerminalMode(); diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 1a9a5583df..9cd21ad577 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -117,6 +117,8 @@ int32_t taosGetErrSize(); #define TSDB_CODE_REF_INVALID_ID TAOS_DEF_ERROR_CODE(0, 0x0108) // internal #define TSDB_CODE_REF_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x0109) // internal #define TSDB_CODE_REF_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x010A) // internal +#define TSDB_CODE_DLL_NOT_LOAD TAOS_DEF_ERROR_CODE(0, 0x010B) +#define TSDB_CODE_DLL_FUNC_NOT_LOAD TAOS_DEF_ERROR_CODE(0, 0x010C) #define TSDB_CODE_APP_ERROR TAOS_DEF_ERROR_CODE(0, 0x0110) // #define TSDB_CODE_ACTION_IN_PROGRESS TAOS_DEF_ERROR_CODE(0, 0x0111) // internal diff --git a/packaging/check_package.sh b/packaging/check_package.sh index 5c3a2f9267..2179b64f3b 100644 --- a/packaging/check_package.sh +++ b/packaging/check_package.sh @@ -152,10 +152,14 @@ function check_lib_path() { # check all links check_link ${lib_link_dir}/libtaos.so check_link ${lib_link_dir}/libtaos.so.1 + check_link ${lib_link_dir}/libtaosnative.so + check_link ${lib_link_dir}/libtaosnative.so.1 if [[ -d ${lib64_link_dir} ]]; then check_link ${lib64_link_dir}/libtaos.so check_link ${lib64_link_dir}/libtaos.so.1 + check_link ${lib64_link_dir}/libtaosnative.so + check_link ${lib64_link_dir}/libtaosnative.so.1 fi echo -e "Check lib path:\033[32mOK\033[0m!" } diff --git a/packaging/deb/DEBIAN/preinst b/packaging/deb/DEBIAN/preinst index 904a946e20..b223dbf3d8 100644 --- a/packaging/deb/DEBIAN/preinst +++ b/packaging/deb/DEBIAN/preinst @@ -80,4 +80,5 @@ fi # there can not libtaos.so*, otherwise ln -s error ${csudo}rm -f ${install_main_dir}/driver/libtaos.* || : +${csudo}rm -f ${install_main_dir}/driver/libtaosnative.* || : [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}rm -f ${install_main_dir}/driver/libtaosws.so || : diff --git a/packaging/deb/DEBIAN/prerm b/packaging/deb/DEBIAN/prerm index cdf68e0d78..0c9eaf2860 100644 --- a/packaging/deb/DEBIAN/prerm +++ b/packaging/deb/DEBIAN/prerm @@ -44,6 +44,8 @@ else ${csudo}rm -f ${inc_link_dir}/taosws.h || : ${csudo}rm -f ${lib_link_dir}/libtaos.* || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : diff --git a/packaging/deb/makedeb.sh b/packaging/deb/makedeb.sh index d4616f29ff..d7bfe533e9 100755 --- a/packaging/deb/makedeb.sh +++ b/packaging/deb/makedeb.sh @@ -31,6 +31,7 @@ mkdir -p ${pkg_dir} cd ${pkg_dir} libfile="libtaos.so.${tdengine_ver}" +nativelibfile="libtaosnative.so.${tdengine_ver}" wslibfile="libtaosws.so" # create install dir @@ -120,11 +121,12 @@ fi cp ${compile_dir}/build/bin/taos ${pkg_dir}${install_home_path}/bin cp ${compile_dir}/build/lib/${libfile} ${pkg_dir}${install_home_path}/driver +cp ${compile_dir}/build/lib/${nativelibfile} ${pkg_dir}${install_home_path}/driver [ -f ${compile_dir}/build/lib/${wslibfile} ] && cp ${compile_dir}/build/lib/${wslibfile} ${pkg_dir}${install_home_path}/driver ||: cp ${compile_dir}/../include/client/taos.h ${pkg_dir}${install_home_path}/include cp ${compile_dir}/../include/common/taosdef.h ${pkg_dir}${install_home_path}/include cp ${compile_dir}/../include/util/taoserror.h ${pkg_dir}${install_home_path}/include -cp ${compile_dir}/../include/util/tdef.h ${pkg_dir}${install_home_path}/include +cp ${compile_dir}/../include/util/tdef.h ${pkg_dir}${install_home_path}/include cp ${compile_dir}/../include/libs/function/taosudf.h ${pkg_dir}${install_home_path}/include [ -f ${compile_dir}/build/include/taosws.h ] && cp ${compile_dir}/build/include/taosws.h ${pkg_dir}${install_home_path}/include ||: cp -r ${top_dir}/examples/* ${pkg_dir}${install_home_path}/examples diff --git a/packaging/rpm/tdengine.spec b/packaging/rpm/tdengine.spec index ff576949c7..2801794623 100644 --- a/packaging/rpm/tdengine.spec +++ b/packaging/rpm/tdengine.spec @@ -44,6 +44,7 @@ echo version: %{_version} echo buildroot: %{buildroot} libfile="libtaos.so.%{_version}" +nativelibfile="libtaosnative.so.%{_version}" wslibfile="libtaosws.so" # create install path, and cp file @@ -112,11 +113,12 @@ if [ -f %{_compiledir}/build/bin/taosadapter ]; then cp %{_compiledir}/build/bin/taosadapter %{buildroot}%{homepath}/bin fi cp %{_compiledir}/build/lib/${libfile} %{buildroot}%{homepath}/driver +cp %{_compiledir}/build/lib/${nativelibfile} %{buildroot}%{homepath}/driver [ -f %{_compiledir}/build/lib/${wslibfile} ] && cp %{_compiledir}/build/lib/${wslibfile} %{buildroot}%{homepath}/driver ||: cp %{_compiledir}/../include/client/taos.h %{buildroot}%{homepath}/include cp %{_compiledir}/../include/common/taosdef.h %{buildroot}%{homepath}/include cp %{_compiledir}/../include/util/taoserror.h %{buildroot}%{homepath}/include -cp %{_compiledir}/../include/util/tdef.h %{buildroot}%{homepath}/include +cp %{_compiledir}/../include/util/tdef.h %{buildroot}%{homepath}/include cp %{_compiledir}/../include/libs/function/taosudf.h %{buildroot}%{homepath}/include [ -f %{_compiledir}/build/include/taosws.h ] && cp %{_compiledir}/build/include/taosws.h %{buildroot}%{homepath}/include ||: #cp -r %{_compiledir}/../src/connector/python %{buildroot}%{homepath}/connector @@ -246,6 +248,8 @@ if [ $1 -eq 0 ];then ${csudo}rm -f ${inc_link_dir}/taosudf.h || : ${csudo}rm -f ${inc_link_dir}/taows.h || : ${csudo}rm -f ${lib_link_dir}/libtaos.so || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative.so || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative.so || : ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : diff --git a/packaging/tools/install.sh b/packaging/tools/install.sh index d844ce876e..8fd483b6a7 100755 --- a/packaging/tools/install.sh +++ b/packaging/tools/install.sh @@ -271,17 +271,23 @@ function install_lib() { # Remove links ${csudo}rm -f ${lib_link_dir}/libtaos.* || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : #${csudo}rm -rf ${v15_java_app_dir} || : ${csudo}cp -rf ${script_dir}/driver/* ${install_main_dir}/driver && ${csudo}chmod 777 ${install_main_dir}/driver/* ${csudo}ln -sf ${install_main_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.so.1 ${csudo}ln -sf ${lib_link_dir}/libtaos.so.1 ${lib_link_dir}/libtaos.so + ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib_link_dir}/libtaosnative.so.1 + ${csudo}ln -sf ${lib_link_dir}/libtaosnative.so.1 ${lib_link_dir}/libtaosnative.so [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.so ${lib_link_dir}/libtaosws.so || : if [[ -d ${lib64_link_dir} && ! -e ${lib64_link_dir}/libtaos.so ]]; then ${csudo}ln -sf ${install_main_dir}/driver/libtaos.* ${lib64_link_dir}/libtaos.so.1 || : ${csudo}ln -sf ${lib64_link_dir}/libtaos.so.1 ${lib64_link_dir}/libtaos.so || : + ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib64_link_dir}/libtaosnative.so.1 || : + ${csudo}ln -sf ${lib64_link_dir}/libtaosnative.so.1 ${lib64_link_dir}/libtaosnative.so || : [ -f ${install_main_dir}/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/libtaosws.so ${lib64_link_dir}/libtaosws.so || : fi diff --git a/packaging/tools/install_client.sh b/packaging/tools/install_client.sh index 532838fd2b..a3fe210e8e 100755 --- a/packaging/tools/install_client.sh +++ b/packaging/tools/install_client.sh @@ -134,6 +134,7 @@ function install_bin() { function clean_lib() { sudo rm -f /usr/lib/libtaos.* || : + sudo rm -f /usr/lib/libtaosnative.* || : [ -f /usr/lib/libtaosws.so ] && sudo rm -f /usr/lib/libtaosws.so || : [ -f /usr/lib64/libtaosws.so ] && sudo rm -f /usr/lib64/libtaosws.so || : sudo rm -rf ${lib_dir} || : @@ -143,6 +144,8 @@ function install_lib() { # Remove links ${csudo}rm -f ${lib_link_dir}/libtaos.* || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : [ -f ${lib_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : [ -f ${lib64_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : @@ -154,18 +157,24 @@ function install_lib() { if [ "$osType" != "Darwin" ]; then ${csudo}ln -s ${install_main_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.so.1 ${csudo}ln -s ${lib_link_dir}/libtaos.so.1 ${lib_link_dir}/libtaos.so + ${csudo}ln -s ${install_main_dir}/driver/libtaosnative.* ${lib_link_dir}/libtaosnative.so.1 + ${csudo}ln -s ${lib_link_dir}/libtaosnative.so.1 ${lib_link_dir}/libtaosnative.so [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.so ${lib_link_dir}/libtaosws.so ||: if [ -d "${lib64_link_dir}" ]; then ${csudo}ln -s ${install_main_dir}/driver/libtaos.* ${lib64_link_dir}/libtaos.so.1 || : ${csudo}ln -s ${lib64_link_dir}/libtaos.so.1 ${lib64_link_dir}/libtaos.so || : + ${csudo}ln -s ${install_main_dir}/driver/libtaosnative.* ${lib64_link_dir}/libtaosnative.so.1 || : + ${csudo}ln -s ${lib64_link_dir}/libtaosnative.so.1 ${lib64_link_dir}/libtaosnative.so || : [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.so ${lib64_link_dir}/libtaosws.so || : fi else ${csudo}ln -s ${install_main_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.1.dylib ${csudo}ln -s ${lib_link_dir}/libtaos.1.dylib ${lib_link_dir}/libtaos.dylib + ${csudo}ln -s ${install_main_dir}/driver/libtaosnative.* ${lib_link_dir}/libtaosnative.1.dylib + ${csudo}ln -s ${lib_link_dir}/libtaosnative.1.dylib ${lib_link_dir}/libtaosnative.dylib [ -f ${install_main_dir}/driver/libtaosws.dylib ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.dylib ${lib_link_dir}/libtaosws.dylib ||: fi @@ -178,7 +187,7 @@ function install_lib() { } function install_header() { - ${csudo}rm -f ${inc_link_dir}/taos.h ${inc_link_dir}/taosdef.h ${inc_link_dir}/tdef.h ${inc_link_dir}/taoserror.h ${inc_link_dir}/taosudf.h || : + ${csudo}rm -f ${inc_link_dir}/taos.h ${inc_link_dir}/taosws.h ${inc_link_dir}/taosdef.h ${inc_link_dir}/tdef.h ${inc_link_dir}/taoserror.h ${inc_link_dir}/taosudf.h || : ${csudo}cp -f ${script_dir}/inc/* ${install_main_dir}/include && ${csudo}chmod 644 ${install_main_dir}/include/* ${csudo}ln -s ${install_main_dir}/include/taos.h ${inc_link_dir}/taos.h ${csudo}ln -s ${install_main_dir}/include/taosdef.h ${inc_link_dir}/taosdef.h diff --git a/packaging/tools/make_install.bat b/packaging/tools/make_install.bat index e5b29b9557..7e1264d216 100644 --- a/packaging/tools/make_install.bat +++ b/packaging/tools/make_install.bat @@ -66,6 +66,9 @@ copy %source_dir%\\include\\libs\\function\\taosudf.h %target_dir%\\include > nu copy %binary_dir%\\build\\lib\\taos.lib %target_dir%\\driver > nul copy %binary_dir%\\build\\lib\\taos_static.lib %target_dir%\\driver > nul copy %binary_dir%\\build\\lib\\taos.dll %target_dir%\\driver > nul +copy %binary_dir%\\build\\lib\\taosnative.lib %target_dir%\\driver > nul +copy %binary_dir%\\build\\lib\\taosnative_static.lib %target_dir%\\driver > nul +copy %binary_dir%\\build\\lib\\taosnative.dll %target_dir%\\driver > nul copy %binary_dir%\\build\\bin\\taos.exe %target_dir% > nul if exist %binary_dir%\\build\\bin\\taosBenchmark.exe ( copy %binary_dir%\\build\\bin\\taosBenchmark.exe %target_dir% > nul @@ -149,12 +152,14 @@ call :check_svc taoskeeper if exist c:\\windows\\sysnative ( echo x86 copy /y C:\\TDengine\\driver\\taos.dll %windir%\\sysnative > nul + copy /y C:\\TDengine\\driver\\taosnative.dll %windir%\\sysnative > nul if exist C:\\TDengine\\driver\\taosws.dll ( copy /y C:\\TDengine\\driver\\taosws.dll %windir%\\sysnative > nul ) ) else ( echo x64 copy /y C:\\TDengine\\driver\\taos.dll C:\\Windows\\System32 > nul + copy /y C:\\TDengine\\driver\\taosnative.dll C:\\Windows\\System32 > nul if exist C:\\TDengine\\driver\\taosws.dll ( copy /y C:\\TDengine\\driver\\taosws.dll C:\\Windows\\System32 > nul ) diff --git a/packaging/tools/make_install.sh b/packaging/tools/make_install.sh index f44a46d862..4a694f9841 100755 --- a/packaging/tools/make_install.sh +++ b/packaging/tools/make_install.sh @@ -313,9 +313,11 @@ function install_avro() { function install_lib() { # Remove links ${csudo}rm -f ${lib_link_dir}/libtaos.* || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : [ -f ${lib_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : if [ "$osType" != "Darwin" ]; then ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : [ -f ${lib64_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : fi @@ -324,6 +326,10 @@ function install_lib() { ${install_main_dir}/driver && ${csudo}chmod 777 ${install_main_dir}/driver/libtaos.so.${verNumber} + ${csudo}cp ${binary_dir}/build/lib/libtaosnative.so.${verNumber} \ + ${install_main_dir}/driver && + ${csudo}chmod 777 ${install_main_dir}/driver/libtaosnative.so.${verNumber} + ${csudo}ln -sf ${install_main_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.so.1 > /dev/null 2>&1 ${csudo}ln -sf ${lib_link_dir}/libtaos.so.1 ${lib_link_dir}/libtaos.so > /dev/null 2>&1 if [ -d "${lib64_link_dir}" ]; then @@ -331,6 +337,13 @@ function install_lib() { ${csudo}ln -sf ${lib64_link_dir}/libtaos.so.1 ${lib64_link_dir}/libtaos.so > /dev/null 2>&1 fi + ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib_link_dir}/libtaosnative.so.1 > /dev/null 2>&1 + ${csudo}ln -sf ${lib_link_dir}/libtaosnative.so.1 ${lib_link_dir}/libtaosnative.so > /dev/null 2>&1 + if [ -d "${lib64_link_dir}" ]; then + ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib64_link_dir}/libtaosnative.so.1 > /dev/null 2>&1 + ${csudo}ln -sf ${lib64_link_dir}/libtaosnative.so.1 ${lib64_link_dir}/libtaosnative.so > /dev/null 2>&1 + fi + if [ -f ${binary_dir}/build/lib/libtaosws.so ]; then ${csudo}cp ${binary_dir}/build/lib/libtaosws.so \ ${install_main_dir}/driver && @@ -342,11 +355,19 @@ function install_lib() { ${csudo}cp -Rf ${binary_dir}/build/lib/libtaos.${verNumber}.dylib \ ${install_main_dir}/driver && ${csudo}chmod 777 ${install_main_dir}/driver/* + ${csudo}cp -Rf ${binary_dir}/build/lib/libtaosnative.${verNumber}.dylib \ + ${install_main_dir}/driver && ${csudo}chmod 777 ${install_main_dir}/driver/* + ${csudo}ln -sf ${install_main_dir}/driver/libtaos.${verNumber}.dylib \ ${lib_link_dir}/libtaos.1.dylib > /dev/null 2>&1 || : + ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.${verNumber}.dylib \ + ${lib_link_dir}/libtaosnative.1.dylib > /dev/null 2>&1 || : + ${csudo}ln -sf ${lib_link_dir}/libtaos.1.dylib ${lib_link_dir}/libtaos.dylib > /dev/null 2>&1 || : + ${csudo}ln -sf ${lib_link_dir}/libtaosnative.1.dylib ${lib_link_dir}/libtaosnative.dylib > /dev/null 2>&1 || : + if [ -f ${binary_dir}/build/lib/libtaosws.dylib ]; then ${csudo}cp ${binary_dir}/build/lib/libtaosws.dylib \ ${install_main_dir}/driver && diff --git a/packaging/tools/makeclient.sh b/packaging/tools/makeclient.sh index 87f4f57fd3..2c2f6205b5 100755 --- a/packaging/tools/makeclient.sh +++ b/packaging/tools/makeclient.sh @@ -79,10 +79,12 @@ if [ "$osType" != "Darwin" ]; then ${script_dir}/get_client.sh" fi lib_files="${build_dir}/lib/libtaos.so.${version}" + nativelib_files="${build_dir}/lib/libtaosnative.so.${version}" wslib_files="${build_dir}/lib/libtaosws.so" else bin_files="${build_dir}/bin/${clientName} ${script_dir}/remove_client.sh" lib_files="${build_dir}/lib/libtaos.${version}.dylib" + nativelib_files="${build_dir}/lib/libtaosnative.${version}.dylib" wslib_files="${build_dir}/lib/libtaosws.dylib" fi @@ -224,6 +226,7 @@ fi # Copy driver mkdir -p ${install_dir}/driver cp ${lib_files} ${install_dir}/driver +cp ${nativelib_files} ${install_dir}/driver # Copy connector connector_dir="${code_dir}/connector" diff --git a/packaging/tools/makepkg.sh b/packaging/tools/makepkg.sh index 7ef7903137..cc36d6bd5f 100755 --- a/packaging/tools/makepkg.sh +++ b/packaging/tools/makepkg.sh @@ -108,9 +108,11 @@ fi if [ "$osType" == "Darwin" ]; then lib_files="${build_dir}/lib/libtaos.${version}.dylib" + nativelib_files="${build_dir}/lib/libtaosnative.${version}.dylib" wslib_files="${build_dir}/lib/libtaosws.dylib" else lib_files="${build_dir}/lib/libtaos.so.${version}" + nativelib_files="${build_dir}/lib/libtaosnative.so.${version}" wslib_files="${build_dir}/lib/libtaosws.so" fi header_files="${code_dir}/include/client/taos.h ${code_dir}/include/common/taosdef.h ${code_dir}/include/util/taoserror.h ${code_dir}/include/util/tdef.h ${code_dir}/include/libs/function/taosudf.h" @@ -332,7 +334,7 @@ if [[ $dbName == "taos" ]]; then fi # Copy driver -mkdir -p ${install_dir}/driver && cp ${lib_files} ${install_dir}/driver && echo "${versionComp}" >${install_dir}/driver/vercomp.txt +mkdir -p ${install_dir}/driver && cp ${lib_files} ${install_dir}/driver && cp ${nativelib_files} ${install_dir}/driver && echo "${versionComp}" >${install_dir}/driver/vercomp.txt [ -f ${wslib_files} ] && cp ${wslib_files} ${install_dir}/driver || : # Copy connector && taosx diff --git a/packaging/tools/post.sh b/packaging/tools/post.sh index 68e3df8138..d8e9d207b1 100755 --- a/packaging/tools/post.sh +++ b/packaging/tools/post.sh @@ -205,18 +205,24 @@ function install_lib() { log_print "start install lib from ${lib_dir} to ${lib_link_dir}" ${csudo}rm -f ${lib_link_dir}/libtaos* || : ${csudo}rm -f ${lib64_link_dir}/libtaos* || : + ${csudo}rm -f ${lib_link_dir}/libtaosnative* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosnative* || : [ -f ${lib_link_dir}/libtaosws.${lib_file_ext} ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.${lib_file_ext} || : [ -f ${lib64_link_dir}/libtaosws.${lib_file_ext} ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.${lib_file_ext} || : ${csudo}ln -s ${lib_dir}/libtaos.* ${lib_link_dir}/libtaos.${lib_file_ext_1} 2>>${install_log_path} || return 1 ${csudo}ln -s ${lib_link_dir}/libtaos.${lib_file_ext_1} ${lib_link_dir}/libtaos.${lib_file_ext} 2>>${install_log_path} || return 1 + ${csudo}ln -s ${lib_dir}/libtaosnative.* ${lib_link_dir}/libtaosnative.${lib_file_ext_1} 2>>${install_log_path} || return 1 + ${csudo}ln -s ${lib_link_dir}/libtaosnative.${lib_file_ext_1} ${lib_link_dir}/libtaosnative.${lib_file_ext} 2>>${install_log_path} || return 1 [ -f ${lib_dir}/libtaosws.${lib_file_ext} ] && ${csudo}ln -sf ${lib_dir}/libtaosws.${lib_file_ext} ${lib_link_dir}/libtaosws.${lib_file_ext} ||: if [[ -d ${lib64_link_dir} && ! -e ${lib64_link_dir}/libtaos.${lib_file_ext} ]]; then ${csudo}ln -s ${lib_dir}/libtaos.* ${lib64_link_dir}/libtaos.${lib_file_ext_1} 2>>${install_log_path} || return 1 ${csudo}ln -s ${lib64_link_dir}/libtaos.${lib_file_ext_1} ${lib64_link_dir}/libtaos.${lib_file_ext} 2>>${install_log_path} || return 1 + ${csudo}ln -s ${lib_dir}/libtaosnative.* ${lib64_link_dir}/libtaosnative.${lib_file_ext_1} 2>>${install_log_path} || return 1 + ${csudo}ln -s ${lib64_link_dir}/libtaosnative.${lib_file_ext_1} ${lib64_link_dir}/libtaosnative.${lib_file_ext} 2>>${install_log_path} || return 1 [ -f ${lib_dir}/libtaosws.${lib_file_ext} ] && ${csudo}ln -sf ${lib_dir}/libtaosws.${lib_file_ext} ${lib64_link_dir}/libtaosws.${lib_file_ext} 2>>${install_log_path} fi diff --git a/packaging/tools/preun.sh b/packaging/tools/preun.sh index cb83a92d87..9ebe880e9c 100755 --- a/packaging/tools/preun.sh +++ b/packaging/tools/preun.sh @@ -168,8 +168,10 @@ ${csudo}rm -f ${inc_link_dir}/tdef.h || : ${csudo}rm -f ${inc_link_dir}/taosudf.h || : ${csudo}rm -f ${inc_link_dir}/taosws.h || : ${csudo}rm -f ${lib_link_dir}/libtaos.* || : +${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : +${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : ${csudo}rm -f ${log_link_dir} || : diff --git a/packaging/tools/remove.sh b/packaging/tools/remove.sh index ec73ca88cf..d62aa5a564 100755 --- a/packaging/tools/remove.sh +++ b/packaging/tools/remove.sh @@ -180,9 +180,11 @@ remove_bin() { function clean_lib() { # Remove link ${csudo}rm -f ${lib_link_dir}/libtaos.* || : + [ -f ${lib_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : [ -f ${lib_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.* || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : + [ -f ${lib64_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : [ -f ${lib64_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.* || : #${csudo}rm -rf ${v15_java_app_dir} || : } diff --git a/packaging/tools/remove_client.sh b/packaging/tools/remove_client.sh index a7eb225704..e6ec9c3768 100755 --- a/packaging/tools/remove_client.sh +++ b/packaging/tools/remove_client.sh @@ -73,9 +73,11 @@ function clean_lib() { # Remove link ${csudo}rm -f ${lib_link_dir}/libtaos.* || : [ -f ${lib_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.* || : + [ -f ${lib_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : [ -f ${lib64_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.* || : + [ -f ${lib64_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : #${csudo}rm -rf ${v15_java_app_dir} || : } diff --git a/source/client/CMakeLists.txt b/source/client/CMakeLists.txt index 1b38ecd7ad..e4b6077113 100644 --- a/source/client/CMakeLists.txt +++ b/source/client/CMakeLists.txt @@ -5,19 +5,19 @@ if(TD_ENTERPRISE) endif() if(TD_WINDOWS) - add_library(${TAOS_LIB} SHARED ${CLIENT_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/src/taos.rc.in) + add_library(${TAOS_NATIVE_LIB} SHARED ${CLIENT_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/src/taosnative.rc.in) else() - add_library(${TAOS_LIB} SHARED ${CLIENT_SRC}) + add_library(${TAOS_NATIVE_LIB} SHARED ${CLIENT_SRC}) endif() if(${TD_DARWIN}) - target_compile_options(${TAOS_LIB} PRIVATE -Wno-error=deprecated-non-prototype) + target_compile_options(${TAOS_NATIVE_LIB} PRIVATE -Wno-error=deprecated-non-prototype) endif() -INCLUDE_DIRECTORIES(jni) + target_include_directories( - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} PUBLIC "${TD_SOURCE_DIR}/include/client" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -26,46 +26,38 @@ if(${TAOSD_INTEGRATED}) set(TAOSD_MODULE "taosd") endif() target_link_libraries( - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} INTERFACE api PRIVATE os util common transport monitor nodes parser command planner catalog scheduler function qcom geometry ${TAOSD_MODULE} decimal ) -if(TD_WINDOWS) - INCLUDE_DIRECTORIES(jni/windows) - INCLUDE_DIRECTORIES(jni/windows/win32) - INCLUDE_DIRECTORIES(jni/windows/win32/bridge) -else() - INCLUDE_DIRECTORIES(jni/linux) -endif() - set_target_properties( - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} PROPERTIES CLEAN_DIRECT_OUTPUT 1 ) set_target_properties( - ${TAOS_LIB} + ${TAOS_NATIVE_LIB} PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1 ) -add_library(${TAOS_LIB_STATIC} STATIC ${CLIENT_SRC}) +add_library(${TAOS_NATIVE_LIB_STATIC} STATIC ${CLIENT_SRC}) if(${TD_DARWIN}) - target_compile_options(${TAOS_LIB_STATIC} PRIVATE -Wno-error=deprecated-non-prototype) + target_compile_options(${TAOS_NATIVE_LIB_STATIC} PRIVATE -Wno-error=deprecated-non-prototype) endif() target_include_directories( - ${TAOS_LIB_STATIC} + ${TAOS_NATIVE_LIB_STATIC} PUBLIC "${TD_SOURCE_DIR}/include/client" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) target_link_libraries( - ${TAOS_LIB_STATIC} + ${TAOS_NATIVE_LIB_STATIC} INTERFACE api PRIVATE os util common transport monitor nodes parser command planner catalog scheduler function qcom geometry decimal ) @@ -73,3 +65,5 @@ target_link_libraries( if(${BUILD_TEST}) ADD_SUBDIRECTORY(test) endif(${BUILD_TEST}) + +ADD_SUBDIRECTORY(wrapper) diff --git a/source/client/src/clientEnv.c b/source/client/src/clientEnv.c index aa6e06a989..39c9bb685e 100644 --- a/source/client/src/clientEnv.c +++ b/source/client/src/clientEnv.c @@ -922,7 +922,7 @@ void tscStopCrashReport() { } } -void tscWriteCrashInfo(int signum, void *sigInfo, void *context) { +void taos_write_crashinfo(int signum, void *sigInfo, void *context) { writeCrashLogToFile(signum, sigInfo, CUS_PROMPT, lastClusterId, appInfo.startTime); } #endif diff --git a/source/client/src/taos.rc.in b/source/client/src/taos.rc.in index 84a2a7a5b5..c062a32304 100644 --- a/source/client/src/taos.rc.in +++ b/source/client/src/taos.rc.in @@ -15,10 +15,10 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "FileDescription", "Native C Driver for TDengine" + VALUE "FileDescription", "C Driver for TDengine" VALUE "FileVersion", "${TD_VER_NUMBER}" VALUE "InternalName", "taos.dll(${TD_VER_CPUTYPE})" - VALUE "LegalCopyright", "Copyright (C) 2020 TAOS Data" + VALUE "LegalCopyright", "Copyright (C) 2025 TAOS Data" VALUE "OriginalFilename", "" VALUE "ProductName", "taos.dll(${TD_VER_CPUTYPE})" VALUE "ProductVersion", "${TD_VER_NUMBER}" diff --git a/source/client/src/taosnative.rc.in b/source/client/src/taosnative.rc.in new file mode 100644 index 0000000000..1cd080b492 --- /dev/null +++ b/source/client/src/taosnative.rc.in @@ -0,0 +1,31 @@ +1 VERSIONINFO + FILEVERSION ${TD_VER_NUMBER} + PRODUCTVERSION ${TD_VER_NUMBER} + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "Internal C Driver for TDengine" + VALUE "FileVersion", "${TD_VER_NUMBER}" + VALUE "InternalName", "taosnative.dll(${TD_VER_CPUTYPE})" + VALUE "LegalCopyright", "Copyright (C) 2025 TAOS Data" + VALUE "OriginalFilename", "" + VALUE "ProductName", "taosnative.dll(${TD_VER_CPUTYPE})" + VALUE "ProductVersion", "${TD_VER_NUMBER}" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END \ No newline at end of file diff --git a/source/client/test/CMakeLists.txt b/source/client/test/CMakeLists.txt index 9e1a04879e..cee5dc08f9 100644 --- a/source/client/test/CMakeLists.txt +++ b/source/client/test/CMakeLists.txt @@ -8,49 +8,49 @@ AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_LIST) ADD_EXECUTABLE(clientTest clientTests.cpp) TARGET_LINK_LIBRARIES( clientTest - os util common transport parser catalog scheduler gtest ${TAOS_LIB_STATIC} qcom executor function + os util common transport parser catalog scheduler gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor function ) ADD_EXECUTABLE(connectOptionsTest connectOptionsTest.cpp) TARGET_LINK_LIBRARIES( connectOptionsTest - os util common transport parser catalog scheduler gtest ${TAOS_LIB_STATIC} qcom executor function + os util common transport parser catalog scheduler gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor function ) ADD_EXECUTABLE(tmqTest tmqTest.cpp) TARGET_LINK_LIBRARIES( tmqTest - PUBLIC os util common transport parser catalog scheduler function gtest ${TAOS_LIB_STATIC} qcom + PUBLIC os util common transport parser catalog scheduler function gtest ${TAOS_NATIVE_LIB_STATIC} qcom ) ADD_EXECUTABLE(smlTest smlTest.cpp) TARGET_LINK_LIBRARIES( smlTest - PUBLIC os util common transport parser catalog scheduler function gtest ${TAOS_LIB_STATIC} qcom geometry + PUBLIC os util common transport parser catalog scheduler function gtest ${TAOS_NATIVE_LIB_STATIC} qcom geometry ) #ADD_EXECUTABLE(clientMonitorTest clientMonitorTests.cpp) #TARGET_LINK_LIBRARIES( # clientMonitorTest -# PUBLIC os util common transport monitor parser catalog scheduler function gtest ${TAOS_LIB_STATIC} qcom executor +# PUBLIC os util common transport monitor parser catalog scheduler function gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor #) ADD_EXECUTABLE(userOperTest ../../../tests/script/api/passwdTest.c) TARGET_LINK_LIBRARIES( userOperTest - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} ) ADD_EXECUTABLE(stmt2Test stmt2Test.cpp) TARGET_LINK_LIBRARIES( stmt2Test - os util common transport parser catalog scheduler gtest ${TAOS_LIB_STATIC} qcom executor function + os util common transport parser catalog scheduler gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor function ) ADD_EXECUTABLE(stmtTest stmtTest.cpp) TARGET_LINK_LIBRARIES( stmtTest - os util common transport parser catalog scheduler gtest ${TAOS_LIB_STATIC} qcom executor function + os util common transport parser catalog scheduler gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor function ) TARGET_INCLUDE_DIRECTORIES( diff --git a/source/client/wrapper/CMakeLists.txt b/source/client/wrapper/CMakeLists.txt new file mode 100644 index 0000000000..17243f571c --- /dev/null +++ b/source/client/wrapper/CMakeLists.txt @@ -0,0 +1,67 @@ +aux_source_directory(src WRAPPER_SRC) + +if(TD_WINDOWS) + add_library(${TAOS_LIB} SHARED ${WRAPPER_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/../src/taos.rc.in) +else() + add_library(${TAOS_LIB} SHARED ${WRAPPER_SRC}) +endif() + +if(${TD_DARWIN}) + target_compile_options(${TAOS_LIB} PRIVATE -Wno-error=deprecated-non-prototype) +endif() + +# jni include +INCLUDE_DIRECTORIES(jni) +if(TD_WINDOWS) + INCLUDE_DIRECTORIES(jni/windows) + INCLUDE_DIRECTORIES(jni/windows/win32) + INCLUDE_DIRECTORIES(jni/windows/win32/bridge) +else() + INCLUDE_DIRECTORIES(jni/linux) +endif() + +target_include_directories( + ${TAOS_LIB} + PUBLIC "${TD_SOURCE_DIR}/include/client" + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" +) + +target_link_libraries( + ${TAOS_LIB} + PUBLIC os util +) + +set_target_properties( + ${TAOS_LIB} + PROPERTIES + CLEAN_DIRECT_OUTPUT + 1 +) + +set_target_properties( + ${TAOS_LIB} + PROPERTIES + VERSION ${TD_VER_NUMBER} + SOVERSION 1 +) + +add_library(${TAOS_LIB_STATIC} STATIC ${WRAPPER_SRC}) + +if(${TD_DARWIN}) + target_compile_options(${TAOS_LIB_STATIC} PRIVATE -Wno-error=deprecated-non-prototype) +endif() + +target_include_directories( + ${TAOS_LIB_STATIC} + PUBLIC "${TD_SOURCE_DIR}/include/client" + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" +) + +target_link_libraries( + ${TAOS_LIB_STATIC} + PUBLIC os util +) + +# if(${BUILD_TEST}) +# ADD_SUBDIRECTORY(test) +# endif(${BUILD_TEST}) diff --git a/source/client/wrapper/inc/wrapper.h b/source/client/wrapper/inc/wrapper.h new file mode 100644 index 0000000000..34f9283f99 --- /dev/null +++ b/source/client/wrapper/inc/wrapper.h @@ -0,0 +1,232 @@ +/* + * 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 . + */ + +#ifndef TDENGINE_WRAPPER_H +#define TDENGINE_WRAPPER_H + +#include "os.h" +#include "taos.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + DRIVER_NATIVE = 0, + DRIVER_WEBSOCKET = 1, + DRIVER_MAX = 2, +} EDriverType; + +extern EDriverType tsDriverType; +extern void *tsDriver; + +extern int32_t taosDriverInit(EDriverType driverType); +extern void taosDriverCleanup(); + +extern setConfRet (*fp_taos_set_config)(const char *config); + +extern int (*fp_taos_init)(void); +extern void (*fp_taos_cleanup)(void); +extern int (*fp_taos_options)(TSDB_OPTION option, const void *arg, ...); +extern int (*fp_taos_options_connection)(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...); +extern TAOS *(*fp_taos_connect)(const char *ip, const char *user, const char *pass, const char *db, uint16_t port); +extern TAOS *(*fp_taos_connect_auth)(const char *ip, const char *user, const char *auth, const char *db, uint16_t port); +extern void (*fp_taos_close)(TAOS *taos); + +extern const char *(*fp_taos_data_type)(int type); + +extern TAOS_STMT *(*fp_taos_stmt_init)(TAOS *taos); +extern TAOS_STMT *(*fp_taos_stmt_init_with_reqid)(TAOS *taos, int64_t reqid); +extern TAOS_STMT *(*fp_taos_stmt_init_with_options)(TAOS *taos, TAOS_STMT_OPTIONS *options); +extern int (*fp_taos_stmt_prepare)(TAOS_STMT *stmt, const char *sql, unsigned long length); +extern int (*fp_taos_stmt_set_tbname_tags)(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags); +extern int (*fp_taos_stmt_set_tbname)(TAOS_STMT *stmt, const char *name); +extern int (*fp_taos_stmt_set_tags)(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags); +extern int (*fp_taos_stmt_set_sub_tbname)(TAOS_STMT *stmt, const char *name); +extern int (*fp_taos_stmt_get_tag_fields)(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields); +extern int (*fp_taos_stmt_get_col_fields)(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields); +extern void (*fp_taos_stmt_reclaim_fields)(TAOS_STMT *stmt, TAOS_FIELD_E *fields); + +extern int (*fp_taos_stmt_is_insert)(TAOS_STMT *stmt, int *insert); +extern int (*fp_taos_stmt_num_params)(TAOS_STMT *stmt, int *nums); +extern int (*fp_taos_stmt_get_param)(TAOS_STMT *stmt, int idx, int *type, int *bytes); +extern int (*fp_taos_stmt_bind_param)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind); +extern int (*fp_taos_stmt_bind_param_batch)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind); +extern int (*fp_taos_stmt_bind_single_param_batch)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind, int colIdx); +extern int (*fp_taos_stmt_add_batch)(TAOS_STMT *stmt); +extern int (*fp_taos_stmt_execute)(TAOS_STMT *stmt); +extern TAOS_RES *(*fp_taos_stmt_use_result)(TAOS_STMT *stmt); +extern int (*fp_taos_stmt_close)(TAOS_STMT *stmt); +extern char *(*fp_taos_stmt_errstr)(TAOS_STMT *stmt); +extern int (*fp_taos_stmt_affected_rows)(TAOS_STMT *stmt); +extern int (*fp_taos_stmt_affected_rows_once)(TAOS_STMT *stmt); + +extern TAOS_STMT2 *(*fp_taos_stmt2_init)(TAOS *taos, TAOS_STMT2_OPTION *option); +extern int (*fp_taos_stmt2_prepare)(TAOS_STMT2 *stmt, const char *sql, unsigned long length); +extern int (*fp_taos_stmt2_bind_param)(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx); +extern int (*fp_taos_stmt2_bind_param_a)(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx, + __taos_async_fn_t fp, void *param); +extern int (*fp_taos_stmt2_exec)(TAOS_STMT2 *stmt, int *affected_rows); +extern int (*fp_taos_stmt2_close)(TAOS_STMT2 *stmt); +extern int (*fp_taos_stmt2_is_insert)(TAOS_STMT2 *stmt, int *insert); +extern int (*fp_taos_stmt2_get_fields)(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields); +extern void (*fp_taos_stmt2_free_fields)(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields); +extern TAOS_RES *(*fp_taos_stmt2_result)(TAOS_STMT2 *stmt); +extern char *(*fp_taos_stmt2_error)(TAOS_STMT2 *stmt); + +extern TAOS_RES *(*fp_taos_query)(TAOS *taos, const char *sql); +extern TAOS_RES *(*fp_taos_query_with_reqid)(TAOS *taos, const char *sql, int64_t reqId); + +extern TAOS_ROW (*fp_taos_fetch_row)(TAOS_RES *res); +extern int (*fp_taos_result_precision)(TAOS_RES *res); // get the time precision of result +extern void (*fp_taos_free_result)(TAOS_RES *res); +extern void (*fp_taos_kill_query)(TAOS *taos); +extern int (*fp_taos_field_count)(TAOS_RES *res); +extern int (*fp_taos_num_fields)(TAOS_RES *res); +extern int (*fp_taos_affected_rows)(TAOS_RES *res); +extern int64_t (*fp_taos_affected_rows64)(TAOS_RES *res); + +extern TAOS_FIELD *(*fp_taos_fetch_fields)(TAOS_RES *res); +extern TAOS_FIELD_E *(*fp_taos_fetch_fields_e)(TAOS_RES *res); +extern int (*fp_taos_select_db)(TAOS *taos, const char *db); +extern int (*fp_taos_print_row)(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields); +extern int (*fp_taos_print_row_with_size)(char *str, uint32_t size, TAOS_ROW row, TAOS_FIELD *fields, int num_fields); +extern void (*fp_taos_stop_query)(TAOS_RES *res); +extern bool (*fp_taos_is_null)(TAOS_RES *res, int32_t row, int32_t col); +extern int (*fp_taos_is_null_by_column)(TAOS_RES *res, int columnIndex, bool result[], int *rows); +extern bool (*fp_taos_is_update_query)(TAOS_RES *res); +extern int (*fp_taos_fetch_block)(TAOS_RES *res, TAOS_ROW *rows); +extern int (*fp_taos_fetch_block_s)(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows); +extern int (*fp_taos_fetch_raw_block)(TAOS_RES *res, int *numOfRows, void **pData); +extern int *(*fp_taos_get_column_data_offset)(TAOS_RES *res, int columnIndex); +extern int (*fp_taos_validate_sql)(TAOS *taos, const char *sql); +extern void (*fp_taos_reset_current_db)(TAOS *taos); + +extern int *(*fp_taos_fetch_lengths)(TAOS_RES *res); +extern TAOS_ROW *(*fp_taos_result_block)(TAOS_RES *res); + +extern const char *(*fp_taos_get_server_info)(TAOS *taos); +extern const char *(*fp_taos_get_client_info)(); +extern int (*fp_taos_get_current_db)(TAOS *taos, char *database, int len, int *required); + +extern const char *(*fp_taos_errstr)(TAOS_RES *res); +extern int (*fp_taos_errno)(TAOS_RES *res); + +extern void (*fp_taos_query_a)(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param); +extern void (*fp_taos_query_a_with_reqid)(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param, + int64_t reqid); +extern void (*fp_taos_fetch_rows_a)(TAOS_RES *res, __taos_async_fn_t fp, void *param); +extern void (*fp_taos_fetch_raw_block_a)(TAOS_RES *res, __taos_async_fn_t fp, void *param); +extern const void *(*fp_taos_get_raw_block)(TAOS_RES *res); + +extern int (*fp_taos_get_db_route_info)(TAOS *taos, const char *db, TAOS_DB_ROUTE_INFO *dbInfo); +extern int (*fp_taos_get_table_vgId)(TAOS *taos, const char *db, const char *table, int *vgId); +extern int (*fp_taos_get_tables_vgId)(TAOS *taos, const char *db, const char *table[], int tableNum, int *vgId); + +extern int (*fp_taos_load_table_info)(TAOS *taos, const char *tableNameList); + +extern void (*fp_taos_set_hb_quit)(int8_t quitByKill); + +extern int (*fp_taos_set_notify_cb)(TAOS *taos, __taos_notify_fn_t fp, void *param, int type); + +extern void (*fp_taos_fetch_whitelist_a)(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param); + +extern int (*fp_taos_set_conn_mode)(TAOS *taos, int mode, int value); + +extern TAOS_RES *(*fp_taos_schemaless_insert)(TAOS *taos, char *lines[], int numLines, int protocol, int precision); +extern TAOS_RES *(*fp_taos_schemaless_insert_with_reqid)(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int64_t reqid); +extern TAOS_RES *(*fp_taos_schemaless_insert_raw)(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision); +extern TAOS_RES *(*fp_taos_schemaless_insert_raw_with_reqid)(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int64_t reqid); +extern TAOS_RES *(*fp_taos_schemaless_insert_ttl)(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int32_t ttl); +extern TAOS_RES *(*fp_taos_schemaless_insert_ttl_with_reqid)(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid); +extern TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl)(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl); +extern TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl_with_reqid)(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl, + int64_t reqid); +extern TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl_with_reqid_tbname_key)(TAOS *taos, char *lines, int len, + int32_t *totalRows, int protocol, + int precision, int32_t ttl, int64_t reqid, + char *tbnameKey); +extern TAOS_RES *(*fp_taos_schemaless_insert_ttl_with_reqid_tbname_key)(TAOS *taos, char *lines[], int numLines, + int protocol, int precision, int32_t ttl, + int64_t reqid, char *tbnameKey); + +extern tmq_conf_t *(*fp_tmq_conf_new)(); +extern tmq_conf_res_t (*fp_tmq_conf_set)(tmq_conf_t *conf, const char *key, const char *value); +extern void (*fp_tmq_conf_destroy)(tmq_conf_t *conf); +extern void (*fp_tmq_conf_set_auto_commit_cb)(tmq_conf_t *conf, tmq_commit_cb *cb, void *param); + +extern tmq_list_t *(*fp_tmq_list_new)(); +extern int32_t (*fp_tmq_list_append)(tmq_list_t *, const char *); +extern void (*fp_tmq_list_destroy)(tmq_list_t *); +extern int32_t (*fp_tmq_list_get_size)(const tmq_list_t *); +extern char **(*fp_tmq_list_to_c_array)(const tmq_list_t *); + +extern tmq_t *(*fp_tmq_consumer_new)(tmq_conf_t *conf, char *errstr, int32_t errstrLen); +extern int32_t (*fp_tmq_subscribe)(tmq_t *tmq, const tmq_list_t *topic_list); +extern int32_t (*fp_tmq_unsubscribe)(tmq_t *tmq); +extern int32_t (*fp_tmq_subscription)(tmq_t *tmq, tmq_list_t **topics); +extern TAOS_RES *(*fp_tmq_consumer_poll)(tmq_t *tmq, int64_t timeout); +extern int32_t (*fp_tmq_consumer_close)(tmq_t *tmq); +extern int32_t (*fp_tmq_commit_sync)(tmq_t *tmq, const TAOS_RES *msg); +extern void (*fp_tmq_commit_async)(tmq_t *tmq, const TAOS_RES *msg, tmq_commit_cb *cb, void *param); +extern int32_t (*fp_tmq_commit_offset_sync)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset); +extern void (*fp_tmq_commit_offset_async)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, + tmq_commit_cb *cb, void *param); +extern int32_t (*fp_tmq_get_topic_assignment)(tmq_t *tmq, const char *pTopicName, tmq_topic_assignment **assignment, + int32_t *numOfAssignment); +extern void (*fp_tmq_free_assignment)(tmq_topic_assignment *pAssignment); +extern int32_t (*fp_tmq_offset_seek)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset); +extern int64_t (*fp_tmq_position)(tmq_t *tmq, const char *pTopicName, int32_t vgId); +extern int64_t (*fp_tmq_committed)(tmq_t *tmq, const char *pTopicName, int32_t vgId); + +extern TAOS *(*fp_tmq_get_connect)(tmq_t *tmq); +extern const char *(*fp_tmq_get_table_name)(TAOS_RES *res); +extern tmq_res_t (*fp_tmq_get_res_type)(TAOS_RES *res); +extern const char *(*fp_tmq_get_topic_name)(TAOS_RES *res); +extern const char *(*fp_tmq_get_db_name)(TAOS_RES *res); +extern int32_t (*fp_tmq_get_vgroup_id)(TAOS_RES *res); +extern int64_t (*fp_tmq_get_vgroup_offset)(TAOS_RES *res); +extern const char *(*fp_tmq_err2str)(int32_t code); + +extern int32_t (*fp_tmq_get_raw)(TAOS_RES *res, tmq_raw_data *raw); +extern int32_t (*fp_tmq_write_raw)(TAOS *taos, tmq_raw_data raw); +extern int (*fp_taos_write_raw_block)(TAOS *taos, int numOfRows, char *pData, const char *tbname); +extern int (*fp_taos_write_raw_block_with_reqid)(TAOS *taos, int numOfRows, char *pData, const char *tbname, + int64_t reqid); +extern int (*fp_taos_write_raw_block_with_fields)(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields); +extern int (*fp_taos_write_raw_block_with_fields_with_reqid)(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields, int64_t reqid); +extern void (*fp_tmq_free_raw)(tmq_raw_data raw); + +extern char *(*fp_tmq_get_json_meta)(TAOS_RES *res); +extern void (*fp_tmq_free_json_meta)(char *jsonMeta); + +extern TSDB_SERVER_STATUS (*fp_taos_check_server_status)(const char *fqdn, int port, char *details, int maxlen); +extern void (*fp_taos_write_crashinfo)(int signum, void *sigInfo, void *context); +extern char *(*fp_getBuildInfo)(); + +#ifdef __cplusplus +} +#endif + +#endif // TDENGINE_CLIENT_WRAPPER_H diff --git a/source/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h b/source/client/wrapper/jni/com_taosdata_jdbc_TSDBJNIConnector.h similarity index 100% rename from source/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h rename to source/client/wrapper/jni/com_taosdata_jdbc_TSDBJNIConnector.h diff --git a/source/client/jni/com_taosdata_jdbc_tmq_TMQConnector.h b/source/client/wrapper/jni/com_taosdata_jdbc_tmq_TMQConnector.h similarity index 100% rename from source/client/jni/com_taosdata_jdbc_tmq_TMQConnector.h rename to source/client/wrapper/jni/com_taosdata_jdbc_tmq_TMQConnector.h diff --git a/source/client/jni/jniCommon.h b/source/client/wrapper/jni/jniCommon.h similarity index 100% rename from source/client/jni/jniCommon.h rename to source/client/wrapper/jni/jniCommon.h diff --git a/source/client/jni/linux/AWTCocoaComponent.h b/source/client/wrapper/jni/linux/AWTCocoaComponent.h similarity index 100% rename from source/client/jni/linux/AWTCocoaComponent.h rename to source/client/wrapper/jni/linux/AWTCocoaComponent.h diff --git a/source/client/jni/linux/JDWP.h b/source/client/wrapper/jni/linux/JDWP.h similarity index 100% rename from source/client/jni/linux/JDWP.h rename to source/client/wrapper/jni/linux/JDWP.h diff --git a/source/client/jni/linux/JDWPCommands.h b/source/client/wrapper/jni/linux/JDWPCommands.h similarity index 100% rename from source/client/jni/linux/JDWPCommands.h rename to source/client/wrapper/jni/linux/JDWPCommands.h diff --git a/source/client/jni/linux/JavaVM.h b/source/client/wrapper/jni/linux/JavaVM.h similarity index 100% rename from source/client/jni/linux/JavaVM.h rename to source/client/wrapper/jni/linux/JavaVM.h diff --git a/source/client/jni/linux/NSJavaConfiguration.h b/source/client/wrapper/jni/linux/NSJavaConfiguration.h similarity index 100% rename from source/client/jni/linux/NSJavaConfiguration.h rename to source/client/wrapper/jni/linux/NSJavaConfiguration.h diff --git a/source/client/jni/linux/NSJavaVirtualMachine.h b/source/client/wrapper/jni/linux/NSJavaVirtualMachine.h similarity index 100% rename from source/client/jni/linux/NSJavaVirtualMachine.h rename to source/client/wrapper/jni/linux/NSJavaVirtualMachine.h diff --git a/source/client/jni/linux/jawt.h b/source/client/wrapper/jni/linux/jawt.h similarity index 63% rename from source/client/jni/linux/jawt.h rename to source/client/wrapper/jni/linux/jawt.h index b62fe666fe..0ddbbaad82 100644 --- a/source/client/jni/linux/jawt.h +++ b/source/client/wrapper/jni/linux/jawt.h @@ -14,107 +14,6 @@ extern "C" { #endif -/* - * AWT native interface (new in JDK 1.3) - * - * The AWT native interface allows a native C or C++ application a means - * by which to access native structures in AWT. This is to facilitate moving - * legacy C and C++ applications to Java and to target the needs of the - * community who, at present, wish to do their own native rendering to canvases - * for performance reasons. Standard extensions such as Java3D also require a - * means to access the underlying native data structures of AWT. - * - * There may be future extensions to this API depending on demand. - * - * A VM does not have to implement this API in order to pass the JCK. - * It is recommended, however, that this API is implemented on VMs that support - * standard extensions, such as Java3D. - * - * Since this is a native API, any program which uses it cannot be considered - * 100% pure java. - */ - -/* - * AWT Native Drawing Surface (JAWT_DrawingSurface). - * - * For each platform, there is a native drawing surface structure. This - * platform-specific structure can be found in jawt_md.h. It is recommended - * that additional platforms follow the same model. It is also recommended - * that VMs on Win32 and Solaris support the existing structures in jawt_md.h. - * - ******************* - * EXAMPLE OF USAGE: - ******************* - * - * In Win32, a programmer wishes to access the HWND of a canvas to perform - * native rendering into it. The programmer has declared the paint() method - * for their canvas subclass to be native: - * - * - * MyCanvas.java: - * - * import java.awt.*; - * - * public class MyCanvas extends Canvas { - * - * static { - * System.loadLibrary("mylib"); - * } - * - * public native void paint(Graphics g); - * } - * - * - * myfile.c: - * - * #include "jawt_md.h" - * #include - * - * JNIEXPORT void JNICALL - * Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics) - * { - * JAWT awt; - * JAWT_DrawingSurface* ds; - * JAWT_DrawingSurfaceInfo* dsi; - * JAWT_Win32DrawingSurfaceInfo* dsi_win; - * jboolean result; - * jint lock; - * - * // Get the AWT - * awt.version = JAWT_VERSION_1_3; - * result = JAWT_GetAWT(env, &awt); - * assert(result != JNI_FALSE); - * - * // Get the drawing surface - * ds = awt.GetDrawingSurface(env, canvas); - * assert(ds != NULL); - * - * // Lock the drawing surface - * lock = ds->Lock(ds); - * assert((lock & JAWT_LOCK_ERROR) == 0); - * - * // Get the drawing surface info - * dsi = ds->GetDrawingSurfaceInfo(ds); - * - * // Get the platform-specific drawing info - * dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo; - * - * ////////////////////////////// - * // !!! DO PAINTING HERE !!! // - * ////////////////////////////// - * - * // Free the drawing surface info - * ds->FreeDrawingSurfaceInfo(dsi); - * - * // Unlock the drawing surface - * ds->Unlock(ds); - * - * // Free the drawing surface - * awt.FreeDrawingSurface(ds); - * } - * - */ - /* * JAWT_Rectangle * Structure for a native rectangle. diff --git a/source/client/jni/linux/jawt_md.h b/source/client/wrapper/jni/linux/jawt_md.h similarity index 100% rename from source/client/jni/linux/jawt_md.h rename to source/client/wrapper/jni/linux/jawt_md.h diff --git a/source/client/jni/linux/jdwpTransport.h b/source/client/wrapper/jni/linux/jdwpTransport.h similarity index 100% rename from source/client/jni/linux/jdwpTransport.h rename to source/client/wrapper/jni/linux/jdwpTransport.h diff --git a/source/client/jni/linux/jni.h b/source/client/wrapper/jni/linux/jni.h similarity index 100% rename from source/client/jni/linux/jni.h rename to source/client/wrapper/jni/linux/jni.h diff --git a/source/client/jni/linux/jni_md.h b/source/client/wrapper/jni/linux/jni_md.h similarity index 100% rename from source/client/jni/linux/jni_md.h rename to source/client/wrapper/jni/linux/jni_md.h diff --git a/source/client/jni/linux/jvmti.h b/source/client/wrapper/jni/linux/jvmti.h similarity index 100% rename from source/client/jni/linux/jvmti.h rename to source/client/wrapper/jni/linux/jvmti.h diff --git a/source/client/jni/windows/classfile_constants.h b/source/client/wrapper/jni/windows/classfile_constants.h similarity index 100% rename from source/client/jni/windows/classfile_constants.h rename to source/client/wrapper/jni/windows/classfile_constants.h diff --git a/source/client/jni/windows/jawt.h b/source/client/wrapper/jni/windows/jawt.h similarity index 73% rename from source/client/jni/windows/jawt.h rename to source/client/wrapper/jni/windows/jawt.h index 231c292dc8..e9bc89d5fb 100644 --- a/source/client/jni/windows/jawt.h +++ b/source/client/wrapper/jni/windows/jawt.h @@ -52,87 +52,6 @@ extern "C" { * 100% pure java. */ -/* - * AWT Native Drawing Surface (JAWT_DrawingSurface). - * - * For each platform, there is a native drawing surface structure. This - * platform-specific structure can be found in jawt_md.h. It is recommended - * that additional platforms follow the same model. It is also recommended - * that VMs on Win32 and Solaris support the existing structures in jawt_md.h. - * - ******************* - * EXAMPLE OF USAGE: - ******************* - * - * In Win32, a programmer wishes to access the HWND of a canvas to perform - * native rendering into it. The programmer has declared the paint() method - * for their canvas subclass to be native: - * - * - * MyCanvas.java: - * - * import java.awt.*; - * - * public class MyCanvas extends Canvas { - * - * static { - * System.loadLibrary("mylib"); - * } - * - * public native void paint(Graphics g); - * } - * - * - * myfile.c: - * - * #include "jawt_md.h" - * #include - * - * JNIEXPORT void JNICALL - * Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics) - * { - * JAWT awt; - * JAWT_DrawingSurface* ds; - * JAWT_DrawingSurfaceInfo* dsi; - * JAWT_Win32DrawingSurfaceInfo* dsi_win; - * jboolean result; - * jint lock; - * - * // Get the AWT - * awt.version = JAWT_VERSION_1_3; - * result = JAWT_GetAWT(env, &awt); - * assert(result != JNI_FALSE); - * - * // Get the drawing surface - * ds = awt.GetDrawingSurface(env, canvas); - * assert(ds != NULL); - * - * // Lock the drawing surface - * lock = ds->Lock(ds); - * assert((lock & JAWT_LOCK_ERROR) == 0); - * - * // Get the drawing surface info - * dsi = ds->GetDrawingSurfaceInfo(ds); - * - * // Get the platform-specific drawing info - * dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo; - * - * ////////////////////////////// - * // !!! DO PAINTING HERE !!! // - * ////////////////////////////// - * - * // Free the drawing surface info - * ds->FreeDrawingSurfaceInfo(dsi); - * - * // Unlock the drawing surface - * ds->Unlock(ds); - * - * // Free the drawing surface - * awt.FreeDrawingSurface(ds); - * } - * - */ - /* * JAWT_Rectangle * Structure for a native rectangle. diff --git a/source/client/jni/windows/jdwpTransport.h b/source/client/wrapper/jni/windows/jdwpTransport.h similarity index 100% rename from source/client/jni/windows/jdwpTransport.h rename to source/client/wrapper/jni/windows/jdwpTransport.h diff --git a/source/client/jni/windows/jni.h b/source/client/wrapper/jni/windows/jni.h similarity index 100% rename from source/client/jni/windows/jni.h rename to source/client/wrapper/jni/windows/jni.h diff --git a/source/client/jni/windows/jvmti.h b/source/client/wrapper/jni/windows/jvmti.h similarity index 100% rename from source/client/jni/windows/jvmti.h rename to source/client/wrapper/jni/windows/jvmti.h diff --git a/source/client/jni/windows/jvmticmlr.h b/source/client/wrapper/jni/windows/jvmticmlr.h similarity index 100% rename from source/client/jni/windows/jvmticmlr.h rename to source/client/wrapper/jni/windows/jvmticmlr.h diff --git a/source/client/jni/windows/win32/bridge/AccessBridgeCallbacks.h b/source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCallbacks.h similarity index 100% rename from source/client/jni/windows/win32/bridge/AccessBridgeCallbacks.h rename to source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCallbacks.h diff --git a/source/client/jni/windows/win32/bridge/AccessBridgeCalls.c b/source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCalls.c similarity index 100% rename from source/client/jni/windows/win32/bridge/AccessBridgeCalls.c rename to source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCalls.c diff --git a/source/client/jni/windows/win32/bridge/AccessBridgeCalls.h b/source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCalls.h similarity index 100% rename from source/client/jni/windows/win32/bridge/AccessBridgeCalls.h rename to source/client/wrapper/jni/windows/win32/bridge/AccessBridgeCalls.h diff --git a/source/client/jni/windows/win32/bridge/AccessBridgePackages.h b/source/client/wrapper/jni/windows/win32/bridge/AccessBridgePackages.h similarity index 100% rename from source/client/jni/windows/win32/bridge/AccessBridgePackages.h rename to source/client/wrapper/jni/windows/win32/bridge/AccessBridgePackages.h diff --git a/source/client/jni/windows/win32/jawt_md.h b/source/client/wrapper/jni/windows/win32/jawt_md.h similarity index 100% rename from source/client/jni/windows/win32/jawt_md.h rename to source/client/wrapper/jni/windows/win32/jawt_md.h diff --git a/source/client/jni/windows/win32/jni_md.h b/source/client/wrapper/jni/windows/win32/jni_md.h similarity index 100% rename from source/client/jni/windows/win32/jni_md.h rename to source/client/wrapper/jni/windows/win32/jni_md.h diff --git a/source/client/src/clientJniConnector.c b/source/client/wrapper/src/clientJniConnector.c similarity index 100% rename from source/client/src/clientJniConnector.c rename to source/client/wrapper/src/clientJniConnector.c diff --git a/source/client/src/clientTmqConnector.c b/source/client/wrapper/src/clientTmqConnector.c similarity index 100% rename from source/client/src/clientTmqConnector.c rename to source/client/wrapper/src/clientTmqConnector.c diff --git a/source/client/wrapper/src/wrapperDriver.c b/source/client/wrapper/src/wrapperDriver.c new file mode 100644 index 0000000000..415affc66f --- /dev/null +++ b/source/client/wrapper/src/wrapperDriver.c @@ -0,0 +1,271 @@ +/* + * 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 "wrapper.h" + +#ifdef WINDOWS +#define DRIVER_NATIVE_NAME "taosnative.dll" +#define DRIVER_WSBSOCKET_NAME "taosws.dll" +#elif defined(DARWIN) +#define DRIVER_NATIVE_NAME "libtaosnative.dylib" +#define DRIVER_WSBSOCKET_NAME "libtaosws.dylib" +#else +#define DRIVER_NATIVE_NAME "libtaosnative.so" +#define DRIVER_WSBSOCKET_NAME "libtaosws.so" +#endif + +#define LOAD_FUNC(fptr, fname) \ + funcName = fname; \ + fptr = taosLoadDllFunc(tsDriver, funcName); \ + if (fptr == NULL) goto _OVER; + +#ifdef WEBSOCKET +EDriverType tsDriverType = DRIVER_NATIVE; // todo simon +#else +EDriverType tsDriverType = DRIVER_NATIVE; +#endif + +void *tsDriver = NULL; + +static int32_t tossGetDevelopPath(char *driverPath, const char *driverName) { + char appPath[PATH_MAX] = {0}; + int32_t ret = taosAppPath(appPath, PATH_MAX); + if (ret == 0) { + snprintf(driverPath, PATH_MAX, "%s%s..%slib%s%s", appPath, TD_DIRSEP, TD_DIRSEP, TD_DIRSEP, driverName); + ret = taosRealPath(driverPath, NULL, PATH_MAX); + } + + return ret; +} + +static int32_t taosGetInstallPath(char *driverPath, const char *driverName) { + tstrncpy(driverPath, driverName, PATH_MAX); + return 0; +} + +int32_t taosDriverInit(EDriverType driverType) { + int32_t code = -1; + char driverPath[PATH_MAX + 32] = {0}; + const char *driverName = NULL; + const char *funcName = NULL; + + if (driverType == DRIVER_NATIVE) { + driverName = DRIVER_NATIVE_NAME; + } else { + driverName = DRIVER_WSBSOCKET_NAME; + } + + if (tsDriver == NULL && tossGetDevelopPath(driverPath, driverName) == 0) { + tsDriver = taosLoadDll(driverPath); + } + + if (tsDriver == NULL && taosGetInstallPath(driverPath, driverName) == 0) { + tsDriver = taosLoadDll(driverPath); + } + + if (tsDriver == NULL) { + printf("failed to load %s since %s [0x%X]\r\n", driverName, terrstr(), terrno); + return code; + } + + // printf("load driver from %s\r\n", driverPath); + LOAD_FUNC(fp_taos_set_config, "taos_set_config"); + + LOAD_FUNC(fp_taos_init, "taos_init"); + LOAD_FUNC(fp_taos_cleanup, "taos_cleanup"); + LOAD_FUNC(fp_taos_options, "taos_options"); + LOAD_FUNC(fp_taos_options_connection, "taos_options_connection"); + LOAD_FUNC(fp_taos_connect, "taos_connect"); + LOAD_FUNC(fp_taos_connect_auth, "taos_connect_auth"); + LOAD_FUNC(fp_taos_close, "taos_close"); + + LOAD_FUNC(fp_taos_data_type, "taos_data_type"); + + LOAD_FUNC(fp_taos_stmt_init, "taos_stmt_init"); + LOAD_FUNC(fp_taos_stmt_init_with_reqid, "taos_stmt_init_with_reqid"); + LOAD_FUNC(fp_taos_stmt_init_with_options, "taos_stmt_init_with_options"); + LOAD_FUNC(fp_taos_stmt_prepare, "taos_stmt_prepare"); + LOAD_FUNC(fp_taos_stmt_set_tbname_tags, "taos_stmt_set_tbname_tags"); + LOAD_FUNC(fp_taos_stmt_set_tbname, "taos_stmt_set_tbname"); + LOAD_FUNC(fp_taos_stmt_set_tags, "taos_stmt_set_tags"); + LOAD_FUNC(fp_taos_stmt_set_sub_tbname, "taos_stmt_set_sub_tbname"); + LOAD_FUNC(fp_taos_stmt_get_tag_fields, "taos_stmt_get_tag_fields"); + LOAD_FUNC(fp_taos_stmt_get_col_fields, "taos_stmt_get_col_fields"); + LOAD_FUNC(fp_taos_stmt_reclaim_fields, "taos_stmt_reclaim_fields"); + + LOAD_FUNC(fp_taos_stmt_is_insert, "taos_stmt_is_insert"); + LOAD_FUNC(fp_taos_stmt_num_params, "taos_stmt_num_params"); + LOAD_FUNC(fp_taos_stmt_get_param, "taos_stmt_get_param"); + LOAD_FUNC(fp_taos_stmt_bind_param, "taos_stmt_bind_param"); + LOAD_FUNC(fp_taos_stmt_bind_param_batch, "taos_stmt_bind_param_batch"); + LOAD_FUNC(fp_taos_stmt_bind_single_param_batch, "taos_stmt_bind_single_param_batch"); + LOAD_FUNC(fp_taos_stmt_add_batch, "taos_stmt_add_batch"); + LOAD_FUNC(fp_taos_stmt_execute, "taos_stmt_execute"); + LOAD_FUNC(fp_taos_stmt_use_result, "taos_stmt_use_result"); + LOAD_FUNC(fp_taos_stmt_close, "taos_stmt_close"); + LOAD_FUNC(fp_taos_stmt_errstr, "taos_stmt_errstr"); + LOAD_FUNC(fp_taos_stmt_affected_rows, "taos_stmt_affected_rows"); + LOAD_FUNC(fp_taos_stmt_affected_rows_once, "taos_stmt_affected_rows_once"); + + LOAD_FUNC(fp_taos_stmt2_init, "taos_stmt2_init"); + LOAD_FUNC(fp_taos_stmt2_prepare, "taos_stmt2_prepare"); + LOAD_FUNC(fp_taos_stmt2_bind_param, "taos_stmt2_bind_param"); + LOAD_FUNC(fp_taos_stmt2_bind_param_a, "taos_stmt2_bind_param_a"); + LOAD_FUNC(fp_taos_stmt2_exec, "taos_stmt2_exec"); + LOAD_FUNC(fp_taos_stmt2_close, "taos_stmt2_close"); + LOAD_FUNC(fp_taos_stmt2_is_insert, "taos_stmt2_is_insert"); + LOAD_FUNC(fp_taos_stmt2_get_fields, "taos_stmt2_get_fields"); + LOAD_FUNC(fp_taos_stmt2_free_fields, "taos_stmt2_free_fields"); + LOAD_FUNC(fp_taos_stmt2_result, "taos_stmt2_result"); + LOAD_FUNC(fp_taos_stmt2_error, "taos_stmt2_error"); + + LOAD_FUNC(fp_taos_query, "taos_query"); + LOAD_FUNC(fp_taos_query_with_reqid, "taos_query_with_reqid"); + + LOAD_FUNC(fp_taos_fetch_row, "taos_fetch_row"); + LOAD_FUNC(fp_taos_result_precision, "taos_result_precision"); + LOAD_FUNC(fp_taos_free_result, "taos_free_result"); + LOAD_FUNC(fp_taos_kill_query, "taos_kill_query"); + LOAD_FUNC(fp_taos_field_count, "taos_field_count"); + LOAD_FUNC(fp_taos_num_fields, "taos_num_fields"); + LOAD_FUNC(fp_taos_affected_rows, "taos_affected_rows"); + LOAD_FUNC(fp_taos_affected_rows64, "taos_affected_rows64"); + + LOAD_FUNC(fp_taos_fetch_fields, "taos_fetch_fields"); + LOAD_FUNC(fp_taos_fetch_fields_e, "taos_fetch_fields_e"); + LOAD_FUNC(fp_taos_select_db, "taos_select_db"); + LOAD_FUNC(fp_taos_print_row, "taos_print_row"); + LOAD_FUNC(fp_taos_print_row_with_size, "taos_print_row_with_size"); + LOAD_FUNC(fp_taos_stop_query, "taos_stop_query"); + LOAD_FUNC(fp_taos_is_null, "taos_is_null"); + LOAD_FUNC(fp_taos_is_null_by_column, "taos_is_null_by_column"); + LOAD_FUNC(fp_taos_is_update_query, "taos_is_update_query"); + LOAD_FUNC(fp_taos_fetch_block, "taos_fetch_block"); + LOAD_FUNC(fp_taos_fetch_block_s, "taos_fetch_block_s"); + LOAD_FUNC(fp_taos_fetch_raw_block, "taos_fetch_raw_block"); + LOAD_FUNC(fp_taos_get_column_data_offset, "taos_get_column_data_offset"); + LOAD_FUNC(fp_taos_validate_sql, "taos_validate_sql"); + LOAD_FUNC(fp_taos_reset_current_db, "taos_reset_current_db"); + + LOAD_FUNC(fp_taos_fetch_lengths, "taos_fetch_lengths"); + LOAD_FUNC(fp_taos_result_block, "taos_result_block"); + + LOAD_FUNC(fp_taos_get_server_info, "taos_get_server_info"); + LOAD_FUNC(fp_taos_get_client_info, "taos_get_client_info"); + LOAD_FUNC(fp_taos_get_current_db, "taos_get_current_db"); + + LOAD_FUNC(fp_taos_errstr, "taos_errstr"); + LOAD_FUNC(fp_taos_errno, "taos_errno"); + + LOAD_FUNC(fp_taos_query_a, "taos_query_a"); + LOAD_FUNC(fp_taos_query_a_with_reqid, "taos_query_a_with_reqid"); + LOAD_FUNC(fp_taos_fetch_rows_a, "taos_fetch_rows_a"); + LOAD_FUNC(fp_taos_fetch_raw_block_a, "taos_fetch_raw_block_a"); + LOAD_FUNC(fp_taos_get_raw_block, "taos_get_raw_block"); + + LOAD_FUNC(fp_taos_get_db_route_info, "taos_get_db_route_info"); + LOAD_FUNC(fp_taos_get_table_vgId, "taos_get_table_vgId"); + LOAD_FUNC(fp_taos_get_tables_vgId, "taos_get_tables_vgId"); + + LOAD_FUNC(fp_taos_load_table_info, "taos_load_table_info"); + + LOAD_FUNC(fp_taos_set_hb_quit, "taos_set_hb_quit"); + + LOAD_FUNC(fp_taos_set_notify_cb, "taos_set_notify_cb"); + + LOAD_FUNC(fp_taos_fetch_whitelist_a, "taos_fetch_whitelist_a"); + + LOAD_FUNC(fp_taos_set_conn_mode, "taos_set_conn_mode"); + + LOAD_FUNC(fp_taos_schemaless_insert, "taos_schemaless_insert"); + LOAD_FUNC(fp_taos_schemaless_insert_with_reqid, "taos_schemaless_insert_with_reqid"); + LOAD_FUNC(fp_taos_schemaless_insert_raw, "taos_schemaless_insert_raw"); + LOAD_FUNC(fp_taos_schemaless_insert_raw_with_reqid, "taos_schemaless_insert_raw_with_reqid"); + LOAD_FUNC(fp_taos_schemaless_insert_ttl, "taos_schemaless_insert_ttl"); + LOAD_FUNC(fp_taos_schemaless_insert_ttl_with_reqid, "taos_schemaless_insert_ttl_with_reqid"); + LOAD_FUNC(fp_taos_schemaless_insert_raw_ttl, "taos_schemaless_insert_raw_ttl"); + LOAD_FUNC(fp_taos_schemaless_insert_raw_ttl_with_reqid, "taos_schemaless_insert_raw_ttl_with_reqid"); + LOAD_FUNC(fp_taos_schemaless_insert_raw_ttl_with_reqid_tbname_key, + "taos_schemaless_insert_raw_ttl_with_reqid_tbname_key"); + LOAD_FUNC(fp_taos_schemaless_insert_ttl_with_reqid_tbname_key, "taos_schemaless_insert_ttl_with_reqid_tbname_key"); + + LOAD_FUNC(fp_tmq_conf_new, "tmq_conf_new"); + LOAD_FUNC(fp_tmq_conf_set, "tmq_conf_set"); + LOAD_FUNC(fp_tmq_conf_destroy, "tmq_conf_destroy"); + LOAD_FUNC(fp_tmq_conf_set_auto_commit_cb, "tmq_conf_set_auto_commit_cb"); + + LOAD_FUNC(fp_tmq_list_new, "tmq_list_new"); + LOAD_FUNC(fp_tmq_list_append, "tmq_list_append"); + LOAD_FUNC(fp_tmq_list_destroy, "tmq_list_destroy"); + LOAD_FUNC(fp_tmq_list_get_size, "tmq_list_get_size"); + LOAD_FUNC(fp_tmq_list_to_c_array, "tmq_list_to_c_array"); + + LOAD_FUNC(fp_tmq_consumer_new, "tmq_consumer_new"); + LOAD_FUNC(fp_tmq_subscribe, "tmq_subscribe"); + LOAD_FUNC(fp_tmq_unsubscribe, "tmq_unsubscribe"); + LOAD_FUNC(fp_tmq_subscription, "tmq_subscription"); + LOAD_FUNC(fp_tmq_consumer_poll, "tmq_consumer_poll"); + LOAD_FUNC(fp_tmq_consumer_close, "tmq_consumer_close"); + LOAD_FUNC(fp_tmq_commit_sync, "tmq_commit_sync"); + LOAD_FUNC(fp_tmq_commit_async, "tmq_commit_async"); + LOAD_FUNC(fp_tmq_commit_offset_sync, "tmq_commit_offset_sync"); + LOAD_FUNC(fp_tmq_commit_offset_async, "tmq_commit_offset_async"); + LOAD_FUNC(fp_tmq_get_topic_assignment, "tmq_get_topic_assignment"); + LOAD_FUNC(fp_tmq_free_assignment, "tmq_free_assignment"); + LOAD_FUNC(fp_tmq_offset_seek, "tmq_offset_seek"); + LOAD_FUNC(fp_tmq_position, "tmq_position"); + LOAD_FUNC(fp_tmq_committed, "tmq_committed"); + + LOAD_FUNC(fp_tmq_get_connect, "tmq_get_connect"); + LOAD_FUNC(fp_tmq_get_table_name, "tmq_get_table_name"); + LOAD_FUNC(fp_tmq_get_res_type, "tmq_get_res_type"); + LOAD_FUNC(fp_tmq_get_topic_name, "tmq_get_topic_name"); + LOAD_FUNC(fp_tmq_get_db_name, "tmq_get_db_name"); + LOAD_FUNC(fp_tmq_get_vgroup_id, "tmq_get_vgroup_id"); + LOAD_FUNC(fp_tmq_get_vgroup_offset, "tmq_get_vgroup_offset"); + LOAD_FUNC(fp_tmq_err2str, "tmq_err2str"); + + LOAD_FUNC(fp_tmq_get_raw, "tmq_get_raw"); + LOAD_FUNC(fp_tmq_write_raw, "tmq_write_raw"); + LOAD_FUNC(fp_taos_write_raw_block, "taos_write_raw_block"); + LOAD_FUNC(fp_taos_write_raw_block_with_reqid, "taos_write_raw_block_with_reqid"); + LOAD_FUNC(fp_taos_write_raw_block_with_fields, "taos_write_raw_block_with_fields"); + LOAD_FUNC(fp_taos_write_raw_block_with_fields_with_reqid, "taos_write_raw_block_with_fields_with_reqid"); + LOAD_FUNC(fp_tmq_free_raw, "tmq_free_raw"); + + LOAD_FUNC(fp_tmq_get_json_meta, "tmq_get_json_meta"); + LOAD_FUNC(fp_tmq_free_json_meta, "tmq_free_json_meta"); + + LOAD_FUNC(fp_taos_check_server_status, "taos_check_server_status"); + LOAD_FUNC(fp_taos_write_crashinfo, "taos_write_crashinfo"); + LOAD_FUNC(fp_getBuildInfo, "getBuildInfo"); + + code = 0; + +_OVER: + if (code != 0) { + printf("failed to load function %s from %s since %s [0x%X]\r\n", funcName, driverPath, terrstr(), terrno); + taosDriverCleanup(); + } + + return code; +} + +void taosDriverCleanup() { + if (tsDriver != NULL) { + taosCloseDll(tsDriver); + tsDriver = NULL; + } +} diff --git a/source/client/wrapper/src/wrapperFunc.c b/source/client/wrapper/src/wrapperFunc.c new file mode 100644 index 0000000000..e77de0b82d --- /dev/null +++ b/source/client/wrapper/src/wrapperFunc.c @@ -0,0 +1,870 @@ +/* + * 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 "version.h" +#include "wrapper.h" + +static TdThreadOnce tsDriverOnce = PTHREAD_ONCE_INIT; +volatile int32_t tsDriverOnceRet = 0; + +#define ERR_VOID(code) \ + terrno = code; \ + return; + +#define ERR_PTR(code) \ + terrno = code; \ + return NULL; + +#define ERR_INT(code) \ + terrno = code; \ + return -1; + +#define ERR_BOOL(code) \ + terrno = code; \ + return false; + +#define ERR_CONFRET(code) \ + terrno = code; \ + setConfRet ret = {.retCode = -1}; \ + return ret; + +#define CHECK_VOID(fp) \ + if (tsDriver == NULL) { \ + ERR_VOID(TSDB_CODE_DLL_NOT_LOAD) \ + } \ + if (fp == NULL) { \ + ERR_VOID(TSDB_CODE_DLL_NOT_LOAD) \ + } + +#define CHECK_PTR(fp) \ + if (tsDriver == NULL) { \ + ERR_PTR(TSDB_CODE_DLL_NOT_LOAD) \ + } \ + if (fp == NULL) { \ + ERR_PTR(TSDB_CODE_DLL_NOT_LOAD) \ + } + +#define CHECK_INT(fp) \ + if (tsDriver == NULL) { \ + ERR_INT(TSDB_CODE_DLL_NOT_LOAD) \ + } \ + if (fp == NULL) { \ + ERR_INT(TSDB_CODE_DLL_NOT_LOAD) \ + } + +#define CHECK_BOOL(fp) \ + if (tsDriver == NULL) { \ + ERR_BOOL(TSDB_CODE_DLL_NOT_LOAD) \ + } \ + if (fp == NULL) { \ + ERR_BOOL(TSDB_CODE_DLL_NOT_LOAD) \ + } + +#define CHECK_CONFRET(fp) \ + if (tsDriver == NULL) { \ + ERR_CONFRET(TSDB_CODE_DLL_NOT_LOAD) \ + } \ + if (fp == NULL) { \ + ERR_CONFRET(TSDB_CODE_DLL_NOT_LOAD) \ + } + +setConfRet taos_set_config(const char *config) { + if (taos_init() != 0) { + ERR_CONFRET(TSDB_CODE_DLL_NOT_LOAD) + } + + CHECK_CONFRET(fp_taos_set_config); + return (*fp_taos_set_config)(config); +} + +static void taos_init_wrapper(void) { + tsDriverOnceRet = taosDriverInit(tsDriverType); + if (tsDriverOnceRet != 0) return; + + if (fp_taos_init == NULL) { + terrno = TSDB_CODE_DLL_FUNC_NOT_LOAD; + tsDriverOnceRet = -1; + } else { + tsDriverOnceRet = (*fp_taos_init)(); + } +} + +int taos_init(void) { + (void)taosThreadOnce(&tsDriverOnce, taos_init_wrapper); + return tsDriverOnceRet; +} + +void taos_cleanup(void) { + CHECK_VOID(fp_taos_cleanup); + (*fp_taos_cleanup)(); +} + +int taos_options(TSDB_OPTION option, const void *arg, ...) { + if (option == TSDB_OPTION_DRIVER) { + if (tsDriver == NULL) { + if (strcasecmp((const char *)arg, "native") == 0) { + tsDriverType = DRIVER_NATIVE; + return 0; + } + if (strcasecmp((const char *)arg, "websocket") == 0) { + tsDriverType = DRIVER_WEBSOCKET; + return 0; + } + } + terrno = TSDB_CODE_REPEAT_INIT; + return -1; + } + + if (taos_init() != 0) { + terrno = TSDB_CODE_DLL_NOT_LOAD; + return -1; + } + + CHECK_INT(fp_taos_options); + return (*fp_taos_options)(option, arg); +} + +int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...) { + CHECK_INT(fp_taos_options_connection); + return (*fp_taos_options_connection)(taos, option, (const char *)arg); +} + +TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) { + if (taos_init() != 0) { + terrno = TSDB_CODE_DLL_NOT_LOAD; + return NULL; + } + + CHECK_PTR(fp_taos_connect); + return (*fp_taos_connect)(ip, user, pass, db, port); +} + +TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port) { + if (taos_init() != 0) { + terrno = TSDB_CODE_DLL_NOT_LOAD; + return NULL; + } + + CHECK_PTR(fp_taos_connect_auth); + return (*fp_taos_connect_auth)(ip, user, auth, db, port); +} + +void taos_close(TAOS *taos) { + CHECK_VOID(fp_taos_close); + (*fp_taos_close)(taos); +} + +const char *taos_data_type(int type) { + CHECK_PTR(fp_taos_data_type); + return (*fp_taos_data_type)(type); +} + +TAOS_STMT *taos_stmt_init(TAOS *taos) { + CHECK_PTR(fp_taos_stmt_init); + return (*fp_taos_stmt_init)(taos); +} + +TAOS_STMT *taos_stmt_init_with_reqid(TAOS *taos, int64_t reqid) { + CHECK_PTR(fp_taos_stmt_init_with_reqid); + return (*fp_taos_stmt_init_with_reqid)(taos, reqid); +} + +TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS *options) { + CHECK_PTR(fp_taos_stmt_init_with_options); + return (*fp_taos_stmt_init_with_options)(taos, options); +} + +int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length) { + CHECK_INT(fp_taos_stmt_prepare); + return (*fp_taos_stmt_prepare)(stmt, sql, length); +} + +int taos_stmt_set_tbname_tags(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags) { + CHECK_INT(fp_taos_stmt_set_tbname_tags); + return (*fp_taos_stmt_set_tbname_tags)(stmt, name, tags); +} + +int taos_stmt_set_tbname(TAOS_STMT *stmt, const char *name) { + CHECK_INT(fp_taos_stmt_set_tbname); + return (*fp_taos_stmt_set_tbname)(stmt, name); +} + +int taos_stmt_set_tags(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags) { + CHECK_INT(fp_taos_stmt_set_tags); + return (*fp_taos_stmt_set_tags)(stmt, tags); +} + +int taos_stmt_set_sub_tbname(TAOS_STMT *stmt, const char *name) { + CHECK_INT(fp_taos_stmt_set_sub_tbname); + return (*fp_taos_stmt_set_sub_tbname)(stmt, name); +} + +int taos_stmt_get_tag_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) { + CHECK_INT(fp_taos_stmt_get_tag_fields); + return (*fp_taos_stmt_get_tag_fields)(stmt, fieldNum, fields); +} + +int taos_stmt_get_col_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) { + CHECK_INT(fp_taos_stmt_get_col_fields); + return (*fp_taos_stmt_get_col_fields)(stmt, fieldNum, fields); +} + +void taos_stmt_reclaim_fields(TAOS_STMT *stmt, TAOS_FIELD_E *fields) { + CHECK_VOID(fp_taos_stmt_reclaim_fields); + (*fp_taos_stmt_reclaim_fields)(stmt, fields); +} + +int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert) { + CHECK_INT(fp_taos_stmt_is_insert); + return (*fp_taos_stmt_is_insert)(stmt, insert); +} + +int taos_stmt_num_params(TAOS_STMT *stmt, int *nums) { + CHECK_INT(fp_taos_stmt_num_params); + return (*fp_taos_stmt_num_params)(stmt, nums); +} + +int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) { + CHECK_INT(fp_taos_stmt_get_param); + return (*fp_taos_stmt_get_param)(stmt, idx, type, bytes); +} + +int taos_stmt_bind_param(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) { + CHECK_INT(fp_taos_stmt_bind_param); + return (*fp_taos_stmt_bind_param)(stmt, bind); +} + +int taos_stmt_bind_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) { + CHECK_INT(fp_taos_stmt_bind_param_batch); + return (*fp_taos_stmt_bind_param_batch)(stmt, bind); +} + +int taos_stmt_bind_single_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind, int colIdx) { + CHECK_INT(fp_taos_stmt_bind_single_param_batch); + return (*fp_taos_stmt_bind_single_param_batch)(stmt, bind, colIdx); +} + +int taos_stmt_add_batch(TAOS_STMT *stmt) { + CHECK_INT(fp_taos_stmt_add_batch); + return (*fp_taos_stmt_add_batch)(stmt); +} + +int taos_stmt_execute(TAOS_STMT *stmt) { + CHECK_INT(fp_taos_stmt_execute); + return (*fp_taos_stmt_execute)(stmt); +} + +TAOS_RES *taos_stmt_use_result(TAOS_STMT *stmt) { + CHECK_PTR(fp_taos_stmt_use_result); + return (*fp_taos_stmt_use_result)(stmt); +} + +int taos_stmt_close(TAOS_STMT *stmt) { + CHECK_INT(fp_taos_stmt_close); + return (*fp_taos_stmt_close)(stmt); +} + +char *taos_stmt_errstr(TAOS_STMT *stmt) { + CHECK_PTR(fp_taos_stmt_errstr); + return (*fp_taos_stmt_errstr)(stmt); +} + +int taos_stmt_affected_rows(TAOS_STMT *stmt) { + CHECK_INT(fp_taos_stmt_affected_rows); + return (*fp_taos_stmt_affected_rows)(stmt); +} + +int taos_stmt_affected_rows_once(TAOS_STMT *stmt) { + CHECK_INT(fp_taos_stmt_affected_rows_once); + return (*fp_taos_stmt_affected_rows_once)(stmt); +} + +TAOS_STMT2 *taos_stmt2_init(TAOS *taos, TAOS_STMT2_OPTION *option) { + CHECK_PTR(fp_taos_stmt2_init); + return (*fp_taos_stmt2_init)(taos, option); +} + +int taos_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length) { + CHECK_INT(fp_taos_stmt2_prepare); + return (*fp_taos_stmt2_prepare)(stmt, sql, length); +} + +int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) { + CHECK_INT(fp_taos_stmt2_bind_param); + return (*fp_taos_stmt2_bind_param)(stmt, bindv, col_idx); +} + +int taos_stmt2_bind_param_a(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx, __taos_async_fn_t fp, + void *param) { + CHECK_INT(fp_taos_stmt2_bind_param_a); + return (*fp_taos_stmt2_bind_param_a)(stmt, bindv, col_idx, fp, param); +} + +int taos_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows) { + CHECK_INT(fp_taos_stmt2_exec); + return (*fp_taos_stmt2_exec)(stmt, affected_rows); +} + +int taos_stmt2_close(TAOS_STMT2 *stmt) { + CHECK_INT(fp_taos_stmt2_close); + return (*fp_taos_stmt2_close)(stmt); +} + +int taos_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert) { + CHECK_INT(fp_taos_stmt2_is_insert); + return (*fp_taos_stmt2_is_insert)(stmt, insert); +} + +int taos_stmt2_get_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields) { + CHECK_INT(fp_taos_stmt2_get_fields); + return (*fp_taos_stmt2_get_fields)(stmt, count, fields); +} + +void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields) { + CHECK_VOID(fp_taos_stmt2_free_fields); + (*fp_taos_stmt2_free_fields)(stmt, fields); +} + +TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt) { + CHECK_PTR(fp_taos_stmt2_result); + return (*fp_taos_stmt2_result)(stmt); +} + +char *taos_stmt2_error(TAOS_STMT2 *stmt) { + CHECK_PTR(fp_taos_stmt2_error); + return (*fp_taos_stmt2_error)(stmt); +} + +TAOS_RES *taos_query(TAOS *taos, const char *sql) { + CHECK_PTR(fp_taos_query); + return (*fp_taos_query)(taos, sql); +} + +TAOS_RES *taos_query_with_reqid(TAOS *taos, const char *sql, int64_t reqId) { + CHECK_PTR(fp_taos_query_with_reqid); + return (*fp_taos_query_with_reqid)(taos, sql, reqId); +} + +TAOS_ROW taos_fetch_row(TAOS_RES *res) { + CHECK_PTR(fp_taos_fetch_row); + return (*fp_taos_fetch_row)(res); +} + +int taos_result_precision(TAOS_RES *res) { + CHECK_INT(fp_taos_result_precision); + return (*fp_taos_result_precision)(res); +} + +void taos_free_result(TAOS_RES *res) { + CHECK_VOID(fp_taos_free_result); + return (*fp_taos_free_result)(res); +} + +void taos_kill_query(TAOS *taos) { + CHECK_VOID(fp_taos_kill_query); + return (*fp_taos_kill_query)(taos); +} + +int taos_field_count(TAOS_RES *res) { + CHECK_INT(fp_taos_field_count); + return (*fp_taos_field_count)(res); +} + +int taos_num_fields(TAOS_RES *res) { + CHECK_INT(fp_taos_num_fields); + return (*fp_taos_num_fields)(res); +} + +int taos_affected_rows(TAOS_RES *res) { + CHECK_INT(fp_taos_affected_rows); + return (*fp_taos_affected_rows)(res); +} + +int64_t taos_affected_rows64(TAOS_RES *res) { + CHECK_INT(fp_taos_affected_rows64); + return (*fp_taos_affected_rows64)(res); +} + +TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) { + CHECK_PTR(fp_taos_fetch_fields); + return (*fp_taos_fetch_fields)(res); +} + +TAOS_FIELD_E *taos_fetch_fields_e(TAOS_RES *res) { + CHECK_PTR(fp_taos_fetch_fields_e); + return (*fp_taos_fetch_fields_e)(res); +} + +int taos_select_db(TAOS *taos, const char *db) { + CHECK_INT(fp_taos_select_db); + return (*fp_taos_select_db)(taos, db); +} + +int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) { + CHECK_INT(fp_taos_print_row); + return (*fp_taos_print_row)(str, row, fields, num_fields); +} + +int taos_print_row_with_size(char *str, uint32_t size, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) { + CHECK_INT(fp_taos_print_row_with_size); + return (*fp_taos_print_row_with_size)(str, size, row, fields, num_fields); +} + +void taos_stop_query(TAOS_RES *res) { + CHECK_VOID(fp_taos_stop_query); + (*fp_taos_stop_query)(res); +} + +bool taos_is_null(TAOS_RES *res, int32_t row, int32_t col) { + CHECK_BOOL(fp_taos_is_null); + return (*fp_taos_is_null)(res, row, col); +} + +int taos_is_null_by_column(TAOS_RES *res, int columnIndex, bool result[], int *rows) { + CHECK_INT(fp_taos_is_null_by_column); + return (*fp_taos_is_null_by_column)(res, columnIndex, result, rows); +} + +bool taos_is_update_query(TAOS_RES *res) { + CHECK_BOOL(fp_taos_is_update_query); + return (*fp_taos_is_update_query)(res); +} + +int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) { + CHECK_INT(fp_taos_fetch_block); + return (*fp_taos_fetch_block)(res, rows); +} + +int taos_fetch_block_s(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows) { + CHECK_INT(fp_taos_fetch_block_s); + return (*fp_taos_fetch_block_s)(res, numOfRows, rows); +} + +int taos_fetch_raw_block(TAOS_RES *res, int *numOfRows, void **pData) { + CHECK_INT(fp_taos_fetch_raw_block); + return (*fp_taos_fetch_raw_block)(res, numOfRows, pData); +} + +int *taos_get_column_data_offset(TAOS_RES *res, int columnIndex) { + CHECK_PTR(fp_taos_get_column_data_offset); + return (*fp_taos_get_column_data_offset)(res, columnIndex); +} + +int taos_validate_sql(TAOS *taos, const char *sql) { + CHECK_INT(fp_taos_validate_sql); + return (*fp_taos_validate_sql)(taos, sql); +} + +void taos_reset_current_db(TAOS *taos) { + CHECK_VOID(fp_taos_reset_current_db); + (*fp_taos_reset_current_db)(taos); +} + +int *taos_fetch_lengths(TAOS_RES *res) { + CHECK_PTR(fp_taos_fetch_lengths); + return (*fp_taos_fetch_lengths)(res); +} + +TAOS_ROW *taos_result_block(TAOS_RES *res) { + CHECK_PTR(fp_taos_result_block); + return (*fp_taos_result_block)(res); +} + +const char *taos_get_server_info(TAOS *taos) { + CHECK_PTR(fp_taos_get_server_info); + return (*fp_taos_get_server_info)(taos); +} + +const char *taos_get_client_info() { + if (fp_taos_get_client_info == NULL) { + return td_version; + } else { + return (*fp_taos_get_client_info)(); + } +} + +int taos_get_current_db(TAOS *taos, char *database, int len, int *required) { + CHECK_INT(fp_taos_get_current_db); + return (*fp_taos_get_current_db)(taos, database, len, required); +} + +const char *taos_errstr(TAOS_RES *res) { + if (fp_taos_errstr == NULL) { + return tstrerror(terrno); + } + return (*fp_taos_errstr)(res); +} + +int taos_errno(TAOS_RES *res) { + if (fp_taos_errno == NULL) { + return terrno; + } + return (*fp_taos_errno)(res); +} + +void taos_query_a(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param) { + CHECK_VOID(fp_taos_query_a); + (*fp_taos_query_a)(taos, sql, fp, param); +} + +void taos_query_a_with_reqid(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param, int64_t reqid) { + CHECK_VOID(fp_taos_query_a_with_reqid); + (*fp_taos_query_a_with_reqid)(taos, sql, fp, param, reqid); +} + +void taos_fetch_rows_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) { + CHECK_VOID(fp_taos_fetch_rows_a); + (*fp_taos_fetch_rows_a)(res, fp, param); +} + +void taos_fetch_raw_block_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) { + CHECK_VOID(fp_taos_fetch_raw_block_a); + (*fp_taos_fetch_raw_block_a)(res, fp, param); +} + +const void *taos_get_raw_block(TAOS_RES *res) { + CHECK_PTR(fp_taos_get_raw_block); + return (*fp_taos_get_raw_block)(res); +} + +int taos_get_db_route_info(TAOS *taos, const char *db, TAOS_DB_ROUTE_INFO *dbInfo) { + CHECK_INT(fp_taos_get_db_route_info); + return (*fp_taos_get_db_route_info)(taos, db, dbInfo); +} + +int taos_get_table_vgId(TAOS *taos, const char *db, const char *table, int *vgId) { + CHECK_INT(fp_taos_get_table_vgId); + return (*fp_taos_get_table_vgId)(taos, db, table, vgId); +} + +int taos_get_tables_vgId(TAOS *taos, const char *db, const char *table[], int tableNum, int *vgId) { + CHECK_INT(fp_taos_get_tables_vgId); + return (*fp_taos_get_tables_vgId)(taos, db, table, tableNum, vgId); +} + +int taos_load_table_info(TAOS *taos, const char *tableNameList) { + CHECK_INT(fp_taos_load_table_info); + return (*fp_taos_load_table_info)(taos, tableNameList); +} + +void taos_set_hb_quit(int8_t quitByKill) { + if (taos_init() != 0) { + return; + } + + CHECK_VOID(fp_taos_set_hb_quit); + return (*fp_taos_set_hb_quit)(quitByKill); +} + +int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type) { + CHECK_INT(fp_taos_set_notify_cb); + return (*fp_taos_set_notify_cb)(taos, fp, param, type); +} + +void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param) { + CHECK_VOID(fp_taos_fetch_whitelist_a); + return (*fp_taos_fetch_whitelist_a)(taos, fp, param); +} + +int taos_set_conn_mode(TAOS *taos, int mode, int value) { + CHECK_INT(fp_taos_set_conn_mode); + return (*fp_taos_set_conn_mode)(taos, mode, value); +} + +TAOS_RES *taos_schemaless_insert(TAOS *taos, char *lines[], int numLines, int protocol, int precision) { + CHECK_PTR(fp_taos_schemaless_insert); + return (*fp_taos_schemaless_insert)(taos, lines, numLines, protocol, precision); +} + +TAOS_RES *taos_schemaless_insert_with_reqid(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int64_t reqid) { + CHECK_PTR(fp_taos_schemaless_insert_with_reqid); + return (*fp_taos_schemaless_insert_with_reqid)(taos, lines, numLines, protocol, precision, reqid); +} + +TAOS_RES *taos_schemaless_insert_raw(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision) { + CHECK_PTR(fp_taos_schemaless_insert_raw); + return (*fp_taos_schemaless_insert_raw)(taos, lines, len, totalRows, protocol, precision); +} + +TAOS_RES *taos_schemaless_insert_raw_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision, int64_t reqid) { + CHECK_PTR(fp_taos_schemaless_insert_raw_with_reqid); + return (*fp_taos_schemaless_insert_raw_with_reqid)(taos, lines, len, totalRows, protocol, precision, reqid); +} + +TAOS_RES *taos_schemaless_insert_ttl(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int32_t ttl) { + CHECK_PTR(fp_taos_schemaless_insert_ttl); + return (*fp_taos_schemaless_insert_ttl)(taos, lines, numLines, protocol, precision, ttl); +} + +TAOS_RES *taos_schemaless_insert_ttl_with_reqid(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int32_t ttl, int64_t reqid) { + CHECK_PTR(fp_taos_schemaless_insert_ttl_with_reqid); + return (*fp_taos_schemaless_insert_ttl_with_reqid)(taos, lines, numLines, protocol, precision, ttl, reqid); +} + +TAOS_RES *taos_schemaless_insert_raw_ttl(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision, int32_t ttl) { + CHECK_PTR(fp_taos_schemaless_insert_raw_ttl); + return (*fp_taos_schemaless_insert_raw_ttl)(taos, lines, len, totalRows, protocol, precision, ttl); +} + +TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision, int32_t ttl, int64_t reqid) { + CHECK_PTR(fp_taos_schemaless_insert_raw_ttl_with_reqid); + return (*fp_taos_schemaless_insert_raw_ttl_with_reqid)(taos, lines, len, totalRows, protocol, precision, ttl, reqid); +} + +TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl, int64_t reqid, + char *tbnameKey) { + CHECK_PTR(fp_taos_schemaless_insert_raw_ttl_with_reqid_tbname_key); + return (*fp_taos_schemaless_insert_raw_ttl_with_reqid_tbname_key)(taos, lines, len, totalRows, protocol, precision, + ttl, reqid, tbnameKey); +} + +TAOS_RES *taos_schemaless_insert_ttl_with_reqid_tbname_key(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid, char *tbnameKey) { + CHECK_PTR(fp_taos_schemaless_insert_ttl_with_reqid_tbname_key); + return (*fp_taos_schemaless_insert_ttl_with_reqid_tbname_key)(taos, lines, numLines, protocol, precision, ttl, reqid, + tbnameKey); +} + +tmq_conf_t *tmq_conf_new() { + CHECK_PTR(fp_tmq_conf_new); + return (*fp_tmq_conf_new)(); +} + +tmq_conf_res_t tmq_conf_set(tmq_conf_t *conf, const char *key, const char *value) { + CHECK_INT(fp_tmq_conf_set); + return (*fp_tmq_conf_set)(conf, key, value); +} + +void tmq_conf_destroy(tmq_conf_t *conf) { + CHECK_VOID(fp_tmq_conf_destroy); + (*fp_tmq_conf_destroy)(conf); +} + +void tmq_conf_set_auto_commit_cb(tmq_conf_t *conf, tmq_commit_cb *cb, void *param) { + CHECK_VOID(fp_tmq_conf_set_auto_commit_cb); + (*fp_tmq_conf_set_auto_commit_cb)(conf, cb, param); +} + +tmq_list_t *tmq_list_new() { + CHECK_PTR(fp_tmq_list_new); + return (*fp_tmq_list_new)(); +} + +int32_t tmq_list_append(tmq_list_t *tlist, const char *val) { + CHECK_INT(fp_tmq_list_append); + return (*fp_tmq_list_append)(tlist, val); +} + +void tmq_list_destroy(tmq_list_t *tlist) { + CHECK_VOID(fp_tmq_list_destroy); + (*fp_tmq_list_destroy)(tlist); +} + +int32_t tmq_list_get_size(const tmq_list_t *tlist) { + CHECK_INT(fp_tmq_list_get_size); + return (*fp_tmq_list_get_size)(tlist); +} + +char **tmq_list_to_c_array(const tmq_list_t *tlist) { + CHECK_PTR(fp_tmq_list_to_c_array); + return (*fp_tmq_list_to_c_array)(tlist); +} + +tmq_t *tmq_consumer_new(tmq_conf_t *conf, char *errstr, int32_t errstrLen) { + CHECK_PTR(fp_tmq_consumer_new); + return (*fp_tmq_consumer_new)(conf, errstr, errstrLen); +} + +int32_t tmq_subscribe(tmq_t *tmq, const tmq_list_t *topic_list) { + CHECK_INT(fp_tmq_subscribe); + return (*fp_tmq_subscribe)(tmq, topic_list); +} + +int32_t tmq_unsubscribe(tmq_t *tmq) { + CHECK_INT(fp_tmq_unsubscribe); + return (*fp_tmq_unsubscribe)(tmq); +} + +int32_t tmq_subscription(tmq_t *tmq, tmq_list_t **topics) { + CHECK_INT(fp_tmq_subscription); + return (*fp_tmq_subscription)(tmq, topics); +} + +TAOS_RES *tmq_consumer_poll(tmq_t *tmq, int64_t timeout) { + CHECK_PTR(fp_tmq_consumer_poll); + return (*fp_tmq_consumer_poll)(tmq, timeout); +} + +int32_t tmq_consumer_close(tmq_t *tmq) { + CHECK_INT(fp_tmq_consumer_close); + return (*fp_tmq_consumer_close)(tmq); +} + +int32_t tmq_commit_sync(tmq_t *tmq, const TAOS_RES *msg) { + CHECK_INT(fp_tmq_commit_sync); + return (*fp_tmq_commit_sync)(tmq, msg); +} + +void tmq_commit_async(tmq_t *tmq, const TAOS_RES *msg, tmq_commit_cb *cb, void *param) { + CHECK_VOID(fp_tmq_commit_async); + (*fp_tmq_commit_async)(tmq, msg, cb, param); +} + +int32_t tmq_commit_offset_sync(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset) { + CHECK_INT(fp_tmq_commit_offset_sync); + return (*fp_tmq_commit_offset_sync)(tmq, pTopicName, vgId, offset); +} + +void tmq_commit_offset_async(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, tmq_commit_cb *cb, + void *param) { + CHECK_VOID(fp_tmq_commit_offset_async); + (*fp_tmq_commit_offset_async)(tmq, pTopicName, vgId, offset, cb, param); +} + +int32_t tmq_get_topic_assignment(tmq_t *tmq, const char *pTopicName, tmq_topic_assignment **assignment, + int32_t *numOfAssignment) { + CHECK_INT(fp_tmq_get_topic_assignment); + return (*fp_tmq_get_topic_assignment)(tmq, pTopicName, assignment, numOfAssignment); +} + +void tmq_free_assignment(tmq_topic_assignment *pAssignment) { + CHECK_VOID(fp_tmq_free_assignment); + (*fp_tmq_free_assignment)(pAssignment); +} + +int32_t tmq_offset_seek(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset) { + CHECK_INT(fp_tmq_offset_seek); + return (*fp_tmq_offset_seek)(tmq, pTopicName, vgId, offset); +} + +int64_t tmq_position(tmq_t *tmq, const char *pTopicName, int32_t vgId) { + CHECK_INT(fp_tmq_position); + return (*fp_tmq_position)(tmq, pTopicName, vgId); +} + +int64_t tmq_committed(tmq_t *tmq, const char *pTopicName, int32_t vgId) { + CHECK_INT(fp_tmq_committed); + return (*fp_tmq_committed)(tmq, pTopicName, vgId); +} + +TAOS *tmq_get_connect(tmq_t *tmq) { + CHECK_PTR(fp_tmq_get_connect); + return (*fp_tmq_get_connect)(tmq); +} + +const char *tmq_get_table_name(TAOS_RES *res) { + CHECK_PTR(fp_tmq_get_table_name); + return (*fp_tmq_get_table_name)(res); +} + +tmq_res_t tmq_get_res_type(TAOS_RES *res) { + CHECK_INT(fp_tmq_get_res_type); + return (*fp_tmq_get_res_type)(res); +} + +const char *tmq_get_topic_name(TAOS_RES *res) { + CHECK_PTR(fp_tmq_get_topic_name); + return (*fp_tmq_get_topic_name)(res); +} + +const char *tmq_get_db_name(TAOS_RES *res) { + CHECK_PTR(fp_tmq_get_db_name); + return (*fp_tmq_get_db_name)(res); +} + +int32_t tmq_get_vgroup_id(TAOS_RES *res) { + CHECK_INT(fp_tmq_get_vgroup_id); + return (*fp_tmq_get_vgroup_id)(res); +} + +int64_t tmq_get_vgroup_offset(TAOS_RES *res) { + CHECK_INT(fp_tmq_get_vgroup_offset); + return (*fp_tmq_get_vgroup_offset)(res); +} + +const char *tmq_err2str(int32_t code) { + CHECK_PTR(fp_tmq_err2str); + return (*fp_tmq_err2str)(code); +} + +int32_t tmq_get_raw(TAOS_RES *res, tmq_raw_data *raw) { + CHECK_INT(fp_tmq_get_raw); + return (*fp_tmq_get_raw)(res, raw); +} + +int32_t tmq_write_raw(TAOS *taos, tmq_raw_data raw) { + CHECK_INT(fp_tmq_write_raw); + return (*fp_tmq_write_raw)(taos, raw); +} + +int taos_write_raw_block(TAOS *taos, int numOfRows, char *pData, const char *tbname) { + CHECK_INT(fp_taos_write_raw_block); + return (*fp_taos_write_raw_block)(taos, numOfRows, pData, tbname); +} + +int taos_write_raw_block_with_reqid(TAOS *taos, int numOfRows, char *pData, const char *tbname, int64_t reqid) { + CHECK_INT(fp_taos_write_raw_block_with_reqid); + return (*fp_taos_write_raw_block_with_reqid)(taos, numOfRows, pData, tbname, reqid); +} + +int taos_write_raw_block_with_fields(TAOS *taos, int rows, char *pData, const char *tbname, TAOS_FIELD *fields, + int numFields) { + CHECK_INT(fp_taos_write_raw_block_with_fields); + return (*fp_taos_write_raw_block_with_fields)(taos, rows, pData, tbname, fields, numFields); +} + +int taos_write_raw_block_with_fields_with_reqid(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields, int64_t reqid) { + CHECK_INT(fp_taos_write_raw_block_with_fields_with_reqid); + return (*fp_taos_write_raw_block_with_fields_with_reqid)(taos, rows, pData, tbname, fields, numFields, reqid); +} + +void tmq_free_raw(tmq_raw_data raw) { + CHECK_VOID(fp_tmq_free_raw); + (*fp_tmq_free_raw)(raw); +} + +char *tmq_get_json_meta(TAOS_RES *res) { + CHECK_PTR(fp_tmq_get_json_meta); + return (*fp_tmq_get_json_meta)(res); +} + +void tmq_free_json_meta(char *jsonMeta) { + CHECK_VOID(fp_tmq_free_json_meta); + return (*fp_tmq_free_json_meta)(jsonMeta); +} + +TSDB_SERVER_STATUS taos_check_server_status(const char *fqdn, int port, char *details, int maxlen) { + CHECK_INT(fp_taos_check_server_status); + return (*fp_taos_check_server_status)(fqdn, port, details, maxlen); +} + +void taos_write_crashinfo(int signum, void *sigInfo, void *context) { + CHECK_VOID(fp_taos_write_crashinfo); + (*fp_taos_write_crashinfo)(signum, sigInfo, context); +} + +char *getBuildInfo() { + CHECK_PTR(fp_getBuildInfo); + return (*fp_getBuildInfo)(); +} diff --git a/source/client/wrapper/src/wrapperVariable.c b/source/client/wrapper/src/wrapperVariable.c new file mode 100644 index 0000000000..ef95b3b3a8 --- /dev/null +++ b/source/client/wrapper/src/wrapperVariable.c @@ -0,0 +1,205 @@ +/* + * 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 = NULL; 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 "wrapper.h" + +setConfRet (*fp_taos_set_config)(const char *config) = NULL; + +int (*fp_taos_init)(void) = NULL; +void (*fp_taos_cleanup)(void) = NULL; +int (*fp_taos_options)(TSDB_OPTION option, const void *arg, ...) = NULL; +int (*fp_taos_options_connection)(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...) = NULL; +TAOS *(*fp_taos_connect)(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) = NULL; +TAOS *(*fp_taos_connect_auth)(const char *ip, const char *user, const char *auth, const char *db, uint16_t port) = NULL; +void (*fp_taos_close)(TAOS *taos) = NULL; + +const char *(*fp_taos_data_type)(int type) = NULL; + +TAOS_STMT *(*fp_taos_stmt_init)(TAOS *taos) = NULL; +TAOS_STMT *(*fp_taos_stmt_init_with_reqid)(TAOS *taos, int64_t reqid) = NULL; +TAOS_STMT *(*fp_taos_stmt_init_with_options)(TAOS *taos, TAOS_STMT_OPTIONS *options) = NULL; +int (*fp_taos_stmt_prepare)(TAOS_STMT *stmt, const char *sql, unsigned long length) = NULL; +int (*fp_taos_stmt_set_tbname_tags)(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags) = NULL; +int (*fp_taos_stmt_set_tbname)(TAOS_STMT *stmt, const char *name) = NULL; +int (*fp_taos_stmt_set_tags)(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags) = NULL; +int (*fp_taos_stmt_set_sub_tbname)(TAOS_STMT *stmt, const char *name) = NULL; +int (*fp_taos_stmt_get_tag_fields)(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) = NULL; +int (*fp_taos_stmt_get_col_fields)(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) = NULL; +void (*fp_taos_stmt_reclaim_fields)(TAOS_STMT *stmt, TAOS_FIELD_E *fields) = NULL; + +int (*fp_taos_stmt_is_insert)(TAOS_STMT *stmt, int *insert) = NULL; +int (*fp_taos_stmt_num_params)(TAOS_STMT *stmt, int *nums) = NULL; +int (*fp_taos_stmt_get_param)(TAOS_STMT *stmt, int idx, int *type, int *bytes) = NULL; +int (*fp_taos_stmt_bind_param)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) = NULL; +int (*fp_taos_stmt_bind_param_batch)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) = NULL; +int (*fp_taos_stmt_bind_single_param_batch)(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind, int colIdx) = NULL; +int (*fp_taos_stmt_add_batch)(TAOS_STMT *stmt) = NULL; +int (*fp_taos_stmt_execute)(TAOS_STMT *stmt) = NULL; +TAOS_RES *(*fp_taos_stmt_use_result)(TAOS_STMT *stmt) = NULL; +int (*fp_taos_stmt_close)(TAOS_STMT *stmt) = NULL; +char *(*fp_taos_stmt_errstr)(TAOS_STMT *stmt) = NULL; +int (*fp_taos_stmt_affected_rows)(TAOS_STMT *stmt) = NULL; +int (*fp_taos_stmt_affected_rows_once)(TAOS_STMT *stmt) = NULL; + +TAOS_STMT2 *(*fp_taos_stmt2_init)(TAOS *taos, TAOS_STMT2_OPTION *option) = NULL; +int (*fp_taos_stmt2_prepare)(TAOS_STMT2 *stmt, const char *sql, unsigned long length) = NULL; +int (*fp_taos_stmt2_bind_param)(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) = NULL; +int (*fp_taos_stmt2_bind_param_a)(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx, __taos_async_fn_t fp, + void *param) = NULL; +int (*fp_taos_stmt2_exec)(TAOS_STMT2 *stmt, int *affected_rows) = NULL; +int (*fp_taos_stmt2_close)(TAOS_STMT2 *stmt) = NULL; +int (*fp_taos_stmt2_is_insert)(TAOS_STMT2 *stmt, int *insert) = NULL; +int (*fp_taos_stmt2_get_fields)(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields) = NULL; +void (*fp_taos_stmt2_free_fields)(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields) = NULL; +TAOS_RES *(*fp_taos_stmt2_result)(TAOS_STMT2 *stmt) = NULL; +char *(*fp_taos_stmt2_error)(TAOS_STMT2 *stmt) = NULL; + +TAOS_RES *(*fp_taos_query)(TAOS *taos, const char *sql) = NULL; +TAOS_RES *(*fp_taos_query_with_reqid)(TAOS *taos, const char *sql, int64_t reqId) = NULL; + +TAOS_ROW (*fp_taos_fetch_row)(TAOS_RES *res) = NULL; +int (*fp_taos_result_precision)(TAOS_RES *res) = NULL; // get the time precision of result +void (*fp_taos_free_result)(TAOS_RES *res) = NULL; +void (*fp_taos_kill_query)(TAOS *taos) = NULL; +int (*fp_taos_field_count)(TAOS_RES *res) = NULL; +int (*fp_taos_num_fields)(TAOS_RES *res) = NULL; +int (*fp_taos_affected_rows)(TAOS_RES *res) = NULL; +int64_t (*fp_taos_affected_rows64)(TAOS_RES *res) = NULL; + +TAOS_FIELD *(*fp_taos_fetch_fields)(TAOS_RES *res) = NULL; +TAOS_FIELD_E *(*fp_taos_fetch_fields_e)(TAOS_RES *res) = NULL; +int (*fp_taos_select_db)(TAOS *taos, const char *db) = NULL; +int (*fp_taos_print_row)(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) = NULL; +int (*fp_taos_print_row_with_size)(char *str, uint32_t size, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) = NULL; +void (*fp_taos_stop_query)(TAOS_RES *res) = NULL; +bool (*fp_taos_is_null)(TAOS_RES *res, int32_t row, int32_t col) = NULL; +int (*fp_taos_is_null_by_column)(TAOS_RES *res, int columnIndex, bool result[], int *rows) = NULL; +bool (*fp_taos_is_update_query)(TAOS_RES *res) = NULL; +int (*fp_taos_fetch_block)(TAOS_RES *res, TAOS_ROW *rows) = NULL; +int (*fp_taos_fetch_block_s)(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows) = NULL; +int (*fp_taos_fetch_raw_block)(TAOS_RES *res, int *numOfRows, void **pData) = NULL; +int *(*fp_taos_get_column_data_offset)(TAOS_RES *res, int columnIndex) = NULL; +int (*fp_taos_validate_sql)(TAOS *taos, const char *sql) = NULL; +void (*fp_taos_reset_current_db)(TAOS *taos) = NULL; + +int *(*fp_taos_fetch_lengths)(TAOS_RES *res) = NULL; +TAOS_ROW *(*fp_taos_result_block)(TAOS_RES *res) = NULL; + +const char *(*fp_taos_get_server_info)(TAOS *taos) = NULL; +const char *(*fp_taos_get_client_info)() = NULL; +int (*fp_taos_get_current_db)(TAOS *taos, char *database, int len, int *required) = NULL; + +const char *(*fp_taos_errstr)(TAOS_RES *res) = NULL; +int (*fp_taos_errno)(TAOS_RES *res) = NULL; + +void (*fp_taos_query_a)(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param) = NULL; +void (*fp_taos_query_a_with_reqid)(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param, + int64_t reqid) = NULL; +void (*fp_taos_fetch_rows_a)(TAOS_RES *res, __taos_async_fn_t fp, void *param) = NULL; +void (*fp_taos_fetch_raw_block_a)(TAOS_RES *res, __taos_async_fn_t fp, void *param) = NULL; +const void *(*fp_taos_get_raw_block)(TAOS_RES *res) = NULL; + +int (*fp_taos_get_db_route_info)(TAOS *taos, const char *db, TAOS_DB_ROUTE_INFO *dbInfo) = NULL; +int (*fp_taos_get_table_vgId)(TAOS *taos, const char *db, const char *table, int *vgId) = NULL; +int (*fp_taos_get_tables_vgId)(TAOS *taos, const char *db, const char *table[], int tableNum, int *vgId) = NULL; + +int (*fp_taos_load_table_info)(TAOS *taos, const char *tableNameList) = NULL; + +void (*fp_taos_set_hb_quit)(int8_t quitByKill) = NULL; + +int (*fp_taos_set_notify_cb)(TAOS *taos, __taos_notify_fn_t fp, void *param, int type) = NULL; + +void (*fp_taos_fetch_whitelist_a)(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param) = NULL; + +int (*fp_taos_set_conn_mode)(TAOS *taos, int mode, int value) = NULL; + +TAOS_RES *(*fp_taos_schemaless_insert)(TAOS *taos, char *lines[], int numLines, int protocol, int precision) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_with_reqid)(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int64_t reqid) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_raw)(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_raw_with_reqid)(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int64_t reqid) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_ttl)(TAOS *taos, char *lines[], int numLines, int protocol, int precision, + int32_t ttl) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_ttl_with_reqid)(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl)(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, + int precision, int32_t ttl) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl_with_reqid)(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl, + int64_t reqid) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_raw_ttl_with_reqid_tbname_key)(TAOS *taos, char *lines, int len, + int32_t *totalRows, int protocol, int precision, + int32_t ttl, int64_t reqid, + char *tbnameKey) = NULL; +TAOS_RES *(*fp_taos_schemaless_insert_ttl_with_reqid_tbname_key)(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid, + char *tbnameKey) = NULL; + +tmq_conf_t *(*fp_tmq_conf_new)() = NULL; +tmq_conf_res_t (*fp_tmq_conf_set)(tmq_conf_t *conf, const char *key, const char *value) = NULL; +void (*fp_tmq_conf_destroy)(tmq_conf_t *conf) = NULL; +void (*fp_tmq_conf_set_auto_commit_cb)(tmq_conf_t *conf, tmq_commit_cb *cb, void *param) = NULL; + +tmq_list_t *(*fp_tmq_list_new)() = NULL; +int32_t (*fp_tmq_list_append)(tmq_list_t *, const char *) = NULL; +void (*fp_tmq_list_destroy)(tmq_list_t *) = NULL; +int32_t (*fp_tmq_list_get_size)(const tmq_list_t *) = NULL; +char **(*fp_tmq_list_to_c_array)(const tmq_list_t *) = NULL; + +tmq_t *(*fp_tmq_consumer_new)(tmq_conf_t *conf, char *errstr, int32_t errstrLen) = NULL; +int32_t (*fp_tmq_subscribe)(tmq_t *tmq, const tmq_list_t *topic_list) = NULL; +int32_t (*fp_tmq_unsubscribe)(tmq_t *tmq) = NULL; +int32_t (*fp_tmq_subscription)(tmq_t *tmq, tmq_list_t **topics) = NULL; +TAOS_RES *(*fp_tmq_consumer_poll)(tmq_t *tmq, int64_t timeout) = NULL; +int32_t (*fp_tmq_consumer_close)(tmq_t *tmq) = NULL; +int32_t (*fp_tmq_commit_sync)(tmq_t *tmq, const TAOS_RES *msg) = NULL; +void (*fp_tmq_commit_async)(tmq_t *tmq, const TAOS_RES *msg, tmq_commit_cb *cb, void *param) = NULL; +int32_t (*fp_tmq_commit_offset_sync)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset) = NULL; +void (*fp_tmq_commit_offset_async)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, tmq_commit_cb *cb, + void *param) = NULL; +int32_t (*fp_tmq_get_topic_assignment)(tmq_t *tmq, const char *pTopicName, tmq_topic_assignment **assignment, + int32_t *numOfAssignment) = NULL; +void (*fp_tmq_free_assignment)(tmq_topic_assignment *pAssignment) = NULL; +int32_t (*fp_tmq_offset_seek)(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset) = NULL; +int64_t (*fp_tmq_position)(tmq_t *tmq, const char *pTopicName, int32_t vgId) = NULL; +int64_t (*fp_tmq_committed)(tmq_t *tmq, const char *pTopicName, int32_t vgId) = NULL; + +TAOS *(*fp_tmq_get_connect)(tmq_t *tmq) = NULL; +const char *(*fp_tmq_get_table_name)(TAOS_RES *res) = NULL; +tmq_res_t (*fp_tmq_get_res_type)(TAOS_RES *res) = NULL; +const char *(*fp_tmq_get_topic_name)(TAOS_RES *res) = NULL; +const char *(*fp_tmq_get_db_name)(TAOS_RES *res) = NULL; +int32_t (*fp_tmq_get_vgroup_id)(TAOS_RES *res) = NULL; +int64_t (*fp_tmq_get_vgroup_offset)(TAOS_RES *res) = NULL; +const char *(*fp_tmq_err2str)(int32_t code) = NULL; + +int32_t (*fp_tmq_get_raw)(TAOS_RES *res, tmq_raw_data *raw) = NULL; +int32_t (*fp_tmq_write_raw)(TAOS *taos, tmq_raw_data raw) = NULL; +int (*fp_taos_write_raw_block)(TAOS *taos, int numOfRows, char *pData, const char *tbname) = NULL; +int (*fp_taos_write_raw_block_with_reqid)(TAOS *taos, int numOfRows, char *pData, const char *tbname, + int64_t reqid) = NULL; +int (*fp_taos_write_raw_block_with_fields)(TAOS *taos, int rows, char *pData, const char *tbname, TAOS_FIELD *fields, + int numFields) = NULL; +int (*fp_taos_write_raw_block_with_fields_with_reqid)(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields, int64_t reqid) = NULL; +void (*fp_tmq_free_raw)(tmq_raw_data raw) = NULL; +char *(*fp_tmq_get_json_meta)(TAOS_RES *res) = NULL; +void (*fp_tmq_free_json_meta)(char *jsonMeta) = NULL; + +TSDB_SERVER_STATUS (*fp_taos_check_server_status)(const char *fqdn, int port, char *details, int maxlen) = NULL; +void (*fp_taos_write_crashinfo)(int signum, void *sigInfo, void *context) = NULL; +char *(*fp_getBuildInfo)() = NULL; diff --git a/source/dnode/mgmt/node_util/CMakeLists.txt b/source/dnode/mgmt/node_util/CMakeLists.txt index 320da45065..ad8282f87f 100644 --- a/source/dnode/mgmt/node_util/CMakeLists.txt +++ b/source/dnode/mgmt/node_util/CMakeLists.txt @@ -6,5 +6,5 @@ target_include_directories( PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) target_link_libraries( - node_util cjson mnode vnode qnode snode wal sync ${TAOS_LIB_STATIC} tfs monitor monitorfw + node_util cjson mnode vnode qnode snode wal sync ${TAOS_NATIVE_LIB_STATIC} tfs monitor monitorfw ) \ No newline at end of file diff --git a/source/libs/catalog/test/CMakeLists.txt b/source/libs/catalog/test/CMakeLists.txt index f23a6beaee..f3b82fd624 100644 --- a/source/libs/catalog/test/CMakeLists.txt +++ b/source/libs/catalog/test/CMakeLists.txt @@ -9,7 +9,7 @@ IF(NOT TD_DARWIN) ADD_EXECUTABLE(catalogTest ${SOURCE_LIST}) TARGET_LINK_LIBRARIES( catalogTest - PUBLIC os util common nodes catalog transport gtest qcom ${TAOS_LIB_STATIC} + PUBLIC os util common nodes catalog transport gtest qcom ${TAOS_NATIVE_LIB_STATIC} ) TARGET_INCLUDE_DIRECTORIES( @@ -19,7 +19,7 @@ IF(NOT TD_DARWIN) ) add_test( - NAME catalogTest - COMMAND catalogTest + NAME catalogTest + COMMAND catalogTest ) ENDIF() diff --git a/source/libs/executor/test/CMakeLists.txt b/source/libs/executor/test/CMakeLists.txt index 4136640847..ab64dd85d4 100644 --- a/source/libs/executor/test/CMakeLists.txt +++ b/source/libs/executor/test/CMakeLists.txt @@ -9,7 +9,7 @@ MESSAGE(STATUS "build parser unit test") # ADD_EXECUTABLE(executorTest ${SOURCE_LIST}) # TARGET_LINK_LIBRARIES( # executorTest -# PRIVATE os util common transport gtest ${TAOS_LIB_STATIC} qcom executor function planner scalar nodes vnode +# PRIVATE os util common transport gtest ${TAOS_NATIVE_LIB_STATIC} qcom executor function planner scalar nodes vnode # ) # # TARGET_INCLUDE_DIRECTORIES( diff --git a/source/libs/scheduler/test/CMakeLists.txt b/source/libs/scheduler/test/CMakeLists.txt index d9572e8dec..ac06d1e167 100644 --- a/source/libs/scheduler/test/CMakeLists.txt +++ b/source/libs/scheduler/test/CMakeLists.txt @@ -8,15 +8,15 @@ IF(NOT TD_DARWIN) ADD_EXECUTABLE(schedulerTest ${SOURCE_LIST}) - IF (TD_GRANT) + IF(TD_GRANT) TARGET_LINK_LIBRARIES( schedulerTest - PUBLIC os util common catalog transport gtest qcom ${TAOS_LIB_STATIC} planner scheduler grant + PUBLIC os util common catalog transport gtest qcom ${TAOS_NATIVE_LIB_STATIC} planner scheduler grant ) - ELSE () + ELSE() TARGET_LINK_LIBRARIES( schedulerTest - PUBLIC os util common catalog transport gtest qcom ${TAOS_LIB_STATIC} planner scheduler + PUBLIC os util common catalog transport gtest qcom ${TAOS_NATIVE_LIB_STATIC} planner scheduler ) ENDIF() @@ -28,6 +28,5 @@ IF(NOT TD_DARWIN) add_test( NAME schedulerTest COMMAND schedulerTest - ) - + ) ENDIF() \ No newline at end of file diff --git a/source/os/CMakeLists.txt b/source/os/CMakeLists.txt index 01103e7bd0..c565b7528d 100644 --- a/source/os/CMakeLists.txt +++ b/source/os/CMakeLists.txt @@ -85,6 +85,7 @@ else() ) endif() + if(JEMALLOC_ENABLED) add_dependencies(os jemalloc) endif() @@ -96,3 +97,4 @@ endif() if(${BUILD_TEST}) add_subdirectory(test) endif(${BUILD_TEST}) + diff --git a/source/os/src/osDir.c b/source/os/src/osDir.c index cf3b84d24e..b10e0c090a 100644 --- a/source/os/src/osDir.c +++ b/source/os/src/osDir.c @@ -58,7 +58,7 @@ int32_t wordexp(char *words, wordexp_t *pwordexp, int32_t flags) { void wordfree(wordexp_t *pwordexp) {} #elif defined(DARWIN) - +#include #include #include #include @@ -77,6 +77,7 @@ typedef struct TdDir { #else +#include #include #include #include @@ -372,8 +373,9 @@ int32_t taosExpandDir(const char *dirname, char *outname, int32_t maxlen) { int32_t taosRealPath(char *dirname, char *realPath, int32_t maxlen) { OS_PARAM_CHECK(dirname); + #ifndef TD_ASTRA - char tmp[PATH_MAX] = {0}; + char tmp[PATH_MAX + 1] = {0}; #ifdef WINDOWS if (_fullpath(tmp, dirname, maxlen) != NULL) { #else @@ -602,6 +604,24 @@ void taosGetCwd(char *buf, int32_t len) { #endif } +int32_t taosAppPath(char *path, int32_t maxLen) { + int32_t ret = 0; + +#ifdef WINDOWS + ret = GetModuleFileName(NULL, path, maxLen - 1); +#elif defined(DARWIN) + ret = _NSGetExecutablePath(path, &maxLen) ; +#else + ret = readlink("/proc/self/exe", path, maxLen - 1); +#endif + + if (ret >= 0) { + ret = (taosDirName(path) == NULL) ? -1 : 0; + } + + return ret; +} + int32_t taosGetDirSize(const char *path, int64_t *size) { int32_t code = 0; char fullPath[PATH_MAX + 100] = {0}; @@ -638,3 +658,54 @@ _OVER: TAOS_UNUSED(taosCloseDir(&pDir)); return code; } + + +void* taosLoadDll(const char* fileName) { +#if defined(WINDOWS) + void* handle = LoadLibraryA(fileName); +#else + void* handle = dlopen(fileName, RTLD_LAZY); +#endif + + if (handle == NULL) { + if (errno != 0) { + terrno = TAOS_SYSTEM_ERROR(errno); + } else { + terrno = TSDB_CODE_DLL_NOT_LOAD; + } + } + + return handle; +} + +void taosCloseDll(void* handle) { + if (handle == NULL) return; + +#if defined(WINDOWS) + FreeLibrary((HMODULE)handle); +#else + if (dlclose(handle) != 0 && errno != 0) { + terrno = TAOS_SYSTEM_ERROR(errno); + } +#endif +} + +void* taosLoadDllFunc(void* handle, const char* funcName) { + if (handle == NULL) return NULL; + +#if defined(WINDOWS) + void *fptr = GetProcAddress((HMODULE)handle, funcName); +#else + void *fptr = dlsym(handle, funcName); +#endif + + if (handle == NULL) { + if (errno != 0) { + terrno = TAOS_SYSTEM_ERROR(errno); + } else { + terrno = TSDB_CODE_DLL_FUNC_NOT_LOAD; + } + } + + return fptr; +} diff --git a/source/os/src/osSystem.c b/source/os/src/osSystem.c index 38114a8deb..837a4791f6 100644 --- a/source/os/src/osSystem.c +++ b/source/os/src/osSystem.c @@ -88,38 +88,6 @@ struct termios oldtio; typedef struct FILE TdCmd; -#ifdef BUILD_NO_CALL -void* taosLoadDll(const char* filename) { -#if defined(WINDOWS) - return NULL; -#elif defined(_TD_DARWIN_64) - return NULL; -#else - void* handle = dlopen(filename, RTLD_LAZY); - if (!handle) { - // printf("load dll:%s failed, error:%s", filename, dlerror()); - return NULL; - } - - // printf("dll %s loaded", filename); - - return handle; -#endif -} - -void taosCloseDll(void* handle) { -#if defined(WINDOWS) - return; -#elif defined(_TD_DARWIN_64) - return; -#else - if (handle) { - dlclose(handle); - } -#endif -} -#endif - int32_t taosSetConsoleEcho(bool on) { #if defined(WINDOWS) HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); diff --git a/source/util/src/terror.c b/source/util/src/terror.c index fd88a53b23..0e7d1bcbdd 100644 --- a/source/util/src/terror.c +++ b/source/util/src/terror.c @@ -76,7 +76,8 @@ TAOS_DEFINE_ERROR(TSDB_CODE_REF_ID_REMOVED, "Ref ID is removed") TAOS_DEFINE_ERROR(TSDB_CODE_REF_INVALID_ID, "Invalid Ref ID") TAOS_DEFINE_ERROR(TSDB_CODE_REF_ALREADY_EXIST, "Ref is already there") TAOS_DEFINE_ERROR(TSDB_CODE_REF_NOT_EXIST, "Ref is not there") - +TAOS_DEFINE_ERROR(TSDB_CODE_DLL_NOT_LOAD, "Driver was not loaded") +TAOS_DEFINE_ERROR(TSDB_CODE_DLL_FUNC_NOT_LOAD, "Function was not loaded from the driver") TAOS_DEFINE_ERROR(TSDB_CODE_APP_ERROR, "Unexpected generic error") TAOS_DEFINE_ERROR(TSDB_CODE_ACTION_IN_PROGRESS, "Action in progress") TAOS_DEFINE_ERROR(TSDB_CODE_OUT_OF_RANGE, "Out of range") diff --git a/source/util/src/tlog.c b/source/util/src/tlog.c index 3bc984aabe..367b4431a3 100644 --- a/source/util/src/tlog.c +++ b/source/util/src/tlog.c @@ -1374,6 +1374,10 @@ static void checkWriteCrashLogToFileInNewThead() { } taosLogCrashInfo(gCrashBasicInfo.nodeType, pMsg, msgLen, gCrashBasicInfo.signum, gCrashBasicInfo.sigInfo); setCrashWriterStatus(CRASH_LOG_WRITER_INIT); + int32_t code = tsem_post(&gCrashBasicInfo.sem); + if (code != 0 ) { + uError("failed to post sem for crashBasicInfo, code:%d", code); + } TAOS_UNUSED(tsem_post(&gCrashBasicInfo.sem)); } } diff --git a/source/util/test/errorCodeTable.ini b/source/util/test/errorCodeTable.ini index f66948504d..c135b677bf 100644 --- a/source/util/test/errorCodeTable.ini +++ b/source/util/test/errorCodeTable.ini @@ -17,6 +17,8 @@ TSDB_CODE_REF_ID_REMOVED = 0x80000107 TSDB_CODE_REF_INVALID_ID = 0x80000108 TSDB_CODE_REF_ALREADY_EXIST = 0x80000109 TSDB_CODE_REF_NOT_EXIST = 0x8000010A +TSDB_CODE_DLL_NOT_LOAD = 0x8000010B +TSDB_CODE_DLL_FUNC_NOT_LOAD = 0x8000010C TSDB_CODE_APP_ERROR = 0x80000110 TSDB_CODE_ACTION_IN_PROGRESS = 0x80000111 TSDB_CODE_OUT_OF_RANGE = 0x80000112 diff --git a/tests/army/cmdline/taosCli.py b/tests/army/cmdline/taosCli.py index aed9400111..2624248a28 100644 --- a/tests/army/cmdline/taosCli.py +++ b/tests/army/cmdline/taosCli.py @@ -57,31 +57,29 @@ class TDTestCase(TBase): def checkResultWithMode(self, db, stb, arg): result = "Query OK, 10 row(s)" mode = arg[0] - rowh = arg[1] - rowv = arg[2] - idx = arg[3] - idxv = arg[4] # use db - if mode != "-R": - rlist = self.taos(f'{mode} -s "show databases;use {db};show databases;" ') - self.checkListString(rlist, "Database changed") + rlist = self.taos(f'{mode} -s "show databases;use {db};show databases;" ') + self.checkListString(rlist, "Database changed") # hori - cmd = f'{mode} -s "select * from {db}.{stb} limit 10' + cmd = f'{mode} -s "select ts,ic from {db}.{stb} limit 10' rlist = self.taos(cmd + '"') - # line count - self.checkSame(len(rlist), rowh) - # last line - self.checkSame(rlist[idx][:len(result)], result) + results = [ + "2022-10-01 00:00:09.000 |", + result + ] + self.checkManyString(rlist, results) # vec rlist = self.taos(cmd + '\G"') - # line count - self.checkSame(len(rlist), rowv) - self.checkSame(rlist[idxv], "*************************** 10.row ***************************") - # last line - self.checkSame(rlist[idx][:len(result)], result) + results = [ + "****** 10.row *******", + "ts: 2022-10-01 00:00:09.000", + result + ] + self.checkManyString(rlist, results) + # -B have some problem need todo self.taos(f'{mode} -B -s "select * from {db}.{stb} where ts < 1"') @@ -125,12 +123,16 @@ class TDTestCase(TBase): # insert json = "cmdline/json/taosCli.json" db, stb, childCount, insertRows = self.insertBenchJson(json) + # set + self.db = db + self.stb = stb + self.insert_rows = insertRows + self.childtable_count = childCount # native restful websock test args = [ - ["", 18, 346, -2, 310], - ["-R", 22, 350, -3, 313], - ["-T 40 -E http://localhost:6041", 21, 349, -3, 312] + ["-Z native"], + ["-T 40 -E http://localhost:6041"] ] for arg in args: self.checkResultWithMode(db, stb, arg) @@ -164,8 +166,7 @@ class TDTestCase(TBase): def checkDumpInOut(self): args = [ - ["", 18], - ["-R ", 22], + ["", 18], ["-E http://localhost:6041", 21] ] @@ -181,10 +182,18 @@ class TDTestCase(TBase): rlist2 = self.taos("--version") self.checkSame(rlist1, rlist2) - self.checkSame(len(rlist1), 5) + if len(rlist1) < 4: + tdLog.exit(f"version lines less than 4. {rlist1}") if len(rlist1[2]) < 42: tdLog.exit("git commit id length is invalid: " + rlist1[2]) + + keys = [ + "version:", + "git:", + "build:" + ] + self.checkManyString(rlist1, keys) def checkHelp(self): @@ -205,20 +214,13 @@ class TDTestCase(TBase): def checkCommand(self): # check coredump - - # o logpath - char = 'a' - lname =f'-o "/root/log/{char * 1000}/" -s "quit;"' queryOK = "Query OK" - # invalid input check + # support Both args = [ - [lname, "failed to create log at"], ['-uroot -w 40 -ptaosdata -c /root/taos/ -s"show databases"', queryOK], - ['-o "./current/log/files/" -s"show databases;"', queryOK], - ['-a ""', "Invalid auth"], + ['-o "./current/log/files/" -h localhost -uroot -ptaosdata -s"show databases;"', queryOK], ['-s "quit;"', "Welcome to the TDengine Command Line Interface"], - ['-a "abc"', "[0x80000357]"], ['-h "" -s "show dnodes;"', "Invalid host"], ['-u "" -s "show dnodes;"', "Invalid user"], ['-P "" -s "show dnodes;"', "Invalid port"], @@ -226,7 +228,7 @@ class TDTestCase(TBase): ['-p"abc" -s "show dnodes;"', "[0x80000357]"], ['-d "abc" -s "show dnodes;"', "[0x80000388]"], ['-N 0 -s "show dnodes;"', "Invalid pktNum"], - ['-N 10 -s "show dnodes;"', queryOK], + ['-N 10 -h 127.0.0.1 -s "show dnodes;"', queryOK], ['-w 0 -s "show dnodes;"', "Invalid displayWidth"], ['-w 10 -s "show dnodes;"', queryOK], ['-W 10 -s "show dnodes;"', None], @@ -240,10 +242,133 @@ class TDTestCase(TBase): ['-uroot -p < cmdline/data/pwd.txt -s "show dnodes;"', queryOK], ] + modes = ["-Z 0","-Z 1"] + for mode in modes: + for arg in args: + rlist = self.taos(mode + " " + arg[0]) + if arg[1] != None: + self.checkListString(rlist, arg[1]) + + # + # support native only + # + + # o logpath + char = 'a' + lname =f'-o "/root/log/{char * 1000}/" -s "quit;"' + + args = [ + [lname, "failed to create log at"], + ['-a ""', "Invalid auth"], + ['-a "abc"', "[0x80000357]"], + ] for arg in args: - rlist = self.taos(arg[0]) + rlist = self.taos("Z 0 " + arg[0]) if arg[1] != None: - self.checkListString(rlist, arg[1]) + self.checkListString(rlist, arg[1]) + + # expect cmd > json > evn + def checkPriority(self): + # + # cmd & env + # + + # env 6043 - invalid + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6043" + # cmd 6041 - valid + cmd = f"-X http://127.0.0.1:6041 -s 'select ts from test.meters'" + rlist = self.taos(cmd, checkRun = True) + results = [ + "WebSocket Client Version", + "2022-10-01 00:01:39.000", + "Query OK, 200 row(s) in set" + ] + self.checkManyString(rlist, results) + + # + # env + # + + # cloud + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6041" + cmd = f"-s 'select ts from test.meters'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + # local + os.environ['TDENGINE_CLOUD_DSN'] = "" + os.environ['TDENGINE_DSN'] = "http://127.0.0.1:6041" + cmd = f"-s 'select ts from test.meters'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + # local & cloud -> cloud first + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6041" # valid + os.environ['TDENGINE_DSN'] = "http://127.0.0.1:6042" # invalid + cmd = f"-s 'select ts from test.meters'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + + + # + # cmd + # + + os.environ['TDENGINE_CLOUD_DSN'] = "" + os.environ['TDENGINE_DSN'] = "" + cmd = f"-X http://127.0.0.1:6041 -s 'select ts from test.meters'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + + + def checkExceptCmd(self): + # exe + taos = frame.etool.taosFile() + # option + options = [ + "-Z native -X http://127.0.0.1:6041", + "-Z 100", + "-Z abcdefg", + "-X", + "-X ", + "-X 127.0.0.1:6041", + "-X https://gw.cloud.taosdata.com?token617ffdf...", + "-Z 1 -X https://gw.cloud.taosdata.com?token=617ffdf...", + "-X http://127.0.0.1:6042" + ] + + # do check + for option in options: + self.checkExcept(taos + " -s 'show dnodes;' " + option) + + def checkModeVersion(self): + # results + results = [ + "WebSocket Client Version", + "2022-10-01 00:01:39.000", + "Query OK, 100 row(s) in set" + ] + + # default + cmd = f"-s 'select ts from test.d0'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + # websocket + cmd = f"-Z 1 -s 'select ts from test.d0'" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + + # native + cmd = f"-Z 0 -s 'select ts from test.d0'" + results[0] = "Native Client Version" + rlist = self.taos(cmd, checkRun = True) + self.checkManyString(rlist, results) + + def checkConnMode(self): + # priority + self.checkPriority() + # except + self.checkExceptCmd() + # mode version + self.checkModeVersion() # password def checkPassword(self): @@ -288,6 +413,10 @@ class TDTestCase(TBase): # check data in/out self.checkDumpInOut() + + # check conn mode + self.checkConnMode() + # max password self.checkPassword() diff --git a/tests/army/frame/caseBase.py b/tests/army/frame/caseBase.py index 37f025468c..b8345c3257 100644 --- a/tests/army/frame/caseBase.py +++ b/tests/army/frame/caseBase.py @@ -38,6 +38,12 @@ class TBase: # init def init(self, conn, logSql, replicaVar=1, db="db", stb="stb", checkColName="ic"): + + # init + self.childtable_count = 0 + self.insert_rows = 0 + self.timestamp_step = 0 + # save param self.replicaVar = int(replicaVar) tdSql.init(conn.cursor(), True) @@ -54,12 +60,12 @@ class TBase: self.stb = stb # sql - self.sqlSum = f"select sum({checkColName}) from {self.stb}" - self.sqlMax = f"select max({checkColName}) from {self.stb}" - self.sqlMin = f"select min({checkColName}) from {self.stb}" - self.sqlAvg = f"select avg({checkColName}) from {self.stb}" - self.sqlFirst = f"select first(ts) from {self.stb}" - self.sqlLast = f"select last(ts) from {self.stb}" + self.sqlSum = f"select sum({checkColName}) from {db}.{self.stb}" + self.sqlMax = f"select max({checkColName}) from {db}.{self.stb}" + self.sqlMin = f"select min({checkColName}) from {db}.{self.stb}" + self.sqlAvg = f"select avg({checkColName}) from {db}.{self.stb}" + self.sqlFirst = f"select first(ts) from {db}.{self.stb}" + self.sqlLast = f"select last(ts) from {db}.{self.stb}" # stop def stop(self): @@ -140,15 +146,15 @@ class TBase: # basic def checkInsertCorrect(self, difCnt = 0): # check count - sql = f"select count(*) from {self.stb}" + sql = f"select count(*) from {self.db}.{self.stb}" tdSql.checkAgg(sql, self.childtable_count * self.insert_rows) # check child table count - sql = f" select count(*) from (select count(*) as cnt , tbname from {self.stb} group by tbname) where cnt = {self.insert_rows} " + sql = f" select count(*) from (select count(*) as cnt , tbname from {self.db}.{self.stb} group by tbname) where cnt = {self.insert_rows} " tdSql.checkAgg(sql, self.childtable_count) # check step - sql = f"select count(*) from (select diff(ts) as dif from {self.stb} partition by tbname order by ts desc) where dif != {self.timestamp_step}" + sql = f"select count(*) from (select diff(ts) as dif from {self.db}.{self.stb} partition by tbname order by ts desc) where dif != {self.timestamp_step}" tdSql.checkAgg(sql, difCnt) # save agg result @@ -172,27 +178,27 @@ class TBase: # self check def checkConsistency(self, col): # top with max - sql = f"select max({col}) from {self.stb}" + sql = f"select max({col}) from {self.db}.{self.stb}" expect = tdSql.getFirstValue(sql) - sql = f"select top({col}, 5) from {self.stb}" + sql = f"select top({col}, 5) from {self.db}.{self.stb}" tdSql.checkFirstValue(sql, expect) #bottom with min - sql = f"select min({col}) from {self.stb}" + sql = f"select min({col}) from {self.db}.{self.stb}" expect = tdSql.getFirstValue(sql) - sql = f"select bottom({col}, 5) from {self.stb}" + sql = f"select bottom({col}, 5) from {self.db}.{self.stb}" tdSql.checkFirstValue(sql, expect) # order by asc limit 1 with first - sql = f"select last({col}) from {self.stb}" + sql = f"select last({col}) from {self.db}.{self.stb}" expect = tdSql.getFirstValue(sql) - sql = f"select {col} from {self.stb} order by _c0 desc limit 1" + sql = f"select {col} from {self.db}.{self.stb} order by _c0 desc limit 1" tdSql.checkFirstValue(sql, expect) # order by desc limit 1 with last - sql = f"select first({col}) from {self.stb}" + sql = f"select first({col}) from {self.db}.{self.db}." expect = tdSql.getFirstValue(sql) - sql = f"select {col} from {self.stb} order by _c0 asc limit 1" + sql = f"select {col} from {self.db}.{self.db}. order by _c0 asc limit 1" tdSql.checkFirstValue(sql, expect) @@ -243,6 +249,17 @@ class TBase: else: tdLog.exit(f"check same failed. real={real} expect={expect}.") + # check except + def checkExcept(self, command): + try: + code = frame.eos.exe(command, show = True) + if code == 0: + tdLog.exit(f"Failed, not report error cmd:{command}") + else: + tdLog.info(f"Passed, report error code={code} is expect, cmd:{command}") + except: + tdLog.info(f"Passed, catch expect report error for command {command}") + # # get db information # @@ -292,7 +309,8 @@ class TBase: def taosdump(self, command, show = True, checkRun = True, retFail = True): return frame.etool.runBinFile("taosdump", command, show, checkRun, retFail) - + def benchmark(self, command, show = True, checkRun = True, retFail = True): + return frame.etool.runBinFile("taosBenchmark", command, show, checkRun, retFail) # # util # @@ -335,15 +353,22 @@ class TBase: # check list have str - def checkListString(self, vlist, s): - for i in range(len(vlist)): - if vlist[i].find(s) != -1: + def checkListString(self, rlist, s): + if s is None: + return + for i in range(len(rlist)): + if rlist[i].find(s) != -1: # found - tdLog.info(f'found "{s}" on index {i} , line={vlist[i]}') + tdLog.info(f'found "{s}" on index {i} , line={rlist[i]}') return # not found - tdLog.exit(f'faild, not found "{s}" on list:{vlist}') + tdLog.exit(f'faild, not found "{s}" on list:{rlist}') + + # check many string + def checkManyString(self, rlist, manys): + for s in manys: + self.checkListString(rlist, s) # # str util @@ -480,6 +505,23 @@ class TBase: return rlist + # cmd + def benchmarkCmd(self, options, childCnt, insertRows, timeStep, results): + # set + self.childtable_count = childCnt + self.insert_rows = insertRows + self.timestamp_step = timeStep + + # run + cmd = f"{options} -t {childCnt} -n {insertRows} -S {timeStep} -y" + rlist = self.benchmark(cmd) + for result in results: + self.checkListString(rlist, result) + + # check correct + self.checkInsertCorrect() + + # generate new json file def genNewJson(self, jsonFile, modifyFunc=None): try: diff --git a/tests/army/frame/etool.py b/tests/army/frame/etool.py index 4ad3efb036..041a43d4df 100644 --- a/tests/army/frame/etool.py +++ b/tests/army/frame/etool.py @@ -23,6 +23,14 @@ import frame.epath import frame.eos from frame.log import * + +# taos +def taosFile(): + bmFile = frame.epath.binFile("taos") + if frame.eos.isWin(): + bmFile += ".exe" + return bmFile + # taosdump def taosDumpFile(): bmFile = frame.epath.binFile("taosdump") diff --git a/tests/army/pytest.sh b/tests/army/pytest.sh index bae0fdf278..c267b74bc3 100755 --- a/tests/army/pytest.sh +++ b/tests/army/pytest.sh @@ -89,6 +89,10 @@ else export LD_PRELOAD="$(realpath "$(gcc -print-file-name=libasan.so)") $(realpath "$(gcc -print-file-name=libstdc++.so)")" echo "Preload AsanSo:" $? + export ASAN_OPTIONS=detect_odr_violation=0 + echo "forbid check ODR violation." + + $* -a 2>$AsanFile unset LD_PRELOAD diff --git a/tests/army/test.py b/tests/army/test.py index 6ac0948b7b..a66743b40a 100644 --- a/tests/army/test.py +++ b/tests/army/test.py @@ -37,6 +37,9 @@ import taos import taosrest import taosws +from taos.cinterface import * +taos.taos_options(6, "native") + def checkRunTimeError(): import win32gui timeCount = 0 @@ -258,8 +261,9 @@ if __name__ == "__main__": # # do exeCmd command # + taosAdapter = True # default is websocket , so must start taosAdapter if not execCmd == "": - if taosAdapter or taosAdapter or restful or websocket: + if taosAdapter or restful or websocket: tAdapter.init(deployPath) else: tdDnodes.init(deployPath) diff --git a/tests/army/tools/benchmark/basic/commandline-sml-rest.py b/tests/army/tools/benchmark/basic/commandline-sml-rest.py deleted file mode 100644 index 3f5bcd8040..0000000000 --- a/tests/army/tools/benchmark/basic/commandline-sml-rest.py +++ /dev/null @@ -1,75 +0,0 @@ -################################################################### -# 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 - -import frame -import frame.etool -from frame.log import * -from frame.cases import * -from frame.sql import * -from frame.caseBase import * -from frame import * - - - -class TDTestCase(TBase): - def caseDescription(self): - """ - [TD-22334] taosBenchmark sml rest test cases - """ - - - def run(self): - binPath = etool.benchMarkFile() - - cmd = "%s -I sml-rest -t 1 -n 1 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - tdSql.query("select count(*) from test.meters") - tdSql.checkData(0, 0, 1) - - cmd = "%s -I sml-rest-line -t 1 -n 1 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - tdSql.query("select count(*) from test.meters") - tdSql.checkData(0, 0, 1) - - cmd = "%s -I sml-rest-telnet -t 1 -n 1 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - tdSql.query("select count(*) from test.meters") - tdSql.checkData(0, 0, 1) - - cmd = "%s -I sml-rest-json -t 1 -n 1 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - tdSql.query("select count(*) from test.meters") - tdSql.checkData(0, 0, 1) - - cmd = "%s -I sml-rest-taosjson -t 1 -n 1 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - tdSql.query("select count(*) from test.meters") - tdSql.checkData(0, 0, 1) - - cmd = "%s -N -I sml-rest -y" % binPath - tdLog.info("%s" % cmd) - assert os.system("%s" % cmd) != 0 - - def stop(self): - tdSql.close() - tdLog.success("%s successfully executed" % __file__) - - -tdCases.addWindows(__file__, TDTestCase()) -tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/army/tools/benchmark/basic/commandline-sml.py b/tests/army/tools/benchmark/basic/commandline-sml.py index 7c3dc39f7b..4533dedbbd 100644 --- a/tests/army/tools/benchmark/basic/commandline-sml.py +++ b/tests/army/tools/benchmark/basic/commandline-sml.py @@ -67,6 +67,16 @@ class TDTestCase(TBase): tdSql.query("select count(*) from test.meters") tdSql.checkData(0, 0, 10*10000) + # add normal table + cmd = "%s -N -I sml -t 2 -n 10000 -y" % binPath + tdLog.info("%s" % cmd) + os.system("%s" % cmd) + + tdSql.query("select count(*) from test.d0") + tdSql.checkData(0, 0, 1*10000) + tdSql.query("select count(*) from test.d1") + tdSql.checkData(0, 0, 1*10000) + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) diff --git a/tests/army/tools/benchmark/basic/commandline.py b/tests/army/tools/benchmark/basic/commandline.py index 94b812aed0..3330056d51 100644 --- a/tests/army/tools/benchmark/basic/commandline.py +++ b/tests/army/tools/benchmark/basic/commandline.py @@ -184,7 +184,7 @@ class TDTestCase(TBase): tdSql.query("select last(ts) from test.meters") tdSql.checkData(0, 0, "2017-07-14 10:40:00.034") - cmd = "%s -N -I taosc -t 11 -n 11 -y -x -E" % binPath + cmd = "%s -N -I taosc -t 11 -n 11 -y -x -E -c abcde" % binPath tdLog.info("%s" % cmd) os.system("%s" % cmd) tdSql.execute("use test") @@ -195,7 +195,7 @@ class TDTestCase(TBase): tdSql.query("select count(*) from `d10`") tdSql.checkData(0, 0, 11) - cmd = "%s -N -I rest -t 11 -n 11 -y -x" % binPath + cmd = "%s -N -I rest -t 11 -n 11 -y -x -c /etc/taos" % binPath tdLog.info("%s" % cmd) os.system("%s" % cmd) tdSql.execute("use test") @@ -315,21 +315,6 @@ class TDTestCase(TBase): tdSql.query("describe test.meters") tdSql.checkData(1, 1, "NCHAR") - # 2.x is binary and 3.x is varchar - # cmd = "%s -n 1 -t 1 -y -b binary" %binPath - # tdLog.info("%s" % cmd) - # os.system("%s" % cmd) - # tdSql.execute("reset query cache") - # tdSql.query("describe test.meters") - # tdSql.checkData(1, 1, "BINARY") - - # cmd = "%s -n 1 -t 1 -y -b binary\(7\)" %binPath - # tdLog.info("%s" % cmd) - # os.system("%s" % cmd) - # tdSql.execute("reset query cache") - # tdSql.query("describe test.meters") - # tdSql.checkData(1, 1, "BINARY") - cmd = "%s -n 1 -t 1 -y -A json" % binPath tdLog.info("%s" % cmd) os.system("%s" % cmd) diff --git a/tests/army/tools/benchmark/basic/connMode.py b/tests/army/tools/benchmark/basic/connMode.py new file mode 100644 index 0000000000..0f3a99a386 --- /dev/null +++ b/tests/army/tools/benchmark/basic/connMode.py @@ -0,0 +1,158 @@ +################################################################### +# 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, signal +import os +from time import sleep +import frame +import frame.etool +from frame.log import * +from frame.cases import * +from frame.sql import * +from frame.caseBase import * +from frame import * + + +class TDTestCase(TBase): + def caseDescription(self): + """ + taosBenchmark public->connMode test cases + """ + + # expect cmd > evn > json + def checkPriority(self): + + # + # cmd & json + # + + # cmd first 6041 - valid + options = "-X http://127.0.0.1:6041" + # json 6042 - invalid + json = "tools/benchmark/basic/json/connModePriorityErrDsn.json" + self.insertBenchJson(json, options, True) + + # + # env > json + # + + # env 6041 - valid + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6041" + # json 6042 - invalid + json = "tools/benchmark/basic/json/connModePriorityErrDsn.json" + self.insertBenchJson(json, "", True) + + + # + # cmd & json & evn + # + + # cmd 6041 - valid + options = "-X http://127.0.0.1:6041" + # env 6043 - invalid + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6043" + # json 6042 - invalid + json = "tools/benchmark/basic/json/connModePriorityErrDsn.json" + self.insertBenchJson(json, options, True) + + # clear env + os.environ['TDENGINE_CLOUD_DSN'] = "" + + def checkCommandLine(self): + # modes + modes = ["", "-Z 1 -B 1", "-Z websocket", "-Z 0", "-Z native -B 2"] + # result + Rows = "insert rows: 9990" + results1 = [ + ["Connect mode is : WebSocket", Rows], + ["Connect mode is : WebSocket", Rows], + ["Connect mode is : WebSocket", Rows], + ["Connect mode is : Native", Rows], + ["Connect mode is : Native", Rows], + ] + # iface todo add sml + iface = ["taosc", "stmt", "stmt2"] + + # do check + for face in iface: + for i in range(len(modes)): + self.benchmarkCmd(f"{modes[i]} -I {face}", 10, 999, 1000, results1[i]) + + + def checkExceptCmd(self): + # exe + bench = frame.etool.benchMarkFile() + # option + options = [ + "-Z native -X http://127.0.0.1:6041", + "-Z 100", + "-Z abcdefg", + "-X", + "-X 127.0.0.1:6041", + "-X https://gw.cloud.taosdata.com?token617ffdf...", + "-Z 1 -X https://gw.cloud.taosdata.com?token=617ffdf...", + "-X http://127.0.0.1:6042" + ] + + # do check + for option in options: + self.checkExcept(bench + " -y " + option) + + def checkHostPort(self): + # + # ommand + # + self.benchmarkCmd("-h 127.0.0.1", 5, 100, 10, ["insert rows: 500"]) + self.benchmarkCmd("-h 127.0.0.1 -P 6041 -uroot -ptaosdata", 5, 100, 10, ["insert rows: 500"]) + self.benchmarkCmd("-Z 0 -h 127.0.0.1 -P 6030 -uroot -ptaosdata", 5, 100, 10, ["insert rows: 500"]) + + # + # command & json + # + + # 6041 is default + options = "-h 127.0.0.1 -P 6041 -uroot -ptaosdata" + json = "tools/benchmark/basic/json/connModePriorityErrHost.json" + self.insertBenchJson(json, options, True) + + # cmd port first json port + options = "-Z native -P 6030" + json = "tools/benchmark/basic/json/connModePriority.json" + self.insertBenchJson(json, options, True) + options = "-Z websocket -P 6041" + json = "tools/benchmark/basic/json/connModePriority.json" + self.insertBenchJson(json, options, True) + + def run(self): + # init + self.db = "test" + self.stb = "meters" + + # command line test + self.checkCommandLine() + + # except + self.checkExceptCmd() + + # cmd > json > env + self.checkPriority() + + # host and port + self.checkHostPort() + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/army/tools/benchmark/basic/json/TD-31490.json b/tests/army/tools/benchmark/basic/json/TD-31490.json index a4c674fa50..469be9ba54 100644 --- a/tests/army/tools/benchmark/basic/json/TD-31490.json +++ b/tests/army/tools/benchmark/basic/json/TD-31490.json @@ -22,7 +22,7 @@ "wal_retention_period": 0, "buffer": 256, "stt_trigger": 1, - "vgroups ": 1 + "vgroups": 1 }, "super_tables": [ { diff --git a/tests/army/tools/benchmark/basic/json/TS-5002.json b/tests/army/tools/benchmark/basic/json/TS-5002.json index 024f9f0f9e..3e39085ca9 100644 --- a/tests/army/tools/benchmark/basic/json/TS-5002.json +++ b/tests/army/tools/benchmark/basic/json/TS-5002.json @@ -24,7 +24,7 @@ "cachemodel": "'both'", "cachesize": 100, "stt_trigger": 1, - "vgroups ": 3 + "vgroups": 3 }, "super_tables": [ { diff --git a/tests/army/tools/benchmark/basic/json/connModePriority.json b/tests/army/tools/benchmark/basic/json/connModePriority.json new file mode 100644 index 0000000000..aec4e5ac9c --- /dev/null +++ b/tests/army/tools/benchmark/basic/json/connModePriority.json @@ -0,0 +1,65 @@ +{ + "filetype": "insert", + "dsn": "http://127.0.0.1:6041", + "cfgdir": "/etc/taos", + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "num_of_records_per_req": 3000, + "thread_count": 2, + "confirm_parameter_prompt": "no", + "databases": [ + { + "dbinfo": { + "name": "test", + "drop": "yes", + "precision": "ms", + "vgroups": 1 + }, + "super_tables": [ + { + "name": "meters", + "child_table_exists": "no", + "childtable_count": 2, + "insert_rows": 1000, + "childtable_prefix": "d", + "insert_mode": "taosc", + "interlace_rows": 0, + "timestamp_step": 1000, + "start_timestamp":1700000000000, + "columns": [ + { "type": "bool", "name": "bc"}, + { "type": "float", "name": "fc", "max": 1, "min": 0 }, + { "type": "double", "name": "dc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "ti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "si", "max": 100, "min": -50 }, + { "type": "int", "name": "ic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "bi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "uti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "usi", "max": 100, "min": 0 }, + { "type": "uint", "name": "ui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "ubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "bin", "len": 4}, + { "type": "nchar", "name": "nch", "len": 8} + ], + "tags": [ + { "type": "bool", "name": "tbc"}, + { "type": "float", "name": "tfc", "max": 1, "min": 0 }, + { "type": "double", "name": "tdc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "tti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "tsi", "max": 100, "min": -50 }, + { "type": "int", "name": "tic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "tbi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "tuti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "tusi", "max": 100, "min": 0 }, + { "type": "uint", "name": "tui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "tubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "tbin", "len": 4}, + { "type": "nchar", "name": "tnch", "len": 8} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/army/tools/benchmark/basic/json/connModePriorityErrDsn.json b/tests/army/tools/benchmark/basic/json/connModePriorityErrDsn.json new file mode 100644 index 0000000000..633d657861 --- /dev/null +++ b/tests/army/tools/benchmark/basic/json/connModePriorityErrDsn.json @@ -0,0 +1,60 @@ +{ + "filetype": "insert", + "dsn": "http://127.0.0.1:6042", + "num_of_records_per_req": 3000, + "thread_count": 2, + "confirm_parameter_prompt": "no", + "databases": [ + { + "dbinfo": { + "name": "test", + "drop": "yes", + "precision": "ms", + "vgroups": 1 + }, + "super_tables": [ + { + "name": "meters", + "child_table_exists": "no", + "childtable_count": 2, + "insert_rows": 1000, + "childtable_prefix": "d", + "insert_mode": "taosc", + "interlace_rows": 0, + "timestamp_step": 1000, + "start_timestamp":1700000000000, + "columns": [ + { "type": "bool", "name": "bc"}, + { "type": "float", "name": "fc", "max": 1, "min": 0 }, + { "type": "double", "name": "dc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "ti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "si", "max": 100, "min": -50 }, + { "type": "int", "name": "ic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "bi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "uti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "usi", "max": 100, "min": 0 }, + { "type": "uint", "name": "ui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "ubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "bin", "len": 4}, + { "type": "nchar", "name": "nch", "len": 8} + ], + "tags": [ + { "type": "bool", "name": "tbc"}, + { "type": "float", "name": "tfc", "max": 1, "min": 0 }, + { "type": "double", "name": "tdc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "tti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "tsi", "max": 100, "min": -50 }, + { "type": "int", "name": "tic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "tbi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "tuti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "tusi", "max": 100, "min": 0 }, + { "type": "uint", "name": "tui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "tubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "tbin", "len": 4}, + { "type": "nchar", "name": "tnch", "len": 8} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/army/tools/benchmark/basic/json/connModePriorityErrHost.json b/tests/army/tools/benchmark/basic/json/connModePriorityErrHost.json new file mode 100644 index 0000000000..f32acbeb1f --- /dev/null +++ b/tests/army/tools/benchmark/basic/json/connModePriorityErrHost.json @@ -0,0 +1,64 @@ +{ + "filetype": "insert", + "cfgdir": "/etc/taos", + "host": "127.0.0.2", + "port": 6032, + "user": "root-error", + "password": "taosdata-error", + "num_of_records_per_req": 3000, + "thread_count": 2, + "confirm_parameter_prompt": "no", + "databases": [ + { + "dbinfo": { + "name": "test", + "drop": "yes", + "precision": "ms", + "vgroups": 1 + }, + "super_tables": [ + { + "name": "meters", + "child_table_exists": "no", + "childtable_count": 2, + "insert_rows": 1000, + "childtable_prefix": "d", + "insert_mode": "taosc", + "interlace_rows": 0, + "timestamp_step": 1000, + "start_timestamp":1700000000000, + "columns": [ + { "type": "bool", "name": "bc"}, + { "type": "float", "name": "fc", "max": 1, "min": 0 }, + { "type": "double", "name": "dc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "ti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "si", "max": 100, "min": -50 }, + { "type": "int", "name": "ic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "bi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "uti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "usi", "max": 100, "min": 0 }, + { "type": "uint", "name": "ui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "ubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "bin", "len": 4}, + { "type": "nchar", "name": "nch", "len": 8} + ], + "tags": [ + { "type": "bool", "name": "tbc"}, + { "type": "float", "name": "tfc", "max": 1, "min": 0 }, + { "type": "double", "name": "tdc", "max": 10, "min": 0 }, + { "type": "tinyint", "name": "tti", "max": 100, "min": -100 }, + { "type": "smallint", "name": "tsi", "max": 100, "min": -50 }, + { "type": "int", "name": "tic", "max": 1000, "min": -1000 }, + { "type": "bigint", "name": "tbi", "max": 100, "min": -1000 }, + { "type": "utinyint", "name": "tuti", "max": 100, "min": 0 }, + { "type": "usmallint", "name": "tusi", "max": 100, "min": 0 }, + { "type": "uint", "name": "tui", "max": 1000, "min": 0 }, + { "type": "ubigint", "name": "tubi", "max": 10000, "min": 0 }, + { "type": "binary", "name": "tbin", "len": 4}, + { "type": "nchar", "name": "tnch", "len": 8} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/army/tools/benchmark/basic/json/queryInsertrestdata.json b/tests/army/tools/benchmark/basic/json/queryInsertrestdata.json deleted file mode 100644 index 6714497766..0000000000 --- a/tests/army/tools/benchmark/basic/json/queryInsertrestdata.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "filetype": "insert", - "cfgdir": "/etc/taos", - "host": "127.0.0.1", - "port": 6030, - "user": "root", - "password": "taosdata", - "thread_count": 4, - "thread_count_create_tbl": 4, - "result_file": "./insert_res.txt", - "confirm_parameter_prompt": "no", - "insert_interval": 0, - "interlace_rows": 0, - "num_of_records_per_req": 3000, - "max_sql_len": 1024000, - "databases": [{ - "dbinfo": { - "name": "db", - "drop": "yes", - "precision": "ms" - }, - "super_tables": [{ - "name": "stb0", - "child_table_exists":"no", - "childtable_count": 2, - "childtable_prefix": "stb00_", - "auto_create_table": "no", - "batch_create_tbl_num": 10, - "data_source": "rand", - "insert_mode": "taosc", - "insert_rows": 10, - "childtable_limit": 0, - "childtable_offset": 0, - "interlace_rows": 0, - "insert_interval": 0, - "max_sql_len": 1024000, - "disorder_ratio": 0, - "disorder_range": 1000, - "timestamp_step": 1, - "start_timestamp": "2020-11-01 00:00:00.000", - "sample_format": "csv", - "sample_file": "./sample.csv", - "tags_file": "", - "columns": [{"type": "BINARY", "len": 1, "count":1}, {"type": "BINARY", "len": 3, "count":1}, {"type": "INT"}, {"type": "DOUBLE", "count":1}], - "tags": [{"type": "TINYINT", "count":2}, {"type": "BINARY", "len": 16, "count":5}] - }, - { - "name": "stb1", - "child_table_exists":"no", - "childtable_count": 2, - "childtable_prefix": "stb01_", - "auto_create_table": "no", - "batch_create_tbl_num": 10, - "data_source": "rand", - "insert_mode": "taosc", - "insert_rows": 5, - "childtable_limit": 0, - "childtable_offset": 0, - "interlace_rows": 0 , - "insert_interval": 0, - "max_sql_len": 1024000, - "disorder_ratio": 0, - "disorder_range": 1000, - "timestamp_step": 1, - "start_timestamp": "2020-11-01 00:00:00.000", - "sample_format": "csv", - "sample_file": "./sample.csv", - "tags_file": "", - "columns": [{"type": "INT"}, {"type": "DOUBLE", "count":6}, {"type": "BINARY", "len": 1, "count":3}, {"type": "BINARY", "len": 2, "count":6}], - "tags": [{"type": "TINYINT", "count":2}, {"type": "BINARY", "len": 16, "count":5}] - }] - }] -} diff --git a/tests/army/tools/benchmark/basic/json/queryRestful.json b/tests/army/tools/benchmark/basic/json/queryRestful.json deleted file mode 100644 index 6cb83bc2e1..0000000000 --- a/tests/army/tools/benchmark/basic/json/queryRestful.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "filetype": "query", - "cfgdir": "/etc/taos", - "host": "127.0.0.1", - "port": 6030, - "user": "root", - "password": "taosdata", - "confirm_parameter_prompt": "no", - "databases": "db", - "query_times": 2, - "query_mode": "rest", - "specified_table_query": { - "query_interval": 1, - "threads": 3, - "sqls": [ - { - "sql": "select last_row(*) from db.stb0 ", - "result": "./query_res0.txt" - }, - { - "sql": "select count(*) from db.stb00_1", - "result": "./query_res1.txt" - } - ] - } - } - diff --git a/tests/army/tools/benchmark/basic/json/queryRestful1.json b/tests/army/tools/benchmark/basic/json/queryRestful1.json deleted file mode 100644 index 54d2589ce9..0000000000 --- a/tests/army/tools/benchmark/basic/json/queryRestful1.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "filetype": "query", - "cfgdir": "/etc/taos", - "host": "127.0.0.1", - "port": 6030, - "user": "root", - "password": "taosdata", - "confirm_parameter_prompt": "no", - "databases": "db", - "query_times": 2, - "query_mode": "rest", - "super_table_query": { - "stblname": "stb1", - "query_interval": 1, - "threads": 3, - "sqls": [ - { - "sql": "select last_row(ts) from xxxx", - "result": "./query_res2.txt" - } - ] - } - } - diff --git a/tests/army/tools/benchmark/basic/json/taosc_query-sqlfile.json b/tests/army/tools/benchmark/basic/json/taosc_query-sqlfile.json index 236e87a36d..efb77bbed7 100644 --- a/tests/army/tools/benchmark/basic/json/taosc_query-sqlfile.json +++ b/tests/army/tools/benchmark/basic/json/taosc_query-sqlfile.json @@ -13,7 +13,7 @@ { "query_interval": 1, "concurrent":1, - "sql_file": "./taosbenchmark/json/query-sqls.txt", + "sql_file": "tools/benchmark/basic/json/query-sqls.txt", "result": "taosc_query_specified-sqlfile" } } diff --git a/tests/army/tools/benchmark/basic/queryMain.py b/tests/army/tools/benchmark/basic/queryMain.py index 2c7f45c975..43a9488b5b 100644 --- a/tests/army/tools/benchmark/basic/queryMain.py +++ b/tests/army/tools/benchmark/basic/queryMain.py @@ -124,7 +124,7 @@ class TDTestCase(TBase): except: continueIfFail = "no" - concurrent = data[label]["concurrent"] + threads = data[label]["threads"] sqls = data[label]["sqls"] @@ -140,7 +140,7 @@ class TDTestCase(TBase): except: mixedQuery = "no" - tdLog.info(f"queryTimes={queryTimes} concurrent={concurrent} mixedQuery={mixedQuery} " + tdLog.info(f"queryTimes={queryTimes} threads={threads} mixedQuery={mixedQuery} " f"batchQuery={batchQuery} len(sqls)={len(sqls)} label={label}\n") totalQueries = 0 @@ -154,9 +154,9 @@ class TDTestCase(TBase): if specMode and mixedQuery.lower() != "yes": # spec - threadQueries = queryTimes * concurrent - totalQueries = queryTimes * concurrent * len(sqls) - threadKey = f"complete query with {concurrent} threads and " + threadQueries = queryTimes * threads + totalQueries = queryTimes * threads * len(sqls) + threadKey = f"complete query with {threads} threads and " qpsKey = "QPS: " avgKey = "query delay avg: " minKey = "min:" @@ -178,10 +178,10 @@ class TDTestCase(TBase): threadQueries = totalQueries nSql = len(sqls) - if specMode and nSql < concurrent : - tdLog.info(f"set concurrent = {nSql} because len(sqls) < concurrent") - concurrent = nSql - threadKey = f"using {concurrent} threads complete query " + if specMode and nSql < threads : + tdLog.info(f"set threads = {nSql} because len(sqls) < threads") + threads = nSql + threadKey = f"using {threads} threads complete query " qpsKey = "" avgKey = "avg delay:" minKey = "min delay:" @@ -219,10 +219,6 @@ class TDTestCase(TBase): for arg in args: self.checkAfterRun(benchmark, arg[0] + ".json", arg[1], tbCnt) - # rest - for arg in args: - self.checkAfterRun(benchmark, arg[0] + "Rest.json", arg[1], tbCnt) - def expectFailed(self, command): ret = os.system(command) if ret == 0: diff --git a/tests/army/tools/benchmark/basic/query_json-with-sqlfile.py b/tests/army/tools/benchmark/basic/query_json-with-sqlfile.py index 110651a52d..82968d7ea5 100644 --- a/tests/army/tools/benchmark/basic/query_json-with-sqlfile.py +++ b/tests/army/tools/benchmark/basic/query_json-with-sqlfile.py @@ -40,13 +40,9 @@ class TDTestCase(TBase): tdSql.execute("insert into stb_1 using stb tags (1) values (now, 1)") tdSql.execute("insert into stb_2 using stb tags (2) values (now, 2)") cmd = "%s -f ./tools/benchmark/basic/json/taosc_query-sqlfile.json" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - - # with open("%s" % "taosc_query_specified-sqlfile-0", "r+") as f1: - # for line in f1.readlines(): - # queryTaosc = line.strip().split()[0] - # assert queryTaosc == "3", "result is %s != expect: 3" % queryTaosc + rlist = self.benchmark(f"-f {cmd}") + # check result + self.checkListString(rlist, "completed total queries: 2") def stop(self): tdSql.close() diff --git a/tests/army/tools/benchmark/basic/query_json.py b/tests/army/tools/benchmark/basic/query_json.py index 6f71a508af..5e59b1392f 100644 --- a/tests/army/tools/benchmark/basic/query_json.py +++ b/tests/army/tools/benchmark/basic/query_json.py @@ -32,7 +32,7 @@ class TDTestCase(TBase): def run(self): binPath = etool.benchMarkFile() os.system( - "rm -f rest_query_specified-0 rest_query_super-0 taosc_query_specified-0 taosc_query_super-0" + "rm -f taosc_query_specified-0 taosc_query_super-0" ) tdSql.execute("drop database if exists db") tdSql.execute("create database if not exists db") @@ -58,46 +58,6 @@ class TDTestCase(TBase): queryTaosc = line.strip().split()[0] assert queryTaosc == "1", "result is %s != expect: 1" % queryTaosc - # split two - cmd = "%s -f ./tools/benchmark/basic/json/rest_query.json" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - cmd = "%s -f ./tools/benchmark/basic/json/rest_query1.json" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - - times = 0 - with open("rest_query_super-0", "r+") as f1: - for line in f1.readlines(): - contents = line.strip() - if contents.find("data") != -1: - pattern = re.compile("{.*}") - contents = pattern.search(contents).group() - contentsDict = ast.literal_eval(contents) - queryResultRest = contentsDict["data"][0][0] - assert queryResultRest == 1, ( - "result is %s != expect: 1" % queryResultRest - ) - times += 1 - - assert times == 3, "result is %s != expect: 3" % times - - times = 0 - with open("rest_query_specified-0", "r+") as f1: - for line in f1.readlines(): - contents = line.strip() - if contents.find("data") != -1: - pattern = re.compile("{.*}") - contents = pattern.search(contents).group() - contentsDict = ast.literal_eval(contents) - queryResultRest = contentsDict["data"][0][0] - assert queryResultRest == 3, ( - "result is %s != expect: 3" % queryResultRest - ) - times += 1 - - assert times == 1, "result is %s != expect: 1" % times - def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) diff --git a/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson-mixed-query.py b/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson-mixed-query.py index 14bf201e97..a3f1a14967 100644 --- a/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson-mixed-query.py +++ b/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson-mixed-query.py @@ -37,22 +37,6 @@ class TDTestCase(TBase): queryResultTaosc = line.strip().split()[0] self.assertCheck(filename, queryResultTaosc, expectResult) - # 获取restful接口查询的结果文件中的关键内容,目前的关键内容找到第一个key就跳出循,所以就只有一个数据。后续再修改多个结果文件。 - def getfileDataRestful(self, filename): - self.filename = filename - with open("%s" % filename, "r+") as f1: - for line in f1.readlines(): - contents = line.strip() - if contents.find("data") != -1: - pattern = re.compile("{.*}") - contents = pattern.search(contents).group() - contentsDict = ast.literal_eval(contents) # 字符串转换为字典 - queryResultRest = contentsDict["data"][0][0] - break - else: - queryResultRest = "" - return queryResultRest - # 获取taosc接口查询次数 def queryTimesTaosc(self, filename): self.filename = filename @@ -60,13 +44,6 @@ class TDTestCase(TBase): times = int(subprocess.getstatusoutput(command)[1]) return times - # 获取restful接口查询次数 - def queryTimesRestful(self, filename): - self.filename = filename - command = 'cat %s |grep "200 OK" |wc -l' % filename - times = int(subprocess.getstatusoutput(command)[1]) - return times - # 定义断言结果是否正确。不正确返回错误结果,正确即通过。 def assertCheck(self, filename, queryResult, expectResult): self.filename = filename @@ -106,26 +83,6 @@ class TDTestCase(TBase): os.system("rm -rf ./query_res*") os.system("rm -rf ./all_query*") - # use restful api to query - os.system("%s -f ./tools/benchmark/basic/json/queryInsertrestdata.json" % binPath) - os.system("%s -f ./tools/benchmark/basic/json/queryRestful.json" % binPath) - os.system("%s -f ./tools/benchmark/basic/json/queryRestful1.json" % binPath) - os.system("cat query_res2.txt* > all_query_res2_rest.txt") - - # correct Times testcases - - queryTimes2Restful = self.queryTimesRestful("all_query_res2_rest.txt") - self.assertCheck("all_query_res2_rest.txt", queryTimes2Restful, 4) - - # correct data testcase - - data2 = self.getfileDataRestful("all_query_res2_rest.txt") - print(data2) - if data2 != "2020-11-01 00:00:00.004" and data2 != "2020-10-31T16:00:00.004Z": - tdLog.exit( - "data2 is not 2020-11-01 00:00:00.004 and 2020-10-31T16:00:00.004Z" - ) - # query times less than or equal to 100 assert ( os.system("%s -f ./tools/benchmark/basic/json/queryInsertdata.json" % binPath) == 0 diff --git a/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson.py b/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson.py index 3e55a5df70..c529381c18 100644 --- a/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson.py +++ b/tests/army/tools/benchmark/basic/taosdemoTestQueryWithJson.py @@ -115,41 +115,6 @@ class TDTestCase(TBase): os.system("rm -rf ./query_res*") os.system("rm -rf ./all_query*") - # use restful api to query - os.system("%s -f ./tools/benchmark/basic/json/queryInsertrestdata.json" % binPath) - os.system("%s -f ./tools/benchmark/basic/json/queryRestful.json" % binPath) - os.system("%s -f ./tools/benchmark/basic/json/queryRestful1.json" % binPath) - os.system("cat query_res0.txt* > all_query_res0_rest.txt") - os.system("cat query_res1.txt* > all_query_res1_rest.txt") - os.system("cat query_res2.txt* > all_query_res2_rest.txt") - - # correct Times testcases - queryTimes0Restful = self.queryTimesRestful("all_query_res0_rest.txt") - self.assertCheck("all_query_res0_rest.txt", queryTimes0Restful, 6) - - queryTimes1Restful = self.queryTimesRestful("all_query_res1_rest.txt") - self.assertCheck("all_query_res1_rest.txt", queryTimes1Restful, 6) - - queryTimes2Restful = self.queryTimesRestful("all_query_res2_rest.txt") - self.assertCheck("all_query_res2_rest.txt", queryTimes2Restful, 4) - - # correct data testcase - data0 = self.getfileDataRestful("all_query_res0_rest.txt") - if data0 != "2020-11-01 00:00:00.009" and data0 != "2020-10-31T16:00:00.009Z": - tdLog.exit( - "data0 is not 2020-11-01 00:00:00.009 and 2020-10-31T16:00:00.009Z" - ) - - data1 = self.getfileDataRestful("all_query_res1_rest.txt") - self.assertCheck("all_query_res1_rest.txt", data1, 10) - - data2 = self.getfileDataRestful("all_query_res2_rest.txt") - print(data2) - if data2 != "2020-11-01 00:00:00.004" and data2 != "2020-10-31T16:00:00.004Z": - tdLog.exit( - "data2 is not 2020-11-01 00:00:00.004 and 2020-10-31T16:00:00.004Z" - ) - # query times less than or equal to 100 assert ( os.system("%s -f ./tools/benchmark/basic/json/queryInsertdata.json" % binPath) == 0 @@ -170,10 +135,6 @@ class TDTestCase(TBase): exceptcode = os.system("%s -f ./tools/benchmark/basic/json/queryQps1.json" % binPath) assert exceptcode == 0 - # 2021.02.09 need modify taosBenchmakr code - # use illegal or out of range parameters query json file - os.system("%s -f ./tools/benchmark/basic/json/queryInsertdata.json" % binPath) - # delete useless files os.system("rm -rf ./insert_res.txt") os.system("rm -rf ./tools/benchmark/basic/*.py.sql") diff --git a/tests/army/tools/taosdump/native/json/insertFullType.json b/tests/army/tools/taosdump/native/json/insertFullType.json index a121670c37..5bdecef72b 100644 --- a/tests/army/tools/taosdump/native/json/insertFullType.json +++ b/tests/army/tools/taosdump/native/json/insertFullType.json @@ -41,7 +41,9 @@ { "type": "ubigint", "name": "ubi", "max": 10000, "min": 0 }, { "type": "binary", "name": "bin", "len": 4}, { "type": "nchar", "name": "nch", "len": 8}, - { "type": "varchar", "name": "vac", "len": 8} + { "type": "varbinary", "name": "vab", "len": 8}, + { "type": "varchar", "name": "vac", "len": 8}, + { "type": "geometry", "name": "geo", "len": 32} ], "tags":[ { "type": "bool", "name": "tbc"}, @@ -57,7 +59,9 @@ { "type": "ubigint", "name": "tubi", "max": 10000, "min": 0 }, { "type": "binary", "name": "tbin", "len": 4}, { "type": "nchar", "name": "tnch", "len": 8}, - { "type": "varchar", "name": "tvac", "len": 8} + { "type": "varbinary", "name": "tvab", "len": 8}, + { "type": "varchar", "name": "tvac", "len": 8}, + { "type": "geometry", "name": "tgeo", "len": 32} ] } ] diff --git a/tests/army/tools/taosdump/native/json/insertOther.json b/tests/army/tools/taosdump/native/json/insertOther.json deleted file mode 100644 index bd6bb12bec..0000000000 --- a/tests/army/tools/taosdump/native/json/insertOther.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "filetype":"insert", - "cfgdir":"/etc/taos", - "host":"127.0.0.1", - "port":6030, - "user":"root", - "password":"taosdata", - "thread_count":1, - "create_table_thread_count":1, - "confirm_parameter_prompt":"no", - "prepare_rand":100, - "num_of_records_per_req":100, - "databases": [ - { - "dbinfo":{ - "name":"testother", - "drop":"yes" - }, - "super_tables":[ - { - "name":"meters", - "child_table_exists":"no", - "childtable_prefix":"d", - "data_source":"rand", - "insert_mode":"taosc", - "childtable_count": 2, - "insert_rows":100, - "timestamp_step":1000, - "start_timestamp":"2022-10-01 00:00:00.000", - "columns":[ - { "type": "bool", "name": "bc"}, - { "type": "float", "name": "fc", "max": 1, "min": 0 }, - { "type": "double", "name": "dc", "max": 10, "min": 0 }, - { "type": "tinyint", "name": "ti", "max": 100, "min": -100 }, - { "type": "smallint", "name": "si", "max": 100, "min": -50 }, - { "type": "int", "name": "ic", "max": 1000, "min": -1000 }, - { "type": "bigint", "name": "bi", "max": 100, "min": -1000 }, - { "type": "utinyint", "name": "uti", "max": 100, "min": 0 }, - { "type": "usmallint", "name": "usi", "max": 100, "min": 0 }, - { "type": "uint", "name": "ui", "max": 1000, "min": 0 }, - { "type": "ubigint", "name": "ubi", "max": 10000, "min": 0 }, - { "type": "binary", "name": "bin", "len": 4}, - { "type": "nchar", "name": "nch", "len": 8}, - { "type": "varbinary", "name": "vab", "len": 8}, - { "type": "varchar", "name": "vac", "len": 8}, - { "type": "geometry", "name": "geo", "len": 32} - ], - "tags":[ - { "type": "bool", "name": "tbc"}, - { "type": "float", "name": "tfc", "max": 1, "min": 0 }, - { "type": "double", "name": "tdc", "max": 10, "min": 0 }, - { "type": "tinyint", "name": "tti", "max": 100, "min": -100 }, - { "type": "smallint", "name": "tsi", "max": 100, "min": -50 }, - { "type": "int", "name": "tic", "max": 1000, "min": -1000 }, - { "type": "bigint", "name": "tbi", "max": 100, "min": -1000 }, - { "type": "utinyint", "name": "tuti", "max": 100, "min": 0 }, - { "type": "usmallint", "name": "tusi", "max": 100, "min": 0 }, - { "type": "uint", "name": "tui", "max": 1000, "min": 0 }, - { "type": "ubigint", "name": "tubi", "max": 10000, "min": 0 }, - { "type": "binary", "name": "tbin", "len": 4}, - { "type": "nchar", "name": "tnch", "len": 8}, - { "type": "varbinary", "name": "tvab", "len": 8}, - { "type": "varchar", "name": "tvac", "len": 8}, - { "type": "geometry", "name": "tgeo", "len": 32} - ] - } - ] - } - ] -} diff --git a/tests/army/tools/taosdump/native/taosdumpCommandline.py b/tests/army/tools/taosdump/native/taosdumpCommandline.py index 98f1ff6b1d..c3b33ba45e 100644 --- a/tests/army/tools/taosdump/native/taosdumpCommandline.py +++ b/tests/army/tools/taosdump/native/taosdumpCommandline.py @@ -95,11 +95,11 @@ class TDTestCase(TBase): # normal table sqls = [ f"create table {db}.ntb(st timestamp, c1 int, c2 binary(32))", - f"insert into {db}.ntb values(now, 1, 'abc1')", - f"insert into {db}.ntb values(now, 2, 'abc2')", - f"insert into {db}.ntb values(now, 3, 'abc3')", - f"insert into {db}.ntb values(now, 4, 'abc4')", - f"insert into {db}.ntb values(now, 5, 'abc5')", + f"insert into {db}.ntb values('2025-01-01 10:00:01', 1, 'abc1')", + f"insert into {db}.ntb values('2025-01-01 10:00:02', 2, 'abc2')", + f"insert into {db}.ntb values('2025-01-01 10:00:03', 3, 'abc3')", + f"insert into {db}.ntb values('2025-01-01 10:00:04', 4, 'abc4')", + f"insert into {db}.ntb values('2025-01-01 10:00:05', 5, 'abc5')", ] for sql in sqls: tdSql.execute(sql) @@ -158,9 +158,10 @@ class TDTestCase(TBase): def basicCommandLine(self, tmpdir): #command and check result checkItems = [ - [f"-h 127.0.0.1 -P 6030 -uroot -ptaosdata -A -N -o {tmpdir}", ["OK: Database test dumped"]], + [f"-h 127.0.0.1 -P 6041 -uroot -ptaosdata -A -N -o {tmpdir}", ["OK: Database test dumped"]], [f"-r result -a -e test d0 -o {tmpdir}", ["OK: table: d0 dumped", "OK: 100 row(s) dumped out!"]], [f"-n -D test -o {tmpdir}", ["OK: Database test dumped", "OK: 205 row(s) dumped out!"]], + [f"-Z 0 -P 6030 -n -D test -o {tmpdir}", ["OK: Database test dumped", "OK: 205 row(s) dumped out!"]], [f"-L -D test -o {tmpdir}", ["OK: Database test dumped", "OK: 205 row(s) dumped out!"]], [f"-s -D test -o {tmpdir}", ["dumping out schema: 1 from meters.d0", "OK: Database test dumped", "OK: 0 row(s) dumped out!"]], [f"-N -d deflate -S '2022-10-01 00:00:50.000' test meters -o {tmpdir}",["OK: table: meters dumped", "OK: 100 row(s) dumped out!"]], @@ -172,7 +173,18 @@ class TDTestCase(TBase): [f"--help", ["Report bugs to"]], [f"-?", ["Report bugs to"]], [f"-V", ["version:"]], - [f"--usage", ["taosdump [OPTION...] -o outpath"]] + [f"--usage", ["taosdump [OPTION...] -o outpath"]], + # conn mode -Z + [f"-Z 0 -E '2022-10-01 00:00:60.000' test -o {tmpdir}", [ + "Connect mode is : Native", + "OK: Database test dumped", + "OK: 122 row(s) dumped out!"] + ], + [f"-Z 1 -E '2022-10-01 00:00:60.000' test -o {tmpdir}", [ + "Connect mode is : WebSocket", + "OK: Database test dumped", + "OK: 122 row(s) dumped out!"] + ], ] # executes @@ -181,8 +193,9 @@ class TDTestCase(TBase): command = item[0] results = item[1] rlist = self.taosdump(command) - for result in results: - self.checkListString(rlist, result) + self.checkManyString(rlist, results) + # clear tmp + # check except def checkExcept(self, command): @@ -212,6 +225,73 @@ class TDTestCase(TBase): self.checkExcept(taosdump + f" -t 2 -k 2 -z 1 -C https://not-exist.com:80/cloud -D test -o {tmpdir}") self.checkExcept(taosdump + f" -P 65536") + # conn mode + options = [ + f"-Z native -X http://127.0.0.1:6041 -D {db} -o {tmpdir}", + f"-Z 100 -D {db} -o {tmpdir}", + f"-Z abcdefg -D {db} -o {tmpdir}", + f"-X -D {db} -o {tmpdir}", + f"-X 127.0.0.1:6041 -D {db} -o {tmpdir}", + f"-X https://gw.cloud.taosdata.com?token617ffdf... -D {db} -o {tmpdir}", + f"-Z 1 -X https://gw.cloud.taosdata.com?token=617ffdf... -D {db} -o {tmpdir}", + f"-X http://127.0.0.1:6042 -D {db} -o {tmpdir}" + ] + + # do check + for option in options: + self.checkExcept(taosdump + " " + option) + + + # expect cmd > json > evn + def checkPriority(self, db, stb, childCount, insertRows, tmpdir): + # + # cmd & env + # + + # env 6043 - invalid + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6043" + # cmd 6041 - valid + cmd = f"-X http://127.0.0.1:6041 -D {db} -o {tmpdir}" + self.clearPath(tmpdir) + rlist = self.taosdump(cmd) + results = [ + "Connect mode is : WebSocket", + "OK: Database test dumped", + "OK: 205 row(s) dumped out!" + ] + self.checkManyString(rlist, results) + + # + # env + # + + os.environ['TDENGINE_CLOUD_DSN'] = "http://127.0.0.1:6041" + # cmd 6041 - valid + self.clearPath(tmpdir) + cmd = f"-D {db} -o {tmpdir}" + rlist = self.taosdump(cmd) + self.checkManyString(rlist, results) + + # + # cmd + # + + os.environ['TDENGINE_CLOUD_DSN'] = "" + # cmd 6041 - valid + self.clearPath(tmpdir) + cmd = f"-X http://127.0.0.1:6041 -D {db} -o {tmpdir}" + rlist = self.taosdump(cmd) + self.checkManyString(rlist, results) + + # clear env + os.environ['TDENGINE_CLOUD_DSN'] = "" + + + # conn mode + def checkConnMode(self, db, stb, childCount, insertRows, tmpdir): + # priority + self.checkPriority(db, stb, childCount, insertRows, tmpdir) + # password def checkPassword(self, tmpdir): # 255 char max password @@ -254,7 +334,7 @@ class TDTestCase(TBase): tdLog.info("1. check long password ................................. [Passed]") # dumpInOut - modes = ["", "-R" , "--cloud=http://localhost:6041"] + modes = ["-Z native", "-Z websocket", "--dsn=http://localhost:6041"] for mode in modes: self.dumpInOutMode(mode, db , json, tmpdir) @@ -268,9 +348,6 @@ class TDTestCase(TBase): self.exceptCommandLine(taosdump, db, stb, tmpdir) tdLog.info("4. except command line ................................. [Passed]") - # - # varbinary and geometry for native - # json = "./tools/taosdump/native/json/insertOther.json" # insert db, stb, childCount, insertRows = self.insertData(json) @@ -278,6 +355,12 @@ class TDTestCase(TBase): self.dumpInOutMode("", db , json, tmpdir) tdLog.info("5. native varbinary geometry ........................... [Passed]") + # + # check connMode + # + + self.checkConnMode(db, stb, childCount, insertRows, tmpdir) + tdLog.info("6. check conn mode ..................................... [Passed]") def stop(self): diff --git a/tests/develop-test/test.py b/tests/develop-test/test.py index 3525fd6332..b291e58e3d 100644 --- a/tests/develop-test/test.py +++ b/tests/develop-test/test.py @@ -38,6 +38,8 @@ from util.taosadapter import * import taos import taosrest +from taos.cinterface import * +taos.taos_options(6, "native") def checkRunTimeError(): import win32gui diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 4fc4e83790..75c50ceb05 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -96,30 +96,19 @@ # army/tools # -# benchmark 66 cases +# benchmark 64 cases ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline-partial-col-numpy.py -# benchmark 64 cases -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/websiteCase.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/rest_insert_alltypes_json.py -R -,,n,army,python3 ./test.py -f tools/benchmark/basic/taosdemoTestQueryWithJson-mixed-query.py -R -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/stmt_sample_csv_json.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/taosdemoTestInsertWithJsonStmt-otherPara.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/sml_telnet_insert_alltypes-same-min-max.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/default_tmq_json.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/reuse-exist-stb.py -,,n,army,python3 ./test.py -f tools/benchmark/basic/sml_interlace.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/stmt2_insert.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/stmt_offset_json.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/json_tag.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline-sml-rest.py -R ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline-single-table.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline-supplement-insert.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/commandline-vgroups.py +,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/connMode.py -B + ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/custom_col_tag.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/default_json.py +,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/default_tmq_json.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/demo.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/csv-export.py @@ -140,6 +129,7 @@ ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/query_json.py -B ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/query_json-with-error-sqlfile.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/query_json-with-sqlfile.py +,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/queryMain.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/rest_insert_alltypes_json.py -R ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/reuse-exist-stb.py @@ -175,6 +165,7 @@ ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/tmqBasic.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/tmq_case.py +,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/websiteCase.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/cloud/cloud-test.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/ws/websocket.py -R diff --git a/tests/parallel_test/run_case.sh b/tests/parallel_test/run_case.sh index b72a7cacca..6cbeecd65e 100755 --- a/tests/parallel_test/run_case.sh +++ b/tests/parallel_test/run_case.sh @@ -50,6 +50,8 @@ if [ $ent -eq 0 ]; then export LD_LIBRARY_PATH=/home/TDengine/debug/build/lib ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so 2>/dev/null ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so.1 2>/dev/null + ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so 2>/dev/null + ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so.1 2>/dev/null ln -s /home/TDengine/include/client/taos.h /usr/include/taos.h 2>/dev/null ln -s /home/TDengine/include/common/taosdef.h /usr/include/taosdef.h 2>/dev/null ln -s /home/TDengine/include/util/taoserror.h /usr/include/taoserror.h 2>/dev/null @@ -60,6 +62,8 @@ else export LD_LIBRARY_PATH=/home/TDinternal/debug/build/lib ln -s /home/TDinternal/debug/build/lib/libtaos.so /usr/lib/libtaos.so 2>/dev/null ln -s /home/TDinternal/debug/build/lib/libtaos.so /usr/lib/libtaos.so.1 2>/dev/null + ln -s /home/TDinternal/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so 2>/dev/null + ln -s /home/TDinternal/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so.1 2>/dev/null ln -s /home/TDinternal/community/include/client/taos.h /usr/include/taos.h 2>/dev/null ln -s /home/TDinternal/community/include/common/taosdef.h /usr/include/taosdef.h 2>/dev/null ln -s /home/TDinternal/community/include/util/taoserror.h /usr/include/taoserror.h 2>/dev/null @@ -75,6 +79,8 @@ ulimit -c unlimited md5sum /usr/lib/libtaos.so.1 md5sum /home/TDinternal/debug/build/lib/libtaos.so +md5sum /usr/lib/libtaosnative.so.1 +md5sum /home/TDinternal/debug/build/lib/libtaosnative.so #get python connector and update: taospy and taos-ws-py to latest pip3 install taospy==2.7.21 @@ -84,6 +90,8 @@ RET=$? echo "cmd exit code: $RET" md5sum /usr/lib/libtaos.so.1 md5sum /home/TDinternal/debug/build/lib/libtaos.so +md5sum /usr/lib/libtaosnative.so.1 +md5sum /home/TDinternal/debug/build/lib/libtaosnative.so if [ $RET -ne 0 ]; then diff --git a/tests/pytest/auto_run_regular.sh b/tests/pytest/auto_run_regular.sh index 27e8013269..c5f275cd68 100755 --- a/tests/pytest/auto_run_regular.sh +++ b/tests/pytest/auto_run_regular.sh @@ -5,6 +5,8 @@ export PATH=$PATH:/home/TDengine/debug/build/bin export LD_LIBRARY_PATH=/home/TDengine/debug/build/lib ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so 2>/dev/null ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so.1 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so.1 2>/dev/null ln -s /home/TDengine/include/client/taos.h /usr/include/taos.h 2>/dev/null # run crash_gen auto script diff --git a/tests/pytest/auto_run_valgrind.sh b/tests/pytest/auto_run_valgrind.sh index c7154e867c..4b5e9ee91c 100755 --- a/tests/pytest/auto_run_valgrind.sh +++ b/tests/pytest/auto_run_valgrind.sh @@ -5,6 +5,8 @@ export PATH=$PATH:/home/TDengine/debug/build/bin export LD_LIBRARY_PATH=/home/TDengine/debug/build/lib ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so 2>/dev/null ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so.1 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so.1 2>/dev/null ln -s /home/TDengine/include/client/taos.h /usr/include/taos.h 2>/dev/null # run crash_gen auto script diff --git a/tests/pytest/auto_run_valgrind_cluster.sh b/tests/pytest/auto_run_valgrind_cluster.sh index 62bc22e923..4706bbd6d0 100755 --- a/tests/pytest/auto_run_valgrind_cluster.sh +++ b/tests/pytest/auto_run_valgrind_cluster.sh @@ -5,6 +5,8 @@ export PATH=$PATH:/home/TDengine/debug/build/bin export LD_LIBRARY_PATH=/home/TDengine/debug/build/lib ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so 2>/dev/null ln -s /home/TDengine/debug/build/lib/libtaos.so /usr/lib/libtaos.so.1 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so 2>/dev/null +ln -s /home/TDengine/debug/build/lib/libtaosnative.so /usr/lib/libtaosnative.so.1 2>/dev/null ln -s /home/TDengine/include/client/taos.h /usr/include/taos.h 2>/dev/null # run crash_gen auto script diff --git a/tests/pytest/dockerCluster/Dockerfile b/tests/pytest/dockerCluster/Dockerfile index 437dbc65e6..ecb068541f 100644 --- a/tests/pytest/dockerCluster/Dockerfile +++ b/tests/pytest/dockerCluster/Dockerfile @@ -33,6 +33,7 @@ COPY --from=builder /root/bin/taosdump /usr/bin COPY --from=builder /root/bin/taos /usr/bin COPY --from=builder /root/cfg/taos.cfg /etc/taos/ COPY --from=builder /root/lib/libtaos.so.* /usr/lib/libtaos.so.1 +COPY --from=builder /root/lib/libtaosnative.so.* /usr/lib/libtaosnative.so.1 ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib" ENV LC_CTYPE=en_US.UTF-8 diff --git a/tests/system-test/pytest.sh b/tests/system-test/pytest.sh index 060717c20e..1ebaa76258 100755 --- a/tests/system-test/pytest.sh +++ b/tests/system-test/pytest.sh @@ -89,6 +89,9 @@ else export LD_PRELOAD="$(realpath "$(gcc -print-file-name=libasan.so)") $(realpath "$(gcc -print-file-name=libstdc++.so)")" echo "Preload AsanSo:" $? + export ASAN_OPTIONS=detect_odr_violation=0 + echo "forbid check ODR violation." + $* -a 2> $AsanFile cat $AsanFile unset LD_PRELOAD diff --git a/tests/system-test/test.py b/tests/system-test/test.py index 01a35df6aa..1958e9976e 100644 --- a/tests/system-test/test.py +++ b/tests/system-test/test.py @@ -40,6 +40,9 @@ import taos import taosrest import taosws +from taos.cinterface import * +taos.taos_options(6, "native") + def checkRunTimeError(): import win32gui timeCount = 0 @@ -251,8 +254,9 @@ if __name__ == "__main__": # # do exeCmd command # + taosAdapter = True # default is websocket , so must start taosAdapter if not execCmd == "": - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.init(deployPath) else: tdDnodes.init(deployPath) @@ -291,7 +295,7 @@ if __name__ == "__main__": if valgrind: time.sleep(2) - if restful or websocket: + if taosAdapter or restful or websocket: toBeKilled = "taosadapter" # killCmd = "ps -ef|grep -w %s| grep -v grep | awk '{print $2}' | xargs kill -TERM > /dev/null 2>&1" % toBeKilled @@ -387,7 +391,7 @@ if __name__ == "__main__": tdDnodes.deploy(1,updateCfgDict) tdDnodes.start(1) tdCases.logSql(logSql) - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -427,7 +431,7 @@ if __name__ == "__main__": tdDnodes.starttaosd(dnode.index) tdCases.logSql(logSql) - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -549,7 +553,7 @@ if __name__ == "__main__": except: pass - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.init(deployPath, masterIp) tAdapter.stop(force_kill=True) @@ -559,7 +563,7 @@ if __name__ == "__main__": tdDnodes.start(1) tdCases.logSql(logSql) - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -614,7 +618,7 @@ if __name__ == "__main__": tdDnodes.starttaosd(dnode.index) tdCases.logSql(logSql) - if restful or websocket: + if taosAdapter or restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() diff --git a/tests/taosc_test/CMakeLists.txt b/tests/taosc_test/CMakeLists.txt index e95e232b8c..925845ca5a 100644 --- a/tests/taosc_test/CMakeLists.txt +++ b/tests/taosc_test/CMakeLists.txt @@ -16,7 +16,7 @@ aux_source_directory(src OS_SRC) # taoscTest add_executable(taoscTest "taoscTest.cpp") -target_link_libraries(taoscTest PUBLIC ${TAOS_LIB} os util common gtest_main) +target_link_libraries(taoscTest PUBLIC ${TAOS_NATIVE_LIB} os util common gtest_main) target_include_directories( taoscTest PUBLIC "${TD_SOURCE_DIR}/include/os" diff --git a/tools/inc/pub.h b/tools/inc/pub.h new file mode 100644 index 0000000000..7e96c7a324 --- /dev/null +++ b/tools/inc/pub.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the MIT license 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 . + */ + +#ifndef PUB_H_ +#define PUB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WINDOWS +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif + +// +// -------------- define ------------------ +// + +// connect mode string +#define STR_NATIVE "Native" +#define STR_WEBSOCKET "WebSocket" + +#define DRIVER_OPT "driver" +#define DRIVER_DESC "Connect driver , value can be \"Native\" or \"WebSocket\"" + +#define DSN_DESC "The dsn to connect the cloud service." +#define OLD_DSN_DESC "same with -X options" + +#define DSN_NATIVE_CONFLICT "DSN option not support in native connection mode.\n" + +// connect mode type define +#define CONN_MODE_INVALID -1 +#define CONN_MODE_NATIVE 0 +#define CONN_MODE_WEBSOCKET 1 + +// define error show module +#define INIT_PHASE "init" +#define TIP_ENGINE_ERR "Call engine failed." + +// default port +#define DEFAULT_PORT_WS_LOCAL 6041 +#define DEFAULT_PORT_WS_CLOUD 443 +#define DEFAULT_PORT_NATIVE 6030 + + +// +// -------------- api ------------------ +// + +// get comn mode, if invalid argp then exit app +int8_t getConnMode(char *arg); + +char* strToLowerCopy(const char *str); +int32_t parseDsn(char* dsn, char **host, char **port, char **user, char **pwd, char* error); + +#endif // PUB_H_ \ No newline at end of file diff --git a/tools/shell/CMakeLists.txt b/tools/shell/CMakeLists.txt index ac901f5ca2..a503ceedf1 100644 --- a/tools/shell/CMakeLists.txt +++ b/tools/shell/CMakeLists.txt @@ -1,21 +1,13 @@ aux_source_directory(src SHELL_SRC) -add_executable(shell ${SHELL_SRC}) +add_executable(shell ${SHELL_SRC} ../src/pub.c) -IF(TD_LINUX AND TD_WEBSOCKET) - ADD_DEFINITIONS(-DWEBSOCKET -I${CMAKE_BINARY_DIR}/build/include -ltaosws) - SET(LINK_WEBSOCKET "-L${CMAKE_BINARY_DIR}/build/lib -ltaosws") - ADD_DEPENDENCIES(shell taosws-rs) -ELSEIF(TD_DARWIN AND TD_WEBSOCKET) - ADD_DEFINITIONS(-DWEBSOCKET -I${CMAKE_BINARY_DIR}/build/include) - SET(LINK_WEBSOCKET "${CMAKE_BINARY_DIR}/build/lib/libtaosws.dylib") - ADD_DEPENDENCIES(shell taosws-rs) -ELSEIF(TD_WINDOWS AND TD_WEBSOCKET) - ADD_DEFINITIONS(-DWEBSOCKET -I${CMAKE_BINARY_DIR}/build/include) - SET(LINK_WEBSOCKET "${CMAKE_BINARY_DIR}/build/lib/taosws.lib") - ADD_DEPENDENCIES(shell taosws-rs) +IF(TD_LINUX_64 AND JEMALLOC_ENABLED) + ADD_DEFINITIONS(-DTD_JEMALLOC_ENABLED -I${CMAKE_BINARY_DIR}/build/include -L${CMAKE_BINARY_DIR}/build/lib -Wl,-rpath,${CMAKE_BINARY_DIR}/build/lib -ljemalloc) + SET(LINK_JEMALLOC "-L${CMAKE_BINARY_DIR}/build/lib -ljemalloc") + ADD_DEPENDENCIES(shell jemalloc) ELSE() - SET(LINK_WEBSOCKET "") + SET(LINK_JEMALLOC "") ENDIF() IF(TD_LINUX AND TD_ALPINE) @@ -25,9 +17,9 @@ ELSE() ENDIF() if(TD_WINDOWS) - target_link_libraries(shell PUBLIC ${TAOS_LIB_STATIC}) + target_link_libraries(shell PUBLIC ${TAOS_LIB}) else() - target_link_libraries(shell PUBLIC ${TAOS_LIB} ${LINK_ARGP}) + target_link_libraries(shell PUBLIC ${TAOS_LIB} ${LINK_JEMALLOC} ${LINK_ARGP}) endif() target_link_libraries( @@ -50,14 +42,11 @@ IF(TD_LINUX) # include include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) + # shell_ut library - add_library(shell_ut STATIC ${SHELL_SRC}) + add_library(shell_ut STATIC ${SHELL_SRC} ../src/pub.c) - IF(TD_WEBSOCKET) - ADD_DEPENDENCIES(shell_ut taosws-rs) - ENDIF() - - target_link_libraries(shell_ut PUBLIC ${TAOS_LIB} ${LINK_WEBSOCKET} ${LINK_JEMALLOC} ${LINK_ARGP}) + target_link_libraries(shell_ut PUBLIC ${TAOS_LIB} ${LINK_JEMALLOC} ${LINK_ARGP}) target_link_libraries(shell_ut PRIVATE os common transport geometry util) # util depends @@ -72,3 +61,16 @@ IF(TD_LINUX) ADD_SUBDIRECTORY(test) ENDIF(${BUILD_TEST}) ENDIF() + +# +# collect --version information +# +MESSAGE("collect --version show info:") +# version +IF (DEFINED TD_VER_NUMBER) + ADD_DEFINITIONS(-DTD_VER_NUMBER="${TD_VER_NUMBER}") + MESSAGE(STATUS "taos version:${TD_VER_NUMBER}") +ELSE () + # abort build + MESSAGE(FATAL_ERROR "build taos not found TD_VER_NUMBER define.") +ENDIF () \ No newline at end of file diff --git a/tools/shell/inc/shellAuto.h b/tools/shell/inc/shellAuto.h index 7583932ff5..836898cdf1 100644 --- a/tools/shell/inc/shellAuto.h +++ b/tools/shell/inc/shellAuto.h @@ -31,7 +31,7 @@ void pressTabKey(SShellCmd* cmd); void pressOtherKey(char c); // init shell auto function , shell start call once -bool shellAutoInit(); +void shellAutoInit(); // set conn void shellSetConn(TAOS* conn, bool runOnce); @@ -51,9 +51,8 @@ void showAD(bool end); // show all commands help void showHelp(); - // -// for unit test +// for unit test // bool fieldOptionsArea(char* p); bool isCreateFieldsArea(char* p); diff --git a/tools/shell/inc/shellInt.h b/tools/shell/inc/shellInt.h index 6dbc5db94f..4b27f4a939 100644 --- a/tools/shell/inc/shellInt.h +++ b/tools/shell/inc/shellInt.h @@ -17,23 +17,22 @@ #define _TD_SHELL_INT_H_ #include "os.h" -#include "taos.h" #include "taosdef.h" #include "taoserror.h" +#include "taos.h" +#include "tcommon.h" #include "tconfig.h" #include "tglobal.h" #include "trpc.h" #include "ttypes.h" #include "tutil.h" +#include "tversion.h" +#include "version.h" +#include "../../inc/pub.h" -#ifdef WEBSOCKET -#include "taosws.h" - -#define SHELL_WS_TIMEOUT 30 -#define SHELL_WS_DSN_BUFF 256 -#define SHELL_WS_DSN_MASK 10 -#endif - +#define SHELL_WS_TIMEOUT 30 +#define SHELL_WS_DSN_BUFF 256 +#define SHELL_WS_DSN_MASK 10 #define SHELL_MAX_HISTORY_SIZE 1000 #define SHELL_MAX_COMMAND_SIZE 1048586 #define SHELL_HISTORY_FILE ".taos_history" @@ -48,7 +47,9 @@ #define SHELL_FLOAT_WIDTH 20 #define SHELL_DOUBLE_WIDTH 25 -#define ERROR_CODE_DETAIL "\r\n\r\nTo view possible causes and suggested actions for error codes, see \r\n\"Error Code Reference\" in the TDengine online documentation.\r\n" +#define ERROR_CODE_DETAIL \ + "\r\n\r\nTo view possible causes and suggested actions for error codes, see \r\n\"Error Code Reference\" in the " \ + "TDengine online documentation.\r\n" typedef struct { char* hist[SHELL_MAX_HISTORY_SIZE]; char file[TSDB_FILENAME_LEN]; @@ -79,20 +80,17 @@ typedef struct { int32_t pktNum; int32_t displayWidth; int32_t abort; -#ifdef WEBSOCKET - bool restful; - bool cloud; - bool local; char* dsn; int32_t timeout; -#endif + int8_t connMode; + bool port_inputted; } SShellArgs; typedef struct { - const char *clientVersion; - char cusName[32]; - char promptHeader[32]; - char promptContinue[32]; + const char* clientVersion; + char cusName[32]; + char promptHeader[32]; + char promptContinue[32]; const char* osname; int32_t promptSize; char programVersion[256]; @@ -106,10 +104,6 @@ typedef struct { TdThread pid; tsem_t cancelSem; bool exit; -#ifdef WEBSOCKET - WS_TAOS* ws_conn; - bool stop_query; -#endif } SShellObj; typedef struct { @@ -134,6 +128,7 @@ int32_t shellCalcColWidth(TAOS_FIELD *field, int32_t precision); void shellPrintHeader(TAOS_FIELD *fields, int32_t *width, int32_t num_fields); void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t length, int32_t precision); void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, int32_t length, int32_t precision); + // shellUtil.c int32_t shellCheckIntSize(); void shellPrintVersion(); @@ -142,21 +137,13 @@ void shellGenerateAuth(); void shellDumpConfig(); void shellCheckServerStatus(); bool shellRegexMatch(const char* s, const char* reg, int32_t cflags); +int32_t getDsnEnv(); void shellExit(); // shellNettest.c void shellTestNetWork(); -#ifdef WEBSOCKET -void shellCheckConnectMode(); -// shellWebsocket.c -int shell_conn_ws_server(bool first); -int32_t shell_run_websocket(); -void shellRunSingleCommandWebsocketImp(char *command); -#endif - // shellMain.c extern SShellObj shell; -extern void tscWriteCrashInfo(int signum, void *sigInfo, void *context); #endif /*_TD_SHELL_INT_H_*/ diff --git a/tools/shell/inc/shellTire.h b/tools/shell/inc/shellTire.h index 472f604a2c..247f6dfa27 100644 --- a/tools/shell/inc/shellTire.h +++ b/tools/shell/inc/shellTire.h @@ -13,8 +13,8 @@ * along with this program. If not, see . */ -#ifndef __TRIE__ -#define __TRIE__ +#ifndef _TD_TRIE_H_ +#define _TD_TRIE_H_ // // The prefix search tree is a efficient storage words and search words tree, it support 95 visible ascii code character diff --git a/tools/shell/src/shellArguments.c b/tools/shell/src/shellArguments.c index 659bb54aef..209168149e 100644 --- a/tools/shell/src/shellArguments.c +++ b/tools/shell/src/shellArguments.c @@ -13,13 +13,8 @@ * along with this program. If not, see . */ -#ifdef _TD_DARWIN_64 -#include -#endif - -#include "cus_name.h" #include "shellInt.h" -#include "version.h" +#include "../../inc/pub.h" #define TAOS_CONSOLE_PROMPT_CONTINUE " -> " @@ -43,17 +38,19 @@ #define SHELL_PKT_LEN "Packet length used for net test, default is 1024 bytes." #define SHELL_PKT_NUM "Packet numbers used for net test, default is 100." #define SHELL_BI_MODE "Set BI mode" +#define SHELL_VERSION "Print program version." +#define SHELL_DSN "Use dsn to connect to the cloud server or to a remote server which provides WebSocket connection." +#define SHELL_TIMEOUT "Set the timeout for WebSocket query in seconds, default is 30." #define SHELL_LOG_OUTPUT \ "Specify log output. Options:\n\r\t\t\t stdout, stderr, /dev/null, , /, " \ "\n\r\t\t\t * If OUTPUT contains an absolute directory, logs will be stored in that directory " \ "instead of logDir.\n\r\t\t\t * If OUTPUT contains a relative directory, logs will be stored in the directory " \ "combined with logDir and the relative directory." -#define SHELL_VERSION "Print program version." #ifdef WEBSOCKET -#define SHELL_DSN "Use dsn to connect to the cloud server or to a remote server which provides WebSocket connection." -#define SHELL_REST "Use RESTful mode when connecting." -#define SHELL_TIMEOUT "Set the timeout for websocket query in seconds, default is 30." +#define SHELL_DRIVER_DEFAULT "0." // todo simon -> 1 +#else +#define SHELL_DRIVER_DEFAULT "0." #endif static int32_t shellParseSingleOpt(int32_t key, char *arg); @@ -82,13 +79,13 @@ void shellPrintHelp() { printf("%s%s%s%s\r\n", indent, "-s,", indent, SHELL_CMD); printf("%s%s%s%s\r\n", indent, "-t,", indent, SHELL_STARTUP); printf("%s%s%s%s\r\n", indent, "-u,", indent, SHELL_USER); -#ifdef WEBSOCKET - printf("%s%s%s%s\r\n", indent, "-E,", indent, SHELL_DSN); - printf("%s%s%s%s\r\n", indent, "-R,", indent, SHELL_REST); + printf("%s%s%s%s\r\n", indent, "-E,", indent, OLD_DSN_DESC); printf("%s%s%s%s\r\n", indent, "-T,", indent, SHELL_TIMEOUT); -#endif printf("%s%s%s%s\r\n", indent, "-w,", indent, SHELL_WIDTH); printf("%s%s%s%s\r\n", indent, "-V,", indent, SHELL_VERSION); + printf("%s%s%s%s\r\n", indent, "-X,", indent, DSN_DESC); + printf("%s%s%s%s\r\n", indent, "-Z,", indent, DRIVER_DESC); + #ifdef CUS_EMAIL printf("\r\n\r\nReport bugs to %s.\r\n", CUS_EMAIL); #else @@ -129,16 +126,13 @@ static struct argp_option shellOptions[] = { {"display-width", 'w', "WIDTH", 0, SHELL_WIDTH}, {"netrole", 'n', "NETROLE", 0, SHELL_NET_ROLE}, {"pktlen", 'l', "PKTLEN", 0, SHELL_PKT_LEN}, -#ifdef WEBSOCKET - {"dsn", 'E', "DSN", 0, SHELL_DSN}, - {"restful", 'R', 0, 0, SHELL_REST}, + {"cloud-dsn", 'E', "DSN", 0, OLD_DSN_DESC}, {"timeout", 'T', "SECONDS", 0, SHELL_TIMEOUT}, -#endif {"pktnum", 'N', "PKTNUM", 0, SHELL_PKT_NUM}, {"bimode", 'B', 0, 0, SHELL_BI_MODE}, -#if defined(LINUX) {"log-output", 'o', "OUTPUT", 0, SHELL_LOG_OUTPUT}, -#endif + {"dsn", 'X', "DSN", 0, DSN_DESC}, + {DRIVER_OPT, 'Z', "DRIVER", 0, DRIVER_DESC}, {0}, }; @@ -146,9 +140,10 @@ static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) { static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""}; -static void shellParseArgsUseArgp(int argc, char *argv[]) { +static int32_t shellParseArgsUseArgp(int argc, char *argv[]) { argp_program_version = shell.info.programVersion; - argp_parse(&shellArgp, argc, argv, 0, 0, &shell.args); + error_t err = argp_parse(&shellArgp, argc, argv, 0, 0, &shell.args); + return (err != 0); } #endif @@ -163,16 +158,14 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { switch (key) { case 'h': pArgs->host = arg; -#ifdef WEBSOCKET - pArgs->cloud = false; -#endif break; case 'P': pArgs->port = atoi(arg); -#ifdef WEBSOCKET - pArgs->cloud = false; -#endif - if (pArgs->port == 0) pArgs->port = -1; + if (pArgs->port == 0) { + pArgs->port = -1; + } else { + pArgs->port_inputted = true; + } break; case 'u': pArgs->user = arg; @@ -189,9 +182,6 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { pArgs->is_bi_mode = true; break; case 'c': -#ifdef WEBSOCKET - pArgs->cloud = false; -#endif pArgs->cfgdir = arg; break; case 'C': @@ -229,33 +219,35 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { break; #if defined(LINUX) case 'o': + printf(" -o need todo optins.\n"); + // need todo pass tsLogOutput to engine + /* if (strlen(arg) >= PATH_MAX) { - printf("failed to set log output since length overflow, max length is %d\n", PATH_MAX); + printf("failed to set log output since length overflow, max length is %d\r\n", PATH_MAX); return TSDB_CODE_INVALID_CFG; } tsLogOutput = taosMemoryMalloc(PATH_MAX); if (!tsLogOutput) { - printf("failed to set log output: '%s' since %s\n", arg, tstrerror(terrno)); + printf("failed to set log output: '%s' since %s\r\n", arg, tstrerror(terrno)); return terrno; } if (taosExpandDir(arg, tsLogOutput, PATH_MAX) != 0) { - printf("failed to expand log output: '%s' since %s\n", arg, tstrerror(terrno)); + printf("failed to expand log output: '%s' since %s\r\n", arg, tstrerror(terrno)); return terrno; } + */ break; #endif -#ifdef WEBSOCKET - case 'R': - pArgs->restful = true; - break; case 'E': + case 'X': pArgs->dsn = arg; - pArgs->cloud = true; break; case 'T': pArgs->timeout = atoi(arg); break; -#endif + case 'Z': + pArgs->connMode = getConnMode(arg); + break; case 'V': pArgs->is_version = true; break; @@ -271,14 +263,15 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { return 0; } #if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32) || defined(_TD_DARWIN_64) || defined(TD_ASTRA) + int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) { SShellArgs *pArgs = &shell.args; + int32_t ret = 0; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--usage") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "/?") == 0) { - shellParseSingleOpt('?', NULL); - return 0; + return shellParseSingleOpt('?', NULL); } char *key = argv[i]; @@ -292,14 +285,9 @@ int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) { return -1; } - if (key[1] == 'h' || key[1] == 'P' || key[1] == 'u' - || key[1] == 'a' || key[1] == 'c' || key[1] == 's' - || key[1] == 'f' || key[1] == 'd' || key[1] == 'w' - || key[1] == 'n' || key[1] == 'l' || key[1] == 'N' -#ifdef WEBSOCKET - || key[1] == 'E' || key[1] == 'T' -#endif - ) { + if (key[1] == 'h' || key[1] == 'P' || key[1] == 'u' || key[1] == 'a' || key[1] == 'c' || key[1] == 's' || + key[1] == 'f' || key[1] == 'd' || key[1] == 'w' || key[1] == 'n' || key[1] == 'l' || key[1] == 'N' || + key[1] == 'E' || key[1] == 'T' || key[1] == 'X' || key[1] == 'Z') { if (i + 1 >= argc) { fprintf(stderr, "option %s requires an argument\r\n", key); return -1; @@ -309,21 +297,19 @@ int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) { fprintf(stderr, "option %s requires an argument\r\n", key); return -1; } - shellParseSingleOpt(key[1], val); + ret = shellParseSingleOpt(key[1], val); i++; - } else if (key[1] == 'p' || key[1] == 'A' || key[1] == 'C' - || key[1] == 'r' || key[1] == 'k' - || key[1] == 't' || key[1] == 'V' - || key[1] == '?' || key[1] == 1 -#ifdef WEBSOCKET - ||key[1] == 'R' -#endif - ) { - shellParseSingleOpt(key[1], NULL); + } else if (key[1] == 'p' || key[1] == 'A' || key[1] == 'C' || key[1] == 'r' || key[1] == 'k' || key[1] == 't' || + key[1] == 'V' || key[1] == '?' || key[1] == 1 || key[1] == 'R'|| key[1] == 'B') { + ret = shellParseSingleOpt(key[1], NULL); } else { fprintf(stderr, "invalid option %s\r\n", key); return -1; } + + if (ret != 0) { + return ret; + } } return 0; @@ -348,6 +334,7 @@ static void shellInitArgs(int argc, char *argv[]) { tstrncpy(shell.args.password, (char *)(argv[i] + 2), sizeof(shell.args.password)); strcpy(argv[i], "-p"); } + printf("\r\n"); } } if (strlen(shell.args.password) == 0) { @@ -359,6 +346,9 @@ static void shellInitArgs(int argc, char *argv[]) { pArgs->pktLen = SHELL_DEF_PKG_LEN; pArgs->pktNum = SHELL_DEF_PKG_NUM; pArgs->displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH; + pArgs->timeout = SHELL_WS_TIMEOUT; + + shell.exit = false; } static int32_t shellCheckArgs() { @@ -442,7 +432,7 @@ static int32_t shellCheckArgs() { int32_t shellParseArgs(int32_t argc, char *argv[]) { shellInitArgs(argc, argv); shell.info.clientVersion = - "Welcome to the %s Command Line Interface, Client Version:%s\r\n" + "Welcome to the %s Command Line Interface, %s Client Version:%s \r\n" "Copyright (c) 2025 by %s, all rights reserved.\r\n\r\n"; #ifdef CUS_NAME strcpy(shell.info.cusName, CUS_NAME); @@ -485,8 +475,7 @@ int32_t shellParseArgs(int32_t argc, char *argv[]) { #else shell.info.osname = "Linux"; snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), SHELL_HISTORY_FILE); - shellParseArgsUseArgp(argc, argv); - // if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1; + if (shellParseArgsUseArgp(argc, argv) != 0) return -1; if (shell.args.abort) { return -1; } @@ -494,3 +483,35 @@ int32_t shellParseArgs(int32_t argc, char *argv[]) { return shellCheckArgs(); } + +int32_t getDsnEnv() { + if (shell.args.connMode == CONN_MODE_NATIVE) { + if (shell.args.dsn != NULL) { + fprintf(stderr, DSN_NATIVE_CONFLICT); + return -1; + } + } else { + if (shell.args.dsn != NULL) { + return 0; + } else { + // read cloud + shell.args.dsn = getenv("TDENGINE_CLOUD_DSN"); + if (shell.args.dsn && strlen(shell.args.dsn) > 4) { + fprintf(stderr, "Use the environment variable TDENGINE_CLOUD_DSN:%s as the input for the DSN option.\r\n", + shell.args.dsn); + return 0; + } + + // read local + shell.args.dsn = getenv("TDENGINE_DSN"); + if (shell.args.dsn && strlen(shell.args.dsn) > 4) { + fprintf(stderr, "Use the environment variable TDENGINE_DSN:%s as the input for the DSN option.\r\n", + shell.args.dsn); + return 0; + } + shell.args.dsn = NULL; + } + } + + return 0; +} diff --git a/tools/shell/src/shellAuto.c b/tools/shell/src/shellAuto.c index f8ea42917c..41ed417716 100644 --- a/tools/shell/src/shellAuto.c +++ b/tools/shell/src/shellAuto.c @@ -787,7 +787,7 @@ void GenerateVarType(int type, char** p, int count) { // // init shell auto function , shell start call once -bool shellAutoInit() { +void shellAutoInit() { // command int32_t count = SHELL_COMMAND_COUNT(); for (int32_t i = 0; i < count; i++) { @@ -816,8 +816,6 @@ bool shellAutoInit() { GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*)); GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*)); GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*)); - - return true; } // set conn diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index 10c3d351d4..89d599997d 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -128,15 +128,7 @@ int32_t shellRunSingleCommand(char *command) { shellSourceFile(c_ptr); return 0; } -#ifdef WEBSOCKET - if (shell.args.restful || shell.args.cloud) { - shellRunSingleCommandWebsocketImp(command); - } else { -#endif - shellRunSingleCommandImp(command); -#ifdef WEBSOCKET - } -#endif + shellRunSingleCommandImp(command); return 0; } @@ -291,7 +283,6 @@ void shellRunSingleCommandImp(char *command) { if (error_no == 0) { printf("Query OK, %" PRId64 " row(s) in set (%.6fs)\r\n", numOfRows, (et - st) / 1E6); } else { - terrno = error_no; printf("Query interrupted (%s), %" PRId64 " row(s) in set (%.6fs)\r\n", taos_errstr(NULL), numOfRows, (et - st) / 1E6); } @@ -1101,7 +1092,7 @@ void shellCleanupHistory() { void shellPrintError(TAOS_RES *tres, int64_t st) { int64_t et = taosGetTimestampUs(); - fprintf(stderr, "\r\nDB error: %s[0x%08X] (%.6fs)\r\n", taos_errstr(tres), taos_errno(tres), (et - st) / 1E6); + fprintf(stderr, "\r\nDB error: %s [0x%08X] (%.6fs)\r\n", taos_errstr(tres), taos_errno(tres), (et - st) / 1E6); taos_free_result(tres); } @@ -1258,18 +1249,11 @@ void *shellCancelHandler(void *arg) { continue; } -#ifdef WEBSOCKET - if (shell.args.restful || shell.args.cloud) { - shell.stop_query = true; - } else { -#endif - if (shell.conn) { - shellCmdkilled = true; - taos_kill_query(shell.conn); - } -#ifdef WEBSOCKET + if (shell.conn) { + shellCmdkilled = true; + taos_kill_query(shell.conn); } -#endif + #ifdef WINDOWS printf("\n%s", shell.info.promptHeader); #endif @@ -1314,35 +1298,85 @@ void *shellThreadLoop(void *arg) { } #pragma GCC diagnostic pop +TAOS* createConnect(SShellArgs *pArgs) { + char show[256] = "\0"; + char * host = NULL; + uint16_t port = 0; + char * user = NULL; + char * pwd = NULL; + int32_t code = 0; + char * dsnc = NULL; + + // set mode + if (pArgs->connMode != CONN_MODE_NATIVE && pArgs->dsn) { + dsnc = strToLowerCopy(pArgs->dsn); + if (dsnc == NULL) { + return NULL; + } + + char *cport = NULL; + char error[512] = "\0"; + code = parseDsn(dsnc, &host, &cport, &user, &pwd, error); + if (code) { + printf("%s dsn=%s\n", error, dsnc); + free(dsnc); + return NULL; + } + + // default ws port + if (cport == NULL) { + if (user) + port = DEFAULT_PORT_WS_CLOUD; + else + port = DEFAULT_PORT_WS_LOCAL; + } else { + port = atoi(cport); + } + + // websocket + memcpy(show, pArgs->dsn, 20); + memcpy(show + 20, "...", 3); + memcpy(show + 23, pArgs->dsn + strlen(pArgs->dsn) - 10, 10); + + } else { + + host = (char *)pArgs->host; + user = (char *)pArgs->user; + pwd = pArgs->password; + + if (pArgs->port_inputted) { + port = pArgs->port; + } else { + port = pArgs->connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + } + + sprintf(show, "host:%s port:%d ", host, port); + } + + // connect main + if (pArgs->auth) { + return taos_connect_auth(host, user, pArgs->auth, pArgs->database, port); + } else { + return taos_connect(host, user, pwd, pArgs->database, port); + } +} + int32_t shellExecute(int argc, char *argv[]) { int32_t code = 0; - printf(shell.info.clientVersion, shell.info.cusName, taos_get_client_info(), shell.info.cusName); + printf(shell.info.clientVersion, shell.info.cusName, + shell.args.connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET, + taos_get_client_info(), shell.info.cusName); fflush(stdout); SShellArgs *pArgs = &shell.args; -#ifdef WEBSOCKET - if (shell.args.restful || shell.args.cloud) { - if (shell_conn_ws_server(1)) { - printf("failed to connect to server, reason: %s[0x%08X]\n%s", ws_errstr(NULL), ws_errno(NULL), ERROR_CODE_DETAIL); - fflush(stdout); - return -1; - } - } else { -#endif - if (shell.args.auth == NULL) { - shell.conn = taos_connect(pArgs->host, pArgs->user, pArgs->password, pArgs->database, pArgs->port); - } else { - shell.conn = taos_connect_auth(pArgs->host, pArgs->user, pArgs->auth, pArgs->database, pArgs->port); - } + shell.conn = createConnect(pArgs); - if (shell.conn == NULL) { - printf("failed to connect to server, reason: %s[0x%08X]\n%s", taos_errstr(NULL), taos_errno(NULL), ERROR_CODE_DETAIL); - fflush(stdout); - return -1; - } -#ifdef WEBSOCKET + if (shell.conn == NULL) { + printf("failed to connect to server, reason: %s [0x%08X]\n%s", taos_errstr(NULL), taos_errno(NULL), + ERROR_CODE_DETAIL); + fflush(stdout); + return -1; } -#endif bool runOnce = pArgs->commands != NULL || pArgs->file[0] != 0; shellSetConn(shell.conn, runOnce); @@ -1351,9 +1385,7 @@ int32_t shellExecute(int argc, char *argv[]) { if (shell.args.is_bi_mode) { // need set bi mode printf("Set BI mode is true.\n"); -#ifndef WEBSOCKET taos_set_conn_mode(shell.conn, TAOS_CONN_MODE_BI, 1); -#endif } if (runOnce) { @@ -1367,15 +1399,8 @@ int32_t shellExecute(int argc, char *argv[]) { if (pArgs->file[0] != 0) { shellSourceFile(pArgs->file); } -#ifdef WEBSOCKET - if (shell.args.restful || shell.args.cloud) { - ws_close(shell.ws_conn); - } else { -#endif - taos_close(shell.conn); -#ifdef WEBSOCKET - } -#endif + + taos_close(shell.conn); shellWriteHistory(); shellCleanupHistory(); @@ -1394,28 +1419,20 @@ int32_t shellExecute(int argc, char *argv[]) { taosSetSignal(SIGHUP, shellQueryInterruptHandler); taosSetSignal(SIGINT, shellQueryInterruptHandler); -#ifdef WEBSOCKET - if (!shell.args.restful && !shell.args.cloud) { -#endif - char buf[512] = {0}; - int32_t verType = shellGetGrantInfo(buf); + char buf[512] = {0}; + int32_t verType = shellGetGrantInfo(buf); #ifndef WINDOWS - printfIntroduction(verType); + printfIntroduction(verType); #else -#ifndef WEBSOCKET if (verType == TSDB_VERSION_OSS) { showAD(false); } #endif -#endif - // printf version - if (verType == TSDB_VERSION_ENTERPRISE || verType == TSDB_VERSION_CLOUD) { - printf("%s\n", buf); - } - -#ifdef WEBSOCKET + // printf version + if (verType == TSDB_VERSION_ENTERPRISE || verType == TSDB_VERSION_CLOUD) { + printf("%s\n", buf); } -#endif + while (1) { taosThreadCreate(&shell.pid, NULL, shellThreadLoop, NULL); taosThreadJoin(shell.pid, NULL); @@ -1425,12 +1442,10 @@ int32_t shellExecute(int argc, char *argv[]) { break; } } -#ifndef WEBSOCKET - // commnuity + if (verType == TSDB_VERSION_OSS) { showAD(true); } -#endif taosThreadJoin(spid, NULL); diff --git a/tools/shell/src/shellMain.c b/tools/shell/src/shellMain.c index 19277de1dd..677d2808b2 100644 --- a/tools/shell/src/shellMain.c +++ b/tools/shell/src/shellMain.c @@ -14,8 +14,8 @@ */ #define __USE_XOPEN -#include "shellInt.h" #include "shellAuto.h" +#include "shellInt.h" extern SShellObj shell; @@ -24,15 +24,14 @@ void shellCrashHandler(int signum, void *sigInfo, void *context) { taosIgnSignal(SIGHUP); taosIgnSignal(SIGINT); taosIgnSignal(SIGBREAK); - -#if !defined(WINDOWS) - taosIgnSignal(SIGBUS); -#endif taosIgnSignal(SIGABRT); taosIgnSignal(SIGFPE); taosIgnSignal(SIGSEGV); +#if !defined(WINDOWS) + taosIgnSignal(SIGBUS); +#endif #ifdef USE_REPORT - tscWriteCrashInfo(signum, sigInfo, context); + taos_write_crashinfo(signum, sigInfo, context); #endif #ifdef _TD_DARWIN_64 exit(signum); @@ -41,14 +40,33 @@ void shellCrashHandler(int signum, void *sigInfo, void *context) { #endif } -int main(int argc, char *argv[]) { - shell.exit = false; -#ifdef WEBSOCKET - shell.args.timeout = SHELL_WS_TIMEOUT; - shell.args.cloud = true; - shell.args.local = false; -#endif +// init arguments +void initArgument(SShellArgs *pArgs) { + pArgs->host = NULL; + pArgs->port = 0; + pArgs->user = NULL; + pArgs->database = NULL; + // conn mode + pArgs->dsn = NULL; + pArgs->connMode = CONN_MODE_INVALID; + + pArgs->port_inputted = false; +} + +// set conn mode +int32_t setConnMode(int8_t connMode) { + // set conn mode + char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; + int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); + if (code != TSDB_CODE_SUCCESS) { + fprintf(stderr, "failed to load driver since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) { #if !defined(WINDOWS) taosSetSignal(SIGBUS, shellCrashHandler); #endif @@ -56,6 +74,8 @@ int main(int argc, char *argv[]) { taosSetSignal(SIGFPE, shellCrashHandler); taosSetSignal(SIGSEGV, shellCrashHandler); + initArgument(&shell.args); + if (shellCheckIntSize() != 0) { return -1; } @@ -78,10 +98,27 @@ int main(int argc, char *argv[]) { shellPrintHelp(); return 0; } -#ifdef WEBSOCKET - shellCheckConnectMode(); -#endif + + if (shell.args.netrole != NULL) { + shellTestNetWork(); + return 0; + } + + if (shell.args.is_dump_config) { + shellDumpConfig(); + return 0; + } + + if (getDsnEnv() != 0) { + return -1; + } + + if (setConnMode(shell.args.connMode)) { + return -1; + } + if (taos_init() != 0) { + fprintf(stderr, "failed to init shell since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); return -1; } @@ -111,5 +148,6 @@ int main(int argc, char *argv[]) { shellAutoInit(); int32_t ret = shellExecute(argc, argv); shellAutoExit(); + return ret; } diff --git a/tools/shell/src/shellNettest.c b/tools/shell/src/shellNettest.c index d1ecf503d2..c779a2d899 100644 --- a/tools/shell/src/shellNettest.c +++ b/tools/shell/src/shellNettest.c @@ -15,7 +15,6 @@ #define _GNU_SOURCE #include "shellInt.h" -#include "tversion.h" static void shellWorkAsClient() { SShellArgs *pArgs = &shell.args; @@ -30,9 +29,9 @@ static void shellWorkAsClient() { rpcInit.numOfThreads = 1; rpcInit.sessions = 16; rpcInit.connType = TAOS_CONN_CLIENT; - rpcInit.idleTime = tsShellActivityTimer * 1000; + rpcInit.idleTime = 3000; rpcInit.user = "_dnd"; - rpcInit.timeToGetConn = tsTimeToGetAvailableConn; + rpcInit.timeToGetConn = 500000; taosVersionStrToInt(td_version, &rpcInit.compatibilityVer); clientRpc = rpcOpen(&rpcInit); @@ -41,17 +40,16 @@ static void shellWorkAsClient() { goto _OVER; } + if (pArgs->port == 0) { + pArgs->port = 6030; + } if (pArgs->host == NULL) { - pArgs->host = tsFirst; + pArgs->host = "localhost"; } char fqdn[TSDB_FQDN_LEN] = {0}; tstrncpy(fqdn, pArgs->host, TSDB_FQDN_LEN); strtok(fqdn, ":"); - if (pArgs->port == 0) { - pArgs->port = tsServerPort; - } - printf("network test client is initialized, the server is %s:%u\r\n", fqdn, pArgs->port); tstrncpy(epSet.eps[0].fqdn, fqdn, TSDB_FQDN_LEN); @@ -112,18 +110,21 @@ static void shellWorkAsServer() { SShellArgs *pArgs = &shell.args; if (pArgs->port == 0) { - pArgs->port = tsServerPort; + pArgs->port = 6030; + } + if (pArgs->host == NULL) { + pArgs->host = "127.0.0.1"; } SRpcInit rpcInit = {0}; - memcpy(rpcInit.localFqdn, tsLocalFqdn, strlen(tsLocalFqdn)); + memcpy(rpcInit.localFqdn, pArgs->host, strlen(pArgs->host)); rpcInit.localPort = pArgs->port; rpcInit.label = "CHK"; rpcInit.numOfThreads = 2; rpcInit.cfp = (RpcCfp)shellProcessMsg; rpcInit.sessions = 10; rpcInit.connType = TAOS_CONN_SERVER; - rpcInit.idleTime = tsShellActivityTimer * 1000; + rpcInit.idleTime = 3000; taosVersionStrToInt(td_version, &rpcInit.compatibilityVer); @@ -131,13 +132,16 @@ static void shellWorkAsServer() { if (serverRpc == NULL) { printf("failed to init net test server since %s\r\n", terrstr()); } else { - printf("network test server is initialized, port:%u\r\n", pArgs->port); + printf("network test server is initialized, %s:%u\r\n", pArgs->host, pArgs->port); taosSetSignal(SIGTERM, shellNettestHandler); while (1) taosMsleep(10); } } void shellTestNetWork() { + (void)osDefaultInit(); + (void)rpcInit(); + if (strcmp(shell.args.netrole, "client") == 0) { shellWorkAsClient(); } diff --git a/tools/shell/src/shellUtil.c b/tools/shell/src/shellUtil.c index a8c1193ab8..73150b89d3 100644 --- a/tools/shell/src/shellUtil.c +++ b/tools/shell/src/shellUtil.c @@ -50,19 +50,19 @@ bool shellRegexMatch(const char *s, const char *reg, int32_t cflags) { int32_t shellCheckIntSize() { if (sizeof(int8_t) != 1) { - printf("int8 size is %d(!= 1)", (int)sizeof(int8_t)); + printf("int8 size is %d(!= 1)\r\n", (int)sizeof(int8_t)); return -1; } if (sizeof(int16_t) != 2) { - printf("int16 size is %d(!= 2)", (int)sizeof(int16_t)); + printf("int16 size is %d(!= 2)\r\n", (int)sizeof(int16_t)); return -1; } if (sizeof(int32_t) != 4) { - printf("int32 size is %d(!= 4)", (int)sizeof(int32_t)); + printf("int32 size is %d(!= 4)\r\n", (int)sizeof(int32_t)); return -1; } if (sizeof(int64_t) != 8) { - printf("int64 size is %d(!= 8)", (int)sizeof(int64_t)); + printf("int64 size is %d(!= 8)\r\n", (int)sizeof(int64_t)); return -1; } return 0; @@ -78,12 +78,15 @@ void shellGenerateAuth() { } void shellDumpConfig() { - SConfig *pCfg = taosGetCfg(); - if (pCfg == NULL) { - printf("read global config failed!\r\n"); - } else { - cfgDumpCfg(pCfg, 1, true); + (void)osDefaultInit(); + + if (taosInitCfg(configDir, NULL, NULL, NULL, NULL, 1) != 0) { + fprintf(stderr, "failed to load cfg since %s [0x%08X]\n", terrstr(), terrno); + return; } + + cfgDumpCfg(taosGetCfg(), 1, true); + fflush(stdout); } @@ -121,48 +124,6 @@ void shellCheckServerStatus() { } } while (1); } -#ifdef WEBSOCKET -char dsn[1024] = "ws://localhost:6041"; -void shellCheckConnectMode() { - if (shell.args.dsn) { - shell.args.cloud = true; - shell.args.restful = false; - return; - } - if (shell.args.cloud) { - shell.args.dsn = getenv("TDENGINE_CLOUD_DSN"); - if (shell.args.dsn && strlen(shell.args.dsn) > 4) { - shell.args.cloud = true; - shell.args.local = false; - shell.args.restful = false; - return; - } - - shell.args.dsn = getenv("TDENGINE_DSN"); - if (shell.args.dsn && strlen(shell.args.dsn) > 4) { - shell.args.cloud = true; - shell.args.local = true; - shell.args.restful = false; - return; - } - } - - if (shell.args.restful) { - if (!shell.args.host) { - shell.args.host = "localhost"; - } - if (!shell.args.port) { - shell.args.port = 6041; - } - shell.args.dsn = dsn; - snprintf(shell.args.dsn, 1024, "ws://%s:%d", - shell.args.host, shell.args.port); - } - shell.args.cloud = false; - return; - -} -#endif void shellExit() { if (shell.conn != NULL) { diff --git a/tools/shell/src/shellWebsocket.c b/tools/shell/src/shellWebsocket.c deleted file mode 100644 index 61074102be..0000000000 --- a/tools/shell/src/shellWebsocket.c +++ /dev/null @@ -1,396 +0,0 @@ - -/* - * 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 . - */ -#ifdef WEBSOCKET -#include -#include - -// save current database name -char curDBName[128] = ""; // TDB_MAX_DBNAME_LEN is 24, put large - -int shell_conn_ws_server(bool first) { - char cuttedDsn[SHELL_WS_DSN_BUFF] = {0}; - int dsnLen = strlen(shell.args.dsn); - snprintf(cuttedDsn, - ((dsnLen-SHELL_WS_DSN_MASK) > SHELL_WS_DSN_BUFF)? - SHELL_WS_DSN_BUFF:(dsnLen-SHELL_WS_DSN_MASK), - "%s", shell.args.dsn); - fprintf(stdout, "trying to connect %s****** ", cuttedDsn); - fflush(stdout); - for (int i = 0; i < shell.args.timeout; i++) { - if(shell.args.is_bi_mode) { - size_t len = strlen(shell.args.dsn); - char * dsn = taosMemoryMalloc(len + 32); - sprintf(dsn, "%s&conn_mode=1", shell.args.dsn); - shell.ws_conn = ws_connect(dsn); - taosMemoryFree(dsn); - } else { - shell.ws_conn = ws_connect(shell.args.dsn); - } - - if (NULL == shell.ws_conn) { - int errNo = ws_errno(NULL); - if (0xE001 == errNo) { - fprintf(stdout, "."); - fflush(stdout); - taosMsleep(1000); // sleep 1 second then try again - continue; - } else { - fprintf(stderr, "\nfailed to connect %s***, reason: %s\n", - cuttedDsn, ws_errstr(NULL)); - return -1; - } - } else { - break; - } - } - if (NULL == shell.ws_conn) { - fprintf(stdout, "\n timeout\n"); - fprintf(stderr, "\nfailed to connect %s***, reason: %s\n", - cuttedDsn, ws_errstr(NULL)); - return -1; - } else { - fprintf(stdout, "\n"); - } - if (first && shell.args.restful) { - fprintf(stdout, "successfully connected to %s\n\n", - shell.args.dsn); - } else if (first && shell.args.cloud) { - if(shell.args.local) { - const char* host = strstr(shell.args.dsn, "@"); - if(host) { - host += 1; - } else { - host = shell.args.dsn; - } - fprintf(stdout, "successfully connected to %s\n", host); - } else { - fprintf(stdout, "successfully connected to service\n"); - } - } - fflush(stdout); - - // switch to current database if have - if(curDBName[0] !=0) { - char command[256]; - sprintf(command, "use %s;", curDBName); - shellRunSingleCommandWebsocketImp(command); - } - - return 0; -} - -static int horizontalPrintWebsocket(WS_RES* wres, double* execute_time) { - const void* data = NULL; - int rows; - ws_fetch_raw_block(wres, &data, &rows); - if (wres) { - *execute_time += (double)(ws_take_timing(wres)/1E6); - } - if (!rows) { - return 0; - } - int num_fields = ws_field_count(wres); - TAOS_FIELD* fields = (TAOS_FIELD*)ws_fetch_fields(wres); - int precision = ws_result_precision(wres); - - int width[TSDB_MAX_COLUMNS]; - for (int col = 0; col < num_fields; col++) { - width[col] = shellCalcColWidth(fields + col, precision); - } - - shellPrintHeader(fields, width, num_fields); - - int numOfRows = 0; - do { - uint8_t ty; - uint32_t len; - for (int i = 0; i < rows; i++) { - for (int j = 0; j < num_fields; j++) { - putchar(' '); - const void *value = ws_get_value_in_block(wres, i, j, &ty, &len); - shellPrintField((const char*)value, fields+j, width[j], len, precision); - putchar(' '); - putchar('|'); - } - putchar('\r'); - putchar('\n'); - } - numOfRows += rows; - ws_fetch_raw_block(wres, &data, &rows); - } while (rows && !shell.stop_query); - return numOfRows; -} - -static int verticalPrintWebsocket(WS_RES* wres, double* pexecute_time) { - int rows = 0; - const void* data = NULL; - ws_fetch_raw_block(wres, &data, &rows); - if (wres) { - *pexecute_time += (double)(ws_take_timing(wres)/1E6); - } - if (!rows) { - return 0; - } - int num_fields = ws_field_count(wres); - TAOS_FIELD* fields = (TAOS_FIELD*)ws_fetch_fields(wres); - int precision = ws_result_precision(wres); - - int maxColNameLen = 0; - for (int col = 0; col < num_fields; col++) { - int len = (int)strlen(fields[col].name); - if (len > maxColNameLen) { - maxColNameLen = len; - } - } - int numOfRows = 0; - do { - uint8_t ty; - uint32_t len; - for (int i = 0; i < rows; i++) { - printf("*************************** %d.row ***************************\n", - numOfRows + 1); - for (int j = 0; j < num_fields; j++) { - TAOS_FIELD* field = fields + j; - int padding = (int)(maxColNameLen - strlen(field->name)); - printf("%*.s%s: ", padding, " ", field->name); - const void *value = ws_get_value_in_block(wres, i, j, &ty, &len); - shellPrintField((const char*)value, field, 0, len, precision); - putchar('\n'); - } - numOfRows++; - } - ws_fetch_raw_block(wres, &data, &rows); - } while (rows && !shell.stop_query); - return numOfRows; -} - -static int dumpWebsocketToFile(const char* fname, WS_RES* wres, - double* pexecute_time) { - char fullname[PATH_MAX] = {0}; - if (taosExpandDir(fname, fullname, PATH_MAX) != 0) { - tstrncpy(fullname, fname, PATH_MAX); - } - - TdFilePtr pFile = taosOpenFile(fullname, - TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM); - if (pFile == NULL) { - fprintf(stderr, "failed to open file: %s\r\n", fullname); - return -1; - } - int rows = 0; - const void* data = NULL; - ws_fetch_raw_block(wres, &data, &rows); - if (wres) { - *pexecute_time += (double)(ws_take_timing(wres)/1E6); - } - if (!rows) { - taosCloseFile(&pFile); - return 0; - } - int numOfRows = 0; - TAOS_FIELD* fields = (TAOS_FIELD*)ws_fetch_fields(wres); - int num_fields = ws_field_count(wres); - int precision = ws_result_precision(wres); - for (int col = 0; col < num_fields; col++) { - if (col > 0) { - taosFprintfFile(pFile, ","); - } - taosFprintfFile(pFile, "%s", fields[col].name); - } - taosFprintfFile(pFile, "\r\n"); - do { - uint8_t ty; - uint32_t len; - numOfRows += rows; - for (int i = 0; i < rows; i++) { - for (int j = 0; j < num_fields; j++) { - if (j > 0) { - taosFprintfFile(pFile, ","); - } - const void *value = ws_get_value_in_block(wres, i, j, &ty, &len); - shellDumpFieldToFile(pFile, (const char*)value, - fields + j, len, precision); - } - taosFprintfFile(pFile, "\r\n"); - } - ws_fetch_raw_block(wres, &data, &rows); - } while (rows && !shell.stop_query); - taosCloseFile(&pFile); - return numOfRows; -} - -static int shellDumpWebsocket(WS_RES *wres, char *fname, - int *error_no, bool vertical, - double* pexecute_time) { - int numOfRows = 0; - if (fname != NULL) { - numOfRows = dumpWebsocketToFile(fname, wres, pexecute_time); - } else if (vertical) { - numOfRows = verticalPrintWebsocket(wres, pexecute_time); - } else { - numOfRows = horizontalPrintWebsocket(wres, pexecute_time); - } - *error_no = ws_errno(wres); - return numOfRows; -} - -char * strendG(const char* pstr); -void shellRunSingleCommandWebsocketImp(char *command) { - int64_t st, et; - char *sptr = NULL; - char *cptr = NULL; - char *fname = NULL; - bool printMode = false; - - if ((sptr = strstr(command, ">>")) != NULL) { - fname = sptr + 2; - while (*fname == ' ') fname++; - *sptr = '\0'; - - cptr = strstr(fname, ";"); - if (cptr != NULL) { - *cptr = '\0'; - } - } - - if ((sptr = strendG(command)) != NULL) { - *sptr = '\0'; - printMode = true; // When output to a file, the switch does not work. - } - - shell.stop_query = false; - WS_RES* res; - - for (int reconnectNum = 0; reconnectNum < 2; reconnectNum++) { - if (!shell.ws_conn && shell_conn_ws_server(0) || shell.stop_query) { - return; - } - st = taosGetTimestampUs(); - - res = ws_query_timeout(shell.ws_conn, command, shell.args.timeout); - int code = ws_errno(res); - if (code != 0 && !shell.stop_query) { - // if it's not a ws connection error - if (TSDB_CODE_WS_DSN_ERROR != (code&TSDB_CODE_WS_DSN_ERROR)) { - et = taosGetTimestampUs(); - fprintf(stderr, "\nDB: error:0x%08X %s (%.6fs)\n", - ws_errno(res), ws_errstr(res), (et - st)/1E6); - ws_free_result(res); - return; - } - if (code == TSDB_CODE_WS_SEND_TIMEOUT - || code == TSDB_CODE_WS_RECV_TIMEOUT) { - fprintf(stderr, "Hint: use -T to increase the timeout in seconds\n"); - } else if (code == TSDB_CODE_WS_INTERNAL_ERRO - || code == TSDB_CODE_WS_CLOSED) { - shell.ws_conn = NULL; - } - ws_free_result(res); - if (reconnectNum == 0) { - continue; - } else { - fprintf(stderr, "The server is disconnected, will try to reconnect\n"); - } - return; - } - break; - } - - double execute_time = 0; - if (res) { - execute_time = ws_take_timing(res)/1E6; - } - - if (shellRegexMatch(command, "^\\s*use\\s+[a-zA-Z0-9_]+\\s*;\\s*$", - REG_EXTENDED | REG_ICASE)) { - - // copy dbname to curDBName - char *p = command; - bool firstStart = false; - bool firstEnd = false; - int i = 0; - while (*p != 0) { - if (*p != ' ') { - // not blank - if (!firstStart) { - firstStart = true; - } else if (firstEnd) { - if(*p == ';' && *p != '\\') { - break; - } - // database name - curDBName[i++] = *p; - if(i + 4 > sizeof(curDBName)) { - // DBName is too long, reset zero and break - i = 0; - break; - } - } - } else { - // blank - if(firstStart == true && firstEnd == false){ - firstEnd = true; - } - if(firstStart && firstEnd && i > 0){ - // blank after database name - break; - } - } - // move next - p++; - } - // append end - curDBName[i] = 0; - - fprintf(stdout, "Database changed to %s.\r\n\r\n", curDBName); - fflush(stdout); - ws_free_result(res); - return; - } - - int numOfRows = 0; - if (ws_is_update_query(res)) { - numOfRows = ws_affected_rows(res); - et = taosGetTimestampUs(); - double total_time = (et - st)/1E3; - double net_time = total_time - (double)execute_time; - printf("Query Ok, %d of %d row(s) in database\n", numOfRows, numOfRows); - printf("Execute: %.2f ms Network: %.2f ms Total: %.2f ms\n", - execute_time, net_time, total_time); - } else { - int error_no = 0; - numOfRows = shellDumpWebsocket(res, fname, &error_no, - printMode, &execute_time); - if (numOfRows < 0) { - ws_free_result(res); - return; - } - et = taosGetTimestampUs(); - double total_time = (et - st) / 1E3; - double net_time = total_time - execute_time; - if (error_no == 0 && !shell.stop_query) { - printf("Query OK, %d row(s) in set\n", numOfRows); - printf("Execute: %.2f ms Network: %.2f ms Total: %.2f ms\n", - execute_time, net_time, total_time); - } else { - printf("Query interrupted, %d row(s) in set (%.6fs)\n", numOfRows, - (et - st)/1E6); - } - } - printf("\n"); - ws_free_result(res); -} -#endif diff --git a/tools/src/pub.c b/tools/src/pub.c new file mode 100644 index 0000000000..0e1cbdd654 --- /dev/null +++ b/tools/src/pub.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the MIT license 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. + */ + + #include + #include "../inc/pub.h" + + + char* strToLowerCopy(const char *str) { + if (str == NULL) { + return NULL; + } + size_t len = strlen(str); + char *result = (char*)malloc(len + 1); + if (result == NULL) { + return NULL; + } + for (size_t i = 0; i < len; i++) { + result[i] = tolower((unsigned char)str[i]); + } + result[len] = '\0'; + return result; + } + + int32_t parseDsn(char* dsn, char **host, char **port, char **user, char **pwd, char *error) { + // dsn format: + // local http://127.0.0.1:6041 + // cloud https://gw.cloud.taosdata.com?token=617ffdf... + // https://gw.cloud.taosdata.com:433?token=617ffdf... + + // find "://" + char *p1 = strstr(dsn, "://"); + if (p1 == NULL) { + sprintf(error, "%s", "dsn invalid, not found \"://\" "); + return -1; + } + *host = p1 + 3; // host + char *p = *host; + + // find ":" - option + char *p2 = strstr(p, ":"); + if (p2) { + p = p2 + 1; + *port = p2 + 1; // port + *p2 = 0; + } + + // find "?" + char *p3 = strstr(p, "?"); + if (p3) { + p = p3 + 1; + *user = p3 + 1; + *p3 = 0; + } else { + return 0; + } + + // find "=" + char *p4 = strstr(p, "="); + if (p4) { + *p4 = 0; + *pwd = p4 + 1; + } else { + sprintf(error, "%s", "dsn invalid, found \"?\" but not found \"=\" "); + return -1; + } + + return 0; + } + + // get comn mode, if invalid exit app + int8_t getConnMode(char *arg) { + // compare + if (strcasecmp(arg, STR_NATIVE) == 0 || strcasecmp(arg, "0") == 0) { + return CONN_MODE_NATIVE; + } else if (strcasecmp(arg, STR_WEBSOCKET) == 0 || strcasecmp(arg, "1") == 0) { + return CONN_MODE_WEBSOCKET; + } else { + fprintf(stderr, "invalid input %s for option -Z, only support: %s or %s\r\n", arg, STR_NATIVE, STR_WEBSOCKET); + exit(-1); + } + } + \ No newline at end of file diff --git a/tools/taos-tools/deps/toolscJson/src/toolscJson.c b/tools/taos-tools/deps/toolscJson/src/toolscJson.c index b52538912c..110dcd6c49 100644 --- a/tools/taos-tools/deps/toolscJson/src/toolscJson.c +++ b/tools/taos-tools/deps/toolscJson/src/toolscJson.c @@ -277,7 +277,7 @@ loop_end: item->valuedouble = number; /* use saturation in case of overflow */ - if (number >= LLONG_MAX) + if (number >= (double)LLONG_MAX) { item->valueint = LLONG_MAX; } @@ -303,7 +303,7 @@ loop_end: /* don't ask me, but the original tools_cJSON_SetNumberValue returns an integer or double */ CJSON_PUBLIC(double) tools_cJSON_SetNumberHelper(tools_cJSON *object, double number) { - if (number >= LLONG_MAX) + if (number >= (double)LLONG_MAX) { object->valueint = LLONG_MAX; } @@ -2104,7 +2104,7 @@ CJSON_PUBLIC(tools_cJSON *) tools_cJSON_CreateNumber(double num) item->valuedouble = num; /* use saturation in case of overflow */ - if (num >= LLONG_MAX) + if (num >= (double)LLONG_MAX) { item->valueint = LLONG_MAX; } diff --git a/tools/taos-tools/inc/bench.h b/tools/taos-tools/inc/bench.h index 8adb879301..a965984e33 100644 --- a/tools/taos-tools/inc/bench.h +++ b/tools/taos-tools/inc/bench.h @@ -16,6 +16,8 @@ #ifndef INC_BENCH_H_ #define INC_BENCH_H_ +#include "pub.h" + #define _GNU_SOURCE #define CURL_STATICLIB #define ALLOW_FORBID_FUNC @@ -74,10 +76,7 @@ #include #include #include - -#ifdef WEBSOCKET -#include -#endif +#include "../../inc/pub.h" #ifdef WINDOWS #define _CRT_RAND_S @@ -257,19 +256,11 @@ typedef unsigned __int32 uint32_t; "when keep trying be enabled." #define BENCH_NODROP "Do not drop database." -#ifdef WEBSOCKET -#define BENCH_DSN "The dsn to connect the cloud service." -#define BENCH_TIMEOUT \ - "The timeout wait on websocket query in seconds, default is 10." -#endif - #define IS_VAR_DATA_TYPE(t) \ (((t) == TSDB_DATA_TYPE_VARCHAR) || ((t) == TSDB_DATA_TYPE_VARBINARY) || ((t) == TSDB_DATA_TYPE_NCHAR) || \ ((t) == TSDB_DATA_TYPE_JSON) || ((t) == TSDB_DATA_TYPE_GEOMETRY)) - - enum TEST_MODE { INSERT_TEST, // 0 QUERY_TEST, // 1 @@ -281,11 +272,9 @@ enum enumSYNC_MODE { SYNC_MODE, ASYNC_MODE, MODE_BUT }; enum enum_TAOS_INTERFACE { TAOSC_IFACE, - REST_IFACE, STMT_IFACE, STMT2_IFACE, SML_IFACE, - SML_REST_IFACE, INTERFACE_BUT }; @@ -763,7 +752,6 @@ typedef struct SArguments_S { uint64_t insert_interval; bool demo_mode; bool aggr_func; - struct sockaddr_in serv_addr; uint64_t totalChildTables; uint64_t actualChildTables; uint64_t autoCreatedChildTables; @@ -777,18 +765,16 @@ typedef struct SArguments_S { #endif bool terminate; bool in_prompt; -#ifdef WEBSOCKET - int32_t timeout; + + // websocket char* dsn; - bool websocket; -#endif + bool supplementInsert; int64_t startTimestamp; int32_t partialColNum; int32_t keep_trying; uint32_t trying_interval; int iface; - int rest_server_ver_major; bool check_sql; int suit; // see define SUIT_ int16_t inputted_vgroups; @@ -797,10 +783,9 @@ typedef struct SArguments_S { bool escape_character; bool pre_load_tb_meta; bool bind_vgroup; - + int8_t connMode; // see define CONN_MODE_ char* output_path; char output_path_buf[MAX_PATH_LEN]; - } SArguments; typedef struct SBenchConn { @@ -808,10 +793,6 @@ typedef struct SBenchConn { TAOS* ctaos; // check taos TAOS_STMT* stmt; TAOS_STMT2* stmt2; -#ifdef WEBSOCKET - WS_TAOS* taos_ws; - WS_STMT* stmt_ws; -#endif } SBenchConn; #define MAX_BATCOLS 256 @@ -941,18 +922,10 @@ void tmfclose(FILE *fp); int64_t fetchResult(TAOS_RES *res, char *filePath); void prompt(bool NonStopMode); void ERROR_EXIT(const char *msg); -int getServerVersionRest(int16_t rest_port); -int postProceSql(char *sqlstr, char* dbName, int precision, int iface, - int protocol, uint16_t rest_port, bool tcp, - int sockfd, char* filePath); int queryDbExecCall(SBenchConn *conn, char *command); -int queryDbExecRest(char *command, char* dbName, int precision, - int iface, int protocol, bool tcp, int sockfd); SBenchConn* initBenchConn(); void closeBenchConn(SBenchConn* conn); int regexMatch(const char *s, const char *reg, int cflags); -int convertHostToServAddr(char *host, uint16_t port, - struct sockaddr_in *serv_addr); int getAllChildNameOfSuperTable(TAOS *taos, char *dbName, char *stbName, char ** childTblNameOfSuperTbl, int64_t childTblCountOfSuperTbl); @@ -998,9 +971,6 @@ int insertTestProcess(); void postFreeResource(); int queryTestProcess(); int subscribeTestProcess(); -int convertServAddr(int iface, bool tcp, int protocol); -int createSockFd(); -void destroySockFd(int sockfd); void printVersion(); int32_t benchParseSingleOpt(int32_t key, char* arg); @@ -1034,6 +1004,9 @@ int tmpGeometry(char *tmp, int iface, Field *field, int64_t k); int tmpInt32ImplTag(Field *field, int i, int k); char* genQMark( int32_t QCnt); +// get colNames , first is tbname if tbName is true +char *genColNames(BArray *cols, bool tbName); + // stmt2 TAOS_STMT2_BINDV* createBindV(int32_t count, int32_t tagCnt, int32_t colCnt); // clear bindv table count tables tag and column @@ -1042,9 +1015,6 @@ void clearBindV(TAOS_STMT2_BINDV *bindv); void freeBindV(TAOS_STMT2_BINDV *bindv); void showBindV(TAOS_STMT2_BINDV *bindv, BArray *tags, BArray *cols); -// IFace is rest return True -bool isRest(int32_t iface); - // get group index about dbname.tbname int32_t calcGroupIndex(char* dbName, char* tbName, int32_t groupCnt); @@ -1060,6 +1030,8 @@ void *queryKiller(void *arg); int killSlowQuery(); // fetch super table child name from server int fetchChildTableName(char *dbName, char *stbName); +// call engine error +void engineError(char * module, char * fun, int32_t code); // trim prefix suffix blank cmp int trimCaseCmp(char *str1,char *str2); diff --git a/tools/taos-tools/inc/benchData.h b/tools/taos-tools/inc/benchData.h index 0ccbf7df22..804ae0c793 100644 --- a/tools/taos-tools/inc/benchData.h +++ b/tools/taos-tools/inc/benchData.h @@ -29,8 +29,8 @@ int generateRandData(SSuperTable *stbInfo, char *sampleDataBuf, int lenOfOneRow, BArray * fields, int64_t loop, bool tag, BArray *childCols); // prepare -int prepareStmt (TAOS_STMT *stmt, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq); -int prepareStmt2(TAOS_STMT2 *stmt2, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq); +int prepareStmt (TAOS_STMT *stmt, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char *db); +int prepareStmt2(TAOS_STMT2 *stmt2, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char *db); uint32_t bindParamBatch(threadInfo *pThreadInfo, uint32_t batch, int64_t startTime, int64_t pos, diff --git a/tools/taos-tools/inc/benchLog.h b/tools/taos-tools/inc/benchLog.h index ab74aaff75..5b7b9ec139 100644 --- a/tools/taos-tools/inc/benchLog.h +++ b/tools/taos-tools/inc/benchLog.h @@ -39,7 +39,6 @@ void unlockLog(int8_t idx); // exit log void exitLog(); - #define debugPrint(fmt, ...) \ do { \ if (g_arguments->debug_print) { \ diff --git a/tools/taos-tools/inc/dump.h b/tools/taos-tools/inc/dump.h index 9a30ebb9cd..68ccd20d1a 100644 --- a/tools/taos-tools/inc/dump.h +++ b/tools/taos-tools/inc/dump.h @@ -39,10 +39,7 @@ #include #include #include - -#ifdef WEBSOCKET -#include -#endif +#include "../../inc/pub.h" // @@ -378,22 +375,18 @@ typedef struct arguments { bool performance_print; bool dotReplace; int dumpDbCount; -#ifdef WEBSOCKET - bool restful; - bool cloud; - int ws_timeout; + + int8_t connMode; + bool port_inputted; char *dsn; - char *cloudToken; - int cloudPort; - char cloudHost[MAX_HOSTNAME_LEN]; -#endif // put rename db string char * renameBuf; SRenameDB * renameHead; // retry for call engine api int32_t retryCount; - int32_t retrySleepMs; + int32_t retrySleepMs; + } SArguments; bool isSystemDatabase(char *dbName); @@ -480,6 +473,7 @@ int64_t dumpANormalTableNotBelong( void* openQuery(void** taos_v , const char * sql); void closeQuery(void* res); int32_t readRow(void *res, int32_t idx, int32_t col, uint32_t *len, char **data); +void engineError(char * module, char * fun, int32_t code); extern struct arguments g_args; diff --git a/tools/taos-tools/inc/dumpUtil.h b/tools/taos-tools/inc/dumpUtil.h index 484237177e..b4c05e8d51 100644 --- a/tools/taos-tools/inc/dumpUtil.h +++ b/tools/taos-tools/inc/dumpUtil.h @@ -66,18 +66,4 @@ TAOS *taosConnect(const char *dbName); TAOS_RES *taosQuery(TAOS *taos, const char *sql, int32_t *code); -// -// --------------- websocket ------------------ -// -#ifdef WEBSOCKET -// ws connect -WS_TAOS *wsConnect(); -// ws query -WS_RES *wsQuery(WS_TAOS **ws_taos, const char *sql, int32_t *code); -// ws fetch -int32_t wsFetchBlock(WS_RES *rs, const void **pData, int32_t *numOfRows); - -#endif - - #endif // INC_DUMPUTIL_H_ \ No newline at end of file diff --git a/tools/taos-tools/inc/wsdump.h b/tools/taos-tools/inc/wsdump.h deleted file mode 100644 index 5b65b8c17c..0000000000 --- a/tools/taos-tools/inc/wsdump.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef INC_WSDUMP_H_ -#define INC_WSDUMP_H_ - -// -// --------------- websocket ------------------ -// - -#ifdef WEBSOCKET - -#include -#include -#include - -int cleanIfQueryFailedWS(const char *funcname, int lineno, char *command, WS_RES *res); -int getTableRecordInfoWS(char *dbName, char *table, TableRecordInfo *pTableRecordInfo); -int getDbCountWS(WS_RES *ws_res); -int64_t getNtbCountOfStbWS(char *dbName, const char *stbName); -int getTableDesFromStbWS(WS_TAOS **taos_v, const char *dbName, const TableDes *stbTableDes, const char *table, - TableDes **ppTableDes); -int getTableDesWS(WS_TAOS **taos_v, const char *dbName, const char *table, TableDes *tableDes, const bool colOnly); -int64_t queryDbForDumpOutCountWS(char *command, WS_TAOS **taos_v, const char *dbName, const char *tbName, - const int precision); -TAOS_RES *queryDbForDumpOutOffsetWS(WS_TAOS **taos_v, char *command); -int64_t dumpTableDataAvroWS(char *dataFilename, int64_t index, const char *tbName, const bool belongStb, - const char *dbName, const int precision, int colCount, TableDes *tableDes, - int64_t start_time, int64_t end_time); -int64_t fillTbNameArrWS(WS_TAOS **taos_v, char *command, char **tbNameArr, const char *stable, const int64_t preCount); -int readNextTableDesWS(void *ws_res, TableDes *tbDes, int *idx, int *cnt); -void dumpExtraInfoVarWS(void **taos_v, FILE *fp); -int queryDbImplWS(WS_TAOS *taos_v, char *command); -void dumpNormalTablesOfStbWS(threadInfo *pThreadInfo, FILE *fp, char *dumpFilename); -int64_t dumpStbAndChildTbOfDbWS(WS_TAOS **taos_v, SDbInfo *dbInfo, FILE *fpDbs); -int64_t dumpNTablesOfDbWS(WS_TAOS **taos_v, SDbInfo *dbInfo); -int fillDbInfoWS(void **taos_v); -bool jointCloudDsn(); -bool splitCloudDsn(); -int64_t dumpTableDataWS(const int64_t index, FILE *fp, const char *tbName, const char *dbName, const int precision, - TableDes *tableDes, const int64_t start_time, const int64_t end_time); -int32_t readRowWS(void *res, int32_t idx, int32_t col, uint32_t *len, char **data); -#endif - -#endif // INC_WSDUMP_H_ \ No newline at end of file diff --git a/tools/taos-tools/src/CMakeLists.txt b/tools/taos-tools/src/CMakeLists.txt index 320fb1f413..832e0904e8 100644 --- a/tools/taos-tools/src/CMakeLists.txt +++ b/tools/taos-tools/src/CMakeLists.txt @@ -86,6 +86,7 @@ LINK_DIRECTORIES(/usr/lib /usr/lib64) INCLUDE_DIRECTORIES(/usr/local/taos/include) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/../deps/avro/lang/c/src) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/../deps/toolscJson/src) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/../../inc) INCLUDE_DIRECTORIES(${TD_SOURCE_DIR}/contrib/pthread) INCLUDE_DIRECTORIES(${TD_SOURCE_DIR}/contrib/msvcregex) @@ -116,38 +117,18 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin SET_PROPERTY(TARGET snappy PROPERTY IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/build/lib/libsnappy.a") - ADD_EXECUTABLE(taosdump taosdump.c dumpUtil.c wsdump.c toolstime.c toolsSys.c toolsDir.c toolsString.c) + ADD_EXECUTABLE(taosdump taosdump.c ../../src/pub.c dumpUtil.c toolstime.c toolsSys.c toolsDir.c toolsString.c) ADD_DEPENDENCIES(deps-snappy apache-avro) ADD_DEPENDENCIES(taosdump deps-jansson) ADD_DEPENDENCIES(taosdump deps-snappy) - ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c benchUtilDs.c benchSys.c toolstime.c toolsSys.c toolsString.c) + ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c ../../src/pub.c benchUtilDs.c benchSys.c toolstime.c toolsSys.c toolsString.c) ELSE () INCLUDE_DIRECTORIES(/usr/local/include) ADD_DEFINITIONS(-DDARWIN) LINK_DIRECTORIES(/usr/local/lib) SET(OS_ID "Darwin") - ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c benchUtilDs.c benchSys.c toolstime.c toolsSys.c toolsString.c) - ENDIF () - - # websocket - IF (${WEBSOCKET}) - ADD_DEFINITIONS(-DWEBSOCKET) - INCLUDE_DIRECTORIES(/usr/local/include/) - SET(WEBSOCKET_LINK_FLAGS "-ltaosws") - - IF (${CMAKE_PROJECT_NAME} STREQUAL "taos-tools") - MESSAGE("libtaosws.so need to be installed first") - ELSE () - ADD_DEPENDENCIES(taosBenchmark taosws-rs) - IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - ADD_DEPENDENCIES(taosdump taosws-rs) - ELSE () - MESSAGE("TODO: taosdump for macOS is WIP") - ENDIF () - ENDIF () - ELSE () - SET(WEBSOCKET_LINK_FLAGS "") + ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c ../../src/pub.c benchUtilDs.c benchSys.c toolstime.c toolsSys.c toolsString.c) ENDIF () IF (${TOOLS_COVER} MATCHES "true") @@ -191,7 +172,7 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin ENDIF() ELSE () MESSAGE("Compiler is: ${CMAKE_C_COMPILER_ID}, version: ${CMAKE_C_COMPILER_VERSION}") - SET(CMAKE_C_FLAGS "-std=c99 -std=gnu11 -O0 -g3 -DDEBUG ${WEBSOCKET_LINK_FLAGS}") + SET(CMAKE_C_FLAGS "-std=c99 -std=gnu11 -O0 -g3 -DDEBUG ") ENDIF () IF (${OS_ID} MATCHES "alpine") @@ -202,8 +183,8 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin FIND_LIBRARY(LIBZ_LIBRARY z) MESSAGE(${ARGP_LIBRARY}) - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${WEBSOCKET_LINK_FLAGS}) - TARGET_LINK_LIBRARIES(taosdump taos avro jansson atomic pthread m argp $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson atomic pthread m argp $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ) ELSEIF(${OS_ID} MATCHES "Darwin") ADD_LIBRARY(argp STATIC IMPORTED) IF (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") @@ -213,11 +194,11 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin SET_PROPERTY(TARGET argp PROPERTY IMPORTED_LOCATION "/usr/local/lib/libargp.a") INCLUDE_DIRECTORIES(/usr/local/include/) ENDIF () - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson argp ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson argp ) ElSE () MESSAGE("${Yellow} DEBUG mode use shared avro library to link for debug ${ColourReset}") - TARGET_LINK_LIBRARIES(taosdump taos avro jansson atomic pthread m ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson atomic pthread m ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson ${GCC_COVERAGE_LINK_FLAGS}) ENDIF() ELSE () @@ -238,15 +219,6 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin ENDIF () IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # ADD_LIBRARY(jansson STATIC IMPORTED) - #SET_PROPERTY(TARGET jansson PROPERTY IMPORTED_LOCATION "/opt/homebrew/opt/jansson/lib/libjansson.a") - - # ADD_LIBRARY(snappy STATIC IMPORTED) - # SET_PROPERTY(TARGET snappy PROPERTY IMPORTED_LOCATION "/opt/homebrew/opt/snappy/lib/libsnappy.a") - - # ADD_LIBRARY(avro STATIC IMPORTED) - # SET_PROPERTY(TARGET avro PROPERTY IMPORTED_LOCATION "/opt/homebrew/opt/avro-c/lib/libavro.a") - # TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy lzma z pthread) ADD_LIBRARY(argp STATIC IMPORTED) IF (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") SET_PROPERTY(TARGET argp PROPERTY IMPORTED_LOCATION "/opt/homebrew/opt/argp-standalone/lib/libargp.a") @@ -256,7 +228,7 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin INCLUDE_DIRECTORIES(/usr/local/include/) ENDIF () - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson argp ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson argp ) ELSE () EXECUTE_PROCESS ( COMMAND sh -c "awk -F= '/^ID=/{print $2}' /etc/os-release |tr -d '\n' | tr -d '\"'" @@ -307,11 +279,11 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin FIND_LIBRARY(LIBZ_LIBRARY z) MESSAGE(${LIBZ_LIBRARY}) - TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy stdc++ lzma atomic pthread $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy stdc++ lzma atomic pthread $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson $<$:${LIBZ_LIBRARY}> $<$:${ARGP_LIBRARY}> ${GCC_COVERAGE_LINK_FLAGS}) ELSE() - TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy stdc++ lzma libz-static atomic pthread ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) - TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson ${WEBSOCKET_LINK_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy stdc++ lzma libz-static atomic pthread ${GCC_COVERAGE_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos pthread m toolscJson ${GCC_COVERAGE_LINK_FLAGS}) ENDIF() ENDIF () @@ -324,9 +296,9 @@ ELSE () SET(CMAKE_C_STANDARD 11) SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /utf-8") SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /utf-8") - ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c benchUtilDs.c benchSys.c toolstime.c toolsString.c toolsSys.c toolsString.c) + ADD_EXECUTABLE(taosBenchmark benchMain.c benchLog.c benchTmq.c benchQuery.c benchCsv.c benchJsonOpt.c benchInsert.c benchInsertMix.c benchDataMix.c wrapDb.c benchData.c benchCommandOpt.c benchUtil.c ../../src/pub.c benchUtilDs.c benchSys.c toolstime.c toolsString.c toolsSys.c toolsString.c) - ADD_EXECUTABLE(taosdump taosdump.c dumpUtil.c wsdump.c toolsSys.c toolstime.c toolsDir.c toolsString.c) + ADD_EXECUTABLE(taosdump taosdump.c ../../src/pub.c dumpUtil.c toolsSys.c toolstime.c toolsDir.c toolsString.c) ADD_DEPENDENCIES(apache-avro tools-zlib) ADD_DEPENDENCIES(apache-avro deps-jansson) ADD_DEPENDENCIES(apache-avro deps-snappy) @@ -336,19 +308,6 @@ ELSE () ADD_DEPENDENCIES(taosdump apache-avro) ADD_DEPENDENCIES(taosBenchmark tools-zlib) - IF (${WEBSOCKET}) - INCLUDE_DIRECTORIES(/usr/local/include/) - SET(WEBSOCKET_LINK_FLAGS "taosws.lib") - IF (${CMAKE_PROJECT_NAME} STREQUAL "taos-tools") - MESSAGE("taosws.lib need to be installed first") - ELSE () - ADD_DEPENDENCIES(taosBenchmark taosws-rs) - ADD_DEPENDENCIES(taosdump taosws-rs) - ENDIF () - ELSE () - SET(WEBSOCKET_LINK_FLAGS "") - ENDIF () - target_include_directories( taosdump PUBLIC "${TD_SOURCE_DIR}/contrib/pthread" @@ -356,16 +315,12 @@ ELSE () ) IF (${TOOLS_BUILD_TYPE} MATCHES "Debug") - TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy pthread libargp.lib zlib ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy pthread libargp.lib zlib ) ELSE () - #SET(CMAKE_C_FLAGS "/w /D_WIN32 /DWIN32 /Zi /D NDEBUG /MTd") - # SET(CMAKE_C_FLAGS "/permissive- /GS /GL /Gy /Zc:wchar_t /Zi /Gm- /O2 /Zc:inline /fp:precise /D \"RELEASE\" /D \"NDEBUG\" /D \"_CONSOLE\" /D \"_UNICODE\" /D \"UNICODE\" /errorReport:prompt /Zc:forScope /Gd /Oi /MTd /FC /EHsc /nologo /diagnostics:column") - # SET(CMAKE_CXX_FLAGS "/permissive- /GS /GL /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise /D \"NDEBUG\" /D \"_CONSOLE\" /D \"_UNICODE\" /D \"UNICODE\" /errorReport:prompt /Zc:forScope /Gd /Oi /MTd /FC /EHsc /nologo /diagnostics:column") - #TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy pthread libargp.lib zlibstatic ${WEBSOCKET_LINK_FLAGS} msvcrt.lib ucrtd.lib) - TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy pthread libargp.lib zlibstatic ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosdump taos avro jansson snappy pthread libargp.lib zlibstatic ) ENDIF () - TARGET_LINK_LIBRARIES(taosBenchmark taos msvcregex pthread toolscJson ${WEBSOCKET_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(taosBenchmark taos msvcregex pthread toolscJson ) TARGET_LINK_LIBRARIES(taosBenchmark zlibstatic) diff --git a/tools/taos-tools/src/benchCommandOpt.c b/tools/taos-tools/src/benchCommandOpt.c index e2bb3129e1..65194ea02e 100644 --- a/tools/taos-tools/src/benchCommandOpt.c +++ b/tools/taos-tools/src/benchCommandOpt.c @@ -210,13 +210,11 @@ void initArgument() { g_arguments->test_mode = INSERT_TEST; g_arguments->demo_mode = true; g_arguments->host = NULL; - g_arguments->host_auto = true; - g_arguments->port = DEFAULT_PORT; + g_arguments->port = 0; g_arguments->port_inputted = false; - g_arguments->port_auto = true; g_arguments->telnet_tcp_port = TELNET_TCP_PORT; - g_arguments->user = TSDB_DEFAULT_USER; - g_arguments->password = TSDB_DEFAULT_PASS; + g_arguments->user = NULL; + g_arguments->password = NULL; g_arguments->answer_yes = 0; g_arguments->debug_print = 0; g_arguments->binwidth = DEFAULT_BINWIDTH; @@ -233,9 +231,6 @@ void initArgument() { g_arguments->chinese = false; g_arguments->aggr_func = 0; g_arguments->terminate = false; -#ifdef WEBSOCKET - g_arguments->timeout = 10; -#endif g_arguments->supplementInsert = false; g_arguments->startTimestamp = DEFAULT_START_TIME; @@ -244,10 +239,10 @@ void initArgument() { g_arguments->keep_trying = 0; g_arguments->trying_interval = 0; g_arguments->iface = TAOSC_IFACE; - g_arguments->rest_server_ver_major = -1; g_arguments->inputted_vgroups = -1; g_arguments->mistMode = false; + g_arguments->connMode = CONN_MODE_INVALID; initDatabase(); initStable(); @@ -257,29 +252,6 @@ void initArgument() { void modifyArgument() { SDataBase * database = benchArrayGet(g_arguments->databases, 0); SSuperTable *superTable = benchArrayGet(database->superTbls, 0); -#ifdef WEBSOCKET - if (!g_arguments->websocket) { -#endif - if (strlen(g_configDir) - && g_arguments->host_auto - && g_arguments->port_auto) { -#ifdef LINUX - wordexp_t full_path; - if (wordexp(g_configDir, &full_path, 0) != 0) { - errorPrint("Invalid path %s\n", g_configDir); - exit(EXIT_FAILURE); - } - taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); - wordfree(&full_path); -#else - taos_options(TSDB_OPTION_CONFIGDIR, g_configDir); -#endif - g_arguments->host = DEFAULT_HOST; - g_arguments->port = 0; - } -#ifdef WEBSOCKET - } -#endif superTable->startTimestamp = g_arguments->startTimestamp; @@ -332,10 +304,7 @@ void modifyArgument() { static void *queryStableAggrFunc(void *sarg) { threadInfo *pThreadInfo = (threadInfo *)sarg; - TAOS *taos = NULL; - if (REST_IFACE != g_arguments->iface) { - taos = pThreadInfo->conn->taos; - } + TAOS *taos = taos = pThreadInfo->conn->taos; #ifdef LINUX prctl(PR_SET_NAME, "queryStableAggrFunc"); #endif @@ -391,24 +360,18 @@ static void *queryStableAggrFunc(void *sarg) { } double t = (double)toolsGetTimestampUs(); int32_t code = -1; - if (REST_IFACE == g_arguments->iface) { - code = postProceSql(command, NULL, 0, REST_IFACE, - 0, g_arguments->port, 0, - pThreadInfo->sockfd, NULL); - } else { - TAOS_RES *res = taos_query(taos, command); - code = taos_errno(res); - if (code != 0) { - printErrCmdCodeStr(command, code, res); - free(command); - return NULL; - } - int count = 0; - while (taos_fetch_row(res) != NULL) { - count++; - } - taos_free_result(res); + TAOS_RES *res = taos_query(taos, command); + code = taos_errno(res); + if (code != 0) { + printErrCmdCodeStr(command, code, res); + free(command); + return NULL; } + int count = 0; + while (taos_fetch_row(res) != NULL) { + count++; + } + taos_free_result(res); t = toolsGetTimestampUs() - t; if (fp) { fprintf(fp, "| Speed: %12.2f(per s) | Latency: %.4f(ms) |\n", @@ -469,23 +432,17 @@ static void *queryNtableAggrFunc(void *sarg) { (uint64_t) DEFAULT_START_TIME); double t = (double)toolsGetTimestampUs(); int32_t code = -1; - if (REST_IFACE == g_arguments->iface) { - code = postProceSql(command, NULL, 0, REST_IFACE, - 0, g_arguments->port, 0, - pThreadInfo->sockfd, NULL); - } else { - TAOS_RES *res = taos_query(taos, command); - code = taos_errno(res); - if (code != 0) { - printErrCmdCodeStr(command, code, res); - free(command); - return NULL; - } - while (taos_fetch_row(res) != NULL) { - count++; - } - taos_free_result(res); + TAOS_RES *res = taos_query(taos, command); + code = taos_errno(res); + if (code != 0) { + printErrCmdCodeStr(command, code, res); + free(command); + return NULL; } + while (taos_fetch_row(res) != NULL) { + count++; + } + taos_free_result(res); t = toolsGetTimestampUs() - t; totalT += t; @@ -524,19 +481,11 @@ void queryAggrFunc() { return; } - if (REST_IFACE != g_arguments->iface) { - pThreadInfo->conn = initBenchConn(); - if (pThreadInfo->conn == NULL) { - errorPrint("%s() failed to init connection\n", __func__); - free(pThreadInfo); - return; - } - } else { - pThreadInfo->sockfd = createSockFd(); - if (pThreadInfo->sockfd < 0) { - free(pThreadInfo); - return; - } + pThreadInfo->conn = initBenchConn(); + if (pThreadInfo->conn == NULL) { + errorPrint("%s() failed to init connection\n", __func__); + free(pThreadInfo); + return; } if (stbInfo->use_metric) { pthread_create(&read_id, NULL, queryStableAggrFunc, pThreadInfo); @@ -544,12 +493,7 @@ void queryAggrFunc() { pthread_create(&read_id, NULL, queryNtableAggrFunc, pThreadInfo); } pthread_join(read_id, NULL); - if (REST_IFACE != g_arguments->iface) { - closeBenchConn(pThreadInfo->conn); - } else { - if (pThreadInfo->sockfd) { - destroySockFd(pThreadInfo->sockfd); - } - } + + closeBenchConn(pThreadInfo->conn); free(pThreadInfo); } diff --git a/tools/taos-tools/src/benchData.c b/tools/taos-tools/src/benchData.c index 0925d1002c..1a49c7f75c 100644 --- a/tools/taos-tools/src/benchData.c +++ b/tools/taos-tools/src/benchData.c @@ -229,12 +229,13 @@ void rand_string(char *str, int size, bool chinese) { } // generate prepare sql -char* genPrepareSql(SSuperTable *stbInfo, char* tagData, uint64_t tableSeq) { +char* genPrepareSql(SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char *db) { int len = 0; char *prepare = benchCalloc(1, TSDB_MAX_ALLOWED_SQL_LEN, true); int n; char *tagQ = NULL; char *colQ = genQMark(stbInfo->cols->size); + char *colNames = NULL; bool tagQFree = false; if(tagData == NULL) { @@ -252,19 +253,30 @@ char* genPrepareSql(SSuperTable *stbInfo, char* tagData, uint64_t tableSeq) { } n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, - "INSERT INTO ? USING `%s` TAGS (%s) %s VALUES(?,%s)", - stbInfo->stbName, tagQ, ttl, colQ); + "INSERT INTO ? USING `%s`.`%s` TAGS (%s) %s VALUES(?,%s)", + db, stbInfo->stbName, tagQ, ttl, colQ); } else { - n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, - "INSERT INTO ? VALUES(?,%s)", colQ); + if (g_arguments->connMode == CONN_MODE_NATIVE) { + // native + n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, + "INSERT INTO ? VALUES(?,%s)", colQ); + } else { + // websocket + bool ntb = stbInfo->tags == NULL || stbInfo->tags->size == 0; // nomral table + colNames = genColNames(stbInfo->cols, !ntb); + n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, + "INSERT INTO `%s`.`%s`(%s) VALUES(%s,%s)", db, stbInfo->stbName, colNames, + ntb ? "?" : "?,?", colQ); + } } len += n; - // free from genQMark - if(tagQFree) { + // free + if (tagQFree) { tmfree(tagQ); } tmfree(colQ); + tmfree(colNames); // check valid if (g_arguments->prepared_rand < g_arguments->reqPerReq) { @@ -281,19 +293,20 @@ char* genPrepareSql(SSuperTable *stbInfo, char* tagData, uint64_t tableSeq) { return prepare; } -int prepareStmt(TAOS_STMT *stmt, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq) { - char *prepare = genPrepareSql(stbInfo, tagData, tableSeq); +int prepareStmt(TAOS_STMT *stmt, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char *db) { + char *prepare = genPrepareSql(stbInfo, tagData, tableSeq, db); if (taos_stmt_prepare(stmt, prepare, strlen(prepare))) { errorPrint("taos_stmt_prepare(%s) failed. errstr=%s\n", prepare, taos_stmt_errstr(stmt)); tmfree(prepare); return -1; } + debugPrint("succ call taos_stmt_prepare sql:%s\n", prepare); tmfree(prepare); return 0; } -int prepareStmt2(TAOS_STMT2 *stmt2, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq) { - char *prepare = genPrepareSql(stbInfo, tagData, tableSeq); +int prepareStmt2(TAOS_STMT2 *stmt2, SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char *db) { + char *prepare = genPrepareSql(stbInfo, tagData, tableSeq, db); if (taos_stmt2_prepare(stmt2, prepare, strlen(prepare))) { errorPrint("taos_stmt2_prepare(%s) failed. errstr=%s\n", prepare, taos_stmt2_error(stmt2)); tmfree(prepare); @@ -469,11 +482,11 @@ uint32_t accumulateRowLen(BArray *fields, int iface) { return len; } len += 1; - if (iface == SML_REST_IFACE || iface == SML_IFACE) { + if (iface == SML_IFACE) { len += SML_LINE_SQL_SYNTAX_OFFSET + strlen(field->name); } } - if (iface == SML_IFACE || iface == SML_REST_IFACE) { + if (iface == SML_IFACE) { len += 2 * TSDB_TABLE_NAME_LEN * 2 + SML_LINE_SQL_SYNTAX_OFFSET; } len += TIMESTAMP_BUFF_LEN; @@ -1802,7 +1815,6 @@ int generateRandData(SSuperTable *stbInfo, char *sampleDataBuf, int iface = stbInfo->iface; switch (iface) { case TAOSC_IFACE: - case REST_IFACE: return generateRandDataSQL(stbInfo, sampleDataBuf, bufLen, lenOfOneRow, fields, loop, tag); case STMT_IFACE: @@ -1817,7 +1829,6 @@ int generateRandData(SSuperTable *stbInfo, char *sampleDataBuf, bufLen, lenOfOneRow, fields, loop, tag); } case SML_IFACE: - case SML_REST_IFACE: return generateRandDataSml(stbInfo, sampleDataBuf, bufLen, lenOfOneRow, fields, loop, tag); default: @@ -1843,8 +1854,7 @@ int prepareSampleData(SDataBase* database, SSuperTable* stbInfo) { stbInfo->lenOfCols = accumulateRowLen(stbInfo->cols, stbInfo->iface); stbInfo->lenOfTags = accumulateRowLen(stbInfo->tags, stbInfo->iface); if (stbInfo->partialColNum != 0 - && ((stbInfo->iface == TAOSC_IFACE - || stbInfo->iface == REST_IFACE))) { + && stbInfo->iface == TAOSC_IFACE) { // check valid if(stbInfo->partialColFrom >= stbInfo->cols->size) { stbInfo->partialColFrom = 0; @@ -2003,12 +2013,6 @@ int prepareSampleData(SDataBase* database, SSuperTable* stbInfo) { } } - if (0 != convertServAddr( - stbInfo->iface, - stbInfo->tcpTransfer, - stbInfo->lineProtocol)) { - return -1; - } return 0; } diff --git a/tools/taos-tools/src/benchInsert.c b/tools/taos-tools/src/benchInsert.c index 6108f4990c..af084e482d 100644 --- a/tools/taos-tools/src/benchInsert.c +++ b/tools/taos-tools/src/benchInsert.c @@ -39,32 +39,6 @@ TAOS_STMT2* initStmt2(TAOS* taos, bool single); tmfree(infos); \ } while (0) \ -static int getSuperTableFromServerRest( - SDataBase* database, SSuperTable* stbInfo, char *command) { - - // TODO(zero): it will create super table based on this error code. - return TSDB_CODE_NOT_FOUND; - // TODO(me): finish full implementation -#if 0 - int sockfd = createSockFd(); - if (sockfd < 0) { - return -1; - } - - int code = postProceSql(command, - database->dbName, - database->precision, - REST_IFACE, - 0, - g_arguments->port, - false, - sockfd, - NULL); - - destroySockFd(sockfd); -#endif // 0 -} - static int getSuperTableFromServerTaosc( SDataBase *database, SSuperTable *stbInfo, char *command) { TAOS_RES *res; @@ -161,90 +135,41 @@ static int getSuperTableFromServerTaosc( static int getSuperTableFromServer(SDataBase* database, SSuperTable* stbInfo) { -#ifdef WEBSOCKET - if (g_arguments->websocket) { - return 0; - } -#endif - int ret = 0; char command[SHORT_1K_SQL_BUFF_LEN] = "\0"; snprintf(command, SHORT_1K_SQL_BUFF_LEN, "DESCRIBE `%s`.`%s`", database->dbName, stbInfo->stbName); - if (REST_IFACE == stbInfo->iface) { - ret = getSuperTableFromServerRest(database, stbInfo, command); - } else { - ret = getSuperTableFromServerTaosc(database, stbInfo, command); - } - - return ret; + return getSuperTableFromServerTaosc(database, stbInfo, command); } static int queryDbExec(SDataBase *database, SSuperTable *stbInfo, char *command) { int ret = 0; - if (isRest(stbInfo->iface)) { - if (0 != convertServAddr(stbInfo->iface, false, 1)) { - errorPrint("%s", "Failed to convert server address\n"); - return -1; - } - int sockfd = createSockFd(); - if (sockfd < 0) { - ret = -1; - } else { - ret = queryDbExecRest(command, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - stbInfo->tcpTransfer, - sockfd); - destroySockFd(sockfd); - } + SBenchConn* conn = initBenchConn(); + if (NULL == conn) { + ret = -1; } else { - SBenchConn* conn = initBenchConn(); - if (NULL == conn) { - ret = -1; - } else { + ret = queryDbExecCall(conn, command); + int32_t trying = g_arguments->keep_trying; + while (ret && trying) { + infoPrint("will sleep %"PRIu32" milliseconds then re-execute command: %s\n", + g_arguments->trying_interval, command); + toolsMsleep(g_arguments->trying_interval); ret = queryDbExecCall(conn, command); - int32_t trying = g_arguments->keep_trying; - while (ret && trying) { - infoPrint("will sleep %"PRIu32" milliseconds then re-execute command: %s\n", - g_arguments->trying_interval, command); - toolsMsleep(g_arguments->trying_interval); - ret = queryDbExecCall(conn, command); - if (trying != -1) { - trying--; - } + if (trying != -1) { + trying--; } - if (0 != ret) { - ret = -1; - } - closeBenchConn(conn); } + if (0 != ret) { + ret = -1; + } + closeBenchConn(conn); } return ret; } -#ifdef WEBSOCKET -static void dropSuperTable(SDataBase* database, SSuperTable* stbInfo) { - char command[SHORT_1K_SQL_BUFF_LEN] = "\0"; - snprintf(command, sizeof(command), - g_arguments->escape_character - ? "DROP TABLE IF EXISTS `%s`.`%s`" - : "DROP TABLE IF EXISTS %s.%s", - database->dbName, - stbInfo->stbName); - - infoPrint("drop stable: <%s>\n", command); - queryDbExec(database, stbInfo, command); - - return; -} -#endif // WEBSOCKET - int getCompressStr(Field* col, char* buf) { int pos = 0; if(strlen(col->encode) > 0) { @@ -521,80 +446,6 @@ int32_t getVgroupsNative(SBenchConn *conn, SDataBase *database) { return vgroups; } -#ifdef WEBSOCKET -int32_t getVgroupsWS(SBenchConn *conn, SDataBase *database) { - int vgroups = 0; - char sql[128] = "\0"; - snprintf(sql, sizeof(sql), - g_arguments->escape_character - ? "SHOW `%s`.VGROUPS" - : "SHOW %s.VGROUPS", - database->dbName); - - // query - WS_RES *res = ws_query_timeout(conn->taos_ws, sql, g_arguments->timeout); - int32_t code = ws_errno(res); - if (code != 0) { - // failed - errorPrint("Failed ws_query_timeout <%s>, code: 0x%08x, reason: %s\n", - sql, code, ws_errstr(res)); - ws_free_result(res); - return 0; - } - - // fetch - WS_ROW row; - database->vgArray = benchArrayInit(8, sizeof(SVGroup)); - while ( (row = ws_fetch_row(res)) && !g_arguments->terminate) { - SVGroup *vg = benchCalloc(1, sizeof(SVGroup), true); - vg->vgId = *(int32_t *)row[0]; - benchArrayPush(database->vgArray, vg); - vgroups++; - debugPrint(" ws fetch vgroups vgid=%d cnt=%d \n", vg->vgId, vgroups); - } - ws_free_result(res); - database->vgroups = vgroups; - - // return count - return vgroups; -} - -/* -int32_t getTableVgidWS(SBenchConn *conn, char *db, char *tb, int32_t *vgId) { - char sql[128] = "\0"; - snprintf(sql, sizeof(sql), - "select vgroup_id from information_schema.ins_tables where db_name='%s' and table_name='%s';", - db, tb); - // query - WS_RES *res = ws_query_timeout(conn->taos_ws, sql, g_arguments->timeout); - int32_t code = ws_errno(res); - if (code != 0) { - // failed - errorPrint("Failed ws_query_timeout <%s>, code: 0x%08x, reason: %s\n", - sql, code, ws_errstr(res)); - ws_free_result(res); - return code; - } - - // fetch - WS_ROW row; - while ( (row = ws_fetch_row(res)) && !g_arguments->terminate) { - *vgId = *(int32_t *)row[0]; - debugPrint(" getTableVgidWS table:%s vgid=%d\n", tb, *vgId); - break; - } - ws_free_result(res); - - if(*vgId == 0) { - return -1; - } else { - return 0; - } -} -*/ - -#endif - int32_t toolsGetDefaultVGroups() { int32_t cores = toolsGetNumberOfCores(); if (cores < 3 ) { @@ -616,6 +467,7 @@ int32_t toolsGetDefaultVGroups() { } } + int geneDbCreateCmd(SDataBase *database, char *command, int remainVnodes) { int dataLen = 0; int n; @@ -701,70 +553,6 @@ int geneDbCreateCmd(SDataBase *database, char *command, int remainVnodes) { return dataLen; } -int createDatabaseRest(SDataBase* database) { - int32_t code = 0; - char command[SHORT_1K_SQL_BUFF_LEN] = "\0"; - - int sockfd = createSockFd(); - if (sockfd < 0) { - return -1; - } - - // drop exist database - snprintf(command, SHORT_1K_SQL_BUFF_LEN, - g_arguments->escape_character - ? "DROP DATABASE IF EXISTS `%s`;" - : "DROP DATABASE IF EXISTS %s;", - database->dbName); - code = postProceSql(command, - database->dbName, - database->precision, - REST_IFACE, - 0, - g_arguments->port, - false, - sockfd, - NULL); - if (code != 0) { - errorPrint("Failed to drop database %s\n", database->dbName); - } - - // create database - int remainVnodes = INT_MAX; - geneDbCreateCmd(database, command, remainVnodes); - code = postProceSql(command, - database->dbName, - database->precision, - REST_IFACE, - 0, - g_arguments->port, - false, - sockfd, - NULL); - int32_t trying = g_arguments->keep_trying; - while (code && trying) { - infoPrint("will sleep %"PRIu32" milliseconds then " - "re-create database %s\n", - g_arguments->trying_interval, database->dbName); - toolsMsleep(g_arguments->trying_interval); - code = postProceSql(command, - database->dbName, - database->precision, - REST_IFACE, - 0, - g_arguments->port, - false, - sockfd, - NULL); - if (trying != -1) { - trying--; - } - } - - destroySockFd(sockfd); - return code; -} - int32_t getRemainVnodes(SBenchConn *conn) { int remainVnodes = 0; char command[SHORT_1K_SQL_BUFF_LEN] = "SHOW DNODES"; @@ -786,7 +574,7 @@ int32_t getRemainVnodes(SBenchConn *conn) { return remainVnodes; } -int createDatabaseTaosc(SDataBase* database) { +int createDatabase(SDataBase* database) { char command[SHORT_1K_SQL_BUFF_LEN] = "\0"; // conn SBenchConn* conn = initBenchConn(); @@ -817,22 +605,17 @@ int createDatabaseTaosc(SDataBase* database) { "DROP DATABASE IF EXISTS %s;", database->dbName); if (0 != queryDbExecCall(conn, command)) { -#ifdef WEBSOCKET - if (g_arguments->websocket) { + if (g_arguments->dsn) { + // websocket warnPrint("%s", "TDengine cloud normal users have no privilege " "to drop database! DROP DATABASE failure is ignored!\n"); - } else { -#endif - closeBenchConn(conn); - return -1; -#ifdef WEBSOCKET } -#endif + closeBenchConn(conn); + return -1; } // get remain vgroups int remainVnodes = INT_MAX; -#ifndef WEBSOCKET if (g_arguments->bind_vgroup) { remainVnodes = getRemainVnodes(conn); if (0 >= remainVnodes) { @@ -841,7 +624,6 @@ int createDatabaseTaosc(SDataBase* database) { return -1; } } -#endif // generate and execute create database sql geneDbCreateCmd(database, command, remainVnodes); @@ -859,21 +641,15 @@ int createDatabaseTaosc(SDataBase* database) { } if (code) { -#ifdef WEBSOCKET - if (g_arguments->websocket) { + if (g_arguments->dsn) { warnPrint("%s", "TDengine cloud normal users have no privilege " "to create database! CREATE DATABASE " "failure is ignored!\n"); - } else { -#endif + } - closeBenchConn(conn); - errorPrint("\ncreate database %s failed!\n\n", - database->dbName); - return -1; -#ifdef WEBSOCKET - } -#endif + closeBenchConn(conn); + errorPrint("\ncreate database %s failed!\n\n", database->dbName); + return -1; } infoPrint("command to create database: <%s>\n", command); @@ -881,15 +657,7 @@ int createDatabaseTaosc(SDataBase* database) { // malloc and get vgroup if (g_arguments->bind_vgroup) { int32_t vgroups; -#ifdef WEBSOCKET - if (g_arguments->websocket) { - vgroups = getVgroupsWS(conn, database); - } else { -#endif - vgroups = getVgroupsNative(conn, database); -#ifdef WEBSOCKET - } -#endif + vgroups = getVgroupsNative(conn, database); if (vgroups <= 0) { closeBenchConn(conn); errorPrint("Database %s's vgroups is %d\n", @@ -902,28 +670,6 @@ int createDatabaseTaosc(SDataBase* database) { return 0; } -int createDatabase(SDataBase* database) { - int ret = 0; - if (REST_IFACE == g_arguments->iface || SML_REST_IFACE == g_arguments->iface) { - ret = createDatabaseRest(database); - } else { - ret = createDatabaseTaosc(database); - } -#if 0 -#ifdef LINUX - infoPrint("%s() LN%d, ret: %d\n", __func__, __LINE__, ret); - sleep(10); - infoPrint("%s() LN%d, ret: %d\n", __func__, __LINE__, ret); -#elif defined(DARWIN) - sleep(2); -#else - Sleep(2); -#endif -#endif - - return ret; -} - static int generateChildTblName(int len, char *buffer, SDataBase *database, SSuperTable *stbInfo, uint64_t tableSeq, char* tagData, int i, char *ttl) { @@ -1072,26 +818,16 @@ static void *createTable(void *sarg) { int ret = 0; debugPrint("thread[%d] creating table: %s\n", pThreadInfo->threadID, pThreadInfo->buffer); - if (REST_IFACE == stbInfo->iface) { - ret = queryDbExecRest(pThreadInfo->buffer, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - stbInfo->tcpTransfer, - pThreadInfo->sockfd); - } else { + ret = queryDbExecCall(pThreadInfo->conn, pThreadInfo->buffer); + int32_t trying = g_arguments->keep_trying; + while (ret && trying) { + infoPrint("will sleep %"PRIu32" milliseconds then re-create " + "table %s\n", + g_arguments->trying_interval, pThreadInfo->buffer); + toolsMsleep(g_arguments->trying_interval); ret = queryDbExecCall(pThreadInfo->conn, pThreadInfo->buffer); - int32_t trying = g_arguments->keep_trying; - while (ret && trying) { - infoPrint("will sleep %"PRIu32" milliseconds then re-create " - "table %s\n", - g_arguments->trying_interval, pThreadInfo->buffer); - toolsMsleep(g_arguments->trying_interval); - ret = queryDbExecCall(pThreadInfo->conn, pThreadInfo->buffer); - if (trying != -1) { - trying--; - } + if (trying != -1) { + trying--; } } @@ -1123,17 +859,7 @@ static void *createTable(void *sarg) { int ret = 0; debugPrint("thread[%d] creating table: %s\n", pThreadInfo->threadID, pThreadInfo->buffer); - if (REST_IFACE == stbInfo->iface) { - ret = queryDbExecRest(pThreadInfo->buffer, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - stbInfo->tcpTransfer, - pThreadInfo->sockfd); - } else { - ret = queryDbExecCall(pThreadInfo->conn, pThreadInfo->buffer); - } + ret = queryDbExecCall(pThreadInfo->conn, pThreadInfo->buffer); if (0 != ret) { g_fail = true; goto create_table_end; @@ -1188,17 +914,9 @@ static int startMultiThreadCreateChildTable(SDataBase* database, SSuperTable* st pThreadInfo->threadID = i; pThreadInfo->stbInfo = stbInfo; pThreadInfo->dbInfo = database; - if (REST_IFACE == stbInfo->iface) { - int sockfd = createSockFd(); - if (sockfd < 0) { - FREE_PIDS_INFOS_RETURN_MINUS_1(); - } - pThreadInfo->sockfd = sockfd; - } else { - pThreadInfo->conn = initBenchConn(); - if (NULL == pThreadInfo->conn) { - goto over; - } + pThreadInfo->conn = initBenchConn(); + if (NULL == pThreadInfo->conn) { + goto over; } pThreadInfo->start_table_from = tableFrom; pThreadInfo->ntables = i < mod ? div + 1 : div; @@ -1221,7 +939,7 @@ static int startMultiThreadCreateChildTable(SDataBase* database, SSuperTable* st threadInfo *pThreadInfo = infos + i; g_arguments->actualChildTables += pThreadInfo->tables_created; - if ((REST_IFACE != stbInfo->iface) && pThreadInfo->conn) { + if (pThreadInfo->conn) { closeBenchConn(pThreadInfo->conn); } } @@ -1254,8 +972,7 @@ static int createChildTables() { for (int j = 0; (j < database->superTbls->size && !g_arguments->terminate); j++) { SSuperTable * stbInfo = benchArrayGet(database->superTbls, j); - if (stbInfo->autoTblCreating || stbInfo->iface == SML_IFACE - || stbInfo->iface == SML_REST_IFACE) { + if (stbInfo->autoTblCreating || stbInfo->iface == SML_IFACE) { g_arguments->autoCreatedChildTables += stbInfo->childTblCount; continue; @@ -1441,37 +1158,6 @@ int32_t execInsert(threadInfo *pThreadInfo, uint32_t k, int64_t *delay3) { } } break; - - case REST_IFACE: - debugPrint("buffer: %s\n", pThreadInfo->buffer); - code = postProceSql(pThreadInfo->buffer, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - g_arguments->port, - stbInfo->tcpTransfer, - pThreadInfo->sockfd, - pThreadInfo->filePath); - while (code && trying && !g_arguments->terminate) { - infoPrint("will sleep %"PRIu32" milliseconds then re-insert\n", - trying_interval); - toolsMsleep(trying_interval); - code = postProceSql(pThreadInfo->buffer, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - g_arguments->port, - stbInfo->tcpTransfer, - pThreadInfo->sockfd, - pThreadInfo->filePath); - if (trying != -1) { - trying--; - } - } - break; - case STMT_IFACE: // add batch if(!stbInfo->autoTblCreating) { @@ -1552,54 +1238,6 @@ int32_t execInsert(threadInfo *pThreadInfo, uint32_t k, int64_t *delay3) { } taos_free_result(res); break; - - case SML_REST_IFACE: { - if (TSDB_SML_JSON_PROTOCOL == protocol - || SML_JSON_TAOS_FORMAT == protocol) { - code = postProceSql(pThreadInfo->lines[0], database->dbName, - database->precision, stbInfo->iface, - protocol, g_arguments->port, - stbInfo->tcpTransfer, - pThreadInfo->sockfd, pThreadInfo->filePath); - } else { - int len = 0; - for (int i = 0; i < k; i++) { - if (strlen(pThreadInfo->lines[i]) != 0) { - int n; - if (TSDB_SML_TELNET_PROTOCOL == protocol - && stbInfo->tcpTransfer) { - n = snprintf(pThreadInfo->buffer + len, - TSDB_MAX_ALLOWED_SQL_LEN - len, - "put %s\n", pThreadInfo->lines[i]); - } else { - n = snprintf(pThreadInfo->buffer + len, - TSDB_MAX_ALLOWED_SQL_LEN - len, - "%s\n", - pThreadInfo->lines[i]); - } - if (n < 0 || n >= TSDB_MAX_ALLOWED_SQL_LEN - len) { - errorPrint("%s() LN%d snprintf overflow on %d\n", - __func__, __LINE__, i); - break; - } else { - len += n; - } - } else { - break; - } - } - if (g_arguments->terminate) { - break; - } - code = postProceSql(pThreadInfo->buffer, database->dbName, - database->precision, - stbInfo->iface, protocol, - g_arguments->port, - stbInfo->tcpTransfer, - pThreadInfo->sockfd, pThreadInfo->filePath); - } - break; - } } return code; } @@ -1622,29 +1260,20 @@ static int smartContinueIfFail(threadInfo *pThreadInfo, stbInfo->stbName, tagData + i * stbInfo->lenOfTags, ttl); debugPrint("creating table: %s\n", buffer); - int ret; - if (REST_IFACE == stbInfo->iface) { - ret = queryDbExecRest(buffer, - database->dbName, - database->precision, - stbInfo->iface, - stbInfo->lineProtocol, - stbInfo->tcpTransfer, - pThreadInfo->sockfd); - } else { + + int32_t ret = queryDbExecCall(pThreadInfo->conn, buffer); + int32_t trying = g_arguments->keep_trying; + while (ret && trying) { + infoPrint("will sleep %"PRIu32" milliseconds then " + "re-create table %s\n", + g_arguments->trying_interval, buffer); + toolsMsleep(g_arguments->trying_interval); ret = queryDbExecCall(pThreadInfo->conn, buffer); - int32_t trying = g_arguments->keep_trying; - while (ret && trying) { - infoPrint("will sleep %"PRIu32" milliseconds then " - "re-create table %s\n", - g_arguments->trying_interval, buffer); - toolsMsleep(g_arguments->trying_interval); - ret = queryDbExecCall(pThreadInfo->conn, buffer); - if (trying != -1) { - trying--; - } + if (trying != -1) { + trying--; } } + tmfree(buffer); return ret; @@ -1791,7 +1420,7 @@ int32_t reConnectStmt2(threadInfo * pThreadInfo, int32_t w) { } // prepare - code = prepareStmt2(pThreadInfo->conn->stmt2, pThreadInfo->stbInfo, NULL, w); + code = prepareStmt2(pThreadInfo->conn->stmt2, pThreadInfo->stbInfo, NULL, w, pThreadInfo->dbInfo->dbName); if (code != 0) { return code; } @@ -1932,14 +1561,14 @@ static void *syncWriteInterlace(void *sarg) { // not auto create table call once if(stbInfo->iface == STMT_IFACE && !oldInitStmt) { debugPrint("call prepareStmt for stable:%s\n", stbInfo->stbName); - if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w)) { + if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_interlace; } } else if (stbInfo->iface == STMT2_IFACE) { // only prepare once - if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, NULL, w)) { + if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, NULL, w, database->dbName)) { g_fail = true; goto free_of_interlace; } @@ -1980,7 +1609,6 @@ static void *syncWriteInterlace(void *sarg) { snprintf(ttl, SMALL_BUFF_LEN, "TTL %d", stbInfo->ttl); } switch (stbInfo->iface) { - case REST_IFACE: case TAOSC_IFACE: { char escapedTbName[TSDB_TABLE_NAME_LEN+2] = "\0"; if (g_arguments->escape_character) { @@ -2123,7 +1751,7 @@ static void *syncWriteInterlace(void *sarg) { // old must call prepareStmt for each table if (oldInitStmt) { debugPrint("call prepareStmt for stable:%s\n", stbInfo->stbName); - if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w)) { + if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_interlace; } @@ -2208,7 +1836,6 @@ static void *syncWriteInterlace(void *sarg) { break; } - case SML_REST_IFACE: case SML_IFACE: { int protocol = stbInfo->lineProtocol; for (int64_t j = 0; j < interlaceRows; j++) { @@ -2341,15 +1968,11 @@ static void *syncWriteInterlace(void *sarg) { int protocol = stbInfo->lineProtocol; switch (stbInfo->iface) { case TAOSC_IFACE: - case REST_IFACE: debugPrint("pThreadInfo->buffer: %s\n", pThreadInfo->buffer); free_ds(&pThreadInfo->buffer); pThreadInfo->buffer = new_ds(0); break; - case SML_REST_IFACE: - memset(pThreadInfo->buffer, 0, - g_arguments->reqPerReq * (pThreadInfo->max_sql_len + 1)); case SML_IFACE: if (TSDB_SML_JSON_PROTOCOL == protocol || SML_JSON_TAOS_FORMAT == protocol) { @@ -2893,7 +2516,7 @@ void *syncWriteProgressive(void *sarg) { char* tagData = NULL; bool stmt = (stbInfo->iface == STMT_IFACE || stbInfo->iface == STMT2_IFACE) && stbInfo->autoTblCreating; bool smart = SMART_IF_FAILED == stbInfo->continueIfFail; - bool acreate = (stbInfo->iface == TAOSC_IFACE || stbInfo->iface == REST_IFACE) && stbInfo->autoTblCreating; + bool acreate = stbInfo->iface == TAOSC_IFACE && stbInfo->autoTblCreating; int w = 0; if (stmt || smart || acreate) { csvFile = openTagCsv(stbInfo); @@ -2903,13 +2526,13 @@ void *syncWriteProgressive(void *sarg) { bool oldInitStmt = stbInfo->autoTblCreating; // stmt. not auto table create call on stmt if (stbInfo->iface == STMT_IFACE && !oldInitStmt) { - if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w)) { + if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_progressive; } } else if (stbInfo->iface == STMT2_IFACE && !stbInfo->autoTblCreating) { - if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, tagData, w)) { + if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_progressive; } @@ -2957,13 +2580,13 @@ void *syncWriteProgressive(void *sarg) { // old init stmt must call for each table if (stbInfo->iface == STMT_IFACE && oldInitStmt) { - if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w)) { + if (prepareStmt(pThreadInfo->conn->stmt, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_progressive; } } else if (stbInfo->iface == STMT2_IFACE && stbInfo->autoTblCreating) { - if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, tagData, w)) { + if (prepareStmt2(pThreadInfo->conn->stmt2, stbInfo, tagData, w, database->dbName)) { g_fail = true; goto free_of_progressive; } @@ -2988,7 +2611,6 @@ void *syncWriteProgressive(void *sarg) { int32_t generated = 0; switch (stbInfo->iface) { case TAOSC_IFACE: - case REST_IFACE: generated = prepareProgressDataSql( pThreadInfo, childTbl, @@ -3010,7 +2632,6 @@ void *syncWriteProgressive(void *sarg) { &delay3, &startTs, &endTs, w); break; } - case SML_REST_IFACE: case SML_IFACE: generated = prepareProgressDataSml( pThreadInfo, @@ -3116,14 +2737,9 @@ void *syncWriteProgressive(void *sarg) { } int protocol = stbInfo->lineProtocol; switch (stbInfo->iface) { - case REST_IFACE: case TAOSC_IFACE: memset(pThreadInfo->buffer, 0, pThreadInfo->max_sql_len); break; - case SML_REST_IFACE: - memset(pThreadInfo->buffer, 0, - g_arguments->reqPerReq * - (pThreadInfo->max_sql_len + 1)); case SML_IFACE: if (TSDB_SML_JSON_PROTOCOL == protocol) { memset(pThreadInfo->lines[0], 0, @@ -3660,8 +3276,7 @@ static int64_t fillChildTblName(SDataBase *database, SSuperTable *stbInfo) { snprintf(childName, TSDB_TABLE_NAME_LEN, "%s", stbInfo->stbName); stbInfo->childTblArray[0]->name = strdup(childName); - } else if ((stbInfo->iface != SML_IFACE - && stbInfo->iface != SML_REST_IFACE) + } else if ((stbInfo->iface != SML_IFACE) && stbInfo->childTblExists) { ntables = fillChildTblNameImp(database, stbInfo); } else { @@ -3888,20 +3503,6 @@ int32_t initInsertThread(SDataBase* database, SSuperTable* stbInfo, int32_t nthr // init conn pThreadInfo->delayList = benchArrayInit(1, sizeof(int64_t)); switch (stbInfo->iface) { - // rest - case REST_IFACE: { - if (stbInfo->interlaceRows > 0) { - pThreadInfo->buffer = new_ds(0); - } else { - pThreadInfo->buffer = benchCalloc(1, TSDB_MAX_ALLOWED_SQL_LEN, true); - } - int sockfd = createSockFd(); - if (sockfd < 0) { - goto END; - } - pThreadInfo->sockfd = sockfd; - break; - } // stmt & stmt2 init case STMT_IFACE: case STMT2_IFACE: { @@ -3965,14 +3566,6 @@ int32_t initInsertThread(SDataBase* database, SSuperTable* stbInfo, int32_t nthr break; } - // sml rest - case SML_REST_IFACE: { - int sockfd = createSockFd(); - if (sockfd < 0) { - goto END; - } - pThreadInfo->sockfd = sockfd; - } // sml case SML_IFACE: { if (stbInfo->iface == SML_IFACE) { @@ -3987,9 +3580,6 @@ int32_t initInsertThread(SDataBase* database, SSuperTable* stbInfo, int32_t nthr } } pThreadInfo->max_sql_len = stbInfo->lenOfCols + stbInfo->lenOfTags; - if (stbInfo->iface == SML_REST_IFACE) { - pThreadInfo->buffer = benchCalloc(1, g_arguments->reqPerReq * (1 + pThreadInfo->max_sql_len), true); - } int protocol = stbInfo->lineProtocol; if (TSDB_SML_JSON_PROTOCOL != protocol && SML_JSON_TAOS_FORMAT != protocol) { pThreadInfo->sml_tags = (char **)benchCalloc(pThreadInfo->ntables, sizeof(char *), true); @@ -4202,22 +3792,6 @@ int32_t exitInsertThread(SDataBase* database, SSuperTable* stbInfo, int32_t nthr // close conn int protocol = stbInfo->lineProtocol; switch (stbInfo->iface) { - case REST_IFACE: - if (g_arguments->terminate) - toolsMsleep(100); - destroySockFd(pThreadInfo->sockfd); - if (stbInfo->interlaceRows > 0) { - free_ds(&pThreadInfo->buffer); - } else { - tmfree(pThreadInfo->buffer); - pThreadInfo->buffer = NULL; - } - break; - case SML_REST_IFACE: - if (g_arguments->terminate) - toolsMsleep(100); - tmfree(pThreadInfo->buffer); - // on-purpose no break here case SML_IFACE: if (TSDB_SML_JSON_PROTOCOL != protocol && SML_JSON_TAOS_FORMAT != protocol) { @@ -4352,7 +3926,7 @@ int32_t exitInsertThread(SDataBase* database, SSuperTable* stbInfo, int32_t nthr } static int startMultiThreadInsertData(SDataBase* database, SSuperTable* stbInfo) { - if ((stbInfo->iface == SML_IFACE || stbInfo->iface == SML_REST_IFACE) + if ((stbInfo->iface == SML_IFACE) && !stbInfo->use_metric) { errorPrint("%s", "schemaless cannot work without stable\n"); return -1; @@ -4619,26 +4193,9 @@ int insertTestProcess() { //loop create database for (int i = 0; i < g_arguments->databases->size; i++) { - if (isRest(g_arguments->iface)) { - if (0 != convertServAddr(g_arguments->iface, - false, - 1)) { - return -1; - } - } SDataBase * database = benchArrayGet(g_arguments->databases, i); if (database->drop && !(g_arguments->supplementInsert)) { - if (database->superTbls && database->superTbls->size > 0) { - SSuperTable * stbInfo = benchArrayGet(database->superTbls, 0); - if (stbInfo && isRest(stbInfo->iface)) { - if (0 != convertServAddr(stbInfo->iface, - stbInfo->tcpTransfer, - stbInfo->lineProtocol)) { - return -1; - } - } - } if (createDatabase(database)) { errorPrint("failed to create database (%s)\n", database->dbName); @@ -4649,16 +4206,7 @@ int insertTestProcess() { // database already exist, get vgroups from server SBenchConn* conn = initBenchConn(); if (conn) { - int32_t vgroups; -#ifdef WEBSOCKET - if (g_arguments->websocket) { - vgroups = getVgroupsWS(conn, database); - } else { -#endif - vgroups = getVgroupsNative(conn, database); -#ifdef WEBSOCKET - } -#endif + int32_t vgroups = getVgroupsNative(conn, database); if (vgroups <=0) { closeBenchConn(conn); errorPrint("Database %s's vgroups is zero , db exist case.\n", database->dbName); @@ -4677,13 +4225,7 @@ int insertTestProcess() { for (int j = 0; j < database->superTbls->size; j++) { SSuperTable * stbInfo = benchArrayGet(database->superTbls, j); if (stbInfo->iface != SML_IFACE - && stbInfo->iface != SML_REST_IFACE && !stbInfo->childTblExists) { -#ifdef WEBSOCKET - if (g_arguments->websocket && !g_arguments->supplementInsert) { - dropSuperTable(database, stbInfo); - } -#endif int code = getSuperTableFromServer(database, stbInfo); if (code == TSDB_CODE_FAILED) { return -1; diff --git a/tools/taos-tools/src/benchJsonOpt.c b/tools/taos-tools/src/benchJsonOpt.c index 952bef3e8b..90275e95ca 100644 --- a/tools/taos-tools/src/benchJsonOpt.c +++ b/tools/taos-tools/src/benchJsonOpt.c @@ -820,16 +820,12 @@ void parseStringToIntArray(char *str, BArray *arr) { // get interface name uint16_t getInterface(char *name) { uint16_t iface = TAOSC_IFACE; - if (0 == strcasecmp(name, "rest")) { - iface = REST_IFACE; - } else if (0 == strcasecmp(name, "stmt")) { + if (0 == strcasecmp(name, "stmt")) { iface = STMT_IFACE; } else if (0 == strcasecmp(name, "stmt2")) { iface = STMT2_IFACE; } else if (0 == strcasecmp(name, "sml")) { iface = SML_IFACE; - } else if (0 == strcasecmp(name, "sml-rest")) { - iface = SML_REST_IFACE; } return iface; @@ -969,30 +965,7 @@ static int getStableInfo(tools_cJSON *dbinfos, int index) { g_arguments->reqPerReq, SML_MAX_BATCH); return -1; } - } else if (isRest(superTable->iface)) { - if (g_arguments->reqPerReq > SML_MAX_BATCH) { - errorPrint("reqPerReq (%u) larger than maximum (%d)\n", - g_arguments->reqPerReq, SML_MAX_BATCH); - return -1; - } - if (0 != convertServAddr(REST_IFACE, - false, - 1)) { - errorPrint("%s", "Failed to convert server address\n"); - return -1; - } - encodeAuthBase64(); - g_arguments->rest_server_ver_major = - getServerVersionRest(g_arguments->port + TSDB_PORT_HTTP); } -#ifdef WEBSOCKET - if (g_arguments->websocket) { - infoPrint("Since WebSocket interface is enabled, " - "the interface %s is changed to use WebSocket.\n", - stbIface->valuestring); - superTable->iface = TAOSC_IFACE; - } -#endif } @@ -1582,45 +1555,69 @@ static int getMetaFromCommonJsonFile(tools_cJSON *json) { tools_cJSON *cfgdir = tools_cJSON_GetObjectItem(json, "cfgdir"); if (cfgdir && (cfgdir->type == tools_cJSON_String) && (cfgdir->valuestring != NULL)) { - tstrncpy(g_configDir, cfgdir->valuestring, MAX_FILE_NAME_LEN); + if (!g_arguments->cfg_inputted) { + tstrncpy(g_configDir, cfgdir->valuestring, MAX_FILE_NAME_LEN); + debugPrint("configDir from cfg: %s\n", g_configDir); + } else { + warnPrint("configDir set by command line, so ignore cfg. cmd: %s\n", g_configDir); + } } + // dsn + tools_cJSON *dsn = tools_cJSON_GetObjectItem(json, "dsn"); + if (tools_cJSON_IsString(dsn) && strlen(dsn->valuestring) > 0) { + if (g_arguments->dsn == NULL) { + g_arguments->dsn = dsn->valuestring; + infoPrint("read dsn from json. dsn=%s\n", g_arguments->dsn); + } + } + + // host tools_cJSON *host = tools_cJSON_GetObjectItem(json, "host"); if (host && host->type == tools_cJSON_String && host->valuestring != NULL) { - if(g_arguments->host && strlen(g_arguments->host) > 0) { - warnPrint("command line already pass host is %s, json config host(%s) had been ignored.\n", g_arguments->host, host->valuestring); - } else { + if(g_arguments->host == NULL) { g_arguments->host = host->valuestring; + infoPrint("read host from json: %s .\n", g_arguments->host); } } + // port tools_cJSON *port = tools_cJSON_GetObjectItem(json, "port"); if (port && port->type == tools_cJSON_Number) { - if(g_arguments->port != DEFAULT_PORT) { - warnPrint("command line already pass port is %d, json config port(%d) had been ignored.\n", g_arguments->port, (uint16_t)port->valueint); + if (g_arguments->port_inputted) { + // command line input port first + warnPrint("command port: %d, json port ignored.\n", g_arguments->port); } else { - g_arguments->port = (uint16_t)port->valueint; - if(g_arguments->port != DEFAULT_PORT) { - infoPrint("json file config special port %d .\n", g_arguments->port); - g_arguments->port_inputted = true; + // default port set auto port + if (port->valueint != DEFAULT_PORT) { + g_arguments->port = (uint16_t)port->valueint; + infoPrint("read port form json: %d .\n", g_arguments->port); + g_arguments->port_inputted = true; } } } + // user tools_cJSON *user = tools_cJSON_GetObjectItem(json, "user"); if (user && user->type == tools_cJSON_String && user->valuestring != NULL) { - g_arguments->user = user->valuestring; + if (g_arguments->user == NULL) { + g_arguments->user = user->valuestring; + infoPrint("read user from json: %s .\n", g_arguments->user); + } } + // pass tools_cJSON *password = tools_cJSON_GetObjectItem(json, "password"); if (password && password->type == tools_cJSON_String && password->valuestring != NULL) { - g_arguments->password = password->valuestring; + if(g_arguments->password == NULL) { + g_arguments->password = password->valuestring; + infoPrint("read password from json: %s .\n", "******"); + } } - tools_cJSON *answerPrompt = - tools_cJSON_GetObjectItem(json, - "confirm_parameter_prompt"); // yes, no, + // yes, no + tools_cJSON *answerPrompt = tools_cJSON_GetObjectItem(json, "confirm_parameter_prompt"); if (answerPrompt && answerPrompt->type == tools_cJSON_String && answerPrompt->valuestring != NULL) { if (0 == strcasecmp(answerPrompt->valuestring, "no")) { @@ -1661,15 +1658,6 @@ static int getMetaFromCommonJsonFile(tools_cJSON *json) { static int getMetaFromInsertJsonFile(tools_cJSON *json) { int32_t code = -1; -#ifdef WEBSOCKET - tools_cJSON *dsn = tools_cJSON_GetObjectItem(json, "dsn"); - if (tools_cJSON_IsString(dsn)) { - g_arguments->dsn = dsn->valuestring; - g_arguments->websocket = true; - infoPrint("set websocket true from json->dsn=%s\n", g_arguments->dsn); - } -#endif - // check after inserted tools_cJSON *checkSql = tools_cJSON_GetObjectItem(json, "check_sql"); if (tools_cJSON_IsString(checkSql)) { @@ -1724,24 +1712,6 @@ static int getMetaFromInsertJsonFile(tools_cJSON *json) { g_arguments->table_threads = (uint32_t)table_theads->valueint; } -#ifdef WEBSOCKET - if (!g_arguments->websocket) { -#endif -#ifdef LINUX - if (strlen(g_configDir)) { - wordexp_t full_path; - if (wordexp(g_configDir, &full_path, 0) != 0) { - errorPrint("Invalid path %s\n", g_configDir); - exit(EXIT_FAILURE); - } - taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); - wordfree(&full_path); - } -#endif -#ifdef WEBSOCKET - } -#endif - tools_cJSON *numRecPerReq = tools_cJSON_GetObjectItem(json, "num_of_records_per_req"); if (numRecPerReq && numRecPerReq->type == tools_cJSON_Number) { @@ -2268,9 +2238,7 @@ static int getMetaFromQueryJsonFile(tools_cJSON *json) { tools_cJSON *queryMode = tools_cJSON_GetObjectItem(json, "query_mode"); if (tools_cJSON_IsString(queryMode)) { - if (0 == strcasecmp(queryMode->valuestring, "rest")) { - g_queryInfo.iface = REST_IFACE; - } else if (0 == strcasecmp(queryMode->valuestring, "taosc")) { + if (0 == strcasecmp(queryMode->valuestring, "taosc")) { g_queryInfo.iface = TAOSC_IFACE; } else { errorPrint("Invalid query_mode value: %s\n", @@ -2320,24 +2288,6 @@ static int getMetaFromQueryJsonFile(tools_cJSON *json) { static int getMetaFromTmqJsonFile(tools_cJSON *json) { int32_t code = -1; - - tools_cJSON *cfgdir = tools_cJSON_GetObjectItem(json, "cfgdir"); - if (tools_cJSON_IsString(cfgdir)) { - tstrncpy(g_configDir, cfgdir->valuestring, MAX_FILE_NAME_LEN); - } - -#ifdef LINUX - if (strlen(g_configDir)) { - wordexp_t full_path; - if (wordexp(g_configDir, &full_path, 0) != 0) { - errorPrint("Invalid path %s\n", g_configDir); - exit(EXIT_FAILURE); - } - taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); - wordfree(&full_path); - } -#endif - tools_cJSON *resultfile = tools_cJSON_GetObjectItem(json, "result_file"); if (resultfile && resultfile->type == tools_cJSON_String && resultfile->valuestring != NULL) { diff --git a/tools/taos-tools/src/benchMain.c b/tools/taos-tools/src/benchMain.c index 16b3e3a617..564bc80bc6 100644 --- a/tools/taos-tools/src/benchMain.c +++ b/tools/taos-tools/src/benchMain.c @@ -21,6 +21,7 @@ STmqMetaInfo g_tmqInfo; bool g_fail = false; uint64_t g_memoryUsage = 0; tools_cJSON* root; +extern char g_configDir[MAX_PATH_LEN]; #define CLIENT_INFO_LEN 20 static char g_client_info[CLIENT_INFO_LEN] = {0}; @@ -59,18 +60,6 @@ int checkArgumentValid() { g_arguments->host = DEFAULT_HOST; } - if (isRest(g_arguments->iface)) { - if (0 != convertServAddr(g_arguments->iface, - false, - 1)) { - errorPrint("%s", "Failed to convert server address\n"); - return -1; - } - encodeAuthBase64(); - g_arguments->rest_server_ver_major = - getServerVersionRest(g_arguments->port); - } - // check batch query if (g_arguments->test_mode == QUERY_TEST) { if (g_queryInfo.specifiedQueryInfo.batchQuery) { @@ -80,18 +69,48 @@ int checkArgumentValid() { errorPrint("%s\n", "batch_query = yes require mixed_query is yes"); return -1; } - - // rest not support - if (g_queryInfo.iface == REST_IFACE) { - errorPrint("%s\n", "batch_query = yes not support restful."); - return -1; - } } } return 0; } +// apply cfg +int32_t applyConfigDir(char * cfgDir){ + // set engine config dir + int32_t code; +#ifdef LINUX + wordexp_t full_path; + if (wordexp(cfgDir, &full_path, 0) != 0) { + errorPrint("Invalid path %s\n", cfgDir); + exit(EXIT_FAILURE); + } + code = taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); + wordfree(&full_path); +#else + code = taos_options(TSDB_OPTION_CONFIGDIR, cfgDir); +#endif + // show error + if (code) { + engineError("applyConfigDir", "taos_options(TSDB_OPTION_CONFIGDIR, ...)", code); + } + + return code; + } + +int32_t setConnMode(int8_t connMode, char *dsn) { + // set conn mode + char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; + int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); + if (code != TSDB_CODE_SUCCESS) { + engineError(INIT_PHASE, "taos_options", code); + return -1; + } + + infoPrint("Connect mode is : %s\n\n", strMode); + return 0; +} + int main(int argc, char* argv[]) { int ret = 0; @@ -100,46 +119,36 @@ int main(int argc, char* argv[]) { initArgument(); srand(time(NULL)%1000000); + // majorVersion snprintf(g_client_info, CLIENT_INFO_LEN, "%s", taos_get_client_info()); g_majorVersionOfClient = atoi(g_client_info); debugPrint("Client info: %s, major version: %d\n", g_client_info, g_majorVersionOfClient); -#ifdef LINUX - if (sem_init(&g_arguments->cancelSem, 0, 0) != 0) { - errorPrint("%s", "failed to create cancel semaphore\n"); - exit(EXIT_FAILURE); - } - pthread_t spid = {0}; - pthread_create(&spid, NULL, benchCancelHandler, NULL); - - benchSetSignal(SIGINT, benchQueryInterruptHandler); - -#endif + // read command line if (benchParseArgs(argc, argv)) { exitLog(); return -1; } -#ifdef WEBSOCKET - if (g_arguments->debug_print) { - ws_enable_log("info"); + + // check valid + if(g_arguments->connMode == CONN_MODE_NATIVE && g_arguments->dsn) { + errorPrint("%s", DSN_NATIVE_CONFLICT); + exitLog(); + return -1; } - if (g_arguments->dsn != NULL) { - g_arguments->websocket = true; - infoPrint("set websocket true from dsn not empty. dsn=%s\n", g_arguments->dsn); - } else { + // read evn + if (g_arguments->dsn == NULL) { char * dsn = getenv("TDENGINE_CLOUD_DSN"); - if (dsn != NULL && strlen(dsn) > 3) { + if (dsn != NULL && strlen(dsn) > 0) { g_arguments->dsn = dsn; - g_arguments->websocket = true; - infoPrint("set websocket true from getenv TDENGINE_CLOUD_DSN=%s\n", g_arguments->dsn); - } else { - g_arguments->dsn = false; - } + infoPrint("Get dsn from getenv TDENGINE_CLOUD_DSN=%s\n", g_arguments->dsn); + } } -#endif + + // read json config if (g_arguments->metaFile) { g_arguments->totalChildTables = 0; if (readJsonConfig(g_arguments->metaFile)) { @@ -151,6 +160,7 @@ int main(int argc, char* argv[]) { modifyArgument(); } + // open result file if(g_arguments->output_file[0] == 0) { infoPrint("%s","result_file is empty, ignore output."); g_arguments->fpOfInsertResult = NULL; @@ -162,6 +172,7 @@ int main(int argc, char* argv[]) { } } + // check argument infoPrint("client version: %s\n", taos_get_client_info()); if (checkArgumentValid()) { errorPrint("failed to readJsonConfig %s\n", g_arguments->metaFile); @@ -169,6 +180,36 @@ int main(int argc, char* argv[]) { return -1; } + // conn mode + if (setConnMode(g_arguments->connMode, g_arguments->dsn) != 0) { + exitLog(); + return -1; + } + + // check condition for set config dir + if (strlen(g_configDir) + && g_arguments->host_auto + && g_arguments->port_auto) { + // apply + if(applyConfigDir(g_configDir) != TSDB_CODE_SUCCESS) { + exitLog(); + return -1; + } + infoPrint("Set engine cfgdir successfully, dir:%s\n", g_configDir); + } + + // cancel thread +#ifdef LINUX + if (sem_init(&g_arguments->cancelSem, 0, 0) != 0) { + errorPrint("%s", "failed to create cancel semaphore\n"); + exit(EXIT_FAILURE); + } + pthread_t spid = {0}; + pthread_create(&spid, NULL, benchCancelHandler, NULL); + benchSetSignal(SIGINT, benchQueryInterruptHandler); +#endif + + // running if (g_arguments->test_mode == INSERT_TEST) { if (insertTestProcess()) { errorPrint("%s", "insert test process failed\n"); @@ -194,6 +235,8 @@ int main(int argc, char* argv[]) { if ((ret == 0) && g_arguments->aggr_func) { queryAggrFunc(); } + + // free and exit postFreeResource(); #ifdef LINUX diff --git a/tools/taos-tools/src/benchQuery.c b/tools/taos-tools/src/benchQuery.c index 8be8bf9f6c..d0c0713b3d 100644 --- a/tools/taos-tools/src/benchQuery.c +++ b/tools/taos-tools/src/benchQuery.c @@ -23,43 +23,32 @@ int selectAndGetResult(qThreadInfo *pThreadInfo, char *command, bool record) { } // execute sql - uint32_t threadID = pThreadInfo->threadID; char dbName[TSDB_DB_NAME_LEN] = {0}; tstrncpy(dbName, g_queryInfo.dbName, TSDB_DB_NAME_LEN); - if (g_queryInfo.iface == REST_IFACE) { - int retCode = postProceSql(command, g_queryInfo.dbName, 0, REST_IFACE, - 0, g_arguments->port, false, - pThreadInfo->sockfd, pThreadInfo->filePath); - if (0 != retCode) { - errorPrint("====restful return fail, threadID[%u]\n", threadID); - ret = -1; - } + // query + TAOS *taos = pThreadInfo->conn->taos; + int64_t rows = 0; + TAOS_RES *res = taos_query(taos, command); + int code = taos_errno(res); + if (res == NULL || code) { + // failed query + errorPrint("failed to execute sql:%s, " + "code: 0x%08x, reason:%s\n", + command, code, taos_errstr(res)); + ret = -1; } else { - // query - TAOS *taos = pThreadInfo->conn->taos; - int64_t rows = 0; - TAOS_RES *res = taos_query(taos, command); - int code = taos_errno(res); - if (res == NULL || code) { - // failed query - errorPrint("failed to execute sql:%s, " - "code: 0x%08x, reason:%s\n", - command, code, taos_errstr(res)); - ret = -1; - } else { - // succ query - if (record) - rows = fetchResult(res, pThreadInfo->filePath); - } - - // free result - if (res) { - taos_free_result(res); - } - debugPrint("query sql:%s rows:%"PRId64"\n", command, rows); + // succ query + if (record) + rows = fetchResult(res, pThreadInfo->filePath); } + // free result + if (res) { + taos_free_result(res); + } + debugPrint("query sql:%s rows:%"PRId64"\n", command, rows); + // record count if (ret ==0) { // succ @@ -1077,10 +1066,6 @@ void totalQuery(int64_t spends) { int queryTestProcess() { prompt(0); - if (REST_IFACE == g_queryInfo.iface) { - encodeAuthBase64(); - } - // kill sql for executing seconds over "kill_slow_query_threshold" if (g_queryInfo.iface == TAOSC_IFACE && g_queryInfo.killQueryThreshold) { int32_t ret = killSlowQuery(); @@ -1089,16 +1074,6 @@ int queryTestProcess() { } } - // covert addr - if (g_queryInfo.iface == REST_IFACE) { - if (convertHostToServAddr(g_arguments->host, - g_arguments->port + TSDB_PORT_HTTP, - &(g_arguments->serv_addr)) != 0) { - errorPrint("%s", "convert host to server address\n"); - return -1; - } - } - // fetch child name if super table if ((g_queryInfo.superQueryInfo.sqlCount > 0) && (g_queryInfo.superQueryInfo.threadCnt > 0)) { diff --git a/tools/taos-tools/src/benchSys.c b/tools/taos-tools/src/benchSys.c index d7e44c045f..b808b2d8df 100644 --- a/tools/taos-tools/src/benchSys.c +++ b/tools/taos-tools/src/benchSys.c @@ -73,12 +73,10 @@ void benchPrintHelp() { printf("%s%s%s%s\r\n", indent, "-x,", indent, BENCH_AGGR); printf("%s%s%s%s\r\n", indent, "-y,", indent, BENCH_YES); printf("%s%s%s%s\r\n", indent, "-z,", indent, BENCH_TRYING_INTERVAL); -#ifdef WEBSOCKET - printf("%s%s%s%s\r\n", indent, "-W,", indent, BENCH_DSN); - printf("%s%s%s%s\r\n", indent, "-D,", indent, BENCH_TIMEOUT); -#endif printf("%s%s%s%s\r\n", indent, "-v,", indent, BENCH_VGROUPS); printf("%s%s%s%s\r\n", indent, "-V,", indent, BENCH_VERSION); + printf("%s%s%s%s\r\n", indent, "-X,", indent, DSN_DESC); + printf("%s%s%s%s\r\n", indent, "-Z,", indent, DRIVER_DESC); printf("\r\n\r\nReport bugs to %s.\r\n", CUS_EMAIL); } @@ -120,11 +118,10 @@ int32_t benchParseArgsNoArgp(int argc, char* argv[]) { || key[1] == 'R' || key[1] == 'O' || key[1] == 'a' || key[1] == 'F' || key[1] == 'k' || key[1] == 'z' -#ifdef WEBSOCKET - || key[1] == 'D' || key[1] == 'W' -#endif - || key[1] == 'v' + || key[1] == 'W' || key[1] == 'v' + || key[1] == 'X' || key[1] == 'Z' ) { + // check input value if (i + 1 >= argc) { errorPrint("option %s requires an argument\r\n", key); return -1; @@ -191,15 +188,14 @@ static struct argp_option bench_options[] = { {"debug", 'g', 0, 0, BENCH_DEBUG}, {"performance", 'G', 0, 0, BENCH_PERFORMANCE}, {"prepared_rand", 'F', "NUMBER", 0, BENCH_PREPARE}, -#ifdef WEBSOCKET - {"cloud_dsn", 'W', "DSN", 0, BENCH_DSN}, - {"timeout", 'D', "NUMBER", 0, BENCH_TIMEOUT}, -#endif + {"cloud_dsn", 'W', "DSN", 0, OLD_DSN_DESC}, {"keep-trying", 'k', "NUMBER", 0, BENCH_KEEPTRYING}, {"trying-interval", 'z', "NUMBER", 0, BENCH_TRYING_INTERVAL}, {"vgroups", 'v', "NUMBER", 0, BENCH_VGROUPS}, {"version", 'V', 0, 0, BENCH_VERSION}, {"nodrop", 'Q', 0, 0, BENCH_NODROP}, + {"dsn", 'X', "DSN", 0, DSN_DESC}, + {DRIVER_OPT, 'Z', "DRIVER", 0, DRIVER_DESC}, {0} }; @@ -251,11 +247,7 @@ int32_t benchParseSingleOpt(int32_t key, char* arg) { errorPrint( "Invalid -P: %s, will auto set to default(6030)\n", arg); - if (REST_IFACE == g_arguments->iface) { - g_arguments->port = DEFAULT_REST_PORT; - } else { - g_arguments->port = DEFAULT_PORT; - } + g_arguments->port = DEFAULT_PORT; } else { g_arguments->port_auto = false; } @@ -269,11 +261,6 @@ int32_t benchParseSingleOpt(int32_t key, char* arg) { stbInfo->iface = STMT_IFACE; } else if (0 == strcasecmp(arg, "stmt2")) { stbInfo->iface = STMT2_IFACE; - } else if (0 == strcasecmp(arg, "rest")) { - stbInfo->iface = REST_IFACE; - if (false == g_arguments->port_inputted) { - g_arguments->port = DEFAULT_REST_PORT; - } } else if (0 == strcasecmp(arg, "sml") || 0 == strcasecmp(arg, "sml-line")) { stbInfo->iface = SML_IFACE; @@ -287,19 +274,6 @@ int32_t benchParseSingleOpt(int32_t key, char* arg) { } else if (0 == strcasecmp(arg, "sml-taosjson")) { stbInfo->iface = SML_IFACE; stbInfo->lineProtocol = SML_JSON_TAOS_FORMAT; - } else if (0 == strcasecmp(arg, "sml-rest") - || (0 == strcasecmp(arg, "sml-rest-line"))) { - stbInfo->iface = SML_REST_IFACE; - stbInfo->lineProtocol = TSDB_SML_LINE_PROTOCOL; - } else if (0 == strcasecmp(arg, "sml-rest-telnet")) { - stbInfo->iface = SML_REST_IFACE; - stbInfo->lineProtocol = TSDB_SML_TELNET_PROTOCOL; - } else if (0 == strcasecmp(arg, "sml-rest-json")) { - stbInfo->iface = SML_REST_IFACE; - stbInfo->lineProtocol = TSDB_SML_JSON_PROTOCOL; - } else if (0 == strcasecmp(arg, "sml-rest-taosjson")) { - stbInfo->iface = SML_REST_IFACE; - stbInfo->lineProtocol = SML_JSON_TAOS_FORMAT; } else { errorPrint( "Invalid -I: %s, will auto set to default (taosc)\n", @@ -625,19 +599,11 @@ int32_t benchParseSingleOpt(int32_t key, char* arg) { g_arguments->performance_print = true; break; -#ifdef WEBSOCKET case 'W': + case 'X': g_arguments->dsn = arg; break; - case 'D': - if (!toolsIsStringNumber(arg)) { - errorPrintReqArg2(CUS_PROMPT"Benchmark", "D"); - } - - g_arguments->timeout = atoi(arg); - break; -#endif case 'v': if (!toolsIsStringNumber(arg)) { errorPrintReqArg2(CUS_PROMPT"Benchmark", "v"); @@ -651,6 +617,9 @@ int32_t benchParseSingleOpt(int32_t key, char* arg) { case 'V': printVersion(); exit(0); + case 'Z': + g_arguments->connMode = getConnMode(arg); + break; default: return ARGP_ERR_UNKNOWN; } diff --git a/tools/taos-tools/src/benchUtil.c b/tools/taos-tools/src/benchUtil.c index 467af0198a..32bc5b0813 100644 --- a/tools/taos-tools/src/benchUtil.c +++ b/tools/taos-tools/src/benchUtil.c @@ -10,6 +10,7 @@ * FITNESS FOR A PARTICULAR PURPOSE. */ +#include #include #include "benchLog.h" @@ -45,8 +46,8 @@ FORCE_INLINE void tmfree(void *buf) { } } -FORCE_INLINE bool isRest(int32_t iface) { - return REST_IFACE == iface || SML_REST_IFACE == iface; +void engineError(char * module, char * fun, int32_t code) { + errorPrint("%s API:%s error code:0x%08X %s\n", TIP_ENGINE_ERR, fun, code, module); } void ERROR_EXIT(const char *msg) { @@ -161,50 +162,6 @@ int getAllChildNameOfSuperTable(TAOS *taos, char *dbName, char *stbName, return 0; } -int convertHostToServAddr(char *host, uint16_t port, - struct sockaddr_in *serv_addr) { - if (!host) { - errorPrint("%s", "convertHostToServAddr host is null."); - return -1; - } - debugPrint("convertHostToServAddr(host: %s, port: %d)\n", host, - port); -#ifdef WINDOWS - WSADATA wsaData; - int ret = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (ret) { - return ret; - } -#endif - struct hostent *server = gethostbyname(host); - if ((server == NULL) || (server->h_addr == NULL)) { - errorPrint("%s", "no such host"); - return -1; - } - memset(serv_addr, 0, sizeof(struct sockaddr_in)); - serv_addr->sin_family = AF_INET; - serv_addr->sin_port = htons(port); - -#ifdef WINDOWS - struct addrinfo hints = {0}; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - struct addrinfo *pai = NULL; - - if (!getaddrinfo(server->h_name, NULL, &hints, &pai)) { - serv_addr->sin_addr.s_addr = - ((struct sockaddr_in *) pai->ai_addr)->sin_addr.s_addr; - freeaddrinfo(pai); - } - WSACleanup(); -#else - serv_addr->sin_addr.s_addr = inet_addr(host); - memcpy(&(serv_addr->sin_addr.s_addr), server->h_addr, server->h_length); -#endif - return 0; -} - void prompt(bool nonStopMode) { if (!g_arguments->answer_yes) { g_arguments->in_prompt = true; @@ -295,48 +252,85 @@ int regexMatch(const char *s, const char *reg, int cflags) { return 0; } - - - SBenchConn* initBenchConnImpl() { SBenchConn* conn = benchCalloc(1, sizeof(SBenchConn), true); -#ifdef WEBSOCKET - if (g_arguments->websocket) { - conn->taos_ws = ws_connect(g_arguments->dsn); - char maskedDsn[256] = "\0"; - memcpy(maskedDsn, g_arguments->dsn, 20); - memcpy(maskedDsn+20, "...", 3); - memcpy(maskedDsn+23, - g_arguments->dsn + strlen(g_arguments->dsn)-10, 10); - if (conn->taos_ws == NULL) { - errorPrint("failed to connect %s, reason: %s\n", - maskedDsn, ws_errstr(NULL)); + char show[256] = "\0"; + char * host = NULL; + uint16_t port = 0; + char * user = NULL; + char * pwd = NULL; + int32_t code = 0; + char * dsnc = NULL; + + // set mode + if (g_arguments->connMode != CONN_MODE_NATIVE && g_arguments->dsn) { + dsnc = strToLowerCopy(g_arguments->dsn); + if (dsnc == NULL) { tmfree(conn); return NULL; } - succPrint("%s conneced\n", maskedDsn); + char *cport = NULL; + char error[512] = "\0"; + code = parseDsn(dsnc, &host, &cport, &user, &pwd, error); + if (code) { + errorPrint("%s dsn=%s\n", error, dsnc); + tmfree(conn); + tmfree(dsnc); + return NULL; + } + + // default ws port + if (cport == NULL) { + if (user) + port = DEFAULT_PORT_WS_CLOUD; + else + port = DEFAULT_PORT_WS_LOCAL; + } else { + port = atoi(cport); + } + + // websocket + memcpy(show, g_arguments->dsn, 20); + memcpy(show + 20, "...", 3); + memcpy(show + 23, g_arguments->dsn + strlen(g_arguments->dsn) - 10, 10); + } else { -#endif - conn->taos = taos_connect(g_arguments->host, - g_arguments->user, g_arguments->password, - NULL, g_arguments->port); - if (conn->taos == NULL) { - errorPrint("failed to connect native %s:%d, " - "code: 0x%08x, reason: %s\n", - g_arguments->host, g_arguments->port, - taos_errno(NULL), taos_errstr(NULL)); - tmfree(conn); - return NULL; + + host = g_arguments->host; + user = g_arguments->user; + pwd = g_arguments->password; + + if (g_arguments->port_inputted) { + port = g_arguments->port; + } else { + port = g_arguments->connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; } - conn->ctaos = taos_connect(g_arguments->host, - g_arguments->user, - g_arguments->password, - NULL, g_arguments->port); -#ifdef WEBSOCKET + sprintf(show, "host:%s port:%d ", host, port); + } + + // connect main + conn->taos = taos_connect(host, user, pwd, NULL, port); + if (conn->taos == NULL) { + errorPrint("failed to connect %s:%d, " + "code: 0x%08x, reason: %s\n", + g_arguments->host, g_arguments->port, + taos_errno(NULL), taos_errstr(NULL)); + tmfree(conn); + if (dsnc) { + tmfree(dsnc); + } + return NULL; + } + succPrint("%s connect successfully.\n", show); + + // check write correct connect + conn->ctaos = taos_connect(host, user, pwd, NULL, port); + + if (dsnc) { + tmfree(dsnc); } -#endif return conn; } @@ -350,7 +344,7 @@ SBenchConn* initBenchConn() { break; } - infoPrint("sleep %dms and try to connect... %d \n", g_arguments->trying_interval, keep_trying); + infoPrint("sleep %dms and try to connect... %d/%d \n", g_arguments->trying_interval, keep_trying, g_arguments->keep_trying); if(g_arguments->trying_interval > 0) { toolsMsleep(g_arguments->trying_interval); } @@ -362,63 +356,28 @@ SBenchConn* initBenchConn() { void closeBenchConn(SBenchConn* conn) { if(conn == NULL) return ; -#ifdef WEBSOCKET - if (g_arguments->websocket) { - ws_close(conn->taos_ws); - } else { -#endif - if(conn->taos) { - taos_close(conn->taos); - conn->taos = NULL; - } - if (conn->ctaos) { - taos_close(conn->ctaos); - conn->ctaos = NULL; - } -#ifdef WEBSOCKET - } -#endif - tmfree(conn); -} -int32_t queryDbExecRest(char *command, char* dbName, int precision, - int iface, int protocol, bool tcp, int sockfd) { - int32_t code = postProceSql(command, - dbName, - precision, - iface, - protocol, - g_arguments->port, - tcp, - sockfd, - NULL); - return code; + if(conn->taos) { + taos_close(conn->taos); + conn->taos = NULL; + } + + if (conn->ctaos) { + taos_close(conn->ctaos); + conn->ctaos = NULL; + } + tmfree(conn); } int32_t queryDbExecCall(SBenchConn *conn, char *command) { int32_t code = 0; -#ifdef WEBSOCKET - if (g_arguments->websocket) { - WS_RES* res = ws_query_timeout(conn->taos_ws, - command, g_arguments->timeout); - code = ws_errno(res); - if (code != 0) { - errorPrint("Failed to execute <%s>, code: 0x%08x, reason: %s\n", - command, code, ws_errstr(res)); - } - ws_free_result(res); + TAOS_RES *res = taos_query(conn->taos, command); + code = taos_errno(res); + if (code) { + printErrCmdCodeStr(command, code, res); } else { -#endif - TAOS_RES *res = taos_query(conn->taos, command); - code = taos_errno(res); - if (code) { - printErrCmdCodeStr(command, code, res); - } else { - taos_free_result(res); - } -#ifdef WEBSOCKET + taos_free_result(res); } -#endif return code; } @@ -458,374 +417,6 @@ void encodeAuthBase64() { g_arguments->base64_buf[encoded_len - 1 - l] = '='; } -int postProceSqlImpl(char *sqlstr, char* dbName, int precision, int iface, - int protocol, uint16_t rest_port, bool tcp, int sockfd, - char* filePath, - char *responseBuf, int64_t response_length) { - int32_t code = -1; - char * req_fmt = - "POST %s HTTP/1.1\r\nHost: %s:%d\r\nAccept: */*\r\nAuthorization: " - "Basic %s\r\nContent-Length: %d\r\nContent-Type: " - "application/x-www-form-urlencoded\r\n\r\n%s"; - char url[URL_BUFF_LEN] = {0}; - if (iface == REST_IFACE) { - snprintf(url, URL_BUFF_LEN, "/rest/sql/%s", dbName); - } else if (iface == SML_REST_IFACE - && protocol == TSDB_SML_LINE_PROTOCOL) { - snprintf(url, URL_BUFF_LEN, - "/influxdb/v1/write?db=%s&precision=%s", dbName, - precision == TSDB_TIME_PRECISION_MILLI - ? "ms" - : precision == TSDB_TIME_PRECISION_NANO - ? "ns" - : "u"); - } else if (iface == SML_REST_IFACE - && protocol == TSDB_SML_TELNET_PROTOCOL) { - snprintf(url, URL_BUFF_LEN, "/opentsdb/v1/put/telnet/%s", dbName); - } else if (iface == SML_REST_IFACE - && (protocol == TSDB_SML_JSON_PROTOCOL - || protocol == SML_JSON_TAOS_FORMAT)) { - snprintf(url, URL_BUFF_LEN, "/opentsdb/v1/put/json/%s", dbName); - } - - int bytes, sent, received, req_str_len, resp_len; - char * request_buf = NULL; - int req_buf_len = (int)strlen(sqlstr) + REQ_EXTRA_BUF_LEN; - - if (g_arguments->terminate) { - goto free_of_postImpl; - } - request_buf = benchCalloc(1, req_buf_len, false); - - int r; - if (protocol == TSDB_SML_TELNET_PROTOCOL && tcp) { - r = snprintf(request_buf, req_buf_len, "%s", sqlstr); - } else { - r = snprintf(request_buf, req_buf_len, req_fmt, url, g_arguments->host, - rest_port, g_arguments->base64_buf, strlen(sqlstr), - sqlstr); - } - if (r >= req_buf_len) { - free(request_buf); - ERROR_EXIT("too long request"); - } - - req_str_len = (int)strlen(request_buf); - debugPrint("request buffer: %s\n", request_buf); - sent = 0; - do { - bytes = send(sockfd, request_buf + sent, - req_str_len - sent, 0); - if (bytes < 0) { - errorPrint("%s", "writing no message to socket\n"); - goto free_of_postImpl; - } - if (bytes == 0) break; - sent += bytes; - } while ((sent < req_str_len) && !g_arguments->terminate); - - if (protocol == TSDB_SML_TELNET_PROTOCOL - && iface == SML_REST_IFACE && tcp) { - code = 0; - goto free_of_postImpl; - } - - resp_len = response_length - 1; - received = 0; - - bool chunked = false; - - if (g_arguments->terminate) { - goto free_of_postImpl; - } - do { - bytes = recv(sockfd, responseBuf + received, - resp_len - received, 0); - if (bytes <= 0) { - errorPrint("%s", "reading no response from socket\n"); - goto free_of_postImpl; - } - responseBuf[resp_len] = 0; - debugPrint("response buffer: %s bytes=%d\n", responseBuf, bytes); - if (NULL != strstr(responseBuf, resEncodingChunk)) { - chunked = true; - } - int64_t index = strlen(responseBuf) - 1; - while (responseBuf[index] == '\n' || responseBuf[index] == '\r') { - if (index == 0) { - break; - } - index--; - } - debugPrint("index: %" PRId64 "\n", index); - if (chunked && responseBuf[index] == '0') { - code = 0; - break; - } - if (!chunked && responseBuf[index] == '}') { - code = 0; - break; - } - - received += bytes; - - if (g_arguments->test_mode == INSERT_TEST) { - if (strlen(responseBuf)) { - if (((NULL != strstr(responseBuf, resEncodingChunk)) && - (NULL != strstr(responseBuf, resHttp))) || - ((NULL != strstr(responseBuf, resHttpOk)) || - (NULL != strstr(responseBuf, influxHttpOk)) || - (NULL != strstr(responseBuf, opentsdbHttpOk)))) { - break; - } - } - } - } while ((received < resp_len) && !g_arguments->terminate); - - if (received == resp_len) { - errorPrint("%s", "storing complete response from socket\n"); - goto free_of_postImpl; - } - - if (NULL == strstr(responseBuf, resHttpOk) && - NULL == strstr(responseBuf, influxHttpOk) && - NULL == strstr(responseBuf, succMessage) && - NULL == strstr(responseBuf, opentsdbHttpOk)) { - errorPrint("Response:\n%s\n", responseBuf); - goto free_of_postImpl; - } - - code = 0; -free_of_postImpl: - if (filePath && strlen(filePath) > 0 && !g_arguments->terminate) { - appendResultBufToFile(responseBuf, filePath); - } - tmfree(request_buf); - return code; -} - -static int getServerVersionRestImpl(int16_t rest_port, int sockfd) { - int server_ver = -1; - char command[SHORT_1K_SQL_BUFF_LEN] = "\0"; - snprintf(command, SHORT_1K_SQL_BUFF_LEN, "SELECT SERVER_VERSION()"); - char *responseBuf = benchCalloc(1, RESP_BUF_LEN, false); - int code = postProceSqlImpl(command, - NULL, - 0, - REST_IFACE, - 0, - rest_port, - false, - sockfd, - NULL, responseBuf, RESP_BUF_LEN); - if (code != 0) { - errorPrint("Failed to execute command: %s\n", command); - goto free_of_getversion; - } - debugPrint("response buffer: %s\n", responseBuf); - if (NULL != strstr(responseBuf, resHttpOk)) { - char* start = strstr(responseBuf, "{"); - if (start == NULL) { - errorPrint("Invalid response format: %s\n", responseBuf); - goto free_of_getversion; - } - tools_cJSON* resObj = tools_cJSON_Parse(start); - if (resObj == NULL) { - errorPrint("Cannot parse response into json: %s\n", start); - } - tools_cJSON* dataObj = tools_cJSON_GetObjectItem(resObj, "data"); - if (!tools_cJSON_IsArray(dataObj)) { - char* pstr = tools_cJSON_Print(resObj); - errorPrint("Invalid or miss 'data' key in json: %s\n", pstr ? pstr : "null"); - tmfree(pstr); - tools_cJSON_Delete(resObj); - goto free_of_getversion; - } - tools_cJSON *versionObj = tools_cJSON_GetArrayItem(dataObj, 0); - tools_cJSON *versionStrObj = tools_cJSON_GetArrayItem(versionObj, 0); - server_ver = atoi(versionStrObj->valuestring); - char* pstr = tools_cJSON_Print(versionStrObj); - debugPrint("versionStrObj: %s, version: %s, server_ver: %d\n", - pstr ? pstr : "null", - versionStrObj->valuestring, server_ver); - tmfree(pstr); - tools_cJSON_Delete(resObj); - } -free_of_getversion: - free(responseBuf); - return server_ver; -} - -int getServerVersionRest(int16_t rest_port) { - int sockfd = createSockFd(); - if (sockfd < 0) { - return -1; - } - - int server_version = getServerVersionRestImpl(rest_port, sockfd); - - destroySockFd(sockfd); - return server_version; -} - -static int getCodeFromResp(char *responseBuf) { - int code = -1; - char* start = strstr(responseBuf, "{"); - if (start == NULL) { - errorPrint("Invalid response format: %s\n", responseBuf); - return -1; - } - tools_cJSON* resObj = tools_cJSON_Parse(start); - if (resObj == NULL) { - errorPrint("Cannot parse response into json: %s\n", start); - return -1; - } - tools_cJSON* codeObj = tools_cJSON_GetObjectItem(resObj, "code"); - if (!tools_cJSON_IsNumber(codeObj)) { - char* pstr = tools_cJSON_Print(resObj); - errorPrint("Invalid or miss 'code' key in json: %s\n", pstr ? pstr : "null"); - tmfree(pstr); - tools_cJSON_Delete(resObj); - return -1; - } - - code = codeObj->valueint; - - if (codeObj->valueint != 0) { - tools_cJSON* desc = tools_cJSON_GetObjectItem(resObj, "desc"); - if (!tools_cJSON_IsString(desc)) { - char* pstr = tools_cJSON_Print(resObj); - errorPrint("Invalid or miss 'desc' key in json: %s\n", pstr ? pstr : "null"); - tmfree(pstr); - return -1; - } - errorPrint("response, code: %d, reason: %s\n", - (int)codeObj->valueint, desc->valuestring); - } - - tools_cJSON_Delete(resObj); - return code; -} - -int postProceSql(char *sqlstr, char* dbName, int precision, int iface, - int protocol, uint16_t rest_port, - bool tcp, int sockfd, char* filePath) { - uint64_t response_length; - if (g_arguments->test_mode == INSERT_TEST) { - response_length = RESP_BUF_LEN; - } else { - response_length = g_queryInfo.response_buffer; - } - - char *responseBuf = benchCalloc(1, response_length, false); - int code = postProceSqlImpl(sqlstr, dbName, precision, iface, protocol, - rest_port, - tcp, sockfd, filePath, responseBuf, - response_length); - // compatibility 2.6 - if (-1 == g_arguments->rest_server_ver_major) { - // confirm version is 2.x according to "succ" - if (NULL != strstr(responseBuf, succMessage) && iface == REST_IFACE) { - g_arguments->rest_server_ver_major = 2; - } - } - - if (NULL != strstr(responseBuf, resHttpOk) && iface == REST_IFACE) { - // if taosd is not starting , rest_server_ver_major can't be got by 'select server_version()' , so is -1 - if (-1 == g_arguments->rest_server_ver_major || 3 <= g_arguments->rest_server_ver_major) { - code = getCodeFromResp(responseBuf); - } else { - code = 0; - } - goto free_of_post; - } - - if (2 == g_arguments->rest_server_ver_major) { - if (NULL != strstr(responseBuf, succMessage) && iface == REST_IFACE) { - code = getCodeFromResp(responseBuf); - } else { - code = 0; - } - goto free_of_post; - } - - if (NULL != strstr(responseBuf, influxHttpOk) && - protocol == TSDB_SML_LINE_PROTOCOL && iface == SML_REST_IFACE) { - code = 0; - goto free_of_post; - } - - if (NULL != strstr(responseBuf, opentsdbHttpOk) - && (protocol == TSDB_SML_TELNET_PROTOCOL - || protocol == TSDB_SML_JSON_PROTOCOL - || protocol == SML_JSON_TAOS_FORMAT) - && iface == SML_REST_IFACE) { - code = 0; - goto free_of_post; - } - - if (g_arguments->test_mode == INSERT_TEST) { - debugPrint("Response: \n%s\n", responseBuf); - char* start = strstr(responseBuf, "{"); - if ((start == NULL) - && (TSDB_SML_TELNET_PROTOCOL != protocol) - && (TSDB_SML_JSON_PROTOCOL != protocol) - && (SML_JSON_TAOS_FORMAT != protocol) - ) { - errorPrint("Invalid response format: %s\n", responseBuf); - goto free_of_post; - } - tools_cJSON* resObj = tools_cJSON_Parse(start); - if ((resObj == NULL) - && (TSDB_SML_TELNET_PROTOCOL != protocol) - && (TSDB_SML_JSON_PROTOCOL != protocol) - && (SML_JSON_TAOS_FORMAT != protocol) - ) { - errorPrint("Cannot parse response into json: %s\n", start); - } - tools_cJSON* codeObj = tools_cJSON_GetObjectItem(resObj, "code"); - if ((!tools_cJSON_IsNumber(codeObj)) - && (TSDB_SML_TELNET_PROTOCOL != protocol) - && (TSDB_SML_JSON_PROTOCOL != protocol) - && (SML_JSON_TAOS_FORMAT != protocol) - ) { - char* pstr = tools_cJSON_Print(resObj); - errorPrint("Invalid or miss 'code' key in json: %s\n", pstr ? pstr : "null"); - tmfree(pstr); - tools_cJSON_Delete(resObj); - goto free_of_post; - } - - if ((SML_REST_IFACE == iface) && codeObj - && (200 == codeObj->valueint)) { - code = 0; - tools_cJSON_Delete(resObj); - goto free_of_post; - } - - if ((iface == SML_REST_IFACE) - && (protocol == TSDB_SML_LINE_PROTOCOL) - && codeObj - && (codeObj->valueint != 0) && (codeObj->valueint != 200)) { - tools_cJSON* desc = tools_cJSON_GetObjectItem(resObj, "desc"); - if (!tools_cJSON_IsString(desc)) { - char* pstr = tools_cJSON_Print(resObj); - errorPrint("Invalid or miss 'desc' key in json: %s\n", pstr ? pstr : "null"); - tmfree(pstr); - } else { - errorPrint("insert mode response, code: %d, reason: %s\n", - (int)codeObj->valueint, desc->valuestring); - } - } else { - code = 0; - } - tools_cJSON_Delete(resObj); - } -free_of_post: - free(responseBuf); - return code; -} - // fetch result fo file or nothing int64_t fetchResult(TAOS_RES *res, char * filePath) { TAOS_ROW row = NULL; @@ -1219,111 +810,6 @@ void benchSetSignal(int32_t signum, ToolsSignalHandler sigfp) { } #endif -int convertServAddr(int iface, bool tcp, int protocol) { - if (tcp - && iface == SML_REST_IFACE - && protocol == TSDB_SML_TELNET_PROTOCOL) { - // telnet_tcp_port - if (convertHostToServAddr(g_arguments->host, - g_arguments->telnet_tcp_port, - &(g_arguments->serv_addr))) { - errorPrint("%s\n", "convert host to server address"); - return -1; - } - infoPrint("convertServAddr host=%s telnet_tcp_port:%d to serv_addr=%p iface=%d \n", - g_arguments->host, g_arguments->telnet_tcp_port, &g_arguments->serv_addr, iface); - } else { - int port = g_arguments->port_inputted ? g_arguments->port:DEFAULT_REST_PORT; - if (convertHostToServAddr(g_arguments->host, - port, - &(g_arguments->serv_addr))) { - errorPrint("%s\n", "convert host to server address"); - return -1; - } - infoPrint("convertServAddr host=%s port:%d to serv_addr=%p iface=%d \n", - g_arguments->host, port, &g_arguments->serv_addr, iface); - } - return 0; -} - -static void errorPrintSocketMsg(char *msg, int result) { -#ifdef WINDOWS - errorPrint("%s: %d\n", msg, WSAGetLastError()); -#else - errorPrint("%s: %d\n", msg, result); -#endif -} - -int createSockFd() { -#ifdef WINDOWS - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); - SOCKET sockfd; -#else - int sockfd; -#endif - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) { - errorPrintSocketMsg("Could not create socket : ", sockfd); - return -1; - } - - int retConn = connect( - sockfd, (struct sockaddr *)&(g_arguments->serv_addr), - sizeof(struct sockaddr)); - infoPrint("createSockFd call connect serv_addr=%p retConn=%d\n", &g_arguments->serv_addr, retConn); - if (retConn < 0) { - errorPrint("%s\n", "failed to connect"); -#ifdef WINDOWS - closesocket(sockfd); - WSACleanup(); -#else - close(sockfd); -#endif - return -1; - } - return sockfd; -} - -static void closeSockFd(int sockfd) { -#ifdef WINDOWS - closesocket(sockfd); - WSACleanup(); -#else - close(sockfd); -#endif -} - -void destroySockFd(int sockfd) { - // check valid - if (sockfd < 0) { - return; - } - - // shutdown the connection since no more data will be sent - int result; - result = shutdown(sockfd, SHUT_WR); - if (SOCKET_ERROR == result) { - errorPrintSocketMsg("Socket shutdown failed with error: ", result); - closeSockFd(sockfd); - return; - } - // Receive until the peer closes the connection - do { - int recvbuflen = LARGE_BUFF_LEN; - char recvbuf[LARGE_BUFF_LEN]; - result = recv(sockfd, recvbuf, recvbuflen, 0); - if ( result > 0 ) { - debugPrint("Socket bytes received: %d\n", result); - } else if (result == 0) { - infoPrint("Connection closed with result %d\n", result); - } else { - errorPrintSocketMsg("Socket recv failed with error: ", result); - } - } while (result > 0); - - closeSockFd(sockfd); -} FORCE_INLINE void printErrCmdCodeStr(char *cmd, int32_t code, TAOS_RES *res) { char buff[512]; @@ -1334,7 +820,7 @@ FORCE_INLINE void printErrCmdCodeStr(char *cmd, int32_t code, TAOS_RES *res) { strcat(buff, "..."); msg = buff; } - errorPrint("failed to run error code: 0x%08x, reason: %s command %s\n", + errorPrint("%s error code: 0x%08x, reason: %s command %s\n", TIP_ENGINE_ERR, code, taos_errstr(res), msg); taos_free_result(res); } @@ -1372,6 +858,24 @@ char* genQMark( int32_t QCnt) { return buf; } +// get colNames , first is tbname if tbName is true +char *genColNames(BArray *cols, bool tbName) { + // reserve tbname,ts and "," space + char * buf = benchCalloc(TSDB_TABLE_NAME_LEN + 1, cols->size + 1, false); + if (tbName) { + strcpy(buf, "tbname,ts"); + } else { + strcpy(buf, "ts"); + } + + for (int32_t i = 0; i < cols->size; i++) { + Field * col = benchArrayGet(cols, i); + strcat(buf, ","); + strcat(buf, col->name); + } + return buf; +} + // // STMT2 // @@ -1583,17 +1087,9 @@ uint32_t MurmurHash3_32(const char *key, uint32_t len) { // init conn int32_t initQueryConn(qThreadInfo * pThreadInfo, int iface) { // create conn - if (iface == REST_IFACE) { - int sockfd = createSockFd(); - if (sockfd < 0) { - return -1; - } - pThreadInfo->sockfd = sockfd; - } else { - pThreadInfo->conn = initBenchConn(); - if (pThreadInfo->conn == NULL) { - return -1; - } + pThreadInfo->conn = initBenchConn(); + if (pThreadInfo->conn == NULL) { + return -1; } return 0; @@ -1601,17 +1097,8 @@ int32_t initQueryConn(qThreadInfo * pThreadInfo, int iface) { // close conn void closeQueryConn(qThreadInfo * pThreadInfo, int iface) { - if (iface == REST_IFACE) { -#ifdef WINDOWS - closesocket(pThreadInfo->sockfd); - WSACleanup(); -#else - close(pThreadInfo->sockfd); -#endif - } else { - closeBenchConn(pThreadInfo->conn); - pThreadInfo->conn = NULL; - } + closeBenchConn(pThreadInfo->conn); + pThreadInfo->conn = NULL; } diff --git a/tools/taos-tools/src/dumpUtil.c b/tools/taos-tools/src/dumpUtil.c index 0b684de43f..8535a2f0a7 100644 --- a/tools/taos-tools/src/dumpUtil.c +++ b/tools/taos-tools/src/dumpUtil.c @@ -15,6 +15,7 @@ #include +#include "pub.h" #include "dump.h" #include "dumpUtil.h" @@ -74,19 +75,6 @@ bool canRetry(int32_t code, int8_t type) { } } -#ifdef WEBSOCKET - int32_t wsCode = code & 0xFFFF; - // range1 - if (wsCode >= WEBSOCKET_CODE_BEGIN1 && wsCode <= WEBSOCKET_CODE_END1) { - return true; - } - // range2 - if (wsCode >= WEBSOCKET_CODE_BEGIN2 && wsCode <= WEBSOCKET_CODE_END2) { - return true; - } - -#endif - return false; } @@ -97,21 +85,81 @@ bool canRetry(int32_t code, int8_t type) { // connect TAOS *taosConnect(const char *dbName) { + // + // collect params + // + char show[256] = "\0"; + char * host = NULL; + uint16_t port = 0; + char * user = NULL; + char * pwd = NULL; + int32_t code = 0; + char * dsnc = NULL; + + // set mode + if (g_args.dsn) { + dsnc = strToLowerCopy(g_args.dsn); + if (dsnc == NULL) { + return NULL; + } + + char *cport = NULL; + char error[512] = ""; + code = parseDsn(dsnc, &host, &cport, &user, &pwd, error); + if (code) { + errorPrint("%s dsn=%s\n", error, dsnc); + free(dsnc); + return NULL; + } + + // default ws port + if (cport == NULL) { + if (user) + port = DEFAULT_PORT_WS_CLOUD; + else + port = DEFAULT_PORT_WS_LOCAL; + } else { + port = atoi(cport); + } + + // websocket + memcpy(show, g_args.dsn, 20); + memcpy(show + 20, "...", 3); + memcpy(show + 23, g_args.dsn + strlen(g_args.dsn) - 10, 10); + + } else { + + host = g_args.host; + user = g_args.user; + pwd = g_args.password; + + if (g_args.port_inputted) { + port = g_args.port; + } else { + port = g_args.connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + } + + sprintf(show, "host:%s port:%d ", host, port); + } + + // + // connect + // int32_t i = 0; + TAOS *taos = NULL; while (1) { - TAOS *taos = taos_connect(g_args.host, g_args.user, g_args.password, dbName, g_args.port); + taos = taos_connect(host, user, pwd, dbName, port); if (taos) { // successful if (i > 0) { - okPrint("Retry %d to connect %s:%d successfully!\n", i, g_args.host, g_args.port); + okPrint("Retry %d to connect %s:%d successfully!\n", i, host, port); } - return taos; + break; } // fail - errorPrint("Failed to connect to server %s, code: 0x%08x, reason: %s! \n", g_args.host, taos_errno(NULL), + errorPrint("Failed to connect to server %s, code: 0x%08x, reason: %s! \n", host, taos_errno(NULL), taos_errstr(NULL)); - if (++i > g_args.retryCount) { break; } @@ -120,7 +168,11 @@ TAOS *taosConnect(const char *dbName) { infoPrint("Retry to connect for %d after sleep %dms ...\n", i, g_args.retrySleepMs); toolsMsleep(g_args.retrySleepMs); } - return NULL; + + if (dsnc) { + free(dsnc); + } + return taos; } // query @@ -160,132 +212,6 @@ TAOS_RES *taosQuery(TAOS *taos, const char *sql, int32_t *code) { return NULL; } - -// -// --------------- websocket ------------------ -// - -#ifdef WEBSOCKET -// ws connect -WS_TAOS *wsConnect() { - int32_t i = 0; - while (1) { - WS_TAOS *ws_taos = ws_connect(g_args.dsn); - if (ws_taos) { - // successful - if (i > 0) { - okPrint("Retry %d to connect %s:%d successfully!\n", i, g_args.host, g_args.port); - } - return ws_taos; - } - - // fail - char maskedDsn[256] = "\0"; - memcpy(maskedDsn, g_args.dsn, 20); - memcpy(maskedDsn + 20, "...", 3); - memcpy(maskedDsn + 23, g_args.dsn + strlen(g_args.dsn) - 10, 10); - errorPrint("Failed to ws_connect to server %s, code: 0x%08x, reason: %s!\n", maskedDsn, ws_errno(NULL), - ws_errstr(NULL)); - - if (++i > g_args.retryCount) { - break; - } - - // retry agian - infoPrint("Retry to ws_connect for %d after sleep %dms ...\n", i, g_args.retrySleepMs); - toolsMsleep(g_args.retrySleepMs); - } - return NULL; -} - -// ws query -WS_RES *wsQuery(WS_TAOS **taos_v, const char *sql, int32_t *code) { - int32_t i = 0; - WS_RES *ws_res = NULL; - while (1) { - ws_res = ws_query_timeout(*taos_v, sql, g_args.ws_timeout); - *code = ws_errno(ws_res); - if (*code == 0) { - if (i > 0) { - okPrint("Retry %d to execute taosQuery %s successfully!\n", i, sql); - } - // successful - return ws_res; - } - - // fail - errorPrint("Failed to execute taosQuery, code: 0x%08x, reason: %s, sql=%s \n", *code, ws_errstr(ws_res), sql); - - // can retry - if(!canRetry(*code, RETRY_TYPE_QUERY)) { - infoPrint("%s", "error code not in retry range , give up retry.\n"); - return ws_res; - } - - if (++i > g_args.retryCount) { - break; - } - - // retry agian - infoPrint("Retry to execute taosQuery for %d after sleep %dms ...\n", i, g_args.retrySleepMs); - toolsMsleep(g_args.retrySleepMs); - } - - // need reconnect - infoPrint("query switch new connect to try , sql=%s \n", sql); - WS_TAOS * new_conn = wsConnect(); - if(new_conn == NULL) { - // return old - return ws_res; - } - - // use new conn to query - ws_res = ws_query_timeout(new_conn, sql, g_args.ws_timeout); - *code = ws_errno(ws_res); - if (*code == 0) { - // set new connect to old - ws_close(*taos_v); - *taos_v = new_conn; - okPrint("execute taosQuery with new connection successfully! sql=%s\n", sql); - // successful - return ws_res; - } - - // fail - errorPrint("execute taosQuery with new connection failed, code: 0x%08x, reason: %s \n", *code, ws_errstr(ws_res)); - ws_close(new_conn); - return ws_res; -} - -// fetch -int32_t wsFetchBlock(WS_RES *rs, const void **pData, int32_t *numOfRows) { - int32_t i = 0; - int32_t ws_code = TSDB_CODE_FAILED; - while (1) { - ws_code = ws_fetch_raw_block(rs, pData, numOfRows); - if (ws_code == TSDB_CODE_SUCCESS) { - // successful - if (i > 0) { - okPrint("Retry %d to fetch block successfully!\n", i); - } - return ws_code; - } - - if(!canRetry(ws_code, RETRY_TYPE_FETCH)) { - infoPrint("give up retry fetch because error code need not retry. err code=%d\n", ws_code); - break; - } - - if (++i > g_args.retryCount) { - break; - } - - // retry agian - infoPrint("Retry to ws fetch raw block for %d after sleep %dms ...\n", i, g_args.retrySleepMs); - toolsMsleep(g_args.retrySleepMs); - } - - return ws_code; -} - -#endif \ No newline at end of file +void engineError(char * module, char * fun, int32_t code) { + errorPrint("%s %s fun=%s error code:0x%08X \n", TIP_ENGINE_ERR, module, fun, code); +} \ No newline at end of file diff --git a/tools/taos-tools/src/taosdump.c b/tools/taos-tools/src/taosdump.c index e300a976b9..6c14ca080a 100644 --- a/tools/taos-tools/src/taosdump.c +++ b/tools/taos-tools/src/taosdump.c @@ -11,12 +11,10 @@ #define _GNU_SOURCE +#include "pub.h" #include "cus_name.h" // include/util/ #include "dump.h" #include "dumpUtil.h" -#ifdef WEBSOCKET -#include "wsdump.h" -#endif static char **g_tsDumpInDebugFiles = NULL; static char g_dumpInCharset[64] = {0}; @@ -152,18 +150,17 @@ static struct argp_option options[] = { {"inspect", 'I', 0, 0, "inspect avro file content and print on screen", 10}, {"no-escape", 'n', 0, 0, "No escape char '`'. Default is using it.", 10}, -#ifdef WEBSOCKET - {"restful", 'R', 0, 0, "Use RESTful interface to connect server", 11}, - {"cloud", 'C', "CLOUD_DSN", 0, - "specify a DSN to access the cloud service", 11}, + {"cloud", 'C', "CLOUD_DSN", 0, OLD_DSN_DESC, 11}, {"timeout", 't', "SECONDS", 0, "The timeout seconds for " "websocket to interact."}, -#endif {"debug", 'g', 0, 0, "Print debug info.", 15}, {"dot-replace", 'Q', 0, 0, "Repalce dot character with underline character in the table name.", 10}, - {"rename", 'W', "RENAME-LIST", 0, "Rename database name with new name during importing data. RENAME-LIST: \"db1=newDB1|db2=newDB2\" means rename db1 to newDB1 and rename db2 to newDB2", 10}, + {"rename", 'W', "RENAME-LIST", 0, "Rename database name with new name during importing data. \ + RENAME-LIST: \"db1=newDB1|db2=newDB2\" means rename db1 to newDB1 and rename db2 to newDB2", 10}, {"retry-count", 'k', "VALUE", 0, "Set the number of retry attempts for connection or query failures", 11}, {"retry-sleep-ms", 'z', "VALUE", 0, "retry interval sleep time, unit ms", 11}, + {"dsn", 'X', "DSN", 0, DSN_DESC, 11}, + {DRIVER_OPT, 'Z', "DRIVER", 0, DRIVER_DESC}, {0} }; @@ -221,15 +218,9 @@ struct arguments g_args = { false, // dotRepalce 0, // dumpDbCount -#ifdef WEBSOCKET - false, // restful - false, // cloud - 10, // ws_timeout + CONN_MODE_INVALID, // connMode NULL, // dsn - NULL, // cloudToken - 0, // cloudPort - {0}, // cloudHost -#endif // WEBSOCKET + false, // port_inputted NULL, // renameBuf NULL, // renameHead @@ -584,6 +575,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { exit(EXIT_FAILURE); } g_args.port = (uint16_t)port; + g_args.port_inputted = true; break; case 'o': @@ -700,29 +692,19 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { g_args.thread_num = atoi((const char *)arg); break; -#ifdef WEBSOCKET - case 'R': - g_args.restful = true; - break; - case 'C': + case 'X': if (arg) { - g_args.dsn = arg; + if (arg[0]!= 0) { + g_args.dsn = arg; + } + } else { errorPrint("%s", "\n\t-C need a valid cloud DSN following!\n"); exit(EXIT_FAILURE); } break; - case 't': - if (arg) { - g_args.ws_timeout = atoi(arg); - } else { - fprintf(stderr, "Invalid -t option\n"); - } - break; -#endif // WEBSOCKET - case OPT_ABORT: g_args.abort = 1; break; @@ -745,6 +727,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { g_args.retrySleepMs = atoi((const char *)arg); printf(" set argument retry interval sleep = %d ms\n", g_args.retrySleepMs); break; + case 'Z': + g_args.connMode = getConnMode(arg); + break; + default: return ARGP_ERR_UNKNOWN; } @@ -1082,7 +1068,7 @@ static int getTableRecordInfoImplNative( return -1; } -static int getTableRecordInfoNative( +static int getTableRecordInfo( char *dbName, char *table, TableRecordInfo *pTableRecordInfo) { if (0 == getTableRecordInfoImplNative( @@ -1097,22 +1083,6 @@ static int getTableRecordInfoNative( return -1; } -static int getTableRecordInfo( - char *dbName, - char *table, TableRecordInfo *pTableRecordInfo) { - int ret; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ret = getTableRecordInfoWS(dbName, table, pTableRecordInfo); - } else { -#endif - ret = getTableRecordInfoNative(dbName, table, pTableRecordInfo); -#ifdef WEBSOCKET - } -#endif - return ret; -} - bool isSystemDatabase(char *dbName) { if (g_majorVersionOfClient == 3) { if ((strcmp(dbName, "information_schema") == 0) @@ -1214,46 +1184,20 @@ static int getDumpDbCount() { int32_t code = -1; -#ifdef WEBSOCKET - WS_TAOS *ws_taos = NULL; - WS_RES *ws_res; - /* Connect to server */ - if (g_args.cloud || g_args.restful) { - if (NULL == (ws_taos = wsConnect())) { - free(command); - return 0; - } - - int32_t ws_code = -1; - ws_res = wsQuery(&ws_taos, command, &ws_code); - if (0 != ws_code) { - cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - ws_close(ws_taos); - return 0; - } - - count = getDbCountWS(ws_res); - ws_free_result(ws_res); - ws_close(ws_taos); - } else { -#endif // WEBSOCKET - if (NULL == (taos = taosConnect(NULL))) { - free(command); - return 0; - } - res = taosQuery(taos, command, &code); - if (0 != code) { - cleanIfQueryFailed(__func__, __LINE__, command, res); - taos_close(taos); - return 0; - } - - count = getDbCountNative(res); - taos_free_result(res); - taos_close(taos); -#ifdef WEBSOCKET + if (NULL == (taos = taosConnect(NULL))) { + free(command); + return 0; } -#endif + res = taosQuery(taos, command, &code); + if (0 != code) { + cleanIfQueryFailed(__func__, __LINE__, command, res); + taos_close(taos); + return 0; + } + + count = getDbCountNative(res); + taos_free_result(res); + taos_close(taos); free(command); return count; @@ -2043,18 +1987,8 @@ char *queryCreateTableSql(void** taos_v, const char *dbName, char *tbName) { // read uint32_t len = 0; char* data = 0; - int32_t ret; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ret = readRowWS(res, 0, 1, &len, &data); - } else { -#endif - ret = readRow(res, 0, 1, &len, &data); -#ifdef WEBSOCKET - } -#endif - + int32_t ret = readRow(res, 0, 1, &len, &data); if (ret != 0) { closeQuery(res); return NULL; @@ -2506,20 +2440,10 @@ static int dumpStableClasuse( const char *stbName, TableDes **pStbTableDes, FILE *fp) { - int colCount = -1; + TableDes *tableDes = *pStbTableDes; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - colCount = getTableDesWS( - taos_v, dbInfo->name, + int32_t colCount = getTableDesNative(*taos_v, dbInfo->name, stbName, tableDes, true); - } else { -#endif - colCount = getTableDesNative(*taos_v, dbInfo->name, - stbName, tableDes, true); -#ifdef WEBSOCKET - } -#endif if (colCount < 0) { errorPrint("%s() LN%d, failed to get stable[%s] schema\n", @@ -3480,7 +3404,6 @@ int64_t queryDbForDumpOutCount( const char *dbName, const char *tbName, const int precision) { - int64_t count = -1; char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); if (NULL == command) { errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); @@ -3499,17 +3422,8 @@ int64_t queryDbForDumpOutCount( dbName, g_escapeChar, tbName, g_escapeChar, startTime, endTime); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - count = queryDbForDumpOutCountWS( - command, taos_v, dbName, tbName, precision); - } else { -#endif - count = queryDbForDumpOutCountNative( + int64_t count = queryDbForDumpOutCountNative( command, *taos_v, dbName, tbName, precision); -#ifdef WEBSOCKET - } -#endif return count; } @@ -3563,16 +3477,7 @@ void *queryDbForDumpOutOffset( start_time, end_time, limit, offset); } - void *res = NULL; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - res = queryDbForDumpOutOffsetWS(taos_v, command); - } else { -#endif - res = queryDbForDumpOutOffsetNative(*taos_v, command); -#ifdef WEBSOCKET - } -#endif + void *res = queryDbForDumpOutOffsetNative(*taos_v, command); return res; } @@ -4697,17 +4602,8 @@ static int64_t dumpInAvroTbTagsImpl( if ((0 == strlen(tableDes->name)) || (0 != strcmp(tableDes->name, stbName))) { -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - getTableDesWS(taos_v, namespace, + getTableDesNative(*taos_v, namespace, stbName, tableDes, false); - } else { -#endif - getTableDesNative(*taos_v, namespace, - stbName, tableDes, false); -#ifdef WEBSOCKET - } -#endif } avro_value_get_by_name(&value, "tbname", &field_value, NULL); @@ -4831,34 +4727,16 @@ static int64_t dumpInAvroTbTagsImpl( curr_sqlstr_len += sprintf(sqlstr + curr_sqlstr_len-1, ")"); debugPrint("%s() LN%d, sqlstr=\n%s\n", __func__, __LINE__, sqlstr); freeTbNameIfLooseMode(stbName); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, sqlstr, &ws_code); - if (ws_code != 0) { - warnPrint("%s() LN%d ws_query() failed! reason: %s\n", - __func__, __LINE__, ws_errstr(ws_res)); - failed++; - } else { - success++; - } - ws_free_result(ws_res); - ws_res = NULL; + int32_t code = -1; + TAOS_RES *res = taosQuery(*taos_v, sqlstr, &code); + if (code != 0) { + warnPrint("%s() LN%d taosQuery() failed! sqlstr: %s, reason: %s\n", + __func__, __LINE__, sqlstr, taos_errstr(res)); + failed++; } else { -#endif - int32_t code = -1; - TAOS_RES *res = taosQuery(*taos_v, sqlstr, &code); - if (code != 0) { - warnPrint("%s() LN%d taosQuery() failed! sqlstr: %s, reason: %s\n", - __func__, __LINE__, sqlstr, taos_errstr(res)); - failed++; - } else { - success++; - } - taos_free_result(res); -#ifdef WEBSOCKET + success++; } -#endif + taos_free_result(res); } avro_value_decref(&value); @@ -4910,40 +4788,20 @@ static int64_t dumpInAvroNtbImpl( buf = newBuf; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, buf, &ws_code); - if (0 != ws_code) { - errorPrint("%s() LN%d," - " Failed to execute ws_query(%s)." - " ws_taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, buf, - *taos_v, ws_code, ws_errstr(ws_res)); - failed++; - } else { - success++; - } - ws_free_result(ws_res); - ws_res = NULL; + int32_t code = -1; + TAOS_RES *res = taosQuery(*taos_v, buf, &code); + if (0 != code) { + errorPrint("%s() LN%d," + " Failed to execute taosQuery(%s)." + " taos: %p, code: 0x%08x, reason: %s\n", + __func__, __LINE__, buf, + *taos_v, code, taos_errstr(res)); + failed++; } else { -#endif - int32_t code = -1; - TAOS_RES *res = taosQuery(*taos_v, buf, &code); - if (0 != code) { - errorPrint("%s() LN%d," - " Failed to execute taosQuery(%s)." - " taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, buf, - *taos_v, code, taos_errstr(res)); - failed++; - } else { - success++; - } - taos_free_result(res); -#ifdef WEBSOCKET + success++; } -#endif + taos_free_result(res); + // free if (newBuf) { free(newBuf); @@ -5589,6 +5447,39 @@ static void countFailureAndFree(char *bindArray, freeTbNameIfLooseMode(tbName); } +// stmt prepare +static int32_t prepareStmt(TAOS_STMT *stmt, RecordSchema *recordSchema, char *tbName, int32_t *onlyCol) { + char *sql = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); + if (NULL == sql) { + errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); + return -1; + } + + char *pstr = sql; + pstr += snprintf(pstr, TSDB_MAX_ALLOWED_SQL_LEN, "INSERT INTO %s VALUES(?", tbName); + + for (int col = 1; col < recordSchema->num_fields + -(g_dumpInLooseModeFlag?0:1); col++) { + pstr += sprintf(pstr, ",?"); + (*onlyCol)++; + } + pstr += sprintf(pstr, ")"); + debugPrint("%s() LN%d, stmt buffer: %s\n", + __func__, __LINE__, sql); + + int code; + if (0 != (code = taos_stmt_prepare(stmt, sql, 0))) { + errorPrint("Failed to execute taos_stmt_prepare(). sql:%s reason: %s\n", + sql, taos_stmt_errstr(stmt)); + + free(sql); + return -1; + } + + free(sql); + return code; +} + static int64_t dumpInAvroDataImpl( void **taos_v, char *namespace, @@ -5597,126 +5488,30 @@ static int64_t dumpInAvroDataImpl( RecordSchema *recordSchema, char *fileName) { TAOS_STMT *stmt = NULL; -#ifdef WEBSOCKET - WS_STMT *ws_stmt = NULL; - if (g_args.cloud || g_args.restful) { - ws_stmt = ws_stmt_init(*taos_v); - int32_t ws_code = ws_errno(ws_stmt); - if (ws_code) { - errorPrint("%s() LN%d, stmt init failed! ws_taos: %p," - " code: 0x%08x, reason: %s\n", - __func__, __LINE__, *taos_v, ws_code, ws_errstr(ws_stmt)); - return -1; - } - } else { -#endif - stmt = taos_stmt_init(*taos_v); - if (NULL == stmt) { - errorPrint("%s() LN%d, stmt init failed! taos: %p, code: 0x%08x, " - "reason: %s\n", - __func__, __LINE__, *taos_v, - taos_errno(NULL), taos_errstr(NULL)); - return -1; - } -#ifdef WEBSOCKET + stmt = taos_stmt_init(*taos_v); + if (NULL == stmt) { + errorPrint("%s() LN%d, stmt init failed! taos: %p, code: 0x%08x, " + "reason: %s\n", + __func__, __LINE__, *taos_v, + taos_errno(NULL), taos_errstr(NULL)); + return -1; } -#endif TableDes *tableDes = (TableDes *)calloc(1, sizeof(TableDes) + sizeof(ColDes) * TSDB_MAX_COLUMNS); if (NULL == tableDes) { errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_stmt_close(ws_stmt); - } else { -#endif - taos_stmt_close(stmt); -#ifdef WEBSOCKET - } -#endif + taos_stmt_close(stmt); return -1; } - char *stmtBuffer = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == stmtBuffer) { - errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); - free(tableDes); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_stmt_close(ws_stmt); - } else { -#endif - taos_stmt_close(stmt); -#ifdef WEBSOCKET - } -#endif - return -1; - } - - char *pstr = stmtBuffer; - pstr += snprintf(pstr, TSDB_MAX_ALLOWED_SQL_LEN, "INSERT INTO ? VALUES(?"); - - int32_t onlyCol = 1; // at least timestamp - for (int col = 1; col < recordSchema->num_fields - -(g_dumpInLooseModeFlag?0:1); col++) { - pstr += sprintf(pstr, ",?"); - onlyCol++; - } - pstr += sprintf(pstr, ")"); - debugPrint("%s() LN%d, stmt buffer: %s\n", - __func__, __LINE__, stmtBuffer); - - int code; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if (0 != (code = ws_stmt_prepare(ws_stmt, stmtBuffer, strlen(stmtBuffer)))) { - errorPrint("%s() LN%d, failed to execute ws_stmt_prepare()." - " ws_taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, - *taos_v, code, ws_errstr(ws_stmt)); - - free(stmtBuffer); - free(tableDes); - ws_stmt_close(ws_stmt); - return -1; - } - } else { -#endif - if (0 != (code = taos_stmt_prepare(stmt, stmtBuffer, 0))) { - errorPrint("Failed to execute taos_stmt_prepare(). reason: %s\n", - taos_stmt_errstr(stmt)); - - free(stmtBuffer); - free(tableDes); - taos_stmt_close(stmt); - return -1; - } -#ifdef WEBSOCKET - } -#endif + int32_t code = 0; + int32_t onlyCol = 1; + char *bindArray = NULL; avro_value_iface_t *value_class = avro_generic_class_from_schema(schema); avro_value_t value; avro_generic_value_new(value_class, &value); - char *bindArray = - calloc(1, sizeof(TAOS_MULTI_BIND) * onlyCol); - if (NULL == bindArray) { - errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); - free(stmtBuffer); - free(tableDes); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_stmt_close(ws_stmt); - } else { -#endif - taos_stmt_close(stmt); -#ifdef WEBSOCKET - } -#endif - return -1; - } - int64_t success = 0; int64_t failed = 0; int64_t count = 0; @@ -5757,78 +5552,48 @@ static int64_t dumpInAvroDataImpl( char *escapedTbName = calloc(1, escapedTbNameLen); if (NULL == escapedTbName) { errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); - free(bindArray); - free(stmtBuffer); free(tableDes); tfree(tbName); - #ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_stmt_close(ws_stmt); - } else { - #endif - taos_stmt_close(stmt); - #ifdef WEBSOCKET - } - #endif + taos_stmt_close(stmt); return -1; } - #ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - snprintf(escapedTbName, escapedTbNameLen, "%s.%s%s%s", - namespace, g_escapeChar, tbName, g_escapeChar); + snprintf(escapedTbName, escapedTbNameLen, "%s%s%s", + g_escapeChar, tbName, g_escapeChar); - debugPrint("%s() LN%d escaped table: %s\n", - __func__, __LINE__, escapedTbName); + debugPrint("%s() LN%d escaped table: %s\n", + __func__, __LINE__, escapedTbName); - debugPrint("%s() LN%d, stmt: %p, will call ws_stmt_set_tbname(%s)\n", - __func__, __LINE__, ws_stmt, escapedTbName); - if (0 != (code = ws_stmt_set_tbname(ws_stmt, escapedTbName))) { - errorPrint("%s() LN%d, failed to execute ws_stmt_set_tbname(%s)." - " ws_taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, - escapedTbName, *taos_v, code, ws_errstr(ws_stmt)); - free(escapedTbName); - freeTbNameIfLooseMode(tbName); - continue; - } - debugPrint("%s() LN%d, stmt: %p, ws_stmt_set_tbname(%s) done\n", - __func__, __LINE__, ws_stmt, escapedTbName); - } else { - #endif - snprintf(escapedTbName, escapedTbNameLen, "%s%s%s", - g_escapeChar, tbName, g_escapeChar); - - debugPrint("%s() LN%d escaped table: %s\n", - __func__, __LINE__, escapedTbName); - - if (0 != taos_stmt_set_tbname(stmt, escapedTbName)) { - errorPrint("Failed to execute taos_stmt_set_tbname(%s)." - "reason: %s\n", - escapedTbName, taos_stmt_errstr(stmt)); - free(escapedTbName); - free(tbName); - tbName = NULL; - continue; - } - #ifdef WEBSOCKET + // prepare + code = prepareStmt(stmt, recordSchema, escapedTbName, &onlyCol); + if (code) { + free(tableDes); + free(tbName); + free(escapedTbName); + taos_stmt_close(stmt); + return -1; + } + + // maloc bind + if (bindArray == NULL) { + bindArray = calloc(1, sizeof(TAOS_MULTI_BIND) * onlyCol); + if (NULL == bindArray) { + errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); + free(tableDes); + free(tbName); + free(escapedTbName); + taos_stmt_close(stmt); + return -1; + } } - #endif free(escapedTbName); + + // get table des if ((0 == strlen(tableDes->name)) || (0 != strcmp(tableDes->name, tbName))) { - #ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - getTableDesWS(taos_v, namespace, + getTableDesNative(*taos_v, namespace, tbName, tableDes, true); - } else { - #endif - getTableDesNative(*taos_v, namespace, - tbName, tableDes, true); - #ifdef WEBSOCKET - } - #endif - } + } } // tbName debugPrint("%s() LN%d, count: %"PRId64"\n", @@ -6044,133 +5809,62 @@ static int64_t dumpInAvroDataImpl( bind->num = 1; } debugPrint2("%s", "\n"); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if (0 != (code = ws_stmt_bind_param_batch(ws_stmt, - (const WS_MULTI_BIND *)bindArray, onlyCol))) { - errorPrint("%s() LN%d ws_stmt_bind_param_batch() failed!" - " ws_taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, *taos_v, code, ws_errstr(ws_stmt)); - countFailureAndFree(bindArray, onlyCol, &failed, tbName); - continue; - } - - if (0 != (code = ws_stmt_add_batch(ws_stmt))) { - errorPrint("%s() LN%d stmt_bind_param() failed!" - " ws_taos: %p, code: 0x%08x, reason: %s\n", - __func__, __LINE__, *taos_v, code, ws_errstr(ws_stmt)); - countFailureAndFree(bindArray, onlyCol, &failed, tbName); - continue; - } - - if ( 0 == (count % g_args.data_batch) ) { - // batch to exec - int32_t affected_rows; - if (0 != (code = ws_stmt_execute(ws_stmt, &affected_rows))) { - errorPrint("%s() LN%d ws_stmt_execute() failed!" - " ws_taos: %p, code: 0x%08x, reason: %s, " - "timestamp: %"PRId64" count=%"PRId64"\n", - __func__, __LINE__, *taos_v, code, - ws_errstr(ws_stmt), ts_debug, count); - countFailureAndFree(bindArray, onlyCol, &failed, tbName); - continue; - } else { - success += g_args.data_batch; - debugPrint("ok call ws_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", - count, success, failed); - } - } - } else { -#endif - if (0 != (code = taos_stmt_bind_param_batch(stmt, - (TAOS_MULTI_BIND *)bindArray))) { - errorPrint("%s() LN%d stmt_bind_param_batch() failed! " - "reason: %s\n", - __func__, __LINE__, taos_stmt_errstr(stmt)); - countFailureAndFree(bindArray, onlyCol, &failed, tbName); - continue; - } - - if (0 != (code = taos_stmt_add_batch(stmt))) { - errorPrint("%s() LN%d stmt_bind_param() failed! reason: %s\n", + if (0 != (code = taos_stmt_bind_param_batch(stmt, + (TAOS_MULTI_BIND *)bindArray))) { + errorPrint("%s() LN%d stmt_bind_param_batch() failed! " + "reason: %s\n", __func__, __LINE__, taos_stmt_errstr(stmt)); + countFailureAndFree(bindArray, onlyCol, &failed, tbName); + continue; + } + + if (0 != (code = taos_stmt_add_batch(stmt))) { + errorPrint("%s() LN%d stmt_bind_param() failed! reason: %s\n", + __func__, __LINE__, taos_stmt_errstr(stmt)); + countFailureAndFree(bindArray, onlyCol, &failed, tbName); + continue; + } + + // batch execute + if ( 0 == (count % g_args.data_batch) ) { + if( 0 != (code = taos_stmt_execute(stmt)) ){ + if (code == TSDB_CODE_TDB_TIMESTAMP_OUT_OF_RANGE) { + countTSOutOfRange++; + } else { + errorPrint("%s() LN%d taos_stmt_execute() failed! " + "code: 0x%08x, reason: %s, timestamp: %"PRId64"\n", + __func__, __LINE__, + code, taos_stmt_errstr(stmt), ts_debug); + } countFailureAndFree(bindArray, onlyCol, &failed, tbName); continue; + } else { + success += g_args.data_batch; + debugPrint("ok call taos_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", + count, success, failed); } - - // batch execute - if ( 0 == (count % g_args.data_batch) ) { - if( 0 != (code = taos_stmt_execute(stmt)) ){ - if (code == TSDB_CODE_TDB_TIMESTAMP_OUT_OF_RANGE) { - countTSOutOfRange++; - } else { - errorPrint("%s() LN%d taos_stmt_execute() failed! " - "code: 0x%08x, reason: %s, timestamp: %"PRId64"\n", - __func__, __LINE__, - code, taos_stmt_errstr(stmt), ts_debug); - } - countFailureAndFree(bindArray, onlyCol, &failed, tbName); - continue; - } else { - success += g_args.data_batch; - debugPrint("ok call taos_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", - count, success, failed); - } - } -#ifdef WEBSOCKET } -#endif freeBindArray(bindArray, onlyCol); } // last batch execute -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if ( 0 != (count % g_args.data_batch) ) { - int32_t affected_rows; - if (0 != (code = ws_stmt_execute(ws_stmt, &affected_rows))) { - errorPrint( - "%s() LN%d ws_stmt_execute() failed!" - " ws_taos: %p, code: 0x%08x, reason: %s \n", - __func__, __LINE__, *taos_v, code, ws_errstr(ws_stmt)); - failed++; - } else { - success += count % g_args.data_batch; - debugPrint("ok call last ws_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", - count, success, failed); - } + if (0 != (count % g_args.data_batch)) { + if (0 != (code = taos_stmt_execute(stmt))) { + errorPrint("error last execute taos_stmt_execute. errstr=%s\n", taos_stmt_errstr(stmt)); + failed++; + } else { + success += count % g_args.data_batch; + debugPrint("ok call last ws_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", + count, success, failed); } - } else { -#endif - if (0 != (count % g_args.data_batch)) { - if (0 != (code = taos_stmt_execute(stmt))) { - errorPrint("error last execute taos_stmt_execute. errstr=%s\n", taos_stmt_errstr(stmt)); - failed++; - } else { - success += count % g_args.data_batch; - debugPrint("ok call last ws_stmt_execute count=%"PRId64" success=%"PRId64" failed=%"PRId64"\n", - count, success, failed); - } - } -#ifdef WEBSOCKET } -#endif free(tbName); avro_value_decref(&value); avro_value_iface_decref(value_class); tfree(bindArray); - tfree(stmtBuffer); freeTbDes(tableDes, true); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_stmt_close(ws_stmt); - } else { -#endif - taos_stmt_close(stmt); -#ifdef WEBSOCKET - } -#endif + taos_stmt_close(stmt); if (failed) { if (countTSOutOfRange) { errorPrint("Total %"PRId64" record(s) ts out of range!\n", @@ -6266,15 +5960,7 @@ static RecordSchema *getSchemaAndReaderFromFile( } static void closeTaosConnWrapper(void *taos) { -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_close(taos); - } else { -#endif - taos_close(taos); -#ifdef WEBSOCKET - } -#endif + taos_close(taos); } static int64_t dumpInOneAvroFile( @@ -6310,22 +5996,10 @@ static int64_t dumpInOneAvroFile( TAOS *taos = NULL; void **taos_v = NULL; -#ifdef WEBSOCKET - WS_TAOS *ws_taos = NULL; - if (g_args.cloud || g_args.restful) { - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - taos_v = &ws_taos; - } else { -#endif - if (NULL == (taos = taosConnect(namespace))) { - return -1; - } - taos_v = &taos; -#ifdef WEBSOCKET + if (NULL == (taos = taosConnect(namespace))) { + return -1; } -#endif + taos_v = &taos; int64_t retExec = 0; switch (avroType) { @@ -7028,27 +6702,15 @@ static int64_t dumpTableDataAvro( return -1; } - int64_t rows; - int64_t start_time = getStartTime(precision); int64_t end_time = getEndTime(precision); if ((-1 == start_time) || (-1 == end_time)) { return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - rows = dumpTableDataAvroWS(dataFilename, index, tbName, + int64_t rows = dumpTableDataAvroNative(dataFilename, index, tbName, belongStb, dbInfo->name, precision, colCount, tableDes, start_time, end_time); - } else { -#endif - rows = dumpTableDataAvroNative(dataFilename, index, tbName, - belongStb, dbInfo->name, precision, colCount, tableDes, - start_time, end_time); -#ifdef WEBSOCKET - } -#endif return rows; } @@ -7093,18 +6755,9 @@ static int64_t dumpTableData( return -1; } - int64_t rows; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - rows = dumpTableDataWS(index, fp, tbName, dbInfo->name, + + int64_t rows = dumpTableDataNative(index, fp, tbName, dbInfo->name, precision, tableDes, start_time, end_time); - } else { -#endif - rows = dumpTableDataNative(index, fp, tbName, dbInfo->name, - precision, tableDes, start_time, end_time); -#ifdef WEBSOCKET - } -#endif return rows; } @@ -7138,17 +6791,8 @@ int64_t dumpNormalTable( __func__, __LINE__); return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - numColsAndTags = getTableDesWS(taos_v, + numColsAndTags = getTableDesNative(*taos_v, dbInfo->name, tbName, tableDes, !belongStb); - } else { -#endif - numColsAndTags = getTableDesNative(*taos_v, - dbInfo->name, tbName, tableDes, !belongStb); -#ifdef WEBSOCKET - } -#endif if (numColsAndTags < 0) { errorPrint("%s() LN%d, failed to get table[%s] schema\n", @@ -7169,18 +6813,8 @@ int64_t dumpNormalTable( errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - numColsAndTags = getTableDesWS( - taos_v, + numColsAndTags = getTableDesNative(*taos_v, dbInfo->name, tbName, tableDes, !belongStb); - } else { -#endif - numColsAndTags = getTableDesNative(*taos_v, - dbInfo->name, tbName, tableDes, !belongStb); -#ifdef WEBSOCKET - } -#endif if (numColsAndTags < 0) { errorPrint("%s() LN%d, failed to get table[%s] schema\n", @@ -7242,22 +6876,9 @@ int64_t dumpNormalTable( __func__, __LINE__); return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - numColsAndTags = getTableDesFromStbWS( - taos_v, - dbInfo->name, - stbDes, - tbName, &tableDes); - - } else { -#endif - numColsAndTags = getTableDesFromStbNative( + numColsAndTags = getTableDesFromStbNative( *taos_v, dbInfo->name, stbDes, tbName, &tableDes); -#ifdef WEBSOCKET - } -#endif if (numColsAndTags < 0) { errorPrint("%s() LN%d columns/tags count is %d\n", __func__, __LINE__, numColsAndTags); @@ -7416,34 +7037,10 @@ static int createMTableAvroHeadImp( return -1; } - int colCount = 0; - colCount = colCount; // reduce compile warning -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - colCount = getTableDesFromStbWS( - (WS_TAOS*)taos_v, - dbName, + getTableDesFromStbNative(*taos_v, dbName, stbTableDes, tbName, &subTableDes); - } else { -#endif // WEBSOCKET - colCount = getTableDesFromStbNative(*taos_v, dbName, - stbTableDes, - tbName, - &subTableDes); -#ifdef WEBSOCKET - } - - if (colCount < 0) { - errorPrint("%s() LN%d, columns count is %d\n", - __func__, __LINE__, colCount); - if (subTableDes) { - freeTbDes(subTableDes, true); - } - return -1; - } -#endif for (int tag = 0; tag < subTableDes->tags; tag++) { debugPrint("%s() LN%d, sub table %s no. %d tags is %s, " @@ -7785,15 +7382,7 @@ static int createMTableAvroHeadSpecified( return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - getTableDesWS(taos_v, dbName, stable, stbTableDes, false); - } else { -#endif - getTableDesNative(*taos_v, dbName, stable, stbTableDes, false); -#ifdef WEBSOCKET - } -#endif + getTableDesNative(*taos_v, dbName, stable, stbTableDes, false); char *jsonTagsSchema = NULL; if (0 != convertTbTagsDesToJsonWrap( @@ -7925,19 +7514,8 @@ static int64_t fillTbNameArr( debugPrint("%s() LN%d, run command <%s>.\n", __func__, __LINE__, command2); - int64_t ntbCount; - -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ntbCount = fillTbNameArrWS( - taos_v, command2, tbNameArr, stable, preCount); - } else { -#endif - ntbCount = fillTbNameArrNative( + int64_t ntbCount = fillTbNameArrNative( *taos_v, command2, tbNameArr, stable, preCount); -#ifdef WEBSOCKET - } -#endif infoPrint("The number of tables of %s be filled is %"PRId64"!\n", stable, ntbCount); @@ -8313,46 +7891,21 @@ static int writeTagsToAvro( // open query with native or websocket void* openQuery(void** taos_v, const char * sql) { -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, sql, &ws_code); - if (ws_code != 0) { - errorPrint("exe sql:%s failed. error code =%d\n", sql, ws_code); - return NULL; - } - return ws_res; - } else { -#endif - int32_t code = -1; - TAOS_RES* res = taosQuery(*taos_v, sql, &code); - if (code != 0) { - taos_free_result(res); - errorPrint("open query: %s execute failed. errcode=%d\n", sql, code); - return NULL; - } - return res; -#ifdef WEBSOCKET + int32_t code = -1; + TAOS_RES* res = taosQuery(*taos_v, sql, &code); + if (code != 0) { + taos_free_result(res); + errorPrint("open query: %s execute failed. errcode=%d\n", sql, code); + return NULL; } -#endif + return res; } // close query and free result void closeQuery(void* res) { -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if(res) { - ws_free_result(res); - } - return ; - } else { -#endif - if(res) { - taos_free_result(res); - } -#ifdef WEBSOCKET - } -#endif + if(res) { + taos_free_result(res); + } } // read next table tags to tbDes @@ -8477,11 +8030,6 @@ static int dumpStableMeta( return -1; } -#ifdef WEBSOCKET - int idx = 0; - int cnt = 0; -#endif - // loop read tables des int size = sizeof(TableDes) + sizeof(ColDes) * stbDes->tags; TableDes *tbDes = calloc(1, size); @@ -8492,16 +8040,7 @@ static int dumpStableMeta( memset(tbDes->name, 0, sizeof(tbDes->name)); // reset zero tbDes->tags = stbDes->tags; // stable tags same with child table memcpy(tbDes->cols, &stbDes->cols[stbDes->columns], sizeof(ColDes)* stbDes->tags); // copy tag info - int ret; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ret = readNextTableDesWS(tagsRes, tbDes, &idx, &cnt); - } else { -#endif - ret = readNextTableDesNative(tagsRes, tbDes); -#ifdef WEBSOCKET - } -#endif + int32_t ret = readNextTableDesNative(tagsRes, tbDes); if(ret < 0){ // read error @@ -8654,6 +8193,8 @@ static void printArgs(FILE *file) { fprintf(file, "loose_mode: %s\n", g_args.loose_mode?"true":"false"); fprintf(file, "isDumpIn: %s\n", g_args.isDumpIn?"true":"false"); fprintf(file, "arg_list_len: %d\n", g_args.arg_list_len); + +/* TODO #ifdef WEBSOCKET if (g_args.cloud) { fprintf(file, "cloud: %s\n", g_args.cloud?"true":"false"); @@ -8670,6 +8211,7 @@ static void printArgs(FILE *file) { } } #endif // WEBSOCKET +*/ fflush(file); } @@ -8870,17 +8412,8 @@ static int dumpExtraInfoHead(void *taos, FILE *fp) { return -1; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - snprintf(buffer, BUFFER_LEN, "#!server_ver: %s\n", - ws_get_server_info(taos)); - } else { -#endif - snprintf(buffer, BUFFER_LEN, "#!server_ver: %s\n", + snprintf(buffer, BUFFER_LEN, "#!server_ver: %s\n", taos_get_server_info(taos)); -#ifdef WEBSOCKET - } -#endif char *firstline = strchr(buffer, '\n'); @@ -8964,15 +8497,7 @@ static int dumpExtraInfo(void **taos_v, FILE *fp) { return ret; } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - dumpExtraInfoVarWS(taos_v, fp); - } else { -#endif - dumpExtraInfoVar(*taos_v, fp); -#ifdef WEBSOCKET - } -#endif + dumpExtraInfoVar(*taos_v, fp); ret = ferror(fp); @@ -9165,15 +8690,7 @@ static int64_t dumpInOneDebugFile( } debugPrint("%s() LN%d, cmd: %s\n", __func__, __LINE__, cmd); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ret = queryDbImplWS(taos_v, newSql?newSql:cmd); - } else { -#endif - ret = queryDbImplNative(*taos_v, newSql?newSql:cmd); -#ifdef WEBSOCKET - } -#endif + ret = queryDbImplNative(*taos_v, newSql?newSql:cmd); // free if (newSql) { free(newSql); @@ -9305,23 +8822,11 @@ static int dumpInDebugWorkThreads(const char *dbPath) { " from %"PRId64"\n", t, pThreadInfo->count, pThreadInfo->from); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if (NULL == (pThreadInfo->taos = wsConnect())) { - free(infos); - free(pids); - return -1; - } - } else { -#endif // WEBSOCKET - if (NULL == (pThreadInfo->taos = taosConnect(NULL))) { - free(infos); - free(pids); - return -1; - } -#ifdef WEBSOCKET + if (NULL == (pThreadInfo->taos = taosConnect(NULL))) { + free(infos); + free(pids); + return -1; } -#endif // WEBSOCKET if (pthread_create(pids + t, NULL, dumpInDebugWorkThreadFp, (void*)pThreadInfo) != 0) { @@ -9344,15 +8849,7 @@ static int dumpInDebugWorkThreads(const char *dbPath) { } for (int32_t t = 0; t < threads; ++t) { -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_close(infos[t].taos); - } else { -#endif - taos_close(infos[t].taos); -#ifdef WEBSOCKET - } -#endif // WEBSOCKET + taos_close(infos[t].taos); } for (int32_t t = 0; t < threads; ++t) { @@ -9371,22 +8868,10 @@ static int dumpInDebugWorkThreads(const char *dbPath) { static int dumpInDbs(const char *dbPath) { void **taos_v = NULL; TAOS *taos = NULL; -#ifdef WEBSOCKET - WS_TAOS *ws_taos = NULL; - if (g_args.cloud || g_args.restful) { - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - taos_v = &ws_taos; - } else { -#endif - if (NULL == (taos = taosConnect(NULL))) { - return -1; - } - taos_v = &taos; -#ifdef WEBSOCKET + if (NULL == (taos = taosConnect(NULL))) { + return -1; } -#endif + taos_v = &taos; char dbsSql[MAX_PATH_LEN]; snprintf(dbsSql, MAX_PATH_LEN, "%s/%s", dbPath, "dbs.sql"); @@ -9628,15 +9113,7 @@ static void *dumpTablesOfStbThread(void *arg) { } } -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - dumpNormalTablesOfStbWS(pThreadInfo, fp, dumpFilename); - } else { -#endif - dumpTablesOfStbNative(pThreadInfo, fp, dumpFilename); -#ifdef WEBSOCKET - } -#endif + dumpTablesOfStbNative(pThreadInfo, fp, dumpFilename); if (fp) { fclose(fp); fp = NULL; @@ -9665,28 +9142,11 @@ int dumpSTableData(SDbInfo* dbInfo, TableDes* stbDes, char** tbNameArr, int64_t threadInfo *pThreadInfo; for (int32_t i = 0; i < threads; i++) { pThreadInfo = infos + i; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - if (NULL == (pThreadInfo->taos = wsConnect())) { - errorPrint("%s() LN%d, Failed to connect to server, " - "reason: %s\n", - __func__, - __LINE__, - ws_errstr(NULL)); - free(pids); - free(infos); - return -1; - } - } else { -#endif // WEBSOCKET - if (NULL == (pThreadInfo->taos = taosConnect(dbInfo->name))) { - free(pids); - free(infos); - return -1; - } -#ifdef WEBSOCKET + if (NULL == (pThreadInfo->taos = taosConnect(dbInfo->name))) { + free(pids); + free(infos); + return -1; } -#endif pThreadInfo->threadIndex = i; pThreadInfo->count = (i < mod) ? batch+1 : batch; @@ -9727,15 +9187,7 @@ int dumpSTableData(SDbInfo* dbInfo, TableDes* stbDes, char** tbNameArr, int64_t stbDes->name, tbCount); for (int32_t i = 0; i < threads; i++) { pThreadInfo = infos + i; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ws_close(pThreadInfo->taos); - } else { -#endif // WEBSOCKET - taos_close(pThreadInfo->taos); -#ifdef WEBSOCKET - } -#endif + taos_close(pThreadInfo->taos); } free(pids); @@ -9776,18 +9228,8 @@ static int64_t dumpStable( } // obtain stable des data - int colCount = 0; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - colCount = getTableDesWS(taos_v, dbInfo->name, + int32_t colCount = getTableDesNative(*taos_v, dbInfo->name, stbName, stbDes, true); - } else { -#endif - colCount = getTableDesNative(*taos_v, dbInfo->name, - stbName, stbDes, true); -#ifdef WEBSOCKET - } -#endif if (colCount < 0) { errorPrint("%s() LN%d, failed to get stable[%s] schema\n", __func__, __LINE__, stbName); @@ -9799,16 +9241,7 @@ static int64_t dumpStable( stbName, stbDes->columns, stbDes->tags); // get stable child count - int64_t tbCount = 0; -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - tbCount = getNtbCountOfStbWS(dbInfo->name, stbName); - } else { -#endif - tbCount = getTbCountOfStbNative(dbInfo->name, stbName); -#ifdef WEBSOCKET - } -#endif + int64_t tbCount = getTbCountOfStbNative(dbInfo->name, stbName); if(tbCount < 0 ) { errorPrint("get stable %s failed.", stbName); freeTbDes(stbDes, true); @@ -10138,21 +9571,10 @@ static int64_t dumpWholeDatabase(void **taos_v, SDbInfo *dbInfo, FILE *fp) { atomic_add_fetch_64( &g_resultStatistics.totalDatabasesOfDumpOut, 1); -#ifdef WEBSOCKET - if (g_args.cloud || g_args.restful) { - ret = dumpStbAndChildTbOfDbWS(taos_v, dbInfo, fpDbs); - if (ret >= 0) { - ret = dumpNTablesOfDbWS(taos_v, dbInfo); - } - } else { -#endif - ret = dumpStbAndChildTbOfDbNative(taos_v, dbInfo, fpDbs); - if (ret >= 0) { - ret = dumpNTablesOfDbNative(taos_v, dbInfo); - } -#ifdef WEBSOCKET + ret = dumpStbAndChildTbOfDbNative(taos_v, dbInfo, fpDbs); + if (ret >= 0) { + ret = dumpNTablesOfDbNative(taos_v, dbInfo); } -#endif if (AVRO_CODEC_UNKNOWN != g_args.avro_codec) { fclose(fpDbs); } @@ -10637,41 +10059,19 @@ static int dumpOut() { /* Connect to server and dump extra info*/ void **taos_v = NULL; -#ifdef WEBSOCKET - WS_TAOS *ws_taos = NULL; - - if (g_args.cloud || g_args.restful) { - if (NULL == (ws_taos = wsConnect())) { - ret = -1; - goto _exit_failure; - } - - taos_v = &ws_taos; - ret = dumpExtraInfo(taos_v, fp); - - if (ret < 0) { - goto _exit_failure; - } - - dbCount = fillDbInfoWS(taos_v); - } else { -#endif - if (NULL == (taos = taosConnect(NULL))) { - ret = -1; - goto _exit_failure; - } - - taos_v = &taos; - ret = dumpExtraInfo(taos_v, fp); - - if (ret < 0) { - goto _exit_failure; - } - - dbCount = fillDbInfoNative(taos); -#ifdef WEBSOCKET + if (NULL == (taos = taosConnect(NULL))) { + ret = -1; + goto _exit_failure; } -#endif + + taos_v = &taos; + ret = dumpExtraInfo(taos_v, fp); + + if (ret < 0) { + goto _exit_failure; + } + + dbCount = fillDbInfoNative(taos); if (dbCount <= 0) { errorPrint("%d database(s) valid to dump\n", dbCount); @@ -10823,33 +10223,6 @@ _exit_failure_2: static int dumpEntry() { int ret = 0; -#ifdef WEBSOCKET - if ( g_args.debug_print) { - ws_enable_log("trace"); - printf("ws_enable_log(\"trace\");\n"); - } else { - ws_enable_log("error"); - printf("ws_enable_log(\"error\");\n"); - } - - if (NULL == g_args.dsn) { - g_args.dsn = getenv("TDENGINE_CLOUD_DSN"); - if (NULL == g_args.dsn) { - g_args.cloud = false; - } else { - g_args.cloud = true; - } - } else { - g_args.cloud = true; - } - - if (g_args.cloud) { - splitCloudDsn(); - } else if (g_args.restful) { - jointCloudDsn(); - } -#endif // WEBSOCKET - if (checkParam() < 0) { exit(EXIT_FAILURE); } @@ -11483,6 +10856,20 @@ static int inspectAvroFiles(int argc, char *argv[]) { return ret; } +int32_t setConnMode(int8_t connMode) { + // set conn mode + char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; + int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); + if (code != TSDB_CODE_SUCCESS) { + engineError(INIT_PHASE, "taos_options", code); + return -1; + } + + infoPrint("\nConnect mode is : %s\n\n", strMode); + return 0; +} + + int main(int argc, char *argv[]) { g_uniqueID = getUniqueIDFromEpoch(); @@ -11494,12 +10881,13 @@ int main(int argc, char *argv[]) { parse_args(argc, argv, &g_args); } + // command line argp_parse(&argp, argc, argv, 0, 0, &g_args); - if (g_args.abort) { abort(); } + // client info snprintf(g_client_info, MIDDLE_BUFF_LEN, "%s", taos_get_client_info()); g_majorVersionOfClient = atoi(g_client_info); debugPrint("Client info: %s, major version: %d\n", @@ -11515,6 +10903,31 @@ int main(int argc, char *argv[]) { } } + // env dsn + if ( NULL == g_args.dsn) { + char *dsn = getenv("TDENGINE_CLOUD_DSN"); + if(dsn && dsn[0] != 0) { + if (g_args.connMode != CONN_MODE_NATIVE) { + g_args.dsn = dsn; + infoPrint("read dsn from evn dsn=%s\n", dsn); + } else { + warnPrint("command line pass native mode , ignore evn dsn:%s\n", dsn); + } + } + } else { + // check conflict + if (g_args.connMode == CONN_MODE_NATIVE) { + errorPrint("%s", DSN_NATIVE_CONFLICT); + return -1; + } + } + + // conn mode + if (setConnMode(g_args.connMode) != 0) { + return -1; + } + + // running if (g_args.inspect) { ret = inspectAvroFiles(argc, argv); } else { diff --git a/tools/taos-tools/src/wsdump.c b/tools/taos-tools/src/wsdump.c deleted file mode 100644 index 3ed0c461b9..0000000000 --- a/tools/taos-tools/src/wsdump.c +++ /dev/null @@ -1,1939 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the MIT license 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. - */ - -#define _GNU_SOURCE - -#ifdef WEBSOCKET - -#include "dump.h" -#include "dumpUtil.h" - -int cleanIfQueryFailedWS(const char *funcname, int lineno, char *command, WS_RES *res) { - errorPrint("%s() LN%d, failed to run command <%s>. code: 0x%08x, reason: %s\n", funcname, lineno, command, - ws_errno(res), ws_errstr(res)); - ws_free_result(res); - free(command); - return -1; -} - -int getTableRecordInfoImplWS(char *dbName, char *table, TableRecordInfo *pTableRecordInfo, bool tryStable) { - WS_TAOS *ws_taos = NULL; - WS_RES *ws_res; - int32_t ws_code = -1; - - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - memset(pTableRecordInfo, 0, sizeof(TableRecordInfo)); - - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, g_args.db_escape_char ? "USE `%s`" : "USE %s", dbName); - ws_res = wsQuery(&ws_taos, command, &ws_code); - if (ws_code != 0) { - errorPrint("Invalid database %s, reason: %s\n", dbName, ws_errstr(ws_res)); - ws_free_result(ws_res); - ws_res = NULL; - free(command); - return 0; - } - ws_free_result(ws_res); - - if (3 == g_majorVersionOfClient) { - if (tryStable) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT STABLE_NAME FROM information_schema.ins_stables " - "WHERE db_name='%s' AND stable_name='%s'", - dbName, table); - } else { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT TABLE_NAME,STABLE_NAME FROM " - "information_schema.ins_tables " - "WHERE db_name='%s' AND table_name='%s'", - dbName, table); - } - } else { - if (tryStable) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SHOW STABLES LIKE \'%s\'", table); - } else { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SHOW TABLES LIKE \'%s\'", table); - } - } - - ws_res = wsQuery(&ws_taos, command, &ws_code); - - if (ws_code != 0) { - cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - ws_close(ws_taos); - return -1; - } - - bool isSet = false; - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - if (ws_code) { - errorPrint("%s() LN%d, ws_fetch_raw_block() error. reason: %s!\n", __func__, __LINE__, ws_errstr(ws_res)); - ws_free_result(ws_res); - ws_res = NULL; - ws_close(ws_taos); - ws_taos = NULL; - free(command); - return 0; - } - - if (0 == rows) { - break; - } - - uint8_t type; - uint32_t length; - char buffer[TSDB_TABLE_NAME_LEN] = {0}; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_DB_NAME_INDEX, &type, &length); - if (NULL == value0) { - errorPrint( - "%s() LN%d, row: %d, col: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, row, TSDB_SHOW_DB_NAME_INDEX); - continue; - } - - memset(buffer, 0, TSDB_TABLE_NAME_LEN); - memcpy(buffer, value0, length); - - if (0 == strcmp(buffer, table)) { - if (tryStable) { - pTableRecordInfo->isStb = true; - tstrncpy(pTableRecordInfo->tableRecord.stable, buffer, min(TSDB_TABLE_NAME_LEN, length + 1)); - isSet = true; - } else { - pTableRecordInfo->isStb = false; - tstrncpy(pTableRecordInfo->tableRecord.name, buffer, min(TSDB_TABLE_NAME_LEN, length + 1)); - const void *value1 = NULL; - if (3 == g_majorVersionOfClient) { - value1 = ws_get_value_in_block(ws_res, row, 1, &type, &length); - } else { - value1 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_TABLES_METRIC_INDEX, &type, &length); - } - if (length) { - if (NULL == value1) { - errorPrint( - "%s() LN%d, row: %d, col: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, row, TSDB_SHOW_TABLES_METRIC_INDEX); - break; - } - - pTableRecordInfo->belongStb = true; - memset(buffer, 0, TSDB_TABLE_NAME_LEN); - memcpy(buffer, value1, length); - tstrncpy(pTableRecordInfo->tableRecord.stable, buffer, min(TSDB_TABLE_NAME_LEN, length + 1)); - } else { - pTableRecordInfo->belongStb = false; - } - isSet = true; - break; - } - } - } - - if (isSet) { - break; - } - } - - ws_free_result(ws_res); - ws_res = NULL; - ws_close(ws_taos); - ws_taos = NULL; - - free(command); - - if (isSet) { - return 0; - } - return -1; -} - -int getTableRecordInfoWS(char *dbName, char *table, TableRecordInfo *pTableRecordInfo) { - if (0 == getTableRecordInfoImplWS(dbName, table, pTableRecordInfo, false)) { - return 0; - } else if (0 == getTableRecordInfoImplWS(dbName, table, pTableRecordInfo, true)) { - return 0; - } - - errorPrint("Invalid table/stable %s\n", table); - return -1; -} - -int getDbCountWS(WS_RES *ws_res) { - int count = 0; - int32_t code; - - while (true) { - int rows = 0; - const void *data = NULL; - code = ws_fetch_raw_block(ws_res, &data, &rows); - if (code) { - errorPrint("%s() LN%d, ws_fetch_raw_block() error. reason: %s!\n", __func__, __LINE__, ws_errstr(ws_res)); - return 0; - } - - if (0 == rows) { - break; - } - - uint8_t type; - uint32_t length; - char buffer[VALUE_BUF_LEN] = {0}; - - for (int row = 0; row < rows; row++) { - const void *value = ws_get_value_in_block(ws_res, row, TSDB_SHOW_DB_NAME_INDEX, &type, &length); - if (NULL == value) { - errorPrint( - "%s() LN%d, row: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, row); - continue; - } - - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value, length); - debugPrint("%s() LN%d, dbname: %s\n", __func__, __LINE__, buffer); - - if (isSystemDatabase(buffer)) { - if (!g_args.allow_sys) { - continue; - } - } else if (g_args.databases) { // input multi dbs - if (inDatabasesSeq(buffer) != 0) { - continue; - } - } else if (!g_args.all_databases) { // only input one db - if (strcmp(g_args.arg_list[0], buffer)) { - continue; - } - } - count++; - } - } - - return count; -} - -int64_t getNtbCountOfStbWS(char *dbName, const char *stbName) { - WS_TAOS *ws_taos; - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - - int64_t count = 0; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - if (3 == g_majorVersionOfClient) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - g_args.db_escape_char ? "SELECT COUNT(*) FROM (SELECT DISTINCT(TBNAME) " - "FROM `%s`.%s%s%s)" - : "SELECT COUNT(*) FROM (SELECT DISTINCT(TBNAME) " - "FROM %s.%s%s%s)", - dbName, g_escapeChar, stbName, g_escapeChar); - } else { - snprintf( - command, TSDB_MAX_ALLOWED_SQL_LEN, - g_args.db_escape_char ? "SELECT COUNT(TBNAME) FROM `%s`.%s%s%s" : "SELECT COUNT(TBNAME) FROM %s.%s%s%s", - dbName, g_escapeChar, stbName, g_escapeChar); - } - debugPrint("get stable child count %s", command); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(&ws_taos, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - tfree(command); - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, ws_taos, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - - for (int row = 0; row < rows; row++) { - const void *value = ws_get_value_in_block(ws_res, row, TSDB_SHOW_TABLES_NAME_INDEX, &type, &len); - if (0 == len) { - errorPrint( - "%s() LN%d, row: %d, col: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, TSDB_DESCRIBE_METRIC_FIELD_INDEX, row); - continue; - } - count = *(int64_t *)value; - } - break; - } - debugPrint("%s() LN%d, COUNT(TBNAME): %" PRId64 "\n", __func__, __LINE__, count); - - ws_free_result(ws_res); - ws_close(ws_taos); - return count; -} - -int getTableTagValueWSV3(WS_TAOS **taos_v, const char *dbName, const char *table, TableDes **ppTableDes) { - TableDes *tableDes = *ppTableDes; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT tag_name,tag_value FROM information_schema.ins_tags " - "WHERE db_name = '%s' AND table_name = '%s'", - dbName, table); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (ws_code) { - errorPrint( - "%s() LN%d, ws_fetch_raw_block() error, " - "code: 0x%08x, command: %s, reason: %s\n", - __func__, __LINE__, ws_code, command, ws_errstr(ws_res)); - } - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from fetch to run " - "command <%s>, " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, command, taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - int index = tableDes->columns; - - for (int row = 0; row < rows; row++) { - const void *value1 = ws_get_value_in_block(ws_res, row, 1, &type, &len); - - debugPrint("%s() LN%d, len=%d\n", __func__, __LINE__, len); - - if (NULL == value1) { - strcpy(tableDes->cols[index].value, "NULL"); - strcpy(tableDes->cols[index].note, "NUL"); - } else if (0 != processFieldsValueV3(index, tableDes, value1, len)) { - errorPrint("%s() LN%d, processFieldsValueV3 tag_value: %p\n", __func__, __LINE__, value1); - ws_free_result(ws_res); - free(command); - return -1; - } - index++; - } - } - - ws_free_result(ws_res); - free(command); - - return (tableDes->columns + tableDes->tags); -} - -int getTableTagValueWSV2(WS_TAOS **taos_v, const char *dbName, const char *table, TableDes **ppTableDes) { - TableDes *tableDes = *ppTableDes; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - char *sqlstr = command; - - sqlstr += snprintf(sqlstr, TSDB_MAX_ALLOWED_SQL_LEN, "SELECT %s%s%s", g_escapeChar, - tableDes->cols[tableDes->columns].field, g_escapeChar); - for (int i = tableDes->columns + 1; i < (tableDes->columns + tableDes->tags); i++) { - sqlstr += sprintf(sqlstr, ",%s%s%s ", g_escapeChar, tableDes->cols[i].field, g_escapeChar); - } - sqlstr += sprintf(sqlstr, g_args.db_escape_char ? " FROM `%s`.%s%s%s LIMIT 1" : " FROM %s.%s%s%s LIMIT 1", dbName, - g_escapeChar, table, g_escapeChar); - - int32_t ws_code = -1; - int32_t retryCount = 0; - WS_RES *ws_res = NULL; - - RETRY_QUERY: - ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = wsFetchBlock(ws_res, &data, &rows); - - if (ws_code) { - // output error - errorPrint( - "%s() LN%d, getTableTagValueWSV2-> wsFetchBlock() error, " - "code: 0x%08x, sqlstr: %s, reason: %s\n", - __func__, __LINE__, ws_code, sqlstr, ws_errstr(ws_res)); - - // check can retry - if(canRetry(ws_code, RETRY_TYPE_FETCH) && ++retryCount <= g_args.retryCount) { - infoPrint("wsFetchBlock failed, goto wsQuery to retry %d\n", retryCount); - ws_free_result(ws_res); - ws_res = NULL; - toolsMsleep(g_args.retrySleepMs); - goto RETRY_QUERY; - } - - // error break while - break; - } - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from fetch to run " - "command <%s>, " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, sqlstr, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - for (int row = 0; row < rows; row++) { - for (int j = tableDes->columns; j < (tableDes->columns + tableDes->tags); j++) { - const void *value = ws_get_value_in_block(ws_res, row, j - tableDes->columns, &type, &len); - - debugPrint("%s() LN%d, len=%d\n", __func__, __LINE__, len); - - if (NULL == value) { - strcpy(tableDes->cols[j].value, "NULL"); - strcpy(tableDes->cols[j].note, "NUL"); - } else if (0 != processFieldsValueV2(j, tableDes, value, len)) { - errorPrint("%s() LN%d, processFieldsValueV2 value0: %p\n", __func__, __LINE__, value); - ws_free_result(ws_res); - free(command); - return -1; - } - } - } - } - - ws_free_result(ws_res); - free(command); - - return (tableDes->columns + tableDes->tags); -} - -int getTableTagValueWS(void **taos_v, const char *dbName, const char *table, TableDes **ppTableDes) { - int ret = -1; - if (3 == g_majorVersionOfClient) { - // if child-table have tag, V3 using select tag_value - // from information_schema.ins_tag where table to get tagValue - ret = getTableTagValueWSV2(taos_v, dbName, table, ppTableDes); - if (ret < 0) { - ret = getTableTagValueWSV3(taos_v, dbName, table, ppTableDes); - } - } else if (2 == g_majorVersionOfClient) { - // if child-table have tag, - // using select tagName from table to get tagValue - ret = getTableTagValueWSV2(taos_v, dbName, table, ppTableDes); - } else { - errorPrint("%s() LN%d, major version %d is not supported\n", __func__, __LINE__, g_majorVersionOfClient); - } - - return ret; -} - -int getTableDesFromStbWS(WS_TAOS **taos_v, const char *dbName, const TableDes *stbTableDes, const char *table, - TableDes **ppTableDes) { - constructTableDesFromStb(stbTableDes, table, ppTableDes); - return getTableTagValueWS(taos_v, dbName, table, ppTableDes); -} - -int getTableDesWS(WS_TAOS **taos_v, const char *dbName, const char *table, TableDes *tableDes, const bool colOnly) { - int colCount = 0; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, g_args.db_escape_char ? "DESCRIBE `%s`.%s%s%s" : "DESCRIBE %s.%s%s%s", - dbName, g_escapeChar, table, g_escapeChar); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } else { - debugPrint("%s() LN%d, run command <%s> success, ws_taos: %p\n", __func__, __LINE__, command, *taos_v); - } - - tstrncpy(tableDes->name, table, TSDB_TABLE_NAME_LEN); - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - char buffer[VALUE_BUF_LEN] = {0}; - const void *value = NULL; - - for (int row = 0; row < rows; row++) { - value = ws_get_value_in_block(ws_res, row, TSDB_DESCRIBE_METRIC_FIELD_INDEX, &type, &len); - if (NULL == value) { - errorPrint( - "%s() LN%d, row: %d, col: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, TSDB_DESCRIBE_METRIC_FIELD_INDEX, row); - continue; - } - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value, len); - strncpy(tableDes->cols[colCount].field, buffer, len); - - value = ws_get_value_in_block(ws_res, row, TSDB_DESCRIBE_METRIC_TYPE_INDEX, &type, &len); - if (NULL == value) { - errorPrint( - "%s() LN%d, row: %d, col: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, TSDB_DESCRIBE_METRIC_TYPE_INDEX, row); - continue; - } - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value, len); - tableDes->cols[colCount].type = typeStrToType(buffer); - - value = ws_get_value_in_block(ws_res, row, TSDB_DESCRIBE_METRIC_LENGTH_INDEX, &type, &len); - if (NULL == value) { - errorPrint("row: %d, col: %d, ws_get_value_in_block() error!\n", TSDB_DESCRIBE_METRIC_LENGTH_INDEX, - row); - continue; - } - tableDes->cols[colCount].length = *((int *)value); - - value = ws_get_value_in_block(ws_res, row, TSDB_DESCRIBE_METRIC_NOTE_INDEX, &type, &len); - if (NULL == value) { - errorPrint("row: %d, col: %d, ws_get_value_in_block() error!\n", TSDB_DESCRIBE_METRIC_NOTE_INDEX, row); - continue; - } - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value, len); - - debugPrint("%s() LN%d, buffer: %s\n", __func__, __LINE__, buffer); - - strncpy(tableDes->cols[colCount].note, buffer, len); - if (strcmp(tableDes->cols[colCount].note, "TAG") != 0) { - tableDes->columns++; - } else { - tableDes->tags++; - } - colCount++; - } - } - - ws_free_result(ws_res); - ws_res = NULL; - free(command); - - if (colOnly) { - return colCount; - } - - return getTableTagValueWS(taos_v, dbName, table, &tableDes); -} - -int64_t queryDbForDumpOutCountWS(char *command, WS_TAOS **taos_v, const char *dbName, const char *tbName, - const int precision) { - int64_t count = -1; - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code != 0) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_TABLES_NAME_INDEX, &type, &len); - if (NULL == value0) { - if (0 == ws_errno(ws_res)) { - count = 0; - debugPrint("%s fetch row, count: %" PRId64 "\n", command, count); - } else { - count = -1; - errorPrint( - "failed run %s to fetch row, ws_taos: %p, " - "code: 0x%08x, reason: %s\n", - command, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - } - } else { - count = *(int64_t *)value0; - debugPrint("%s fetch row, count: %" PRId64 "\n", command, count); - break; - } - } - } - - ws_free_result(ws_res); - free(command); - return count; -} - -TAOS_RES *queryDbForDumpOutOffsetWS(WS_TAOS **taos_v, char *command) { - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - return NULL; - } - free(command); - return ws_res; -} - -int64_t writeResultToAvroWS(const char *avroFilename, const char *dbName, const char *tbName, char *jsonSchema, - WS_TAOS **taos_v, int precision, int64_t start_time, int64_t end_time) { - int64_t queryCount = queryDbForDumpOutCount(taos_v, dbName, tbName, precision); - if (queryCount <= 0) { - return 0; - } - - avro_schema_t schema; - RecordSchema *recordSchema; - avro_file_writer_t db; - - avro_value_iface_t *wface = prepareAvroWface(avroFilename, jsonSchema, &schema, &recordSchema, &db); - - int64_t success = 0; - int64_t failed = 0; - - bool printDot = true; - - int currentPercent = 0; - int percentComplete = 0; - - int64_t limit = g_args.data_batch; - int64_t offset = 0; - - do { - if (queryCount > limit) { - if (limit < (queryCount - offset)) { - limit = queryCount - offset; - } - } else { - limit = queryCount; - } - - WS_RES *ws_res = NULL; - int numFields = 0; - void *ws_fields = NULL; - int32_t countInBatch = 0; - int32_t retryCount = 0; - -RETRY_QUERY: - countInBatch = 0; - ws_res = queryDbForDumpOutOffset(taos_v, dbName, tbName, precision, start_time, end_time, limit, offset); - if (NULL == ws_res) { - break; - } - - numFields = ws_field_count(ws_res); - if (3 == g_majorVersionOfClient) { - const struct WS_FIELD *ws_fields_v3 = ws_fetch_fields(ws_res); - ws_fields = (void *)ws_fields_v3; - } else { - const struct WS_FIELD_V2 *ws_fields_v2 = ws_fetch_fields_v2(ws_res); - ws_fields = (void *)ws_fields_v2; - } - - while (true) { - int rows = 0; - const void *data = NULL; - int32_t ws_code = wsFetchBlock(ws_res, &data, &rows); - - if (ws_code) { - errorPrint( - "%s() LN%d, writeResultToAvroWS->wsFetchBlock() error, ws_taos: %p, " - "code: 0x%08x, reason: %s\n", - __func__, __LINE__, *taos_v, ws_code, ws_errstr(ws_res)); - - // check can retry - if(canRetry(ws_code, RETRY_TYPE_FETCH) && ++retryCount <= g_args.retryCount) { - infoPrint("wsFetchBlock failed, goto wsQuery to retry %d limit=%"PRId64" offset=%"PRId64" queryCount=%"PRId64" \n", - retryCount, limit, offset, queryCount); - // need close old res - ws_free_result(ws_res); - ws_res = NULL; - toolsMsleep(g_args.retrySleepMs); - goto RETRY_QUERY; - } - - // break - break; - } - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from wsFetchBlock(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - for (int row = 0; row < rows; row++) { - avro_value_t record; - avro_generic_value_new(wface, &record); - - avro_value_t avro_value, branch; - - if (!g_args.loose_mode) { - if (0 != avro_value_get_by_name(&record, "tbname", &avro_value, NULL)) { - errorPrint( - "%s() LN%d, avro_value_get_by_name(tbname) " - "failed\n", - __func__, __LINE__); - break; - } - avro_value_set_branch(&avro_value, 1, &branch); - avro_value_set_string(&branch, tbName); - } - - for (int32_t f = 0; f < numFields; f++) { - uint8_t type; - uint32_t len; - - const void *value = ws_get_value_in_block(ws_res, row, f, &type, &len); - - if (3 == g_majorVersionOfClient) { - struct WS_FIELD *ws_fields_3 = (struct WS_FIELD *)ws_fields; - processValueToAvro(f, record, avro_value, branch, ws_fields_3[f].name, ws_fields_3[f].type, - ws_fields_3[f].bytes, value, len); - } else { - struct WS_FIELD_V2 *ws_fields_2 = (struct WS_FIELD_V2 *)ws_fields; - processValueToAvro(f, record, avro_value, branch, ws_fields_2[f].name, ws_fields_2[f].type, - ws_fields_2[f].bytes, value, len); - } - } - - if (0 != avro_file_writer_append_value(db, &record)) { - errorPrint( - "%s() LN%d, " - "Unable to write record to file. Message: %s\n", - __func__, __LINE__, avro_strerror()); - failed--; - } else { - success++; - } - - countInBatch++; - avro_value_decref(&record); - } - } - - if (countInBatch != limit) { - errorPrint("%s() LN%d, actual dump out: %d, batch %" PRId64 "\n", __func__, __LINE__, countInBatch, limit); - } - ws_free_result(ws_res); - ws_res = NULL; - printDotOrX(offset, &printDot); - offset += limit; - - currentPercent = ((offset) * 100 / queryCount); - if (currentPercent > percentComplete) { - // infoPrint("%d%% of %s\n", currentPercent, tbName); - percentComplete = currentPercent; - } - } while (offset < queryCount); - - if (percentComplete < 100) { - errorPrint("%d%% of %s\n", percentComplete, tbName); - } - - avro_value_iface_decref(wface); - freeRecordSchema(recordSchema); - avro_file_writer_close(db); - avro_schema_decref(schema); - - return success; -} - -int64_t writeResultDebugWS(WS_RES *ws_res, FILE *fp, const char *dbName, const char *tbName) { - int64_t totalRows = 0; - - int32_t sql_buf_len = g_args.max_sql_len; - char *tmpBuffer = (char *)calloc(1, sql_buf_len + 128); - if (NULL == tmpBuffer) { - errorPrint("%s() LN%d, memory allocation failed!\n", __func__, __LINE__); - return 0; - } - - char *pstr = tmpBuffer; - - int64_t lastRowsPrint = 5000000; - int count = 0; - - int fieldCount = ws_field_count(ws_res); - ASSERT(fieldCount > 0); - - void *ws_fields = NULL; - if (3 == g_majorVersionOfClient) { - const struct WS_FIELD *ws_fields_v3 = ws_fetch_fields(ws_res); - ws_fields = (void *)ws_fields_v3; - } else { - const struct WS_FIELD_V2 *ws_fields_v2 = ws_fetch_fields_v2(ws_res); - ws_fields = (void *)ws_fields_v2; - } - - int32_t total_sqlstr_len = 0; - - while (true) { - int rows = 0; - const void *data = NULL; - int32_t ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (ws_code) { - errorPrint( - "%s() LN%d, ws_fetch_raw_block() error!" - " code: 0x%08x, reason: %s\n", - __func__, __LINE__, ws_code, ws_errstr(ws_res)); - break; - } - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "code: 0x%08x, reason:%s\n", - __func__, __LINE__, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - for (int row = 0; row < rows; row++) { - int32_t curr_sqlstr_len = 0; - - if (count == 0) { - total_sqlstr_len = 0; - curr_sqlstr_len += sprintf(pstr + curr_sqlstr_len, "INSERT INTO %s.%s VALUES (", dbName, tbName); - } else { - curr_sqlstr_len += sprintf(pstr + curr_sqlstr_len, "("); - } - - for (int f = 0; f < fieldCount; f++) { - if (f != 0) { - curr_sqlstr_len += sprintf(pstr + curr_sqlstr_len, ", "); - } - uint8_t type; - uint32_t len; - - const void *value = ws_get_value_in_block(ws_res, row, f, &type, &len); - if (NULL == value) { - errorPrint("row: %d, ws_get_value_in_block() error!\n", row); - continue; - } - - if (3 == g_majorVersionOfClient) { - struct WS_FIELD *ws_fields_3 = (struct WS_FIELD *)ws_fields; - curr_sqlstr_len += processResultValue(pstr, curr_sqlstr_len, ws_fields_3[f].type, value, len); - } else { - struct WS_FIELD_V2 *ws_fields_2 = (struct WS_FIELD_V2 *)ws_fields; - curr_sqlstr_len += processResultValue(pstr, curr_sqlstr_len, ws_fields_2[f].type, value, len); - } - } - curr_sqlstr_len += sprintf(pstr + curr_sqlstr_len, ")"); - - totalRows++; - count++; - fprintf(fp, "%s", tmpBuffer); - - if (totalRows >= lastRowsPrint) { - infoPrint(" %" PRId64 " rows already be dump-out from %s.%s\n", totalRows, dbName, tbName); - lastRowsPrint += 5000000; - } - - total_sqlstr_len += curr_sqlstr_len; - - if ((count >= g_args.data_batch) || (sql_buf_len - total_sqlstr_len < TSDB_MAX_BYTES_PER_ROW)) { - fprintf(fp, ";\n"); - count = 0; - } - } - } - - debugPrint("total_sqlstr_len: %d\n", total_sqlstr_len); - - fprintf(fp, "\n"); - free(tmpBuffer); - - return totalRows; -} - -WS_RES *queryDbForDumpOutWS(WS_TAOS **taos_v, const char *dbName, const char *tbName, const int precision, - const int64_t start_time, const int64_t end_time) { - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return NULL; - } - - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - g_args.db_escape_char ? "SELECT * FROM `%s`.%s%s%s WHERE _c0 >= %" PRId64 - " " - "AND _c0 <= %" PRId64 " ORDER BY _c0 ASC;" - : "SELECT * FROM %s.%s%s%s WHERE _c0 >= %" PRId64 - " " - "AND _c0 <= %" PRId64 " ORDER BY _c0 ASC;", - dbName, g_escapeChar, tbName, g_escapeChar, start_time, end_time); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code != 0) { - cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - return NULL; - } - - free(command); - return ws_res; -} - -int64_t dumpTableDataAvroWS(char *dataFilename, int64_t index, const char *tbName, const bool belongStb, - const char *dbName, const int precision, int colCount, TableDes *tableDes, - int64_t start_time, int64_t end_time) { - WS_TAOS *ws_taos; - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - - char *jsonSchema = NULL; - if (0 != convertTbDesToJsonWrap(dbName, tbName, tableDes, colCount, &jsonSchema)) { - errorPrint("%s() LN%d, convertTbDesToJsonWrap failed\n", __func__, __LINE__); - ws_close(ws_taos); - return -1; - } - - int64_t totalRows = - writeResultToAvroWS(dataFilename, dbName, tbName, jsonSchema, &ws_taos, precision, start_time, end_time); - - ws_close(ws_taos); - ws_taos = NULL; - tfree(jsonSchema); - - return totalRows; -} - -int64_t fillTbNameArrWS(WS_TAOS **taos_v, char *command, char **tbNameArr, const char *stable, const int64_t preCount) { - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - int currentPercent = 0; - int percentComplete = 0; - - int64_t ntbCount = 0; - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_TABLES_NAME_INDEX, &type, &len); - if (NULL == value0) { - errorPrint( - "%s() LN%d, ws_get_value_in_blocK() return NULL." - " code: 0x%08x, reason: %s!\n", - __func__, __LINE__, ws_errno(ws_res), ws_errstr(ws_res)); - continue; - } else { - debugPrint("%s() LN%d, ws_get_value_in_blocK() return %s. len: %d\n", __func__, __LINE__, - (char *)value0, len); - } - - tbNameArr[ntbCount] = calloc(len + 1, 1); - strncpy(tbNameArr[ntbCount], (char *)value0, len); - - debugPrint("%s() LN%d, sub table name: %s %" PRId64 " of stable: %s\n", __func__, __LINE__, - tbNameArr[ntbCount], ntbCount, stable); - ++ntbCount; - - currentPercent = (ntbCount * 100 / preCount); - - if (currentPercent > percentComplete) { - infoPrint("connection %p fetched %d%% of %s' tbname\n", *taos_v, currentPercent, stable); - percentComplete = currentPercent; - } - } - } - - if ((preCount > 0) && (percentComplete < 100)) { - errorPrint("%d%% - total %" PRId64 " sub-table's names of stable: %s fetched\n", percentComplete, ntbCount, - stable); - } else { - okPrint("total %" PRId64 " sub-table's name of stable: %s fetched\n", ntbCount, stable); - } - - ws_free_result(ws_res); - free(command); - return ntbCount; -} - -int readNextTableDesWS(void* ws_res, TableDes* tbDes, int *idx, int *cnt) { - // tbname, tagName , tagValue - int index = 0; - uint8_t type = 0; - uint32_t len = 0; - while( index < tbDes->tags) { - // get block - if(*idx >= *cnt || *cnt == 0) { - const void *data = NULL; - int ws_code = ws_fetch_raw_block(ws_res, &data, cnt); - if (ws_code !=0 ) { - // read to end - errorPrint("read next ws_fetch_raw_block failed, err code=%d idx=%d index=%d\n", ws_code, *idx, index); - return -1; - } - - if(*cnt == 0) { - infoPrint("read schema over. tag columns %d.\n", tbDes->tags); - break; - } - *idx = 0; - } - - // read first column tbname - const void *val = ws_get_value_in_block(ws_res, *idx, 0, &type, &len); - if(val == NULL) { - errorPrint("read tbname failed, idx=%d cnt=%d \n", *idx, *cnt); - return -1; - } - - // tbname changed check - if(tbDes->name[0] == 0) { - // first set tbName - strncpy(tbDes->name, val, len); - } else { - // compare tbname change - if(!(strncmp(tbDes->name, val, len) == 0 - && tbDes->name[len] == 0)) { - // tbname cnanged, break - break; - } - } - - // read third column tagvalue - val = ws_get_value_in_block(ws_res, *idx, 2, &type, &len); - // copy tagvalue - if (NULL == val) { - strcpy(tbDes->cols[index].value, "NULL"); - strcpy(tbDes->cols[index].note , "NUL"); - } else if (0 != processFieldsValueV3(index, tbDes, val, len)) { - errorPrint("%s() LN%d, call processFieldsValueV3 tag_value: %p\n", - __func__, __LINE__, val); - return -1; - } - - // move next row - *idx = *idx + 1; - // counter ++ - index++; - } - - // check tags count corrent - if(*cnt && index != tbDes->tags) { - errorPrint("child table %s read tags(%d) not equal stable tags (%d).\n", - tbDes->name, index, tbDes->tags); - return -1; - } - - return index; -} - -// read specail line, col -int32_t readRowWS(void *res, int32_t idx, int32_t col, uint32_t *len, char **data) { - int32_t i = 0; - while (i <= idx) { - // fetch block - const void *block = NULL; - int32_t cnt = 0; - int ws_code = ws_fetch_raw_block(res, &block, &cnt); - if (ws_code != 0) { - errorPrint("readRow->ws_fetch_raw_block failed, err code=%d i=%d\n", ws_code, i); - return -1; - } - - // cnt check - if (cnt == 0) { - infoPrint("ws_fetch_raw_block read cnt zero. i=%d.\n", i); - return -1; - } - - // check idx - if (i + cnt <= idx) { - // move next block - i += cnt; - continue; - } - - // set - uint8_t type = 0; - const void *val = ws_get_value_in_block(res, idx, col, &type, len); - if (val == NULL) { - errorPrint("readRow ws_get_value_in_block failed, cnt=%d idx=%d col=%d \n", cnt, idx, col); - return -1; - } - *data = (char *)val; - break; - } - - return 0; -} - -void dumpExtraInfoVarWS(void **taos_v, FILE *fp) { - char buffer[BUFFER_LEN]; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return; - } - strcpy(command, "SHOW VARIABLES"); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - - if (0 != ws_code) { - warnPrint( - "%s() LN%d, failed to run command %s, " - "code: 0x%08x, reason: %s. Will use default settings\n", - __func__, __LINE__, command, ws_code, ws_errstr(ws_res)); - fprintf(g_fpOfResult, - "# SHOW VARIABLES failed, " - "code: 0x%08x, reason:%s\n", - ws_errno(ws_res), ws_errstr(ws_res)); - snprintf(buffer, BUFFER_LEN, "#!charset: %s\n", "UTF-8"); - size_t len = fwrite(buffer, 1, strlen(buffer), fp); - if (len != strlen(buffer)) { - errorPrint( - "%s() LN%d, write to file. " - "try to write %zu, actual len %zu, " - "Errno is %d. Reason is %s.\n", - __func__, __LINE__, strlen(buffer), len, errno, strerror(errno)); - } - ws_free_result(ws_res); - ws_res = NULL; - free(command); - return; - } - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - char tmp[BUFFER_LEN - 12] = {0}; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, 0, &type, &len); - memset(tmp, 0, BUFFER_LEN - 12); - memcpy(tmp, value0, len); - - verbosePrint("%s() LN%d, value0: %s\n", __func__, __LINE__, tmp); - if (0 == strcmp(tmp, "charset")) { - const void *value1 = ws_get_value_in_block(ws_res, row, 1, &type, &len); - memset(tmp, 0, BUFFER_LEN - 12); - memcpy(tmp, value1, min(BUFFER_LEN - 13, len)); - snprintf(buffer, BUFFER_LEN, "#!charset: %s\n", tmp); - debugPrint("%s() LN%d buffer: %s\n", __func__, __LINE__, buffer); - size_t w_len = fwrite(buffer, 1, strlen(buffer), fp); - if (w_len != strlen(buffer)) { - errorPrint( - "%s() LN%d, write to file. " - "try to write %zu, actual len %zu, " - "Errno is %d. Reason is %s.\n", - __func__, __LINE__, strlen(buffer), w_len, errno, strerror(errno)); - } - } - } - } - - ws_free_result(ws_res); - ws_res = NULL; - free(command); -} - -int queryDbImplWS(WS_TAOS **taos_v, char *command) { - int ret = 0; - WS_RES *ws_res = NULL; - int32_t ws_code = -1; - - ws_res = wsQuery(taos_v, command, &ws_code); - - if (ws_code) { - errorPrint( - "Failed to run <%s>, ws_taos: %p, " - "code: 0x%08x, reason: %s\n", - command, *taos_v, ws_code, ws_errstr(ws_res)); - ret = -1; - ; - } - - ws_free_result(ws_res); - ws_res = NULL; - return ret; -} - -void dumpNormalTablesOfStbWS(threadInfo *pThreadInfo, FILE *fp, char *dumpFilename) { - for (int64_t i = pThreadInfo->from; i < (pThreadInfo->from + pThreadInfo->count); i++) { - char *tbName = pThreadInfo->tbNameArr[i]; - debugPrint("%s() LN%d, [%d] sub table %" PRId64 ": name: %s\n", __func__, __LINE__, pThreadInfo->threadIndex, i, - tbName); - - int64_t count; - if (g_args.avro) { - count = dumpNormalTable(i, &pThreadInfo->taos, pThreadInfo->dbInfo, true, pThreadInfo->stbName, - pThreadInfo->stbDes, tbName, pThreadInfo->precision, dumpFilename, NULL); - } else { - count = dumpNormalTable(i, &pThreadInfo->taos, pThreadInfo->dbInfo, true, pThreadInfo->stbName, - pThreadInfo->stbDes, tbName, pThreadInfo->precision, NULL, fp); - } - - // show progress - atomic_add_fetch_64(&g_tableDone, 1); - infoPrint("%s.%s %" PRId64 "/%" PRId64 " %s dump data ok.\n", g_dbName, g_stbName, g_tableDone, g_tableCount, - tbName); - if (count < 0) { - break; - } else { - atomic_add_fetch_64(&g_totalDumpOutRows, count); - } - } - - return; -} - -int64_t dumpStbAndChildTbOfDbWS(WS_TAOS **taos_v, SDbInfo *dbInfo, FILE *fpDbs) { - int64_t ret = 0; - - // - // obtain need dump all stable name - // - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, g_args.db_escape_char ? "USE `%s`" : "USE %s", dbInfo->name); - WS_RES *ws_res; - int32_t ws_code = -1; - - ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code != 0) { - errorPrint("Invalid database %s, reason: %s\n", dbInfo->name, ws_errstr(ws_res)); - ws_free_result(ws_res); - free(command); - return -1; - } - - if (3 == g_majorVersionOfClient) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT STABLE_NAME FROM information_schema.ins_stables " - "WHERE db_name='%s'", - dbInfo->name); - } else { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SHOW STABLES"); - } - - ws_res = wsQuery(taos_v, command, &ws_code); - - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - // link - SNode* head = NULL; - SNode* end = NULL; - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_DB_NAME_INDEX, &type, &len); - if (NULL == value0) { - errorPrint("row: %d, ws_get_value_in_block() error!\n", row); - continue; - } - - // put to linked list - if (head == NULL) { - head = end = mallocNode(value0, len); - if(head == NULL) { - errorPrint("row: %d, mallocNode head error!\n", row); - continue; - } - } else { - end->next = mallocNode(value0, len); - if(end->next == NULL) { - errorPrint("row: %d, mallocNode next error!\n", row); - continue; - } - end = end->next; - } - // check - debugPrint("%s() LN%d, stable: %s\n", __func__, __LINE__, end->name); - } - } - - free(command); - - // check except - if (head == NULL) { - infoPrint("%s() LN%d, stable count is zero.\n", __func__, __LINE__ ); - return 0; - } - - // - // dump stable data - // - SNode * next = head; - while (next) { - ret = dumpStbAndChildTb(taos_v, dbInfo, next->name, fpDbs); - if (ret < 0) { - errorPrint("%s() LN%d, stable: %s dump out failed\n", __func__, __LINE__, next->name); - break; - } - // move next - next = next->next; - } - - // free nodes - freeNodes(head); - return ret; -} - -int64_t dumpNTablesOfDbWS(WS_TAOS **taos_v, SDbInfo *dbInfo) { - int64_t ret = 0; - if (0 == dbInfo->ntables) { - errorPrint("%s() LN%d, database: %s has 0 tables\n", __func__, __LINE__, dbInfo->name); - return 0; - } - - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - WS_RES *ws_res; - int32_t ws_code = -1; - - if (3 == g_majorVersionOfClient) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT TABLE_NAME,STABLE_NAME FROM " - "information_schema.ins_tables WHERE db_name='%s'", - dbInfo->name); - } else { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, g_args.db_escape_char ? "USE `%s`" : "USE %s", dbInfo->name); - ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - errorPrint("invalid database %s, code: 0x%08x, reason: %s\n", dbInfo->name, ws_code, ws_errstr(ws_res)); - ws_free_result(ws_res); - ws_res = NULL; - ws_close(taos_v); - taos_v = NULL; - free(command); - return 0; - } - ws_free_result(ws_res); - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SHOW TABLES"); - } - - ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - errorPrint("Failed to show %s\'s tables, code: 0x%08x, reason: %s!\n", dbInfo->name, ws_code, - ws_errstr(ws_res)); - ws_free_result(ws_res); - ws_res = NULL; - ws_close(taos_v); - taos_v = NULL; - free(command); - return 0; - } - - // link - SNode* head = NULL; - SNode* end = NULL; - - int64_t count = 0; - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len0, len1; - - for (int row = 0; row < rows; row++) { - const void *value1 = NULL; - if (3 == g_majorVersionOfClient) { - value1 = ws_get_value_in_block(ws_res, row, 1, &type, &len1); - } else { - value1 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_TABLES_METRIC_INDEX, &type, &len1); - } - - if (len1) { - if (g_args.debug_print || g_args.verbose_print) { - char buffer[VALUE_BUF_LEN]; - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value1, len1); - debugPrint("%s() LN%d, get table belong %s\n", __func__, __LINE__, buffer); - } - continue; - } else { - const void *value0 = ws_get_value_in_block(ws_res, row, 0, &type, &len0); - if ((NULL == value0) || (0 == len0)) { - errorPrint("%s() LN%d, value0: %p, type: %d, len0: %d\n", __func__, __LINE__, value0, type, len0); - continue; - } - - // put to linked list - if (head == NULL) { - head = end = mallocNode(value0, len0); - if (head == NULL) { - errorPrint("row: %d, mallocNode head error!\n", row); - continue; - } - } else { - end->next = mallocNode(value0, len0); - if (end->next == NULL) { - errorPrint("row: %d, mallocNode next error!\n", row); - continue; - } - end = end->next; - } - - debugPrint("%s() LN%d count: %" PRId64 - ", table name: %s, " - "length: %d\n", - __func__, __LINE__, count, end->name, len0); - } - count++; - } - } - - ws_free_result(ws_res); - free(command); - - // check except - if (head == NULL) { - infoPrint("%s() LN%d, normal table count is zero.\n", __func__, __LINE__ ); - return 0; - } - - // - // dump stable data - // - SNode * next = head; - while (next) { - ret = dumpANormalTableNotBelong(count, taos_v, dbInfo, next->name); - if (0 == ret) { - infoPrint("Dumping normal table: %s\n", next->name); - } else { - errorPrint("%s() LN%d, dump normal table: %s\n", __func__, __LINE__, next->name); - break; - } - - // move next - next = next->next; - } - - // free nodes - freeNodes(head); - - return ret; -} - -bool fillDBInfoWithFieldsWS(const int index, const char *name, const int row, const int f, WS_RES *res) { - uint8_t type; - uint32_t len; - char tmp[VALUE_BUF_LEN] = {0}; - - const void *value = ws_get_value_in_block(res, row, f, &type, &len); - if (0 == strcmp(name, "name")) { - if (NULL == value) { - errorPrint( - "%s() LN%d, row: %d, field: %d, " - "ws_get_value_in_block() error!\n", - __func__, __LINE__, row, f); - return false; - } else { - memset(tmp, 0, VALUE_BUF_LEN); - memcpy(tmp, value, len); - strncpy(g_dbInfos[index]->name, tmp, len); - } - } else if (0 == strcmp(name, "vgroups")) { - if (TSDB_DATA_TYPE_INT == type) { - g_dbInfos[index]->vgroups = *((int32_t *)value); - } else if (TSDB_DATA_TYPE_SMALLINT == type) { - g_dbInfos[index]->vgroups = *((int16_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "ntables")) { - if (TSDB_DATA_TYPE_INT == type) { - g_dbInfos[index]->ntables = *((int32_t *)value); - } else if (TSDB_DATA_TYPE_BIGINT == type) { - g_dbInfos[index]->ntables = *((int64_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "replica")) { - if (TSDB_DATA_TYPE_TINYINT == type) { - g_dbInfos[index]->replica = *((int8_t *)value); - } else if (TSDB_DATA_TYPE_SMALLINT == type) { - g_dbInfos[index]->replica = *((int16_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "strict")) { - tstrncpy(g_dbInfos[index]->strict, (char *)value, min(STRICT_LEN, len + 1)); - debugPrint("%s() LN%d: field: %d, strict: %s, length:%d\n", __func__, __LINE__, f, g_dbInfos[index]->strict, - len); - } else if (0 == strcmp(name, "quorum")) { - g_dbInfos[index]->quorum = *((int16_t *)value); - } else if (0 == strcmp(name, "days")) { - g_dbInfos[index]->days = *((int16_t *)value); - } else if ((0 == strcmp(name, "keep")) || (0 == strcmp(name, "keep0,keep1,keep2"))) { - tstrncpy(g_dbInfos[index]->keeplist, value, min(KEEPLIST_LEN, len + 1)); - debugPrint("%s() LN%d: field: %d, keep: %s, length:%d\n", __func__, __LINE__, f, g_dbInfos[index]->keeplist, - len); - } else if (0 == strcmp(name, "duration")) { - tstrncpy(g_dbInfos[index]->duration, value, min(DURATION_LEN, len + 1)); - debugPrint("%s() LN%d: field: %d, tmp: %s, duration: %s, length:%d\n", __func__, __LINE__, f, tmp, - g_dbInfos[index]->duration, len); - } else if ((0 == strcmp(name, "cache")) || (0 == strcmp(name, "cache(MB)"))) { - g_dbInfos[index]->cache = *((int32_t *)value); - } else if (0 == strcmp(name, "blocks")) { - g_dbInfos[index]->blocks = *((int32_t *)value); - } else if (0 == strcmp(name, "minrows")) { - if (TSDB_DATA_TYPE_INT == type) { - g_dbInfos[index]->minrows = *((int32_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "maxrows")) { - if (TSDB_DATA_TYPE_INT == type) { - g_dbInfos[index]->maxrows = *((int32_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "wallevel")) { - g_dbInfos[index]->wallevel = *((int8_t *)value); - } else if (0 == strcmp(name, "wal")) { - if (TSDB_DATA_TYPE_TINYINT == type) { - g_dbInfos[index]->wal = *((int8_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "fsync")) { - if (TSDB_DATA_TYPE_INT == type) { - g_dbInfos[index]->fsync = *((int32_t *)value); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "comp")) { - if (TSDB_DATA_TYPE_TINYINT == type) { - g_dbInfos[index]->comp = (int8_t)(*((int8_t *)value)); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "cachelast")) { - if (TSDB_DATA_TYPE_TINYINT == type) { - g_dbInfos[index]->cachelast = (int8_t)(*((int8_t *)value)); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "cache_model")) { - if (TSDB_DATA_TYPE_TINYINT == type) { - g_dbInfos[index]->cache_model = (int8_t)(*((int8_t *)value)); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "single_stable_model")) { - if (TSDB_DATA_TYPE_BOOL == type) { - g_dbInfos[index]->single_stable_model = (bool)(*((bool *)value)); - } else { - errorPrint("%s() LN%d, unexpected type: %d\n", __func__, __LINE__, type); - return false; - } - } else if (0 == strcmp(name, "precision")) { - tstrncpy(g_dbInfos[index]->precision, (char *)value, min(DB_PRECISION_LEN, len + 1)); - } else if (0 == strcmp(name, "update")) { - g_dbInfos[index]->update = *((int8_t *)value); - } - - return true; -} - -int fillDbExtraInfoV3WS(void **taos_v, const char *dbName, const int dbIndex) { - int ret = 0; - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, - "SELECT COUNT(table_name) FROM " - "information_schema.ins_tables WHERE db_name='%s'", - dbName); - - infoPrint("Getting table(s) count of db (%s) ...\n", dbName); - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } else { - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_DB_NAME_INDEX, &type, &len); - if (NULL == value0) { - errorPrint("row: %d, ws_get_value_in_block() error!\n", row); - continue; - } - - if (TSDB_DATA_TYPE_BIGINT == type) { - g_dbInfos[dbIndex]->ntables = *(int64_t *)value0; - } else { - errorPrint("%s() LN%d, type: %d, not converted\n", __func__, __LINE__, type); - } - } - } - } - - ws_free_result(ws_res); - free(command); - return ret; -} - -int fillDbInfoWS(void **taos_v) { - int ret = 0; - int dbIndex = 0; - - char *command = calloc(1, TSDB_MAX_ALLOWED_SQL_LEN); - if (NULL == command) { - errorPrint("%s() LN%d, memory allocation failed\n", __func__, __LINE__); - return -1; - } - - if (3 == g_majorVersionOfClient) { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SELECT * FROM information_schema.ins_databases"); - } else { - snprintf(command, TSDB_MAX_ALLOWED_SQL_LEN, "SHOW DATABASES"); - } - - int32_t ws_code = -1; - WS_RES *ws_res = wsQuery(taos_v, command, &ws_code); - if (ws_code != 0) { - return cleanIfQueryFailedWS(__func__, __LINE__, command, ws_res); - } - - int fieldCount = ws_field_count(ws_res); - void *ws_fields = NULL; - if (3 == g_majorVersionOfClient) { - const struct WS_FIELD *ws_fields_v3 = ws_fetch_fields(ws_res); - ws_fields = (void *)ws_fields_v3; - } else { - const struct WS_FIELD_V2 *ws_fields_v2 = ws_fetch_fields_v2(ws_res); - ws_fields = (void *)ws_fields_v2; - } - - while (true) { - int rows = 0; - const void *data = NULL; - ws_code = ws_fetch_raw_block(ws_res, &data, &rows); - - if (0 == rows) { - debugPrint( - "%s() LN%d, No more data from ws_fetch_raw_block(), " - "ws_taos: %p, code: 0x%08x, reason:%s\n", - __func__, __LINE__, *taos_v, ws_errno(ws_res), ws_errstr(ws_res)); - break; - } - - uint8_t type; - uint32_t len; - char buffer[VALUE_BUF_LEN] = {0}; - - for (int row = 0; row < rows; row++) { - const void *value0 = ws_get_value_in_block(ws_res, row, TSDB_SHOW_DB_NAME_INDEX, &type, &len); - if (NULL == value0) { - errorPrint("row: %d, ws_get_value_in_block() error!\n", row); - continue; - } - memset(buffer, 0, VALUE_BUF_LEN); - memcpy(buffer, value0, len); - debugPrint("%s() LN%d, dbname: %s\n", __func__, __LINE__, buffer); - - if (isSystemDatabase(buffer)) { - if (!g_args.allow_sys) { - continue; - } - } else if (g_args.databases) { - if (inDatabasesSeq(buffer) != 0) { - continue; - } - } else if (!g_args.all_databases) { - if (strcmp(g_args.arg_list[0], buffer)) { - continue; - } - } - - g_dbInfos[dbIndex] = (SDbInfo *)calloc(1, sizeof(SDbInfo)); - if (NULL == g_dbInfos[dbIndex]) { - errorPrint("%s() LN%d, failed to allocate %" PRIu64 " memory\n", __func__, __LINE__, - (uint64_t)sizeof(SDbInfo)); - ret = -1; - break; - } - - okPrint("Database: %s exists\n", buffer); - if (3 == g_majorVersionOfClient) { - struct WS_FIELD *fields = (struct WS_FIELD *)ws_fields; - for (int f = 0; f < fieldCount; f++) { - if (false == fillDBInfoWithFieldsWS(dbIndex, fields[f].name, row, f, ws_res)) { - ret = -1; - break; - } - } - } else { - struct WS_FIELD_V2 *fields = (struct WS_FIELD_V2 *)ws_fields; - for (int f = 0; f < fieldCount; f++) { - if (false == fillDBInfoWithFieldsWS(dbIndex, fields[f].name, row, f, ws_res)) { - ret = -1; - break; - } - } - } - - if (3 == g_majorVersionOfClient) { - fillDbExtraInfoV3WS(taos_v, g_dbInfos[dbIndex]->name, dbIndex); - } - - dbIndex++; - - if (g_args.databases) { - if (dbIndex > g_args.dumpDbCount) break; - } else if (!g_args.all_databases) { - if (dbIndex >= 1) break; - } - } - } - - ws_free_result(ws_res); - ws_res = NULL; - free(command); - - if (0 != ret) { - return ret; - } - - return dbIndex; -} - -bool jointCloudDsn() { - if ((NULL != g_args.host) && strlen(g_args.host)) { - if (0 == g_args.port) { - snprintf(g_args.cloudHost, MAX_HOSTNAME_LEN, "ws://%s:6041", g_args.host); - } else { - snprintf(g_args.cloudHost, MAX_HOSTNAME_LEN, "ws://%s:%d", g_args.host, g_args.port); - } - } else { - if (0 == g_args.port) { - snprintf(g_args.cloudHost, MAX_HOSTNAME_LEN, "ws://localhost:6041"); - } else { - snprintf(g_args.cloudHost, MAX_HOSTNAME_LEN, "ws://localhost:%d", g_args.port); - } - } - - g_args.dsn = g_args.cloudHost; - debugPrint("%s() LN%d, dsn: %s\n", __func__, __LINE__, g_args.dsn); - return true; -} - -bool splitCloudDsn() { - if (g_args.dsn) { - char *token = strstr(g_args.dsn, "?token="); - if (NULL == token) { - return false; - } else { - g_args.cloudToken = token + strlen("?token="); - } - - char *http = NULL, *https = NULL; - http = strstr(g_args.dsn, "http://"); - if (NULL == http) { - https = strstr(g_args.dsn, "https://"); - if (NULL == https) { - tstrncpy(g_args.cloudHost, g_args.dsn, MAX_HOSTNAME_LEN); - } else { - tstrncpy(g_args.cloudHost, https + strlen("https://"), MAX_HOSTNAME_LEN); - } - } else { - tstrncpy(g_args.cloudHost, http + strlen("http://"), MAX_HOSTNAME_LEN); - } - - char *colon = strstr(g_args.cloudHost, ":"); - if (colon) { - g_args.cloudHost[strlen(g_args.cloudHost) - strlen(colon)] = '\0'; - g_args.cloudPort = atoi(colon + 1); - } - - return true; - } - - return false; -} - -int64_t dumpTableDataWS(const int64_t index, FILE *fp, const char *tbName, const char *dbName, const int precision, - TableDes *tableDes, const int64_t start_time, const int64_t end_time) { - WS_TAOS *ws_taos; - if (NULL == (ws_taos = wsConnect())) { - return -1; - } - - WS_RES *ws_res = queryDbForDumpOutWS(&ws_taos, dbName, tbName, precision, start_time, end_time); - - int64_t totalRows = -1; - if (ws_res) { - totalRows = writeResultDebugWS(ws_res, fp, dbName, tbName); - } - - ws_free_result(ws_res); - ws_res = NULL; - ws_close(ws_taos); - - return totalRows; -} - -#endif // WEBSOCKET diff --git a/tools/taos-tools/test/CMakeLists.txt b/tools/taos-tools/test/CMakeLists.txt index 1586dae65d..182cb166dd 100644 --- a/tools/taos-tools/test/CMakeLists.txt +++ b/tools/taos-tools/test/CMakeLists.txt @@ -15,8 +15,9 @@ IF(TD_LINUX) ) target_include_directories( - benchmarkTest - PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../inc" + benchmarkTest PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/../inc" + "${CMAKE_CURRENT_SOURCE_DIR}/../deps/toolscJson/inc/" ) add_test( diff --git a/tools/taos-tools/test/benchmarkTest.cpp b/tools/taos-tools/test/benchmarkTest.cpp index 5ea296e4cb..389cfe6e71 100644 --- a/tools/taos-tools/test/benchmarkTest.cpp +++ b/tools/taos-tools/test/benchmarkTest.cpp @@ -16,11 +16,55 @@ #include #include -TEST(jsonTest, taosBenchmarkTest) { - printf("hello world taosBenchmark unit test for C \n"); + +// lower +char* strToLowerCopy(const char *str) { + if (str == NULL) { + return NULL; + } + size_t len = strlen(str); + char *result = (char*)malloc(len + 1); + if (result == NULL) { + return NULL; + } + for (size_t i = 0; i < len; i++) { + result[i] = tolower((unsigned char)str[i]); + } + result[len] = '\0'; + return result; +} + +// pase dsn +int32_t parseDsn(char* dsn, char **host, char **port, char **user, char **pwd); + +TEST(jsonTest, strToLowerCopy) { + // strToLowerCopy + const char* arr[][2] = { + {"ABC","abc"}, + {"Http://Localhost:6041","http://localhost:6041"}, + {"DEF","def"} + }; + + int rows = sizeof(arr) / sizeof(arr[0]); + for (int i = 0; i < rows; i++) { + char *p1 = (char *)arr[i][1]; + char *p2 = strToLowerCopy((char *)arr[i][0]); + printf("p1: %s\n", p1); + printf("p2: %s\n", p2); + int32_t cmp = strcmp(p1, p2); + if (p2) { + free(p2); + } + ASSERT_EQ(cmp, 0); + } + + // null + char * p = strToLowerCopy(NULL); + ASSERT_EQ(p, nullptr); } int main(int argc, char **argv) { + printf("Hello world taosBenchmark unit test for C \n"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/utils/test/c/CMakeLists.txt b/utils/test/c/CMakeLists.txt index e85fbf4d6d..160374cb3a 100644 --- a/utils/test/c/CMakeLists.txt +++ b/utils/test/c/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(tmq_demo tmqDemo.c) +add_dependencies(tmq_demo ${TAOS_NATIVE_LIB}) add_executable(tmq_sim tmqSim.c) add_executable(create_table createTable.c) add_executable(tmq_taosx_ci tmq_taosx_ci.c) @@ -27,7 +28,7 @@ endif(${TD_LINUX}) target_link_libraries( tmq_offset - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -35,7 +36,7 @@ target_link_libraries( target_link_libraries( tmq_multi_thread_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -43,7 +44,7 @@ target_link_libraries( target_link_libraries( create_table - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -51,7 +52,7 @@ target_link_libraries( target_link_libraries( tmq_demo - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -59,7 +60,7 @@ target_link_libraries( target_link_libraries( tmq_sim - PUBLIC ${TAOS_LIB_PLATFORM_SPEC} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -67,7 +68,7 @@ target_link_libraries( target_link_libraries( tmq_ts5466 - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -75,7 +76,7 @@ target_link_libraries( target_link_libraries( tmq_td32187 - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -114,7 +115,7 @@ target_link_libraries( ) target_link_libraries( tmq_td32526 - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -130,7 +131,7 @@ target_link_libraries( target_link_libraries( tmq_taosx_ci - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -138,7 +139,7 @@ target_link_libraries( target_link_libraries( tmq_offset_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -146,7 +147,7 @@ target_link_libraries( target_link_libraries( replay_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -154,7 +155,7 @@ target_link_libraries( target_link_libraries( write_raw_block_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -162,7 +163,7 @@ target_link_libraries( target_link_libraries( tmq_write_raw_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -170,7 +171,7 @@ target_link_libraries( target_link_libraries( sml_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -179,7 +180,7 @@ target_link_libraries( target_link_libraries( get_db_name_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -187,7 +188,7 @@ target_link_libraries( target_link_libraries( varbinary_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os @@ -204,9 +205,9 @@ target_link_libraries( if(${TD_LINUX}) target_link_libraries( tsz_test - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os ) -endif(${TD_LINUX}) \ No newline at end of file +endif(${TD_LINUX}) diff --git a/utils/tsim/CMakeLists.txt b/utils/tsim/CMakeLists.txt index b725ed919a..d450e378be 100644 --- a/utils/tsim/CMakeLists.txt +++ b/utils/tsim/CMakeLists.txt @@ -10,7 +10,7 @@ TARGET_INCLUDE_DIRECTORIES( ) TARGET_LINK_LIBRARIES( tsim_static - PUBLIC ${TAOS_LIB} + PUBLIC ${TAOS_NATIVE_LIB} PUBLIC util PUBLIC common PUBLIC os diff --git a/utils/tsim/src/simEntry.c b/utils/tsim/src/simEntry.c index dd11c21af0..2ebad8d191 100644 --- a/utils/tsim/src/simEntry.c +++ b/utils/tsim/src/simEntry.c @@ -43,6 +43,8 @@ int32_t simEntry(int32_t argc, char **argv) { } } + taos_options(TSDB_OPTION_DRIVER, "native"); + simInfo("simulator is running ..."); simSystemInit(); From 66da9e6e796edf3b3c9734aa5c7e4737476889ea Mon Sep 17 00:00:00 2001 From: Linhe Huo Date: Thu, 20 Mar 2025 22:58:29 +0800 Subject: [PATCH 03/28] chore: use taosadapter libtaosnative fix --- cmake/taosadapter_CMakeLists.txt.in | 2 +- tools/CMakeLists.txt | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/taosadapter_CMakeLists.txt.in b/cmake/taosadapter_CMakeLists.txt.in index ef6ed4af1d..dcd47070b7 100644 --- a/cmake/taosadapter_CMakeLists.txt.in +++ b/cmake/taosadapter_CMakeLists.txt.in @@ -2,7 +2,7 @@ # taosadapter ExternalProject_Add(taosadapter GIT_REPOSITORY https://github.com/taosdata/taosadapter.git - GIT_TAG 3.0 + GIT_TAG feat/new-libtaos-with-ws SOURCE_DIR "${TD_SOURCE_DIR}/tools/taosadapter" BINARY_DIR "" #BUILD_IN_SOURCE TRUE diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 110a644e90..d0f676d129 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -13,7 +13,7 @@ IF(TD_WEBSOCKET) PREFIX "taosws-rs" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosws-rs BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosws-rs no need cmake to config" PATCH_COMMAND @@ -31,7 +31,7 @@ IF(TD_WEBSOCKET) PREFIX "taosws-rs" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosws-rs BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosws-rs no need cmake to config" PATCH_COMMAND @@ -50,7 +50,7 @@ IF(TD_WEBSOCKET) PREFIX "taosws-rs" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosws-rs BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosws-rs no need cmake to config" PATCH_COMMAND @@ -190,12 +190,13 @@ ELSE() PREFIX "taosadapter" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosadapter BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosadapter no need cmake to config" PATCH_COMMAND COMMAND git clean -f -d BUILD_COMMAND + COMMAND tree ${CMAKE_BINARY_DIR}/build/lib COMMAND CGO_CFLAGS=-I${CMAKE_CURRENT_SOURCE_DIR}/../include/client CGO_LDFLAGS=-L${CMAKE_BINARY_DIR}/build/lib go build -a -ldflags "-X 'github.com/taosdata/taosadapter/v3/version.Version=${taos_version}' -X 'github.com/taosdata/taosadapter/v3/version.CommitID=${taosadapter_commit_sha1}' -X 'github.com/taosdata/taosadapter/v3/version.BuildInfo=${TD_VER_OSTYPE}-${TD_VER_CPUTYPE} ${TD_VER_DATE}'" # COMMAND CGO_CFLAGS=-I${CMAKE_CURRENT_SOURCE_DIR}/../include/client CGO_LDFLAGS=-L${CMAKE_BINARY_DIR}/build/lib go build -a -o taosadapter-debug -ldflags "-X 'github.com/taosdata/taosadapter/v3/version.Version=${taos_version}' -X 'github.com/taosdata/taosadapter/v3/version.CommitID=${taosadapter_commit_sha1}' -X 'github.com/taosdata/taosadapter/v3/version.BuildInfo=${TD_VER_OSTYPE}-${TD_VER_CPUTYPE} ${TD_VER_DATE}'" From 1a41b0a03143df78a25db7826e374f8601fac918 Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Fri, 21 Mar 2025 10:50:20 +0800 Subject: [PATCH 04/28] feat: switch connMode to Native --- tools/inc/pub.h | 1 + tools/shell/src/shellMain.c | 5 +++++ tools/taos-tools/src/benchMain.c | 9 +++++++-- tools/taos-tools/src/taosdump.c | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/inc/pub.h b/tools/inc/pub.h index 7e96c7a324..9fa8d0a142 100644 --- a/tools/inc/pub.h +++ b/tools/inc/pub.h @@ -50,6 +50,7 @@ #define CONN_MODE_INVALID -1 #define CONN_MODE_NATIVE 0 #define CONN_MODE_WEBSOCKET 1 +#define CONN_MODE_DEFAULT CONN_MODE_NATIVE // set default mode // define error show module #define INIT_PHASE "init" diff --git a/tools/shell/src/shellMain.c b/tools/shell/src/shellMain.c index 677d2808b2..8f4b2c4448 100644 --- a/tools/shell/src/shellMain.c +++ b/tools/shell/src/shellMain.c @@ -56,6 +56,11 @@ void initArgument(SShellArgs *pArgs) { // set conn mode int32_t setConnMode(int8_t connMode) { + // default + if (connMode == CONN_MODE_INVALID) { + connMode = CONN_MODE_DEFAULT; + } + // set conn mode char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); diff --git a/tools/taos-tools/src/benchMain.c b/tools/taos-tools/src/benchMain.c index 564bc80bc6..c2df571a22 100644 --- a/tools/taos-tools/src/benchMain.c +++ b/tools/taos-tools/src/benchMain.c @@ -98,7 +98,12 @@ int32_t applyConfigDir(char * cfgDir){ return code; } -int32_t setConnMode(int8_t connMode, char *dsn) { +int32_t setConnMode(int8_t connMode) { + // default + if (connMode == CONN_MODE_INVALID) { + connMode = CONN_MODE_DEFAULT; + } + // set conn mode char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); @@ -181,7 +186,7 @@ int main(int argc, char* argv[]) { } // conn mode - if (setConnMode(g_arguments->connMode, g_arguments->dsn) != 0) { + if (setConnMode(g_arguments->connMode) != 0) { exitLog(); return -1; } diff --git a/tools/taos-tools/src/taosdump.c b/tools/taos-tools/src/taosdump.c index 6c14ca080a..ec2917940b 100644 --- a/tools/taos-tools/src/taosdump.c +++ b/tools/taos-tools/src/taosdump.c @@ -10857,6 +10857,11 @@ static int inspectAvroFiles(int argc, char *argv[]) { } int32_t setConnMode(int8_t connMode) { + // default + if (connMode == CONN_MODE_INVALID) { + connMode = CONN_MODE_DEFAULT; + } + // set conn mode char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); From 18f9a95f82088e1aa0dc7b2d44293306c5b79a3c Mon Sep 17 00:00:00 2001 From: tjuzyp Date: Fri, 21 Mar 2025 12:13:05 +0800 Subject: [PATCH 05/28] ci: fix pthread_tryjoin_np compile error --- tools/taos-tools/inc/bench.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/taos-tools/inc/bench.h b/tools/taos-tools/inc/bench.h index a965984e33..0957bafded 100644 --- a/tools/taos-tools/inc/bench.h +++ b/tools/taos-tools/inc/bench.h @@ -16,8 +16,6 @@ #ifndef INC_BENCH_H_ #define INC_BENCH_H_ -#include "pub.h" - #define _GNU_SOURCE #define CURL_STATICLIB #define ALLOW_FORBID_FUNC @@ -25,6 +23,8 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#include "pub.h" + #ifdef LINUX #ifndef _ALPINE From 28ff3f75adaf7534628c1c2efba29871f71159da Mon Sep 17 00:00:00 2001 From: tjuzyp Date: Fri, 21 Mar 2025 12:15:06 +0800 Subject: [PATCH 06/28] chore: use taosadapter 3.0 branch in 3.0 --- cmake/taosadapter_CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/taosadapter_CMakeLists.txt.in b/cmake/taosadapter_CMakeLists.txt.in index dcd47070b7..ef6ed4af1d 100644 --- a/cmake/taosadapter_CMakeLists.txt.in +++ b/cmake/taosadapter_CMakeLists.txt.in @@ -2,7 +2,7 @@ # taosadapter ExternalProject_Add(taosadapter GIT_REPOSITORY https://github.com/taosdata/taosadapter.git - GIT_TAG feat/new-libtaos-with-ws + GIT_TAG 3.0 SOURCE_DIR "${TD_SOURCE_DIR}/tools/taosadapter" BINARY_DIR "" #BUILD_IN_SOURCE TRUE From 309cd47aa3393c066e482409d46df85644887eca Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Fri, 21 Mar 2025 13:11:46 +0800 Subject: [PATCH 07/28] fix: get default port rule --- tools/inc/pub.h | 6 ++++ tools/shell/src/shellEngine.c | 5 ++-- tools/shell/src/shellMain.c | 19 +------------ tools/src/pub.c | 47 ++++++++++++++++++++++++++++++++ tools/taos-tools/src/benchMain.c | 4 +-- tools/taos-tools/src/benchUtil.c | 3 +- tools/taos-tools/src/dumpUtil.c | 2 +- tools/taos-tools/src/taosdump.c | 20 +------------- 8 files changed, 63 insertions(+), 43 deletions(-) diff --git a/tools/inc/pub.h b/tools/inc/pub.h index 9fa8d0a142..fd9fa9558f 100644 --- a/tools/inc/pub.h +++ b/tools/inc/pub.h @@ -72,4 +72,10 @@ int8_t getConnMode(char *arg); char* strToLowerCopy(const char *str); int32_t parseDsn(char* dsn, char **host, char **port, char **user, char **pwd, char* error); +int32_t setConnMode(int8_t connMode, char *dsn); + +uint16_t defaultPort(int8_t connMode, char *dsn); + +int8_t defaultMode(int8_t connMode, char *dsn); + #endif // PUB_H_ \ No newline at end of file diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index 89d599997d..a0ec43a14c 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -21,6 +21,7 @@ #include "geosWrapper.h" #include "shellAuto.h" #include "shellInt.h" +#include "../../inc/pub.h" SShellObj shell = {0}; @@ -1347,7 +1348,7 @@ TAOS* createConnect(SShellArgs *pArgs) { if (pArgs->port_inputted) { port = pArgs->port; } else { - port = pArgs->connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + port = defaultPort(pArgs->connMode, pArgs->dsn); } sprintf(show, "host:%s port:%d ", host, port); @@ -1364,7 +1365,7 @@ TAOS* createConnect(SShellArgs *pArgs) { int32_t shellExecute(int argc, char *argv[]) { int32_t code = 0; printf(shell.info.clientVersion, shell.info.cusName, - shell.args.connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET, + defaultMode(shell.args.connMode, shell.args.dsn), taos_get_client_info(), shell.info.cusName); fflush(stdout); diff --git a/tools/shell/src/shellMain.c b/tools/shell/src/shellMain.c index 8f4b2c4448..fa03677824 100644 --- a/tools/shell/src/shellMain.c +++ b/tools/shell/src/shellMain.c @@ -54,23 +54,6 @@ void initArgument(SShellArgs *pArgs) { pArgs->port_inputted = false; } -// set conn mode -int32_t setConnMode(int8_t connMode) { - // default - if (connMode == CONN_MODE_INVALID) { - connMode = CONN_MODE_DEFAULT; - } - - // set conn mode - char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; - int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); - if (code != TSDB_CODE_SUCCESS) { - fprintf(stderr, "failed to load driver since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); - return -1; - } - return 0; -} - int main(int argc, char *argv[]) { #if !defined(WINDOWS) taosSetSignal(SIGBUS, shellCrashHandler); @@ -118,7 +101,7 @@ int main(int argc, char *argv[]) { return -1; } - if (setConnMode(shell.args.connMode)) { + if (setConnMode(&shell.args.connMode, shell.args.dsn)) { return -1; } diff --git a/tools/src/pub.c b/tools/src/pub.c index 0e1cbdd654..0eddbfbe04 100644 --- a/tools/src/pub.c +++ b/tools/src/pub.c @@ -11,6 +11,7 @@ */ #include + #include #include "../inc/pub.h" @@ -88,4 +89,50 @@ exit(-1); } } + + // set conn mode +int32_t setConnMode(int8_t connMode, char *dsn) { + // check default + if (connMode == CONN_MODE_INVALID) { + if (dsn && dsn[0] != 0) { + connMode = CONN_MODE_WEBSOCKET; + } else { + // default + connMode = CONN_MODE_DEFAULT; + } + } + + // set conn mode + char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; + int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); + if (code != TSDB_CODE_SUCCESS) { + fprintf(stderr, "failed to load driver. since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); + return code; + } + return 0; +} + +// default mode +int8_t defaultMode(int8_t connMode, char *dsn) { + int8_t mode = connMode; + if (connMode == CONN_MODE_INVALID) { + // no input from command line or config + if (dsn && dsn[0] != 0) { + mode = CONN_MODE_WEBSOCKET; + } else { + // default + mode = CONN_MODE_DEFAULT; + } + } + return mode; +} + +// get default port +uint16_t defaultPort(int8_t connMode, char *dsn) { + // consistent with setConnMode + int8_t mode = defaultMode(connMode, dsn); + + // default port + return mode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; +} \ No newline at end of file diff --git a/tools/taos-tools/src/benchMain.c b/tools/taos-tools/src/benchMain.c index c2df571a22..9d3583c7a8 100644 --- a/tools/taos-tools/src/benchMain.c +++ b/tools/taos-tools/src/benchMain.c @@ -109,7 +109,7 @@ int32_t setConnMode(int8_t connMode) { int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); if (code != TSDB_CODE_SUCCESS) { engineError(INIT_PHASE, "taos_options", code); - return -1; + return code; } infoPrint("Connect mode is : %s\n\n", strMode); @@ -186,7 +186,7 @@ int main(int argc, char* argv[]) { } // conn mode - if (setConnMode(g_arguments->connMode) != 0) { + if (setConnMode(g_arguments->connMode, g_arguments->dsn) != 0) { exitLog(); return -1; } diff --git a/tools/taos-tools/src/benchUtil.c b/tools/taos-tools/src/benchUtil.c index 32bc5b0813..fe0ab3613b 100644 --- a/tools/taos-tools/src/benchUtil.c +++ b/tools/taos-tools/src/benchUtil.c @@ -13,6 +13,7 @@ #include #include #include "benchLog.h" +#include "pub.h" char resEncodingChunk[] = "Encoding: chunked"; char succMessage[] = "succ"; @@ -304,7 +305,7 @@ SBenchConn* initBenchConnImpl() { if (g_arguments->port_inputted) { port = g_arguments->port; } else { - port = g_arguments->connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + port = defaultPort(g_arguments->connMode, g_arguments->dsn); } sprintf(show, "host:%s port:%d ", host, port); diff --git a/tools/taos-tools/src/dumpUtil.c b/tools/taos-tools/src/dumpUtil.c index 8535a2f0a7..d2403ec4c0 100644 --- a/tools/taos-tools/src/dumpUtil.c +++ b/tools/taos-tools/src/dumpUtil.c @@ -136,7 +136,7 @@ TAOS *taosConnect(const char *dbName) { if (g_args.port_inputted) { port = g_args.port; } else { - port = g_args.connMode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + port = defaultPort(g_args.connMode, g_args.dsn); } sprintf(show, "host:%s port:%d ", host, port); diff --git a/tools/taos-tools/src/taosdump.c b/tools/taos-tools/src/taosdump.c index ec2917940b..6ef633fb9b 100644 --- a/tools/taos-tools/src/taosdump.c +++ b/tools/taos-tools/src/taosdump.c @@ -10856,24 +10856,6 @@ static int inspectAvroFiles(int argc, char *argv[]) { return ret; } -int32_t setConnMode(int8_t connMode) { - // default - if (connMode == CONN_MODE_INVALID) { - connMode = CONN_MODE_DEFAULT; - } - - // set conn mode - char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; - int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); - if (code != TSDB_CODE_SUCCESS) { - engineError(INIT_PHASE, "taos_options", code); - return -1; - } - - infoPrint("\nConnect mode is : %s\n\n", strMode); - return 0; -} - int main(int argc, char *argv[]) { g_uniqueID = getUniqueIDFromEpoch(); @@ -10928,7 +10910,7 @@ int main(int argc, char *argv[]) { } // conn mode - if (setConnMode(g_args.connMode) != 0) { + if (setConnMode(g_args.connMode, g_args.dsn) != 0) { return -1; } From 5db660a58c07be223f3b998a55677c96d402ca09 Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Fri, 21 Mar 2025 13:15:24 +0800 Subject: [PATCH 08/28] fix: build error --- tools/shell/src/shellMain.c | 2 +- tools/src/pub.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/shell/src/shellMain.c b/tools/shell/src/shellMain.c index fa03677824..31fad97bd4 100644 --- a/tools/shell/src/shellMain.c +++ b/tools/shell/src/shellMain.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) { return -1; } - if (setConnMode(&shell.args.connMode, shell.args.dsn)) { + if (setConnMode(shell.args.connMode, shell.args.dsn)) { return -1; } diff --git a/tools/src/pub.c b/tools/src/pub.c index 0eddbfbe04..7e561b57d9 100644 --- a/tools/src/pub.c +++ b/tools/src/pub.c @@ -105,7 +105,7 @@ int32_t setConnMode(int8_t connMode, char *dsn) { // set conn mode char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); - if (code != TSDB_CODE_SUCCESS) { + if (code != 0) { fprintf(stderr, "failed to load driver. since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); return code; } From f5a0d8d6f40be0a30faee97bdbe75dc483a295a1 Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Fri, 21 Mar 2025 13:17:08 +0800 Subject: [PATCH 09/28] fix: remove old setConnMode --- tools/taos-tools/src/benchMain.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tools/taos-tools/src/benchMain.c b/tools/taos-tools/src/benchMain.c index 9d3583c7a8..fa47329b37 100644 --- a/tools/taos-tools/src/benchMain.c +++ b/tools/taos-tools/src/benchMain.c @@ -98,24 +98,6 @@ int32_t applyConfigDir(char * cfgDir){ return code; } -int32_t setConnMode(int8_t connMode) { - // default - if (connMode == CONN_MODE_INVALID) { - connMode = CONN_MODE_DEFAULT; - } - - // set conn mode - char * strMode = connMode == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET; - int32_t code = taos_options(TSDB_OPTION_DRIVER, strMode); - if (code != TSDB_CODE_SUCCESS) { - engineError(INIT_PHASE, "taos_options", code); - return code; - } - - infoPrint("Connect mode is : %s\n\n", strMode); - return 0; -} - int main(int argc, char* argv[]) { int ret = 0; From def4f61f170c26a33b811b39cd4e63196b40036c Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Fri, 21 Mar 2025 13:27:45 +0800 Subject: [PATCH 10/28] fix: show connMode is ok for taos --- tools/shell/src/shellEngine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index a0ec43a14c..46d0c88b02 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -1365,7 +1365,7 @@ TAOS* createConnect(SShellArgs *pArgs) { int32_t shellExecute(int argc, char *argv[]) { int32_t code = 0; printf(shell.info.clientVersion, shell.info.cusName, - defaultMode(shell.args.connMode, shell.args.dsn), + defaultMode(shell.args.connMode, shell.args.dsn) == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET, taos_get_client_info(), shell.info.cusName); fflush(stdout); From a73f69100d898a4035292e89ce449881c18c740c Mon Sep 17 00:00:00 2001 From: tjuzyp Date: Fri, 21 Mar 2025 13:29:21 +0800 Subject: [PATCH 11/28] chore: use taosws 3.0 branch in TDengine 3.0 --- cmake/taosws_CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/taosws_CMakeLists.txt.in b/cmake/taosws_CMakeLists.txt.in index b23c92cef9..820418a452 100644 --- a/cmake/taosws_CMakeLists.txt.in +++ b/cmake/taosws_CMakeLists.txt.in @@ -2,7 +2,7 @@ # taosws-rs ExternalProject_Add(taosws-rs GIT_REPOSITORY https://github.com/taosdata/taos-connector-rust.git - GIT_TAG feat/new-libtaos-with-ws + GIT_TAG 3.0 SOURCE_DIR "${TD_SOURCE_DIR}/tools/taosws-rs" BINARY_DIR "" #BUILD_IN_SOURCE TRUE From cb9f1fde1e581a2d893f97af7ae99e8d37476ac9 Mon Sep 17 00:00:00 2001 From: Xuefeng Tan <1172915550@qq.com> Date: Fri, 21 Mar 2025 16:50:48 +0800 Subject: [PATCH 12/28] chore: update taosadapter depends (#30326) --- tools/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index d0f676d129..fa676f667d 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -136,7 +136,7 @@ ELSE() PREFIX "taosadapter" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosadapter BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosadapter no need cmake to config" PATCH_COMMAND @@ -165,7 +165,7 @@ ELSE() PREFIX "taosadapter" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/taosadapter BUILD_ALWAYS off - DEPENDS ${TAOS_LIB} + DEPENDS ${TAOS_NATIVE_LIB} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND cmake -E echo "taosadapter no need cmake to config" PATCH_COMMAND From 4d348a66d674d88cd6f0c050239a4b4929fd0b4d Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 21 Mar 2025 22:27:00 +0800 Subject: [PATCH 13/28] Update 09-error-code.md (#30327) --- docs/zh/14-reference/09-error-code.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/zh/14-reference/09-error-code.md b/docs/zh/14-reference/09-error-code.md index 7a87e1ddfb..517658482c 100644 --- a/docs/zh/14-reference/09-error-code.md +++ b/docs/zh/14-reference/09-error-code.md @@ -591,3 +591,17 @@ description: TDengine 服务端的错误码列表和详细说明 | 0x80006206 | Virtual table not support in Topic | 不支持在订阅中使用虚拟表 | 不在订阅中使用虚拟表 | | 0x80006207 | Virtual super table query not support origin table from different databases | 虚拟超级表不支持子表的数据源来自不同的数据库 | 确保虚拟超级表的子表的数据源都来自同一个数据库 | + +## TDgpt + +| 错误码 | 错误描述 | 可能的出错场景或者可能的原因 | 建议用户采取的措施 | +| ---------- | --------------------- | -------------------------------------------------------------------------------- | ------------------------------ | +| 0x80000440 | Analysis service response is NULL | 分析服务返回错误 | 检查服务端日志确认返回信息是否正确 | +| 0x80000441 | Analysis service can't access | 分析服务无法使用 | 检查 anoded 服务是否可用 | +| 0x80000442 | Analysis algorithm is missing | 未指定分析算法名称 | 增加算法名称 | +| 0x80000443 | Analysis algorithm not loaded | 指定算法未加载 | 指定算法未加载 | +| 0x80000444 | Analysis invalid buffer type | 缓存数据格式不对 | 具体查看server端的错误日志 | +| 0x80000445 | Analysis failed since anode return error | anode 返回错误信息 | 请检查服务端日志确认问题原因 | +| 0x80000446 | Analysis failed since too many input rows for anode | 输入数据太多 | 减小分析数据输入规模 | +| 0x80000447 | white-noise data not processed | 白噪声数据不分析 | | +| 0x80000448 | tdgpt internal error, not processed | anode 出现内部错误 | 具体查看server端的错误日志 | From ddb4cd6592e4f15a413819a22ab954167dfa6cf0 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 22 Mar 2025 13:14:01 +0800 Subject: [PATCH 14/28] doc: add error code information about tdgpt (#30338) * Update 09-error-code.md * Update 09-error-code.md * Update 09-error-code.md --- docs/en/14-reference/09-error-code.md | 14 ++++++++++++++ docs/zh/14-reference/09-error-code.md | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/en/14-reference/09-error-code.md b/docs/en/14-reference/09-error-code.md index 139f8d38d7..3305eb18eb 100644 --- a/docs/en/14-reference/09-error-code.md +++ b/docs/en/14-reference/09-error-code.md @@ -558,6 +558,20 @@ This document details the server error codes that may be encountered when using | 0x80004017 | Invalid status, please subscribe topic first | tmq status invalidate | Without calling subscribe, directly poll data | | 0x80004100 | Stream task not exist | The stream computing task does not exist | Check the server-side error logs | +## TDgpt + +| Error Code | Description | Possible Error Scenarios or Reasons | Recommanded Actions for Users | +| ---------- | --------------------- | -------------------------------------------------------------------------------- | ------------------------------ | +| 0x80000440 | Analysis service response is NULL | The response content is empty | Check the taosanode.app.log for detailed response information | +| 0x80000441 | Analysis service can't access | Service is not work currectly, or network is broken | Check the status of taosanode and network status | +| 0x80000442 | Analysis algorithm is missing | Algorithm used in analysis is not specified | Add the "algo" parameter in forecast function or anomaly_window clause | +| 0x80000443 | Analysis algorithm not loaded | The specified algorithm is not available | Check for the specified algorithm | +| 0x80000444 | Analysis invalid buffer type | The bufferred data type is invalid | Check the taosanode.app.log for more details | +| 0x80000445 | Analysis failed since anode return error | The responses from anode with error message | Check the taosanode.app.log for more details | +| 0x80000446 | Analysis failed since too many input rows for anode | Input data is too many | Reduce the rows of input data to below than the threshold | +| 0x80000447 | white-noise data not processed | white noise data is not processed | Ignore the white noise check or use another input data | +| 0x80000448 | Analysis internal error, not processed | Internal error occurs | Check the taosanode.app.log for more details | + ## virtual table diff --git a/docs/zh/14-reference/09-error-code.md b/docs/zh/14-reference/09-error-code.md index 517658482c..ef585cf706 100644 --- a/docs/zh/14-reference/09-error-code.md +++ b/docs/zh/14-reference/09-error-code.md @@ -604,4 +604,4 @@ description: TDengine 服务端的错误码列表和详细说明 | 0x80000445 | Analysis failed since anode return error | anode 返回错误信息 | 请检查服务端日志确认问题原因 | | 0x80000446 | Analysis failed since too many input rows for anode | 输入数据太多 | 减小分析数据输入规模 | | 0x80000447 | white-noise data not processed | 白噪声数据不分析 | | -| 0x80000448 | tdgpt internal error, not processed | anode 出现内部错误 | 具体查看server端的错误日志 | +| 0x80000448 | Analysis internal error, not processed | anode 出现内部错误 | 具体查看server端的日志 (taosanode.app.log) | From 0ee9e3db566a05b8dec95d57d83bfe6d6ea61fce Mon Sep 17 00:00:00 2001 From: chenhaoran Date: Sat, 22 Mar 2025 13:56:21 +0800 Subject: [PATCH 15/28] refactor: streamline library removal and linking in installation scripts --- packaging/tools/install.sh | 6 +++++- packaging/tools/make_install.sh | 34 ++++++++++++++++++++++++++------ packaging/tools/remove.sh | 14 ++++++------- packaging/tools/remove_client.sh | 17 ++++++++-------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packaging/tools/install.sh b/packaging/tools/install.sh index 8fd483b6a7..56a18c64c6 100755 --- a/packaging/tools/install.sh +++ b/packaging/tools/install.sh @@ -273,9 +273,12 @@ function install_lib() { ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : + ${csudo}rm -f ${lib_link_dir}/libtaosws.* || : + ${csudo}rm -f ${lib64_link_dir}/libtaosws.* || : #${csudo}rm -rf ${v15_java_app_dir} || : ${csudo}cp -rf ${script_dir}/driver/* ${install_main_dir}/driver && ${csudo}chmod 777 ${install_main_dir}/driver/* + #link lib/link_dir ${csudo}ln -sf ${install_main_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.so.1 ${csudo}ln -sf ${lib_link_dir}/libtaos.so.1 ${lib_link_dir}/libtaos.so ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib_link_dir}/libtaosnative.so.1 @@ -283,13 +286,14 @@ function install_lib() { [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.so ${lib_link_dir}/libtaosws.so || : + #link lib64/link_dir if [[ -d ${lib64_link_dir} && ! -e ${lib64_link_dir}/libtaos.so ]]; then ${csudo}ln -sf ${install_main_dir}/driver/libtaos.* ${lib64_link_dir}/libtaos.so.1 || : ${csudo}ln -sf ${lib64_link_dir}/libtaos.so.1 ${lib64_link_dir}/libtaos.so || : ${csudo}ln -sf ${install_main_dir}/driver/libtaosnative.* ${lib64_link_dir}/libtaosnative.so.1 || : ${csudo}ln -sf ${lib64_link_dir}/libtaosnative.so.1 ${lib64_link_dir}/libtaosnative.so || : - [ -f ${install_main_dir}/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/libtaosws.so ${lib64_link_dir}/libtaosws.so || : + [ -f ${install_main_dir}/driver/libtaosws.so ] && ${csudo}ln -sf ${install_main_dir}/driver/libtaosws.so ${lib64_link_dir}/libtaosws.so || : fi ${csudo}ldconfig diff --git a/packaging/tools/make_install.sh b/packaging/tools/make_install.sh index 4a694f9841..de7dd2d2cb 100755 --- a/packaging/tools/make_install.sh +++ b/packaging/tools/make_install.sh @@ -312,15 +312,37 @@ function install_avro() { function install_lib() { # Remove links - ${csudo}rm -f ${lib_link_dir}/libtaos.* || : - ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : - [ -f ${lib_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.so || : + remove_links() { + local dir=$1 + find ${dir} -name "libtaos.*" -exec ${csudo}rm -f {} \; || : + find ${dir} -name "libtaosnative.so" -exec ${csudo}rm -f {} \; || : + find ${dir} -name "libtaosws.so" -exec ${csudo}rm -f {} \; || : + } + + remove_links ${lib_link_dir} + if [ "$osType" != "Darwin" ]; then - ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : - ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : - [ -f ${lib64_link_dir}/libtaosws.so ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.so || : + remove_links ${lib64_link_dir} fi + # Copy and set permissions for libraries + copy_and_set_permissions() { + local src=$1 + local dest=$2 + if [ "$osType" != "Darwin" ]; then + ${csudo}cp ${src} ${dest} && ${csudo}chmod 777 ${dest} + else + ${csudo}cp -Rf ${src} ${dest} && ${csudo}chmod 777 ${dest} + fi + } + + # Create symbolic links + create_symlink() { + local target=$1 + local link_name=$2 + ${csudo}ln -sf ${target} ${link_name} + } + if [ "$osType" != "Darwin" ]; then ${csudo}cp ${binary_dir}/build/lib/libtaos.so.${verNumber} \ ${install_main_dir}/driver && diff --git a/packaging/tools/remove.sh b/packaging/tools/remove.sh index d62aa5a564..91b1dfc461 100755 --- a/packaging/tools/remove.sh +++ b/packaging/tools/remove.sh @@ -5,7 +5,7 @@ set -e #set -x -verMode=edge +verMode=cluster osType=`uname` RED='\033[0;31m' @@ -179,13 +179,13 @@ remove_bin() { function clean_lib() { # Remove link - ${csudo}rm -f ${lib_link_dir}/libtaos.* || : - [ -f ${lib_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : - [ -f ${lib_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.* || : + ${csudo}find ${lib_link_dir} -name "libtaos.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib_link_dir} -name "libtaosnative.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib_link_dir} -name "libtaosws.*" -exec ${csudo}rm -f {} \; || : - ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : - [ -f ${lib64_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : - [ -f ${lib64_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.* || : + ${csudo}find ${lib64_link_dir} -name "libtaos.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib64_link_dir} -name "libtaosnative.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib64_link_dir} -name "libtaosws.*" -exec ${csudo}rm -f {} \; || : #${csudo}rm -rf ${v15_java_app_dir} || : } diff --git a/packaging/tools/remove_client.sh b/packaging/tools/remove_client.sh index e6ec9c3768..e5c3842a5e 100755 --- a/packaging/tools/remove_client.sh +++ b/packaging/tools/remove_client.sh @@ -70,15 +70,16 @@ function clean_bin() { } function clean_lib() { - # Remove link - ${csudo}rm -f ${lib_link_dir}/libtaos.* || : - [ -f ${lib_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosws.* || : - [ -f ${lib_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib_link_dir}/libtaosnative.* || : + # Remove link + ${csudo}find ${lib_link_dir} -name "libtaos.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib_link_dir} -name "libtaosnative.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib_link_dir} -name "libtaosws.*" -exec ${csudo}rm -f {} \; || : + + ${csudo}find ${lib64_link_dir} -name "libtaos.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib64_link_dir} -name "libtaosnative.*" -exec ${csudo}rm -f {} \; || : + ${csudo}find ${lib64_link_dir} -name "libtaosws.*" -exec ${csudo}rm -f {} \; || : + #${csudo}rm -rf ${v15_java_app_dir} || : - ${csudo}rm -f ${lib64_link_dir}/libtaos.* || : - [ -f ${lib64_link_dir}/libtaosws.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosws.* || : - [ -f ${lib64_link_dir}/libtaosnative.* ] && ${csudo}rm -f ${lib64_link_dir}/libtaosnative.* || : - #${csudo}rm -rf ${v15_java_app_dir} || : } function clean_header() { From 9c07a28e6573b0e32dab04b8eff14c5cc0bb6798 Mon Sep 17 00:00:00 2001 From: haoranchen Date: Sat, 22 Mar 2025 14:35:05 +0800 Subject: [PATCH 16/28] Update remove.sh --- packaging/tools/remove.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/tools/remove.sh b/packaging/tools/remove.sh index 91b1dfc461..1f75f00d5d 100755 --- a/packaging/tools/remove.sh +++ b/packaging/tools/remove.sh @@ -5,7 +5,7 @@ set -e #set -x -verMode=cluster +verMode=edge osType=`uname` RED='\033[0;31m' @@ -338,4 +338,4 @@ fi command -v systemctl >/dev/null 2>&1 && ${csudo}systemctl daemon-reload >/dev/null 2>&1 || true echo echo "${productName} is removed successfully!" -echo \ No newline at end of file +echo From 3a29a1daf12dcfe156066d82d99c8edeb39b9f5e Mon Sep 17 00:00:00 2001 From: WANG Xu Date: Sat, 22 Mar 2025 13:36:29 +0800 Subject: [PATCH 17/28] ci: add release build Signed-off-by: WANG Xu --- .github/workflows/tdengine-release-build.yml | 114 +++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 .github/workflows/tdengine-release-build.yml diff --git a/.github/workflows/tdengine-release-build.yml b/.github/workflows/tdengine-release-build.yml new file mode 100644 index 0000000000..ef708a0ac9 --- /dev/null +++ b/.github/workflows/tdengine-release-build.yml @@ -0,0 +1,114 @@ +name: TDengine Release Build + +on: + push: + branches: + - 'main' + - '3.*' + paths-ignore: + - 'docs/**' + - 'packaging/**' + - 'tests/**' + - '**/*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Run on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-22.04 + - macos-14 + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.18 + + - name: Install dependencies on Linux + if: runner.os == 'Linux' + run: | + sudo apt update -y + sudo apt install -y \ + build-essential \ + cmake \ + gawk \ + libgeos-dev \ + libjansson-dev \ + liblzma-dev \ + libsnappy-dev \ + libssl-dev \ + libz-dev \ + pkg-config \ + zlib1g + + - name: Install dependencies on macOS + if: runner.os == 'macOS' + run: | + brew update + brew install \ + argp-standalone \ + gawk \ + gflags \ + geos \ + jansson \ + openssl \ + pkg-config \ + snappy \ + zlib + + - name: Build and install TDengine + run: | + mkdir debug && cd debug + cmake .. -DBUILD_TOOLS=true \ + -DBUILD_KEEPER=true \ + -DBUILD_HTTP=false \ + -DBUILD_TEST=true \ + -DWEBSOCKET=true \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_DEPENDENCY_TESTS=false + make -j 4 + sudo make install + which taosd + which taosadapter + which taoskeeper + + - name: Statistics ldd + run: | + find ${{ github.workspace }}/debug/build/lib -type f -name "*.so" -print0 | xargs -0 ldd || true + find ${{ github.workspace }}/debug/build/bin -type f -print0 | xargs -0 ldd || true + + - name: Statistics size + run: | + find ${{ github.workspace }}/debug/build/lib -type f -print0 | xargs -0 ls -lhrS + find ${{ github.workspace }}/debug/build/bin -type f -print0 | xargs -0 ls -lhrS + + - name: Start taosd + run: | + cp /etc/taos/taos.cfg ./ + sudo echo "supportVnodes 256" >> taos.cfg + nohup sudo taosd -c taos.cfg & + + - name: Start taosadapter + run: nohup sudo taosadapter & + + - name: Run tests with taosBenchmark + run: | + taosBenchmark -t 10 -n 10 -y + taos -s "select count(*) from test.meters" + + - name: Clean up + if: always() + run: | + if pgrep taosd; then sudo pkill taosd; fi + if pgrep taosadapter; then sudo pkill taosadapter; fi From 523b7003a4d007c0a0132d0e54c706956ec586bf Mon Sep 17 00:00:00 2001 From: haoranchen Date: Sat, 22 Mar 2025 15:31:16 +0800 Subject: [PATCH 18/28] fix: add requests pkg in tdgpt install.sh --- tools/tdgpt/script/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tdgpt/script/install.sh b/tools/tdgpt/script/install.sh index 9952b7f0af..e5bf87740b 100755 --- a/tools/tdgpt/script/install.sh +++ b/tools/tdgpt/script/install.sh @@ -400,6 +400,7 @@ function install_anode_venv() { ${csudo}${venvDir}/bin/pip3 install uwsgi ${csudo}${venvDir}/bin/pip3 install torch --index-url https://download.pytorch.org/whl/cpu ${csudo}${venvDir}/bin/pip3 install --upgrade keras + ${csudo}${venvDir}/bin/pip3 install requests echo -e "Install python library for venv completed!" } From e273a943eaeb4a872736598cf495233a8498dea1 Mon Sep 17 00:00:00 2001 From: Linhe Huo Date: Sat, 22 Mar 2025 20:44:07 +0800 Subject: [PATCH 19/28] fix: add show connMode string (#30323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add show connMode string * fix: add stdbool.h to pub.h * fix: remove trash file army/output.txt * fix: caseBase.py modify syntax error * fix: restore -R option for taosdump * fix: taosdumpCommandline.py case * fix: native stmt write normal table failed * fix: taosdumpCommandline.py case passed * fix: restore test.py from main branch * fix: taosCli.py check default conn mode * fix: commandline-sml.py case pass * fix: websiteCase.py case passed * fix: connMode.py case * fix: modify default port is 0 * fix: taos_options with config dir not work * fix: websocket.py delete -D timeout options * fix: default_tmq_json.py context move to default_json.py, so delete * fix python kafka bug * chore: improve taos_init in wrapper * chore: add installation path preparation in build workflow * fix connMode bug * fix: fix tmq conf/consumer new error in wrapperFunc.c * fix: correct the spelling toss -> taosGetInstall... * chore: fix compile error in wrapperFunc.c * fix: createConnect fix memory leak * fix: tsim forbid CHECK ODR * modify userOperTest uuse static lib * reverse userOperTest use static lib --------- Co-authored-by: Alex Duan <417921451@qq.com> Co-authored-by: taos-support Co-authored-by: “chris <“zk662144@163.com”> Co-authored-by: t_max <1172915550@qq.com> Co-authored-by: sheyanjie-qq <249478495@qq.com> --- .github/workflows/tdengine-build.yml | 5 ++ .../examples/python/kafka_example_consumer.py | 8 +-- source/client/test/CMakeLists.txt | 2 +- source/client/wrapper/src/wrapperDriver.c | 4 +- source/client/wrapper/src/wrapperFunc.c | 30 +++++++---- tests/army/cmdline/taosCli.py | 11 +++- tests/army/frame/caseBase.py | 4 +- tests/army/output.txt | 52 ------------------- tests/army/test.py | 6 +-- .../tools/benchmark/basic/commandline-sml.py | 12 ++--- tests/army/tools/benchmark/basic/connMode.py | 9 ++-- .../army/tools/benchmark/basic/websiteCase.py | 2 +- tests/army/tools/benchmark/ws/websocket.py | 2 +- .../taosdump/native/taosdumpCommandline.py | 11 +--- tests/develop-test/test.py | 2 - tests/docs-examples-test/python.sh | 5 +- tests/parallel_test/cases.task | 1 - tests/script/test.sh | 3 ++ tests/system-test/test.py | 19 +++---- tools/inc/pub.h | 6 ++- tools/shell/src/shellArguments.c | 4 -- tools/shell/src/shellEngine.c | 11 ++-- tools/shell/src/shellMain.c | 2 +- tools/src/pub.c | 16 ++++-- tools/taos-tools/src/benchData.c | 4 +- tools/taos-tools/src/benchMain.c | 2 +- tools/taos-tools/src/taosdump.c | 7 ++- 27 files changed, 105 insertions(+), 135 deletions(-) delete mode 100644 tests/army/output.txt diff --git a/.github/workflows/tdengine-build.yml b/.github/workflows/tdengine-build.yml index 017c9d69fa..07cd17feab 100644 --- a/.github/workflows/tdengine-build.yml +++ b/.github/workflows/tdengine-build.yml @@ -74,6 +74,11 @@ jobs: snappy \ zlib + - name: prepare install path + run: | + sudo mkdir -p /usr/local/lib + sudo mkdir -p /usr/local/include + - name: Build and install TDengine run: | mkdir debug && cd debug diff --git a/docs/examples/python/kafka_example_consumer.py b/docs/examples/python/kafka_example_consumer.py index e2d5cf535b..43c140fe78 100644 --- a/docs/examples/python/kafka_example_consumer.py +++ b/docs/examples/python/kafka_example_consumer.py @@ -182,7 +182,7 @@ def test_json_to_taos(consumer: Consumer): 'voltage': 105, 'phase': 0.02027, }), partition=1, topic='test', serialized_key_size=None, serialized_header_size=None, - serialized_value_size=None, timestamp=time.time(), timestamp_type=None), + serialized_value_size=None, timestamp=time.time(), timestamp_type=None, leader_epoch=0), ConsumerRecord(checksum=None, headers=None, offset=1, key=None, value=json.dumps({'table_name': 'd1', 'ts': '2022-12-06 15:13:39.643', @@ -190,7 +190,7 @@ def test_json_to_taos(consumer: Consumer): 'voltage': 102, 'phase': 0.02027, }), partition=1, topic='test', serialized_key_size=None, serialized_header_size=None, - serialized_value_size=None, timestamp=time.time(), timestamp_type=None), + serialized_value_size=None, timestamp=time.time(), timestamp_type=None,leader_epoch=0 ), ] ] @@ -203,11 +203,11 @@ def test_line_to_taos(consumer: Consumer): ConsumerRecord(checksum=None, headers=None, offset=1, key=None, value="d0 values('2023-01-01 00:00:00.001', 3.49, 109, 0.02737)".encode('utf-8'), partition=1, topic='test', serialized_key_size=None, serialized_header_size=None, - serialized_value_size=None, timestamp=time.time(), timestamp_type=None), + serialized_value_size=None, timestamp=time.time(), timestamp_type=None,leader_epoch=0 ), ConsumerRecord(checksum=None, headers=None, offset=1, key=None, value="d1 values('2023-01-01 00:00:00.002', 6.19, 112, 0.09171)".encode('utf-8'), partition=1, topic='test', serialized_key_size=None, serialized_header_size=None, - serialized_value_size=None, timestamp=time.time(), timestamp_type=None), + serialized_value_size=None, timestamp=time.time(), timestamp_type=None,leader_epoch=0 ), ] ] consumer._line_to_taos(messages=records) diff --git a/source/client/test/CMakeLists.txt b/source/client/test/CMakeLists.txt index cee5dc08f9..161deb12cd 100644 --- a/source/client/test/CMakeLists.txt +++ b/source/client/test/CMakeLists.txt @@ -129,4 +129,4 @@ add_test( add_test( NAME userOperTest COMMAND userOperTest -) \ No newline at end of file +) diff --git a/source/client/wrapper/src/wrapperDriver.c b/source/client/wrapper/src/wrapperDriver.c index 415affc66f..341485e448 100644 --- a/source/client/wrapper/src/wrapperDriver.c +++ b/source/client/wrapper/src/wrapperDriver.c @@ -39,7 +39,7 @@ EDriverType tsDriverType = DRIVER_NATIVE; void *tsDriver = NULL; -static int32_t tossGetDevelopPath(char *driverPath, const char *driverName) { +static int32_t taosGetDevelopPath(char *driverPath, const char *driverName) { char appPath[PATH_MAX] = {0}; int32_t ret = taosAppPath(appPath, PATH_MAX); if (ret == 0) { @@ -67,7 +67,7 @@ int32_t taosDriverInit(EDriverType driverType) { driverName = DRIVER_WSBSOCKET_NAME; } - if (tsDriver == NULL && tossGetDevelopPath(driverPath, driverName) == 0) { + if (tsDriver == NULL && taosGetDevelopPath(driverPath, driverName) == 0) { tsDriver = taosLoadDll(driverPath); } diff --git a/source/client/wrapper/src/wrapperFunc.c b/source/client/wrapper/src/wrapperFunc.c index e77de0b82d..ed5200c064 100644 --- a/source/client/wrapper/src/wrapperFunc.c +++ b/source/client/wrapper/src/wrapperFunc.c @@ -19,6 +19,9 @@ static TdThreadOnce tsDriverOnce = PTHREAD_ONCE_INIT; volatile int32_t tsDriverOnceRet = 0; +static TdThreadOnce tsInitOnce = PTHREAD_ONCE_INIT; +volatile int32_t tsInitOnceRet = 0; + #define ERR_VOID(code) \ terrno = code; \ return; @@ -89,21 +92,25 @@ setConfRet taos_set_config(const char *config) { return (*fp_taos_set_config)(config); } -static void taos_init_wrapper(void) { +static void taos_init_driver(void) { tsDriverOnceRet = taosDriverInit(tsDriverType); if (tsDriverOnceRet != 0) return; + tsDriverOnceRet = 0; +} +static void taos_init_wrapper(void) { if (fp_taos_init == NULL) { terrno = TSDB_CODE_DLL_FUNC_NOT_LOAD; - tsDriverOnceRet = -1; + tsInitOnceRet = -1; } else { - tsDriverOnceRet = (*fp_taos_init)(); + tsInitOnceRet = (*fp_taos_init)(); } } int taos_init(void) { - (void)taosThreadOnce(&tsDriverOnce, taos_init_wrapper); - return tsDriverOnceRet; + (void)taosThreadOnce(&tsDriverOnce, taos_init_driver); + (void)taosThreadOnce(&tsInitOnce, taos_init_wrapper); + return tsInitOnceRet; } void taos_cleanup(void) { @@ -126,11 +133,7 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { terrno = TSDB_CODE_REPEAT_INIT; return -1; } - - if (taos_init() != 0) { - terrno = TSDB_CODE_DLL_NOT_LOAD; - return -1; - } + (void)taosThreadOnce(&tsDriverOnce, taos_init_driver); CHECK_INT(fp_taos_options); return (*fp_taos_options)(option, arg); @@ -143,7 +146,7 @@ int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const voi TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) { if (taos_init() != 0) { - terrno = TSDB_CODE_DLL_NOT_LOAD; + //terrno = TSDB_CODE_DLL_NOT_LOAD; return NULL; } @@ -646,6 +649,7 @@ TAOS_RES *taos_schemaless_insert_ttl_with_reqid_tbname_key(TAOS *taos, char *lin } tmq_conf_t *tmq_conf_new() { + taos_init(); CHECK_PTR(fp_tmq_conf_new); return (*fp_tmq_conf_new)(); } @@ -666,6 +670,7 @@ void tmq_conf_set_auto_commit_cb(tmq_conf_t *conf, tmq_commit_cb *cb, void *para } tmq_list_t *tmq_list_new() { + taos_init(); CHECK_PTR(fp_tmq_list_new); return (*fp_tmq_list_new)(); } @@ -691,6 +696,7 @@ char **tmq_list_to_c_array(const tmq_list_t *tlist) { } tmq_t *tmq_consumer_new(tmq_conf_t *conf, char *errstr, int32_t errstrLen) { + taos_init(); CHECK_PTR(fp_tmq_consumer_new); return (*fp_tmq_consumer_new)(conf, errstr, errstrLen); } @@ -860,11 +866,13 @@ TSDB_SERVER_STATUS taos_check_server_status(const char *fqdn, int port, char *de } void taos_write_crashinfo(int signum, void *sigInfo, void *context) { + taos_init(); CHECK_VOID(fp_taos_write_crashinfo); (*fp_taos_write_crashinfo)(signum, sigInfo, context); } char *getBuildInfo() { + taos_init(); CHECK_PTR(fp_getBuildInfo); return (*fp_getBuildInfo)(); } diff --git a/tests/army/cmdline/taosCli.py b/tests/army/cmdline/taosCli.py index 2624248a28..4aee8f1219 100644 --- a/tests/army/cmdline/taosCli.py +++ b/tests/army/cmdline/taosCli.py @@ -263,7 +263,7 @@ class TDTestCase(TBase): ['-a "abc"', "[0x80000357]"], ] for arg in args: - rlist = self.taos("Z 0 " + arg[0]) + rlist = self.taos("-Z 0 " + arg[0]) if arg[1] != None: self.checkListString(rlist, arg[1]) @@ -340,9 +340,14 @@ class TDTestCase(TBase): self.checkExcept(taos + " -s 'show dnodes;' " + option) def checkModeVersion(self): + + # check default conn mode + #DEFAULT_CONN = "WebSocket" + DEFAULT_CONN = "Native" + # results results = [ - "WebSocket Client Version", + f"{DEFAULT_CONN} Client Version", "2022-10-01 00:01:39.000", "Query OK, 100 row(s) in set" ] @@ -351,8 +356,10 @@ class TDTestCase(TBase): cmd = f"-s 'select ts from test.d0'" rlist = self.taos(cmd, checkRun = True) self.checkManyString(rlist, results) + # websocket cmd = f"-Z 1 -s 'select ts from test.d0'" + results[0] = "WebSocket Client Version" rlist = self.taos(cmd, checkRun = True) self.checkManyString(rlist, results) diff --git a/tests/army/frame/caseBase.py b/tests/army/frame/caseBase.py index b8345c3257..7a73ce09d4 100644 --- a/tests/army/frame/caseBase.py +++ b/tests/army/frame/caseBase.py @@ -196,9 +196,9 @@ class TBase: tdSql.checkFirstValue(sql, expect) # order by desc limit 1 with last - sql = f"select first({col}) from {self.db}.{self.db}." + sql = f"select first({col}) from {self.db}.{self.stb}" expect = tdSql.getFirstValue(sql) - sql = f"select {col} from {self.db}.{self.db}. order by _c0 asc limit 1" + sql = f"select {col} from {self.db}.{self.stb} order by _c0 asc limit 1" tdSql.checkFirstValue(sql, expect) diff --git a/tests/army/output.txt b/tests/army/output.txt deleted file mode 100644 index 132781c0db..0000000000 --- a/tests/army/output.txt +++ /dev/null @@ -1,52 +0,0 @@ -[02/10 13:52:16.164959] SUCC: created database (test) -[02/10 13:52:16.182024] INFO: start creating 1000 table(s) with 8 thread(s) -[02/10 13:52:16.396337] SUCC: Spent 0.2140 seconds to create 1000 table(s) with 8 thread(s) speed: 4673 tables/s, already exist 0 table(s), actual 1000 table(s) pre created, 0 table(s) will be auto created -[02/10 13:53:05.155428] SUCC: thread[2] progressive mode, completed total inserted rows: 12500000, 339193.01 records/second -[02/10 13:53:05.160652] SUCC: thread[7] progressive mode, completed total inserted rows: 12500000, 341816.65 records/second -[02/10 13:53:05.207601] SUCC: thread[0] progressive mode, completed total inserted rows: 12500000, 340556.51 records/second -[02/10 13:53:05.215370] SUCC: thread[4] progressive mode, completed total inserted rows: 12500000, 338804.97 records/second -[02/10 13:53:05.224077] SUCC: thread[5] progressive mode, completed total inserted rows: 12500000, 338596.28 records/second -[02/10 13:53:05.249786] SUCC: thread[1] progressive mode, completed total inserted rows: 12500000, 339208.40 records/second -[02/10 13:53:05.256970] SUCC: thread[3] progressive mode, completed total inserted rows: 12500000, 339174.04 records/second -[02/10 13:53:05.274900] SUCC: thread[6] progressive mode, completed total inserted rows: 12500000, 339551.12 records/second -[02/10 13:53:05.275900] SUCC: Spent 48.867685 (real 36.806958) seconds to insert rows: 100000000 with 8 thread(s) into test 2046342.08 (real 2716877.61) records/second -[02/10 13:53:05.275909] SUCC: insert delay, min: 11.2580ms, avg: 29.4456ms, p90: 32.7750ms, p95: 34.1120ms, p99: 39.5900ms, max: 70.3780ms -[02/12 15:46:06.469780] SUCC: created database (test) -[02/12 15:46:06.499844] INFO: start creating 10000 table(s) with 8 thread(s) -[02/12 15:46:08.185009] SUCC: Spent 1.6860 seconds to create 10000 table(s) with 8 thread(s) speed: 5931 tables/s, already exist 0 table(s), actual 10000 table(s) pre created, 0 table(s) will be auto created -[02/12 15:46:57.356674] SUCC: thread[0] progressive mode, completed total inserted rows: 12500000, 339076.93 records/second -[02/12 15:46:57.434553] SUCC: thread[1] progressive mode, completed total inserted rows: 12500000, 338528.52 records/second -[02/12 15:46:57.452522] SUCC: thread[2] progressive mode, completed total inserted rows: 12500000, 339844.37 records/second -[02/12 15:46:57.452921] SUCC: thread[5] progressive mode, completed total inserted rows: 12500000, 339349.90 records/second -[02/12 15:46:57.463726] SUCC: thread[4] progressive mode, completed total inserted rows: 12500000, 339986.37 records/second -[02/12 15:46:57.466467] SUCC: thread[3] progressive mode, completed total inserted rows: 12500000, 339785.50 records/second -[02/12 15:46:57.499118] SUCC: thread[6] progressive mode, completed total inserted rows: 12500000, 339326.86 records/second -[02/12 15:46:57.501694] SUCC: thread[7] progressive mode, completed total inserted rows: 12500000, 338309.30 records/second -[02/12 15:46:57.502535] SUCC: Spent 49.309586 (real 36.843268) seconds to insert rows: 100000000 with 8 thread(s) into test 2028003.24 (real 2714200.05) records/second -[02/12 15:46:57.502546] SUCC: insert delay, min: 10.9580ms, avg: 29.4746ms, p90: 32.6960ms, p95: 33.8290ms, p99: 36.8390ms, max: 77.9940ms -[02/14 15:27:32.543409] SUCC: created database (test) -[02/14 15:27:32.568881] INFO: start creating 10000 table(s) with 8 thread(s) -[02/14 15:27:34.249759] SUCC: Spent 1.6810 seconds to create 10000 table(s) with 8 thread(s) speed: 5949 tables/s, already exist 0 table(s), actual 10000 table(s) pre created, 0 table(s) will be auto created -[02/14 15:28:26.165699] SUCC: thread[0] progressive mode, completed total inserted rows: 12500000, 321266.73 records/second -[02/14 15:28:26.281188] SUCC: thread[4] progressive mode, completed total inserted rows: 12500000, 319863.00 records/second -[02/14 15:28:26.326975] SUCC: thread[5] progressive mode, completed total inserted rows: 12500000, 321802.51 records/second -[02/14 15:28:26.328615] SUCC: thread[6] progressive mode, completed total inserted rows: 12500000, 321804.13 records/second -[02/14 15:28:26.379189] SUCC: thread[7] progressive mode, completed total inserted rows: 12500000, 320719.22 records/second -[02/14 15:28:26.400891] SUCC: thread[1] progressive mode, completed total inserted rows: 12500000, 321512.59 records/second -[02/14 15:28:26.470912] SUCC: thread[2] progressive mode, completed total inserted rows: 12500000, 319026.94 records/second -[02/14 15:28:26.565079] SUCC: thread[3] progressive mode, completed total inserted rows: 12500000, 317248.21 records/second -[02/14 15:28:26.566013] SUCC: Spent 52.307623 (real 39.013939) seconds to insert rows: 100000000 with 8 thread(s) into test 1911767.24 (real 2563186.45) records/second -[02/14 15:28:26.566024] SUCC: insert delay, min: 11.1290ms, avg: 31.2112ms, p90: 35.4900ms, p95: 37.0580ms, p99: 41.5180ms, max: 68.5900ms -[02/17 14:09:42.181835] SUCC: created database (test) -[02/17 14:09:42.210373] INFO: start creating 10000 table(s) with 8 thread(s) -[02/17 14:09:44.199467] SUCC: Spent 1.9890 seconds to create 10000 table(s) with 8 thread(s) speed: 5028 tables/s, already exist 0 table(s), actual 10000 table(s) pre created, 0 table(s) will be auto created -[02/17 14:10:32.845475] SUCC: thread[3] progressive mode, completed total inserted rows: 12500000, 338184.62 records/second -[02/17 14:10:32.872586] SUCC: thread[4] progressive mode, completed total inserted rows: 12500000, 338445.48 records/second -[02/17 14:10:32.873271] SUCC: thread[1] progressive mode, completed total inserted rows: 12500000, 339256.73 records/second -[02/17 14:10:32.938231] SUCC: thread[5] progressive mode, completed total inserted rows: 12500000, 338737.29 records/second -[02/17 14:10:32.947655] SUCC: thread[2] progressive mode, completed total inserted rows: 12500000, 338938.99 records/second -[02/17 14:10:32.952985] SUCC: thread[0] progressive mode, completed total inserted rows: 12500000, 338652.89 records/second -[02/17 14:10:32.962370] SUCC: thread[6] progressive mode, completed total inserted rows: 12500000, 338890.00 records/second -[02/17 14:10:32.998729] SUCC: thread[7] progressive mode, completed total inserted rows: 12500000, 339216.19 records/second -[02/17 14:10:32.999680] SUCC: Spent 48.790057 (real 36.896020) seconds to insert rows: 100000000 with 8 thread(s) into test 2049597.93 (real 2710319.43) records/second -[02/17 14:10:32.999696] SUCC: insert delay, min: 10.7720ms, avg: 29.5168ms, p90: 32.6910ms, p95: 33.8370ms, p99: 36.6750ms, max: 76.0590ms diff --git a/tests/army/test.py b/tests/army/test.py index a66743b40a..6ac0948b7b 100644 --- a/tests/army/test.py +++ b/tests/army/test.py @@ -37,9 +37,6 @@ import taos import taosrest import taosws -from taos.cinterface import * -taos.taos_options(6, "native") - def checkRunTimeError(): import win32gui timeCount = 0 @@ -261,9 +258,8 @@ if __name__ == "__main__": # # do exeCmd command # - taosAdapter = True # default is websocket , so must start taosAdapter if not execCmd == "": - if taosAdapter or restful or websocket: + if taosAdapter or taosAdapter or restful or websocket: tAdapter.init(deployPath) else: tdDnodes.init(deployPath) diff --git a/tests/army/tools/benchmark/basic/commandline-sml.py b/tests/army/tools/benchmark/basic/commandline-sml.py index 4533dedbbd..8032abdecd 100644 --- a/tests/army/tools/benchmark/basic/commandline-sml.py +++ b/tests/army/tools/benchmark/basic/commandline-sml.py @@ -68,14 +68,10 @@ class TDTestCase(TBase): tdSql.checkData(0, 0, 10*10000) # add normal table - cmd = "%s -N -I sml -t 2 -n 10000 -y" % binPath - tdLog.info("%s" % cmd) - os.system("%s" % cmd) - - tdSql.query("select count(*) from test.d0") - tdSql.checkData(0, 0, 1*10000) - tdSql.query("select count(*) from test.d1") - tdSql.checkData(0, 0, 1*10000) + cmd = "-N -I sml -t 2 -n 10000 -y" + rlist = self.benchmark(cmd, checkRun = False) + # expect failed + self.checkListString(rlist, "schemaless cannot work without stable") def stop(self): tdSql.close() diff --git a/tests/army/tools/benchmark/basic/connMode.py b/tests/army/tools/benchmark/basic/connMode.py index 0f3a99a386..8e85f6a995 100644 --- a/tests/army/tools/benchmark/basic/connMode.py +++ b/tests/army/tools/benchmark/basic/connMode.py @@ -68,12 +68,15 @@ class TDTestCase(TBase): os.environ['TDENGINE_CLOUD_DSN'] = "" def checkCommandLine(self): + # default CONN_MODE + DEFAULT_CONN_MODE = "Native" + # modes modes = ["", "-Z 1 -B 1", "-Z websocket", "-Z 0", "-Z native -B 2"] # result Rows = "insert rows: 9990" results1 = [ - ["Connect mode is : WebSocket", Rows], + [f"Connect mode is : {DEFAULT_CONN_MODE}", Rows], ["Connect mode is : WebSocket", Rows], ["Connect mode is : WebSocket", Rows], ["Connect mode is : Native", Rows], @@ -112,7 +115,7 @@ class TDTestCase(TBase): # ommand # self.benchmarkCmd("-h 127.0.0.1", 5, 100, 10, ["insert rows: 500"]) - self.benchmarkCmd("-h 127.0.0.1 -P 6041 -uroot -ptaosdata", 5, 100, 10, ["insert rows: 500"]) + self.benchmarkCmd("-h 127.0.0.1 -uroot -ptaosdata", 5, 100, 10, ["insert rows: 500"]) self.benchmarkCmd("-Z 0 -h 127.0.0.1 -P 6030 -uroot -ptaosdata", 5, 100, 10, ["insert rows: 500"]) # @@ -120,7 +123,7 @@ class TDTestCase(TBase): # # 6041 is default - options = "-h 127.0.0.1 -P 6041 -uroot -ptaosdata" + options = "-Z 1 -h 127.0.0.1 -P 6041 -uroot -ptaosdata" json = "tools/benchmark/basic/json/connModePriorityErrHost.json" self.insertBenchJson(json, options, True) diff --git a/tests/army/tools/benchmark/basic/websiteCase.py b/tests/army/tools/benchmark/basic/websiteCase.py index 67b5620931..55ee7dcb01 100644 --- a/tests/army/tools/benchmark/basic/websiteCase.py +++ b/tests/army/tools/benchmark/basic/websiteCase.py @@ -221,7 +221,7 @@ class TDTestCase(TBase): def checkTmqJson(self, benchmark, json): OK_RESULT = "Consumed total msgs: 30, total rows: 300000" cmd = benchmark + " -f " + json - output,error = frame.eos.run(cmd, 600) + output, error, code = frame.eos.run(cmd, 600) if output.find(OK_RESULT) != -1: tdLog.info(f"succ: {cmd} found '{OK_RESULT}'") else: diff --git a/tests/army/tools/benchmark/ws/websocket.py b/tests/army/tools/benchmark/ws/websocket.py index 1394e892ef..8242bf8716 100644 --- a/tests/army/tools/benchmark/ws/websocket.py +++ b/tests/army/tools/benchmark/ws/websocket.py @@ -29,7 +29,7 @@ class TDTestCase(TBase): def run(self): binPath = etool.benchMarkFile() - cmd = "%s -t 1 -n 1 -y -W http://localhost:6041 -D 30" % binPath + cmd = "%s -t 1 -n 1 -y -W http://localhost:6041 " % binPath tdLog.info("%s" % cmd) os.system("%s" % cmd) tdSql.execute("reset query cache") diff --git a/tests/army/tools/taosdump/native/taosdumpCommandline.py b/tests/army/tools/taosdump/native/taosdumpCommandline.py index c3b33ba45e..d00df415e2 100644 --- a/tests/army/tools/taosdump/native/taosdumpCommandline.py +++ b/tests/army/tools/taosdump/native/taosdumpCommandline.py @@ -158,7 +158,7 @@ class TDTestCase(TBase): def basicCommandLine(self, tmpdir): #command and check result checkItems = [ - [f"-h 127.0.0.1 -P 6041 -uroot -ptaosdata -A -N -o {tmpdir}", ["OK: Database test dumped"]], + [f"-Z 0 -h 127.0.0.1 -P 6030 -uroot -ptaosdata -A -N -o {tmpdir}", ["OK: Database test dumped"]], [f"-r result -a -e test d0 -o {tmpdir}", ["OK: table: d0 dumped", "OK: 100 row(s) dumped out!"]], [f"-n -D test -o {tmpdir}", ["OK: Database test dumped", "OK: 205 row(s) dumped out!"]], [f"-Z 0 -P 6030 -n -D test -o {tmpdir}", ["OK: Database test dumped", "OK: 205 row(s) dumped out!"]], @@ -348,19 +348,12 @@ class TDTestCase(TBase): self.exceptCommandLine(taosdump, db, stb, tmpdir) tdLog.info("4. except command line ................................. [Passed]") - json = "./tools/taosdump/native/json/insertOther.json" - # insert - db, stb, childCount, insertRows = self.insertData(json) - # dump in/out - self.dumpInOutMode("", db , json, tmpdir) - tdLog.info("5. native varbinary geometry ........................... [Passed]") - # # check connMode # self.checkConnMode(db, stb, childCount, insertRows, tmpdir) - tdLog.info("6. check conn mode ..................................... [Passed]") + tdLog.info("5. check conn mode ..................................... [Passed]") def stop(self): diff --git a/tests/develop-test/test.py b/tests/develop-test/test.py index b291e58e3d..3525fd6332 100644 --- a/tests/develop-test/test.py +++ b/tests/develop-test/test.py @@ -38,8 +38,6 @@ from util.taosadapter import * import taos import taosrest -from taos.cinterface import * -taos.taos_options(6, "native") def checkRunTimeError(): import win32gui diff --git a/tests/docs-examples-test/python.sh b/tests/docs-examples-test/python.sh index 8e43f26d5c..49e3875a6a 100644 --- a/tests/docs-examples-test/python.sh +++ b/tests/docs-examples-test/python.sh @@ -126,7 +126,7 @@ python3 mockdatasource.py python3 fast_write_example.py # 20 -pip3 install kafka-python +pip3 install kafka-python==2.1.2 python3 kafka_example_consumer.py # 21 @@ -196,4 +196,5 @@ check_transactions || exit 1 reset_cache || exit 1 python3 tmq_websocket_example.py -python3 stmt2_native.py \ No newline at end of file +python3 stmt2_native.py + diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 75c50ceb05..b5f41838df 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -108,7 +108,6 @@ ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/custom_col_tag.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/default_json.py -,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/default_tmq_json.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/demo.py ,,y,army,./pytest.sh python3 ./test.py -f tools/benchmark/basic/csv-export.py diff --git a/tests/script/test.sh b/tests/script/test.sh index 080b1c5d1c..81e7bc2f8a 100755 --- a/tests/script/test.sh +++ b/tests/script/test.sh @@ -9,6 +9,9 @@ set +e #set -x +export ASAN_OPTIONS=detect_odr_violation=0 +echo "forbid check ODR violation." + FILE_NAME= VALGRIND=0 TEST=0 diff --git a/tests/system-test/test.py b/tests/system-test/test.py index 1958e9976e..cd0e60160c 100644 --- a/tests/system-test/test.py +++ b/tests/system-test/test.py @@ -40,9 +40,6 @@ import taos import taosrest import taosws -from taos.cinterface import * -taos.taos_options(6, "native") - def checkRunTimeError(): import win32gui timeCount = 0 @@ -73,6 +70,7 @@ def get_local_classes_in_order(file_path): def dynamicLoadModule(fileName): moduleName = fileName.replace(".py", "").replace(os.sep, ".") return importlib.import_module(moduleName, package='..') + # # run case on previous cluster # @@ -254,9 +252,8 @@ if __name__ == "__main__": # # do exeCmd command # - taosAdapter = True # default is websocket , so must start taosAdapter if not execCmd == "": - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.init(deployPath) else: tdDnodes.init(deployPath) @@ -295,7 +292,7 @@ if __name__ == "__main__": if valgrind: time.sleep(2) - if taosAdapter or restful or websocket: + if restful or websocket: toBeKilled = "taosadapter" # killCmd = "ps -ef|grep -w %s| grep -v grep | awk '{print $2}' | xargs kill -TERM > /dev/null 2>&1" % toBeKilled @@ -391,7 +388,7 @@ if __name__ == "__main__": tdDnodes.deploy(1,updateCfgDict) tdDnodes.start(1) tdCases.logSql(logSql) - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -431,7 +428,7 @@ if __name__ == "__main__": tdDnodes.starttaosd(dnode.index) tdCases.logSql(logSql) - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -553,7 +550,7 @@ if __name__ == "__main__": except: pass - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.init(deployPath, masterIp) tAdapter.stop(force_kill=True) @@ -563,7 +560,7 @@ if __name__ == "__main__": tdDnodes.start(1) tdCases.logSql(logSql) - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() @@ -618,7 +615,7 @@ if __name__ == "__main__": tdDnodes.starttaosd(dnode.index) tdCases.logSql(logSql) - if taosAdapter or restful or websocket: + if restful or websocket: tAdapter.deploy(adapter_cfg_dict) tAdapter.start() diff --git a/tools/inc/pub.h b/tools/inc/pub.h index fd9fa9558f..d6114a55ee 100644 --- a/tools/inc/pub.h +++ b/tools/inc/pub.h @@ -17,6 +17,7 @@ #define PUB_H_ #include +#include #include #include #include @@ -72,10 +73,11 @@ int8_t getConnMode(char *arg); char* strToLowerCopy(const char *str); int32_t parseDsn(char* dsn, char **host, char **port, char **user, char **pwd, char* error); -int32_t setConnMode(int8_t connMode, char *dsn); +int32_t setConnMode(int8_t connMode, char *dsn, bool show); uint16_t defaultPort(int8_t connMode, char *dsn); -int8_t defaultMode(int8_t connMode, char *dsn); +// working connect mode +int8_t workingMode(int8_t connMode, char *dsn); #endif // PUB_H_ \ No newline at end of file diff --git a/tools/shell/src/shellArguments.c b/tools/shell/src/shellArguments.c index 209168149e..0b319ac8a1 100644 --- a/tools/shell/src/shellArguments.c +++ b/tools/shell/src/shellArguments.c @@ -219,9 +219,6 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { break; #if defined(LINUX) case 'o': - printf(" -o need todo optins.\n"); - // need todo pass tsLogOutput to engine - /* if (strlen(arg) >= PATH_MAX) { printf("failed to set log output since length overflow, max length is %d\r\n", PATH_MAX); return TSDB_CODE_INVALID_CFG; @@ -235,7 +232,6 @@ static int32_t shellParseSingleOpt(int32_t key, char *arg) { printf("failed to expand log output: '%s' since %s\r\n", arg, tstrerror(terrno)); return terrno; } - */ break; #endif case 'E': diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index 46d0c88b02..afcedeef08 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -1355,17 +1355,22 @@ TAOS* createConnect(SShellArgs *pArgs) { } // connect main + TAOS * taos = NULL; if (pArgs->auth) { - return taos_connect_auth(host, user, pArgs->auth, pArgs->database, port); + taos = taos_connect_auth(host, user, pArgs->auth, pArgs->database, port); } else { - return taos_connect(host, user, pwd, pArgs->database, port); + taos = taos_connect(host, user, pwd, pArgs->database, port); } + + // host user pointer in dsnc address + free(dsnc); + return taos; } int32_t shellExecute(int argc, char *argv[]) { int32_t code = 0; printf(shell.info.clientVersion, shell.info.cusName, - defaultMode(shell.args.connMode, shell.args.dsn) == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET, + workingMode(shell.args.connMode, shell.args.dsn) == CONN_MODE_NATIVE ? STR_NATIVE : STR_WEBSOCKET, taos_get_client_info(), shell.info.cusName); fflush(stdout); diff --git a/tools/shell/src/shellMain.c b/tools/shell/src/shellMain.c index 31fad97bd4..edf52da778 100644 --- a/tools/shell/src/shellMain.c +++ b/tools/shell/src/shellMain.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) { return -1; } - if (setConnMode(shell.args.connMode, shell.args.dsn)) { + if (setConnMode(shell.args.connMode, shell.args.dsn, false)) { return -1; } diff --git a/tools/src/pub.c b/tools/src/pub.c index 7e561b57d9..4b9389e455 100644 --- a/tools/src/pub.c +++ b/tools/src/pub.c @@ -91,7 +91,7 @@ } // set conn mode -int32_t setConnMode(int8_t connMode, char *dsn) { +int32_t setConnMode(int8_t connMode, char *dsn, bool show) { // check default if (connMode == CONN_MODE_INVALID) { if (dsn && dsn[0] != 0) { @@ -109,11 +109,16 @@ int32_t setConnMode(int8_t connMode, char *dsn) { fprintf(stderr, "failed to load driver. since %s [0x%08X]\r\n", taos_errstr(NULL), taos_errno(NULL)); return code; } + + if (show) { + fprintf(stdout, "\nConnect mode is : %s\n\n", strMode); + } + return 0; } // default mode -int8_t defaultMode(int8_t connMode, char *dsn) { +int8_t workingMode(int8_t connMode, char *dsn) { int8_t mode = connMode; if (connMode == CONN_MODE_INVALID) { // no input from command line or config @@ -129,10 +134,15 @@ int8_t defaultMode(int8_t connMode, char *dsn) { // get default port uint16_t defaultPort(int8_t connMode, char *dsn) { + // port 0 is default + return 0; + + /* // consistent with setConnMode - int8_t mode = defaultMode(connMode, dsn); + int8_t mode = workingMode(connMode, dsn); // default port return mode == CONN_MODE_NATIVE ? DEFAULT_PORT_NATIVE : DEFAULT_PORT_WS_LOCAL; + */ } \ No newline at end of file diff --git a/tools/taos-tools/src/benchData.c b/tools/taos-tools/src/benchData.c index 1a49c7f75c..917897e544 100644 --- a/tools/taos-tools/src/benchData.c +++ b/tools/taos-tools/src/benchData.c @@ -256,13 +256,13 @@ char* genPrepareSql(SSuperTable *stbInfo, char* tagData, uint64_t tableSeq, char "INSERT INTO ? USING `%s`.`%s` TAGS (%s) %s VALUES(?,%s)", db, stbInfo->stbName, tagQ, ttl, colQ); } else { - if (g_arguments->connMode == CONN_MODE_NATIVE) { + if (workingMode(g_arguments->connMode, g_arguments->dsn) == CONN_MODE_NATIVE) { // native n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, "INSERT INTO ? VALUES(?,%s)", colQ); } else { // websocket - bool ntb = stbInfo->tags == NULL || stbInfo->tags->size == 0; // nomral table + bool ntb = stbInfo->tags == NULL || stbInfo->tags->size == 0; // normal table colNames = genColNames(stbInfo->cols, !ntb); n = snprintf(prepare + len, TSDB_MAX_ALLOWED_SQL_LEN - len, "INSERT INTO `%s`.`%s`(%s) VALUES(%s,%s)", db, stbInfo->stbName, colNames, diff --git a/tools/taos-tools/src/benchMain.c b/tools/taos-tools/src/benchMain.c index fa47329b37..190defa5a7 100644 --- a/tools/taos-tools/src/benchMain.c +++ b/tools/taos-tools/src/benchMain.c @@ -168,7 +168,7 @@ int main(int argc, char* argv[]) { } // conn mode - if (setConnMode(g_arguments->connMode, g_arguments->dsn) != 0) { + if (setConnMode(g_arguments->connMode, g_arguments->dsn, true) != 0) { exitLog(); return -1; } diff --git a/tools/taos-tools/src/taosdump.c b/tools/taos-tools/src/taosdump.c index 6ef633fb9b..5d513a3ba6 100644 --- a/tools/taos-tools/src/taosdump.c +++ b/tools/taos-tools/src/taosdump.c @@ -150,6 +150,7 @@ static struct argp_option options[] = { {"inspect", 'I', 0, 0, "inspect avro file content and print on screen", 10}, {"no-escape", 'n', 0, 0, "No escape char '`'. Default is using it.", 10}, + {"restful", 'R', 0, 0, "Use RESTful interface to connect server", 11}, {"cloud", 'C', "CLOUD_DSN", 0, OLD_DSN_DESC, 11}, {"timeout", 't', "SECONDS", 0, "The timeout seconds for " "websocket to interact."}, @@ -691,7 +692,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { } g_args.thread_num = atoi((const char *)arg); break; - + case 'R': + warnPrint("%s\n", "'-R' is not supported, ignore this options."); + break; case 'C': case 'X': if (arg) { @@ -10910,7 +10913,7 @@ int main(int argc, char *argv[]) { } // conn mode - if (setConnMode(g_args.connMode, g_args.dsn) != 0) { + if (setConnMode(g_args.connMode, g_args.dsn, true) != 0) { return -1; } From d00f5e332d5e10c052dc29617e4093ff32861769 Mon Sep 17 00:00:00 2001 From: Jing Sima Date: Sat, 22 Mar 2025 21:12:25 +0800 Subject: [PATCH 20/28] docs: [TS-4897] Add docs for virtual table. (#30325) * docs: [TS-4897] Add docs for virtual table. * Update 01-model.md * Update 01-model.md * docs: [TS-4897] Modify docs of virtual table. --------- Co-authored-by: Pan Wei <72057773+dapan1121@users.noreply.github.com> --- docs/zh/05-basic/01-model.md | 191 +++++++++++ .../zh/05-basic/data-model-origin-table-2.png | Bin 0 -> 56202 bytes docs/zh/05-basic/data-model-origin-table.png | Bin 0 -> 54631 bytes docs/zh/14-reference/03-taos-sql/04-stable.md | 2 + docs/zh/14-reference/03-taos-sql/22-meta.md | 48 +-- .../03-taos-sql/34-virtualtable.md | 311 ++++++++++++++++++ .../pic/virtual-table-origin-table.png | Bin 0 -> 7998 bytes .../pic/virtual-table-query-res-part.png | Bin 0 -> 3194 bytes .../pic/virtual-table-query-res.png | Bin 0 -> 5027 bytes 9 files changed, 529 insertions(+), 23 deletions(-) create mode 100644 docs/zh/05-basic/data-model-origin-table-2.png create mode 100644 docs/zh/05-basic/data-model-origin-table.png create mode 100644 docs/zh/14-reference/03-taos-sql/34-virtualtable.md create mode 100644 docs/zh/14-reference/03-taos-sql/pic/virtual-table-origin-table.png create mode 100644 docs/zh/14-reference/03-taos-sql/pic/virtual-table-query-res-part.png create mode 100644 docs/zh/14-reference/03-taos-sql/pic/virtual-table-query-res.png diff --git a/docs/zh/05-basic/01-model.md b/docs/zh/05-basic/01-model.md index fc5c3a0a2e..0f01fbf562 100644 --- a/docs/zh/05-basic/01-model.md +++ b/docs/zh/05-basic/01-model.md @@ -77,6 +77,22 @@ toc_max_heading_level: 4 ![数据模型示意图](./data-model.png) +### 虚拟表 + +“一个设备一张表”的设计解决了工业和物联网等场景下的大多数时序数据管理和分析难题,但是在遇到更复杂的场景时,这种设计受到了设备复杂性的挑战。这种复杂性的根源在于一个设备无法简单的用一个或一组数据采集点来描述或管理,而业务分析往往需要综合多个或多组采集点的数据才能完成。以汽车或发电风机为例,整个设备(汽车或风机)中含有非常大量的传感器(数据采集点),这些传感器的输出和采集频率千差万别。一个超级表只能描述其中一种传感器,当需要综合多个传感器的数据进行分析计算时,只能通过多级关联查询的方式来进行,而这往往会导致易用性和性能方面的问题。 + +为了解决这个问题,TDengine 引入虚拟表(Virtual Table,简称为 VTable)的概念。虚拟表是一种不存储实际数据而可以用于分析计算的表,它的数据来源为其它真实存储数据的子表、普通表,通过将不同列数据按照时间戳排序、对齐、合并的方式来生成虚拟表。同真实表类似,虚拟表也可以分为虚拟超级表、虚拟子表、虚拟普通表。虚拟超级表可以是一个设备或一组分析计算所需数据的完整集合,每个虚拟子表可以根据需要引用相同或不同的列,因此可以灵活地根据业务需要进行定义,最终可以达到千表千面的效果。虚拟表不能写入、删除数据,在查询使用上同真实表基本相同,支持虚拟超级表、虚拟子表、虚拟普通表上的任何查询。唯一的区别在于虚拟表的数据是每次查询计算时动态生成的,只有一个查询中引用的列才会被合并进虚拟表中,因此同一个虚拟表在不同的查询中所呈现的数据可能是不同的。 + +虚拟超级表的主要功能特点包括: +1. 列选择与拼接
+ 用户可以从多个原始表中选择指定的列,按需组合到一张虚拟表中,形成统一的数据视图。 +2. 基于时间戳对齐
+ 以时间戳为依据对数据进行对齐,如果多个表在相同时间戳下存在数据,则对应列的值组合成同一行;若部分表在该时间戳下无数据,则对应列填充为 NULL。 +3. 动态更新
+ 虚拟表根据原始表的数据变化自动更新,确保数据的实时性。虚拟表不需实际存储,计算在生成时动态完成。 + +通过引入虚拟表的概念,现在 TDengine 可以非常方便的管理更大更复杂的设备数据。无论每个采集点如何建模(单列 or 多列),无论这些采集点的数据是分布在一个或多个库中,我们现在都可以通过定义虚拟子表的方式跨库跨表任意指定数据源,通过虚拟超级表的方式进行跨设备、跨分析的聚合运算,从此“一个设备一张表”彻底成为现实。 + ### 库 库是 TDengine 中用于管理一组表的集合。TDengine 允许一个运行实例包含多个库,并且每个库都可以配置不同的存储策略。由于不同类型的数据采集点通常具有不同的数据特征,如数据采集频率、数据保留期限、副本数量、数据块大小等。为了在各种场景下确保 TDengine 能够发挥最大效率,建议将具有不同数据特征的超级表创建在不同的库中。 @@ -93,6 +109,7 @@ toc_max_heading_level: 4 在查询数据时,TDengine 客户端会根据应用程序当前的时区设置,自动将保存的 UTC 时间戳转换成本地时间进行显示,确保用户在不同时区下都能看到正确的时间信息。 + ## 数据建模 本节用智能电表做例子,简要的介绍如何在 TDengine 里使用 SQL 创建数据库、超级表、表的基本操作。 @@ -215,3 +232,177 @@ TDengine 支持灵活的数据模型设计,包括多列模型和单列模型 尽管 TDengine 推荐使用多列模型,因为这种模型在写入效率和存储效率方面通常更优,但在某些特定场景下,单列模型可能更为适用。例如,当一个数据采集点的采集量种类经常发生变化时,如果采用多列模型,就需要频繁修改超级表的结构定义,这会增加应用程序的复杂性。在这种情况下,采用单列模型可以简化应用程序的设计和管理,因为它允许独立地管理和扩展每个物理量的超级表。 总之,TDengine 提供了灵活的数据模型选项,用户可以根据实际需求和场景选择最适合的模型,以优化性能和管理复杂性。 + +### 创建虚拟表 + +无论是选择单列模型还是多列模型,TDengine 都可以通过使用虚拟表进行跨表的运算。为智能电表为例,这里介绍虚拟表的两种使用场景: + +1. 单源多维度时序聚合 +2. 跨源采集量对比分析 + +#### 单源多维度时序聚合 +在单源多维度时序聚合场景中,“单源”并非指单一物理表,而是指来自**同一数据采集点**下的多个单列时序数据表。这些数据因业务需求或其他限制被拆分为多个单列存储的表,但通过设备标签和时间基准保持逻辑一致性。虚拟表在此场景中的作用是将一个采集点中“纵向“拆分的数据,还原为完整的“横向”状态。 +例如,在建模时采用了单列模型,对于电流、电压和相位这 3 种物理量,分别建立 3 张超级表。在这种场景下,用户可以通过虚拟表将这 3 种不同的采集量聚合到一张表中,以便进行统一的查询和分析。 + +创建单列模型的超级表的 SQL 如下: + +```sql + +CREATE STABLE current_stb ( + ts timestamp, + current float +) TAGS ( + device_id varchar(64), + location varchar(64), + group_id int +); + +CREATE STABLE voltage_stb ( + ts timestamp, + voltage int +) TAGS ( + device_id varchar(64), + location varchar(64), + group_id int +); + +CREATE STABLE phase_stb ( + ts timestamp, + phase float +) TAGS ( + device_id varchar(64), + location varchar(64), + group_id int +); +``` + +假设分别有 d1001,d1002,d1003,d1004 四个设备,分别对四个设备的电流、电压、相位采集量创建子表,SQL 如下: + +```sql +create table current_d1001 using current_stb(deviceid, location, group_id) tags("d1001", "California.SanFrancisco", 2); +create table current_d1002 using current_stb(deviceid, location, group_id) tags("d1002", "California.SanFrancisco", 3); +create table current_d1003 using current_stb(deviceid, location, group_id) tags("d1003", "California.LosAngeles", 3); +create table current_d1004 using current_stb(deviceid, location, group_id) tags("d1004", "California.LosAngeles", 2); + +create table voltage_d1001 using voltage_stb(deviceid, location, group_id) tags("d1001", "California.SanFrancisco", 2); +create table voltage_d1002 using voltage_stb(deviceid, location, group_id) tags("d1002", "California.SanFrancisco", 3); +create table voltage_d1003 using voltage_stb(deviceid, location, group_id) tags("d1003", "California.LosAngeles", 3); +create table voltage_d1004 using voltage_stb(deviceid, location, group_id) tags("d1004", "California.LosAngeles", 2); + +create table phase_d1001 using phase_stb(deviceid, location, group_id) tags("d1001", "California.SanFrancisco", 2); +create table phase_d1002 using phase_stb(deviceid, location, group_id) tags("d1002", "California.SanFrancisco", 3); +create table phase_d1003 using phase_stb(deviceid, location, group_id) tags("d1003", "California.LosAngeles", 3); +create table phase_d1004 using phase_stb(deviceid, location, group_id) tags("d1004", "California.LosAngeles", 2); +``` + +此时想要通过一张虚拟超级表来讲这三种采集量聚合到一张表中,创建虚拟超级表 SQL 如下: + +```sql +CREATE STABLE meters_v ( + ts timestamp, + current float, + voltage int, + phase float +) TAGS ( + location varchar(64), + group_id int +) VIRTUAL 1; +``` + +并且对四个设备 d1001,d1002,d1003,d1004 分别创建虚拟子表,SQL 如下: + +```sql +CREATE VTABLE d1001_v ( + current from current_d1001.current, + voltage from voltage_d1001.voltage, + phase from phase_d1001.phase +) +USING meters_v +TAGS ( + "California.SanFrancisco", + 2 +); + +CREATE VTABLE d1002_v ( + current from current_d1002.current, + voltage from voltage_d1002.voltage, + phase from phase_d1002.phase +) +USING meters_v +TAGS ( + "California.SanFrancisco", + 3 +); + +CREATE VTABLE d1003_v ( + current from current_d1003.current, + voltage from voltage_d1003.voltage, + phase from phase_d1003.phase +) +USING meters_v +TAGS ( + "California.LosAngeles", + 3 +); + +CREATE VTABLE d1004_v ( + current from current_d1004.current, + voltage from voltage_d1004.voltage, + phase from phase_d1004.phase +) +USING meters_v +TAGS ( + "California.LosAngeles", + 2 +); +``` + +以设备 d1001 为例,假设 d1001 设备的电流、电压、相位数据如下: + +![data-model-origin-table.png](data-model-origin-table.png) + +虚拟表 d1001_v 中的数据如下 : + +| Timestamp | Current | Voltage | Phase | +|:--------------:|:-------:|:---------:|:-------:| +| 1538548685000 | 10.3 | 219 | 0.31 | +| 1538548695000 | 12.6 | 218 | 0.33 | +| 1538548696800 | 12.3 | 221 | 0.31 | +| 1538548697100 | 12.1 | 220 | NULL | +| 1538548697200 | NULL | NULL | 0.32 | +| 1538548697700 | 11.8 | NULL | NULL | +| 1538548697800 | NULL | 222 | 0.33 | + +#### 跨源采集量对比分析 + +在跨源采集量对比分析中,“跨源”指数据来自**不同数据采集点**。在不同数据采集点中提取具有可比语义的采集量,通过虚拟表将这些采集量按照时间戳进行对齐和合并,并进行对比分析。 +例如,用户可以将来自不同设备的电流数据聚合到一张虚拟表中,以便进行电流数据的对比分析。 + +以分析 d1001, d1002, d1003, d1004 四个设备的电流数据为例,创建虚拟表的 SQL 如下: + +```sql +CREATE VTABLE current_v ( + ts timestamp, + d1001_current float from current_d1001.current, + d1002_current float from current_d1002.current, + d1003_current float from current_d1003.current, + d1004_current float from current_d1004.current +); +``` + +假设 d1001, d1002, d1003, d1004 四个设备的电流数据如下: + +![data-model-origin-table-2.png](data-model-origin-table-2.png) + +虚拟表 current_v 中的数据如下: + +| Timestamp | d1001_current | d1002_current | d1003_current | d1004_current | +|:--------------:|:-------------:|:-------------:|:-------------:|:-------------:| +| 1538548685000 | 10.3 | 11.7 | 11.2 | 12.4 | +| 1538548695000 | 12.6 | 11.9 | 10.8 | 11.3 | +| 1538548696800 | 12.3 | 12.4 | 12.3 | 10.1 | +| 1538548697100 | 12.1 | NULL | 11.1 | NULL | +| 1538548697200 | NULL | 12.2 | NULL | 11.7 | +| 1538548697700 | 11.8 | 11.4 | NULL | NULL | +| 1538548697800 | NULL | NULL | 12.1 | 12.6 | + diff --git a/docs/zh/05-basic/data-model-origin-table-2.png b/docs/zh/05-basic/data-model-origin-table-2.png new file mode 100644 index 0000000000000000000000000000000000000000..8d0e203b4e11f02bf24512e8cfc336021b285b31 GIT binary patch literal 56202 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 literal 0 HcmV?d00001 diff --git a/docs/zh/05-basic/data-model-origin-table.png b/docs/zh/05-basic/data-model-origin-table.png new file mode 100644 index 0000000000000000000000000000000000000000..4e128e26b0bcf54db821f425348193368a8f8787 GIT binary patch literal 54631 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 literal 0 HcmV?d00001 diff --git a/docs/zh/14-reference/03-taos-sql/04-stable.md b/docs/zh/14-reference/03-taos-sql/04-stable.md index 98dad1a2e4..5412e6d129 100644 --- a/docs/zh/14-reference/03-taos-sql/04-stable.md +++ b/docs/zh/14-reference/03-taos-sql/04-stable.md @@ -22,6 +22,7 @@ table_option: { COMMENT 'string_value' | SMA(col_name [, col_name] ...) | KEEP value + | VIRTUAL {0 | 1} } ``` @@ -36,6 +37,7 @@ table_option: { 4. 关于 `ENCODE` 和 `COMPRESS` 的使用,请参考 [按列压缩](../compress) 5. 关于 table_option 中的参数说明,请参考 [建表 SQL 说明](../table) 6. 关于 table_option 中的 keep 参数,仅对超级表生效,keep 参数的详细说明可以参考 [数据库说明](02-database.md),唯一不同的是超级表 keep 不会立即影响查询结果,仅在 compact 后生效。 +7. 关于 table_option 中的 virtual 参数,仅对超级表生效,指定为 1 表示创建虚拟超级表,为 0 表示创建超级表,默认为 0。创建虚拟超级表时,column_definition 中只支持 type_name 选项,不支持定义额外主键列以及压缩选项。 ## 查看超级表 diff --git a/docs/zh/14-reference/03-taos-sql/22-meta.md b/docs/zh/14-reference/03-taos-sql/22-meta.md index 2e583a36b2..e947c06bac 100644 --- a/docs/zh/14-reference/03-taos-sql/22-meta.md +++ b/docs/zh/14-reference/03-taos-sql/22-meta.md @@ -151,18 +151,19 @@ TDengine 内置了一个名为 `INFORMATION_SCHEMA` 的数据库,提供对数 提供用户创建的超级表的相关信息。 -| # | **列名** | **数据类型** | **说明** | -| --- | :-----------: | ------------ | ----------------------------------------------------------------------------------------------------- | -| 1 | stable_name | VARCHAR(192) | 超级表表名 | -| 2 | db_name | VARCHAR(64) | 超级表所在的数据库的名称 | -| 3 | create_time | TIMESTAMP | 创建时间 | -| 4 | columns | INT | 列数目 | -| 5 | tags | INT | 标签数目。需要注意,`tags` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | -| 6 | last_update | TIMESTAMP | 最后更新时间 | -| 7 | table_comment | VARCHAR(1024) | 表注释 | -| 8 | watermark | VARCHAR(64) | 窗口的关闭时间。需要注意,`watermark` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | -| 9 | max_delay | VARCHAR(64) | 推送计算结果的最大延迟。需要注意,`max_delay` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。| -| 10 | rollup | VARCHAR(128) | rollup 聚合函数。需要注意,`rollup` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | +| # | **列名** | **数据类型** | **说明** | +|----|:-------------:|---------------|-----------------------------------------------------------------| +| 1 | stable_name | VARCHAR(192) | 超级表表名 | +| 2 | db_name | VARCHAR(64) | 超级表所在的数据库的名称 | +| 3 | create_time | TIMESTAMP | 创建时间 | +| 4 | columns | INT | 列数目 | +| 5 | tags | INT | 标签数目。需要注意,`tags` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | +| 6 | last_update | TIMESTAMP | 最后更新时间 | +| 7 | table_comment | VARCHAR(1024) | 表注释 | +| 8 | watermark | VARCHAR(64) | 窗口的关闭时间。需要注意,`watermark` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | +| 9 | max_delay | VARCHAR(64) | 推送计算结果的最大延迟。需要注意,`max_delay` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | +| 10 | rollup | VARCHAR(128) | rollup 聚合函数。需要注意,`rollup` 为 TDengine 关键字,作为列名使用时需要使用 ` 进行转义。 | +| 11 | virtual | BOOL | 超级表是否是虚拟超级表。 | ## INS_TABLES @@ -194,17 +195,18 @@ TDengine 内置了一个名为 `INFORMATION_SCHEMA` 的数据库,提供对数 ## INS_COLUMNS -| # | **列名** | **数据类型** | **说明** | -| --- | :-----------: | ------------ | ---------------------- | -| 1 | table_name | VARCHAR(192) | 表名 | -| 2 | db_name | VARCHAR(64) | 该表所在的数据库的名称 | -| 3 | table_type | VARCHAR(21) | 表类型 | -| 4 | col_name | VARCHAR(64) | 列 的名称 | -| 5 | col_type | VARCHAR(32) | 列 的类型 | -| 6 | col_length | INT | 列 的长度 | -| 7 | col_precision | INT | 列 的精度 | -| 8 | col_scale | INT | 列 的比例 | -| 9 | col_nullable | INT | 列 是否可以为空 | +| # | **列名** | **数据类型** | **说明** | +|----|:-------------:|--------------|---------------------------------------------------------------| +| 1 | table_name | VARCHAR(192) | 表名 | +| 2 | db_name | VARCHAR(64) | 该表所在的数据库的名称 | +| 3 | table_type | VARCHAR(21) | 表类型 | +| 4 | col_name | VARCHAR(64) | 列 的名称 | +| 5 | col_type | VARCHAR(32) | 列 的类型 | +| 6 | col_length | INT | 列 的长度 | +| 7 | col_precision | INT | 列 的精度 | +| 8 | col_scale | INT | 列 的比例 | +| 9 | col_nullable | INT | 列 是否可以为空 | +| 10 | col_source | VARCHAR(322) | 列 的数据来源。只有虚拟表的列才会有该值,表示虚拟表的数据来源,为 db_name.table_name.col_name | ## INS_USERS diff --git a/docs/zh/14-reference/03-taos-sql/34-virtualtable.md b/docs/zh/14-reference/03-taos-sql/34-virtualtable.md new file mode 100644 index 0000000000..a243169a0a --- /dev/null +++ b/docs/zh/14-reference/03-taos-sql/34-virtualtable.md @@ -0,0 +1,311 @@ +--- +sidebar_label: 虚拟表 +title: 虚拟表 +description: 对虚拟表的各种管理操作 +--- +## 创建虚拟表 + +`CREATE VTABLE` 语句用于创建普通虚拟表和以虚拟超级表为模板创建虚拟子表。 + +### 创建虚拟超级表 + +见 [创建超级表](./04-stable.md#创建超级表) 中的 `VIRTUAL` 参数。 + +### 创建虚拟普通表 +```sql +CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name + ts_col_name timestamp, + (create_defination[ ,create_defination] ...) + + create_definition: + vtb_col_name column_definition + +column_definition: + type_name [FROM [db_name.]table_name.col_name] + +``` + +### 创建虚拟子表 +```sql +CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name + (create_defination[ ,create_defination] ...) + USING [db_name.]stb_name + [(tag_name [, tag_name] ...)] + TAGS (tag_value [, tag_value] ...) + + create_definition: + [stb_col_name FROM] [db_name.]table_name.col_name + tag_value: + const_value +``` + +**使用说明** + +1. 虚拟表(列)名命名规则参见 [名称命名规则](./19-limit.md#名称命名规则)。 +2. 表名最大长度为 192。 +3. 表的第一个字段必须是 TIMESTAMP,并且系统自动将其设为主键。 +4. 表的每行长度不能超过 64KB(注意:每个 VARCHAR/NCHAR/GEOMETRY 类型的列还会额外占用 2 个字节的存储位置)。 +5. 使用数据类型 VARCHAR/NCHAR/GEOMETRY,需指定其最长的字节数,如 VARCHAR(20),表示 20 字节。 +6. 创建虚拟表时使用 FROM 来指定列的数据源,支持使用 db_name 跨库指定数据源,不指定 db_name 时默认使用当前 use 的数据库,若不指定 db_name 且未 use 数据库,则会报错。 +7. 创建虚拟表时不显式的指定 ts 列的数据源,ts 列的取值是查询虚拟表时查询语句中包含的所有列对应的原始表的主键时间戳合并的结果。 +8. 虚拟超级表下只支持创建虚拟子表,虚拟子表也只能以虚拟超级表为模版来创建。 +9. 创建虚拟表时需要保证虚拟表中的列、标签和指定的数据来源列、标签的数据类型相同,否则会报错。 +10. 在同一个数据库内,虚拟表名称不允许重名,虚拟表名和表名也不允许重名。虚拟表名和视图名允许重名(不推荐)当出现视图与虚拟表名重名时,写入、查询、授权、回收权限等操作优先使用同名表。 +11. 创建虚拟子表和虚拟普通表时,使用 FROM 指定某一列的数据来源时,该列只能来源于普通子表或普通表,不支持来源于超级表、视图或其他虚拟表。也不支持来源于有复合主键的表。 + +## 查询虚拟表 + +虚拟表与正常表无论是查询语法还是范围都没有区别,不同之处在于虚拟表所呈现的数据集在不同的查询中可能是不相同的,具体可以参考虚拟表数据生成规则。 + +### 虚拟表数据生成规则 + +1. 虚拟表以时间戳为基准,对多个原始表的数据进行对齐。 +2. 如果多个原始表在相同时间戳下有数据,则这些列的值组合成同一行;否则,对于缺失的列,填充 NULL。 +3. 虚拟表的时间戳的值是查询中包含的所有列所在的原始表的时间戳的并集,因此当不同查询选择列不同时可能出现结果集行数不一样的情况。 +4. 用户可以从多个表中选择任意列进行组合,未选择的列不会出现在虚拟表中。 + +**示例** + +假设有表 t1, t2, t3 结构和数据如下: + +![virtual-table-origin-table.png](pic/virtual-table-origin-table.png) + +并且有虚拟普通表 v1 ,创建方式如下: + +```sql +create vtable v1 ( + ts timestamp, + c1 int from t1.value, + c2 int from t2.value, + c3 int from t3.value1, + c4 int from t3.value2); +``` + +那么根据虚拟表对于多表数据的整合规则,执行如下查询时: + +```sql +select * from v1; +``` + +结果如下: + +![virtual-table-query-res.png](pic/virtual-table-query-res.png) + +如果没有选择全部列,只是选择了部分列,查询的结果只会包含选择的列的原始表的时间戳,例如执行如下查询: + +```sql +select c1, c2 from v1; +``` + +得到的结果如下图所示: + +![virtual-table-query-res-part.png](pic/virtual-table-query-res-part.png) + +因为 c1, c2 列对应的原始表 t1, t2 中没有 0:00:03 这个时间戳,所以最后的结果也不会包含这个时间戳。 + +**使用限制** + +1. 查询虚拟超级表时,暂不支持虚拟子表的数据源来自不同的数据库。 + +## 修改虚拟普通表 + +```sql +ALTER VTABLE [db_name.]vtb_name alter_table_clause + +alter_table_clause: { + ADD COLUMN vtb_col_name vtb_column_type [FROM table_name.col_name] + | DROP COLUMN vtb_col_name + | ALTER COLUMN vtb_col_name SET {table_name.col_name | NULL } + | MODIFY COLUMN col_name column_type + | RENAME COLUMN old_col_name new_col_name +} +``` + +**使用说明** +对虚拟普通表可以进行如下修改操作 + +1. ADD COLUMN:添加列。 +2. DROP COLUMN:删除列。 +3. MODIFY COLUMN:修改列定义,如果数据列的类型是可变长类型,那么可以使用此指令修改其宽度,只能改大,不能改小。如果虚拟表该列已指定数据源,那么修改列宽会因为修改后的列宽和数据源的列宽不匹配而报错,可以先将数据源置为空后再修改列宽。 +4. RENAME COLUMN:修改列名称。 +5. ALTER COLUMN .. SET:修改列的数据源。 SET NULL 表示将虚拟表某列的数据源置为空。 + +### 增加列 + +```sql +ALTER VTABLE vtb_name ADD COLUMN vtb_col_name vtb_col_type [FROM [db_name].table_name.col_name] +``` + +### 删除列 + +```sql +ALTER VTABLE vtb_name DROP COLUMN vtb_col_name +``` + +### 修改列宽 + +```sql +ALTER VTABLE vtb_name MODIFY COLUMN vtb_col_name data_type(length); +``` + +### 修改列名 + +```sql +ALTER VTABLE vtb_name RENAME COLUMN old_col_name new_col_name +``` + +### 修改列的数据源 + +```sql +ALTER VTABLE vtb_name ALTER COLUMN vtb_col_name SET {[db_name.]table_name.col_name | NULL} +``` + +## 修改虚拟子表 + +```sql +ALTER VTABLE [db_name.]vtb_name alter_table_clause + +alter_table_clause: { + ALTER COLUMN vtb_col_name SET table_name.col_name + | SET TAG tag_name = new_tag_value +} +``` + +**使用说明** + +1. 对虚拟子表的列和标签的修改,除了更改标签值以外,都要通过虚拟超级表才能进行。 + +### 修改虚拟子表标签值 + +```sql +ALTER VTABLE tb_name SET TAG tag_name1=new_tag_value1, tag_name2=new_tag_value2 ...; +``` + +### 修改列的数据源 + +```sql +ALTER VTABLE vtb_name ALTER COLUMN vtb_col_name SET {[db_name.]table_name.col_name | NULL} +``` + +## 删除虚拟表 + +```sql +DROP VTABLE [IF EXISTS] [dbname].vtb_name; +``` + +## 查看虚拟表的信息 + +### 显示某个数据库下所有虚拟表 + +如下 SQL 语句可以列出当前数据库中的所有虚拟表名。 + +```sql +SHOW [NORMAL | CHILD] [db_name.]VTABLES [LIKE 'pattern']; +``` + +**使用说明** + +1. 如果没有指定 db_name, 显示当前数据库下的所有虚拟普通表和虚拟子表的信息。若没有使用数据库并且没有指定 db_name, 则会报错 database not specified。可以使用 LIKE 对表名进行模糊匹配。NORMAL 指定只显示虚拟普通表信息, CHILD 指定只显示虚拟子表信息。 + +### 显示虚拟表创建语句 + +```sql +SHOW CREATE VTABLE [db_name.]vtable_name; +``` + +显示 vtable_name 指定的虚拟表的创建语句。支持虚拟普通表和虚拟子表。常用于数据库迁移。对一个已经存在的虚拟表,返回其创建语句;在另一个集群中执行该语句,就能得到一个结构完全相同的虚拟表。 + +### 获取虚拟表结构信息 + +```sql +DESCRIBE [db_name.]vtb_name; +``` + +### 查看所有虚拟表信息 + +```sql +SELECT ... FROM information_schema.ins_tables where type = 'VIRTUAL_NORMAL_TABLE' or type = 'VIRTUAL_CHILD_TABLE'; +``` + +## 写入虚拟表 + +不支持向虚拟表中写入数据,以及不支持删除虚拟表中的数据。虚拟表只是对原始表进行运算后的计算结果,是一张逻辑表,因此只能对其进行查询,不可以写入或删除数据。 + + +## 虚拟表与视图 + +虚拟表与视图看起来相似,但是有很多不同点: + +| 属性 |虚拟表 (Virtual Table) |视图 (View)| +|----------------|------------------------|-----------| +| 定义 |虚拟表是一种动态数据结构,根据多表的列和时间戳组合规则生成逻辑表。 |视图是一种基于 SQL 查询的虚拟化表结构,用于保存查询逻辑的定义。| +| 数据来源 |来自多个原始表,可以动态选择列,并通过时间戳对齐数据。 |来自单个或多个表的查询结果,通常是一个复杂的 SQL 查询。| +| 数据存储 |不实际存储数据,所有数据在查询时动态生成。 |不实际存储数据,仅保存 SQL 查询逻辑。| +| 时间戳处理 |通过时间戳对齐将不同表的列整合到统一的时间轴上。| 不支持时间戳对齐,数据由查询逻辑直接决定。| +| 更新机制 |动态更新,原始表数据变更时,虚拟表数据实时反映变化。| 动态更新,但依赖于视图定义的查询逻辑,不涉及对齐或数据整合。| +| 功能特性 |支持空值填充和插值(如 prev、next、linear)。 |不支持内置填充和插值功能,需通过查询逻辑自行实现。| +| 应用场景 |时间序列对齐、跨表数据整合、多源数据对比分析等场景。| 简化复杂查询逻辑、限制用户访问、封装业务逻辑等场景。| +| 性能 |由于多表对齐和空值处理,查询复杂度可能较高,尤其在数据量大时。| 性能通常取决于视图的查询语句复杂度,与单表查询性能相似。| + +不支持虚拟表和视图之间的相互转化,如根据虚拟表建立视图或者根据视图建立虚拟表。 + +## 虚拟表的权限 + +### 权限说明 + +虚拟表的权限分为 READ、WRITE 两种,查询操作需要具备 READ 权限,对虚拟表本身的删除和修改操作需要具备 WRITE 权限。 + +### 语法 + +#### 授权 + +```sql +GRANT privileges ON [db_name.]vtable_name TO user_name +privileges: { + ALL, + | priv_type [, priv_type] ... +} +priv_type: { + READ + | WRITE +} +``` + +#### 回收权限 + +```sql +REVOKE privileges ON [db_name.]vtable_name FROM user_name +privileges: { + ALL, + | priv_type [, priv_type] ... +} +priv_type: { + READ + | WRITE +} +``` + +### 权限规则 + +1. 虚拟表的创建者和 root 用户默认具备所有权限。 +2. 用户可以通过 dbname.vtbname 来为指定的虚拟表表(包括虚拟超级表和虚拟普通表)授予或回收其读写权限,不支持直接对虚拟子表授予或回收权限。 +3. 虚拟子表和虚拟超级表不支持基于标签的授权(表级授权),虚拟子表继承虚拟超级表的权限。 +4. 对其他用户进行授权与回收权限可以通过 GRANT 和 REVOKE 语句进行,该操作只能由 root 用户进行。 +5. 具体相关权限控制细则总结如下: + +| 序号 | 操作 | 权限要求 | +|------|------|----------------------------------------------------------| +| 1 | CREATE VTABLE | 用户对虚拟表所属数据库有 WRITE 权限 且
用户对虚拟表的数据源对应的原始表有 READ 权限。 | +| 2 | DROP/ALTER VTABLE | 用户对虚拟表有 WRITE 权限,若要指定某一列的数据源,需要同时对数据源对应的原始表有 READ 权限。 | +| 3 |SHOW VTABLES | 无 | +| 4 | SHOW CREATE VTABLE | 无 | +| 5 | DESCRIBE VTABLE | 无 | +| 6 | 系统表查询 | 无 | +| 7 | SELECT FROM VTABLE | 操作用户对虚拟表有 READ 权限 | +| 8 | GRANT/REVOKE | 只有 root 用户有权限 | + +## 使用场景 + +| SQL 查询 | SQL 写入 | STMT 查询 | STMT 写入 | 订阅 | 流计算 | +|---------|--------|---------|------|--------|---| +| 支持 | 不支持 | 不支持 | 不支持 | 不支持 | 支持 | \ No newline at end of file diff --git a/docs/zh/14-reference/03-taos-sql/pic/virtual-table-origin-table.png b/docs/zh/14-reference/03-taos-sql/pic/virtual-table-origin-table.png new file mode 100644 index 0000000000000000000000000000000000000000..4819389b22550ed58308fdc5f42c54f27772ef39 GIT binary patch literal 7998 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 literal 0 HcmV?d00001 diff --git a/docs/zh/14-reference/03-taos-sql/pic/virtual-table-query-res-part.png b/docs/zh/14-reference/03-taos-sql/pic/virtual-table-query-res-part.png new file mode 100644 index 0000000000000000000000000000000000000000..5afbdac55e068f93a983b5bf3fec60ee69386fb7 GIT binary patch literal 3194 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 Qeq!8(mKPRVL7?XKFY3rBA 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 Uh{1=zKi>%8vZ^x0(xw6b1!APL00000 literal 0 HcmV?d00001 From c625106609361e172aa2bab1d2271f2ac07367ce Mon Sep 17 00:00:00 2001 From: Mario Peng <48949600+Pengrongkun@users.noreply.github.com> Date: Sat, 22 Mar 2025 21:14:08 +0800 Subject: [PATCH 21/28] fix(stmt2):stmt2 get fields return wrong when tag is value (#30283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: add 3.3.6 branch * fix: delete taos-tools repo in Jenkinsfile2 * ci:add 3.3.6 branch to taosd-ci.yml * fix: [TD-34074] compile error (#30220) * fix: add case * fix: stmt2 get fields return wrong when tag is value * enh: replace preCtb bool to flag,handle more situation * fix: some unit test error * diff: add case and fix some problem * fix: remove async test, handle in TD-34077 * fix: [TD-34074] Forbid virtual table in tq and stmt and forbid supertable query's origin table from different databases. fix: [TD-34074] Forbid virtual table in tq and stmt and forbid supertable query's origin table from different databases. * fix(sml): process space in the end if writing raw data in sml & change some log level #30306 fix(sml): process space in the end if writing raw data in sml & change some log level * fix: taosadapter version 3.3.6 (#30324) * docs(stream): document streaming computation support for virtual tables in user manual (#30319) * docs(stream): document streaming computation support for virtual tables in user manual - Added section to user manual describing streaming computation support for virtual tables - Listed known limitations and behavior when using virtual tables in streaming mode * Update 14-stream.md --------- Co-authored-by: Pan Wei <72057773+dapan1121@users.noreply.github.com> * fix: review * ci: add tdgpt .c file into TDengine and TDgpt workflow * ci: add tdgpt .c file into TDengine and TDgpt workflow --------- Signed-off-by: WANG Xu Co-authored-by: WANG Xu Co-authored-by: haoranchen Co-authored-by: Simon Guan Co-authored-by: Feng Chao Co-authored-by: facetosea <285808407@qq.com> Co-authored-by: Jing Sima Co-authored-by: Jinqing Kuang Co-authored-by: dapan1121 Co-authored-by: Pan Wei <72057773+dapan1121@users.noreply.github.com> Co-authored-by: Haojun Liao Co-authored-by: huohong <346479823@qq.com> Co-authored-by: Minglei Jin Co-authored-by: freemine Co-authored-by: Yihao Deng Co-authored-by: 54liuyao <54liuyao@163.com> Co-authored-by: Bomin Zhang Co-authored-by: 蟑螂·魂 Co-authored-by: wangjiaming Co-authored-by: Haojun Liao Co-authored-by: dongming chen Co-authored-by: Zhiyu Yang <69311263+zyyang90@users.noreply.github.com> Co-authored-by: Nie Minhui <143420805+minhuinie@users.noreply.github.com> Co-authored-by: Zhixiao Bao <62235797+xiao-77@users.noreply.github.com> Co-authored-by: Kaili Xu Co-authored-by: Linhe Huo Co-authored-by: tjuzyp Co-authored-by: yanyuxing Co-authored-by: WANG MINGMING Co-authored-by: yihaoDeng Co-authored-by: facetosea <25808407@qq.com> Co-authored-by: Minglei Jin <49711132+stephenkgu@users.noreply.github.com> Co-authored-by: She Yanjie <57549981+sheyanjie-qq@users.noreply.github.com> Co-authored-by: jiajingbin <39030567+jiajingbin@users.noreply.github.com> Co-authored-by: Alex Duan <51781608+DuanKuanJun@users.noreply.github.com> Co-authored-by: kevin men Co-authored-by: Hongze Cheng Co-authored-by: Yaming Pei Co-authored-by: Xuefeng Tan <1172915550@qq.com> --- .github/workflows/tdengine-test.yml | 1 + cmake/taosadapter_CMakeLists.txt.in | 2 +- docs/en/14-reference/03-taos-sql/14-stream.md | 18 ++++ docs/zh/14-reference/03-taos-sql/14-stream.md | 18 ++++ include/libs/parser/parser.h | 10 +- source/client/inc/clientStmt.h | 2 +- source/client/src/clientSmlTelnet.c | 2 +- source/client/src/clientStmt.c | 12 ++- source/client/src/clientStmt2.c | 19 ++-- source/client/test/stmt2Test.cpp | 99 ++++++++++++++----- source/libs/parser/src/parInsertSql.c | 70 ++++++++----- source/libs/parser/src/parInsertStmt.c | 13 +-- source/util/src/tmempool.c | 2 +- source/util/test/memPoolTest.cpp | 2 +- utils/test/c/sml_test.c | 28 +++++- 15 files changed, 222 insertions(+), 76 deletions(-) diff --git a/.github/workflows/tdengine-test.yml b/.github/workflows/tdengine-test.yml index b981d005c4..e5e2cdbfaf 100644 --- a/.github/workflows/tdengine-test.yml +++ b/.github/workflows/tdengine-test.yml @@ -6,6 +6,7 @@ on: - 'main' - '3.0' - '3.1' + - '3.3.6' paths-ignore: - 'packaging/**' - 'docs/**' diff --git a/cmake/taosadapter_CMakeLists.txt.in b/cmake/taosadapter_CMakeLists.txt.in index ef6ed4af1d..a768b332a6 100644 --- a/cmake/taosadapter_CMakeLists.txt.in +++ b/cmake/taosadapter_CMakeLists.txt.in @@ -2,7 +2,7 @@ # taosadapter ExternalProject_Add(taosadapter GIT_REPOSITORY https://github.com/taosdata/taosadapter.git - GIT_TAG 3.0 + GIT_TAG 3.3.6 SOURCE_DIR "${TD_SOURCE_DIR}/tools/taosadapter" BINARY_DIR "" #BUILD_IN_SOURCE TRUE diff --git a/docs/en/14-reference/03-taos-sql/14-stream.md b/docs/en/14-reference/03-taos-sql/14-stream.md index 00e29b0e3d..f8ad80d2a3 100644 --- a/docs/en/14-reference/03-taos-sql/14-stream.md +++ b/docs/en/14-reference/03-taos-sql/14-stream.md @@ -532,6 +532,24 @@ These fields are present only when "windowType" is "Count". #### Fields for Window Invalidation Due to scenarios such as data disorder, updates, or deletions during stream computing, windows that have already been generated might be removed or their results need to be recalculated. In such cases, a notification with the eventType "WINDOW_INVALIDATION" is sent to inform which windows have been invalidated. + For events with "eventType" as "WINDOW_INVALIDATION", the following fields are included: 1. "windowStart": A long integer timestamp representing the start time of the window. 1. "windowEnd": A long integer timestamp representing the end time of the window. + +## Support for Virtual Tables in Stream Computing + +Starting with v3.3.6.0, stream computing can use virtual tables—including virtual regular tables, virtual sub-tables, and virtual super tables—as data sources for computation. The syntax is identical to that for non‑virtual tables. + +However, because the behavior of virtual tables differs from that of non‑virtual tables, the following restrictions apply when using stream computing: + +1. The schema of virtual regular tables/virtual sub-tables involved in stream computing cannot be modified. +1. During stream computing, if the data source corresponding to a column in a virtual table is changed, the stream computation will not pick up the change; it will still read from the old data source. +1. During stream computing, if the original table corresponding to a column in a virtual table is deleted and later a new table with the same name and a column with the same name is created, the stream computation will not read data from the new table. +1. The watermark for stream computing must be 0; otherwise, an error will occur during creation. +1. If the data source for stream computing is a virtual super table, sub-tables that are added after the stream computing task starts will not participate in the computation. +1. The timestamps of different underlying tables in a virtual table may not be completely consistent; merging the data might produce null values, and interpolation is currently not supported. +1. Out-of-order data, updates, or deletions are not handled. In other words, when creating a stream, you cannot specify `ignore update 0` or `ignore expired 0`; otherwise, an error will be reported. +1. Historical data computation is not supported. That is, when creating a stream, you cannot specify `fill_history 1`; otherwise, an error will be reported. +1. The trigger modes MAX_DELAY, CONTINUOUS_WINDOW_CLOSE and FORCE_WINDOW_CLOSE are not supported. +1. The COUNT_WINDOW type is not supported. diff --git a/docs/zh/14-reference/03-taos-sql/14-stream.md b/docs/zh/14-reference/03-taos-sql/14-stream.md index b4c4a76922..a9225a3ab4 100644 --- a/docs/zh/14-reference/03-taos-sql/14-stream.md +++ b/docs/zh/14-reference/03-taos-sql/14-stream.md @@ -527,6 +527,24 @@ CREATE STREAM avg_current_stream FILL_HISTORY 1 #### 窗口失效相关字段 因为流计算过程中会遇到数据乱序、更新、删除等情况,可能造成已生成的窗口被删除,或者结果需要重新计算。此时会向通知地址发送一条 WINDOW_INVALIDATION 的通知,说明哪些窗口已经被删除。 + 这部分是 eventType 为 WINDOW_INVALIDATION 时,event 对象才有的字段。 1. windowStart:长整型时间戳,表示窗口的开始时间,精度与结果表的时间精度一致。 1. windowEnd: 长整型时间戳,表示窗口的结束时间,精度与结果表的时间精度一致。 + +## 流式计算对虚拟表的支持 + +从 v3.3.6.0 开始,流计算能够使用虚拟表(包括虚拟普通表、虚拟子表、虚拟超级表)作为数据源进行计算,语法和非虚拟表完全一致。 + +但是虚拟表的行为与非虚拟表存在差异,所以目前在使用流计算对虚拟表进行计算时存在以下限制: + +1. 流计算中涉及的虚拟普通表/虚拟子表的 schema 不允许更改。 +1. 流计算过程中,如果修改虚拟表某一列对应的数据源,对流计算来说不生效。即:流计算仍只读取老的数据源。 +1. 流计算过程中,如果虚拟表某一列对应的原始表被删除,之后新建了同名的表和同名的列,流计算不会读取新表的数据。 +1. 流计算的 watermark 只能是 0,否则创建时就报错。 +1. 如果流计算的数据源是虚拟超级表,流计算任务启动后新增的子表不参与计算。 +1. 虚拟表的不同原始表的时间戳不完全一致,数据合并后可能会产生空值,暂不支持插值处理。 +1. 不处理数据的乱序、更新或删除。即:流创建时不能指定 `ignore update 0` 或者 `ignore expired 0`,否则报错。 +1. 不支持历史数据计算,即:流创建时不能指定 `fill_history 1`,否则报错。 +1. 不支持触发模式:MAX_DELAY, FORCE_WINDOW_CLOSE, CONTINUOUS_WINDOW_CLOSE。 +1. 不支持窗口类型:COUNT_WINDOW。 diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 7ce4684f07..4fd6fef81a 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -49,10 +49,16 @@ extern "C" { } \ } while (0) +#define HAS_BIND_VALUE ((uint8_t)0x1) +#define IS_FIXED_VALUE ((uint8_t)0x2) +#define USING_CLAUSE ((uint8_t)0x4) +#define IS_FIXED_TAG ((uint8_t)0x8) +#define NO_DATA_USING_CLAUSE ((uint8_t)0x7) + typedef struct SStmtCallback { TAOS_STMT* pStmt; int32_t (*getTbNameFn)(TAOS_STMT*, char**); - int32_t (*setInfoFn)(TAOS_STMT*, STableMeta*, void*, SName*, bool, SHashObj*, SHashObj*, const char*, bool); + int32_t (*setInfoFn)(TAOS_STMT*, STableMeta*, void*, SName*, bool, SHashObj*, SHashObj*, const char*, uint8_t); int32_t (*getExecInfoFn)(TAOS_STMT*, SHashObj**, SHashObj**); } SStmtCallback; @@ -175,7 +181,7 @@ int32_t qBindStmtColsValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, c int32_t qBindStmtSingleColValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen, int32_t colIdx, int32_t rowNum, void* charsetCxt); int32_t qBuildStmtColFields(void* pDataBlock, int32_t* fieldNum, TAOS_FIELD_E** fields); -int32_t qBuildStmtStbColFields(void* pBlock, void* boundTags, bool hasCtbName, int32_t* fieldNum, +int32_t qBuildStmtStbColFields(void* pBlock, void* boundTags, uint8_t tbNameFlag, int32_t* fieldNum, TAOS_FIELD_ALL** fields); int32_t qBuildStmtTagFields(void* pBlock, void* boundTags, int32_t* fieldNum, TAOS_FIELD_E** fields); int32_t qBindStmtTagsValue(void* pBlock, void* boundTags, int64_t suid, const char* sTableName, char* tName, diff --git a/source/client/inc/clientStmt.h b/source/client/inc/clientStmt.h index 74260c42e0..5d61e8b5d0 100644 --- a/source/client/inc/clientStmt.h +++ b/source/client/inc/clientStmt.h @@ -64,7 +64,7 @@ typedef struct SStmtBindInfo { int32_t sBindLastIdx; int8_t tbType; bool tagsCached; - bool preCtbname; + uint8_t tbNameFlag; void *boundTags; char tbName[TSDB_TABLE_FNAME_LEN]; char tbFName[TSDB_TABLE_FNAME_LEN]; diff --git a/source/client/src/clientSmlTelnet.c b/source/client/src/clientSmlTelnet.c index dd264da11e..0427196b83 100644 --- a/source/client/src/clientSmlTelnet.c +++ b/source/client/src/clientSmlTelnet.c @@ -75,7 +75,7 @@ static int32_t smlProcessTagTelnet(SSmlHandle *info, char *data, char *sqlEnd){ const char *sql = data; while (sql < sqlEnd) { JUMP_SPACE(sql, sqlEnd) - if (unlikely(*sql == '\0')) break; + if (unlikely(*sql == '\0' || *sql == '\n')) break; const char *key = sql; size_t keyLen = 0; diff --git a/source/client/src/clientStmt.c b/source/client/src/clientStmt.c index 2d9001d248..4cef20056b 100644 --- a/source/client/src/clientStmt.c +++ b/source/client/src/clientStmt.c @@ -238,7 +238,7 @@ int32_t stmtRestoreQueryFields(STscStmt* pStmt) { } */ int32_t stmtUpdateBindInfo(TAOS_STMT* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, const char* sTableName, - bool autoCreateTbl) { + bool autoCreateTbl, uint8_t tbNameFlag) { STscStmt* pStmt = (STscStmt*)stmt; char tbFName[TSDB_TABLE_FNAME_LEN]; int32_t code = tNameExtractFullName(tbName, tbFName); @@ -256,6 +256,7 @@ int32_t stmtUpdateBindInfo(TAOS_STMT* stmt, STableMeta* pTableMeta, void* tags, pStmt->bInfo.tbType = pTableMeta->tableType; pStmt->bInfo.boundTags = tags; pStmt->bInfo.tagsCached = false; + pStmt->bInfo.tbNameFlag = tbNameFlag; tstrncpy(pStmt->bInfo.stbFName, sTableName, sizeof(pStmt->bInfo.stbFName)); return TSDB_CODE_SUCCESS; @@ -271,10 +272,10 @@ int32_t stmtUpdateExecInfo(TAOS_STMT* stmt, SHashObj* pVgHash, SHashObj* pBlockH } int32_t stmtUpdateInfo(TAOS_STMT* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, bool autoCreateTbl, - SHashObj* pVgHash, SHashObj* pBlockHash, const char* sTableName, bool preCtbname) { + SHashObj* pVgHash, SHashObj* pBlockHash, const char* sTableName, uint8_t tbNameFlag) { STscStmt* pStmt = (STscStmt*)stmt; - STMT_ERR_RET(stmtUpdateBindInfo(stmt, pTableMeta, tags, tbName, sTableName, autoCreateTbl)); + STMT_ERR_RET(stmtUpdateBindInfo(stmt, pTableMeta, tags, tbName, sTableName, autoCreateTbl, tbNameFlag)); STMT_ERR_RET(stmtUpdateExecInfo(stmt, pVgHash, pBlockHash)); pStmt->sql.autoCreateTbl = autoCreateTbl; @@ -1729,7 +1730,10 @@ int stmtGetTagFields(TAOS_STMT* stmt, int* nums, TAOS_FIELD_E** fields) { STMT_ERRI_JRET(stmtFetchTagFields(stmt, nums, fields)); _return: - + // compatible with previous versions + if (code == TSDB_CODE_PAR_TABLE_NOT_EXIST && (pStmt->bInfo.tbNameFlag & NO_DATA_USING_CLAUSE) == 0x0) { + code = TSDB_CODE_TSC_STMT_TBNAME_ERROR; + } pStmt->errCode = preCode; return code; diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index cfd302d895..c4f8702f43 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -193,7 +193,7 @@ static int32_t stmtGetTbName(TAOS_STMT2* stmt, char** tbName) { } static int32_t stmtUpdateBindInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, - const char* sTableName, bool autoCreateTbl, bool preCtbname) { + const char* sTableName, bool autoCreateTbl, int8_t tbNameFlag) { STscStmt2* pStmt = (STscStmt2*)stmt; char tbFName[TSDB_TABLE_FNAME_LEN]; int32_t code = tNameExtractFullName(tbName, tbFName); @@ -217,7 +217,7 @@ static int32_t stmtUpdateBindInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void pStmt->bInfo.boundTags = tags; pStmt->bInfo.tagsCached = false; - pStmt->bInfo.preCtbname = preCtbname; + pStmt->bInfo.tbNameFlag = tbNameFlag; tstrncpy(pStmt->bInfo.stbFName, sTableName, sizeof(pStmt->bInfo.stbFName)); return TSDB_CODE_SUCCESS; @@ -233,10 +233,10 @@ static int32_t stmtUpdateExecInfo(TAOS_STMT2* stmt, SHashObj* pVgHash, SHashObj* } static int32_t stmtUpdateInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, bool autoCreateTbl, - SHashObj* pVgHash, SHashObj* pBlockHash, const char* sTableName, bool preCtbname) { + SHashObj* pVgHash, SHashObj* pBlockHash, const char* sTableName, uint8_t tbNameFlag) { STscStmt2* pStmt = (STscStmt2*)stmt; - STMT_ERR_RET(stmtUpdateBindInfo(stmt, pTableMeta, tags, tbName, sTableName, autoCreateTbl, preCtbname)); + STMT_ERR_RET(stmtUpdateBindInfo(stmt, pTableMeta, tags, tbName, sTableName, autoCreateTbl, tbNameFlag)); STMT_ERR_RET(stmtUpdateExecInfo(stmt, pVgHash, pBlockHash)); pStmt->sql.autoCreateTbl = autoCreateTbl; @@ -1233,7 +1233,8 @@ static int stmtFetchStbColFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIEL } STMT_ERRI_JRET( - qBuildStmtStbColFields(*pDataBlock, pStmt->bInfo.boundTags, pStmt->bInfo.preCtbname, fieldNum, fields)); + qBuildStmtStbColFields(*pDataBlock, pStmt->bInfo.boundTags, pStmt->bInfo.tbNameFlag, fieldNum, fields)); + if (pStmt->bInfo.tbType == TSDB_SUPER_TABLE && cleanStb) { pStmt->bInfo.needParse = true; qDestroyStmtDataBlock(*pDataBlock); @@ -2022,7 +2023,9 @@ int stmtParseColFields2(TAOS_STMT2* stmt) { STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { pStmt->bInfo.needParse = false; } - + if (pStmt->sql.stbInterlaceMode && pStmt->sql.siInfo.pDataCtx != NULL) { + pStmt->bInfo.needParse = false; + } if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { taos_free_result(pStmt->exec.pRequest); pStmt->exec.pRequest = NULL; @@ -2036,6 +2039,10 @@ int stmtParseColFields2(TAOS_STMT2* stmt) { } _return: + // compatible with previous versions + if (code == TSDB_CODE_PAR_TABLE_NOT_EXIST && (pStmt->bInfo.tbNameFlag & NO_DATA_USING_CLAUSE) == 0x0) { + code = TSDB_CODE_TSC_STMT_TBNAME_ERROR; + } pStmt->errCode = preCode; diff --git a/source/client/test/stmt2Test.cpp b/source/client/test/stmt2Test.cpp index cc54cd55d3..5e50760648 100644 --- a/source/client/test/stmt2Test.cpp +++ b/source/client/test/stmt2Test.cpp @@ -534,7 +534,7 @@ TEST(stmt2Case, insert_ctb_using_get_fields_Test) { printf("support case \n"); // case 1 : test child table already exist { - const char* sql = "INSERT INTO stmt2_testdb_3.t0(ts,b)using stmt2_testdb_3.stb (t1,t2) TAGS(?,?) VALUES (?,?)"; + const char* sql = "INSERT INTO stmt2_testdb_3.t0(ts,b)using stmt2_testdb_3.stb (t1,t2) TAGS(?,?) VALUES(?,?)"; TAOS_FIELD_ALL expectedFields[4] = {{"t1", TSDB_DATA_TYPE_INT, 0, 0, 4, TAOS_FIELD_TAG}, {"t2", TSDB_DATA_TYPE_BINARY, 0, 0, 12, TAOS_FIELD_TAG}, {"ts", TSDB_DATA_TYPE_TIMESTAMP, 2, 0, 8, TAOS_FIELD_COL}, @@ -612,7 +612,7 @@ TEST(stmt2Case, insert_ctb_using_get_fields_Test) { // case 8 : 'db' 'stb' { - const char* sql = "INSERT INTO 'stmt2_testdb_3'.? using 'stmt2_testdb_3'.'stb' (t1,t2) TAGS(?,?) (ts,b)VALUES(?,?)"; + const char* sql = "INSERT INTO 'stmt2_testdb_3'.? using 'stmt2_testdb_3'.'stb' (t1,t2) TAGS(?,?)(ts,b)VALUES(?,?)"; TAOS_FIELD_ALL expectedFields[5] = {{"tbname", TSDB_DATA_TYPE_BINARY, 0, 0, 271, TAOS_FIELD_TBNAME}, {"t1", TSDB_DATA_TYPE_INT, 0, 0, 4, TAOS_FIELD_TAG}, {"t2", TSDB_DATA_TYPE_BINARY, 0, 0, 12, TAOS_FIELD_TAG}, @@ -634,9 +634,20 @@ TEST(stmt2Case, insert_ctb_using_get_fields_Test) { printf("case 9 : %s\n", sql); getFieldsSuccess(taos, sql, expectedFields, 5); } + // case 11: TD-34097 + { + do_query(taos, "use stmt2_testdb_3"); + const char* sql = "INSERT INTO ? using stb (t1,t2) TAGS(1,'abc') (ts,b)VALUES(?,?)"; + TAOS_FIELD_ALL expectedFields[3] = {{"tbname", TSDB_DATA_TYPE_BINARY, 0, 0, 271, TAOS_FIELD_TBNAME}, + {"ts", TSDB_DATA_TYPE_TIMESTAMP, 2, 0, 8, TAOS_FIELD_COL}, + {"b", TSDB_DATA_TYPE_BINARY, 0, 0, 12, TAOS_FIELD_COL}}; + printf("case 11 : %s\n", sql); + getFieldsSuccess(taos, sql, expectedFields, 3); + } // case 10 : test all types { + do_query(taos, "use stmt2_testdb_3"); const char* sql = "insert into ? using all_stb tags(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; TAOS_FIELD_ALL expectedFields[33] = {{"tbname", TSDB_DATA_TYPE_BINARY, 0, 0, 271, TAOS_FIELD_TBNAME}, @@ -711,7 +722,27 @@ TEST(stmt2Case, insert_ctb_using_get_fields_Test) { printf("case 5 : %s\n", sql); getFieldsError(taos, sql, TSDB_CODE_TSC_SQL_SYNTAX_ERROR); } - + // case 6 : mix value and ? + { + do_query(taos, "use stmt2_testdb_3"); + const char* sql = "INSERT INTO ? using stb (t1,t2) TAGS(1,?) (ts,b)VALUES(?,?)"; + printf("case 6 : %s\n", sql); + getFieldsError(taos, sql, TSDB_CODE_TSC_SQL_SYNTAX_ERROR); + } + // case 7 : mix value and ? + { + do_query(taos, "use stmt2_testdb_3"); + const char* sql = "INSERT INTO ? using stb (t1,t2) TAGS(?,?) (ts,b)VALUES(15910606280001,?)"; + printf("case 7 : %s\n", sql); + getFieldsError(taos, sql, TSDB_CODE_TSC_INVALID_OPERATION); + } + // case 8 : mix value and ? + { + do_query(taos, "use stmt2_testdb_3"); + const char* sql = "INSERT INTO ? using stb (t1,t2) TAGS(?,?) (ts,b)VALUES(15910606280001,'abc')"; + printf("case 8 : %s\n", sql); + getFieldsError(taos, sql, TSDB_CODE_TSC_INVALID_OPERATION); + } do_query(taos, "drop database if exists stmt2_testdb_3"); taos_close(taos); } @@ -1002,6 +1033,15 @@ TEST(stmt2Case, stmt2_insert_non_statndard) { printf("stmt2 [%s] : %s\n", "less params", sql); int code = taos_stmt2_prepare(stmt, sql, 0); checkError(stmt, code); + // test get fields + int fieldNum = 0; + TAOS_FIELD_ALL* pFields = NULL; + code = taos_stmt2_get_fields(stmt, &fieldNum, &pFields); + checkError(stmt, code); + ASSERT_EQ(fieldNum, 2); + ASSERT_STREQ(pFields[0].name, "tbname"); + ASSERT_STREQ(pFields[1].name, "ts"); + int total_affect_rows = 0; int t64_len[2] = {sizeof(int64_t), sizeof(int64_t)}; @@ -1024,11 +1064,22 @@ TEST(stmt2Case, stmt2_insert_non_statndard) { code = taos_stmt2_bind_param(stmt, &bindv, -1); checkError(stmt, code); + code = taos_stmt2_get_fields(stmt, &fieldNum, &pFields); + checkError(stmt, code); + ASSERT_EQ(fieldNum, 2); + ASSERT_STREQ(pFields[0].name, "tbname"); + ASSERT_STREQ(pFields[1].name, "ts"); + int affected_rows; taos_stmt2_exec(stmt, &affected_rows); total_affect_rows += affected_rows; - checkError(stmt, code); + + code = taos_stmt2_get_fields(stmt, &fieldNum, &pFields); + checkError(stmt, code); + ASSERT_EQ(fieldNum, 2); + ASSERT_STREQ(pFields[0].name, "tbname"); + ASSERT_STREQ(pFields[1].name, "ts"); } ASSERT_EQ(total_affect_rows, 12); @@ -1959,27 +2010,27 @@ void stmt2_async_test(std::atomic& stop_task) { stop_task = true; } -TEST(stmt2Case, async_order) { - std::atomic stop_task(false); - std::thread t(stmt2_async_test, std::ref(stop_task)); +// TEST(stmt2Case, async_order) { +// std::atomic stop_task(false); +// std::thread t(stmt2_async_test, std::ref(stop_task)); - // 等待 60 秒钟 - auto start_time = std::chrono::steady_clock::now(); - while (!stop_task) { - auto elapsed_time = std::chrono::steady_clock::now() - start_time; - if (std::chrono::duration_cast(elapsed_time).count() > 100) { - if (t.joinable()) { - t.detach(); - } - FAIL() << "Test[stmt2_async_test] timed out"; - break; - } - std::this_thread::sleep_for(std::chrono::seconds(1)); // 每 1s 检查一次 - } - if (t.joinable()) { - t.join(); - } -} +// // 等待 60 秒钟 +// auto start_time = std::chrono::steady_clock::now(); +// while (!stop_task) { +// auto elapsed_time = std::chrono::steady_clock::now() - start_time; +// if (std::chrono::duration_cast(elapsed_time).count() > 100) { +// if (t.joinable()) { +// t.detach(); +// } +// FAIL() << "Test[stmt2_async_test] timed out"; +// break; +// } +// std::this_thread::sleep_for(std::chrono::seconds(1)); // 每 1s 检查一次 +// } +// if (t.joinable()) { +// t.join(); +// } +// } TEST(stmt2Case, rowformat_bind) { TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0); diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index 81129a6f8f..25e8ccc1c6 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -32,7 +32,7 @@ typedef struct SInsertParseContext { bool needTableTagVal; bool needRequest; // whether or not request server bool isStmtBind; // whether is stmt bind - bool preCtbname; + uint8_t stmtTbNameFlag; } SInsertParseContext; typedef int32_t (*_row_append_fn_t)(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param); @@ -993,6 +993,10 @@ static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", token.z); break; } + if (pTagVals->size != 0) { + code = buildSyntaxErrMsg(&pCxt->msg, "no mix usage for ? and tag values", token.z); + break; + } continue; } @@ -1026,6 +1030,10 @@ static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt pTag = NULL; } + if (code == TSDB_CODE_SUCCESS && !isParseBindParam) { + pCxt->stmtTbNameFlag |= IS_FIXED_TAG; + } + _exit: for (int32_t i = 0; i < taosArrayGetSize(pTagVals); ++i) { STagVal* p = (STagVal*)TARRAY_GET_ELEM(pTagVals, i); @@ -1416,6 +1424,7 @@ static int32_t parseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt return getTargetTableSchema(pCxt, pStmt); } pStmt->usingTableProcessing = true; + pCxt->stmtTbNameFlag |= USING_CLAUSE; // pStmt->pSql -> stb_name [(tag1_name, ...) pStmt->pSql += index; int32_t code = parseDuplicateUsingClause(pCxt, pStmt, &pCxt->usingDuplicateTable); @@ -1465,7 +1474,7 @@ static int32_t getTableDataCxt(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pS char tbFName[TSDB_TABLE_FNAME_LEN]; int32_t code = 0; - if (pCxt->preCtbname) { + if ((pCxt->stmtTbNameFlag & NO_DATA_USING_CLAUSE) == USING_CLAUSE) { tstrncpy(pStmt->targetTableName.tname, pStmt->usingTableName.tname, sizeof(pStmt->targetTableName.tname)); tstrncpy(pStmt->targetTableName.dbname, pStmt->usingTableName.dbname, sizeof(pStmt->targetTableName.dbname)); pStmt->targetTableName.type = TSDB_SUPER_TABLE; @@ -2764,6 +2773,7 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif } if (TK_NK_QUESTION == pTbName->type) { + pCxt->stmtTbNameFlag &= ~IS_FIXED_VALUE; pCxt->isStmtBind = true; if (NULL == pCxt->pComCxt->pStmtCb) { return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z); @@ -2772,14 +2782,15 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif char* tbName = NULL; int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName); if (TSDB_CODE_SUCCESS == code) { + pCxt->stmtTbNameFlag |= HAS_BIND_VALUE; pTbName->z = tbName; pTbName->n = strlen(tbName); - } else if (code == TSDB_CODE_TSC_STMT_TBNAME_ERROR) { - pCxt->preCtbname = true; - code = TSDB_CODE_SUCCESS; - } else { - return code; } + if (code == TSDB_CODE_TSC_STMT_TBNAME_ERROR) { + pCxt->stmtTbNameFlag &= ~HAS_BIND_VALUE; + code = TSDB_CODE_SUCCESS; + } + return code; } if (TK_NK_ID != pTbName->type && TK_NK_STRING != pTbName->type && TK_NK_QUESTION != pTbName->type) { @@ -2788,26 +2799,34 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif // db.? situation,ensure that the only thing following the '.' mark is '?' char* tbNameAfterDbName = strnchr(pTbName->z, '.', pTbName->n, true); - if ((tbNameAfterDbName != NULL) && (*(tbNameAfterDbName + 1) == '?')) { - char* tbName = NULL; - if (NULL == pCxt->pComCxt->pStmtCb) { - return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z); - } - int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName); - if (code != TSDB_CODE_SUCCESS) { - pCxt->preCtbname = true; + if (tbNameAfterDbName != NULL) { + if (*(tbNameAfterDbName + 1) == '?') { + pCxt->stmtTbNameFlag &= ~IS_FIXED_VALUE; + char* tbName = NULL; + if (NULL == pCxt->pComCxt->pStmtCb) { + return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z); + } + int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName); + if (TSDB_CODE_SUCCESS == code) { + pCxt->stmtTbNameFlag |= HAS_BIND_VALUE; + pTbName->z = tbName; + pTbName->n = strlen(tbName); + } + if (code == TSDB_CODE_TSC_STMT_TBNAME_ERROR) { + pCxt->stmtTbNameFlag &= ~HAS_BIND_VALUE; + code = TSDB_CODE_SUCCESS; + } } else { - pTbName->z = tbName; - pTbName->n = strlen(tbName); - } - } - - if (pCxt->isStmtBind) { - if (TK_NK_ID == pTbName->type || (tbNameAfterDbName != NULL && *(tbNameAfterDbName + 1) != '?')) { - // In SQL statements, the table name has already been specified. + pCxt->stmtTbNameFlag |= IS_FIXED_VALUE; parserWarn("QID:0x%" PRIx64 ", table name is specified in sql, ignore the table name in bind param", pCxt->pComCxt->requestId); + *pHasData = true; } + return TSDB_CODE_SUCCESS; + } + + if (TK_NK_ID == pTbName->type) { + pCxt->stmtTbNameFlag |= IS_FIXED_VALUE; } *pHasData = true; @@ -2824,7 +2843,7 @@ static int32_t setStmtInfo(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) SStmtCallback* pStmtCb = pCxt->pComCxt->pStmtCb; int32_t code = (*pStmtCb->setInfoFn)(pStmtCb->pStmt, pStmt->pTableMeta, tags, &pStmt->targetTableName, pStmt->usingTableProcessing, pStmt->pVgroupsHashObj, pStmt->pTableBlockHashObj, - pStmt->usingTableName.tname, pCxt->preCtbname); + pStmt->usingTableName.tname, pCxt->stmtTbNameFlag); memset(&pCxt->tags, 0, sizeof(pCxt->tags)); pStmt->pVgroupsHashObj = NULL; @@ -2880,9 +2899,6 @@ static int32_t parseInsertBody(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pS if (TSDB_CODE_SUCCESS == code && hasData) { code = parseInsertTableClause(pCxt, pStmt, &token); } - if (TSDB_CODE_PAR_TABLE_NOT_EXIST == code && pCxt->preCtbname) { - code = TSDB_CODE_TSC_STMT_TBNAME_ERROR; - } } if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) { diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 9bb98eb223..2dc9e96264 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -1070,10 +1070,11 @@ int32_t buildBoundFields(int32_t numOfBound, int16_t* boundColumns, SSchema* pSc } int32_t buildStbBoundFields(SBoundColInfo boundColsInfo, SSchema* pSchema, int32_t* fieldNum, TAOS_FIELD_ALL** fields, - STableMeta* pMeta, void* boundTags, bool preCtbname) { + STableMeta* pMeta, void* boundTags, uint8_t tbNameFlag) { SBoundColInfo* tags = (SBoundColInfo*)boundTags; - bool hastag = tags != NULL; - int32_t numOfBound = boundColsInfo.numOfBound + (preCtbname ? 1 : 0); + bool hastag = (tags != NULL) && !(tbNameFlag & IS_FIXED_TAG); + int32_t numOfBound = + boundColsInfo.numOfBound + ((tbNameFlag & IS_FIXED_VALUE) == 0 && (tbNameFlag & USING_CLAUSE) != 0 ? 1 : 0); if (hastag) { numOfBound += tags->mixTagsCols ? 0 : tags->numOfBound; } @@ -1084,7 +1085,7 @@ int32_t buildStbBoundFields(SBoundColInfo boundColsInfo, SSchema* pSchema, int32 return terrno; } - if (preCtbname && numOfBound != boundColsInfo.numOfBound) { + if ((tbNameFlag & IS_FIXED_VALUE) == 0 && (tbNameFlag & USING_CLAUSE) != 0) { (*fields)[idx].field_type = TAOS_FIELD_TBNAME; tstrncpy((*fields)[idx].name, "tbname", sizeof((*fields)[idx].name)); (*fields)[idx].type = TSDB_DATA_TYPE_BINARY; @@ -1188,7 +1189,7 @@ int32_t qBuildStmtColFields(void* pBlock, int32_t* fieldNum, TAOS_FIELD_E** fiel return TSDB_CODE_SUCCESS; } -int32_t qBuildStmtStbColFields(void* pBlock, void* boundTags, bool preCtbname, int32_t* fieldNum, +int32_t qBuildStmtStbColFields(void* pBlock, void* boundTags, uint8_t tbNameFlag, int32_t* fieldNum, TAOS_FIELD_ALL** fields) { STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); @@ -1202,7 +1203,7 @@ int32_t qBuildStmtStbColFields(void* pBlock, void* boundTags, bool preCtbname, i } CHECK_CODE(buildStbBoundFields(pDataBlock->boundColsInfo, pSchema, fieldNum, fields, pDataBlock->pMeta, boundTags, - preCtbname)); + tbNameFlag)); return TSDB_CODE_SUCCESS; } diff --git a/source/util/src/tmempool.c b/source/util/src/tmempool.c index 0a56c69505..96a9cfcea2 100644 --- a/source/util/src/tmempool.c +++ b/source/util/src/tmempool.c @@ -1029,7 +1029,7 @@ void mpUpdateSystemAvailableMemorySize() { atomic_store_64(&tsCurrentAvailMemorySize, sysAvailSize); - uDebug("system available memory size: %" PRId64, sysAvailSize); + uTrace("system available memory size: %" PRId64, sysAvailSize); } void mpSchedTrim(int64_t* loopTimes) { diff --git a/source/util/test/memPoolTest.cpp b/source/util/test/memPoolTest.cpp index 8af8b01368..a0086b8d1c 100644 --- a/source/util/test/memPoolTest.cpp +++ b/source/util/test/memPoolTest.cpp @@ -729,7 +729,7 @@ int32_t mptGetMemPoolMaxMemSize(void* pHandle, int64_t* maxSize) { } if (TSDB_CODE_SUCCESS != code) { - uError("get system avaiable memory size failed, error: 0x%x", code); + uError("get system available memory size failed, error: 0x%x", code); return code; } diff --git a/utils/test/c/sml_test.c b/utils/test/c/sml_test.c index 0907c2a641..4db5a1908d 100644 --- a/utils/test/c/sml_test.c +++ b/utils/test/c/sml_test.c @@ -87,7 +87,8 @@ int smlProcess_telnet_Test() { const char *sql1[] = {"sys.if.bytes.out 1479496100 1.3E0 host=web01 interface=eth0", "sys.if.bytes.out 1479496101 1.3E1 interface=eth0 host=web01 ", "sys.if.bytes.out 1479496102 1.3E3 network=tcp", - " sys.procs.running 1479496100 42 host=web01 "}; + " sys.procs.running 1479496100 42 host=web01 ", + " newline 1479496100 42 host=web\n01 t=fsb\n "}; // for(int i = 0; i < 4; i++){ // strncpy(sql[i], sql1[i], 128); @@ -2355,12 +2356,35 @@ int sml_td17324_Test() { return code; } +int smlProcess_34114_Test() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 0); + + TAOS_RES *pRes = taos_query(taos, "create database if not exists sml_34114_db schemaless 1"); + taos_free_result(pRes); + + pRes = taos_query(taos, "use sml_34114_db"); + taos_free_result(pRes); + + char *sql = {"sys.if.bytes.out 1479496100 1.3E0 host=web01 interface=eth0 \nsys.if.bytes.out 1479496101 1.3E1 interface=eth0 host=web01 "}; + int32_t totalRows = 0; + pRes = taos_schemaless_insert_raw(taos, sql, strlen(sql), &totalRows, TSDB_SML_TELNET_PROTOCOL, + TSDB_SML_TIMESTAMP_NANO_SECONDS); + printf("%s result:%s\n", __FUNCTION__, taos_errstr(pRes)); + int code = taos_errno(pRes); + taos_free_result(pRes); + taos_close(taos); + + return code; +} + int main(int argc, char *argv[]) { if (argc == 2) { taos_options(TSDB_OPTION_CONFIGDIR, argv[1]); } - int ret = smlProcess_json0_Test(); + int ret = smlProcess_34114_Test(); + ASSERT(!ret); + ret = smlProcess_json0_Test(); ASSERT(!ret); ret = sml_ts5528_test(); ASSERT(!ret); From 21317576e4a7471a82f6f46232e6eb136f7eb759 Mon Sep 17 00:00:00 2001 From: She Yanjie <57549981+sheyanjie-qq@users.noreply.github.com> Date: Sat, 22 Mar 2025 21:16:42 +0800 Subject: [PATCH 22/28] docs: fix virtual table err code (#30348) --- docs/en/14-reference/09-error-code.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/14-reference/09-error-code.md b/docs/en/14-reference/09-error-code.md index 3305eb18eb..90a7c67d0a 100644 --- a/docs/en/14-reference/09-error-code.md +++ b/docs/en/14-reference/09-error-code.md @@ -584,4 +584,4 @@ This document details the server error codes that may be encountered when using | 0x80006204 | Virtual table not support decimal type | Create virtual table using decimal type | create virtual table without using decimal type | | 0x80006205 | Virtual table not support in STMT query and STMT insert | Use virtual table in stmt query and stmt insert | do not use virtual table in stmt query and insert | | 0x80006206 | Virtual table not support in Topic | Use virtual table in topic | do not use virtual table in topic | -| 0x80006206 | Virtual super table query not support origin table from different databases | Virtual super table ‘s child table's origin table from different databases | make sure virtual super table's child table's origin table from same database | +| 0x80006207 | Virtual super table query not support origin table from different databases | Virtual super table ‘s child table's origin table from different databases | make sure virtual super table's child table's origin table from same database | From 97063eb19bf408be5a5ce8aaed157cd1e7d05da3 Mon Sep 17 00:00:00 2001 From: Linhe Huo Date: Sat, 22 Mar 2025 22:18:43 +0800 Subject: [PATCH 23/28] doc: update docs for analysis (#30352) * Update 09-error-code.md * Update 03-preprocess.md * Update index.md * Update index.md * Update index.md * doc: update docs. * Update index.md * Update index.md * Update index.md * docs: fix ci error in forecast doc * docs: fix anoal-detection doc ci error --------- Co-authored-by: Haojun Liao Co-authored-by: Haojun Liao --- docs/zh/06-advanced/06-TDgpt/03-preprocess.md | 4 +- .../06-advanced/06-TDgpt/04-forecast/index.md | 51 +++++++++--------- .../06-TDgpt/05-anomaly-detection/index.md | 26 +++++---- .../06-TDgpt/pic/ad-result-figure.png | Bin 42407 -> 0 bytes .../zh/06-advanced/06-TDgpt/pic/ad-result.png | Bin 20151 -> 26716 bytes docs/zh/06-advanced/06-TDgpt/pic/fc.png | Bin 13240 -> 0 bytes 6 files changed, 45 insertions(+), 36 deletions(-) delete mode 100644 docs/zh/06-advanced/06-TDgpt/pic/ad-result-figure.png mode change 100644 => 100755 docs/zh/06-advanced/06-TDgpt/pic/ad-result.png delete mode 100644 docs/zh/06-advanced/06-TDgpt/pic/fc.png diff --git a/docs/zh/06-advanced/06-TDgpt/03-preprocess.md b/docs/zh/06-advanced/06-TDgpt/03-preprocess.md index b63cae0740..8cc207943a 100644 --- a/docs/zh/06-advanced/06-TDgpt/03-preprocess.md +++ b/docs/zh/06-advanced/06-TDgpt/03-preprocess.md @@ -9,14 +9,14 @@ import wndata from './pic/white-noise-data.png' ### 分析流程 时序数据分析之前需要有预处理的过程,为减轻分析算法的负担,TDgpt 在将时序数据发给具体分析算法进行分析时,已经对数据做了预处理,整体的流程如下图所示。 -预处理流程 +预处理流程 TDgpt 首先对输入数据进行白噪声检查(White Noise Data check), 检查通过以后针对预测分析,还要进行输入(历史)数据的重采样和时间戳对齐处理(异常检测跳过数据重采样和时间戳对齐步骤)。 预处理完成以后,再进行预测或异常检测操作。预处理过程不属于预测或异常检测处理逻辑的一部分。 ### 白噪声检查 -white-noise-data +white-noise-data 白噪声时序数据可以简单地认为是随机数构成的时间数据序列(如上图所示的正态分布随机数序列),随机数构成的时间序列没有分析的价值,因此会直接返回。白噪声检查采用经典的 `Ljung-Box` 统计量检验,计算 `Ljung-Box` 统计量需遍历整个输入时间序列。如果用户能够明确输入序列一定不是白噪声序列,那么可以在参数列表中增加参数 `wncheck=0` 强制要求分析平台忽略白噪声检查,从而节省计算资源。 TDgpt 暂不提供独立的时间序列白噪声检测功能。 diff --git a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md index 560e6cdcc0..e0f6f238cf 100644 --- a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md +++ b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md @@ -3,19 +3,18 @@ title: 预测算法 description: 预测算法 --- -import fc_result from '../pic/fc.png'; -import fc_result_figure from '../pic/fc-result.png'; +import fc_result from '../pic/fc-result.png'; 时序数据预测处理以持续一个时间段的时序数据作为输入,预测接下来一个连续时间区间内时间序列数据趋势。用户可以指定输出的(预测)时间序列数据点的数量,因此其输出的结果行数不确定。为此,TDengine 使用新 SQL 函数 `FORECAST` 提供时序数据预测服务。基础数据(用于预测的历史时间序列数据)是该函数的输入,预测结果是该函数的输出。用户可以通过 `FORECAST` 函数调用 Anode 提供的预测算法提供的服务。 -在后续章节中,使用时序数据表`foo`作为示例,介绍预测和异常检测算法的使用方式,`foo` 表的模式如下: +在后续章节中,使用时序数据表 `foo` 作为示例,介绍预测和异常检测算法的使用方式,`foo` 表的模式如下: -|列名称|类型|说明| -|---|---|---| -|ts| timestamp| 主时间戳列| -|i32| int32| 4字节整数,设备测量值 metric| +| 列名称 | 类型 | 说明 | +| ------ | --------- | ---------------------------- | +| ts | timestamp | 主时间戳列 | +| i32 | int32 | 4字节整数,设备测量值 metric | -```bash +```sql taos> select * from foo; ts | i32 | ======================================== @@ -30,6 +29,7 @@ taos> select * from foo; ``` ### 语法 + ```SQL FORECAST(column_expr, option_expr) @@ -42,21 +42,21 @@ algo=expr1 [,start=start_ts_val] [,expr2] "} - ``` + 1. `column_expr`:预测的时序数据列,只支持数值类型列输入。 2. `options`:预测函数的参数。字符串类型,其中使用 K=V 方式调用算法及相关参数。采用逗号分隔的 K=V 字符串表示,其中的字符串不需要使用单引号、双引号、或转义号等符号,不能使用中文及其他宽字符。预测支持 `conf`, `every`, `rows`, `start`, `rows` 几个控制参数,其含义如下: ### 参数说明 -|参数|含义|默认值| -|---|---|---| -|algo|预测分析使用的算法|holtwinters| -|wncheck|白噪声(white noise data)检查|默认值为 1,0 表示不进行检查| -|conf|预测数据的置信区间范围 ,取值范围 [0, 100]|95| -|every|预测数据的采样间隔|输入数据的采样间隔| -|start|预测结果的开始时间戳|输入数据最后一个时间戳加上一个采样间隔时间区间| -|rows|预测结果的记录数|10| +| 参数 | 含义 | 默认值 | +| ------- | ------------------------------------------ | ---------------------------------------------- | +| algo | 预测分析使用的算法 | holtwinters | +| wncheck | 白噪声(white noise data)检查 | 默认值为 1,0 表示不进行检查 | +| conf | 预测数据的置信区间范围 ,取值范围 [0, 100] | 95 | +| every | 预测数据的采样间隔 | 输入数据的采样间隔 | +| start | 预测结果的开始时间戳 | 输入数据最后一个时间戳加上一个采样间隔时间区间 | +| rows | 预测结果的记录数 | 10 | 1. 预测查询结果新增三个伪列,具体如下:`_FROWTS`:预测结果的时间戳、`_FLOW`:置信区间下界、`_FHIGH`:置信区间上界, 对于没有置信区间的预测算法,其置信区间同预测结果 2. 更改参数 `START`:返回预测结果的起始时间,改变起始时间不会影响返回的预测数值,只影响起始时间。 @@ -74,7 +74,8 @@ FROM foo; SELECT _flow, _fhigh, _frowts, FORECAST(i32, "algo=arima,alpha=95,period=10,wncheck=0") FROM foo; ``` -``` + +```sql taos> select _flow, _fhigh, _frowts, forecast(i32) from foo; _flow | _fhigh | _frowts | forecast(i32) | ======================================================================================== @@ -90,8 +91,8 @@ taos> select _flow, _fhigh, _frowts, forecast(i32) from foo; -1076.1566162 | 1214.4498291 | 2020-01-01 00:01:44.000 | 69 | ``` - ## 内置预测算法 + - [arima](./02-arima.md) - [holtwinters](./03-holtwinters.md) - CES (Complex Exponential Smoothing) @@ -111,6 +112,7 @@ taos> select _flow, _fhigh, _frowts, forecast(i32) from foo; - TimesNet ## 算法有效性评估工具 + TDgpt 提供预测分析算法有效性评估工具 `analytics_compare`,调用该工具并设置合适的参数,能够使用 TDengine 中的数据作为回测依据,评估不同预测算法或相同的预测算法在不同的参数或训练模型的下的预测有效性。预测有效性的评估使用 `MSE` 和 `MAE` 指标作为依据,后续还将增加 `MAPE`指标。 ```ini @@ -134,12 +136,13 @@ res_start_time = 1730000000000 gen_figure = true ``` -算法对比分析运行完成以后,生成 fc-results.xlsx 文件,其中包含了调用算法的预测分析误差、执行时间、调用参数等信息。如下图所示: - -预测对比结果 +算法对比分析运行完成以后,生成 fc-results.xlsx 文件,其中包含了调用算法的预测分析误差、执行时间、调用参数等信息,如下表: +| algorithm | params | MSE | elapsed_time(ms.) | +| ----------- | ------------------------------------------------------------------------- | ------- | ----------------- | +| holtwinters | `{"trend":"add", "seasonal":"add"}` | 351.622 | 125.1721 | +| arima | `{"time_step":3600000, "start_p":0, "max_p":10, "start_q":0, "max_q":10}` | 433.709 | 45577.9187 | 如果设置了 `gen_figure` 为 true,分析结果中还会有绘制的分析预测结果图(如下图所示)。 -预测对比结果 - +预测对比结果 diff --git a/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md b/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md index 4802fa2e4f..9b7a5d2834 100644 --- a/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md +++ b/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md @@ -5,7 +5,6 @@ description: 异常检测算法 import ad from '../pic/anomaly-detection.png'; import ad_result from '../pic/ad-result.png'; -import ad_result_figure from '../pic/ad-result-figure.png'; TDengine 中定义了异常(状态)窗口来提供异常检测服务。异常窗口可以视为一种特殊的**事件窗口(Event Window)**,即异常检测算法确定的连续异常时间序列数据所在的时间窗口。与普通事件窗口区别在于——时间窗口的起始时间和结束时间均是分析算法识别确定,不是用户给定的表达式进行判定。因此,在 `WHERE` 子句中使用 `ANOMALY_WINDOW` 关键词即可调用时序数据异常检测服务,同时窗口伪列(`_WSTART`, `_WEND`, `_WDURATION`)也能够像其他时间窗口一样用于描述异常窗口的起始时间(`_WSTART`)、结束时间(`_WEND`)、持续时间(`_WDURATION`)。例如: @@ -40,13 +39,15 @@ algo=expr1 4. 输入数据默认进行白噪声检查,如果输入数据是白噪声,将不会有任何(异常)窗口信息返回。 ### 参数说明 -|参数|含义|默认值| -|---|---|---| -|algo|异常检测调用的算法|iqr| -|wncheck|对输入数据列是否进行白噪声检查,取值为0或1|1| + +| 参数 | 含义 | 默认值 | +| ------- | ------------------------------------------ | ------ | +| algo | 异常检测调用的算法 | iqr | +| wncheck | 对输入数据列是否进行白噪声检查,取值为0或1 | 1 | ### 示例 + ```SQL --- 使用 iqr 算法进行异常检测,检测列 i32 列。 SELECT _wstart, _wend, SUM(i32) @@ -65,11 +66,12 @@ taos> SELECT _wstart, _wend, count(*) FROM foo ANOMAYL_WINDOW(i32); Query OK, 1 row(s) in set (0.028946s) ``` - ### 内置异常检测算法 + 分析平台内置了6个异常检查模型,分为3个类别,分别是[基于统计学的算法](./02-statistics-approach.md)、[基于数据密度的算法](./03-data-density.md)、以及[基于机器学习的算法](./04-machine-learning.md)。在不指定异常检测使用的方法的情况下,默认调用 IQR 进行异常检测。 ### 异常检测算法有效性比较工具 + TDgpt 提供自动化的工具对比不同数据集的不同算法监测有效性,针对异常检测算法提供查全率(recall)和查准率(precision)两个指标衡量不同算法的有效性。 通过在配置文件中(analysis.ini)设置以下的选项可以调用需要使用的异常检测算法,异常检测算法测试用数据的时间范围、是否生成标注结果的图片、调用的异常检测算法以及相应的参数。 调用异常检测算法比较之前,需要人工手动标注异常监测数据集的结果,即设置[anno_res]选项的数值,第几个数值是异常点,需要标注在数组中,如下测试集中,第 9 个点是异常点,我们就标注异常结果为 [9]. @@ -93,14 +95,18 @@ anno_res = [9] ksigma={"k": 2} iqr={} grubbs={} -lof={"algo":"auto", "n_neighbor": 3} +lof={"algorithm":"auto", "n_neighbor": 3} ``` 对比程序执行完成以后,会自动生成名称为`ad_result.xlsx` 的文件,第一个卡片是算法运行结果(如下图所示),分别包含了算法名称、执行调用参数、查全率、查准率、执行时间 5 个指标。 -异常检测对比结果 +| algorithm | params | precision(%) | recall(%) | elapsed_time(ms.) | +| --------- | -------------------------------------- | ------------ | --------- | ----------------- | +| ksigma | `{"k":2}` | 100 | 100 | 0.453 | +| iqr | `{}` | 100 | 100 | 2.727 | +| grubbs | `{}` | 100 | 100 | 2.811 | +| lof | `{"algorithm":"auto", "n_neighbor":3}` | 0 | 0 | 4.660 | 如果设置了 `gen_figure` 为 `true`,比较程序会自动将每个参与比较的算法分析结果采用图片方式呈现出来(如下图所示为 ksigma 的异常检测结果标注)。 -异常检测标注图 - +异常检测标注图 diff --git a/docs/zh/06-advanced/06-TDgpt/pic/ad-result-figure.png b/docs/zh/06-advanced/06-TDgpt/pic/ad-result-figure.png deleted file mode 100644 index b1bf23178639f91b56ec1db66e5d0a63aba81cb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42407 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 diff --git a/docs/zh/06-advanced/06-TDgpt/pic/ad-result.png b/docs/zh/06-advanced/06-TDgpt/pic/ad-result.png old mode 100644 new mode 100755 index 80667c5733336d2f666c2160a36fbd77402bac26..40b9bb44350789d9a8e8f279431907413c373bcb GIT binary patch literal 26716 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 QDz-%~&hCe+4hE(E7oM;|G5`Po literal 20151 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 Q-8Q#W!J3NI@~?ycA9RTndH?_b From ab428f860f2854a683950f82ef5d719a9add04a2 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 22 Mar 2025 22:36:25 +0800 Subject: [PATCH 24/28] doc: update docs. (#30347) * Update 09-error-code.md * Update 03-preprocess.md * Update index.md * Update index.md * Update index.md * doc: update docs. * Update index.md * Update index.md * Update index.md --- docs/zh/06-advanced/06-TDgpt/04-forecast/index.md | 3 +-- docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md index e0f6f238cf..9c9468c9f0 100644 --- a/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md +++ b/docs/zh/06-advanced/06-TDgpt/04-forecast/index.md @@ -136,8 +136,6 @@ res_start_time = 1730000000000 gen_figure = true ``` -算法对比分析运行完成以后,生成 fc-results.xlsx 文件,其中包含了调用算法的预测分析误差、执行时间、调用参数等信息,如下表: - | algorithm | params | MSE | elapsed_time(ms.) | | ----------- | ------------------------------------------------------------------------- | ------- | ----------------- | | holtwinters | `{"trend":"add", "seasonal":"add"}` | 351.622 | 125.1721 | @@ -146,3 +144,4 @@ gen_figure = true 如果设置了 `gen_figure` 为 true,分析结果中还会有绘制的分析预测结果图(如下图所示)。 预测对比结果 + diff --git a/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md b/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md index 9b7a5d2834..9ca0204b42 100644 --- a/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md +++ b/docs/zh/06-advanced/06-TDgpt/05-anomaly-detection/index.md @@ -100,6 +100,7 @@ lof={"algorithm":"auto", "n_neighbor": 3} 对比程序执行完成以后,会自动生成名称为`ad_result.xlsx` 的文件,第一个卡片是算法运行结果(如下图所示),分别包含了算法名称、执行调用参数、查全率、查准率、执行时间 5 个指标。 + | algorithm | params | precision(%) | recall(%) | elapsed_time(ms.) | | --------- | -------------------------------------- | ------------ | --------- | ----------------- | | ksigma | `{"k":2}` | 100 | 100 | 0.453 | @@ -107,6 +108,8 @@ lof={"algorithm":"auto", "n_neighbor": 3} | grubbs | `{}` | 100 | 100 | 2.811 | | lof | `{"algorithm":"auto", "n_neighbor":3}` | 0 | 0 | 4.660 | + 如果设置了 `gen_figure` 为 `true`,比较程序会自动将每个参与比较的算法分析结果采用图片方式呈现出来(如下图所示为 ksigma 的异常检测结果标注)。 异常检测标注图 + From adc892dea601883cc712261cb8622c9a860b6db0 Mon Sep 17 00:00:00 2001 From: Simon Guan Date: Sat, 22 Mar 2025 23:17:13 +0800 Subject: [PATCH 25/28] docs: minor changes for virtual table (#30358) --- docs/zh/05-basic/01-model.md | 71 +++++++++---------- .../03-taos-sql/34-virtualtable.md | 14 ++-- 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/docs/zh/05-basic/01-model.md b/docs/zh/05-basic/01-model.md index 0f01fbf562..15f192b3bc 100644 --- a/docs/zh/05-basic/01-model.md +++ b/docs/zh/05-basic/01-model.md @@ -79,9 +79,9 @@ toc_max_heading_level: 4 ### 虚拟表 -“一个设备一张表”的设计解决了工业和物联网等场景下的大多数时序数据管理和分析难题,但是在遇到更复杂的场景时,这种设计受到了设备复杂性的挑战。这种复杂性的根源在于一个设备无法简单的用一个或一组数据采集点来描述或管理,而业务分析往往需要综合多个或多组采集点的数据才能完成。以汽车或发电风机为例,整个设备(汽车或风机)中含有非常大量的传感器(数据采集点),这些传感器的输出和采集频率千差万别。一个超级表只能描述其中一种传感器,当需要综合多个传感器的数据进行分析计算时,只能通过多级关联查询的方式来进行,而这往往会导致易用性和性能方面的问题。 +“一个设备一张表”的设计解决了工业和物联网等场景下的大多数时序数据管理和分析难题,但是在遇到更复杂的场景时,这种设计受到了设备复杂性的挑战。根源在于一个设备无法简单的用一个或一组数据采集点来描述或管理,而业务分析往往需要综合多个或多组采集点的数据才能完成。以汽车或发电风机为例,整个设备(汽车或风机)中含有非常大量的传感器(数据采集点),这些传感器的输出和采集频率千差万别。一个超级表只能描述其中一种传感器,当需要综合多个传感器的数据进行分析计算时,只能通过多级关联查询的方式来进行,而这往往会导致易用性和性能方面的问题。 -为了解决这个问题,TDengine 引入虚拟表(Virtual Table,简称为 VTable)的概念。虚拟表是一种不存储实际数据而可以用于分析计算的表,它的数据来源为其它真实存储数据的子表、普通表,通过将不同列数据按照时间戳排序、对齐、合并的方式来生成虚拟表。同真实表类似,虚拟表也可以分为虚拟超级表、虚拟子表、虚拟普通表。虚拟超级表可以是一个设备或一组分析计算所需数据的完整集合,每个虚拟子表可以根据需要引用相同或不同的列,因此可以灵活地根据业务需要进行定义,最终可以达到千表千面的效果。虚拟表不能写入、删除数据,在查询使用上同真实表基本相同,支持虚拟超级表、虚拟子表、虚拟普通表上的任何查询。唯一的区别在于虚拟表的数据是每次查询计算时动态生成的,只有一个查询中引用的列才会被合并进虚拟表中,因此同一个虚拟表在不同的查询中所呈现的数据可能是不同的。 +为了解决这个问题,TDengine 引入虚拟表(Virtual Table,简称为 VTable)的概念。虚拟表是一种不存储实际数据而可以用于分析计算的表,它的数据来源为其它真实存储数据的子表、普通表,通过将不同列数据按照时间戳排序、对齐、合并的方式来生成虚拟表。同真实表类似,虚拟表也可以分为虚拟超级表、虚拟子表、虚拟普通表。虚拟超级表可以是一个设备或一组分析计算所需数据的完整集合,每个虚拟子表可以根据需要引用相同或不同的列,因此可以灵活地根据业务需要进行定义,最终达到千表千面的效果。虚拟表不能写入、删除数据,在查询使用上同真实表基本相同,支持虚拟超级表、虚拟子表、虚拟普通表上的任何查询。唯一的区别在于虚拟表的数据是每次查询计算时动态生成的,只有一个查询中引用的列才会被合并进虚拟表中,因此同一个虚拟表在不同的查询中所呈现的数据可能是不同的。 虚拟超级表的主要功能特点包括: 1. 列选择与拼接
@@ -91,7 +91,7 @@ toc_max_heading_level: 4 3. 动态更新
虚拟表根据原始表的数据变化自动更新,确保数据的实时性。虚拟表不需实际存储,计算在生成时动态完成。 -通过引入虚拟表的概念,现在 TDengine 可以非常方便的管理更大更复杂的设备数据。无论每个采集点如何建模(单列 or 多列),无论这些采集点的数据是分布在一个或多个库中,我们现在都可以通过定义虚拟子表的方式跨库跨表任意指定数据源,通过虚拟超级表的方式进行跨设备、跨分析的聚合运算,从此“一个设备一张表”彻底成为现实。 +通过引入虚拟表的概念,TDengine 可以非常方便的管理更大更复杂的设备数据。无论每个采集点如何建模(单列 or 多列),无论这些采集点的数据是分布在一个或多个库中,都可以通过定义虚拟子表的方式跨库跨表任意指定数据源,通过虚拟超级表的方式进行跨设备、跨分析的聚合运算,从此“一个设备一张表”彻底成为现实。 ### 库 @@ -101,7 +101,7 @@ toc_max_heading_level: 4 ### 时间戳 -时间戳在时序数据处理中扮演着至关重要的角色,特别是在应用程序需要从多个不同时区访问数据库时,这一问题变得更加复杂。在深入了解 TDengine 如何处理时间戳与时区之前,我们先介绍以下几个基本概念。 +时间戳在时序数据处理中扮演着至关重要的角色,特别是在应用程序需要从多个不同时区访问数据库时,这一问题变得更加复杂。在深入了解 TDengine 如何处理时间戳与时区之前,先介绍以下几个基本概念。 - 本地日期时间:指特定地区的当地时间,通常表示为 yyyy-MM-dd hh:mm:ss.SSS 格式的字符串。这种时间表示不包含任何时区信息,如 “2021-07-21 12:00:00.000”。 - 时区:地球上不同地理位置的标准时间。协调世界时(Universal Time Coordinated,UTC)或格林尼治时间是国际时间标准,其他时区通常表示为相对于 UTC 的偏移量,如 “UTC+8” 代表东八区时间。 UTC 时间戳:表示自 UNIX 纪元(即 UTC 时间 1970 年 1 月 1 日 0 点)起经过的毫秒数。例如,“1700000000000” 对应的日期时间是 “2023-11-14 22:13:20(UTC+0)”。 在 TDengine 中保存时序数据时,实际上保存的是 UTC 时间戳。TDengine 在写入数据时,时间戳的处理分为如下两种情况。 - RFC-3339 格式:当使用这种格式时,TDengine 能够正确解析带有时区信息的时间字符串为 UTC 时间戳。例如,“2018-10-03T14:38:05.000+08:00” 会被转换为 UTC 时间戳。 @@ -109,10 +109,9 @@ toc_max_heading_level: 4 在查询数据时,TDengine 客户端会根据应用程序当前的时区设置,自动将保存的 UTC 时间戳转换成本地时间进行显示,确保用户在不同时区下都能看到正确的时间信息。 - ## 数据建模 -本节用智能电表做例子,简要的介绍如何在 TDengine 里使用 SQL 创建数据库、超级表、表的基本操作。 +本节以智能电表为例,介绍如何在 TDengine 里使用 SQL 创建数据库、超级表、表的基本操作。 ### 创建数据库 @@ -276,7 +275,7 @@ CREATE STABLE phase_stb ( ); ``` -假设分别有 d1001,d1002,d1003,d1004 四个设备,分别对四个设备的电流、电压、相位采集量创建子表,SQL 如下: +假设有 d1001、d1002、d1003、d1004 四个设备,为四个设备的电流、电压、相位采集量分别创建子表,SQL 如下: ```sql create table current_d1001 using current_stb(deviceid, location, group_id) tags("d1001", "California.SanFrancisco", 2); @@ -295,7 +294,7 @@ create table phase_d1003 using phase_stb(deviceid, location, group_id) tags("d10 create table phase_d1004 using phase_stb(deviceid, location, group_id) tags("d1004", "California.LosAngeles", 2); ``` -此时想要通过一张虚拟超级表来讲这三种采集量聚合到一张表中,创建虚拟超级表 SQL 如下: +可通过一张虚拟超级表来将这三种采集量聚合到一张表中,创建虚拟超级表 SQL 如下: ```sql CREATE STABLE meters_v ( @@ -309,51 +308,51 @@ CREATE STABLE meters_v ( ) VIRTUAL 1; ``` -并且对四个设备 d1001,d1002,d1003,d1004 分别创建虚拟子表,SQL 如下: +并且对四个设备 d1001、d1002、d1003、d1004 分别创建虚拟子表,SQL 如下: ```sql CREATE VTABLE d1001_v ( - current from current_d1001.current, - voltage from voltage_d1001.voltage, - phase from phase_d1001.phase + current from current_d1001.current, + voltage from voltage_d1001.voltage, + phase from phase_d1001.phase ) USING meters_v TAGS ( - "California.SanFrancisco", - 2 + "California.SanFrancisco", + 2 ); CREATE VTABLE d1002_v ( - current from current_d1002.current, - voltage from voltage_d1002.voltage, - phase from phase_d1002.phase + current from current_d1002.current, + voltage from voltage_d1002.voltage, + phase from phase_d1002.phase ) USING meters_v TAGS ( - "California.SanFrancisco", - 3 + "California.SanFrancisco", + 3 ); CREATE VTABLE d1003_v ( - current from current_d1003.current, - voltage from voltage_d1003.voltage, - phase from phase_d1003.phase + current from current_d1003.current, + voltage from voltage_d1003.voltage, + phase from phase_d1003.phase ) USING meters_v TAGS ( - "California.LosAngeles", - 3 + "California.LosAngeles", + 3 ); CREATE VTABLE d1004_v ( - current from current_d1004.current, - voltage from voltage_d1004.voltage, - phase from phase_d1004.phase + current from current_d1004.current, + voltage from voltage_d1004.voltage, + phase from phase_d1004.phase ) USING meters_v TAGS ( - "California.LosAngeles", - 2 + "California.LosAngeles", + 2 ); ``` @@ -361,7 +360,7 @@ TAGS ( ![data-model-origin-table.png](data-model-origin-table.png) -虚拟表 d1001_v 中的数据如下 : +虚拟表 d1001_v 中的数据如下: | Timestamp | Current | Voltage | Phase | |:--------------:|:-------:|:---------:|:-------:| @@ -378,15 +377,15 @@ TAGS ( 在跨源采集量对比分析中,“跨源”指数据来自**不同数据采集点**。在不同数据采集点中提取具有可比语义的采集量,通过虚拟表将这些采集量按照时间戳进行对齐和合并,并进行对比分析。 例如,用户可以将来自不同设备的电流数据聚合到一张虚拟表中,以便进行电流数据的对比分析。 -以分析 d1001, d1002, d1003, d1004 四个设备的电流数据为例,创建虚拟表的 SQL 如下: +以分析 d1001、d1002、d1003、d1004 四个设备的电流数据为例,创建虚拟表的 SQL 如下: ```sql CREATE VTABLE current_v ( - ts timestamp, - d1001_current float from current_d1001.current, - d1002_current float from current_d1002.current, - d1003_current float from current_d1003.current, - d1004_current float from current_d1004.current + ts timestamp, + d1001_current float from current_d1001.current, + d1002_current float from current_d1002.current, + d1003_current float from current_d1003.current, + d1004_current float from current_d1004.current ); ``` diff --git a/docs/zh/14-reference/03-taos-sql/34-virtualtable.md b/docs/zh/14-reference/03-taos-sql/34-virtualtable.md index a243169a0a..976e48acbd 100644 --- a/docs/zh/14-reference/03-taos-sql/34-virtualtable.md +++ b/docs/zh/14-reference/03-taos-sql/34-virtualtable.md @@ -17,10 +17,10 @@ CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name ts_col_name timestamp, (create_defination[ ,create_defination] ...) - create_definition: + create_definition: vtb_col_name column_definition -column_definition: + column_definition: type_name [FROM [db_name.]table_name.col_name] ``` @@ -33,9 +33,9 @@ CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name [(tag_name [, tag_name] ...)] TAGS (tag_value [, tag_value] ...) - create_definition: + create_definition: [stb_col_name FROM] [db_name.]table_name.col_name - tag_value: + tag_value: const_value ``` @@ -66,7 +66,7 @@ CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name **示例** -假设有表 t1, t2, t3 结构和数据如下: +假设有表 t1、t2、t3 结构和数据如下: ![virtual-table-origin-table.png](pic/virtual-table-origin-table.png) @@ -101,7 +101,7 @@ select c1, c2 from v1; ![virtual-table-query-res-part.png](pic/virtual-table-query-res-part.png) -因为 c1, c2 列对应的原始表 t1, t2 中没有 0:00:03 这个时间戳,所以最后的结果也不会包含这个时间戳。 +因为 c1、c2 列对应的原始表 t1、t2 中没有 0:00:03 这个时间戳,所以最后的结果也不会包含这个时间戳。 **使用限制** @@ -205,7 +205,7 @@ SHOW [NORMAL | CHILD] [db_name.]VTABLES [LIKE 'pattern']; **使用说明** -1. 如果没有指定 db_name, 显示当前数据库下的所有虚拟普通表和虚拟子表的信息。若没有使用数据库并且没有指定 db_name, 则会报错 database not specified。可以使用 LIKE 对表名进行模糊匹配。NORMAL 指定只显示虚拟普通表信息, CHILD 指定只显示虚拟子表信息。 +1. 如果没有指定 db_name,显示当前数据库下的所有虚拟普通表和虚拟子表的信息。若没有使用数据库并且没有指定 db_name, 则会报错 database not specified。可以使用 LIKE 对表名进行模糊匹配。NORMAL 指定只显示虚拟普通表信息, CHILD 指定只显示虚拟子表信息。 ### 显示虚拟表创建语句 From 9723fd9182f7bb9dbda52eafd1af8d272f888b67 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Sat, 22 Mar 2025 23:23:14 +0800 Subject: [PATCH 26/28] fix: send uninitialized memory (#30328) --- source/dnode/vnode/src/meta/metaTable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 9ae5a11f26..f3ac385b3c 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -153,7 +153,7 @@ int metaUpdateMetaRsp(tb_uid_t uid, char *tbName, SSchemaWrapper *pSchema, STabl return terrno; } - pMetaRsp->pSchemaExt = taosMemoryMalloc(pSchema->nCols * sizeof(SSchemaExt)); + pMetaRsp->pSchemaExt = taosMemoryCalloc(1, pSchema->nCols * sizeof(SSchemaExt)); if (pMetaRsp->pSchemaExt == NULL) { taosMemoryFree(pMetaRsp->pSchemas); return terrno; From 685fa2c42d31a3f517140fc6bff45e899c0eab12 Mon Sep 17 00:00:00 2001 From: Linhe Huo Date: Sat, 22 Mar 2025 23:45:24 +0800 Subject: [PATCH 27/28] fix: windows ci error in 3.0 [ci skip] (#30357) --- source/client/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client/test/CMakeLists.txt b/source/client/test/CMakeLists.txt index 161deb12cd..0bbe5cb53f 100644 --- a/source/client/test/CMakeLists.txt +++ b/source/client/test/CMakeLists.txt @@ -38,7 +38,7 @@ TARGET_LINK_LIBRARIES( ADD_EXECUTABLE(userOperTest ../../../tests/script/api/passwdTest.c) TARGET_LINK_LIBRARIES( userOperTest - PUBLIC ${TAOS_NATIVE_LIB} + PUBLIC ${TAOS_NATIVE_LIB_STATIC} ) ADD_EXECUTABLE(stmt2Test stmt2Test.cpp) From 8ad8bc741a935f22dc4a6917bd3251ec25fa55e2 Mon Sep 17 00:00:00 2001 From: Linhe Huo Date: Sun, 23 Mar 2025 00:46:55 +0800 Subject: [PATCH 28/28] fix: userOperTest in linux (#30363) Co-authored-by: taos-support --- source/client/test/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/client/test/CMakeLists.txt b/source/client/test/CMakeLists.txt index 0bbe5cb53f..870d979eca 100644 --- a/source/client/test/CMakeLists.txt +++ b/source/client/test/CMakeLists.txt @@ -36,10 +36,17 @@ TARGET_LINK_LIBRARIES( #) ADD_EXECUTABLE(userOperTest ../../../tests/script/api/passwdTest.c) +if (TD_WINDOWS) TARGET_LINK_LIBRARIES( userOperTest PUBLIC ${TAOS_NATIVE_LIB_STATIC} ) +else() +TARGET_LINK_LIBRARIES( + userOperTest + PUBLIC ${TAOS_NATIVE_LIB} +) +endif() ADD_EXECUTABLE(stmt2Test stmt2Test.cpp) TARGET_LINK_LIBRARIES(