diff --git a/.travis.yml b/.travis.yml index d814a465e6..0617d75976 100644 --- a/.travis.yml +++ b/.travis.yml @@ -171,6 +171,8 @@ matrix: - build-essential - cmake - binutils-2.26 + - unixodbc + - unixodbc-dev env: - DESC="trusty/gcc-4.8/bintuils-2.26 build" @@ -198,6 +200,8 @@ matrix: packages: - build-essential - cmake + - unixodbc + - unixodbc-dev before_script: - export TZ=Asia/Harbin @@ -252,6 +256,8 @@ matrix: packages: - build-essential - cmake + - unixodbc + - unixodbc-dev env: - DESC="arm64 xenial build" @@ -280,6 +286,7 @@ matrix: addons: homebrew: - cmake + - unixodbc script: - cd ${TRAVIS_BUILD_DIR} diff --git a/CMakeLists.txt b/CMakeLists.txt index be97e679d1..e0d6e82923 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ SET(TD_MQTT FALSE) SET(TD_TSDB_PLUGINS FALSE) SET(TD_STORAGE FALSE) SET(TD_TOPIC FALSE) +SET(TD_MODULE FALSE) SET(TD_COVER FALSE) SET(TD_MEM_CHECK FALSE) diff --git a/Jenkinsfile b/Jenkinsfile index d96eeaa724..433b46067a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,6 +6,7 @@ node { } def skipstage=0 + def abortPreviousBuilds() { def currentJobName = env.JOB_NAME def currentBuildNumber = env.BUILD_NUMBER.toInteger() @@ -24,7 +25,7 @@ def abortPreviousBuilds() { build.doKill() //doTerm(),doKill(),doTerm() } } -//abort previous build +// abort previous build abortPreviousBuilds() def abort_previous(){ def buildNumber = env.BUILD_NUMBER as int @@ -32,19 +33,20 @@ def abort_previous(){ milestone(buildNumber) } def pre_test(){ - + + sh ''' sudo rmtaos || echo "taosd has not installed" ''' sh ''' - + killall -9 taosd ||echo "no taosd running" + killall -9 gdb || echo "no gdb running" cd ${WKC} git checkout develop git reset --hard HEAD~10 >/dev/null git pull >/dev/null git fetch origin +refs/pull/${CHANGE_ID}/merge git checkout -qf FETCH_HEAD - git --no-pager diff --name-only FETCH_HEAD $(git merge-base FETCH_HEAD develop)|grep -v -E '.*md|//src//connector|Jenkinsfile' find ${WKC}/tests/pytest -name \'*\'.sql -exec rm -rf {} \\; cd ${WK} git reset --hard HEAD~10 @@ -79,6 +81,10 @@ pipeline { changeRequest() } steps { + script{ + abort_previous() + abortPreviousBuilds() + } sh''' cp -r ${WORKSPACE} ${WORKSPACE}.tes cd ${WORKSPACE}.tes @@ -179,6 +185,14 @@ pipeline { rm -rf /var/log/taos/* ./handle_crash_gen_val_log.sh ''' + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + rm -rf /var/lib/taos/* + rm -rf /var/log/taos/* + ./handle_taosd_val_log.sh + ''' + } timeout(time: 45, unit: 'MINUTES'){ sh ''' date @@ -209,6 +223,11 @@ pipeline { cd ${WKC}/tests ./test-all.sh b3fq date''' + sh ''' + date + cd ${WKC}/tests + ./test-all.sh full example + date''' } } } @@ -266,7 +285,7 @@ pipeline { date cd ${WKC}/tests ./test-all.sh b7fq - date''' + date''' } } } diff --git a/README-CN.md b/README-CN.md index 9601cde3af..d4c10e71d6 100644 --- a/README-CN.md +++ b/README-CN.md @@ -258,10 +258,16 @@ TDengine 社区生态中也有一些非常友好的第三方连接器,可以 TDengine 的测试框架和所有测试例全部开源。 -点击[这里](tests/How-To-Run-Test-And-How-To-Add-New-Test-Case.md),了解如何运行测试例和添加新的测试例。 +点击 [这里](tests/How-To-Run-Test-And-How-To-Add-New-Test-Case.md),了解如何运行测试例和添加新的测试例。 # 成为社区贡献者 -点击[这里](https://www.taosdata.com/cn/contributor/),了解如何成为 TDengine 的贡献者。 -#加入技术交流群 -TDengine官方社群「物联网大数据群」对外开放,欢迎您加入讨论。搜索微信号 "tdengine",加小T为好友,即可入群。 +点击 [这里](https://www.taosdata.com/cn/contributor/),了解如何成为 TDengine 的贡献者。 + +# 加入技术交流群 + +TDengine 官方社群「物联网大数据群」对外开放,欢迎您加入讨论。搜索微信号 "tdengine",加小T为好友,即可入群。 + +# [谁在使用TDengine](https://github.com/taosdata/TDengine/issues/2432) + +欢迎所有 TDengine 用户及贡献者在 [这里](https://github.com/taosdata/TDengine/issues/2432) 分享您在当前工作中开发/使用 TDengine 的故事。 diff --git a/README.md b/README.md index 0749f3982e..45a955f458 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ For user manual, system design and architecture, engineering blogs, refer to [TD # Building At the moment, TDengine only supports building and running on Linux systems. You can choose to [install from packages](https://www.taosdata.com/en/getting-started/#Install-from-Package) or from the source code. This quick guide is for installation from the source only. -To build TDengine, use [CMake](https://cmake.org/) 3.5 or higher versions in the project directory. +To build TDengine, use [CMake](https://cmake.org/) 2.8.12.x or higher versions in the project directory. ## Install tools @@ -250,3 +250,6 @@ Please follow the [contribution guidelines](CONTRIBUTING.md) to contribute to th Add WeChat “tdengine” to join the group,you can communicate with other users. +# [User List](https://github.com/taosdata/TDengine/issues/2432) + +If you are using TDengine and feel it helps or you'd like to do some contributions, please add your company to [user list](https://github.com/taosdata/TDengine/issues/2432) and let us know your needs. diff --git a/cmake/define.inc b/cmake/define.inc index ff4583d02b..6f49630d5c 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -29,6 +29,10 @@ IF (TD_TOPIC) ADD_DEFINITIONS(-D_TOPIC) ENDIF () +IF (TD_MODULE) + ADD_DEFINITIONS(-D_MODULE) +ENDIF () + IF (TD_GODLL) ADD_DEFINITIONS(-D_TD_GO_DLL_) ENDIF () diff --git a/cmake/input.inc b/cmake/input.inc index b1a993c996..00e0e1bc0f 100755 --- a/cmake/input.inc +++ b/cmake/input.inc @@ -17,6 +17,14 @@ ELSEIF (${TOPIC} MATCHES "false") MESSAGE(STATUS "Build without topic plugins") ENDIF () +IF (${TD_MODULE} MATCHES "true") + SET(TD_MODULE TRUE) + MESSAGE(STATUS "Build with module plugins") +ELSEIF (${TOPIC} MATCHES "false") + SET(TD_MODULE FALSE) + MESSAGE(STATUS "Build without module plugins") +ENDIF () + IF (${COVER} MATCHES "true") SET(TD_COVER TRUE) MESSAGE(STATUS "Build with test coverage") diff --git a/cmake/install.inc b/cmake/install.inc index 1d50ca292d..01d3c8a4df 100755 --- a/cmake/install.inc +++ b/cmake/install.inc @@ -32,7 +32,7 @@ ELSEIF (TD_WINDOWS) #INSTALL(TARGETS taos RUNTIME DESTINATION driver) #INSTALL(TARGETS shell RUNTIME DESTINATION .) IF (TD_MVN_INSTALLED) - INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.22-dist.jar DESTINATION connector/jdbc) + INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.24-dist.jar DESTINATION connector/jdbc) ENDIF () ELSEIF (TD_DARWIN) SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh") diff --git a/documentation20/cn/00.index/docs.md b/documentation20/cn/00.index/docs.md index c16673cba5..aba10a14e3 100644 --- a/documentation20/cn/00.index/docs.md +++ b/documentation20/cn/00.index/docs.md @@ -120,7 +120,7 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台,专 * [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html) * [IDEA数据库管理工具可视化使用TDengine](https://www.taosdata.com/blog/2020/08/27/1767.html) * [基于eletron开发的跨平台TDengine图形化管理工具](https://github.com/skye0207/TDengineGUI) -* [DataX,支持TDengine的离线数据采集/同步工具](https://github.com/alibaba/DataX) +* [DataX,支持TDengine的离线数据采集/同步工具](https://github.com/wgzhao/DataX)(文档:[读取插件](https://github.com/wgzhao/DataX/blob/master/docs/src/main/sphinx/reader/tdenginereader.md)、[写入插件](https://github.com/wgzhao/DataX/blob/master/docs/src/main/sphinx/writer/tdenginewriter.md)) ## TDengine与其他数据库的对比测试 diff --git a/documentation20/cn/02.getting-started/docs.md b/documentation20/cn/02.getting-started/docs.md index c9c82942f3..f86e616c42 100644 --- a/documentation20/cn/02.getting-started/docs.md +++ b/documentation20/cn/02.getting-started/docs.md @@ -179,18 +179,18 @@ taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s); ### TDengine服务器支持的平台列表 -| | **CentOS** **6/7/8** | **Ubuntu** **16/18/20** | **Other Linux** | **统信****UOS** | **银河****/****中标麒麟** | **凝思** **V60/V80** | +| | **CentOS 6/7/8** | **Ubuntu 16/18/20** | **Other Linux** | **统信 UOS** | **银河/中标麒麟** | **凝思 V60/V80** | | -------------- | --------------------- | ------------------------ | --------------- | --------------- | ------------------------- | --------------------- | | X64 | ● | ● | | ○ | ● | ● | -| 树莓派ARM32 | | ● | ● | | | | -| 龙芯MIPS64 | | | ● | | | | -| 鲲鹏 ARM64 | | ○ | ○ | | ● | | -| 申威 Alpha64 | | | ○ | ● | | | -| 飞腾ARM64 | | ○优麒麟 | | | | | -| 海光X64 | ● | ● | ● | ○ | ● | ● | -| 瑞芯微ARM64/32 | | | ○ | | | | -| 全志ARM64/32 | | | ○ | | | | -| 炬力ARM64/32 | | | ○ | | | | +| 树莓派 ARM32 | | ● | ● | | | | +| 龙芯 MIPS64 | | | ● | | | | +| 鲲鹏 ARM64 | | ○ | ○ | | ● | | +| 申威 Alpha64 | | | ○ | ● | | | +| 飞腾 ARM64 | | ○ 优麒麟 | | | | | +| 海光 X64 | ● | ● | ● | ○ | ● | ● | +| 瑞芯微 ARM64/32 | | | ○ | | | | +| 全志 ARM64/32 | | | ○ | | | | +| 炬力 ARM64/32 | | | ○ | | | | | TI ARM32 | | | ○ | | | | 注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。 @@ -203,7 +203,7 @@ taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s); 对照矩阵如下: -| **CPU** | **X64 64bit** | | | **X86 32bit** | **ARM64** | **ARM32** | **MIPS ** **龙芯** | **Alpha ** **申威** | **X64 ** **海光** | +| **CPU** | **X64 64bit** | | | **X86 32bit** | **ARM64** | **ARM32** | **MIPS 龙芯** | **Alpha 申威** | **X64 海光** | | ----------- | --------------- | --------- | --------- | --------------- | --------- | --------- | ------------------- | -------------------- | ------------------ | | **OS** | **Linux** | **Win64** | **Win32** | **Win32** | **Linux** | **Linux** | **Linux** | **Linux** | **Linux** | | **C/C++** | ● | ● | ● | ○ | ● | ● | ● | ● | ● | diff --git a/documentation20/cn/08.connector/01.java/docs.md b/documentation20/cn/08.connector/01.java/docs.md index c39f6ffb4c..30b485f9b6 100644 --- a/documentation20/cn/08.connector/01.java/docs.md +++ b/documentation20/cn/08.connector/01.java/docs.md @@ -451,7 +451,8 @@ Query OK, 1 row(s) in set (0.000141s) | taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 | | -------------------- | ----------------- | -------- | -| 2.0.12 及以上 | 2.0.8.0 及以上 | 1.8.x | +| 2.0.22 | 2.0.18.0 及以上 | 1.8.x | +| 2.0.12 - 2.0.21 | 2.0.8.0 - 2.0.17.0 | 1.8.x | | 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x | | 1.0.3 | 1.6.1.x 及以上 | 1.8.x | | 1.0.2 | 1.6.1.x 及以上 | 1.8.x | @@ -470,9 +471,11 @@ TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对 | BIGINT | java.lang.Long | | FLOAT | java.lang.Float | | DOUBLE | java.lang.Double | -| SMALLINT, TINYINT | java.lang.Short | +| SMALLINT | java.lang.Short | +| TINYINT | java.lang.Byte | | BOOL | java.lang.Boolean | -| BINARY, NCHAR | java.lang.String | +| BINARY | byte array | +| NCHAR | java.lang.String | diff --git a/documentation20/cn/10.cluster/docs.md b/documentation20/cn/10.cluster/docs.md index 7b4073a883..a430ce8277 100644 --- a/documentation20/cn/10.cluster/docs.md +++ b/documentation20/cn/10.cluster/docs.md @@ -111,9 +111,10 @@ taos> **提示:** -- 任何已经加入集群在线的数据节点,都可以作为后续待加入节点的firstEP。 -- firstEp这个参数仅仅在该数据节点首次加入集群时有作用,加入集群后,该数据节点会保存最新的mnode的End Point列表,不再依赖这个参数。 -- 两个没有配置firstEp参数的数据节点dnode启动后,会独立运行起来。这个时候,无法将其中一个数据节点加入到另外一个数据节点,形成集群。**无法将两个独立的集群合并成为新的集群**。 +- 任何已经加入集群在线的数据节点,都可以作为后续待加入节点的 firstEP。 +- firstEp 这个参数仅仅在该数据节点首次加入集群时有作用,加入集群后,该数据节点会保存最新的 mnode 的 End Point 列表,不再依赖这个参数。 + - 接下来,配置文件中的 firstEp 参数就主要在客户端连接的时候使用了,例如 taos shell 如果不加参数,会默认连接由 firstEp 指定的节点。 +- 两个没有配置 firstEp 参数的数据节点 dnode 启动后,会独立运行起来。这个时候,无法将其中一个数据节点加入到另外一个数据节点,形成集群。**无法将两个独立的集群合并成为新的集群**。 ## 数据节点管理 diff --git a/documentation20/cn/11.administrator/docs.md b/documentation20/cn/11.administrator/docs.md index 027828d903..c2c2927387 100644 --- a/documentation20/cn/11.administrator/docs.md +++ b/documentation20/cn/11.administrator/docs.md @@ -6,19 +6,27 @@ ### 内存需求 -每个 DB 可以创建固定数目的 vgroup,默认与 CPU 核数相同,可通过 maxVgroupsPerDb 配置;vgroup 中的每个副本会是一个 vnode;每个 vnode 会占用固定大小的内存(大小与数据库的配置参数 blocks 和 cache 有关);每个 Table 会占用与标签总长度有关的内存;此外,系统会有一些固定的内存开销。因此,每个 DB 需要的系统内存可通过如下公式计算: +每个 Database 可以创建固定数目的 vgroup,默认与 CPU 核数相同,可通过 maxVgroupsPerDb 配置;vgroup 中的每个副本会是一个 vnode;每个 vnode 会占用固定大小的内存(大小与数据库的配置参数 blocks 和 cache 有关);每个 Table 会占用与标签总长度有关的内存;此外,系统会有一些固定的内存开销。因此,每个 DB 需要的系统内存可通过如下公式计算: ``` -Memory Size = maxVgroupsPerDb * (blocks * cache + 10MB) + numOfTables * (tagSizePerTable + 0.5KB) +Database Memory Size = maxVgroupsPerDb * (blocks * cache + 10MB) + numOfTables * (tagSizePerTable + 0.5KB) ``` -示例:假设是 4 核机器,cache 是缺省大小 16M, blocks 是缺省值 6,假设有 10 万张表,标签总长度是 256 字节,则总的内存需求为:4 \* (16 \* 6 + 10) + 100000 \* (0.25 + 0.5) / 1000 = 499M。 +示例:假设是 4 核机器,cache 是缺省大小 16M, blocks 是缺省值 6,并且一个 DB 中有 10 万张表,标签总长度是 256 字节,则这个 DB 总的内存需求为:4 \* (16 \* 6 + 10) + 100000 \* (0.25 + 0.5) / 1000 = 499M。 -注意:从这个公式计算得到的内存容量,应理解为系统的“必要需求”,而不是“内存总数”。在实际运行的生产系统中,由于操作系统缓存、资源管理调度等方面的需要,内存规划应当在计算结果的基础上保留一定冗余,以维持系统状态和系统性能的稳定性。 +在实际的系统运维中,我们通常会更关心 TDengine 服务进程(taosd)会占用的内存量。 +``` +taosd 内存总量 = vnode 内存 + mnode 内存 + 查询内存 +``` -实际运行的系统往往会根据数据特点的不同,将数据存放在不同的 DB 里。因此做规划时,也需要考虑。 +其中: +1. “vnode 内存”指的是集群中所有的 Database 存储分摊到当前 taosd 节点上所占用的内存资源。可以按上文“Database Memory Size”计算公式估算每个 DB 的内存占用量进行加总,再按集群中总共的 TDengine 节点数做平均(如果设置为多副本,则还需要乘以对应的副本倍数)。 +2. “mnode 内存”指的是集群中管理节点所占用的资源。如果一个 taosd 节点上分布有 mnode 管理节点,则内存消耗还需要增加“0.2KB * 集群中数据表总数”。 +3. “查询内存”指的是服务端处理查询请求时所需要占用的内存。单条查询语句至少会占用“0.2KB * 查询涉及的数据表总数”的内存量。 -如果内存充裕,可以加大 Blocks 的配置,这样更多数据将保存在内存里,提高查询速度。 +注意:以上内存估算方法,主要讲解了系统的“必须内存需求”,而不是“内存总数上限”。在实际运行的生产环境中,由于操作系统缓存、资源管理调度等方面的原因,内存规划应当在估算结果的基础上保留一定冗余,以维持系统状态和系统性能的稳定性。并且,生产环境通常会配置系统资源的监控工具,以便及时发现硬件资源的紧缺情况。 + +最后,如果内存充裕,可以考虑加大 Blocks 的配置,这样更多数据将保存在内存里,提高查询速度。 ### CPU 需求 diff --git a/documentation20/cn/12.taos-sql/docs.md b/documentation20/cn/12.taos-sql/docs.md index 2248b11987..b4fa2b160a 100644 --- a/documentation20/cn/12.taos-sql/docs.md +++ b/documentation20/cn/12.taos-sql/docs.md @@ -249,7 +249,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic 3) TAGS 列名不能为预留关键字; - 4) TAGS 最多允许128个,至少1个,总长度不超过16k个字符。 + 4) TAGS 最多允许 128 个,至少 1 个,总长度不超过 16 KB。 - **删除超级表** diff --git a/packaging/cfg/taos.cfg b/packaging/cfg/taos.cfg index a1178e2eef..83b70ed9f8 100644 --- a/packaging/cfg/taos.cfg +++ b/packaging/cfg/taos.cfg @@ -29,6 +29,9 @@ # number of threads per CPU core # numOfThreadsPerCore 1.0 +# number of threads to commit cache data +# numOfCommitThreads 4 + # the proportion of total CPU cores available for query processing # 2.0: the query threads will be set to double of the CPU cores. # 1.0: all CPU cores are available for query processing [default]. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0f2cc0a48..8cc5cee3b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,6 @@ ADD_SUBDIRECTORY(tsdb) ADD_SUBDIRECTORY(wal) ADD_SUBDIRECTORY(cq) ADD_SUBDIRECTORY(dnode) -#ADD_SUBDIRECTORY(connector/odbc) +ADD_SUBDIRECTORY(connector/odbc) ADD_SUBDIRECTORY(connector/jdbc) diff --git a/src/client/inc/tscUtil.h b/src/client/inc/tscUtil.h index f69ee23222..3eba5d579b 100644 --- a/src/client/inc/tscUtil.h +++ b/src/client/inc/tscUtil.h @@ -83,6 +83,22 @@ typedef struct SJoinSupporter { SArray* pVgroupTables; } SJoinSupporter; + +typedef struct SMergeCtx { + SJoinSupporter* p; + int32_t idx; + SArray* res; + int8_t compared; +}SMergeCtx; + +typedef struct SMergeTsCtx { + SJoinSupporter* p; + STSBuf* res; + int64_t numOfInput; + int8_t compared; +}SMergeTsCtx; + + typedef struct SVgroupTableInfo { SVgroupInfo vgInfo; SArray* itemList; //SArray @@ -183,6 +199,7 @@ int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deep void tscSqlExprInfoDestroy(SArray* pExprInfo); SColumn* tscColumnClone(const SColumn* src); +bool tscColumnExists(SArray* pColumnList, SColumnIndex* pColIndex); SColumn* tscColumnListInsert(SArray* pColList, SColumnIndex* colIndex); SArray* tscColumnListClone(const SArray* src, int16_t tableIndex); void tscColumnListDestroy(SArray* pColList); diff --git a/src/client/inc/tsclient.h b/src/client/inc/tsclient.h index 1740266518..0e20c66305 100644 --- a/src/client/inc/tsclient.h +++ b/src/client/inc/tsclient.h @@ -142,15 +142,15 @@ typedef struct SCond { } SCond; typedef struct SJoinNode { - char tableName[TSDB_TABLE_FNAME_LEN]; uint64_t uid; int16_t tagColId; + SArray* tsJoin; + SArray* tagJoin; } SJoinNode; typedef struct SJoinInfo { - bool hasJoin; - SJoinNode left; - SJoinNode right; + bool hasJoin; + SJoinNode* joinTables[TSDB_MAX_JOIN_TABLE_NUM]; } SJoinInfo; typedef struct STagCond { @@ -284,7 +284,7 @@ typedef struct { char * pRsp; int32_t rspType; int32_t rspLen; - uint64_t qhandle; + uint64_t qId; int64_t useconds; int64_t offset; // offset value from vnode during projection query of stable int32_t row; @@ -367,7 +367,7 @@ typedef struct SSqlObj { int64_t svgroupRid; int64_t squeryLock; - + int32_t retryReason; // previous error code struct SSqlObj *prev, *next; int64_t self; } SSqlObj; diff --git a/src/client/src/tscAsync.c b/src/client/src/tscAsync.c index 87f6058cec..3249529b34 100644 --- a/src/client/src/tscAsync.c +++ b/src/client/src/tscAsync.c @@ -160,8 +160,8 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - if ((pRes->qhandle == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) { - if (pRes->qhandle == 0 && numOfRows != 0) { + if ((pRes->qId == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) { + if (pRes->qId == 0 && numOfRows != 0) { tscError("qhandle is NULL"); } else { pRes->code = numOfRows; @@ -208,7 +208,7 @@ void taos_fetch_rows_a(TAOS_RES *taosa, __async_cb_func_t fp, void *param) { pSql->fetchFp = fp; pSql->fp = tscAsyncFetchRowsProxy; - if (pRes->qhandle == 0) { + if (pRes->qId == 0) { tscError("qhandle is NULL"); pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE; pSql->param = param; @@ -310,10 +310,51 @@ void tscAsyncResultOnError(SSqlObj* pSql) { taosScheduleTask(tscQhandle, &schedMsg); } - - int tscSendMsgToServer(SSqlObj *pSql); +static int32_t updateMetaBeforeRetryQuery(SSqlObj* pSql, STableMetaInfo* pTableMetaInfo, SQueryInfo* pQueryInfo) { + // handle the invalid table error code for super table. + // update the pExpr info, colList info, number of table columns + // TODO Re-parse this sql and issue the corresponding subquery as an alternative for this case. + if (pSql->retryReason == TSDB_CODE_TDB_INVALID_TABLE_ID) { + int32_t numOfExprs = (int32_t) tscSqlExprNumOfExprs(pQueryInfo); + int32_t numOfCols = tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + int32_t numOfTags = tscGetNumOfTags(pTableMetaInfo->pTableMeta); + + SSchema *pSchema = tscGetTableSchema(pTableMetaInfo->pTableMeta); + for (int32_t i = 0; i < numOfExprs; ++i) { + SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); + pExpr->uid = pTableMetaInfo->pTableMeta->id.uid; + + if (pExpr->colInfo.colIndex >= 0) { + int32_t index = pExpr->colInfo.colIndex; + + if ((TSDB_COL_IS_NORMAL_COL(pExpr->colInfo.flag) && index >= numOfCols) || + (TSDB_COL_IS_TAG(pExpr->colInfo.flag) && (index < numOfCols || index >= (numOfCols + numOfTags)))) { + return pSql->retryReason; + } + + if ((pSchema[pExpr->colInfo.colIndex].colId != pExpr->colInfo.colId) && + strcasecmp(pExpr->colInfo.name, pSchema[pExpr->colInfo.colIndex].name) != 0) { + return pSql->retryReason; + } + } + } + + // validate the table columns information + for (int32_t i = 0; i < taosArrayGetSize(pQueryInfo->colList); ++i) { + SColumn *pCol = taosArrayGetP(pQueryInfo->colList, i); + if (pCol->colIndex.columnIndex >= numOfCols) { + return pSql->retryReason; + } + } + } else { + // do nothing + } + + return TSDB_CODE_SUCCESS; +} + void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) { SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)param); if (pSql == NULL) return; @@ -339,7 +380,8 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) { if (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, (TSDB_QUERY_TYPE_STABLE_SUBQUERY|TSDB_QUERY_TYPE_SUBQUERY|TSDB_QUERY_TYPE_TAG_FILTER_QUERY))) { tscDebug("%p update local table meta, continue to process sql and send the corresponding query", pSql); - STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + code = tscGetTableMeta(pSql, pTableMetaInfo); assert(code == TSDB_CODE_TSC_ACTION_IN_PROGRESS || code == TSDB_CODE_SUCCESS); @@ -349,6 +391,10 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) { } assert((tscGetNumOfTags(pTableMetaInfo->pTableMeta) != 0)); + code = updateMetaBeforeRetryQuery(pSql, pTableMetaInfo, pQueryInfo); + if (code != TSDB_CODE_SUCCESS) { + goto _error; + } // tscProcessSql can add error into async res tscProcessSql(pSql); diff --git a/src/client/src/tscLocal.c b/src/client/src/tscLocal.c index 820572859e..188ba29a97 100644 --- a/src/client/src/tscLocal.c +++ b/src/client/src/tscLocal.c @@ -309,7 +309,7 @@ TAOS_ROW tscFetchRow(void *param) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - if (pRes->qhandle == 0 || + if (pRes->qId == 0 || pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pCmd->command == TSDB_SQL_INSERT) { return NULL; @@ -905,7 +905,7 @@ int tscProcessLocalCmd(SSqlObj *pSql) { * set the qhandle to be 1 in order to pass the qhandle check, and to call partial release function to * free allocated resources and remove the SqlObj from sql query linked list */ - pRes->qhandle = 0x1; + pRes->qId = 0x1; pRes->numOfRows = 0; } else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE) { pRes->code = tscProcessShowCreateTable(pSql); diff --git a/src/client/src/tscLocalMerge.c b/src/client/src/tscLocalMerge.c index a44b0c46ba..8a301d1820 100644 --- a/src/client/src/tscLocalMerge.c +++ b/src/client/src/tscLocalMerge.c @@ -1607,7 +1607,7 @@ void tscInitResObjForLocalQuery(SSqlObj *pObj, int32_t numOfRes, int32_t rowLen) tscDestroyLocalMerger(pObj); } - pRes->qhandle = 1; // hack to pass the safety check in fetch_row function + pRes->qId = 1; // hack to pass the safety check in fetch_row function pRes->numOfRows = 0; pRes->row = 0; diff --git a/src/client/src/tscPrepare.c b/src/client/src/tscPrepare.c index c5f06a52f3..4efaf7c2b5 100644 --- a/src/client/src/tscPrepare.c +++ b/src/client/src/tscPrepare.c @@ -261,7 +261,7 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) { return TSDB_CODE_SUCCESS; } - if (1) { + if (0) { // allow user bind param data with different type union { int8_t v1; @@ -903,7 +903,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) { return TSDB_CODE_TSC_OUT_OF_MEMORY; } - pRes->qhandle = 0; + pRes->qId = 0; pRes->numOfRows = 1; strtolower(pSql->sqlstr, sql); @@ -1057,14 +1057,28 @@ int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) { } if (pStmt->isInsert) { - SSqlObj* pSql = pStmt->pSql; - SSqlCmd *pCmd = &pSql->cmd; - STableDataBlocks* pBlock = taosArrayGetP(pCmd->pDataBlocks, 0); + SSqlCmd* pCmd = &pStmt->pSql->cmd; + STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, 0, 0); + STableMeta* pTableMeta = pTableMetaInfo->pTableMeta; + if (pCmd->pTableBlockHashList == NULL) { + pCmd->pTableBlockHashList = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, false); + } - assert(pCmd->numOfParams == pBlock->numOfParams); - if (idx < 0 || idx >= pBlock->numOfParams) return -1; + STableDataBlocks* pBlock = NULL; - SParamInfo* param = pBlock->params + idx; + int32_t ret = + tscGetDataBlockFromList(pCmd->pTableBlockHashList, pTableMeta->id.uid, TSDB_PAYLOAD_SIZE, sizeof(SSubmitBlk), + pTableMeta->tableInfo.rowSize, &pTableMetaInfo->name, pTableMeta, &pBlock, NULL); + if (ret != 0) { + // todo handle error + } + + if (idx<0 || idx>=pBlock->numOfParams) { + tscError("param %d: out of range", idx); + abort(); + } + + SParamInfo* param = &pBlock->params[idx]; if (type) *type = param->type; if (bytes) *bytes = param->bytes; diff --git a/src/client/src/tscProfile.c b/src/client/src/tscProfile.c index 9203dcfbba..3b0e1b5775 100644 --- a/src/client/src/tscProfile.c +++ b/src/client/src/tscProfile.c @@ -249,8 +249,8 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) { pQdesc->stime = htobe64(pSql->stime); pQdesc->queryId = htonl(pSql->queryId); //pQdesc->useconds = htobe64(pSql->res.useconds); - pQdesc->useconds = htobe64(now - pSql->stime); - pQdesc->qHandle = htobe64(pSql->res.qhandle); + pQdesc->useconds = htobe64(now - pSql->stime); // use local time instead of sever rsp elapsed time + pQdesc->qHandle = htobe64(pSql->res.qId); pHeartbeat->numOfQueries++; pQdesc++; diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 402770391d..b0728aa8aa 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -670,7 +670,18 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { if ((code = setKillInfo(pSql, pInfo, pInfo->type)) != TSDB_CODE_SUCCESS) { return code; } + break; + } + case TSDB_SQL_SYNC_DB_REPLICA: { + const char* msg1 = "invalid db name"; + SStrToken* pzName = taosArrayGet(pInfo->pMiscInfo->a, 0); + + assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1); + code = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pzName); + if (code != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); + } break; } @@ -966,12 +977,18 @@ int32_t parseSlidingClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SStrToken* pSl int32_t tscSetTableFullName(STableMetaInfo* pTableMetaInfo, SStrToken* pTableName, SSqlObj* pSql) { const char* msg1 = "name too long"; const char* msg2 = "acctId too long"; + const char* msg3 = "no acctId"; SSqlCmd* pCmd = &pSql->cmd; int32_t code = TSDB_CODE_SUCCESS; if (hasSpecifyDB(pTableName)) { // db has been specified in sql string so we ignore current db path - code = tNameSetAcctId(&pTableMetaInfo->name, getAccountId(pSql)); + char* acctId = getAccountId(pSql); + if (acctId == NULL || strlen(acctId) <= 0) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); + } + + code = tNameSetAcctId(&pTableMetaInfo->name, acctId); if (code != 0) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); } @@ -3342,24 +3359,26 @@ static int32_t getColumnQueryCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSq } } -static int32_t getJoinCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* pExpr) { - const char* msg1 = "invalid join query condition"; - const char* msg2 = "invalid table name in join query"; +static int32_t checkAndSetJoinCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* pExpr) { + int32_t code = 0; + const char* msg1 = "timestamp required for join tables"; const char* msg3 = "type of join columns must be identical"; const char* msg4 = "invalid column name in join condition"; + const char* msg5 = "only support one join tag for each table"; if (pExpr == NULL) { return TSDB_CODE_SUCCESS; } if (!tSqlExprIsParentOfLeaf(pExpr)) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); + code = checkAndSetJoinCondInfo(pCmd, pQueryInfo, pExpr->pLeft); + if (code) { + return code; + } + + return checkAndSetJoinCondInfo(pCmd, pQueryInfo, pExpr->pRight); } - STagCond* pTagCond = &pQueryInfo->tagCond; - SJoinNode* pLeft = &pTagCond->joinInfo.left; - SJoinNode* pRight = &pTagCond->joinInfo.right; - SColumnIndex index = COLUMN_INDEX_INITIALIZER; if (getColumnIndexByName(pCmd, &pExpr->pLeft->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4); @@ -3368,13 +3387,28 @@ static int32_t getJoinCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex); SSchema* pTagSchema1 = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, index.columnIndex); - pLeft->uid = pTableMetaInfo->pTableMeta->id.uid; - pLeft->tagColId = pTagSchema1->colId; + assert(index.tableIndex >= 0 && index.tableIndex < TSDB_MAX_JOIN_TABLE_NUM); - int32_t code = tNameExtractFullName(&pTableMetaInfo->name, pLeft->tableName); - if (code != TSDB_CODE_SUCCESS) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + SJoinNode **leftNode = &pQueryInfo->tagCond.joinInfo.joinTables[index.tableIndex]; + if (*leftNode == NULL) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); } + + (*leftNode)->uid = pTableMetaInfo->pTableMeta->id.uid; + (*leftNode)->tagColId = pTagSchema1->colId; + + if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { + index.columnIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + if (!tscColumnExists(pTableMetaInfo->tagColList, &index)) { + tscColumnListInsert(pTableMetaInfo->tagColList, &index); + if (taosArrayGetSize(pTableMetaInfo->tagColList) > 1) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg5); + } + } + } + + int16_t leftIdx = index.tableIndex; + index = (SColumnIndex)COLUMN_INDEX_INITIALIZER; if (getColumnIndexByName(pCmd, &pExpr->pRight->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { @@ -3384,20 +3418,55 @@ static int32_t getJoinCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex); SSchema* pTagSchema2 = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, index.columnIndex); - pRight->uid = pTableMetaInfo->pTableMeta->id.uid; - pRight->tagColId = pTagSchema2->colId; + assert(index.tableIndex >= 0 && index.tableIndex < TSDB_MAX_JOIN_TABLE_NUM); - code = tNameExtractFullName(&pTableMetaInfo->name, pRight->tableName); - if (code != TSDB_CODE_SUCCESS) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + SJoinNode **rightNode = &pQueryInfo->tagCond.joinInfo.joinTables[index.tableIndex]; + if (*rightNode == NULL) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); } + (*rightNode)->uid = pTableMetaInfo->pTableMeta->id.uid; + (*rightNode)->tagColId = pTagSchema2->colId; + + if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { + index.columnIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + if (!tscColumnExists(pTableMetaInfo->tagColList, &index)) { + tscColumnListInsert(pTableMetaInfo->tagColList, &index); + if (taosArrayGetSize(pTableMetaInfo->tagColList) > 1) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg5); + } + } + } + + int16_t rightIdx = index.tableIndex; + if (pTagSchema1->type != pTagSchema2->type) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); } - pTagCond->joinInfo.hasJoin = true; + if ((*leftNode)->tagJoin == NULL) { + (*leftNode)->tagJoin = taosArrayInit(2, sizeof(int16_t)); + } + + if ((*rightNode)->tagJoin == NULL) { + (*rightNode)->tagJoin = taosArrayInit(2, sizeof(int16_t)); + } + + taosArrayPush((*leftNode)->tagJoin, &rightIdx); + taosArrayPush((*rightNode)->tagJoin, &leftIdx); + + pQueryInfo->tagCond.joinInfo.hasJoin = true; + return TSDB_CODE_SUCCESS; + +} + +static int32_t getJoinCondInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* pExpr) { + if (pExpr == NULL) { + return TSDB_CODE_SUCCESS; + } + + return checkAndSetJoinCondInfo(pCmd, pQueryInfo, pExpr); } static int32_t validateSQLExpr(SSqlCmd* pCmd, tSqlExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList, @@ -3663,7 +3732,7 @@ static int32_t handleExprInQueryCond(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSql const char* msg1 = "table query cannot use tags filter"; const char* msg2 = "illegal column name"; const char* msg3 = "only one query time range allowed"; - const char* msg4 = "only one join condition allowed"; + const char* msg4 = "too many join tables"; const char* msg5 = "not support ordinary column join"; const char* msg6 = "only one query condition on tbname allowed"; const char* msg7 = "only in/like allowed in filter table name"; @@ -3694,6 +3763,47 @@ static int32_t handleExprInQueryCond(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSql TSDB_QUERY_SET_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_JOIN_QUERY); pCondExpr->tsJoin = true; + assert(index.tableIndex >= 0 && index.tableIndex < TSDB_MAX_JOIN_TABLE_NUM); + SJoinNode **leftNode = &pQueryInfo->tagCond.joinInfo.joinTables[index.tableIndex]; + if (*leftNode == NULL) { + *leftNode = calloc(1, sizeof(SJoinNode)); + if (*leftNode == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + } + + int16_t leftIdx = index.tableIndex; + + SColumnIndex index = COLUMN_INDEX_INITIALIZER; + if (getColumnIndexByName(pCmd, &pRight->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + } + + if (index.tableIndex < 0 || index.tableIndex >= TSDB_MAX_JOIN_TABLE_NUM) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4); + } + + SJoinNode **rightNode = &pQueryInfo->tagCond.joinInfo.joinTables[index.tableIndex]; + if (*rightNode == NULL) { + *rightNode = calloc(1, sizeof(SJoinNode)); + if (*rightNode == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + } + + int16_t rightIdx = index.tableIndex; + + if ((*leftNode)->tsJoin == NULL) { + (*leftNode)->tsJoin = taosArrayInit(2, sizeof(int16_t)); + } + + if ((*rightNode)->tsJoin == NULL) { + (*rightNode)->tsJoin = taosArrayInit(2, sizeof(int16_t)); + } + + taosArrayPush((*leftNode)->tsJoin, &rightIdx); + taosArrayPush((*rightNode)->tsJoin, &leftIdx); + /* * to release expression, e.g., m1.ts = m2.ts, * since this expression is used to set the join query type @@ -3751,10 +3861,6 @@ static int32_t handleExprInQueryCond(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSql return TSDB_CODE_TSC_INVALID_SQL; } - if (pCondExpr->pJoinExpr != NULL) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4); - } - pQueryInfo->type |= TSDB_QUERY_TYPE_JOIN_QUERY; ret = setExprToCond(&pCondExpr->pJoinExpr, *pExpr, NULL, parentOptr, pQueryInfo->msg); *pExpr = NULL; @@ -3982,7 +4088,8 @@ static bool validateFilterExpr(SQueryInfo* pQueryInfo) { static int32_t getTimeRangeFromExpr(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlExpr* pExpr) { const char* msg0 = "invalid timestamp"; const char* msg1 = "only one time stamp window allowed"; - + int32_t code = 0; + if (pExpr == NULL) { return TSDB_CODE_SUCCESS; } @@ -3992,8 +4099,11 @@ static int32_t getTimeRangeFromExpr(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSqlE return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); } - getTimeRangeFromExpr(pCmd, pQueryInfo, pExpr->pLeft); - + code = getTimeRangeFromExpr(pCmd, pQueryInfo, pExpr->pLeft); + if (code) { + return code; + } + return getTimeRangeFromExpr(pCmd, pQueryInfo, pExpr->pRight); } else { SColumnIndex index = COLUMN_INDEX_INITIALIZER; @@ -4074,6 +4184,7 @@ static void cleanQueryExpr(SCondExpr* pCondExpr) { } } +/* static void doAddJoinTagsColumnsIntoTagList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SCondExpr* pCondExpr) { STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); if (QUERY_IS_JOIN_QUERY(pQueryInfo->type) && UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { @@ -4096,6 +4207,7 @@ static void doAddJoinTagsColumnsIntoTagList(SSqlCmd* pCmd, SQueryInfo* pQueryInf tscColumnListInsert(pTableMetaInfo->tagColList, &index); } } +*/ static int32_t validateTagCondExpr(SSqlCmd* pCmd, tExprNode *p) { const char *msg1 = "invalid tag operator"; @@ -4239,6 +4351,102 @@ static int32_t getTagQueryCondExpr(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SCondE return ret; } +int32_t validateJoinNodes(SQueryInfo* pQueryInfo, SSqlObj* pSql) { + const char* msg1 = "timestamp required for join tables"; + const char* msg2 = "tag required for join stables"; + + for (int32_t i = 0; i < pQueryInfo->numOfTables; ++i) { + SJoinNode *node = pQueryInfo->tagCond.joinInfo.joinTables[i]; + + if (node == NULL || node->tsJoin == NULL || taosArrayGetSize(node->tsJoin) <= 0) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg1); + } + } + + STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { + for (int32_t i = 0; i < pQueryInfo->numOfTables; ++i) { + SJoinNode *node = pQueryInfo->tagCond.joinInfo.joinTables[i]; + + if (node == NULL || node->tagJoin == NULL || taosArrayGetSize(node->tagJoin) <= 0) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg2); + } + } + } + + return TSDB_CODE_SUCCESS; +} + + +void mergeJoinNodesImpl(int8_t* r, int8_t* p, int16_t* tidx, SJoinNode** nodes, int32_t type) { + SJoinNode *node = nodes[*tidx]; + SArray* arr = (type == 0) ? node->tsJoin : node->tagJoin; + size_t size = taosArrayGetSize(arr); + + p[*tidx] = 1; + + for (int32_t j = 0; j < size; j++) { + int16_t* idx = taosArrayGet(arr, j); + r[*idx] = 1; + if (p[*idx] == 0) { + mergeJoinNodesImpl(r, p, idx, nodes, type); + } + } +} + +int32_t mergeJoinNodes(SQueryInfo* pQueryInfo, SSqlObj* pSql) { + const char* msg1 = "not all join tables have same timestamp"; + const char* msg2 = "not all join tables have same tag"; + + int8_t r[TSDB_MAX_JOIN_TABLE_NUM] = {0}; + int8_t p[TSDB_MAX_JOIN_TABLE_NUM] = {0}; + + for (int16_t i = 0; i < pQueryInfo->numOfTables; ++i) { + mergeJoinNodesImpl(r, p, &i, pQueryInfo->tagCond.joinInfo.joinTables, 0); + + taosArrayClear(pQueryInfo->tagCond.joinInfo.joinTables[i]->tsJoin); + + for (int32_t j = 0; j < TSDB_MAX_JOIN_TABLE_NUM; ++j) { + if (r[j]) { + taosArrayPush(pQueryInfo->tagCond.joinInfo.joinTables[i]->tsJoin, &j); + } + } + + memset(r, 0, sizeof(r)); + memset(p, 0, sizeof(p)); + } + + if (taosArrayGetSize(pQueryInfo->tagCond.joinInfo.joinTables[0]->tsJoin) != pQueryInfo->numOfTables) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg1); + } + + STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { + for (int16_t i = 0; i < pQueryInfo->numOfTables; ++i) { + mergeJoinNodesImpl(r, p, &i, pQueryInfo->tagCond.joinInfo.joinTables, 1); + + taosArrayClear(pQueryInfo->tagCond.joinInfo.joinTables[i]->tagJoin); + + for (int32_t j = 0; j < TSDB_MAX_JOIN_TABLE_NUM; ++j) { + if (r[j]) { + taosArrayPush(pQueryInfo->tagCond.joinInfo.joinTables[i]->tagJoin, &j); + } + } + + memset(r, 0, sizeof(r)); + memset(p, 0, sizeof(p)); + } + + if (taosArrayGetSize(pQueryInfo->tagCond.joinInfo.joinTables[0]->tagJoin) != pQueryInfo->numOfTables) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg2); + } + + } + + return TSDB_CODE_SUCCESS; +} + + int32_t parseWhereClause(SQueryInfo* pQueryInfo, tSqlExpr** pExpr, SSqlObj* pSql) { if (pExpr == NULL) { return TSDB_CODE_SUCCESS; @@ -4284,17 +4492,17 @@ int32_t parseWhereClause(SQueryInfo* pQueryInfo, tSqlExpr** pExpr, SSqlObj* pSql // 4. get the table name query condition if ((ret = getTablenameCond(&pSql->cmd, pQueryInfo, condExpr.pTableCond, &sb)) != TSDB_CODE_SUCCESS) { - return ret; + goto PARSE_WHERE_EXIT; } // 5. other column query condition if ((ret = getColumnQueryCondInfo(&pSql->cmd, pQueryInfo, condExpr.pColumnCond, TK_AND)) != TSDB_CODE_SUCCESS) { - return ret; + goto PARSE_WHERE_EXIT; } // 6. join condition if ((ret = getJoinCondInfo(&pSql->cmd, pQueryInfo, condExpr.pJoinExpr)) != TSDB_CODE_SUCCESS) { - return ret; + goto PARSE_WHERE_EXIT; } // 7. query condition for table name @@ -4302,12 +4510,29 @@ int32_t parseWhereClause(SQueryInfo* pQueryInfo, tSqlExpr** pExpr, SSqlObj* pSql ret = setTableCondForSTableQuery(&pSql->cmd, pQueryInfo, getAccountId(pSql), condExpr.pTableCond, condExpr.tableCondIndex, &sb); taosStringBuilderDestroy(&sb); - - if (!validateFilterExpr(pQueryInfo)) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg2); + if (ret) { + goto PARSE_WHERE_EXIT; } - doAddJoinTagsColumnsIntoTagList(&pSql->cmd, pQueryInfo, &condExpr); + if (!validateFilterExpr(pQueryInfo)) { + ret = invalidSqlErrMsg(tscGetErrorMsgPayload(&pSql->cmd), msg2); + goto PARSE_WHERE_EXIT; + } + + //doAddJoinTagsColumnsIntoTagList(&pSql->cmd, pQueryInfo, &condExpr); + if (condExpr.tsJoin) { + ret = validateJoinNodes(pQueryInfo, pSql); + if (ret) { + goto PARSE_WHERE_EXIT; + } + + ret = mergeJoinNodes(pQueryInfo, pSql); + if (ret) { + goto PARSE_WHERE_EXIT; + } + } + +PARSE_WHERE_EXIT: cleanQueryExpr(&condExpr); return ret; @@ -6520,7 +6745,6 @@ int32_t doValidateSqlNode(SSqlObj* pSql, SQuerySqlNode* pQuerySqlNode, int32_t i const char* msg1 = "point interpolation query needs timestamp"; const char* msg2 = "fill only available for interval query"; const char* msg3 = "start(end) time of query range required or time range too large"; - const char* msg4 = "illegal number of tables in from clause"; const char* msg5 = "too many columns in selection clause"; const char* msg6 = "too many tables in from clause"; const char* msg7 = "invalid table alias name"; @@ -6557,14 +6781,11 @@ int32_t doValidateSqlNode(SSqlObj* pSql, SQuerySqlNode* pQuerySqlNode, int32_t i } size_t fromSize = taosArrayGetSize(pQuerySqlNode->from->tableList); - if (fromSize > TSDB_MAX_JOIN_TABLE_NUM) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4); + if (fromSize > TSDB_MAX_JOIN_TABLE_NUM * 2) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg6); } pQueryInfo->command = TSDB_SQL_SELECT; - if (fromSize > 2) { - return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg6); - } // set all query tables, which are maybe more than one. for (int32_t i = 0; i < fromSize; ++i) { diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index 6f19d49e9a..d6deb7d7e2 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -350,8 +350,8 @@ void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) { taosMsleep(duration); } + pSql->retryReason = rpcMsg->code; rpcMsg->code = tscRenewTableMeta(pSql, 0); - // if there is an error occurring, proceed to the following error handling procedure. if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) { taosReleaseRef(tscObjRef, handle); @@ -508,7 +508,7 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) { SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex); pRetrieveMsg->free = htons(pQueryInfo->type); - pRetrieveMsg->qhandle = htobe64(pSql->res.qhandle); + pRetrieveMsg->qId = htobe64(pSql->res.qId); // todo valid the vgroupId at the client side STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); @@ -520,7 +520,7 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) { assert(pVgroupInfo->vgroups[vgIndex].vgId > 0 && vgIndex < pTableMetaInfo->vgroupList->numOfVgroups); pRetrieveMsg->header.vgId = htonl(pVgroupInfo->vgroups[vgIndex].vgId); - tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qhandle:%" PRIX64, pSql, pVgroupInfo->vgroups[vgIndex].vgId, vgIndex, pSql->res.qhandle); + tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qhandle:%" PRIX64, pSql, pVgroupInfo->vgroups[vgIndex].vgId, vgIndex, pSql->res.qId); } else { int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables); assert(vgIndex >= 0 && vgIndex < numOfVgroups); @@ -528,12 +528,12 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) { SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, vgIndex); pRetrieveMsg->header.vgId = htonl(pTableIdList->vgInfo.vgId); - tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qhandle:%" PRIX64, pSql, pTableIdList->vgInfo.vgId, vgIndex, pSql->res.qhandle); + tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qId:%" PRIu64, pSql, pTableIdList->vgInfo.vgId, vgIndex, pSql->res.qId); } } else { STableMeta* pTableMeta = pTableMetaInfo->pTableMeta; pRetrieveMsg->header.vgId = htonl(pTableMeta->vgId); - tscDebug("%p build fetch msg from only one vgroup, vgId:%d, qhandle:%" PRIX64, pSql, pTableMeta->vgId, pSql->res.qhandle); + tscDebug("%p build fetch msg from only one vgroup, vgId:%d, qId:%" PRIu64, pSql, pTableMeta->vgId, pSql->res.qId); } pSql->cmd.payloadLen = sizeof(SRetrieveTableMsg); @@ -1294,6 +1294,23 @@ int32_t tscBuildUseDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) { return TSDB_CODE_SUCCESS; } +int32_t tscBuildSyncDbReplicaMsg(SSqlObj* pSql, SSqlInfo *pInfo) { + SSqlCmd *pCmd = &pSql->cmd; + pCmd->payloadLen = sizeof(SSyncDbMsg); + + if (TSDB_CODE_SUCCESS != tscAllocPayload(pCmd, pCmd->payloadLen)) { + tscError("%p failed to malloc for query msg", pSql); + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + SSyncDbMsg *pSyncMsg = (SSyncDbMsg *)pCmd->payload; + STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0); + tNameExtractFullName(&pTableMetaInfo->name, pSyncMsg->db); + pCmd->msgType = TSDB_MSG_TYPE_CM_SYNC_DB; + + return TSDB_CODE_SUCCESS; +} + int32_t tscBuildShowMsg(SSqlObj *pSql, SSqlInfo *pInfo) { STscObj *pObj = pSql->pTscObj; SSqlCmd *pCmd = &pSql->cmd; @@ -1566,7 +1583,7 @@ int tscBuildRetrieveFromMgmtMsg(SSqlObj *pSql, SSqlInfo *pInfo) { SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0); SRetrieveTableMsg *pRetrieveMsg = (SRetrieveTableMsg*)pCmd->payload; - pRetrieveMsg->qhandle = htobe64(pSql->res.qhandle); + pRetrieveMsg->qId = htobe64(pSql->res.qId); pRetrieveMsg->free = htons(pQueryInfo->type); return TSDB_CODE_SUCCESS; @@ -2117,7 +2134,7 @@ int tscProcessShowRsp(SSqlObj *pSql) { pShow = (SShowRsp *)pRes->pRsp; pShow->qhandle = htobe64(pShow->qhandle); - pRes->qhandle = pShow->qhandle; + pRes->qId = pShow->qhandle; tscResetForNextRetrieve(pRes); pMetaMsg = &(pShow->tableMeta); @@ -2299,11 +2316,12 @@ int tscProcessQueryRsp(SSqlObj *pSql) { SSqlRes *pRes = &pSql->res; SQueryTableRsp *pQuery = (SQueryTableRsp *)pRes->pRsp; - pQuery->qhandle = htobe64(pQuery->qhandle); - pRes->qhandle = pQuery->qhandle; + pQuery->qId = htobe64(pQuery->qId); + pRes->qId = pQuery->qId; pRes->data = NULL; tscResetForNextRetrieve(pRes); + tscDebug("%p query rsp received, qId:%"PRIu64, pSql, pRes->qId); return 0; } @@ -2361,7 +2379,8 @@ int tscProcessRetrieveRspFromNode(SSqlObj *pSql) { } pRes->row = 0; - tscDebug("%p numOfRows:%d, offset:%" PRId64 ", complete:%d", pSql, pRes->numOfRows, pRes->offset, pRes->completed); + tscDebug("%p numOfRows:%d, offset:%" PRId64 ", complete:%d, qId:%"PRIu64, pSql, pRes->numOfRows, pRes->offset, + pRes->completed, pRes->qId); return 0; } @@ -2574,6 +2593,7 @@ void tscInitMsgsFp() { tscBuildMsg[TSDB_SQL_DROP_USER] = tscBuildDropUserAcctMsg; tscBuildMsg[TSDB_SQL_DROP_ACCT] = tscBuildDropUserAcctMsg; tscBuildMsg[TSDB_SQL_DROP_DB] = tscBuildDropDbMsg; + tscBuildMsg[TSDB_SQL_SYNC_DB_REPLICA] = tscBuildSyncDbReplicaMsg; tscBuildMsg[TSDB_SQL_DROP_TABLE] = tscBuildDropTableMsg; tscBuildMsg[TSDB_SQL_ALTER_USER] = tscBuildUserMsg; tscBuildMsg[TSDB_SQL_CREATE_DNODE] = tscBuildCreateDnodeMsg; diff --git a/src/client/src/tscSql.c b/src/client/src/tscSql.c index 13539a9b19..93d0e9fd09 100644 --- a/src/client/src/tscSql.c +++ b/src/client/src/tscSql.c @@ -476,7 +476,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - if (pRes->qhandle == 0 || + if (pRes->qId == 0 || pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED || pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pCmd->command == TSDB_SQL_INSERT) { @@ -508,7 +508,7 @@ int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - if (pRes->qhandle == 0 || + if (pRes->qId == 0 || pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED || pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pCmd->command == TSDB_SQL_INSERT) { @@ -554,7 +554,7 @@ static bool tscKillQueryInDnode(SSqlObj* pSql) { SSqlCmd* pCmd = &pSql->cmd; SSqlRes* pRes = &pSql->res; - if (pRes == NULL || pRes->qhandle == 0) { + if (pRes == NULL || pRes->qId == 0) { return true; } @@ -1050,7 +1050,7 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) { * If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql() * to free connection, which may cause segment fault, when the parse phrase is not even successfully executed. */ - pRes->qhandle = 0; + pRes->qId = 0; free(str); if (code != TSDB_CODE_SUCCESS) { diff --git a/src/client/src/tscSub.c b/src/client/src/tscSub.c index 32257f5a7c..1277a436a1 100644 --- a/src/client/src/tscSub.c +++ b/src/client/src/tscSub.c @@ -149,7 +149,7 @@ static SSub* tscCreateSubscription(STscObj* pObj, const char* topic, const char* } strtolower(pSql->sqlstr, pSql->sqlstr); - pRes->qhandle = 0; + pRes->qId = 0; pRes->numOfRows = 1; code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE); @@ -448,7 +448,7 @@ SSqlObj* recreateSqlObj(SSub* pSub) { return NULL; } - pRes->qhandle = 0; + pRes->qId = 0; pRes->numOfRows = 1; int code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE); @@ -546,7 +546,7 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) { uint32_t type = pQueryInfo->type; tscFreeSqlResult(pSql); pRes->numOfRows = 1; - pRes->qhandle = 0; + pRes->qId = 0; pSql->cmd.command = TSDB_SQL_SELECT; pQueryInfo->type = type; diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c index 22cb580951..299cf03805 100644 --- a/src/client/src/tscSubquery.c +++ b/src/client/src/tscSubquery.c @@ -46,6 +46,13 @@ static int32_t tsCompare(int32_t order, int64_t left, int64_t right) { } static void skipRemainValue(STSBuf* pTSBuf, tVariant* tag1) { + STSElem el1 = tsBufGetElem(pTSBuf); + + int32_t res = tVariantCompare(el1.tag, tag1); + if (res != 0) { // it is a record with new tag + return; + } + while (tsBufNextPos(pTSBuf)) { STSElem el1 = tsBufGetElem(pTSBuf); @@ -118,123 +125,233 @@ static bool subAndCheckDone(SSqlObj *pSql, SSqlObj *pParentSql, int idx) { -static int64_t doTSBlockIntersect(SSqlObj* pSql, SJoinSupporter* pSupporter1, SJoinSupporter* pSupporter2, STimeWindow * win) { +static int64_t doTSBlockIntersect(SSqlObj* pSql, STimeWindow * win) { SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex); - STSBuf* output1 = tsBufCreate(true, pQueryInfo->order.order); - STSBuf* output2 = tsBufCreate(true, pQueryInfo->order.order); - win->skey = INT64_MAX; win->ekey = INT64_MIN; SLimitVal* pLimit = &pQueryInfo->limit; int32_t order = pQueryInfo->order.order; + int32_t joinNum = pSql->subState.numOfSub; + SMergeTsCtx ctxlist[TSDB_MAX_JOIN_TABLE_NUM] = {{0}}; + SMergeTsCtx* ctxStack[TSDB_MAX_JOIN_TABLE_NUM] = {0}; + int32_t slot = 0; + size_t tableNum = 0; + int16_t* tableMIdx = 0; + int32_t equalNum = 0; + int32_t stackidx = 0; + SMergeTsCtx* ctx = NULL; + SMergeTsCtx* pctx = NULL; + SMergeTsCtx* mainCtx = NULL; + STSElem cur; + STSElem prev; + SArray* tsCond = NULL; + int32_t mergeDone = 0; - SQueryInfo* pSubQueryInfo1 = tscGetQueryInfoDetail(&pSql->pSubs[0]->cmd, 0); - SQueryInfo* pSubQueryInfo2 = tscGetQueryInfoDetail(&pSql->pSubs[1]->cmd, 0); + for (int32_t i = 0; i < joinNum; ++i) { + STSBuf* output = tsBufCreate(true, pQueryInfo->order.order); + SQueryInfo* pSubQueryInfo = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0); - pSubQueryInfo1->tsBuf = output1; - pSubQueryInfo2->tsBuf = output2; + pSubQueryInfo->tsBuf = output; + + SJoinSupporter* pSupporter = pSql->pSubs[i]->param; + + if (pSupporter->pTSBuf == NULL) { + tscDebug("%p at least one ts-comp is empty, 0 for secondary query after ts blocks intersecting", pSql); + return 0; + } + + tsBufResetPos(pSupporter->pTSBuf); + + if (!tsBufNextPos(pSupporter->pTSBuf)) { + tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql); + return 0; + } + + tscDebug("%p sub:%p table idx:%d, input group number:%d", pSql, pSql->pSubs[i], i, pSupporter->pTSBuf->numOfGroups); + + ctxlist[i].p = pSupporter; + ctxlist[i].res = output; + } TSKEY st = taosGetTimestampUs(); - // no result generated, return directly - if (pSupporter1->pTSBuf == NULL || pSupporter2->pTSBuf == NULL) { - tscDebug("%p at least one ts-comp is empty, 0 for secondary query after ts blocks intersecting", pSql); - return 0; - } - - tsBufResetPos(pSupporter1->pTSBuf); - tsBufResetPos(pSupporter2->pTSBuf); - - if (!tsBufNextPos(pSupporter1->pTSBuf)) { - tsBufFlush(output1); - tsBufFlush(output2); - - tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql); - return 0; - } - - if (!tsBufNextPos(pSupporter2->pTSBuf)) { - tsBufFlush(output1); - tsBufFlush(output2); - - tscDebug("%p input2 is empty, 0 for secondary query after ts blocks intersecting", pSql); - return 0; - } - - int64_t numOfInput1 = 1; - int64_t numOfInput2 = 1; - - while(1) { - STSElem elem = tsBufGetElem(pSupporter1->pTSBuf); - - // no data in pSupporter1 anymore, jump out of loop - if (!tsBufIsValidElem(&elem)) { - break; + for (int16_t tidx = 0; tidx < joinNum; tidx++) { + pctx = &ctxlist[tidx]; + if (pctx->compared) { + continue; } - // find the data in supporter2 with the same tag value - STSElem e2 = tsBufFindElemStartPosByTag(pSupporter2->pTSBuf, elem.tag); + assert(pctx->numOfInput == 0); - /** - * there are elements in pSupporter2 with the same tag, continue - */ - tVariant tag1 = {0}; - tVariantAssign(&tag1, elem.tag); + tsCond = pQueryInfo->tagCond.joinInfo.joinTables[tidx]->tsJoin; + + tableNum = taosArrayGetSize(tsCond); + assert(tableNum >= 2); + + for (int32_t i = 0; i < tableNum; ++i) { + tableMIdx = taosArrayGet(tsCond, i); + SMergeTsCtx* tctx = &ctxlist[*tableMIdx]; + tctx->compared = 1; + } + + tableMIdx = taosArrayGet(tsCond, 0); + pctx = &ctxlist[*tableMIdx]; + + mainCtx = pctx; + + while (1) { + pctx = mainCtx; + + prev = tsBufGetElem(pctx->p->pTSBuf); + + ctxStack[stackidx++] = pctx; + + if (!tsBufIsValidElem(&prev)) { + break; + } + + tVariant tag = {0}; + tVariantAssign(&tag, prev.tag); + + int32_t skipped = 0; + + for (int32_t i = 1; i < tableNum; ++i) { + SMergeTsCtx* tctx = &ctxlist[i]; + + // find the data in supporter2 with the same tag value + STSElem e2 = tsBufFindElemStartPosByTag(tctx->p->pTSBuf, &tag); + + if (!tsBufIsValidElem(&e2)) { + skipRemainValue(pctx->p->pTSBuf, &tag); + skipped = 1; + break; + } + } + + if (skipped) { + slot = 0; + stackidx = 0; + continue; + } + + tableMIdx = taosArrayGet(tsCond, ++slot); + equalNum = 1; - if (tsBufIsValidElem(&e2)) { while (1) { - STSElem elem1 = tsBufGetElem(pSupporter1->pTSBuf); - STSElem elem2 = tsBufGetElem(pSupporter2->pTSBuf); + ctx = &ctxlist[*tableMIdx]; + + prev = tsBufGetElem(pctx->p->pTSBuf); + cur = tsBufGetElem(ctx->p->pTSBuf); // data with current are exhausted - if (!tsBufIsValidElem(&elem1) || tVariantCompare(elem1.tag, &tag1) != 0) { + if (!tsBufIsValidElem(&prev) || tVariantCompare(prev.tag, &tag) != 0) { break; } - if (!tsBufIsValidElem(&elem2) || tVariantCompare(elem2.tag, &tag1) != 0) { // ignore all records with the same tag - skipRemainValue(pSupporter1->pTSBuf, &tag1); + if (!tsBufIsValidElem(&cur) || tVariantCompare(cur.tag, &tag) != 0) { // ignore all records with the same tag break; } - /* - * in case of stable query, limit/offset is not applied here. the limit/offset is applied to the - * final results which is acquired after the secondary merge of in the client. - */ - int32_t re = tsCompare(order, elem1.ts, elem2.ts); - if (re < 0) { - tsBufNextPos(pSupporter1->pTSBuf); - numOfInput1++; - } else if (re > 0) { - tsBufNextPos(pSupporter2->pTSBuf); - numOfInput2++; - } else { + ctxStack[stackidx++] = ctx; + + int32_t ret = tsCompare(order, prev.ts, cur.ts); + if (ret == 0) { + if (++equalNum < tableNum) { + pctx = ctx; + + if (++slot >= tableNum) { + slot = 0; + } + + tableMIdx = taosArrayGet(tsCond, slot); + continue; + } + + assert(stackidx == tableNum); + if (pLimit->offset == 0 || pQueryInfo->interval.interval > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) { - if (win->skey > elem1.ts) { - win->skey = elem1.ts; + if (win->skey > prev.ts) { + win->skey = prev.ts; + } + + if (win->ekey < prev.ts) { + win->ekey = prev.ts; } - if (win->ekey < elem1.ts) { - win->ekey = elem1.ts; + for (int32_t i = 0; i < stackidx; ++i) { + SMergeTsCtx* tctx = ctxStack[i]; + prev = tsBufGetElem(tctx->p->pTSBuf); + + tsBufAppend(tctx->res, prev.id, prev.tag, (const char*)&prev.ts, sizeof(prev.ts)); } - - tsBufAppend(output1, elem1.id, elem1.tag, (const char*)&elem1.ts, sizeof(elem1.ts)); - tsBufAppend(output2, elem2.id, elem2.tag, (const char*)&elem2.ts, sizeof(elem2.ts)); } else { pLimit->offset -= 1;//offset apply to projection? } - tsBufNextPos(pSupporter1->pTSBuf); - numOfInput1++; + for (int32_t i = 0; i < stackidx; ++i) { + SMergeTsCtx* tctx = ctxStack[i]; + + if (!tsBufNextPos(tctx->p->pTSBuf) && tctx == mainCtx) { + mergeDone = 1; + } + tctx->numOfInput++; + } - tsBufNextPos(pSupporter2->pTSBuf); - numOfInput2++; + if (mergeDone) { + break; + } + + stackidx = 0; + equalNum = 1; + + ctxStack[stackidx++] = pctx; + } else if (ret > 0) { + if (!tsBufNextPos(ctx->p->pTSBuf) && ctx == mainCtx) { + mergeDone = 1; + break; + } + + ctx->numOfInput++; + stackidx--; + } else { + stackidx--; + + for (int32_t i = 0; i < stackidx; ++i) { + SMergeTsCtx* tctx = ctxStack[i]; + + if (!tsBufNextPos(tctx->p->pTSBuf) && tctx == mainCtx) { + mergeDone = 1; + } + tctx->numOfInput++; + } + + if (mergeDone) { + break; + } + + stackidx = 0; + equalNum = 1; + + ctxStack[stackidx++] = pctx; } + } - } else { // no data in pSupporter2, ignore current data in pSupporter2 - skipRemainValue(pSupporter1->pTSBuf, &tag1); + + if (mergeDone) { + break; + } + + slot = 0; + stackidx = 0; + + skipRemainValue(mainCtx->p->pTSBuf, &tag); } + + stackidx = 0; + slot = 0; + mergeDone = 0; } /* @@ -242,28 +359,32 @@ static int64_t doTSBlockIntersect(SSqlObj* pSql, SJoinSupporter* pSupporter1, SJ * 1. only one element * 2. only one element for each tag. */ - if (output1->tsOrder == -1) { - output1->tsOrder = TSDB_ORDER_ASC; - output2->tsOrder = TSDB_ORDER_ASC; + if (ctxlist[0].res->tsOrder == -1) { + for (int32_t i = 0; i < joinNum; ++i) { + ctxlist[i].res->tsOrder = TSDB_ORDER_ASC; + } } - tsBufFlush(output1); - tsBufFlush(output2); - - tsBufDestroy(pSupporter1->pTSBuf); - pSupporter1->pTSBuf = NULL; - tsBufDestroy(pSupporter2->pTSBuf); - pSupporter2->pTSBuf = NULL; + for (int32_t i = 0; i < joinNum; ++i) { + tsBufFlush(ctxlist[i].res); + + tsBufDestroy(ctxlist[i].p->pTSBuf); + ctxlist[i].p->pTSBuf = NULL; + } TSKEY et = taosGetTimestampUs(); - tscDebug("%p input1:%" PRId64 ", input2:%" PRId64 ", final:%" PRId64 " in %d vnodes for secondary query after ts blocks " - "intersecting, skey:%" PRId64 ", ekey:%" PRId64 ", numOfVnode:%d, elapsed time:%" PRId64 " us", - pSql, numOfInput1, numOfInput2, output1->numOfTotal, output1->numOfGroups, win->skey, win->ekey, - tsBufGetNumOfGroup(output1), et - st); - return output1->numOfTotal; + for (int32_t i = 0; i < joinNum; ++i) { + tscDebug("%p sub:%p tblidx:%d, input:%" PRId64 ", final:%" PRId64 " in %d vnodes for secondary query after ts blocks " + "intersecting, skey:%" PRId64 ", ekey:%" PRId64 ", numOfVnode:%d, elapsed time:%" PRId64 " us", + pSql, pSql->pSubs[i], i, ctxlist[i].numOfInput, ctxlist[i].res->numOfTotal, ctxlist[i].res->numOfGroups, win->skey, win->ekey, + tsBufGetNumOfGroup(ctxlist[i].res), et - st); + } + + return ctxlist[0].res->numOfTotal; } + // todo handle failed to create sub query SJoinSupporter* tscCreateJoinSupporter(SSqlObj* pSql, int32_t index) { SJoinSupporter* pSupporter = calloc(1, sizeof(SJoinSupporter)); @@ -768,76 +889,218 @@ static bool checkForDuplicateTagVal(SSchema* pColSchema, SJoinSupporter* p1, SSq return true; } -static int32_t getIntersectionOfTableTuple(SQueryInfo* pQueryInfo, SSqlObj* pParentSql, SArray** s1, SArray** s2) { - SJoinSupporter* p1 = pParentSql->pSubs[0]->param; - SJoinSupporter* p2 = pParentSql->pSubs[1]->param; - - tscDebug("%p all subquery retrieve complete, do tags match, %d, %d", pParentSql, p1->num, p2->num); - - // sort according to the tag value - qsort(p1->pIdTagList, p1->num, p1->tagSize, tagValCompar); - qsort(p2->pIdTagList, p2->num, p2->tagSize, tagValCompar); +static int32_t getIntersectionOfTableTuple(SQueryInfo* pQueryInfo, SSqlObj* pParentSql, SArray* resList) { + int16_t joinNum = pParentSql->subState.numOfSub; STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); int16_t tagColId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid); - - SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId); + SJoinSupporter* p0 = pParentSql->pSubs[0]->param; + SMergeCtx ctxlist[TSDB_MAX_JOIN_TABLE_NUM] = {{0}}; + SMergeCtx* ctxStack[TSDB_MAX_JOIN_TABLE_NUM] = {0}; // int16_t for padding - int32_t size = p1->tagSize - sizeof(int16_t); - *s1 = taosArrayInit(p1->num, size); - *s2 = taosArrayInit(p2->num, size); + int32_t size = p0->tagSize - sizeof(int16_t); - if (!(checkForDuplicateTagVal(pColSchema, p1, pParentSql) && checkForDuplicateTagVal(pColSchema, p2, pParentSql))) { - return TSDB_CODE_QRY_DUP_JOIN_KEY; - } + SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId); + + tscDebug("%p all subquery retrieve complete, do tags match", pParentSql); - int32_t i = 0, j = 0; - while(i < p1->num && j < p2->num) { - STidTags* pp1 = (STidTags*) varDataVal(p1->pIdTagList + i * p1->tagSize); - STidTags* pp2 = (STidTags*) varDataVal(p2->pIdTagList + j * p2->tagSize); - assert(pp1->tid != 0 && pp2->tid != 0); + for (int32_t i = 0; i < joinNum; i++) { + SJoinSupporter* p = pParentSql->pSubs[i]->param; - int32_t ret = doCompare(pp1->tag, pp2->tag, pColSchema->type, pColSchema->bytes); - if (ret == 0) { - tscDebug("%p tag matched, vgId:%d, val:%d, tid:%d, uid:%"PRIu64", tid:%d, uid:%"PRIu64, pParentSql, pp1->vgId, - *(int*) pp1->tag, pp1->tid, pp1->uid, pp2->tid, pp2->uid); - - taosArrayPush(*s1, pp1); - taosArrayPush(*s2, pp2); - j++; - i++; - } else if (ret > 0) { - j++; - } else { - i++; + ctxlist[i].p = p; + ctxlist[i].res = taosArrayInit(p->num, size); + + tscDebug("Join %d - num:%d", i, p->num); + + // sort according to the tag valu + qsort(p->pIdTagList, p->num, p->tagSize, tagValCompar); + + if (!checkForDuplicateTagVal(pColSchema, p, pParentSql)) { + for (int32_t j = 0; j <= i; j++) { + taosArrayDestroy(ctxlist[j].res); + } + return TSDB_CODE_QRY_DUP_JOIN_KEY; } } - // reorganize the tid-tag value according to both the vgroup id and tag values - // sort according to the tag value - size_t t1 = taosArrayGetSize(*s1); - size_t t2 = taosArrayGetSize(*s2); + int32_t slot = 0; + size_t tableNum = 0; + int16_t* tableMIdx = 0; + int32_t equalNum = 0; + int32_t stackidx = 0; + int32_t mergeDone = 0; + SMergeCtx* ctx = NULL; + SMergeCtx* pctx = NULL; + STidTags* cur = NULL; + STidTags* prev = NULL; + SArray* tagCond = NULL; - qsort((*s1)->pData, t1, size, tidTagsCompar); - qsort((*s2)->pData, t2, size, tidTagsCompar); + for (int16_t tidx = 0; tidx < joinNum; tidx++) { + pctx = &ctxlist[tidx]; + if (pctx->compared) { + continue; + } -#if 0 - for(int32_t k = 0; k < t1; ++k) { - STidTags* p = (*s1)->pData + size * k; - printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data); + assert(pctx->idx == 0 && taosArrayGetSize(pctx->res) == 0); + + tagCond = pQueryInfo->tagCond.joinInfo.joinTables[tidx]->tagJoin; + + tableNum = taosArrayGetSize(tagCond); + assert(tableNum >= 2); + + for (int32_t i = 0; i < tableNum; ++i) { + tableMIdx = taosArrayGet(tagCond, i); + SMergeCtx* tctx = &ctxlist[*tableMIdx]; + tctx->compared = 1; + } + + for (int32_t i = 0; i < tableNum; ++i) { + tableMIdx = taosArrayGet(tagCond, i); + SMergeCtx* tctx = &ctxlist[*tableMIdx]; + if (tctx->p->num <= 0 || tctx->p->pIdTagList == NULL) { + mergeDone = 1; + break; + } + } + + if (mergeDone) { + mergeDone = 0; + continue; + } + + tableMIdx = taosArrayGet(tagCond, slot); + + pctx = &ctxlist[*tableMIdx]; + + prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize); + + ctxStack[stackidx++] = pctx; + + tableMIdx = taosArrayGet(tagCond, ++slot); + + equalNum = 1; + + while (1) { + ctx = &ctxlist[*tableMIdx]; + + cur = (STidTags*) varDataVal(ctx->p->pIdTagList + ctx->idx * ctx->p->tagSize); + + assert(cur->tid != 0 && prev->tid != 0); + + ctxStack[stackidx++] = ctx; + + int32_t ret = doCompare(prev->tag, cur->tag, pColSchema->type, pColSchema->bytes); + if (ret == 0) { + if (++equalNum < tableNum) { + prev = cur; + pctx = ctx; + + if (++slot >= tableNum) { + slot = 0; + } + + tableMIdx = taosArrayGet(tagCond, slot); + continue; + } + + tscDebug("%p tag matched, vgId:%d, val:%d, tid:%d, uid:%"PRIu64", tid:%d, uid:%"PRIu64, pParentSql, prev->vgId, + *(int*) prev->tag, prev->tid, prev->uid, cur->tid, cur->uid); + + assert(stackidx == tableNum); + + for (int32_t i = 0; i < stackidx; ++i) { + SMergeCtx* tctx = ctxStack[i]; + prev = (STidTags*) varDataVal(tctx->p->pIdTagList + tctx->idx * tctx->p->tagSize); + + taosArrayPush(tctx->res, prev); + } + + for (int32_t i = 0; i < stackidx; ++i) { + SMergeCtx* tctx = ctxStack[i]; + + if (++tctx->idx >= tctx->p->num) { + mergeDone = 1; + break; + } + } + + if (mergeDone) { + break; + } + + stackidx = 0; + equalNum = 1; + + prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize); + + ctxStack[stackidx++] = pctx; + } else if (ret > 0) { + stackidx--; + + if (++ctx->idx >= ctx->p->num) { + break; + } + } else { + stackidx--; + + for (int32_t i = 0; i < stackidx; ++i) { + SMergeCtx* tctx = ctxStack[i]; + if (++tctx->idx >= tctx->p->num) { + mergeDone = 1; + break; + } + } + + if (mergeDone) { + break; + } + + stackidx = 0; + equalNum = 1; + + prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize); + ctxStack[stackidx++] = pctx; + } + + } + + slot = 0; + mergeDone = 0; + stackidx = 0; } - for(int32_t k = 0; k < t1; ++k) { - STidTags* p = (*s2)->pData + size * k; - printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data); - } -#endif + for (int32_t i = 0; i < joinNum; ++i) { + // reorganize the tid-tag value according to both the vgroup id and tag values + // sort according to the tag value + size_t num = taosArrayGetSize(ctxlist[i].res); + + qsort((ctxlist[i].res)->pData, num, size, tidTagsCompar); - tscDebug("%p tags match complete, result: %"PRIzu", %"PRIzu, pParentSql, t1, t2); + taosArrayPush(resList, &ctxlist[i].res); + + tscDebug("%p tags match complete, result num: %"PRIzu, pParentSql, num); + } + return TSDB_CODE_SUCCESS; } +bool emptyTagList(SArray* resList, int32_t size) { + size_t rsize = taosArrayGetSize(resList); + if (rsize != size) { + return true; + } + + for (int32_t i = 0; i < size; ++i) { + SArray** s = taosArrayGet(resList, i); + if (taosArrayGetSize(*s) <= 0) { + return true; + } + } + + return false; +} + static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) { SJoinSupporter* pSupporter = (SJoinSupporter*)param; @@ -939,19 +1202,19 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow return; } - SArray *s1 = NULL, *s2 = NULL; - int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, &s1, &s2); + SArray* resList = taosArrayInit(pParentSql->subState.numOfSub, sizeof(SArray *)); + + int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, resList); if (code != TSDB_CODE_SUCCESS) { freeJoinSubqueryObj(pParentSql); pParentSql->res.code = code; tscAsyncResultOnError(pParentSql); - taosArrayDestroy(s1); - taosArrayDestroy(s2); + taosArrayDestroy(resList); return; } - if (taosArrayGetSize(s1) == 0 || taosArrayGetSize(s2) == 0) { // no results,return. + if (emptyTagList(resList, pParentSql->subState.numOfSub)) { // no results,return. assert(pParentSql->fp != tscJoinQueryCallback); tscDebug("%p tag intersect does not generated qualified tables for join, free all sub SqlObj and quit", pParentSql); @@ -963,37 +1226,34 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow (*pParentSql->fp)(pParentSql->param, pParentSql, 0); } else { - // proceed to for ts_comp query - SSqlCmd* pSubCmd1 = &pParentSql->pSubs[0]->cmd; - SSqlCmd* pSubCmd2 = &pParentSql->pSubs[1]->cmd; - - SQueryInfo* pQueryInfo1 = tscGetQueryInfoDetail(pSubCmd1, 0); - STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pQueryInfo1, 0); - tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo1, s1); - - SQueryInfo* pQueryInfo2 = tscGetQueryInfoDetail(pSubCmd2, 0); - STableMetaInfo* pTableMetaInfo2 = tscGetMetaInfo(pQueryInfo2, 0); - tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo2, s2); - - SSqlObj* psub1 = pParentSql->pSubs[0]; - ((SJoinSupporter*)psub1->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo1->pVgroupTables); - - SSqlObj* psub2 = pParentSql->pSubs[1]; - ((SJoinSupporter*)psub2->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo2->pVgroupTables); - - pParentSql->subState.numOfSub = 2; - - memset(pParentSql->subState.states, 0, sizeof(pParentSql->subState.states[0]) * pParentSql->subState.numOfSub); - tscDebug("%p reset all sub states to 0", pParentSql); - for (int32_t m = 0; m < pParentSql->subState.numOfSub; ++m) { - SSqlObj* sub = pParentSql->pSubs[m]; - issueTsCompQuery(sub, sub->param, pParentSql); + // proceed to for ts_comp query + SSqlCmd* pSubCmd = &pParentSql->pSubs[m]->cmd; + SArray** s = taosArrayGet(resList, m); + + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pSubCmd, 0); + STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo, *s); + + SSqlObj* psub = pParentSql->pSubs[m]; + ((SJoinSupporter*)psub->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo->pVgroupTables); + + memset(pParentSql->subState.states, 0, sizeof(pParentSql->subState.states[0]) * pParentSql->subState.numOfSub); + tscDebug("%p reset all sub states to 0", pParentSql); + + issueTsCompQuery(psub, psub->param, pParentSql); } } - taosArrayDestroy(s1); - taosArrayDestroy(s2); + size_t rsize = taosArrayGetSize(resList); + for (int32_t i = 0; i < rsize; ++i) { + SArray** s = taosArrayGet(resList, i); + if (*s) { + taosArrayDestroy(*s); + } + } + + taosArrayDestroy(resList); } static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) { @@ -1124,12 +1384,8 @@ static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow tscDebug("%p all subquery retrieve ts complete, do ts block intersect", pParentSql); - // proceeds to launched secondary query to retrieve final data - SJoinSupporter* p1 = pParentSql->pSubs[0]->param; - SJoinSupporter* p2 = pParentSql->pSubs[1]->param; - STimeWindow win = TSWINDOW_INITIALIZER; - int64_t num = doTSBlockIntersect(pParentSql, p1, p2, &win); + int64_t num = doTSBlockIntersect(pParentSql, &win); if (num <= 0) { // no result during ts intersect tscDebug("%p no results generated in ts intersection, free all sub SqlObj and quit", pParentSql); freeJoinSubqueryObj(pParentSql); @@ -1584,7 +1840,7 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter SSqlCmd * pCmd = &pSql->cmd; SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - pSql->res.qhandle = 0x1; + pSql->res.qId = 0x1; assert(pSql->res.numOfRows == 0); if (pSql->pSubs == NULL) { @@ -1639,6 +1895,8 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter pNewQueryInfo->limit.limit = -1; pNewQueryInfo->limit.offset = 0; + pNewQueryInfo->order.orderColId = INT32_MIN; + // backup the data and clear it in the sqlcmd object memset(&pNewQueryInfo->groupbyExpr, 0, sizeof(SSqlGroupbyExpr)); @@ -2182,7 +2440,7 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) { SColumnModel *pModel = NULL; SColumnModel *pFinalModel = NULL; - pRes->qhandle = 0x1; // hack the qhandle check + pRes->qId = 0x1; // hack the qhandle check const uint32_t nBufferSize = (1u << 16u); // 64KB @@ -2730,7 +2988,7 @@ void tscRetrieveDataRes(void *param, TAOS_RES *tres, int code) { tscDebug("%p sub:%p query complete, ep:%s, vgId:%d, orderOfSub:%d, retrieve data", trsupport->pParentSql, pSql, pVgroup->epAddr[0].fqdn, pVgroup->vgId, trsupport->subqueryIndex); - if (pSql->res.qhandle == 0) { // qhandle is NULL, code is TSDB_CODE_SUCCESS means no results generated from this vnode + if (pSql->res.qId == 0) { // qhandle is NULL, code is TSDB_CODE_SUCCESS means no results generated from this vnode tscRetrieveFromDnodeCallBack(param, pSql, 0); } else { taos_fetch_rows_a(tres, tscRetrieveFromDnodeCallBack, param); diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index e899450261..8d320c9a83 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -1279,6 +1279,34 @@ int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deepco return 0; } +bool tscColumnExists(SArray* pColumnList, SColumnIndex* pColIndex) { + // ignore the tbname columnIndex to be inserted into source list + if (pColIndex->columnIndex < 0) { + return false; + } + + size_t numOfCols = taosArrayGetSize(pColumnList); + int16_t col = pColIndex->columnIndex; + + int32_t i = 0; + while (i < numOfCols) { + SColumn* pCol = taosArrayGetP(pColumnList, i); + if ((pCol->colIndex.columnIndex != col) || (pCol->colIndex.tableIndex != pColIndex->tableIndex)) { + ++i; + continue; + } else { + break; + } + } + + if (i >= numOfCols || numOfCols == 0) { + return false; + } + + return true; +} + + SColumn* tscColumnListInsert(SArray* pColumnList, SColumnIndex* pColIndex) { // ignore the tbname columnIndex to be inserted into source list if (pColIndex->columnIndex < 0) { @@ -1583,7 +1611,25 @@ int32_t tscTagCondCopy(STagCond* dest, const STagCond* src) { dest->tbnameCond.uid = src->tbnameCond.uid; dest->tbnameCond.len = src->tbnameCond.len; - memcpy(&dest->joinInfo, &src->joinInfo, sizeof(SJoinInfo)); + dest->joinInfo.hasJoin = src->joinInfo.hasJoin; + + for (int32_t i = 0; i < TSDB_MAX_JOIN_TABLE_NUM; ++i) { + if (src->joinInfo.joinTables[i]) { + dest->joinInfo.joinTables[i] = calloc(1, sizeof(SJoinNode)); + + memcpy(dest->joinInfo.joinTables[i], src->joinInfo.joinTables[i], sizeof(SJoinNode)); + + if (src->joinInfo.joinTables[i]->tsJoin) { + dest->joinInfo.joinTables[i]->tsJoin = taosArrayDup(src->joinInfo.joinTables[i]->tsJoin); + } + + if (src->joinInfo.joinTables[i]->tagJoin) { + dest->joinInfo.joinTables[i]->tagJoin = taosArrayDup(src->joinInfo.joinTables[i]->tagJoin); + } + } + } + + dest->relType = src->relType; if (src->pCond == NULL) { @@ -1629,6 +1675,23 @@ void tscTagCondRelease(STagCond* pTagCond) { taosArrayDestroy(pTagCond->pCond); } + for (int32_t i = 0; i < TSDB_MAX_JOIN_TABLE_NUM; ++i) { + SJoinNode *node = pTagCond->joinInfo.joinTables[i]; + if (node == NULL) { + continue; + } + + if (node->tsJoin != NULL) { + taosArrayDestroy(node->tsJoin); + } + + if (node->tagJoin != NULL) { + taosArrayDestroy(node->tagJoin); + } + + tfree(node); + } + memset(pTagCond, 0, sizeof(STagCond)); } @@ -2318,16 +2381,21 @@ void tscDoQuery(SSqlObj* pSql) { } int16_t tscGetJoinTagColIdByUid(STagCond* pTagCond, uint64_t uid) { - if (pTagCond->joinInfo.left.uid == uid) { - return pTagCond->joinInfo.left.tagColId; - } else if (pTagCond->joinInfo.right.uid == uid) { - return pTagCond->joinInfo.right.tagColId; - } else { - assert(0); - return -1; + int32_t i = 0; + while (i < TSDB_MAX_JOIN_TABLE_NUM) { + SJoinNode* node = pTagCond->joinInfo.joinTables[i]; + if (node && node->uid == uid) { + return node->tagColId; + } + + i++; } + + assert(0); + return -1; } + int16_t tscGetTagColIndexById(STableMeta* pTableMeta, int16_t colId) { int32_t numOfTags = tscGetNumOfTags(pTableMeta); diff --git a/src/common/inc/tcmdtype.h b/src/common/inc/tcmdtype.h index bec8590536..be16e80124 100644 --- a/src/common/inc/tcmdtype.h +++ b/src/common/inc/tcmdtype.h @@ -51,6 +51,7 @@ enum { TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_ACCT, "alter-acct" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_TABLE, "alter-table" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_DB, "alter-db" ) + TSDB_DEFINE_SQL_TYPE(TSDB_SQL_SYNC_DB_REPLICA, "sync db-replica") TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_MNODE, "create-mnode" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_DROP_MNODE, "drop-mnode" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_DNODE, "create-dnode" ) @@ -87,13 +88,13 @@ enum { */ TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RETRIEVE_EMPTY_RESULT, "retrieve-empty-result" ) - TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RESET_CACHE, "reset-cache" ) - TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_STATUS, "serv-status" ) - TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_DB, "current-db" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RESET_CACHE, "reset-cache" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_STATUS, "serv-status" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_DB, "current-db" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_VERSION, "serv-version" ) - TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CLI_VERSION, "cli-version" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CLI_VERSION, "cli-version" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_USER, "current-user ") - TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CFG_LOCAL, "cfg-local" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CFG_LOCAL, "cfg-local" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_MAX, "max" ) }; diff --git a/src/common/src/tglobal.c b/src/common/src/tglobal.c index 4a5df9361b..5f4ce046ed 100644 --- a/src/common/src/tglobal.c +++ b/src/common/src/tglobal.c @@ -51,7 +51,7 @@ int32_t tsMaxShellConns = 50000; int32_t tsMaxConnections = 5000; int32_t tsShellActivityTimer = 3; // second float tsNumOfThreadsPerCore = 1.0f; -int32_t tsNumOfCommitThreads = 1; +int32_t tsNumOfCommitThreads = 4; float tsRatioOfQueryCores = 1.0f; int8_t tsDaylight = 0; char tsTimezone[TSDB_TIMEZONE_LEN] = {0}; @@ -71,7 +71,7 @@ int32_t tsMaxBinaryDisplayWidth = 30; int32_t tsCompressMsgSize = -1; // client -int32_t tsMaxSQLStringLen = TSDB_MAX_SQL_LEN; +int32_t tsMaxSQLStringLen = TSDB_MAX_ALLOWED_SQL_LEN; int8_t tsTscEnableRecordSql = 0; // the maximum number of results for projection query on super table that are returned from diff --git a/src/connector/jdbc/CMakeLists.txt b/src/connector/jdbc/CMakeLists.txt index 86ddfcb022..540dc8eb58 100644 --- a/src/connector/jdbc/CMakeLists.txt +++ b/src/connector/jdbc/CMakeLists.txt @@ -8,7 +8,7 @@ IF (TD_MVN_INSTALLED) ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME} POST_BUILD COMMAND mvn -Dmaven.test.skip=true install -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.22-dist.jar ${LIBRARY_OUTPUT_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.24-dist.jar ${LIBRARY_OUTPUT_PATH} COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml COMMENT "build jdbc driver") ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME}) diff --git a/src/connector/jdbc/deploy-pom.xml b/src/connector/jdbc/deploy-pom.xml index fe93e54c69..935b3f7e4a 100755 --- a/src/connector/jdbc/deploy-pom.xml +++ b/src/connector/jdbc/deploy-pom.xml @@ -5,7 +5,7 @@ com.taosdata.jdbc taos-jdbcdriver - 2.0.22 + 2.0.24 jar JDBCDriver @@ -37,17 +37,6 @@ - - commons-logging - commons-logging - 1.2 - - - * - * - - - junit junit @@ -61,21 +50,20 @@ httpclient 4.5.8 - - org.apache.commons - commons-lang3 - 3.9 - com.alibaba fastjson 1.2.58 + + com.google.guava + guava + 29.0-jre + - org.apache.maven.plugins maven-assembly-plugin diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml index 51cb0b3808..5d7c89e2d2 100755 --- a/src/connector/jdbc/pom.xml +++ b/src/connector/jdbc/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.taosdata.jdbc taos-jdbcdriver - 2.0.22 + 2.0.24 jar JDBCDriver https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc @@ -43,7 +43,6 @@ 4.13 test - org.apache.httpcomponents @@ -55,7 +54,11 @@ fastjson 1.2.58 - + + com.google.guava + guava + 29.0-jre + diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java index a2496b0099..976078da95 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java @@ -30,9 +30,12 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); // do nothing + return sql; } + + @Override public void setAutoCommit(boolean autoCommit) throws SQLException { if (isClosed()) @@ -448,7 +451,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti if (isClosed) throw (SQLClientInfoException) TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED); - for (Enumeration enumer = properties.keys(); enumer.hasMoreElements(); ) { String name = (String) enumer.nextElement(); clientInfoProps.put(name, properties.getProperty(name)); diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractParameterMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractParameterMetaData.java new file mode 100644 index 0000000000..999df06fc7 --- /dev/null +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractParameterMetaData.java @@ -0,0 +1,138 @@ +package com.taosdata.jdbc; + +import java.sql.ParameterMetaData; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; + +public abstract class AbstractParameterMetaData extends WrapperImpl implements ParameterMetaData { + + private final Object[] parameters; + + public AbstractParameterMetaData(Object[] parameters) { + this.parameters = parameters; + } + + @Override + public int getParameterCount() throws SQLException { + return parameters.length; + } + + @Override + public int isNullable(int param) throws SQLException { + return ParameterMetaData.parameterNullableUnknown; + } + + @Override + public boolean isSigned(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + if (parameters[param - 1] instanceof Byte) + return true; + if (parameters[param - 1] instanceof Short) + return true; + if (parameters[param - 1] instanceof Integer) + return true; + if (parameters[param - 1] instanceof Long) + return true; + if (parameters[param - 1] instanceof Float) + return true; + if (parameters[param - 1] instanceof Double) + return true; + + return false; + } + + @Override + public int getPrecision(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + if (parameters[param - 1] instanceof String) + return ((String) parameters[param - 1]).length(); + if (parameters[param - 1] instanceof byte[]) + return ((byte[]) parameters[param - 1]).length; + return 0; + } + + @Override + public int getScale(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + return 0; + } + + @Override + public int getParameterType(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + if (parameters[param - 1] instanceof Timestamp) + return Types.TIMESTAMP; + if (parameters[param - 1] instanceof Byte) + return Types.TINYINT; + if (parameters[param - 1] instanceof Short) + return Types.SMALLINT; + if (parameters[param - 1] instanceof Integer) + return Types.INTEGER; + if (parameters[param - 1] instanceof Long) + return Types.BIGINT; + if (parameters[param - 1] instanceof Float) + return Types.FLOAT; + if (parameters[param - 1] instanceof Double) + return Types.DOUBLE; + if (parameters[param - 1] instanceof String) + return Types.NCHAR; + if (parameters[param - 1] instanceof byte[]) + return Types.BINARY; + if (parameters[param - 1] instanceof Boolean) + return Types.BOOLEAN; + return Types.OTHER; + } + + @Override + public String getParameterTypeName(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + if (parameters[param - 1] instanceof Timestamp) + return TSDBConstants.jdbcType2TaosTypeName(Types.TIMESTAMP); + if (parameters[param - 1] instanceof Byte) + return TSDBConstants.jdbcType2TaosTypeName(Types.TINYINT); + if (parameters[param - 1] instanceof Short) + return TSDBConstants.jdbcType2TaosTypeName(Types.SMALLINT); + if (parameters[param - 1] instanceof Integer) + return TSDBConstants.jdbcType2TaosTypeName(Types.INTEGER); + if (parameters[param - 1] instanceof Long) + return TSDBConstants.jdbcType2TaosTypeName(Types.BIGINT); + if (parameters[param - 1] instanceof Float) + return TSDBConstants.jdbcType2TaosTypeName(Types.FLOAT); + if (parameters[param - 1] instanceof Double) + return TSDBConstants.jdbcType2TaosTypeName(Types.DOUBLE); + if (parameters[param - 1] instanceof String) + return TSDBConstants.jdbcType2TaosTypeName(Types.NCHAR); + if (parameters[param - 1] instanceof byte[]) + return TSDBConstants.jdbcType2TaosTypeName(Types.BINARY); + if (parameters[param - 1] instanceof Boolean) + return TSDBConstants.jdbcType2TaosTypeName(Types.BOOLEAN); + + return parameters[param - 1].getClass().getName(); + } + + @Override + public String getParameterClassName(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + return parameters[param - 1].getClass().getName(); + } + + @Override + public int getParameterMode(int param) throws SQLException { + if (param < 1 && param >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + return ParameterMetaData.parameterModeUnknown; + } +} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractResultSet.java index 238d18039d..abd348e68c 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractResultSet.java @@ -11,6 +11,15 @@ import java.util.Map; public abstract class AbstractResultSet extends WrapperImpl implements ResultSet { private int fetchSize; + protected void checkAvailability(int columnIndex, int bounds) throws SQLException { + if (isClosed()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); + if (columnIndex < 1) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " < 1"); + if (columnIndex > bounds) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + bounds); + } + @Override public abstract boolean next() throws SQLException; @@ -46,38 +55,20 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet @Override public abstract double getDouble(int columnIndex) throws SQLException; + @Deprecated @Override public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getBigDecimal(columnIndex); } @Override - public byte[] getBytes(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public abstract byte[] getBytes(int columnIndex) throws SQLException; @Override - public Date getDate(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - - } + public abstract Date getDate(int columnIndex) throws SQLException; @Override - public Time getTime(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public abstract Time getTime(int columnIndex) throws SQLException; @Override public abstract Timestamp getTimestamp(int columnIndex) throws SQLException; @@ -147,9 +138,10 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet return getDouble(findColumn(columnLabel)); } + @Deprecated @Override public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { - return getBigDecimal(findColumn(columnLabel)); + return getBigDecimal(findColumn(columnLabel), scale); } @Override @@ -214,12 +206,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet public abstract ResultSetMetaData getMetaData() throws SQLException; @Override - public Object getObject(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public abstract Object getObject(int columnIndex) throws SQLException; @Override public Object getObject(String columnLabel) throws SQLException { @@ -243,12 +230,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet } @Override - public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public abstract BigDecimal getBigDecimal(int columnIndex) throws SQLException; @Override public BigDecimal getBigDecimal(String columnLabel) throws SQLException { @@ -718,9 +700,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet @Override public Object getObject(String columnLabel, Map> map) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getObject(findColumn(columnLabel), map); } @Override @@ -760,9 +740,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet @Override public Date getDate(String columnLabel, Calendar cal) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getDate(findColumn(columnLabel), cal); } @Override @@ -774,23 +752,15 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet @Override public Time getTime(String columnLabel, Calendar cal) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getTime(findColumn(columnLabel), cal); } @Override - public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public abstract Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException; @Override public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getTimestamp(findColumn(columnLabel), cal); } @Override @@ -1198,9 +1168,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet @Override public T getObject(String columnLabel, Class type) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + return getObject(findColumn(columnLabel), type); } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java index 8b6c074d1b..9dc559339a 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java @@ -9,6 +9,8 @@ public abstract class AbstractStatement extends WrapperImpl implements Statement protected List batchedArgs; private int fetchSize; + + @Override public abstract ResultSet executeQuery(String sql) throws SQLException; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/SavedPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/SavedPreparedStatement.java deleted file mode 100644 index 512fcd26b8..0000000000 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/SavedPreparedStatement.java +++ /dev/null @@ -1,452 +0,0 @@ -package com.taosdata.jdbc; - -import com.taosdata.jdbc.bean.TSDBPreparedParam; - -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * this class is used to precompile the sql of tdengine insert or import ops - */ -public class SavedPreparedStatement { - - private TSDBPreparedStatement tsdbPreparedStatement; - - /** - * sql param List - */ - private List sqlParamList; - - /** - * init param according the sql - */ - private TSDBPreparedParam initPreparedParam; - - /** - * is table name dynamic in the prepared sql - */ - private boolean isTableNameDynamic; - - /** - * insert or import sql template pattern, the template are the following: - *

- * insert/import into tableName [(field1, field2, ...)] [using stables tags(?, ?, ...) ] values(?, ?, ...) (?, ?, ...) - *

- * we split it to three part: - * 1. prefix, insert/import - * 2. middle, tableName [(field1, field2, ...)] [using stables tags(?, ?, ...) ] - * 3. valueList, the content after values, for example (?, ?, ...) (?, ?, ...) - */ - private Pattern sqlPattern = Pattern.compile("(?s)(?i)^\\s*(INSERT|IMPORT)\\s+INTO\\s+((?\\S+)\\s*(\\(.*\\))?\\s+(USING\\s+(?\\S+)\\s+TAGS\\s*\\((?.+)\\))?)\\s*VALUES\\s*(?\\(.*\\)).*"); - - /** - * the raw sql template - */ - private String sql; - - /** - * the prefix part of sql - */ - private String prefix; - - /** - * the middle part of sql - */ - private String middle; - - private int middleParamSize; - - /** - * the valueList part of sql - */ - private String valueList; - - private int valueListSize; - - /** - * default param value - */ - private static final String DEFAULT_VALUE = "NULL"; - - private static final String PLACEHOLDER = "?"; - - private String tableName; - - /** - * is the parameter add to batch list - */ - private boolean isAddBatch; - - public SavedPreparedStatement(String sql, TSDBPreparedStatement tsdbPreparedStatement) throws SQLException { - this.sql = sql; - this.tsdbPreparedStatement = tsdbPreparedStatement; - this.sqlParamList = new ArrayList<>(); - - parsePreparedParam(this.sql); - } - - /** - * parse the init param according the sql param - * - * @param sql - */ - private void parsePreparedParam(String sql) throws SQLException { - - Matcher matcher = sqlPattern.matcher(sql); - - if (matcher.find()) { - - tableName = matcher.group("tablename"); - - if (tableName != null && PLACEHOLDER.equals(tableName)) { - // the table name is dynamic - this.isTableNameDynamic = true; - } - - prefix = matcher.group(1); - middle = matcher.group(2); - valueList = matcher.group("valueList"); - - if (middle != null && !"".equals(middle)) { - middleParamSize = parsePlaceholder(middle); - } - - if (valueList != null && !"".equals(valueList)) { - valueListSize = parsePlaceholder(valueList); - } - - initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize); - - } else { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_SQL); - } - - } - - private TSDBPreparedParam initDefaultParam(String tableName, int middleParamSize, int valueListSize) { - - TSDBPreparedParam tsdbPreparedParam = new TSDBPreparedParam(tableName); - - tsdbPreparedParam.setMiddleParamList(getDefaultParamList(middleParamSize)); - - tsdbPreparedParam.setValueList(getDefaultParamList(valueListSize)); - - return tsdbPreparedParam; - } - - /** - * generate the default param value list - * - * @param paramSize - * @return - */ - private List getDefaultParamList(int paramSize) { - - List paramList = new ArrayList<>(paramSize); - if (paramSize > 0) { - for (int i = 0; i < paramSize; i++) { - paramList.add(i, DEFAULT_VALUE); - } - } - - return paramList; - } - - /** - * calculate the placeholder num - * - * @param value - * @return - */ - private int parsePlaceholder(String value) { - - Pattern pattern = Pattern.compile("[?]"); - - Matcher matcher = pattern.matcher(value); - - int result = 0; - while (matcher.find()) { - result++; - } - return result; - } - - /** - * set current row params - * - * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param x the parameter value - */ - public void setParam(int parameterIndex, Object x) throws SQLException { - - int paramSize = this.middleParamSize + this.valueListSize; - - String errorMsg = String.format("the parameterIndex %s out of the range [1, %s]", parameterIndex, paramSize); - - if (parameterIndex < 1 || parameterIndex > paramSize) { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE,errorMsg); - } - - this.isAddBatch = false; //set isAddBatch to false - - if (x == null) { - x = DEFAULT_VALUE; // set default null string - } - - parameterIndex = parameterIndex - 1; // start from 0 in param list - - if (this.middleParamSize > 0 && parameterIndex >= 0 && parameterIndex < this.middleParamSize) { - - this.initPreparedParam.setMiddleParam(parameterIndex, x); - return; - } - - if (this.valueListSize > 0 && parameterIndex >= this.middleParamSize && parameterIndex < paramSize) { - - this.initPreparedParam.setValueParam(parameterIndex - this.middleParamSize, x); - return; - } - - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE,errorMsg); - } - - public void addBatch() { - - addCurrentRowParamToList(); - this.initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize); - } - - /** - * add current param to batch list - */ - private void addCurrentRowParamToList() { - - if (initPreparedParam != null && (this.middleParamSize > 0 || this.valueListSize > 0)) { - this.sqlParamList.add(initPreparedParam); // add current param to batch list - } - this.isAddBatch = true; - } - - - /** - * execute the sql with batch sql - * - * @return - * @throws SQLException - */ - public int[] executeBatch() throws SQLException { - - int result = executeBatchInternal(); - - return new int[]{result}; - } - - - public int executeBatchInternal() throws SQLException { - - if (!isAddBatch) { - addCurrentRowParamToList(); // add current param to batch list - } - - //1. generate batch sql - String sql = generateExecuteSql(); - //2. execute batch sql - int result = executeSql(sql); - - //3. clear batch param list - this.sqlParamList.clear(); - - return result; - } - - /** - * generate the batch sql - * - * @return - */ - private String generateExecuteSql() { - - StringBuilder stringBuilder = new StringBuilder(); - - stringBuilder.append(prefix); - stringBuilder.append(" into "); - - if (!isTableNameDynamic) { - // tablename will not need to be replaced - String middleValue = replaceMiddleListParam(middle, sqlParamList); - stringBuilder.append(middleValue); - stringBuilder.append(" values"); - - stringBuilder.append(replaceValueListParam(valueList, sqlParamList)); - - } else { - // need to replace tablename - - if (sqlParamList.size() > 0) { - - TSDBPreparedParam firstPreparedParam = sqlParamList.get(0); - - //replace middle part and value part of first row - String firstRow = replaceMiddleAndValuePart(firstPreparedParam); - stringBuilder.append(firstRow); - - //the first param in the middleParamList is the tableName - String lastTableName = firstPreparedParam.getMiddleParamList().get(0).toString(); - - if (sqlParamList.size() > 1) { - - for (int i = 1; i < sqlParamList.size(); i++) { - TSDBPreparedParam currentParam = sqlParamList.get(i); - String currentTableName = currentParam.getMiddleParamList().get(0).toString(); - if (lastTableName.equalsIgnoreCase(currentTableName)) { - // tablename is same with the last row ,so only need to append the part of value - - String values = replaceTemplateParam(valueList, currentParam.getValueList()); - stringBuilder.append(values); - - } else { - // tablename difference with the last row - //need to replace middle part and value part - String row = replaceMiddleAndValuePart(currentParam); - stringBuilder.append(row); - lastTableName = currentTableName; - } - } - } - - } else { - - stringBuilder.append(middle); - stringBuilder.append(" values"); - stringBuilder.append(valueList); - } - - } - - return stringBuilder.toString(); - } - - /** - * replace the middle and value part - * - * @param tsdbPreparedParam - * @return - */ - private String replaceMiddleAndValuePart(TSDBPreparedParam tsdbPreparedParam) { - - StringBuilder stringBuilder = new StringBuilder(" "); - - String middlePart = replaceTemplateParam(middle, tsdbPreparedParam.getMiddleParamList()); - - stringBuilder.append(middlePart); - stringBuilder.append(" values "); - - String valuePart = replaceTemplateParam(valueList, tsdbPreparedParam.getValueList()); - stringBuilder.append(valuePart); - stringBuilder.append(" "); - - return stringBuilder.toString(); - } - - /** - * replace the placeholder of the middle part of sql template with TSDBPreparedParam list - * - * @param template - * @param sqlParamList - * @return - */ - private String replaceMiddleListParam(String template, List sqlParamList) { - - if (sqlParamList.size() > 0) { - - //becase once the subTableName is static then will be ignore the tag which after the first setTag - return replaceTemplateParam(template, sqlParamList.get(0).getMiddleParamList()); - - } - - return template; - } - - - /** - * replace the placeholder of the template with TSDBPreparedParam list - * - * @param template - * @param sqlParamList - * @return - */ - private String replaceValueListParam(String template, List sqlParamList) { - - StringBuilder stringBuilder = new StringBuilder(); - - if (sqlParamList.size() > 0) { - - for (TSDBPreparedParam tsdbPreparedParam : sqlParamList) { - - String tmp = replaceTemplateParam(template, tsdbPreparedParam.getValueList()); - - stringBuilder.append(tmp); - } - - } else { - stringBuilder.append(template); - } - - return stringBuilder.toString(); - } - - /** - * replace the placeholder of the template with paramList - * - * @param template - * @param paramList - * @return - */ - private String replaceTemplateParam(String template, List paramList) { - - if (paramList.size() > 0) { - - String tmp = template; - - for (int i = 0; i < paramList.size(); ++i) { - - String paraStr = getParamString(paramList.get(i)); - - tmp = tmp.replaceFirst("[" + PLACEHOLDER + "]", paraStr); - - } - - return tmp; - - } else { - return template; - } - - } - - /** - * get the string of param object - * - * @param paramObj - * @return - */ - private String getParamString(Object paramObj) { - - String paraStr = paramObj.toString(); - if (paramObj instanceof Timestamp || (paramObj instanceof String && !DEFAULT_VALUE.equalsIgnoreCase(paraStr))) { - paraStr = "'" + paraStr + "'"; - } - return paraStr; - } - - - private int executeSql(String sql) throws SQLException { - - return tsdbPreparedStatement.executeUpdate(sql); - } - -} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConnection.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConnection.java index a8653eb172..5b4615485d 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConnection.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConnection.java @@ -27,10 +27,6 @@ public class TSDBConnection extends AbstractConnection { return this.batchFetch; } - public void setBatchFetch(Boolean batchFetch) { - this.batchFetch = batchFetch; - } - public TSDBConnection(Properties info, TSDBDatabaseMetaData meta) throws SQLException { this.databaseMetaData = meta; connect(info.getProperty(TSDBDriver.PROPERTY_KEY_HOST), @@ -61,9 +57,7 @@ public class TSDBConnection extends AbstractConnection { throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); } - TSDBStatement statement = new TSDBStatement(this, this.connector); - statement.setConnection(this); - return statement; + return new TSDBStatement(this, this.connector); } public TSDBSubscribe subscribe(String topic, String sql, boolean restart) throws SQLException { @@ -79,10 +73,8 @@ public class TSDBConnection extends AbstractConnection { } public PreparedStatement prepareStatement(String sql) throws SQLException { - if (isClosed()) { + if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); - } - return new TSDBPreparedStatement(this, this.connector, sql); } @@ -104,11 +96,4 @@ public class TSDBConnection extends AbstractConnection { return this.databaseMetaData; } - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - if (isClosed()) { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); - } - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } - -} +} \ No newline at end of file diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBParameterMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBParameterMetaData.java new file mode 100644 index 0000000000..9ee23e3a26 --- /dev/null +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBParameterMetaData.java @@ -0,0 +1,8 @@ +package com.taosdata.jdbc; + +public class TSDBParameterMetaData extends AbstractParameterMetaData { + + public TSDBParameterMetaData(Object[] parameters) { + super(parameters); + } +} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java index d294c89745..728b537f71 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; +import java.nio.charset.Charset; import java.sql.*; import java.util.ArrayList; import java.util.Calendar; @@ -30,36 +31,49 @@ import java.util.regex.Pattern; * compatibility needs. */ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement { - protected String rawSql; - protected String sql; - protected ArrayList parameters = new ArrayList<>(); + + private String rawSql; + private String sql; + // private ArrayList parameters = new ArrayList<>(); + private Object[] parameters; + private boolean isPrepared; //start with insert or import and is case-insensitive private static Pattern savePattern = Pattern.compile("(?i)^\\s*(insert|import)"); - // is insert or import private boolean isSaved; - private SavedPreparedStatement savedPreparedStatement; - private ParameterMetaData parameterMetaData; + // private SavedPreparedStatement savedPreparedStatement; + private volatile TSDBParameterMetaData parameterMetaData; TSDBPreparedStatement(TSDBConnection connection, TSDBJNIConnector connecter, String sql) { super(connection, connecter); init(sql); + + if (sql.contains("?")) { + int parameterCnt = 0; + for (int i = 0; i < sql.length(); i++) { + if ('?' == sql.charAt(i)) { + parameterCnt++; + } + } + parameters = new Object[parameterCnt]; + this.isPrepared = true; + } } private void init(String sql) { this.rawSql = sql; preprocessSql(); +// this.isSaved = isSavedSql(this.rawSql); +// if (this.isSaved) { +// try { +// this.savedPreparedStatement = new SavedPreparedStatement(this.rawSql, this); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// } - this.isSaved = isSavedSql(this.rawSql); - if (this.isSaved) { - try { - this.savedPreparedStatement = new SavedPreparedStatement(this.rawSql, this); - } catch (SQLException e) { - e.printStackTrace(); - } - } } /** @@ -75,19 +89,11 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat @Override public int[] executeBatch() throws SQLException { - if (isSaved) { - return this.savedPreparedStatement.executeBatch(); - } else { - return super.executeBatch(); - } - } - - public ArrayList getParameters() { - return parameters; - } - - public void setParameters(ArrayList parameters) { - this.parameters = parameters; +// if (isSaved) { +// return this.savedPreparedStatement.executeBatch(); +// } else { + return super.executeBatch(); +// } } /* @@ -151,41 +157,73 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat * * @return a string of the native sql statement for TSDB */ - private String getNativeSql() { - this.sql = this.rawSql; - for (int i = 0; i < parameters.size(); ++i) { - Object para = parameters.get(i); +// private String getNativeSql(String rawSql) { +// for (int i = 0; i < parameters.length; i++) { +// Object para = parameters[i]; +// if (para != null) { +// String paraStr = para.toString(); +// if (para instanceof Timestamp || para instanceof String) { +// paraStr = "'" + paraStr + "'"; +// } +// this.sql = this.sql.replaceFirst("[?]", paraStr); +// } else { +// this.sql = this.sql.replaceFirst("[?]", "NULL"); +// } +// } +// parameters = new Object[parameters.length]; +// return sql; +// } + + private String getNativeSql(String rawSql) throws SQLException { + String sql = rawSql; + for (int i = 0; i < parameters.length; ++i) { + Object para = parameters[i]; if (para != null) { - String paraStr = para.toString(); - if (para instanceof Timestamp || para instanceof String) { + String paraStr; + if (para instanceof byte[]) { + paraStr = new String((byte[]) para, Charset.forName("UTF-8")); + } else { + paraStr = para.toString(); + } + // if para is timestamp or String or byte[] need to translate ' character + if (para instanceof Timestamp || para instanceof String || para instanceof byte[]) { + paraStr = paraStr.replaceAll("'", "\\\\\\\\'"); paraStr = "'" + paraStr + "'"; } - this.sql = this.sql.replaceFirst("[?]", paraStr); + sql = sql.replaceFirst("[?]", paraStr); } else { - this.sql = this.sql.replaceFirst("[?]", "NULL"); + sql = sql.replaceFirst("[?]", "NULL"); } } - parameters.clear(); + clearParameters(); return sql; } @Override public ResultSet executeQuery() throws SQLException { - if (isSaved) { - this.savedPreparedStatement.executeBatchInternal(); - return null; - } else { - return super.executeQuery(getNativeSql()); - } +// if (isSaved) { +// this.savedPreparedStatement.executeBatchInternal(); +// return null; +// } else { + + if (!isPrepared) + return executeQuery(this.rawSql); + + final String sql = getNativeSql(this.rawSql); + return executeQuery(sql); +// } } @Override public int executeUpdate() throws SQLException { - if (isSaved) { - return this.savedPreparedStatement.executeBatchInternal(); - } else { - return super.executeUpdate(getNativeSql()); - } +// if (isSaved) { +// return this.savedPreparedStatement.executeBatchInternal(); +// } else { + if (!isPrepared) + return executeUpdate(this.rawSql); + String sql = getNativeSql(this.rawSql); + return executeUpdate(sql); +// } } private boolean isSupportedSQLType(int sqlType) { @@ -201,35 +239,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat case Types.BINARY: case Types.NCHAR: return true; - case Types.ARRAY: - case Types.BIT: - case Types.BLOB: - case Types.CHAR: - case Types.CLOB: - case Types.DATALINK: - case Types.DATE: - case Types.DECIMAL: - case Types.DISTINCT: - case Types.JAVA_OBJECT: - case Types.LONGNVARCHAR: - case Types.LONGVARBINARY: - case Types.LONGVARCHAR: - case Types.NCLOB: - case Types.NULL: - case Types.NUMERIC: - case Types.NVARCHAR: - case Types.OTHER: - case Types.REAL: - case Types.REF: - case Types.REF_CURSOR: - case Types.ROWID: - case Types.SQLXML: - case Types.STRUCT: - case Types.TIME: - case Types.TIME_WITH_TIMEZONE: - case Types.TIMESTAMP_WITH_TIMEZONE: - case Types.VARBINARY: - case Types.VARCHAR: default: return false; } @@ -259,7 +268,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat public void setByte(int parameterIndex, byte x) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + setObject(parameterIndex,x); } @Override @@ -315,7 +324,8 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat public void setBytes(int parameterIndex, byte[] x) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + + setObject(parameterIndex,x); } @Override @@ -365,45 +375,63 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat public void clearParameters() throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - parameters.clear(); + +// parameters.clear(); + parameters = new Object[parameters.length]; } @Override public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); } @Override public void setObject(int parameterIndex, Object x) throws SQLException { - if (isSaved) { - this.savedPreparedStatement.setParam(parameterIndex, x); - } else { - parameters.add(x); - } +// if (isSaved) { +// this.savedPreparedStatement.setParam(parameterIndex, x); +// } else { + if (parameterIndex < 1 && parameterIndex >= parameters.length) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); + + parameters[parameterIndex - 1] = x; +// parameters.add(x); +// } } @Override public boolean execute() throws SQLException { - if (isSaved) { - int result = this.savedPreparedStatement.executeBatchInternal(); - return result > 0; - } else { - return super.execute(getNativeSql()); - } +// if (isSaved) { +// int result = this.savedPreparedStatement.executeBatchInternal(); +// return result > 0; +// } else { + if (!isPrepared) + return execute(this.rawSql); + + final String sql = getNativeSql(this.rawSql); + + return execute(sql); +// } } @Override public void addBatch() throws SQLException { - if (isSaved) { - this.savedPreparedStatement.addBatch(); - } else { - if (this.batchedArgs == null) { - batchedArgs = new ArrayList<>(); - } - super.addBatch(getNativeSql()); +// if (isSaved) { +// this.savedPreparedStatement.addBatch(); +// } else { + if (this.batchedArgs == null) { + batchedArgs = new ArrayList<>(); } + + if (!isPrepared) { + addBatch(this.rawSql); + } else { + String sql = this.getConnection().nativeSQL(this.rawSql); + addBatch(sql); + } +// } } @Override @@ -491,9 +519,11 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat public ParameterMetaData getParameterMetaData() throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - //TODO: parameterMetaData not supported -// return null; - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + + if (parameterMetaData == null) { + this.parameterMetaData = new TSDBParameterMetaData(parameters); + } + return this.parameterMetaData; } @Override diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java index 7c2940fdc2..a20ddaa836 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java @@ -14,9 +14,14 @@ *****************************************************************************/ package com.taosdata.jdbc; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; + import java.math.BigDecimal; import java.sql.*; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; public class TSDBResultSet extends AbstractResultSet implements ResultSet { @@ -120,158 +125,189 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { } public String getString(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + String res = null; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return this.blockData.getString(colIndex); + return this.blockData.getString(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getString(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public boolean getBoolean(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + boolean res = false; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return this.blockData.getBoolean(colIndex); + return this.blockData.getBoolean(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getBoolean(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public byte getByte(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + byte res = 0; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return (byte) this.blockData.getInt(colIndex); + return (byte) this.blockData.getInt(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = (byte) this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public short getShort(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + short res = 0; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return (short) this.blockData.getInt(colIndex); + return (short) this.blockData.getInt(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = (short) this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public int getInt(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + int res = 0; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return this.blockData.getInt(colIndex); + return this.blockData.getInt(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public long getLong(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + long res = 0L; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return this.blockData.getLong(colIndex); + return this.blockData.getLong(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getLong(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } public float getFloat(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + float res = 0; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return (float) this.blockData.getDouble(colIndex); + return (float) this.blockData.getDouble(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) - res = this.rowData.getFloat(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getFloat(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); return res; } public double getDouble(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + double res = 0; - int colIndex = getTrueColumnIndex(columnIndex); - if (this.getBatchFetch()) - return this.blockData.getDouble(colIndex); + return this.blockData.getDouble(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType()); + res = this.rowData.getDouble(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType()); } return res; } - @Deprecated - public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - return new BigDecimal(getLong(columnIndex)); + public byte[] getBytes(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + + Object value = this.rowData.get(columnIndex - 1); + if (value == null) + return null; + + int colType = this.columnMetaDataList.get(columnIndex - 1).getColType(); + switch (colType) { + case TSDBConstants.TSDB_DATA_TYPE_BIGINT: + return Longs.toByteArray((Long) value); + case TSDBConstants.TSDB_DATA_TYPE_INT: + return Ints.toByteArray((int) value); + case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + return Shorts.toByteArray((Short) value); + case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + return new byte[]{(byte) value}; + } + return value.toString().getBytes(); } - public byte[] getBytes(int columnIndex) throws SQLException { - return getString(columnIndex).getBytes(); + @Override + public Date getDate(int columnIndex) throws SQLException { + Timestamp timestamp = getTimestamp(columnIndex); + return timestamp == null ? null : new Date(timestamp.getTime()); + } + + @Override + public Time getTime(int columnIndex) throws SQLException { + Timestamp timestamp = getTimestamp(columnIndex); + return timestamp == null ? null : new Time(timestamp.getTime()); } public Timestamp getTimestamp(int columnIndex) throws SQLException { + checkAvailability(columnIndex, this.columnMetaDataList.size()); + Timestamp res = null; - int colIndex = getTrueColumnIndex(columnIndex); if (this.getBatchFetch()) - return this.blockData.getTimestamp(columnIndex); + return this.blockData.getTimestamp(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); if (!lastWasNull) { - res = this.rowData.getTimestamp(colIndex); + res = this.rowData.getTimestamp(columnIndex - 1); } return res; } public ResultSetMetaData getMetaData() throws SQLException { + if (isClosed()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); + return new TSDBResultSetMetaData(this.columnMetaDataList); } @Override public Object getObject(int columnIndex) throws SQLException { - int colIndex = getTrueColumnIndex(columnIndex); + checkAvailability(columnIndex, this.columnMetaDataList.size()); + Object res = null; if (this.getBatchFetch()) - return this.blockData.get(colIndex); + return this.blockData.get(columnIndex - 1); - this.lastWasNull = this.rowData.wasNull(colIndex); - return this.rowData.get(colIndex); - } - - @Override - public Object getObject(String columnLabel) throws SQLException { - return this.getObject(this.findColumn(columnLabel)); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); + if (!lastWasNull) { + int colType = this.columnMetaDataList.get(columnIndex - 1).getColType(); + if (colType == TSDBConstants.TSDB_DATA_TYPE_BINARY) + res = ((String) this.rowData.get(columnIndex - 1)).getBytes(); + else + res = this.rowData.get(columnIndex - 1); + } + return res; } public int findColumn(String columnLabel) throws SQLException { @@ -285,14 +321,31 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - int colIndex = getTrueColumnIndex(columnIndex); + if (this.getBatchFetch()) + return new BigDecimal(this.blockData.getLong(columnIndex - 1)); - if (!this.getBatchFetch()) { - this.lastWasNull = this.rowData.wasNull(colIndex); - return new BigDecimal(this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType())); - } else { - return new BigDecimal(this.blockData.getLong(colIndex)); + this.lastWasNull = this.rowData.wasNull(columnIndex - 1); + BigDecimal res = null; + if (!lastWasNull) { + int colType = this.columnMetaDataList.get(columnIndex - 1).getColType(); + switch (colType) { + case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + case TSDBConstants.TSDB_DATA_TYPE_INT: + case TSDBConstants.TSDB_DATA_TYPE_BIGINT: + res = new BigDecimal(Long.valueOf(this.rowData.get(columnIndex - 1).toString())); + break; + case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: + res = new BigDecimal(Double.valueOf(this.rowData.get(columnIndex - 1).toString())); + break; + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: + return new BigDecimal(((Timestamp) this.rowData.get(columnIndex - 1)).getTime()); + default: + res = new BigDecimal(this.rowData.get(columnIndex - 1).toString()); + } } + return res; } @Override @@ -398,6 +451,12 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { return this.statement; } + @Override + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + //TODO:did not use the specified timezone in cal + return getTimestamp(columnIndex); + } + public boolean isClosed() throws SQLException { if (isClosed) return true; @@ -408,17 +467,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { } public String getNString(int columnIndex) throws SQLException { - int colIndex = getTrueColumnIndex(columnIndex); - return (String) rowData.get(colIndex); + return getString(columnIndex); } - private int getTrueColumnIndex(int columnIndex) throws SQLException { - if (columnIndex < 1) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex(" + columnIndex + "): < 1"); - - int numOfCols = this.columnMetaDataList.size(); - if (columnIndex > numOfCols) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex: " + columnIndex); - return columnIndex - 1; - } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetMetaData.java index 7abd997459..e4ac5303d0 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetMetaData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetMetaData.java @@ -22,136 +22,160 @@ import java.util.List; public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaData { - List colMetaDataList = null; + List colMetaDataList; - public TSDBResultSetMetaData(List metaDataList) { - this.colMetaDataList = metaDataList; - } + public TSDBResultSetMetaData(List metaDataList) { + this.colMetaDataList = metaDataList; + } - public int getColumnCount() throws SQLException { - return colMetaDataList.size(); - } + public int getColumnCount() throws SQLException { + return colMetaDataList.size(); + } - public boolean isAutoIncrement(int column) throws SQLException { - return false; - } + public boolean isAutoIncrement(int column) throws SQLException { + return false; + } - public boolean isCaseSensitive(int column) throws SQLException { - return false; - } + public boolean isCaseSensitive(int column) throws SQLException { + return false; + } - public boolean isSearchable(int column) throws SQLException { - if (column == 1) { - return true; - } - return false; - } + public boolean isSearchable(int column) throws SQLException { + if (column == 1) { + return true; + } + return false; + } - public boolean isCurrency(int column) throws SQLException { - return false; - } + public boolean isCurrency(int column) throws SQLException { + return false; + } - public int isNullable(int column) throws SQLException { - if (column == 1) { - return columnNoNulls; - } - return columnNullable; - } + public int isNullable(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public boolean isSigned(int column) throws SQLException { - ColumnMetaData meta = this.colMetaDataList.get(column - 1); - switch (meta.getColType()) { - case TSDBConstants.TSDB_DATA_TYPE_TINYINT: - case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: - case TSDBConstants.TSDB_DATA_TYPE_INT: - case TSDBConstants.TSDB_DATA_TYPE_BIGINT: - case TSDBConstants.TSDB_DATA_TYPE_FLOAT: - case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: - return true; - default: - return false; - } - } + if (column == 1) { + return columnNoNulls; + } + return columnNullable; + } - public int getColumnDisplaySize(int column) throws SQLException { - return colMetaDataList.get(column - 1).getColSize(); - } + public boolean isSigned(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public String getColumnLabel(int column) throws SQLException { - return colMetaDataList.get(column - 1).getColName(); - } + ColumnMetaData meta = this.colMetaDataList.get(column - 1); + switch (meta.getColType()) { + case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + case TSDBConstants.TSDB_DATA_TYPE_INT: + case TSDBConstants.TSDB_DATA_TYPE_BIGINT: + case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: + return true; + default: + return false; + } + } - public String getColumnName(int column) throws SQLException { - return colMetaDataList.get(column - 1).getColName(); - } + public int getColumnDisplaySize(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public String getSchemaName(int column) throws SQLException { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + return colMetaDataList.get(column - 1).getColSize(); + } - public int getPrecision(int column) throws SQLException { - ColumnMetaData columnMetaData = this.colMetaDataList.get(column - 1); - switch (columnMetaData.getColType()) { - case TSDBConstants.TSDB_DATA_TYPE_FLOAT: - return 5; - case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: - return 9; - case TSDBConstants.TSDB_DATA_TYPE_BINARY: - case TSDBConstants.TSDB_DATA_TYPE_NCHAR: - return columnMetaData.getColSize(); - default: - return 0; - } - } + public String getColumnLabel(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public int getScale(int column) throws SQLException { - ColumnMetaData meta = this.colMetaDataList.get(column - 1); - switch (meta.getColType()) { - case TSDBConstants.TSDB_DATA_TYPE_FLOAT: - return 5; - case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: - return 9; - default: - return 0; - } - } + return colMetaDataList.get(column - 1).getColName(); + } - public String getTableName(int column) throws SQLException { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public String getColumnName(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public String getCatalogName(int column) throws SQLException { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + return colMetaDataList.get(column - 1).getColName(); + } - public int getColumnType(int column) throws SQLException { - ColumnMetaData meta = this.colMetaDataList.get(column - 1); - return TSDBConstants.taosType2JdbcType(meta.getColType()); - } + public String getSchemaName(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public String getColumnTypeName(int column) throws SQLException { - ColumnMetaData meta = this.colMetaDataList.get(column - 1); - return TSDBConstants.taosType2JdbcTypeName(meta.getColType()); - } + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + } - public boolean isReadOnly(int column) throws SQLException { - return true; - } + public int getPrecision(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public boolean isWritable(int column) throws SQLException { - return false; - } + ColumnMetaData columnMetaData = this.colMetaDataList.get(column - 1); + switch (columnMetaData.getColType()) { + case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + return 5; + case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: + return 9; + case TSDBConstants.TSDB_DATA_TYPE_BINARY: + case TSDBConstants.TSDB_DATA_TYPE_NCHAR: + return columnMetaData.getColSize(); + default: + return 0; + } + } - public boolean isDefinitelyWritable(int column) throws SQLException { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); - } + public int getScale(int column) throws SQLException { + if (column < 1 && column >= colMetaDataList.size()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); - public String getColumnClassName(int column) throws SQLException { - int columnType = getColumnType(column); - String columnClassName = ""; - switch (columnType) { - case Types.TIMESTAMP: - columnClassName = Timestamp.class.getName(); + ColumnMetaData meta = this.colMetaDataList.get(column - 1); + switch (meta.getColType()) { + case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + return 5; + case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: + return 9; + default: + return 0; + } + } + + public String getTableName(int column) throws SQLException { + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + } + + public String getCatalogName(int column) throws SQLException { + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + } + + public int getColumnType(int column) throws SQLException { + ColumnMetaData meta = this.colMetaDataList.get(column - 1); + return TSDBConstants.taosType2JdbcType(meta.getColType()); + } + + public String getColumnTypeName(int column) throws SQLException { + ColumnMetaData meta = this.colMetaDataList.get(column - 1); + return TSDBConstants.taosType2JdbcTypeName(meta.getColType()); + } + + public boolean isReadOnly(int column) throws SQLException { + return true; + } + + public boolean isWritable(int column) throws SQLException { + return false; + } + + public boolean isDefinitelyWritable(int column) throws SQLException { + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + } + + public String getColumnClassName(int column) throws SQLException { + int columnType = getColumnType(column); + String columnClassName = ""; + switch (columnType) { + case Types.TIMESTAMP: + columnClassName = Timestamp.class.getName(); break; case Types.CHAR: columnClassName = String.class.getName(); @@ -168,8 +192,8 @@ public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaD case Types.INTEGER: columnClassName = Integer.class.getName(); break; - case Types.SMALLINT: - columnClassName = Short.class.getName(); + case Types.SMALLINT: + columnClassName = Short.class.getName(); break; case Types.TINYINT: columnClassName = Byte.class.getName(); @@ -177,7 +201,7 @@ public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaD case Types.BIT: columnClassName = Boolean.class.getName(); break; - } + } return columnClassName; - } + } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java index 44d760897b..7cf5f0d79a 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java @@ -21,18 +21,13 @@ import java.util.ArrayList; import java.util.Collections; public class TSDBResultSetRowData { - private ArrayList data = null; + private ArrayList data; private int colSize = 0; public TSDBResultSetRowData(int colSize) { this.setColSize(colSize); } - public TSDBResultSetRowData() { - this.data = new ArrayList<>(); - this.setColSize(0); - } - public void clear() { if (this.data != null) { this.data.clear(); @@ -71,9 +66,9 @@ public class TSDBResultSetRowData { case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return ((Long) obj) == 1L ? Boolean.TRUE : Boolean.FALSE; + default: + return false; } - - return Boolean.TRUE; } public void setByte(int col, byte value) { @@ -198,7 +193,7 @@ public class TSDBResultSetRowData { data.set(col, value); } - public float getFloat(int col, int srcType) throws SQLException { + public float getFloat(int col, int srcType) { Object obj = data.get(col); switch (srcType) { @@ -226,7 +221,7 @@ public class TSDBResultSetRowData { data.set(col, value); } - public double getDouble(int col, int srcType) throws SQLException { + public double getDouble(int col, int srcType) { Object obj = data.get(col); switch (srcType) { @@ -267,9 +262,8 @@ public class TSDBResultSetRowData { * * @param col column index * @return - * @throws SQLException */ - public String getString(int col, int srcType) throws SQLException { + public String getString(int col, int srcType) { switch (srcType) { case TSDBConstants.TSDB_DATA_TYPE_BINARY: case TSDBConstants.TSDB_DATA_TYPE_NCHAR: @@ -305,11 +299,11 @@ public class TSDBResultSetRowData { } public void setTimestamp(int col, long ts) { - data.set(col, ts); + data.set(col, new Timestamp(ts)); } public Timestamp getTimestamp(int col) { - return new Timestamp((Long) data.get(col)); + return (Timestamp) data.get(col); } public Object get(int col) { @@ -320,7 +314,7 @@ public class TSDBResultSetRowData { return colSize; } - public void setColSize(int colSize) { + private void setColSize(int colSize) { this.colSize = colSize; this.clear(); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/bean/TSDBPreparedParam.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/bean/TSDBPreparedParam.java deleted file mode 100644 index ef78292de6..0000000000 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/bean/TSDBPreparedParam.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.taosdata.jdbc.bean; - -import java.util.List; - -/** - * tdengine batch insert or import param object - */ -public class TSDBPreparedParam { - - /** - * tableName, if sTable Name is not null, and this is sub table name. - */ - private String tableName; - - /** - * sub middle param list - */ - private List middleParamList; - - /** - * value list - */ - private List valueList; - - public TSDBPreparedParam(String tableName) { - this.tableName = tableName; - } - - public String getTableName() { - return tableName; - } - - public void setTableName(String tableName) { - this.tableName = tableName; - } - - public List getMiddleParamList() { - return middleParamList; - } - - public void setMiddleParamList(List middleParamList) { - this.middleParamList = middleParamList; - } - - public void setMiddleParam(int parameterIndex, Object x) { - this.middleParamList.set(parameterIndex, x); - } - - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - - public void setValueParam(int parameterIndex, Object x) { - this.valueList.set(parameterIndex, x); - } - -} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java index c1834a7b80..1f3ed2d144 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java @@ -1,8 +1,14 @@ package com.taosdata.jdbc.rs; -import com.taosdata.jdbc.*; +import com.taosdata.jdbc.AbstractConnection; +import com.taosdata.jdbc.TSDBDriver; +import com.taosdata.jdbc.TSDBError; +import com.taosdata.jdbc.TSDBErrorNumbers; -import java.sql.*; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; import java.util.Properties; public class RestfulConnection extends AbstractConnection { @@ -55,7 +61,6 @@ public class RestfulConnection extends AbstractConnection { public DatabaseMetaData getMetaData() throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); - ; return this.metadata; } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulDriver.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulDriver.java index a94cfa6e07..6efe13561d 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulDriver.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulDriver.java @@ -17,7 +17,7 @@ public class RestfulDriver extends AbstractDriver { static { try { - DriverManager.registerDriver(new RestfulDriver()); + java.sql.DriverManager.registerDriver(new RestfulDriver()); } catch (SQLException e) { throw TSDBError.createRuntimeException(TSDBErrorNumbers.ERROR_URL_NOT_SET, e); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulParameterMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulParameterMetaData.java new file mode 100644 index 0000000000..7a130eb72b --- /dev/null +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulParameterMetaData.java @@ -0,0 +1,10 @@ +package com.taosdata.jdbc.rs; + +import com.taosdata.jdbc.AbstractParameterMetaData; + +public class RestfulParameterMetaData extends AbstractParameterMetaData { + + RestfulParameterMetaData(Object[] parameters) { + super(parameters); + } +} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java index 3a0ff56dd7..f82955ca9d 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java @@ -7,6 +7,7 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; +import java.nio.charset.Charset; import java.sql.*; import java.util.Calendar; @@ -30,7 +31,9 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar parameters = new Object[parameterCnt]; this.isPrepared = true; } - //TODO: build parameterMetaData + + // build parameterMetaData + this.parameterMetaData = new RestfulParameterMetaData(parameters); } @Override @@ -60,8 +63,15 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar for (int i = 0; i < parameters.length; ++i) { Object para = parameters[i]; if (para != null) { - String paraStr = para.toString(); - if (para instanceof Timestamp || para instanceof String) { + String paraStr; + if (para instanceof byte[]) { + paraStr = new String((byte[]) para, Charset.forName("UTF-8")); + } else { + paraStr = para.toString(); + } + // if para is timestamp or String or byte[] need to translate ' character + if (para instanceof Timestamp || para instanceof String || para instanceof byte[]) { + paraStr = paraStr.replaceAll("'", "\\\\\\\\'"); paraStr = "'" + paraStr + "'"; } sql = sql.replaceFirst("[?]", paraStr); @@ -92,7 +102,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar public void setByte(int parameterIndex, byte x) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + setObject(parameterIndex, x); } @Override @@ -153,7 +163,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar public void setBytes(int parameterIndex, byte[] x) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + setObject(parameterIndex, x); } @Override @@ -210,19 +220,16 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); + + setObject(parameterIndex,x); } @Override public void setObject(int parameterIndex, Object x) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - if (parameterIndex < 1 && parameterIndex >= parameters.length) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE); parameters[parameterIndex - 1] = x; - } @Override diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java index 0cbb40dbb6..856f5257bf 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java @@ -2,13 +2,18 @@ package com.taosdata.jdbc.rs; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; import com.taosdata.jdbc.AbstractResultSet; import com.taosdata.jdbc.TSDBConstants; import com.taosdata.jdbc.TSDBError; import com.taosdata.jdbc.TSDBErrorNumbers; +import java.math.BigDecimal; import java.sql.*; import java.util.ArrayList; +import java.util.Calendar; public class RestfulResultSet extends AbstractResultSet implements ResultSet { private volatile boolean isClosed; @@ -16,7 +21,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { private final String database; private final Statement statement; -// private final JSONObject resultJson; // data private final ArrayList> resultSet; // meta @@ -32,7 +36,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { public RestfulResultSet(String database, Statement statement, JSONObject resultJson) throws SQLException { this.database = database; this.statement = statement; -// this.resultJson = resultJson; // column metadata JSONArray columnMeta = resultJson.getJSONArray("column_meta"); @@ -73,7 +76,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { case TSDBConstants.TSDB_DATA_TYPE_INT: return row.getInteger(colIndex); case TSDBConstants.TSDB_DATA_TYPE_BIGINT: - return row.getBigInteger(colIndex); + return row.getLong(colIndex); case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return row.getFloat(colIndex); case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: @@ -81,9 +84,11 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: return new Timestamp(row.getDate(colIndex).getTime()); case TSDBConstants.TSDB_DATA_TYPE_BINARY: + return row.getString(colIndex).getBytes(); case TSDBConstants.TSDB_DATA_TYPE_NCHAR: - default: return row.getString(colIndex); + default: + return row.get(colIndex); } } @@ -130,37 +135,33 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { @Override public String getString(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - Object value = resultSet.get(pos).get(columnIndex); - return value == null ? null : value.toString(); + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + if (value instanceof byte[]) + return new String((byte[]) value); + return value.toString(); } @Override public boolean getBoolean(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - int result = getInt(columnIndex); - return result == 0 ? false : true; + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return false; + if (value instanceof Boolean) + return (boolean) value; + return Boolean.valueOf(value.toString()); } @Override public byte getByte(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - Object value = resultSet.get(pos).get(columnIndex); + Object value = resultSet.get(pos).get(columnIndex - 1); if (value == null) return 0; long valueAsLong = Long.parseLong(value.toString()); @@ -179,13 +180,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { @Override public short getShort(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - Object value = resultSet.get(pos).get(columnIndex); + Object value = resultSet.get(pos).get(columnIndex - 1); if (value == null) return 0; long valueAsLong = Long.parseLong(value.toString()); @@ -198,13 +195,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { @Override public int getInt(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - Object value = resultSet.get(pos).get(columnIndex); + Object value = resultSet.get(pos).get(columnIndex - 1); if (value == null) return 0; long valueAsLong = Long.parseLong(value.toString()); @@ -217,13 +210,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { @Override public long getLong(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - Object value = resultSet.get(pos).get(columnIndex); + Object value = resultSet.get(pos).get(columnIndex - 1); if (value == null) return 0; @@ -240,64 +229,99 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { @Override public float getFloat(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - return Float.parseFloat(resultSet.get(pos).get(columnIndex).toString()); + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return 0; + if (value instanceof Float || value instanceof Double) + return (float) value; + return Float.parseFloat(value.toString()); } @Override public double getDouble(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - if (columnIndex > resultSet.get(pos).size()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - return Double.parseDouble(resultSet.get(pos).get(columnIndex).toString()); + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return 0; + if (value instanceof Double || value instanceof Float) + return (double) value; + return Double.parseDouble(value.toString()); } - private int getTrueColumnIndex(int columnIndex) throws SQLException { - if (columnIndex < 1) { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE - , "Column Index out of range, " + columnIndex + " < 1"); - } + @Override + public byte[] getBytes(int columnIndex) throws SQLException { + checkAvailability(columnIndex, resultSet.get(pos).size()); - int numOfCols = resultSet.get(pos).size(); - if (columnIndex > numOfCols) { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE - , "Column Index out of range, " + columnIndex + " > " + numOfCols); - } + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + if (value instanceof byte[]) + return (byte[]) value; + if (value instanceof String) + return ((String) value).getBytes(); + if (value instanceof Long) + return Longs.toByteArray((long) value); + if (value instanceof Integer) + return Ints.toByteArray((int) value); + if (value instanceof Short) + return Shorts.toByteArray((short) value); + if (value instanceof Byte) + return new byte[]{(byte) value}; - return columnIndex - 1; + return value.toString().getBytes(); + } + + @Override + public Date getDate(int columnIndex) throws SQLException { + checkAvailability(columnIndex, resultSet.get(pos).size()); + + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + if (value instanceof Timestamp) + return new Date(((Timestamp) value).getTime()); + return Date.valueOf(value.toString()); + } + + @Override + public Time getTime(int columnIndex) throws SQLException { + checkAvailability(columnIndex, resultSet.get(pos).size()); + + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + if (value instanceof Timestamp) + return new Time(((Timestamp) value).getTime()); + return Time.valueOf(value.toString()); } @Override public Timestamp getTimestamp(int columnIndex) throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); + checkAvailability(columnIndex, resultSet.get(pos).size()); - columnIndex = getTrueColumnIndex(columnIndex); - String strDate = resultSet.get(pos).get(columnIndex).toString(); -// strDate = strDate.substring(1, strDate.length() - 1); - return Timestamp.valueOf(strDate); + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + if (value instanceof Timestamp) + return (Timestamp) value; + return Timestamp.valueOf(value.toString()); } - /*************************************************************************************************************/ @Override public ResultSetMetaData getMetaData() throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED); - return this.metaData; } @Override - public Object getObject(String columnLabel) throws SQLException { - return getObject(findColumn(columnLabel)); + public Object getObject(int columnIndex) throws SQLException { + checkAvailability(columnIndex, resultSet.get(pos).size()); + + return resultSet.get(pos).get(columnIndex - 1); } @Override @@ -311,6 +335,23 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { return columnIndex + 1; } + @Override + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + checkAvailability(columnIndex, resultSet.get(pos).size()); + + Object value = resultSet.get(pos).get(columnIndex - 1); + if (value == null) + return null; + + if (value instanceof Long || value instanceof Integer || value instanceof Short || value instanceof Byte) + return new BigDecimal(Long.valueOf(value.toString())); + if (value instanceof Double || value instanceof Float) + return new BigDecimal(Double.valueOf(value.toString())); + if (value instanceof Timestamp) + return new BigDecimal(((Timestamp) value).getTime()); + return new BigDecimal(value.toString()); + } + @Override public boolean isBeforeFirst() throws SQLException { if (isClosed()) @@ -471,6 +512,12 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { return this.statement; } + @Override + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + //TODO:did not use the specified timezone in cal + return getTimestamp(columnIndex); + } + @Override public boolean isClosed() throws SQLException { return isClosed; diff --git a/src/connector/jdbc/src/main/resources/META-INF/services/java.sql.Driver b/src/connector/jdbc/src/main/resources/META-INF/services/java.sql.Driver index e65b4e3b22..893f7cdf34 100644 --- a/src/connector/jdbc/src/main/resources/META-INF/services/java.sql.Driver +++ b/src/connector/jdbc/src/main/resources/META-INF/services/java.sql.Driver @@ -1 +1,2 @@ com.taosdata.jdbc.TSDBDriver +com.taosdata.jdbc.rs.RestfulDriver diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/ResultSetTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/ResultSetTest.java deleted file mode 100644 index 87348f9026..0000000000 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/ResultSetTest.java +++ /dev/null @@ -1,266 +0,0 @@ -package com.taosdata.jdbc; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import javax.sql.rowset.serial.SerialBlob; -import javax.sql.rowset.serial.SerialClob; -import java.io.UnsupportedEncodingException; -import java.sql.*; -import java.util.HashMap; -import java.util.Properties; - -import static org.junit.Assert.assertEquals; - -public class ResultSetTest { - static Connection connection; - static Statement statement; - static String dbName = "test"; - static String tName = "t0"; - static String host = "localhost"; - static ResultSet resSet; - - @BeforeClass - public static void createDatabaseAndTable() { - try { - Class.forName("com.taosdata.jdbc.TSDBDriver"); - Properties properties = new Properties(); - properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); - properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); - properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8"); - connection = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/", properties); - statement = connection.createStatement(); - statement.executeUpdate("drop database if exists " + dbName); - statement.executeUpdate("create database if not exists " + dbName); - statement.execute("use " + dbName); - statement.executeUpdate("create table if not exists " + dbName + "." + tName + " (ts timestamp, k1 int, k2 bigint, k3 float, k4 double, k5 binary(30), k6 smallint, k7 bool, k8 nchar(20))"); - } catch (ClassNotFoundException | SQLException e) { - return; - } - } - - @Test - public void testResultSet() { - String sql; - long ts = 1496732686000l; - int v1 = 2147483600; - long v2 = ts + 1000; - float v3 = 3.1415926f; - double v4 = 3.1415926535897; - String v5 = "涛思数据,强~!"; - short v6 = 12; - boolean v7 = false; - String v8 = "TDengine is powerful"; - sql = "insert into " + dbName + "." + tName + " values (" + ts + "," + v1 + "," + v2 + "," + v3 + "," + v4 - + ",\"" + v5 + "\"," + v6 + "," + v7 + ",\"" + v8 + "\")"; - try { - statement.executeUpdate(sql); - assertEquals(1, statement.getUpdateCount()); - } catch (SQLException e) { - assert false : "insert error " + e.getMessage(); - } - try { - statement.execute("select * from " + dbName + "." + tName + " where ts = " + ts); - resSet = statement.getResultSet(); - System.out.println(((TSDBResultSet) resSet).getRowData()); - while (resSet.next()) { - assertEquals(ts, resSet.getLong(1)); - assertEquals(ts, resSet.getLong("ts")); - System.out.println(resSet.getTimestamp(1)); - assertEquals(v1, resSet.getInt(2)); - assertEquals(v1, resSet.getInt("k1")); - assertEquals(v2, resSet.getLong(3)); - assertEquals(v2, resSet.getLong("k2")); - assertEquals(v3, resSet.getFloat(4), 7); - assertEquals(v3, resSet.getFloat("k3"), 7); - assertEquals(v4, resSet.getDouble(5), 13); - assertEquals(v4, resSet.getDouble("k4"), 13); - assertEquals(v5, resSet.getString(6)); - assertEquals(v5, resSet.getString("k5")); - assertEquals(v6, resSet.getShort(7)); - assertEquals(v6, resSet.getShort("k6")); - assertEquals(v7, resSet.getBoolean(8)); - assertEquals(v7, resSet.getBoolean("k7")); - assertEquals(v8, resSet.getString(9)); - assertEquals(v8, resSet.getString("k8")); - resSet.getBytes(9); - resSet.getObject(6); - resSet.getObject("k8"); - } - if (!resSet.isClosed()) { - resSet.close(); - } - } catch (SQLException e) { - assert false : "insert error " + e.getMessage(); - } - } - - @Test(expected = SQLException.class) - public void testUnsupport() throws SQLException, UnsupportedEncodingException { - statement.execute("show databases"); - resSet = statement.getResultSet(); - Assert.assertNotNull(resSet.unwrap(TSDBResultSet.class)); - Assert.assertTrue(resSet.isWrapperFor(TSDBResultSet.class)); - resSet.getUnicodeStream(null); - resSet.getBinaryStream(null); - resSet.getAsciiStream(""); - resSet.getUnicodeStream(null); - resSet.getBinaryStream(null); - resSet.getWarnings(); - resSet.clearWarnings(); - resSet.getCursorName(); - resSet.getCharacterStream(null); - resSet.getCharacterStream(null); - resSet.isBeforeFirst(); - resSet.isAfterLast(); - resSet.isFirst(); - resSet.isLast(); - resSet.beforeFirst(); - resSet.afterLast(); - resSet.first(); - resSet.last(); - resSet.getRow(); - resSet.absolute(1); - resSet.relative(1); - resSet.previous(); - resSet.setFetchDirection(0); - resSet.getFetchDirection(); - resSet.setFetchSize(0); - resSet.getFetchSize(); - resSet.getConcurrency(); - resSet.rowUpdated(); - resSet.rowInserted(); - resSet.rowDeleted(); - resSet.updateNull(null); - resSet.updateBoolean(0, true); - resSet.updateByte(0, (byte) 2); - resSet.updateShort(0, (short) 1); - resSet.updateInt(0, 0); - resSet.updateLong(0, 0l); - resSet.updateFloat(0, 3.14f); - resSet.updateDouble(0, 3.1415); - resSet.updateBigDecimal(null, null); - resSet.updateString(null, null); - resSet.updateBytes(null, null); - resSet.updateDate(null, null); - resSet.updateTime(null, null); - resSet.updateTimestamp(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - resSet.updateObject(null, null); - resSet.updateObject(null, null); - resSet.updateNull(null); - resSet.updateBoolean("", false); - resSet.updateByte("", (byte) 1); - resSet.updateShort("", (short) 1); - resSet.updateInt("", 0); - resSet.updateLong("", 0l); - resSet.updateFloat("", 3.14f); - resSet.updateDouble("", 3.1415); - resSet.updateBigDecimal(null, null); - resSet.updateString(null, null); - resSet.updateBytes(null, null); - resSet.updateDate(null, null); - resSet.updateTime(null, null); - resSet.updateTimestamp(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - resSet.updateObject(null, null); - resSet.updateObject(null, null); - resSet.insertRow(); - resSet.updateRow(); - resSet.deleteRow(); - resSet.refreshRow(); - resSet.cancelRowUpdates(); - resSet.moveToInsertRow(); - resSet.moveToCurrentRow(); - resSet.getStatement(); - resSet.getObject(0, new HashMap<>()); - resSet.getRef(null); - resSet.getBlob(null); - resSet.getClob(null); - resSet.getArray(null); - resSet.getObject("", new HashMap<>()); - resSet.getRef(null); - resSet.getBlob(null); - resSet.getClob(null); - resSet.getArray(null); - resSet.getDate(null, null); - resSet.getDate(null, null); - resSet.getTime(null, null); - resSet.getTime(null, null); - resSet.getTimestamp(null, null); - resSet.getTimestamp(null, null); - resSet.getURL(null); - resSet.getURL(null); - resSet.updateRef(null, null); - resSet.updateRef(null, null); - resSet.updateBlob(0, new SerialBlob("".getBytes("UTF8"))); - resSet.updateBlob("", new SerialBlob("".getBytes("UTF8"))); - resSet.updateClob("", new SerialClob("".toCharArray())); - resSet.updateClob(0, new SerialClob("".toCharArray())); - resSet.updateArray(null, null); - resSet.updateArray(null, null); - resSet.getRowId(null); - resSet.getRowId(null); - resSet.updateRowId(null, null); - resSet.updateRowId(null, null); - resSet.getHoldability(); - resSet.updateNString(null, null); - resSet.updateNString(null, null); - resSet.getNClob(null); - resSet.getNClob(null); - resSet.getSQLXML(null); - resSet.getSQLXML(null); - resSet.updateSQLXML(null, null); - resSet.updateSQLXML(null, null); - resSet.getNCharacterStream(null); - resSet.getNCharacterStream(null); - resSet.updateNCharacterStream(null, null); - resSet.updateNCharacterStream(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - resSet.updateNCharacterStream(null, null); - resSet.updateNCharacterStream(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - resSet.updateAsciiStream(null, null); - resSet.updateBinaryStream(null, null); - resSet.updateCharacterStream(null, null); - } - - @Test - public void testBatch() throws SQLException { - String[] sqls = new String[]{"insert into test.t0 values (1496732686001,2147483600,1496732687000,3.1415925,3.1415926535897," + - "'涛思数据,强~',12,0,'TDengine is powerful')", "insert into test.t0 values (1496732686002,2147483600,1496732687000,3.1415925,3.1415926535897," + - "'涛思数据,强~',12,1,'TDengine is powerful')"}; - for (String sql : sqls) { - statement.addBatch(sql); - } - int[] res = statement.executeBatch(); - assertEquals(res.length, 2); - statement.clearBatch(); - } - - @AfterClass - public static void close() { - try { - statement.executeUpdate("drop database " + dbName); - if (statement != null) - statement.close(); - if (connection != null) - connection.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } -} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBConnectionTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBConnectionTest.java index 0a4ecb739c..ca7251bb0e 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBConnectionTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBConnectionTest.java @@ -233,7 +233,7 @@ public class TSDBConnectionTest { int status = rs.getInt("server_status()"); Assert.assertEquals(1, status); - conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); + conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); } @Test(expected = SQLFeatureNotSupportedException.class) diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBParameterMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBParameterMetaDataTest.java new file mode 100644 index 0000000000..12bcc43917 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBParameterMetaDataTest.java @@ -0,0 +1,194 @@ +package com.taosdata.jdbc; + +import com.taosdata.jdbc.rs.RestfulParameterMetaData; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.*; + +public class TSDBParameterMetaDataTest { + + private static final String host = "127.0.0.1"; + private static Connection conn; + private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static PreparedStatement pstmt_insert; + private static final String sql_select = "select * from t1 where ts > ? and ts <= ? and f1 >= ?"; + private static PreparedStatement pstmt_select; + private static ParameterMetaData parameterMetaData_insert; + private static ParameterMetaData parameterMetaData_select; + + @Test + public void getParameterCount() throws SQLException { + Assert.assertEquals(10, parameterMetaData_insert.getParameterCount()); + } + + @Test + public void isNullable() throws SQLException { + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(1)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(2)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(3)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(4)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(5)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(6)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(7)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(8)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(9)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(10)); + } + + @Test + public void isSigned() throws SQLException { + Assert.assertEquals(false, parameterMetaData_insert.isSigned(1)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(2)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(3)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(4)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(5)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(6)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(7)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(8)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(9)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(10)); + } + + @Test + public void getPrecision() throws SQLException { + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(1)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(2)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(3)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(4)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(5)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(6)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(7)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(8)); + Assert.assertEquals(5, parameterMetaData_insert.getPrecision(9)); + Assert.assertEquals(5, parameterMetaData_insert.getPrecision(10)); + } + + @Test + public void getScale() throws SQLException { + Assert.assertEquals(0, parameterMetaData_insert.getScale(1)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(2)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(3)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(4)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(5)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(6)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(7)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(8)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(9)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(10)); + } + + @Test + public void getParameterType() throws SQLException { + Assert.assertEquals(Types.TIMESTAMP, parameterMetaData_insert.getParameterType(1)); + Assert.assertEquals(Types.INTEGER, parameterMetaData_insert.getParameterType(2)); + Assert.assertEquals(Types.BIGINT, parameterMetaData_insert.getParameterType(3)); + Assert.assertEquals(Types.FLOAT, parameterMetaData_insert.getParameterType(4)); + Assert.assertEquals(Types.DOUBLE, parameterMetaData_insert.getParameterType(5)); + Assert.assertEquals(Types.SMALLINT, parameterMetaData_insert.getParameterType(6)); + Assert.assertEquals(Types.TINYINT, parameterMetaData_insert.getParameterType(7)); + Assert.assertEquals(Types.BOOLEAN, parameterMetaData_insert.getParameterType(8)); + Assert.assertEquals(Types.BINARY, parameterMetaData_insert.getParameterType(9)); + Assert.assertEquals(Types.NCHAR, parameterMetaData_insert.getParameterType(10)); + } + + @Test + public void getParameterTypeName() throws SQLException { + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.TIMESTAMP), parameterMetaData_insert.getParameterTypeName(1)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.INTEGER), parameterMetaData_insert.getParameterTypeName(2)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BIGINT), parameterMetaData_insert.getParameterTypeName(3)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.FLOAT), parameterMetaData_insert.getParameterTypeName(4)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.DOUBLE), parameterMetaData_insert.getParameterTypeName(5)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.SMALLINT), parameterMetaData_insert.getParameterTypeName(6)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.TINYINT), parameterMetaData_insert.getParameterTypeName(7)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BOOLEAN), parameterMetaData_insert.getParameterTypeName(8)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BINARY), parameterMetaData_insert.getParameterTypeName(9)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.NCHAR), parameterMetaData_insert.getParameterTypeName(10)); + } + + @Test + public void getParameterClassName() throws SQLException { + Assert.assertEquals(Timestamp.class.getName(), parameterMetaData_insert.getParameterClassName(1)); + Assert.assertEquals(Integer.class.getName(), parameterMetaData_insert.getParameterClassName(2)); + Assert.assertEquals(Long.class.getName(), parameterMetaData_insert.getParameterClassName(3)); + Assert.assertEquals(Float.class.getName(), parameterMetaData_insert.getParameterClassName(4)); + Assert.assertEquals(Double.class.getName(), parameterMetaData_insert.getParameterClassName(5)); + Assert.assertEquals(Short.class.getName(), parameterMetaData_insert.getParameterClassName(6)); + Assert.assertEquals(Byte.class.getName(), parameterMetaData_insert.getParameterClassName(7)); + Assert.assertEquals(Boolean.class.getName(), parameterMetaData_insert.getParameterClassName(8)); + Assert.assertEquals(byte[].class.getName(), parameterMetaData_insert.getParameterClassName(9)); + Assert.assertEquals(String.class.getName(), parameterMetaData_insert.getParameterClassName(10)); + } + + @Test + public void getParameterMode() throws SQLException { + for (int i = 1; i <= parameterMetaData_insert.getParameterCount(); i++) { + int parameterMode = parameterMetaData_insert.getParameterMode(i); + Assert.assertEquals(ParameterMetaData.parameterModeUnknown, parameterMode); + } + } + + @Test + public void unwrap() throws SQLException { + TSDBParameterMetaData unwrap = parameterMetaData_insert.unwrap(TSDBParameterMetaData.class); + Assert.assertNotNull(unwrap); + } + + @Test + public void isWrapperFor() throws SQLException { + Assert.assertTrue(parameterMetaData_insert.isWrapperFor(TSDBParameterMetaData.class)); + } + + @BeforeClass + public static void beforeClass() { + try { + Class.forName("com.taosdata.jdbc.TSDBDriver"); + conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"); + try (Statement stmt = conn.createStatement()) { + stmt.execute("drop database if exists test_pstmt"); + stmt.execute("create database if not exists test_pstmt"); + stmt.execute("use test_pstmt"); + stmt.execute("create table weather(ts timestamp, f1 int, f2 bigint, f3 float, f4 double, f5 smallint, f6 tinyint, f7 bool, f8 binary(64), f9 nchar(64)) tags(loc nchar(64))"); + stmt.execute("create table t1 using weather tags('beijing')"); + } + pstmt_insert = conn.prepareStatement(sql_insert); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(2, 111); + pstmt_insert.setObject(3, Long.MAX_VALUE); + pstmt_insert.setObject(4, 3.14159265354f); + pstmt_insert.setObject(5, Double.MAX_VALUE); + pstmt_insert.setObject(6, Short.MAX_VALUE); + pstmt_insert.setObject(7, Byte.MAX_VALUE); + pstmt_insert.setObject(8, true); + pstmt_insert.setObject(9, "hello".getBytes()); + pstmt_insert.setObject(10, "Hello"); + parameterMetaData_insert = pstmt_insert.getParameterMetaData(); + + pstmt_select = conn.prepareStatement(sql_select); + pstmt_select.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_select.setTimestamp(2, new Timestamp(System.currentTimeMillis() + 10000)); + pstmt_select.setInt(3, 0); + parameterMetaData_select = pstmt_select.getParameterMetaData(); + + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void afterClass() { + try { + if (pstmt_insert != null) + pstmt_insert.close(); + if (pstmt_select != null) + pstmt_select.close(); + if (conn != null) + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java index 475cfef060..434095efa2 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java @@ -5,14 +5,16 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import java.io.IOException; +import java.io.Serializable; import java.sql.*; public class TSDBPreparedStatementTest { private static final String host = "127.0.0.1"; private static Connection conn; - private static final String sql_insert = "insert into t1 values(?, ?)"; + private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static PreparedStatement pstmt_insert; - private static final String sql_select = "select * from t1 where ts > ? and ts <= ? and temperature >= ?"; + private static final String sql_select = "select * from t1 where ts > ? and ts <= ? and f1 >= ?"; private static PreparedStatement pstmt_select; @Test @@ -21,7 +23,7 @@ public class TSDBPreparedStatementTest { long start = end - 1000 * 60 * 60; pstmt_select.setTimestamp(1, new Timestamp(start)); pstmt_select.setTimestamp(2, new Timestamp(end)); - pstmt_select.setFloat(3, 0); + pstmt_select.setInt(3, 0); ResultSet rs = pstmt_select.executeQuery(); Assert.assertNotNull(rs); @@ -37,48 +39,73 @@ public class TSDBPreparedStatementTest { @Test public void executeUpdate() throws SQLException { pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); - pstmt_insert.setFloat(2, 3.14f); + pstmt_insert.setFloat(4, 3.14f); int result = pstmt_insert.executeUpdate(); Assert.assertEquals(1, result); } @Test public void setNull() throws SQLException { - pstmt_insert.setNull(2, Types.FLOAT); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setNull(2, Types.INTEGER); + int result = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, result); } @Test public void setBoolean() throws SQLException { - pstmt_insert.setBoolean(2, true); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setBoolean(8, true); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void setByte() throws SQLException { - pstmt_insert.setByte(1, (byte) 0x001); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setByte(7, (byte) 0x001); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setShort() { - + public void setShort() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setShort(6, (short) 2); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setInt() { - + public void setInt() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setInt(2, 10086); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setLong() { - + public void setLong() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setLong(3, Long.MAX_VALUE); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setFloat() { - + public void setFloat() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setFloat(4, 3.14f); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setDouble() { + public void setDouble() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setDouble(5, 3.14444); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -87,12 +114,56 @@ public class TSDBPreparedStatementTest { } @Test - public void setString() { + public void setString() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, "aaaa"); + boolean execute = pstmt_insert.execute(); + Assert.assertFalse(execute); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, new Person("john", 33, true).toString()); + Assert.assertFalse(pstmt_insert.execute()); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, new Person("john", 33, true).toString().replaceAll("'", "\"")); + Assert.assertFalse(pstmt_insert.execute()); } - @Test(expected = SQLFeatureNotSupportedException.class) - public void setBytes() throws SQLException { - pstmt_insert.setBytes(1, new byte[]{}); + class Person implements Serializable { + String name; + int age; + boolean sex; + + public Person(String name, int age, boolean sex) { + this.name = name; + this.age = age; + this.sex = sex; + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + ", sex=" + sex + + '}'; + } + } + + @Test + public void setBytes() throws SQLException, IOException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + +// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +// ObjectOutputStream oos = new ObjectOutputStream(baos); +// oos.writeObject(new Person("john", 33, true)); +// oos.flush(); +// byte[] bytes = baos.toByteArray(); +// pstmt_insert.setBytes(9, bytes); + + pstmt_insert.setBytes(9, new Person("john", 33, true).toString().getBytes()); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -106,8 +177,10 @@ public class TSDBPreparedStatementTest { } @Test - public void setTimestamp() { - //TODO + public void setTimestamp() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -121,24 +194,69 @@ public class TSDBPreparedStatementTest { } @Test - public void clearParameters() { - //TODO + public void clearParameters() throws SQLException { + pstmt_insert.clearParameters(); } @Test public void setObject() throws SQLException { - pstmt_insert.setObject(1, System.currentTimeMillis()); - //TODO + pstmt_insert.setObject(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(2, 111); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(3, Long.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(4, 3.14159265354f); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(5, Double.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(6, Short.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(7, Byte.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(8, true); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(9, "hello".getBytes()); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(10, "Hello"); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void execute() { - //TODO - } + public void execute() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); - @Test - public void addBatch() { - //TODO: + executeQuery(); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -176,11 +294,11 @@ public class TSDBPreparedStatementTest { pstmt_insert.setURL(1, null); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void getParameterMetaData() throws SQLException { ParameterMetaData parameterMetaData = pstmt_insert.getParameterMetaData(); -// Assert.assertNotNull(parameterMetaData); - //TODO: + Assert.assertNotNull(parameterMetaData); + //TODO: modify the test case } @Test(expected = SQLFeatureNotSupportedException.class) @@ -215,10 +333,10 @@ public class TSDBPreparedStatementTest { Class.forName("com.taosdata.jdbc.TSDBDriver"); conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"); try (Statement stmt = conn.createStatement()) { - stmt.execute("drop database if exists test_pstmt"); - stmt.execute("create database if not exists test_pstmt"); - stmt.execute("use test_pstmt"); - stmt.execute("create table weather(ts timestamp, temperature float) tags(loc nchar(64))"); + stmt.execute("drop database if exists test_pstmt_jni"); + stmt.execute("create database if not exists test_pstmt_jni"); + stmt.execute("use test_pstmt_jni"); + stmt.execute("create table weather(ts timestamp, f1 int, f2 bigint, f3 float, f4 double, f5 smallint, f6 tinyint, f7 bool, f8 binary(64), f9 nchar(64)) tags(loc nchar(64))"); stmt.execute("create table t1 using weather tags('beijing')"); } pstmt_insert = conn.prepareStatement(sql_insert); @@ -231,7 +349,10 @@ public class TSDBPreparedStatementTest { @AfterClass public static void afterClass() { try { - + if (pstmt_insert != null) + pstmt_insert.close(); + if (pstmt_select != null) + pstmt_select.close(); if (conn != null) conn.close(); } catch (SQLException e) { diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBResultSetTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBResultSetTest.java new file mode 100644 index 0000000000..374b1335fc --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBResultSetTest.java @@ -0,0 +1,678 @@ +package com.taosdata.jdbc; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; +import com.taosdata.jdbc.rs.RestfulResultSet; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.sql.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +public class TSDBResultSetTest { + + private static final String host = "127.0.0.1"; + private static Connection conn; + private static Statement stmt; + private static ResultSet rs; + + @Test + public void wasNull() throws SQLException { + Assert.assertFalse(rs.wasNull()); + } + + @Test + public void getString() throws SQLException { + String f10 = rs.getString("f10"); + Assert.assertEquals("涛思数据", f10); + f10 = rs.getString(10); + Assert.assertEquals("涛思数据", f10); + } + + @Test + public void getBoolean() throws SQLException { + Boolean f9 = rs.getBoolean("f9"); + Assert.assertEquals(true, f9); + f9 = rs.getBoolean(9); + Assert.assertEquals(true, f9); + } + + @Test + public void getByte() throws SQLException { + byte f8 = rs.getByte("f8"); + Assert.assertEquals(10, f8); + f8 = rs.getByte(8); + Assert.assertEquals(10, f8); + } + + @Test + public void getShort() throws SQLException { + short f7 = rs.getShort("f7"); + Assert.assertEquals(10, f7); + f7 = rs.getShort(7); + Assert.assertEquals(10, f7); + } + + @Test + public void getInt() throws SQLException { + int f2 = rs.getInt("f2"); + Assert.assertEquals(1, f2); + f2 = rs.getInt(2); + Assert.assertEquals(1, f2); + } + + @Test + public void getLong() throws SQLException { + long f3 = rs.getLong("f3"); + Assert.assertEquals(100, f3); + f3 = rs.getLong(3); + Assert.assertEquals(100, f3); + } + + @Test + public void getFloat() throws SQLException { + float f4 = rs.getFloat("f4"); + Assert.assertEquals(3.1415f, f4, 0f); + f4 = rs.getFloat(4); + Assert.assertEquals(3.1415f, f4, 0f); + } + + @Test + public void getDouble() throws SQLException { + double f5 = rs.getDouble("f5"); + Assert.assertEquals(3.1415926, f5, 0.0); + f5 = rs.getDouble(5); + Assert.assertEquals(3.1415926, f5, 0.0); + } + + @Test + public void getBigDecimal() throws SQLException { + BigDecimal f1 = rs.getBigDecimal("f1"); + Assert.assertEquals(1609430400000l, f1.longValue()); + + BigDecimal f2 = rs.getBigDecimal("f2"); + Assert.assertEquals(1, f2.intValue()); + + BigDecimal f3 = rs.getBigDecimal("f3"); + Assert.assertEquals(100l, f3.longValue()); + + BigDecimal f4 = rs.getBigDecimal("f4"); + Assert.assertEquals(3.1415f, f4.floatValue(), 0.00000f); + + BigDecimal f5 = rs.getBigDecimal("f5"); + Assert.assertEquals(3.1415926, f5.doubleValue(), 0.0000000); + + BigDecimal f7 = rs.getBigDecimal("f7"); + Assert.assertEquals(10, f7.intValue()); + + BigDecimal f8 = rs.getBigDecimal("f8"); + Assert.assertEquals(10, f8.intValue()); + } + + @Test + public void getBytes() throws SQLException { + byte[] f1 = rs.getBytes("f1"); + Assert.assertEquals("2021-01-01 00:00:00.0", new String(f1)); + + byte[] f2 = rs.getBytes("f2"); + Assert.assertEquals(1, Ints.fromByteArray(f2)); + + byte[] f3 = rs.getBytes("f3"); + Assert.assertEquals(100l, Longs.fromByteArray(f3)); + + byte[] f4 = rs.getBytes("f4"); + Assert.assertEquals(3.1415f, Float.valueOf(new String(f4)), 0.000000f); + + byte[] f5 = rs.getBytes("f5"); + Assert.assertEquals(3.1415926, Double.valueOf(new String(f5)), 0.000000f); + + byte[] f6 = rs.getBytes("f6"); + Assert.assertEquals("abc", new String(f6)); + + byte[] f7 = rs.getBytes("f7"); + Assert.assertEquals((short) 10, Shorts.fromByteArray(f7)); + + byte[] f8 = rs.getBytes("f8"); + Assert.assertEquals(1, f8.length); + Assert.assertEquals((byte) 10, f8[0]); + + byte[] f9 = rs.getBytes("f9"); + Assert.assertEquals("true", new String(f9)); + + byte[] f10 = rs.getBytes("f10"); + Assert.assertEquals("涛思数据", new String(f10)); + } + + @Test + public void getDate() throws SQLException, ParseException { + Date f1 = rs.getDate("f1"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Assert.assertEquals(sdf.parse("2021-01-01"), f1); + } + + @Test + public void getTime() throws SQLException { + Time f1 = rs.getTime("f1"); + Assert.assertEquals("00:00:00", f1.toString()); + } + + @Test + public void getTimestamp() throws SQLException { + Timestamp f1 = rs.getTimestamp("f1"); + Assert.assertEquals("2021-01-01 00:00:00.0", f1.toString()); + f1 = rs.getTimestamp(1); + Assert.assertEquals("2021-01-01 00:00:00.0", f1.toString()); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getAsciiStream() throws SQLException { + rs.getAsciiStream("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getUnicodeStream() throws SQLException { + rs.getUnicodeStream("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getBinaryStream() throws SQLException { + rs.getBinaryStream("f1"); + } + + @Test + public void getWarnings() throws SQLException { + Assert.assertNull(rs.getWarnings()); + } + + @Test + public void clearWarnings() throws SQLException { + rs.clearWarnings(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getCursorName() throws SQLException { + rs.getCursorName(); + } + + @Test + public void getMetaData() throws SQLException { + ResultSetMetaData meta = rs.getMetaData(); + Assert.assertNotNull(meta); + } + + @Test + public void getObject() throws SQLException, ParseException { + Object f1 = rs.getObject("f1"); + Assert.assertEquals(Timestamp.class, f1.getClass()); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.sss"); + java.util.Date date = sdf.parse("2021-01-01 00:00:00.000"); + Assert.assertEquals(new Timestamp(date.getTime()), f1); + + Object f2 = rs.getObject("f2"); + Assert.assertEquals(Integer.class, f2.getClass()); + Assert.assertEquals(1, f2); + + Object f3 = rs.getObject("f3"); + Assert.assertEquals(Long.class, f3.getClass()); + Assert.assertEquals(100l, f3); + + Object f4 = rs.getObject("f4"); + Assert.assertEquals(Float.class, f4.getClass()); + Assert.assertEquals(3.1415f, f4); + + Object f5 = rs.getObject("f5"); + Assert.assertEquals(Double.class, f5.getClass()); + Assert.assertEquals(3.1415926, f5); + + Object f6 = rs.getObject("f6"); + Assert.assertEquals(byte[].class, f6.getClass()); + Assert.assertEquals("abc", new String((byte[]) f6)); + + Object f7 = rs.getObject("f7"); + Assert.assertEquals(Short.class, f7.getClass()); + Assert.assertEquals((short) 10, f7); + + Object f8 = rs.getObject("f8"); + Assert.assertEquals(Byte.class, f8.getClass()); + Assert.assertEquals((byte) 10, f8); + + Object f9 = rs.getObject("f9"); + Assert.assertEquals(Boolean.class, f9.getClass()); + Assert.assertEquals(true, f9); + + Object f10 = rs.getObject("f10"); + Assert.assertEquals(String.class, f10.getClass()); + Assert.assertEquals("涛思数据", f10); + } + + @Test(expected = SQLException.class) + public void findColumn() throws SQLException { + int columnIndex = rs.findColumn("f1"); + Assert.assertEquals(1, columnIndex); + columnIndex = rs.findColumn("f2"); + Assert.assertEquals(2, columnIndex); + columnIndex = rs.findColumn("f3"); + Assert.assertEquals(3, columnIndex); + columnIndex = rs.findColumn("f4"); + Assert.assertEquals(4, columnIndex); + columnIndex = rs.findColumn("f5"); + Assert.assertEquals(5, columnIndex); + columnIndex = rs.findColumn("f6"); + Assert.assertEquals(6, columnIndex); + columnIndex = rs.findColumn("f7"); + Assert.assertEquals(7, columnIndex); + columnIndex = rs.findColumn("f8"); + Assert.assertEquals(8, columnIndex); + columnIndex = rs.findColumn("f9"); + Assert.assertEquals(9, columnIndex); + columnIndex = rs.findColumn("f10"); + Assert.assertEquals(10, columnIndex); + + rs.findColumn("f11"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getCharacterStream() throws SQLException { + rs.getCharacterStream(1); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void isBeforeFirst() throws SQLException { + rs.isBeforeFirst(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void isAfterLast() throws SQLException { + rs.isAfterLast(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void isFirst() throws SQLException { + rs.isFirst(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void isLast() throws SQLException { + rs.isLast(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void beforeFirst() throws SQLException { + rs.beforeFirst(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void afterLast() throws SQLException { + rs.afterLast(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void first() throws SQLException { + rs.first(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void last() throws SQLException { + rs.last(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getRow() throws SQLException { + int row = rs.getRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void absolute() throws SQLException { + rs.absolute(-1); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void relative() throws SQLException { + rs.relative(-1); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void previous() throws SQLException { + rs.previous(); + } + + @Test + public void setFetchDirection() throws SQLException { + rs.setFetchDirection(ResultSet.FETCH_FORWARD); + Assert.assertEquals(ResultSet.FETCH_FORWARD, rs.getFetchDirection()); + rs.setFetchDirection(ResultSet.FETCH_UNKNOWN); + Assert.assertEquals(ResultSet.FETCH_FORWARD, rs.getFetchDirection()); + } + + @Test + public void getFetchDirection() throws SQLException { + Assert.assertEquals(ResultSet.FETCH_FORWARD, rs.getFetchDirection()); + } + + @Test + public void setFetchSize() throws SQLException { + rs.setFetchSize(0); + Assert.assertEquals(0, rs.getFetchSize()); + } + + @Test + public void getFetchSize() throws SQLException { + Assert.assertEquals(0, rs.getFetchSize()); + } + + @Test + public void getType() throws SQLException { + Assert.assertEquals(ResultSet.TYPE_FORWARD_ONLY, rs.getType()); + } + + @Test + public void getConcurrency() throws SQLException { + Assert.assertEquals(ResultSet.CONCUR_READ_ONLY, rs.getConcurrency()); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void rowUpdated() throws SQLException { + rs.rowUpdated(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void rowInserted() throws SQLException { + rs.rowInserted(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void rowDeleted() throws SQLException { + rs.rowDeleted(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateNull() throws SQLException { + rs.updateNull("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateBoolean() throws SQLException { + rs.updateBoolean(1, false); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateByte() throws SQLException { + rs.updateByte(1, new Byte("0")); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateShort() throws SQLException { + rs.updateShort(1, new Short("0")); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateInt() throws SQLException { + rs.updateInt(1, 1); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateLong() throws SQLException { + rs.updateLong(1, 1l); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateFloat() throws SQLException { + rs.updateFloat(1, 1f); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateDouble() throws SQLException { + rs.updateDouble(1, 1.0); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateBigDecimal() throws SQLException { + rs.updateBigDecimal(1, new BigDecimal(1)); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateString() throws SQLException { + rs.updateString(1, "abc"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateBytes() throws SQLException { + rs.updateBytes(1, new byte[]{}); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateDate() throws SQLException { + rs.updateDate(1, new Date(System.currentTimeMillis())); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateTime() throws SQLException { + rs.updateTime(1, new Time(System.currentTimeMillis())); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateTimestamp() throws SQLException { + rs.updateTimestamp(1, new Timestamp(System.currentTimeMillis())); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateAsciiStream() throws SQLException { + rs.updateAsciiStream(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateBinaryStream() throws SQLException { + rs.updateBinaryStream(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateCharacterStream() throws SQLException { + rs.updateCharacterStream(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateObject() throws SQLException { + rs.updateObject(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void insertRow() throws SQLException { + rs.insertRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateRow() throws SQLException { + rs.updateRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void deleteRow() throws SQLException { + rs.deleteRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void refreshRow() throws SQLException { + rs.refreshRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void cancelRowUpdates() throws SQLException { + rs.cancelRowUpdates(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void moveToInsertRow() throws SQLException { + rs.moveToInsertRow(); + } + + @Test + public void getStatement() throws SQLException { + Statement stmt = rs.getStatement(); + Assert.assertNotNull(stmt); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void moveToCurrentRow() throws SQLException { + rs.moveToCurrentRow(); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getRef() throws SQLException { + rs.getRef(1); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getBlob() throws SQLException { + rs.getBlob("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getClob() throws SQLException { + rs.getClob("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getArray() throws SQLException { + rs.getArray("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getURL() throws SQLException { + rs.getURL("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateRef() throws SQLException { + rs.updateRef("f1", null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateBlob() throws SQLException { + rs.updateBlob(1, (InputStream) null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateClob() throws SQLException { + rs.updateClob(1, (Reader) null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateArray() throws SQLException { + rs.updateArray(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getRowId() throws SQLException { + rs.getRowId("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateRowId() throws SQLException { + rs.updateRowId(1, null); + } + + @Test + public void getHoldability() throws SQLException { + Assert.assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, rs.getHoldability()); + } + + @Test + public void isClosed() throws SQLException { + Assert.assertFalse(rs.isClosed()); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateNString() throws SQLException { + rs.updateNString(1, null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateNClob() throws SQLException { + rs.updateNClob(1, (Reader) null); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getNClob() throws SQLException { + rs.getNClob("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getSQLXML() throws SQLException { + rs.getSQLXML("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateSQLXML() throws SQLException { + rs.updateSQLXML(1, null); + } + + @Test + public void getNString() throws SQLException { + String f10 = rs.getNString("f10"); + Assert.assertEquals("涛思数据", f10); + f10 = rs.getNString(10); + Assert.assertEquals("涛思数据", f10); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void getNCharacterStream() throws SQLException { + rs.getNCharacterStream("f1"); + } + + @Test(expected = SQLFeatureNotSupportedException.class) + public void updateNCharacterStream() throws SQLException { + rs.updateNCharacterStream(1, null); + } + + @Test + public void unwrap() throws SQLException { + TSDBResultSet unwrap = rs.unwrap(TSDBResultSet.class); + Assert.assertNotNull(unwrap); + } + + @Test + public void isWrapperFor() throws SQLException { + Assert.assertTrue(rs.isWrapperFor(TSDBResultSet.class)); + } + + @BeforeClass + public static void beforeClass() { + try { + Class.forName("com.taosdata.jdbc.TSDBDriver"); + conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"); + stmt = conn.createStatement(); + stmt.execute("create database if not exists restful_test"); + stmt.execute("use restful_test"); + stmt.execute("drop table if exists weather"); + stmt.execute("create table if not exists weather(f1 timestamp, f2 int, f3 bigint, f4 float, f5 double, f6 binary(64), f7 smallint, f8 tinyint, f9 bool, f10 nchar(64))"); + stmt.execute("insert into restful_test.weather values('2021-01-01 00:00:00.000', 1, 100, 3.1415, 3.1415926, 'abc', 10, 10, true, '涛思数据')"); + rs = stmt.executeQuery("select * from restful_test.weather"); + rs.next(); + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + + } + + @AfterClass + public static void afterClass() { + try { + if (rs != null) + rs.close(); + if (stmt != null) + stmt.close(); + if (conn != null) + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DriverAutoloadTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DriverAutoloadTest.java new file mode 100644 index 0000000000..580b2ac1b5 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DriverAutoloadTest.java @@ -0,0 +1,42 @@ +package com.taosdata.jdbc.cases; + +import com.taosdata.jdbc.TSDBDriver; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class DriverAutoloadTest { + + private Properties properties; + private String host = "127.0.0.1"; + + @Test + public void testRestful() throws SQLException { +// Class.forName("com.taosdata.jdbc.rs.RestfulDriver"); + final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"; + Connection conn = DriverManager.getConnection(url, properties); + Assert.assertNotNull(conn); + } + + @Test + public void testJni() throws SQLException { + final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"; + Connection conn = DriverManager.getConnection(url, properties); + Assert.assertNotNull(conn); + } + + + @Before + public void before() { + properties = new Properties(); + properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); + properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8"); + properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); + } + +} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/InsertDbwithoutUseDbTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/InsertDbwithoutUseDbTest.java index 54ee8fd6eb..84149775c3 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/InsertDbwithoutUseDbTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/InsertDbwithoutUseDbTest.java @@ -14,7 +14,6 @@ import java.util.Random; public class InsertDbwithoutUseDbTest { private static String host = "127.0.0.1"; - // private static String host = "master"; private static Properties properties; private static Random random = new Random(System.currentTimeMillis()); diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/UnsignedNumberRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/UnsignedNumberRestfulTest.java index d0e6306704..4ae2f36fe9 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/UnsignedNumberRestfulTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/UnsignedNumberRestfulTest.java @@ -10,8 +10,8 @@ import java.util.Properties; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class UnsignedNumberRestfulTest { + private static final String host = "127.0.0.1"; -// private static final String host = "master"; private static Connection conn; @Test diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/AuthenticationTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/AuthenticationTest.java index b0666989ba..a6fb6cfda0 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/AuthenticationTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/AuthenticationTest.java @@ -8,7 +8,6 @@ import java.sql.*; public class AuthenticationTest { private static final String host = "127.0.0.1"; - // private static final String host = "master"; private static final String user = "root"; private static final String password = "taos?data"; private Connection conn; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java index 4e005d1291..abd60f5b63 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java @@ -12,7 +12,6 @@ import java.util.Properties; public class RestfulConnectionTest { private static final String host = "127.0.0.1"; - // private static final String host = "master"; private static Connection conn; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java index 1991c17065..a052fbbdcb 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java @@ -10,7 +10,6 @@ import java.sql.*; import java.util.Properties; public class RestfulDatabaseMetaDataTest { - // private static final String host = "master"; private static final String host = "127.0.0.1"; private static final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"; private static Connection connection; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJDBCTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJDBCTest.java index 451f5d4916..c8bb69d827 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJDBCTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJDBCTest.java @@ -10,7 +10,6 @@ import java.util.Random; public class RestfulJDBCTest { private static final String host = "127.0.0.1"; -// private static final String host = "master"; private static Connection connection; private Random random = new Random(System.currentTimeMillis()); diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulParameterMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulParameterMetaDataTest.java new file mode 100644 index 0000000000..8bb2532ce8 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulParameterMetaDataTest.java @@ -0,0 +1,194 @@ +package com.taosdata.jdbc.rs; + +import com.taosdata.jdbc.TSDBConstants; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.*; + +public class RestfulParameterMetaDataTest { + + private static final String host = "127.0.0.1"; + private static Connection conn; + private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static PreparedStatement pstmt_insert; + private static final String sql_select = "select * from t1 where ts > ? and ts <= ? and f1 >= ?"; + private static PreparedStatement pstmt_select; + private static ParameterMetaData parameterMetaData_insert; + private static ParameterMetaData parameterMetaData_select; + + @Test + public void getParameterCount() throws SQLException { + Assert.assertEquals(10, parameterMetaData_insert.getParameterCount()); + } + + @Test + public void isNullable() throws SQLException { + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(1)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(2)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(3)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(4)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(5)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(6)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(7)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(8)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(9)); + Assert.assertEquals(ParameterMetaData.parameterNullableUnknown, parameterMetaData_insert.isNullable(10)); + } + + @Test + public void isSigned() throws SQLException { + Assert.assertEquals(false, parameterMetaData_insert.isSigned(1)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(2)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(3)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(4)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(5)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(6)); + Assert.assertEquals(true, parameterMetaData_insert.isSigned(7)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(8)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(9)); + Assert.assertEquals(false, parameterMetaData_insert.isSigned(10)); + } + + @Test + public void getPrecision() throws SQLException { + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(1)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(2)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(3)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(4)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(5)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(6)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(7)); + Assert.assertEquals(0, parameterMetaData_insert.getPrecision(8)); + Assert.assertEquals(5, parameterMetaData_insert.getPrecision(9)); + Assert.assertEquals(5, parameterMetaData_insert.getPrecision(10)); + } + + @Test + public void getScale() throws SQLException { + Assert.assertEquals(0, parameterMetaData_insert.getScale(1)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(2)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(3)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(4)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(5)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(6)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(7)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(8)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(9)); + Assert.assertEquals(0, parameterMetaData_insert.getScale(10)); + } + + @Test + public void getParameterType() throws SQLException { + Assert.assertEquals(Types.TIMESTAMP, parameterMetaData_insert.getParameterType(1)); + Assert.assertEquals(Types.INTEGER, parameterMetaData_insert.getParameterType(2)); + Assert.assertEquals(Types.BIGINT, parameterMetaData_insert.getParameterType(3)); + Assert.assertEquals(Types.FLOAT, parameterMetaData_insert.getParameterType(4)); + Assert.assertEquals(Types.DOUBLE, parameterMetaData_insert.getParameterType(5)); + Assert.assertEquals(Types.SMALLINT, parameterMetaData_insert.getParameterType(6)); + Assert.assertEquals(Types.TINYINT, parameterMetaData_insert.getParameterType(7)); + Assert.assertEquals(Types.BOOLEAN, parameterMetaData_insert.getParameterType(8)); + Assert.assertEquals(Types.BINARY, parameterMetaData_insert.getParameterType(9)); + Assert.assertEquals(Types.NCHAR, parameterMetaData_insert.getParameterType(10)); + } + + @Test + public void getParameterTypeName() throws SQLException { + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.TIMESTAMP), parameterMetaData_insert.getParameterTypeName(1)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.INTEGER), parameterMetaData_insert.getParameterTypeName(2)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BIGINT), parameterMetaData_insert.getParameterTypeName(3)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.FLOAT), parameterMetaData_insert.getParameterTypeName(4)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.DOUBLE), parameterMetaData_insert.getParameterTypeName(5)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.SMALLINT), parameterMetaData_insert.getParameterTypeName(6)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.TINYINT), parameterMetaData_insert.getParameterTypeName(7)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BOOLEAN), parameterMetaData_insert.getParameterTypeName(8)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.BINARY), parameterMetaData_insert.getParameterTypeName(9)); + Assert.assertEquals(TSDBConstants.jdbcType2TaosTypeName(Types.NCHAR), parameterMetaData_insert.getParameterTypeName(10)); + } + + @Test + public void getParameterClassName() throws SQLException { + Assert.assertEquals(Timestamp.class.getName(), parameterMetaData_insert.getParameterClassName(1)); + Assert.assertEquals(Integer.class.getName(), parameterMetaData_insert.getParameterClassName(2)); + Assert.assertEquals(Long.class.getName(), parameterMetaData_insert.getParameterClassName(3)); + Assert.assertEquals(Float.class.getName(), parameterMetaData_insert.getParameterClassName(4)); + Assert.assertEquals(Double.class.getName(), parameterMetaData_insert.getParameterClassName(5)); + Assert.assertEquals(Short.class.getName(), parameterMetaData_insert.getParameterClassName(6)); + Assert.assertEquals(Byte.class.getName(), parameterMetaData_insert.getParameterClassName(7)); + Assert.assertEquals(Boolean.class.getName(), parameterMetaData_insert.getParameterClassName(8)); + Assert.assertEquals(byte[].class.getName(), parameterMetaData_insert.getParameterClassName(9)); + Assert.assertEquals(String.class.getName(), parameterMetaData_insert.getParameterClassName(10)); + } + + @Test + public void getParameterMode() throws SQLException { + for (int i = 1; i <= parameterMetaData_insert.getParameterCount(); i++) { + int parameterMode = parameterMetaData_insert.getParameterMode(i); + Assert.assertEquals(ParameterMetaData.parameterModeUnknown, parameterMode); + } + } + + @Test + public void unwrap() throws SQLException { + RestfulParameterMetaData unwrap = parameterMetaData_insert.unwrap(RestfulParameterMetaData.class); + Assert.assertNotNull(unwrap); + } + + @Test + public void isWrapperFor() throws SQLException { + Assert.assertTrue(parameterMetaData_insert.isWrapperFor(RestfulParameterMetaData.class)); + } + + @BeforeClass + public static void beforeClass() { + try { + Class.forName("com.taosdata.jdbc.rs.RestfulDriver"); + conn = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"); + try (Statement stmt = conn.createStatement()) { + stmt.execute("drop database if exists test_pstmt"); + stmt.execute("create database if not exists test_pstmt"); + stmt.execute("use test_pstmt"); + stmt.execute("create table weather(ts timestamp, f1 int, f2 bigint, f3 float, f4 double, f5 smallint, f6 tinyint, f7 bool, f8 binary(64), f9 nchar(64)) tags(loc nchar(64))"); + stmt.execute("create table t1 using weather tags('beijing')"); + } + pstmt_insert = conn.prepareStatement(sql_insert); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(2, 111); + pstmt_insert.setObject(3, Long.MAX_VALUE); + pstmt_insert.setObject(4, 3.14159265354f); + pstmt_insert.setObject(5, Double.MAX_VALUE); + pstmt_insert.setObject(6, Short.MAX_VALUE); + pstmt_insert.setObject(7, Byte.MAX_VALUE); + pstmt_insert.setObject(8, true); + pstmt_insert.setObject(9, "hello".getBytes()); + pstmt_insert.setObject(10, "Hello"); + parameterMetaData_insert = pstmt_insert.getParameterMetaData(); + + pstmt_select = conn.prepareStatement(sql_select); + pstmt_select.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_select.setTimestamp(2, new Timestamp(System.currentTimeMillis() + 10000)); + pstmt_select.setInt(3, 0); + parameterMetaData_select = pstmt_select.getParameterMetaData(); + + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void afterClass() { + try { + if (pstmt_insert != null) + pstmt_insert.close(); + if (pstmt_select != null) + pstmt_select.close(); + if (conn != null) + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulPreparedStatementTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulPreparedStatementTest.java index a3867c1b6e..094dff8c8d 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulPreparedStatementTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulPreparedStatementTest.java @@ -5,11 +5,12 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import java.io.IOException; +import java.io.Serializable; import java.sql.*; public class RestfulPreparedStatementTest { private static final String host = "127.0.0.1"; - // private static final String host = "master"; private static Connection conn; private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static PreparedStatement pstmt_insert; @@ -38,48 +39,73 @@ public class RestfulPreparedStatementTest { @Test public void executeUpdate() throws SQLException { pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); - pstmt_insert.setFloat(2, 3.14f); + pstmt_insert.setFloat(4, 3.14f); int result = pstmt_insert.executeUpdate(); Assert.assertEquals(1, result); } @Test public void setNull() throws SQLException { - pstmt_insert.setNull(2, Types.FLOAT); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setNull(2, Types.INTEGER); + int result = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, result); } @Test public void setBoolean() throws SQLException { - pstmt_insert.setBoolean(2, true); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setBoolean(8, true); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void setByte() throws SQLException { - pstmt_insert.setByte(1, (byte) 0x001); + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setByte(7, (byte) 0x001); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setShort() { - + public void setShort() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setShort(6, (short) 2); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setInt() { - + public void setInt() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setInt(2, 10086); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setLong() { - + public void setLong() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setLong(3, Long.MAX_VALUE); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setFloat() { - + public void setFloat() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setFloat(4, 3.14f); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void setDouble() { + public void setDouble() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setDouble(5, 3.14444); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -88,12 +114,56 @@ public class RestfulPreparedStatementTest { } @Test - public void setString() { + public void setString() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, "aaaa"); + boolean execute = pstmt_insert.execute(); + Assert.assertFalse(execute); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, new Person("john", 33, true).toString()); + Assert.assertFalse(pstmt_insert.execute()); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setString(10, new Person("john", 33, true).toString().replaceAll("'", "\"")); + Assert.assertFalse(pstmt_insert.execute()); } - @Test(expected = SQLFeatureNotSupportedException.class) - public void setBytes() throws SQLException { - pstmt_insert.setBytes(1, new byte[]{}); + class Person implements Serializable { + String name; + int age; + boolean sex; + + public Person(String name, int age, boolean sex) { + this.name = name; + this.age = age; + this.sex = sex; + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + ", sex=" + sex + + '}'; + } + } + + @Test + public void setBytes() throws SQLException, IOException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + +// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +// ObjectOutputStream oos = new ObjectOutputStream(baos); +// oos.writeObject(new Person("john", 33, true)); +// oos.flush(); +// byte[] bytes = baos.toByteArray(); +// pstmt_insert.setBytes(9, bytes); + + pstmt_insert.setBytes(9, new Person("john", 33, true).toString().getBytes()); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -107,8 +177,10 @@ public class RestfulPreparedStatementTest { } @Test - public void setTimestamp() { - //TODO + public void setTimestamp() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -122,24 +194,69 @@ public class RestfulPreparedStatementTest { } @Test - public void clearParameters() { - //TODO + public void clearParameters() throws SQLException { + pstmt_insert.clearParameters(); } @Test public void setObject() throws SQLException { - pstmt_insert.setObject(1, System.currentTimeMillis()); - //TODO + pstmt_insert.setObject(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(2, 111); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(3, Long.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(4, 3.14159265354f); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(5, Double.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(6, Short.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(7, Byte.MAX_VALUE); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(8, true); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(9, "hello".getBytes()); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); + + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + pstmt_insert.setObject(10, "Hello"); + ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); } @Test - public void execute() { - //TODO - } + public void execute() throws SQLException { + pstmt_insert.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + int ret = pstmt_insert.executeUpdate(); + Assert.assertEquals(1, ret); - @Test - public void addBatch() { - //TODO: + executeQuery(); } @Test(expected = SQLFeatureNotSupportedException.class) @@ -180,8 +297,8 @@ public class RestfulPreparedStatementTest { @Test public void getParameterMetaData() throws SQLException { ParameterMetaData parameterMetaData = pstmt_insert.getParameterMetaData(); - Assert.assertNull(parameterMetaData); - //TODO: + Assert.assertNotNull(parameterMetaData); + //TODO: modify the test case } @Test(expected = SQLFeatureNotSupportedException.class) diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetMetaDataTest.java index 13973d8b6b..c7fc812972 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetMetaDataTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetMetaDataTest.java @@ -10,7 +10,6 @@ import java.sql.*; public class RestfulResultSetMetaDataTest { private static final String host = "127.0.0.1"; -// private static final String host = "master"; private static Connection conn; private static Statement stmt; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java index a15b1964ea..d6b2a58127 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java @@ -1,5 +1,8 @@ package com.taosdata.jdbc.rs; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -9,11 +12,12 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.sql.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; public class RestfulResultSetTest { private static final String host = "127.0.0.1"; -// private static final String host = "master"; private static Connection conn; private static Statement stmt; @@ -88,24 +92,75 @@ public class RestfulResultSetTest { Assert.assertEquals(3.1415926, f5, 0.0); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void getBigDecimal() throws SQLException { - rs.getBigDecimal("f1"); + BigDecimal f1 = rs.getBigDecimal("f1"); + Assert.assertEquals(1609430400000l, f1.longValue()); + + BigDecimal f2 = rs.getBigDecimal("f2"); + Assert.assertEquals(1, f2.intValue()); + + BigDecimal f3 = rs.getBigDecimal("f3"); + Assert.assertEquals(100l, f3.longValue()); + + BigDecimal f4 = rs.getBigDecimal("f4"); + Assert.assertEquals(3.1415f, f4.floatValue(), 0.00000f); + + BigDecimal f5 = rs.getBigDecimal("f5"); + Assert.assertEquals(3.1415926, f5.doubleValue(), 0.0000000); + + BigDecimal f7 = rs.getBigDecimal("f7"); + Assert.assertEquals(10, f7.intValue()); + + BigDecimal f8 = rs.getBigDecimal("f8"); + Assert.assertEquals(10, f8.intValue()); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void getBytes() throws SQLException { - rs.getBytes("f1"); + byte[] f1 = rs.getBytes("f1"); + Assert.assertEquals("2021-01-01 00:00:00.0", new String(f1)); + + byte[] f2 = rs.getBytes("f2"); + Assert.assertEquals(1, Ints.fromByteArray(f2)); + + byte[] f3 = rs.getBytes("f3"); + Assert.assertEquals(100l, Longs.fromByteArray(f3)); + + byte[] f4 = rs.getBytes("f4"); + Assert.assertEquals(3.1415f, Float.valueOf(new String(f4)), 0.000000f); + + byte[] f5 = rs.getBytes("f5"); + Assert.assertEquals(3.1415926, Double.valueOf(new String(f5)), 0.000000f); + + byte[] f6 = rs.getBytes("f6"); + Assert.assertEquals("abc", new String(f6)); + + byte[] f7 = rs.getBytes("f7"); + Assert.assertEquals((short) 10, Shorts.fromByteArray(f7)); + + byte[] f8 = rs.getBytes("f8"); + Assert.assertEquals(1, f8.length); + Assert.assertEquals((byte) 10, f8[0]); + + byte[] f9 = rs.getBytes("f9"); + Assert.assertEquals("true", new String(f9)); + + byte[] f10 = rs.getBytes("f10"); + Assert.assertEquals("涛思数据", new String(f10)); } - @Test(expected = SQLFeatureNotSupportedException.class) - public void getDate() throws SQLException { - rs.getDate("f1"); + @Test + public void getDate() throws SQLException, ParseException { + Date f1 = rs.getDate("f1"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Assert.assertEquals(sdf.parse("2021-01-01"), f1); } - @Test(expected = SQLFeatureNotSupportedException.class) + @Test public void getTime() throws SQLException { - rs.getTime("f1"); + Time f1 = rs.getTime("f1"); + Assert.assertEquals("00:00:00", f1.toString()); } @Test @@ -152,9 +207,49 @@ public class RestfulResultSetTest { Assert.assertNotNull(meta); } - @Test(expected = SQLFeatureNotSupportedException.class) - public void getObject() throws SQLException { - rs.getObject("f1"); + @Test + public void getObject() throws SQLException, ParseException { + Object f1 = rs.getObject("f1"); + Assert.assertEquals(Timestamp.class, f1.getClass()); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.sss"); + java.util.Date date = sdf.parse("2021-01-01 00:00:00.000"); + Assert.assertEquals(new Timestamp(date.getTime()), f1); + + Object f2 = rs.getObject("f2"); + Assert.assertEquals(Integer.class, f2.getClass()); + Assert.assertEquals(1, f2); + + Object f3 = rs.getObject("f3"); + Assert.assertEquals(Long.class, f3.getClass()); + Assert.assertEquals(100l, f3); + + Object f4 = rs.getObject("f4"); + Assert.assertEquals(Float.class, f4.getClass()); + Assert.assertEquals(3.1415f, f4); + + Object f5 = rs.getObject("f5"); + Assert.assertEquals(Double.class, f5.getClass()); + Assert.assertEquals(3.1415926, f5); + + Object f6 = rs.getObject("f6"); + Assert.assertEquals(byte[].class, f6.getClass()); + Assert.assertEquals("abc", new String((byte[]) f6)); + + Object f7 = rs.getObject("f7"); + Assert.assertEquals(Short.class, f7.getClass()); + Assert.assertEquals((short) 10, f7); + + Object f8 = rs.getObject("f8"); + Assert.assertEquals(Byte.class, f8.getClass()); + Assert.assertEquals((byte) 10, f8); + + Object f9 = rs.getObject("f9"); + Assert.assertEquals(Boolean.class, f9.getClass()); + Assert.assertEquals(true, f9); + + Object f10 = rs.getObject("f10"); + Assert.assertEquals(String.class, f10.getClass()); + Assert.assertEquals("涛思数据", f10); } @Test(expected = SQLException.class) diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java index 653e480413..1be32b502d 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java @@ -12,7 +12,6 @@ import java.util.UUID; public class RestfulStatementTest { private static final String host = "127.0.0.1"; - // private static final String host = "master"; private static Connection conn; private static Statement stmt; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/SQLTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/SQLTest.java index fe4d04775d..4ad9826384 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/SQLTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/SQLTest.java @@ -12,7 +12,6 @@ import java.sql.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SQLTest { private static final String host = "127.0.0.1"; -// private static final String host = "master"; private static Connection connection; @Test diff --git a/src/connector/odbc/.gitignore b/src/connector/odbc/.gitignore new file mode 100644 index 0000000000..bfef9b2efa --- /dev/null +++ b/src/connector/odbc/.gitignore @@ -0,0 +1,3 @@ +!c/ +node_modules/ +package-lock.json diff --git a/src/connector/odbc/CMakeLists.txt b/src/connector/odbc/CMakeLists.txt index 0d8c07041a..5a93ac3f7e 100644 --- a/src/connector/odbc/CMakeLists.txt +++ b/src/connector/odbc/CMakeLists.txt @@ -15,7 +15,7 @@ IF (TD_LINUX_64) message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built") find_package(FLEX) if(NOT FLEX_FOUND) - message(FATAL_ERROR "you need to install flex first") + message(WARNING "you need to install flex first") else () if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0) message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case") @@ -24,7 +24,7 @@ IF (TD_LINUX_64) SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion") ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(tools) - ADD_SUBDIRECTORY(tests) + ADD_SUBDIRECTORY(examples) endif () endif() endif() @@ -33,10 +33,44 @@ IF (TD_LINUX_64) ENDIF () ENDIF () +IF (TD_DARWIN) + find_program(HAVE_ODBCINST NAMES odbcinst) + IF (HAVE_ODBCINST) + include(CheckSymbolExists) + # shall we revert CMAKE_REQUIRED_LIBRARIES and how? + set(CMAKE_REQUIRED_LIBRARIES odbc) + set(CMAKE_REQUIRED_INCLUDES /usr/local/include) + set(CMAKE_REQUIRED_LINK_OPTIONS -L/usr/local/lib) + check_symbol_exists(SQLExecute "sql.h" HAVE_ODBC_DEV) + if(NOT (HAVE_ODBC_DEV)) + unset(HAVE_ODBC_DEV CACHE) + message(WARNING "unixodbc-dev is not installed yet, you may install it with homebrew by typing: brew install unixodbc") + else () + message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built") + find_package(FLEX) + if(NOT FLEX_FOUND) + message(WARNING "you need to install flex first") + else () + if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0) + message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case") + else () + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wconversion") + SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion") + ADD_SUBDIRECTORY(src) + ADD_SUBDIRECTORY(tools) + ADD_SUBDIRECTORY(examples) + endif () + endif() + endif() + ELSE () + message(WARNING "unixodbc is not installed yet, you may install it under ubuntu by typing: brew install unixodbc") + ENDIF () +ENDIF () + IF (TD_WINDOWS_64) find_package(ODBC) if (NOT ODBC_FOUND) - message(FATAL_ERROR "you need to install ODBC first") + message(WARNING "you need to install ODBC first") else () message(STATUS "ODBC_INCLUDE_DIRS: ${ODBC_INCLUDE_DIRS}") message(STATUS "ODBC_LIBRARIES: ${ODBC_LIBRARIES}") @@ -50,6 +84,7 @@ IF (TD_WINDOWS_64) else () ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(tools) - ADD_SUBDIRECTORY(tests) + ADD_SUBDIRECTORY(examples) endif() ENDIF () + diff --git a/src/connector/odbc/README.cn.md b/src/connector/odbc/README.cn.md new file mode 100644 index 0000000000..bf114356a6 --- /dev/null +++ b/src/connector/odbc/README.cn.md @@ -0,0 +1,169 @@ + +# ODBC 驱动 # + +- **TAOS ODBC驱动持续更新中** + +- **目前导出的ODBC函数包括(注: 有些不常用的函数只是导出,但并未实现)**: +SQLAllocEnv +SQLFreeEnv +SQLAllocConnect +SQLFreeConnect +SQLGetEnvAttr +SQLSetEnvAttr +SQLGetConnectAttr +SQLGetConnectOption +SQLGetInfo +SQLConnect +SQLDisconnect +SQLAllocStmt +SQLAllocHandle +SQLFreeHandle +SQLFreeStmt +SQLExecDirect +SQLNumResultCols +SQLRowCount +SQLColAttribute +SQLGetData +SQLFetch +SQLPrepare +SQLExecute +SQLParamData +SQLPutData +SQLGetDiagRec +SQLBindParameter +SQLDescribeParam +SQLDriverConnect +SQLSetConnectAttr +SQLDescribeCol +SQLBindCol +SQLNumParams +SQLSetStmtAttr +SQLBindParam +SQLCancel +SQLCancelHandle +SQLCloseCursor +SQLColumns +SQLCopyDesc +SQLDataSources +SQLEndTran +SQLFetchScroll +SQLGetCursorName +SQLGetDescField +SQLGetDescRec +SQLGetStmtAttr +SQLGetStmtOption +SQLGetTypeInfo +SQLSetConnectOption +SQLSetCursorName +SQLSetDescField +SQLSetDescRec +SQLSetParam +SQLSetStmtOption +SQLSpecialColumns +SQLStatistics +SQLTables +SQLTransact + +` + +- **国际化。可以通过在ODBC连接串中指定针对SQLCHAR/SQLWCHAR/taos_charset/system-locale的字符集来解决常见的环境匹配问题**. + +- **现有的ODBC客户端工具可以籍此驱动同TAOS数据源互联,包括主流linux/macosx/windows平台** + +- **现有的支持ODBC的编程语言可以籍此驱动同TAOS数据源互联, 例如: c/nodejs/python/rust/go已经在上述三个主流平台测试通过, 熟悉其他语言的同学可以发现这基本上是开箱即用** + +- **持续更新中**... + +# 编译和测试使用 +**Note**: 下述所有步骤都在TDengine项目的根目录下进行 +**Note**: 请先确保src/connector/odbc如下所示,被包含在src/CMakeLists.txt源文件中 +``` +... +ADD_SUBDIRECTORY(dnode) +ADD_SUBDIRECTORY(connector/odbc) +ADD_SUBDIRECTORY(connector/jdbc) +``` + +# Linux下的编译, 以Ubuntu为例 +``` +sudo apt install unixodbc unixodbc-dev flex +rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug && echo yes +``` +# MacOSX下的编译, 以Catalina为例,依赖homebrew进行第三方工具安装[https://brew.sh/] +``` +brew install unixodbc +rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug && echo yes +``` +# Windows下的编译, 以Windows 10为例 +- 安装windows的`flex`工具. 目前我们使用[https://github.com/lexxmark/winflexbison](url). 安装完成后请确保win_flex.exe所在目录记录于`PATH`环境变量中. +- 安装Microsoft Visual Studio工具, 以VS2019为例 +- `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"` +- `rmdir /s /q debug` +- `cmake -G "NMake Makefiles" -B debug` +- `cmake --build debug` +- `cmake --install debug` +- 以管理员身份打开`命令提示符` +- 安装ODBC驱动: 在上述打开的提示符下执行 `odbcconf /A {INSTALLDRIVER "TAOS | Driver=C:/TDengine/driver/todbc.dll | ConnectFunctions=YYN | DriverODBCVer=03.00"}` +- 新增一个数据源DSN: 执行 `odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN | Server=:"}` +上述步骤出现失败的话,可以参看这些链接: +1. win flex的安装: https://github.com/lexxmark/winflexbison/releases +2. PATH环境变量: https://jingyan.baidu.com/article/8ebacdf02d3c2949f65cd5d0.html +3. 管理员身份: https://blog.csdn.net/weixin_41083002/article/details/81019893 +4. 安装odbc驱动/数据源: https://docs.microsoft.com/en-us/sql/odbc/odbcconf-exe?view=sql-server-ver15 + +# 测试使用 +强烈建议您在linux上编译运行taosd服务端,因为当前TAOS还没有windows侧的服务端移植. +**Note1**: <>符号所括起的内容请按您当前的系统填写 +**Note2**: `.stmts` 文件存放的是测试用sql语句, 注意其格式为`UTF-8`(不带BOM导引头) +## 按官方文档在linux侧启动taosd,确保选用'UTF-8'作为其字符集 +## 在linux下创建数据 +``` +./debug/build/bin/tcodbc --dsn TAOS_DSN --uid --pwd --sts ./src/connector/odbc/samples/create_data.stmts +--<或指定特殊的ODBC连接字符串 --> +./debug/build/bin/tcodbc -C 'DSN=TAOS_DSN;UID=;PWD=;Server=:' --sts ./src/connector/odbc/samples/create_data.stmts +``` +## 在windows下检索数据 +``` +.\debug\build\bin\tcodbc -C "DSN=TAOS_DSN;UID=;PWD=;Server=:;enc_char=UTF-8" --sts .\src\connector\odbc\samples\query_data.stmts +``` +## 在MacOSX下检索数据 +``` +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;UID=;PWD=;Server=:" --sts ./src/connector/odbc/samples/query_data.stmts +``` + +## 代码示例 +- src/connector/odbc/examples/c +- src/connector/odbc/examples/js +- src/connector/odbc/examples/py +- src/connector/odbc/examples/rust +- src/connector/odbc/examples/go + +在linux或MacOSX上, 可以通过修改运行如下脚本来尝试各种测试: +**Note**: 不要忘记替换: +**Note**: 你需要在你的平台上安装nodejs/python/rust/go +**Note**: 你还需要安装对应语言的ODBC包: +-- node-odbc for nodejs: https://www.npmjs.com/package/odbc +-- pyodbc for python: https://pypi.org/project/pyodbc/ +-- rust-odbc for rust: https://docs.rs/odbc/0.17.0/odbc/ +-- go-odbc for go: https://github.com/alexbrainman/odbc + +``` +echo c && +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=:" --sts src/connector/odbc/samples/create_data.stmts && +echo nodejs && +./src/connector/odbc/examples/js/odbc.js -C 'DSN=TAOS_DSN;Server=:' && +echo python && +python3 src/connector/odbc/examples/py/odbc.py -C 'DSN=TAOS_DSN;Server=:' && +echo rust && +pushd src/connector/odbc/examples/rust/main && DSN='DSN=TAOS_DSN;Server=:' cargo run && popd && +echo go && +DSN='DSN=TAOS_DSN;Server=:' go run src/connector/odbc/examples/go/odbc.go && +``` + +## 您可以对比测试一下prepared-batch-insert是否会带来速度的提升: +**注** src/connector/odbc/examples/c/main.c是tcodbc的源代码 +``` +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=:" --insert --batch_size 200 --batchs 10000 +``` + + diff --git a/src/connector/odbc/README.md b/src/connector/odbc/README.md index e026884a07..670c7b9d95 100644 --- a/src/connector/odbc/README.md +++ b/src/connector/odbc/README.md @@ -1,20 +1,25 @@ # ODBC Driver # -- **very initial implementation of ODBC driver for TAOS +- **on-going implementation of ODBC driver for TAOS** -- **currently partially supported ODBC functions are: ` +- **currently exported ODBC functions are**: SQLAllocEnv SQLFreeEnv SQLAllocConnect SQLFreeConnect +SQLGetEnvAttr +SQLSetEnvAttr +SQLGetConnectAttr +SQLGetConnectOption +SQLGetInfo SQLConnect SQLDisconnect SQLAllocStmt SQLAllocHandle +SQLFreeHandle SQLFreeStmt SQLExecDirect -SQLExecDirectW SQLNumResultCols SQLRowCount SQLColAttribute @@ -22,29 +27,62 @@ SQLGetData SQLFetch SQLPrepare SQLExecute -SQLGetDiagField +SQLParamData +SQLPutData SQLGetDiagRec SQLBindParameter +SQLDescribeParam SQLDriverConnect SQLSetConnectAttr SQLDescribeCol +SQLBindCol SQLNumParams SQLSetStmtAttr -ConfigDSN +SQLBindParam +SQLCancel +SQLCancelHandle +SQLCloseCursor +SQLColumns +SQLCopyDesc +SQLDataSources +SQLEndTran +SQLFetchScroll +SQLGetCursorName +SQLGetDescField +SQLGetDescRec +SQLGetStmtAttr +SQLGetStmtOption +SQLGetTypeInfo +SQLSetConnectOption +SQLSetCursorName +SQLSetDescField +SQLSetDescRec +SQLSetParam +SQLSetStmtOption +SQLSpecialColumns +SQLStatistics +SQLTables +SQLTransact + ` -- **internationalized, you can specify different charset/code page for easy going. eg.: insert `utf-8.zh_cn` characters into database located in linux machine, while query them out in `gb2312/gb18030/...` code page in your chinese windows machine, or vice-versa. and much fun, insert `gb2312/gb18030/...` characters into database located in linux box from -your japanese windows box, and query them out in your local chinese windows machine. +- **internationalized, you can specify charset for SQLCHAR/SQLWCHAR/taos_charset/system-locale to coordinate with the environment**. -- **enable ODBC-aware software to communicate with TAOS. +- **enable ODBC-aware software to communicate with TAOS, no matter what platform it's running on, currently we support linux/macosx/windows** -- **enable any language with ODBC-bindings/ODBC-plugings to communicate with TAOS +- **enable any language with ODBC-bindings/ODBC-plugings to communicate with TAOS, currently c/nodejs/python/rust/go are all passed in our test environment, we believe other languages with ODBC-bindings/plugins are available-out-of-box** -- **still going on... +- **still going on**... # Building and Testing **Note**: all `work` is done in TDengine's project directory - +**Note**: please make sure src/connector/odbc is included in src/CMakeLists.txt +``` +... +ADD_SUBDIRECTORY(dnode) +ADD_SUBDIRECTORY(connector/odbc) +ADD_SUBDIRECTORY(connector/jdbc) +``` # Building under Linux, use Ubuntu as example ``` @@ -53,36 +91,68 @@ rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug & ``` # Building under Windows, use Windows 10 as example - install windows `flex` port. We use [https://github.com/lexxmark/winflexbison](url) at the moment. Please be noted to append `` to your `PATH`. -- install Microsoft Visual Studio, take VS2015 as example here -- `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64` +- install Microsoft Visual Studio, take VS2019 as example here +- `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"` - `rmdir /s /q debug` - `cmake -G "NMake Makefiles" -B debug` - `cmake --build debug` - `cmake --install debug` - open your `Command Prompt` with Administrator's priviledge -- remove previously installed TAOS ODBC driver: run `C:\TDengine\todbcinst -u -f -n TAOS` -- install TAOS ODBC driver that was just built: run `C:\TDengine\todbcinst -i -n TAOS -p C:\TDengine\driver` -- add a new user dsn: run `odbcconf CONFIGDSN TAOS "DSN=TAOS_DSN|Server=:` +- install TAOS ODBC driver that was just built: run `odbcconf /A {INSTALLDRIVER "TAOS | Driver=C:/TDengine/driver/todbc.dll | ConnectFunctions=YYN | DriverODBCVer=03.00"}` +- add a new user dsn: run `odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN | Server=host:port"}` # Test -we highly suggest that you build both in linux(ubuntu) and windows(windows 10) platform, because currently TAOS only has it's server-side port on linux platform. +we highly suggest that you build both in linux(ubuntu) and windows(windows 10) platform, because currently TAOS has not server-side port on windows platform. **Note1**: content within <> shall be modified to match your environment **Note2**: `.stmts` source files are all encoded in `UTF-8` -## start taosd in linux, suppose charset is `UTF-8` as default -``` -taosd -c ./debug/test/cfg -``` +## start taosd in linux, suppose charset is `UTF-8` as default, please follow TAOS doc for starting up ## create data in linux ``` -./debug/build/bin/tcodbc --dsn TAOS_DSN --uid --pwd --sts ./src/connector/odbc/tests/create_data.stmts +./debug/build/bin/tcodbc --dsn TAOS_DSN --uid --pwd --sts ./src/connector/odbc/samples/create_data.stmts -- -./debug/build/bin/tcodbc --dcs 'Driver=TAOS;UID=;PWD=;Server=:;client_enc=UTF-8' ./src/connector/odbc/tests/create_data.stmts +./debug/build/bin/tcodbc -C 'DSN=TAOS_DSN;UID=;PWD=;Server=:' --sts ./src/connector/odbc/samples/create_data.stmts ``` ## query data in windows ``` -.\debug\build\bin\tcodbc --dsn TAOS_DSN --uid --pwd --sts .\src\connector\odbc\tests\query_data.stmts --- -.\debug\build\bin\tcodbc --dcs "Driver=TAOS;UID=;PWD=;Server=:;client_enc=UTF-8" .\src\connector\odbc\tests\query_data.stmts +.\debug\build\bin\tcodbc -C "DSN=TAOS_DSN;UID=;PWD=;Server=:;enc_char=UTF-8" --sts .\src\connector\odbc\samples\query_data.stmts +``` +## query data in MacOSX +``` +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;UID=;PWD=;Server=:" --sts ./src/connector/odbc/samples/query_data.stmts +``` + +## code examples +- src/connector/odbc/examples/c +- src/connector/odbc/examples/js +- src/connector/odbc/examples/py +- src/connector/odbc/examples/rust +- src/connector/odbc/examples/go + +on linux/MacOSX, here after are script-snippet for you to play with: +**Note**: don't forget to replace : with whatever on your environment +**Note**: you need to install node/python3/rust/go on you machine +**Note**: you also need to install odbc-bindings/odbc-pluggins on those language platform, such as: +-- node-odbc for nodejs: https://www.npmjs.com/package/odbc +-- pyodbc for python: https://pypi.org/project/pyodbc/ +-- rust-odbc for rust: https://docs.rs/odbc/0.17.0/odbc/ +-- go-odbc for go: https://github.com/alexbrainman/odbc + +``` +echo c && +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=:" --sts src/connector/odbc/samples/create_data.stmts && +echo nodejs && +./src/connector/odbc/examples/js/odbc.js -C 'DSN=TAOS_DSN;Server=:' && +echo python && +python3 src/connector/odbc/examples/py/odbc.py -C 'DSN=TAOS_DSN;Server=:' && +echo rust && +pushd src/connector/odbc/examples/rust/main && DSN='DSN=TAOS_DSN;Server=:' cargo run && popd && +echo go && +DSN='DSN=TAOS_DSN;Server=:' go run src/connector/odbc/examples/go/odbc.go && +``` + +## see how fast prepared-statment could bring up with: +``` +./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=:" --insert --batch_size 200 --batchs 10000 ``` diff --git a/src/connector/odbc/examples/CMakeLists.txt b/src/connector/odbc/examples/CMakeLists.txt new file mode 100644 index 0000000000..71f00a04e3 --- /dev/null +++ b/src/connector/odbc/examples/CMakeLists.txt @@ -0,0 +1,4 @@ +PROJECT(TDengine) + +ADD_SUBDIRECTORY(c) + diff --git a/src/connector/odbc/examples/c/CMakeLists.txt b/src/connector/odbc/examples/c/CMakeLists.txt new file mode 100644 index 0000000000..7821f894d0 --- /dev/null +++ b/src/connector/odbc/examples/c/CMakeLists.txt @@ -0,0 +1,22 @@ +PROJECT(TDengine) + +ADD_EXECUTABLE(tcodbc main.c ../../src/todbc_log.c) + +IF (TD_LINUX OR TD_DARWIN) + TARGET_LINK_LIBRARIES(tcodbc taos odbc) +ENDIF () + +IF (TD_DARWIN) + target_include_directories(tcodbc PRIVATE /usr/local/include) + target_link_directories(tcodbc PUBLIC /usr/local/lib) +ENDIF () + +IF (TD_WINDOWS_64) + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /GL") + SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL") + TARGET_LINK_LIBRARIES(tcodbc taos_static odbc32 odbccp32 user32 legacy_stdio_definitions os) + + ADD_EXECUTABLE(tms main.cpp) + TARGET_LINK_LIBRARIES(tms odbc32) +ENDIF () + diff --git a/src/connector/odbc/examples/c/main.c b/src/connector/odbc/examples/c/main.c new file mode 100644 index 0000000000..e36c75688e --- /dev/null +++ b/src/connector/odbc/examples/c/main.c @@ -0,0 +1,1060 @@ +#include "../../src/todbc_log.h" + +#ifdef _MSC_VER +#include +#include +#include "os.h" +#endif +#include +#include +#include + +#include "taos.h" +#include "taoserror.h" + +#include +#include + +#define CHK_TEST(statement) \ +do { \ + D("testing: %s", #statement); \ + int r = (statement); \ + if (r) { \ + D("testing failed: %s", #statement); \ + return 1; \ + } \ +} while (0); + +typedef struct { + int batch_size; + int batchs; + int keep_stmt_among_batchs; + int use_odbc; + int use_taos_query; + int use_taos_stmt; +} insert_arg_t; + +typedef struct db_column_s db_column_t; +struct db_column_s { + SQLSMALLINT nameLength; + char name[4096]; // seems enough + SQLSMALLINT dataType; + SQLULEN columnSize; + SQLSMALLINT decimalDigits; + SQLSMALLINT nullable; +}; + +static db_column_t *columns = NULL; + +typedef struct data_s data_t; +struct data_s { + int64_t ts; + int8_t b; + int8_t v1; + int16_t v2; + int32_t v4; + int64_t v8; + float f4; + double f8; + char bin[40+1]; + char blob[40+1]; // why 80? ref: tests/examples/c/apitest.c +}; + +#define CHK_RESULT(r, ht, h, fmt, ...) \ +do { \ + if (r==0) break; \ + SQLSMALLINT i_0381 = 1; \ + while (1) { \ + SQLCHAR ss[10]; \ + SQLINTEGER ne = 0; \ + SQLCHAR es[4096]; \ + SQLSMALLINT n = 0; \ + ss[0] = '\0'; \ + es[0] = '\0'; \ + SQLRETURN ret = SQLGetDiagRec(ht, h, i_0381, ss, &ne, es, sizeof(es), &n); \ + if (ret) break; \ + D("[%s]%s: " fmt "", ss, es, ##__VA_ARGS__); \ + ++i_0381; \ + } \ +} while (0) + +static int open_connect(const char *dsn, const char *uid, const char *pwd, SQLHENV *pEnv, SQLHDBC *pConn) { + SQLRETURN r; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + r = SQLAllocEnv(&env); + if (r!=SQL_SUCCESS) return 1; + do { + r = SQLAllocConnect(env, &conn); + CHK_RESULT(r, SQL_HANDLE_ENV, env, ""); + if (r!=SQL_SUCCESS) break; + do { + r = SQLConnect(conn, (SQLCHAR*)dsn, (SQLSMALLINT)(dsn ? strlen(dsn) : 0), + (SQLCHAR*)uid, (SQLSMALLINT)(uid ? strlen(uid) : 0), + (SQLCHAR*)pwd, (SQLSMALLINT)(pwd ? strlen(pwd) : 0)); + CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); + if (r==SQL_SUCCESS) { + *pEnv = env; + *pConn = conn; + return 0; + } + } while (0); + SQLFreeConnect(conn); + } while (0); + SQLFreeEnv(env); + + return 1; +} + +static int open_driver_connect(const char *connstr, SQLHENV *pEnv, SQLHDBC *pConn) { + SQLRETURN r; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + r = SQLAllocEnv(&env); + if (r!=SQL_SUCCESS) return 1; + do { + r = SQLAllocConnect(env, &conn); + CHK_RESULT(r, SQL_HANDLE_ENV, env, ""); + if (r!=SQL_SUCCESS) break; + do { + SQLCHAR buf[4096]; + SQLSMALLINT blen = 0; + SQLHDBC ConnectionHandle = conn; + SQLHWND WindowHandle = NULL; + SQLCHAR * InConnectionString = (SQLCHAR*)connstr; + SQLSMALLINT StringLength1 = (SQLSMALLINT)(connstr ? strlen(connstr) : 0); + SQLCHAR * OutConnectionString = buf; + SQLSMALLINT BufferLength = sizeof(buf); + SQLSMALLINT * StringLength2Ptr = &blen; + SQLUSMALLINT DriverCompletion = SQL_DRIVER_NOPROMPT; + r = SQLDriverConnect(ConnectionHandle, WindowHandle, InConnectionString, + StringLength1, OutConnectionString, BufferLength, + StringLength2Ptr, DriverCompletion); + CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); + if (r==SQL_SUCCESS) { + *pEnv = env; + *pConn = conn; + return 0; + } + } while (0); + SQLFreeConnect(conn); + } while (0); + SQLFreeEnv(env); + + return 1; +} + +static SQLRETURN traverse_cols(SQLHSTMT stmt, SQLSMALLINT cols) { + SQLRETURN r = SQL_ERROR; + for (SQLSMALLINT i=0; i0) fprintf(stdout, "\n"); + return r; + } + } + if (soi==SQL_NULL_DATA) { + fprintf(stdout, "%snull", i==0?"":","); + } else { + fprintf(stdout, "%s\"%s\"", i==0?"":",", buf); + } + } + fprintf(stdout, "\n"); + } + } while (0); + return r; +} + +int test_statements(const char *dsn, const char *uid, const char *pwd, const char **statements) { + SQLRETURN r = SQL_SUCCESS; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + int n = open_connect(dsn, uid, pwd, &env, &conn); + if (n) return 1; + do { + SQLHSTMT stmt = {0}; + r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt); + if (r!=SQL_SUCCESS) break; + const char **p = statements; + while (*p) { + if (do_statement(stmt, *p)) { + r = SQL_ERROR; + break; + } + ++p; + } + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } while (0); + SQLDisconnect(conn); + SQLFreeConnect(conn); + SQLFreeEnv(env); + return r ? 1 : 0; +} + +int test_driver_connect(const char *connstr) { + SQLRETURN r = SQL_SUCCESS; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + int n = open_driver_connect(connstr, &env, &conn); + if (n) return 1; + SQLDisconnect(conn); + SQLFreeConnect(conn); + SQLFreeEnv(env); + return r ? 1 : 0; +} + +int create_statement(SQLHENV env, SQLHDBC conn, SQLHSTMT *pStmt) { + SQLHSTMT stmt = {0}; + SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt); + CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); + if (r==SQL_SUCCESS) { + *pStmt = stmt; + return 0; + } + if (r==SQL_SUCCESS_WITH_INFO) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + return 1; +} + +int do_statements(SQLHSTMT stmt, const char **statements) { + const char **p = statements; + while (p && *p) { + CHK_TEST(do_statement(stmt, *p)); + ++p; + } + return 0; +} + +int tests_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt) { + const char *statements[] = { + "drop database if exists m", + "create database m", + "use m", + // "create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(1), name nchar(1))", + "create table t (ts timestamp, b bool)", + "insert into t values('2020-10-10 00:00:00', 0)", + "insert into t values('2020-10-10 00:00:00.001', 1)", + NULL + }; + CHK_TEST(do_statements(stmt, statements)); + return 0; +} + +int tests(SQLHENV env, SQLHDBC conn) { + SQLHSTMT stmt = {0}; + CHK_TEST(create_statement(env, conn, &stmt)); + int r = tests_stmt(env, conn, stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return r ? 1 : 0; +} + +int test_env(void) { + SQLRETURN r; + SQLHENV env = {0}; + r = SQLAllocEnv(&env); + if (r!=SQL_SUCCESS) return 1; + SQLFreeEnv(env); + return 0; +} + +static int test_sqls_in_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, const char *sqls) { + FILE *f = fopen(sqls, "rb"); + if (!f) { + D("failed to open file [%s]", sqls); + return -1; + } + + int r = 0; + while (!feof(f)) { + char *line = NULL; + size_t len = 0; + + ssize_t n = 0; +#ifdef _MSC_VER + n = taosGetlineImp(&line, &len, f); +#else + n = getline(&line, &len, f); +#endif + if (n==-1) break; + + const char *p = NULL; + do { + if (line[0] == '#') break; + if (n>0 && line[n-1] == '\n') line[n-1]='\0'; + if (n>0 && line[n-1] == '\r') line[n-1]='\0'; + if (n>1 && line[n-2] == '\r') line[n-2]='\0'; + p = line; + while (isspace(*p)) ++p; + + if (*p==0) break; + + int positive = 1; + if (strncmp(p, "N:", 2)==0) { + // negative sample + positive = 0; + p += 2; + } else if (strncmp(p, "P:", 2)==0) { + // positive sample + p += 2; + } + + D("statement: [%s]", p); + r = do_statement(stmt, p); + + if (positive && r==0) break; + if (!positive && r) { r = 0; break; } + if (positive) return r; + D("expecting negative result, but got positive"); + return -1; + } while (0); + + free(line); + + if (r) break; + } + + fclose(f); + return r ? 1 : 0; +} + +static int test_sqls_in_conn(SQLHENV env, SQLHDBC conn, const char *sqls) { + SQLHSTMT stmt = {0}; + CHK_TEST(create_statement(env, conn, &stmt)); + int r = test_sqls_in_stmt(env, conn, stmt, sqls); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return r ? 1 : 0; +} + +static int test_sqls(const char *dsn, const char *uid, const char *pwd, const char *connstr, const char *sqls) { + int r = 0; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + if (dsn) { + CHK_TEST(open_connect(dsn, uid, pwd, &env, &conn)); + } else { + CHK_TEST(open_driver_connect(connstr, &env, &conn)); + } + + if (sqls) { + r = test_sqls_in_conn(env, conn, sqls); + } + SQLDisconnect(conn); + SQLFreeConnect(conn); + SQLFreeEnv(env); + return r ? 1 : 0; +} + +typedef struct record_s record_t; +struct record_s { + int dummy; + char ts[64]; + SQLLEN ts_len; + int32_t v1; + SQLLEN v1_len; + char ts2[64]; + SQLLEN ts2_len; +}; + +static int do_prepare_in_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt) { + SQLRETURN r = SQL_SUCCESS; + do { + const char *sql = "insert into m.v (ts, v1, ts2) values (?, ?, ?)"; + r = SQLPrepare(stmt, (SQLCHAR*)sql, SQL_NTS); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + + record_t records[] = { + {0, "2020-01-03 11:22:33.345", SQL_NTS, 1, sizeof(int32_t), "2020-01-02 11:22:33.455", SQL_NTS}, + {0, "2020-01-03 11:22:34.346", SQL_NTS, 2, sizeof(int32_t), "2020-01-02 11:22:34.445", SQL_NTS}, + {0, "2020-01-04 11:22:34.345", SQL_NTS, 2, sizeof(int32_t), "2020-01-02 11:22:34.445", SQL_NTS}, + {0, "2020-01-05 11:22:34.345", SQL_NTS, 2, sizeof(int32_t), "2020-01-02 11:22:34.445", SQL_NTS}, + }; + + record_t *base = (record_t*)0; + + r = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(base->ts)-1, 0, base->ts, sizeof(base->ts), &(base->ts_len)); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &base->v1, 0, &(base->v1_len)); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(base->ts2)-1, 0, base->ts2, sizeof(base->ts2), &(base->ts2_len)); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_BIND_TYPE, (SQLPOINTER)sizeof(*base), 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)(sizeof(records)/sizeof(records[0])), 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + record_t *record = NULL; + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR, &record, 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + record = records; + + r = SQLExecute(stmt); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + } while (0); + + return r ? -1 : 0; +} + +static int do_prepare_in_conn(SQLHENV env, SQLHDBC conn) { + SQLHSTMT stmt = {0}; + CHK_TEST(create_statement(env, conn, &stmt)); + int r = do_prepare_in_stmt(env, conn, stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return r ? 1 : 0; +} + +static int do_prepare(const char *dsn, const char *uid, const char *pwd, const char *connstr) { + int r = 0; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + if (dsn) { + CHK_TEST(open_connect(dsn, uid, pwd, &env, &conn)); + } else { + CHK_TEST(open_driver_connect(connstr, &env, &conn)); + } + + r = do_prepare_in_conn(env, conn); + + SQLDisconnect(conn); + SQLFreeConnect(conn); + SQLFreeEnv(env); + return r ? 1 : 0; +} + +typedef struct { + int dummy; + int64_t ts; + SQLLEN ts_len; + int8_t v1; + SQLLEN v1_len; + int16_t v2; + SQLLEN v2_len; + int32_t v4; + SQLLEN v4_len; + int64_t v8; + SQLLEN v8_len; +} test_v_t; + +static int do_insert_in_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, int64_t *ts, insert_arg_t *arg) { + SQLRETURN r = SQL_SUCCESS; + int batch_size = arg->batch_size; + test_v_t *recs = NULL; + do { + const char *sql = "insert into test.v (ts, v1, v2, v4, v8) values (?, ?, ?, ?, ?)"; + r = SQLPrepare(stmt, (SQLCHAR*)sql, SQL_NTS); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + + test_v_t *base = NULL; + + r = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &base->ts, 0, &base->ts_len); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_TINYINT, SQL_TINYINT, 0, 0, &base->v1, 0, &base->v1_len); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0, &base->v2, 0, &base->v2_len); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &base->v4, 0, &base->v4_len); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + r = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &base->v8, 0, &base->v8_len); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_BIND_TYPE, (SQLPOINTER)sizeof(*base), 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + base = NULL; + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR, &base, 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + size_t n_recs = (size_t)batch_size; + recs = (test_v_t*)calloc(n_recs, sizeof(*recs)); + OILE(recs, ""); + + SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)n_recs, 0); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + + base = recs; + + for (int batch=0; batchbatchs; ++batch) { + for (int i=0; idummy = 0; + rec->ts = *ts + i; + rec->ts_len = sizeof(rec->ts); + rec->v1 = (int8_t)rand(); + rec->v1_len = sizeof(rec->v1); + rec->v2 = (int16_t)rand(); + rec->v2_len = sizeof(rec->v2); + rec->v4 = rand(); + rec->v4_len = sizeof(rec->v4); + rec->v8 = rand(); + rec->v8_len = sizeof(rec->v8); + } + + *ts += (int64_t)n_recs; + + r = SQLExecute(stmt); + CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); + if (r) break; + } + } while (0); + + free(recs); + return r ? -1 : 0; +} + +static int do_insert_in_conn(SQLHENV env, SQLHDBC conn, insert_arg_t *arg) { + SQLHSTMT stmt = {0}; + int64_t ts = 1502535178128; + int r = 0; + CHK_TEST(create_statement(env, conn, &stmt)); + for (int i=0; i<1 && ibatchs; ++i) { + r = do_insert_in_stmt(env, conn, stmt, &ts, arg); + if (r) break; + if (!arg->keep_stmt_among_batchs) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + r = create_statement(env, conn, &stmt); + if (r) break; + } + } + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return r ? 1 : 0; +} + +static int do_insert_batch(const char *dsn, const char *uid, const char *pwd, const char *connstr, insert_arg_t *arg, const char *sqls[]) { + int r = 0; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + if (dsn) { + CHK_TEST(open_connect(dsn, uid, pwd, &env, &conn)); + } else { + CHK_TEST(open_driver_connect(connstr, &env, &conn)); + } + + SQLHSTMT stmt = {0}; + CHK_TEST(create_statement(env, conn, &stmt)); + CHK_TEST(do_statements(stmt, sqls)); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + OD("................"); + r = do_insert_in_conn(env, conn, arg); + OD("................"); + + SQLDisconnect(conn); + SQLFreeConnect(conn); + SQLFreeEnv(env); + return r ? 1 : 0; +} + +static int inited = 0; +static void init_once(void) { + if (inited) return; + + int r = taos_init(); + if (r) OILE(0, ""); + inited = 1; +} + +static int do_sqls(TAOS *taos, const char *sqls[]) { + for (int i=0; sqls[i]; ++i) { + OD("[%s]", sqls[i]); + TAOS_RES *res = taos_query(taos, sqls[i]); + if (!res) { + int e = terrno; + OD("taos_query [%s] failed: [%d]%s", sqls[i], e, tstrerror(e)); + return -1; + } + int e = taos_errno(res); + if (e) { + OD("taos_query [%s] failed: [%d]%s", sqls[i], e, tstrerror(e)); + } + taos_stop_query(res); + if (e) return -1; + } + return 0; +} + +static int do_taos_query(TAOS *taos, insert_arg_t *arg) { + char **sqls = (char**)calloc((size_t)arg->batchs, sizeof(*sqls)); + if (!sqls) { + OILE(0, "out of memory"); + } + + int64_t ts = 1502535178128; + for (int i=0; ibatchs; ++i) { + size_t bytes = 100 * (size_t)arg->batch_size; + sqls[i] = (char*)malloc(bytes); + OILE(sqls[i], ""); + char *p = sqls[i]; + size_t count = 0; + + while (1) { + int n = 0; + n = snprintf(p, bytes, "insert into test.v values"); + OILE(n>0, ""); + if (p) p += n; + OILE(bytes>n, ""); + if (bytes>=n) bytes -= (size_t)n; + else bytes = 0; + count += (size_t)n; + + for (int j=0; jbatch_size; ++j) { + int8_t v1 = (int8_t)rand(); if (v1==INT8_MIN) v1++; + int16_t v2 = (int16_t)rand(); if (v2==INT16_MIN) v2++; + int32_t v4 = (int32_t)rand(); if (v4==INT32_MIN) v4++; + int64_t v8 = (int64_t)rand(); if (v8==INT64_MIN) v8++; + n = snprintf(p, bytes, " (%" PRId64 ", %d, %d, %d, %" PRId64 ")", ts + i*arg->batch_size + j, (int)v1, (int)v2, v4, v8); + OILE(n>0, ""); + if (p) p += n; + OILE(bytes>n, ""); + if (bytes>=n) bytes -= (size_t)n; + else bytes = 0; + count += (size_t)n; + } + + if (p) break; + OILE(0, ""); + } + } + + OD(".............."); + for (int i=0; ibatchs; ++i) { + TAOS_RES *res = taos_query(taos, sqls[i]); + if (!res) { + int e = terrno; + OD("taos_query [%s] failed: [%d]%s", sqls[i], e, tstrerror(e)); + return -1; + } + int e = taos_errno(res); + if (e) { + OD("taos_query [%s] failed: [%d]%s", sqls[i], e, tstrerror(e)); + } + taos_stop_query(res); + if (e) return -1; + } + OD(".............."); + + for (int i=0; ibatchs; ++i) { + free(sqls[i]); + } + free(sqls); + + return 0; +} + +static int do_taos_stmt(TAOS *taos, insert_arg_t *arg) { + TAOS_STMT *stmt = taos_stmt_init(taos); + OILE(stmt, ""); + const char *sql = "insert into test.v values (?,?,?,?,?)"; + int r = 0; + do { + r = taos_stmt_prepare(stmt, sql, (unsigned long)strlen(sql)); + if (r) { + OD("taos_stmt_prepare [%s] failed: [%d]%s", sql, r, tstrerror(r)); + break; + } + int64_t ts = 1502535178128; + TAOS_BIND *bindings = (TAOS_BIND*)calloc(5, sizeof(*bindings)); + TAOS_BIND *b_ts = bindings + 0; + TAOS_BIND *b_v1 = bindings + 1; + TAOS_BIND *b_v2 = bindings + 2; + TAOS_BIND *b_v4 = bindings + 3; + TAOS_BIND *b_v8 = bindings + 4; + b_ts->buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + b_ts->buffer_length = sizeof(b_ts->u.ts); + b_ts->length = &b_ts->buffer_length; + b_ts->buffer = &b_ts->u.ts; + b_ts->is_null = NULL; + + b_v1->buffer_type = TSDB_DATA_TYPE_TINYINT; + b_v1->buffer_length = sizeof(b_v1->u.v1); + b_v1->length = &b_v1->buffer_length; + b_v1->buffer = &b_v1->u.v1; + b_v1->is_null = NULL; + + b_v2->buffer_type = TSDB_DATA_TYPE_SMALLINT; + b_v2->buffer_length = sizeof(b_v2->u.v2); + b_v2->length = &b_v2->buffer_length; + b_v2->buffer = &b_v2->u.v2; + b_v2->is_null = NULL; + + b_v4->buffer_type = TSDB_DATA_TYPE_INT; + b_v4->buffer_length = sizeof(b_v4->u.v4); + b_v4->length = &b_v4->buffer_length; + b_v4->buffer = &b_v4->u.v4; + b_v4->is_null = NULL; + + b_v8->buffer_type = TSDB_DATA_TYPE_BIGINT; + b_v8->buffer_length = sizeof(b_v8->u.v8); + b_v8->length = &b_v8->buffer_length; + b_v8->buffer = &b_v8->u.v8; + b_v8->is_null = NULL; + + OILE(bindings, ""); + OD("................"); + for (int i=0; ibatchs; ++i) { + for (int j=0; jbatch_size; ++j) { + b_ts->u.ts = ts + i*arg->batch_size + j; + b_v1->u.v1 = (int8_t)rand(); + b_v2->u.v2 = (int16_t)rand(); + b_v4->u.v4 = (int32_t)rand(); + b_v8->u.v8 = (int64_t)rand(); + r = taos_stmt_bind_param(stmt, bindings); + if (r) { + OD("taos_stmt_bind_param failed: [%d]%s", r, tstrerror(r)); + break; + } + r = taos_stmt_add_batch(stmt); + if (r) { + OD("taos_stmt_add_batch failed: [%d]%s", r, tstrerror(r)); + break; + } + } + + if (r) break; + + r = taos_stmt_execute(stmt); + if (r) { + OD("taos_stmt_execute failed: [%d]%s", r, tstrerror(r)); + break; + } + } + OD("................"); + + free(bindings); + + if (r) break; + } while (0); + taos_stmt_close(stmt); + return r ? -1 : 0; +} + +static int do_insert_batch_taos(const char *dsn, const char *uid, const char *pwd, const char *connstr, insert_arg_t *arg, const char *sqls[]) { + int r = 0; + + init_once(); + + int port = 0; + char *ip = NULL; + const char *p = strchr(connstr, ':'); + if (p) { + ip = strndup(connstr, (size_t)(p-connstr)); + ++p; + sscanf(p, "%d", &port); + } else { + ip = strdup(connstr); + port = 6030; + } + if (!ip) { + OD("bad ip/port:[%s]", connstr); + return -1; + } + + TAOS *taos = NULL; + do { + taos = taos_connect(ip, uid, pwd, NULL, (uint16_t)port); + if (!taos) { + int e = terrno; + OD("taos_connect [%s/%d] failed:[%d]%s", ip, port, e, tstrerror(e)); + break; + } + r = do_sqls(taos, sqls); + if (r) break; + if (arg->use_taos_query) { + r = do_taos_query(taos, arg); + } else if (arg->use_taos_stmt) { + r = do_taos_stmt(taos, arg); + } else { + OILE(0, ""); + } + } while (0); + + if (taos) taos_close(taos); + free(ip); + + return r ? 1 : 0; +} + +static int do_debug_col_name_max_len(const char *dsn, const char *uid, const char *pwd, const char *connstr) { + SQLRETURN r; + SQLHENV env = {0}; + SQLHDBC conn = {0}; + r = SQLAllocEnv(&env); + if (r!=SQL_SUCCESS) { + D("SQLAllocEnv failed"); + return 1; + }; + do { + r = SQLAllocConnect(env, &conn); + CHK_RESULT(r, SQL_HANDLE_ENV, env, ""); + if (r!=SQL_SUCCESS) break; + do { + if (dsn) { + r = SQLConnect(conn, (SQLCHAR*)dsn, (SQLSMALLINT)(dsn ? strlen(dsn) : 0), + (SQLCHAR*)uid, (SQLSMALLINT)(uid ? strlen(uid) : 0), + (SQLCHAR*)pwd, (SQLSMALLINT)(pwd ? strlen(pwd) : 0)); + } else { + SQLCHAR buf[4096]; + SQLSMALLINT blen = 0; + SQLHDBC ConnectionHandle = conn; + SQLHWND WindowHandle = NULL; + SQLCHAR * InConnectionString = (SQLCHAR*)connstr; + SQLSMALLINT StringLength1 = (SQLSMALLINT)(connstr ? strlen(connstr) : 0); + SQLCHAR * OutConnectionString = buf; + SQLSMALLINT BufferLength = sizeof(buf); + SQLSMALLINT * StringLength2Ptr = &blen; + SQLUSMALLINT DriverCompletion = SQL_DRIVER_NOPROMPT; + r = SQLDriverConnect(ConnectionHandle, WindowHandle, InConnectionString, + StringLength1, OutConnectionString, BufferLength, + StringLength2Ptr, DriverCompletion); + } + CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); + if (r!=SQL_SUCCESS) break; + D("connected"); + if (1) { + SQLSMALLINT maxColumnNameLength = 0; + SQLSMALLINT len = 0; + r = SQLGetInfo(conn, SQL_MAX_COLUMN_NAME_LEN, &maxColumnNameLength, sizeof(SQLSMALLINT), &len); + CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); + if (r!=SQL_SUCCESS) break; + D("maxColumnNameLength: %d", maxColumnNameLength); + } + } while (0); + SQLFreeConnect(conn); + conn = NULL; + } while (0); + SQLFreeEnv(env); + env = NULL; + + return (r==SQL_SUCCESS) ? 0 : 1; +} + +void usage(const char *arg0) { + fprintf(stdout, "%s usage:\n", arg0); + fprintf(stdout, "%s [--dsn ] [--uid ] [--pwd ] [-C ] [--sts ]\n", arg0); + fprintf(stdout, " --dsn : DSN\n"); + fprintf(stdout, " --uid : UID\n"); + fprintf(stdout, " --pwd : PWD\n"); + fprintf(stdout, " -C : driver connection string\n"); + fprintf(stdout, " --sts : file where statements store\n"); +} + +int main(int argc, char *argv[]) { + srand((unsigned)time(0)); + const char *conn_str = NULL; + const char *dsn = NULL; + const char *uid = NULL; + const char *pwd = NULL; + const char *sts = NULL; // statements file + int debug_col_name_max_len = 0; + int prepare = 0; + int insert = 0; + insert_arg_t insert_arg = { + .batch_size = 100, + .batchs = 100, + .keep_stmt_among_batchs = 0 + }; + for (size_t i=1; i=argc) { + D(" expected but got nothing"); + return 1; + } + sscanf(argv[i], "%d", &insert_arg.batch_size); + if (insert_arg.batch_size<=0) { + D(" invalid"); + return 1; + } + continue; + } + if (strcmp(arg, "--batchs")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + sscanf(argv[i], "%d", &insert_arg.batchs); + if (insert_arg.batchs<=0) { + D(" invalid"); + return 1; + } + continue; + } + if (strcmp(arg, "--keep_stmt_among_batchs")==0) { + insert_arg.keep_stmt_among_batchs = 1; + continue; + } + if (strcmp(arg, "--dsn")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + if (conn_str) { + D("-C has already been specified"); + return 1; + } + dsn = argv[i]; + continue; + } + if (strcmp(arg, "--uid")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + uid = argv[i]; + continue; + } + if (strcmp(arg, "--pwd")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + pwd = argv[i]; + continue; + } + if (strcmp(arg, "-C")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + if (dsn || uid || pwd) { + D("either of --dsn/--uid/--pwd has already been specified"); + return 1; + } + conn_str = argv[i]; + continue; + } + if (strcmp(arg, "--sts")==0) { + ++i; + if (i>=argc) { + D(" expected but got nothing"); + return 1; + } + sts = argv[i]; + continue; + } + if (strcmp(arg, "-p")==0) { + prepare = 1; + continue; + } + } + if (debug_col_name_max_len) { + int r = do_debug_col_name_max_len(dsn, uid, pwd, conn_str); + if (r) return 1; + } + if (insert) { + const char *sqls[] = { + "drop database if exists test", + "create database test", + "create table test.v (ts timestamp, v1 tinyint, v2 smallint, v4 int, v8 bigint)", + NULL + }; + int r = 0; + if (insert_arg.use_odbc) { + r = do_insert_batch(dsn, uid, pwd, conn_str, &insert_arg, sqls); + } else { + r = do_insert_batch_taos(dsn, uid, pwd, conn_str, &insert_arg, sqls); + } + if (r) return 1; + } + if (sts) { + int r = test_sqls(dsn, uid, pwd, conn_str, sts); + if (r) return 1; + } + if (prepare) { + int r = do_prepare(dsn, uid, pwd, conn_str); + if (r) return 1; + } + D("Done!"); + return 0; +} + diff --git a/src/connector/odbc/examples/c/main.cpp b/src/connector/odbc/examples/c/main.cpp new file mode 100644 index 0000000000..b719534f98 --- /dev/null +++ b/src/connector/odbc/examples/c/main.cpp @@ -0,0 +1,654 @@ +/******************************************************************************* +/* ODBCSQL: a sample program that implements an ODBC command line interpreter. +/* +/* USAGE: ODBCSQL DSN= or +/* ODBCSQL FILEDSN= or +/* ODBCSQL DRIVER={driver name} +/* +/* +/* Copyright(c) Microsoft Corporation. This is a WDAC sample program and +/* is not suitable for use in production environments. +/* +/******************************************************************************/ +/* Modules: +/* Main Main driver loop, executes queries. +/* DisplayResults Display the results of the query if any +/* AllocateBindings Bind column data +/* DisplayTitles Print column titles +/* SetConsole Set console display mode +/* HandleError Show ODBC error messages +/******************************************************************************/ + +#define _UNICODE +#define UNICODE + +#include +#include +#include +#include +#include +#include +#include +#include + + +/*******************************************/ +/* Macro to call ODBC functions and */ +/* report an error on failure. */ +/* Takes handle, handle type, and stmt */ +/*******************************************/ + +#define TRYODBC(h, ht, x) { RETCODE rc = x;\ + if (rc != SQL_SUCCESS) \ + { \ + HandleDiagnosticRecord (h, ht, rc); \ + } \ + if (rc == SQL_ERROR) \ + { \ + fwprintf(stderr, L"Error in " L#x L"\n"); \ + goto Exit; \ + } \ + } +/******************************************/ +/* Structure to store information about */ +/* a column. +/******************************************/ + +typedef struct STR_BINDING { + SQLSMALLINT cDisplaySize; /* size to display */ + WCHAR *wszBuffer; /* display buffer */ + SQLLEN indPtr; /* size or null */ + BOOL fChar; /* character col? */ + struct STR_BINDING *sNext; /* linked list */ +} BINDING; + + + +/******************************************/ +/* Forward references */ +/******************************************/ + +void HandleDiagnosticRecord (SQLHANDLE hHandle, + SQLSMALLINT hType, + RETCODE RetCode); + +void DisplayResults(HSTMT hStmt, + SQLSMALLINT cCols); + +void AllocateBindings(HSTMT hStmt, + SQLSMALLINT cCols, + BINDING** ppBinding, + SQLSMALLINT* pDisplay); + + +void DisplayTitles(HSTMT hStmt, + DWORD cDisplaySize, + BINDING* pBinding); + +void SetConsole(DWORD cDisplaySize, + BOOL fInvert); + +/*****************************************/ +/* Some constants */ +/*****************************************/ + + +#define DISPLAY_MAX 50 // Arbitrary limit on column width to display +#define DISPLAY_FORMAT_EXTRA 3 // Per column extra display bytes (| ) +#define DISPLAY_FORMAT L"%c %*.*s " +#define DISPLAY_FORMAT_C L"%c %-*.*s " +#define NULL_SIZE 6 // +#define SQL_QUERY_SIZE 1000 // Max. Num characters for SQL Query passed in. + +#define PIPE L'|' + +SHORT gHeight = 80; // Users screen height + +int __cdecl wmain(int argc, _In_reads_(argc) WCHAR **argv) +{ + SQLHENV hEnv = NULL; + SQLHDBC hDbc = NULL; + SQLHSTMT hStmt = NULL; + WCHAR* pwszConnStr; + WCHAR wszInput[SQL_QUERY_SIZE]; + + // Allocate an environment + + if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) == SQL_ERROR) + { + fwprintf(stderr, L"Unable to allocate an environment handle\n"); + exit(-1); + } + + // Register this as an application that expects 3.x behavior, + // you must register something if you use AllocHandle + + TRYODBC(hEnv, + SQL_HANDLE_ENV, + SQLSetEnvAttr(hEnv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER)SQL_OV_ODBC3, + 0)); + + // Allocate a connection + TRYODBC(hEnv, + SQL_HANDLE_ENV, + SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc)); + + if (argc > 1) + { + pwszConnStr = *++argv; + } + else + { + pwszConnStr = L""; + } + + // Connect to the driver. Use the connection string if supplied + // on the input, otherwise let the driver manager prompt for input. + + TRYODBC(hDbc, + SQL_HANDLE_DBC, + SQLDriverConnect(hDbc, + GetDesktopWindow(), + pwszConnStr, + SQL_NTS, + NULL, + 0, + NULL, + SQL_DRIVER_COMPLETE)); + + fwprintf(stderr, L"Connected!\n"); + + TRYODBC(hDbc, + SQL_HANDLE_DBC, + SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt)); + + wprintf(L"Enter SQL commands, type (control)Z to exit\nSQL COMMAND>"); + + // Loop to get input and execute queries + + while(_fgetts(wszInput, SQL_QUERY_SIZE-1, stdin)) + { + RETCODE RetCode; + SQLSMALLINT sNumResults; + + // Execute the query + + if (!(*wszInput)) + { + wprintf(L"SQL COMMAND>"); + continue; + } + RetCode = SQLExecDirect(hStmt,wszInput, SQL_NTS); + + switch(RetCode) + { + case SQL_SUCCESS_WITH_INFO: + { + HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode); + // fall through + } + case SQL_SUCCESS: + { + // If this is a row-returning query, display + // results + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLNumResultCols(hStmt,&sNumResults)); + + if (sNumResults > 0) + { + DisplayResults(hStmt,sNumResults); + } + else + { + SQLLEN cRowCount; + + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLRowCount(hStmt,&cRowCount)); + + if (cRowCount >= 0) + { + wprintf(L"%Id %s affected\n", + cRowCount, + cRowCount == 1 ? L"row" : L"rows"); + } + } + break; + } + + case SQL_ERROR: + { + HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode); + break; + } + + default: + fwprintf(stderr, L"Unexpected return code %hd!\n", RetCode); + + } + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLFreeStmt(hStmt, SQL_CLOSE)); + + wprintf(L"SQL COMMAND>"); + } + +Exit: + + // Free ODBC handles and exit + + if (hStmt) + { + SQLFreeHandle(SQL_HANDLE_STMT, hStmt); + } + + if (hDbc) + { + SQLDisconnect(hDbc); + SQLFreeHandle(SQL_HANDLE_DBC, hDbc); + } + + if (hEnv) + { + SQLFreeHandle(SQL_HANDLE_ENV, hEnv); + } + + wprintf(L"\nDisconnected."); + + return 0; + +} + +/************************************************************************ +/* DisplayResults: display results of a select query +/* +/* Parameters: +/* hStmt ODBC statement handle +/* cCols Count of columns +/************************************************************************/ + +void DisplayResults(HSTMT hStmt, + SQLSMALLINT cCols) +{ + BINDING *pFirstBinding, *pThisBinding; + SQLSMALLINT cDisplaySize; + RETCODE RetCode = SQL_SUCCESS; + int iCount = 0; + + // Allocate memory for each column + + AllocateBindings(hStmt, cCols, &pFirstBinding, &cDisplaySize); + + // Set the display mode and write the titles + + DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding); + + + // Fetch and display the data + + bool fNoData = false; + + do { + // Fetch a row + + if (iCount++ >= gHeight - 2) + { + int nInputChar; + bool fEnterReceived = false; + + while(!fEnterReceived) + { + wprintf(L" "); + SetConsole(cDisplaySize+2, TRUE); + wprintf(L" Press ENTER to continue, Q to quit (height:%hd)", gHeight); + SetConsole(cDisplaySize+2, FALSE); + + nInputChar = _getch(); + wprintf(L"\n"); + if ((nInputChar == 'Q') || (nInputChar == 'q')) + { + goto Exit; + } + else if ('\r' == nInputChar) + { + fEnterReceived = true; + } + // else loop back to display prompt again + } + + iCount = 1; + DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding); + } + + TRYODBC(hStmt, SQL_HANDLE_STMT, RetCode = SQLFetch(hStmt)); + + if (RetCode == SQL_NO_DATA_FOUND) + { + fNoData = true; + } + else + { + + // Display the data. Ignore truncations + + for (pThisBinding = pFirstBinding; + pThisBinding; + pThisBinding = pThisBinding->sNext) + { + if (pThisBinding->indPtr != SQL_NULL_DATA) + { + wprintf(pThisBinding->fChar ? DISPLAY_FORMAT_C:DISPLAY_FORMAT, + PIPE, + pThisBinding->cDisplaySize, + pThisBinding->cDisplaySize, + pThisBinding->wszBuffer); + } + else + { + wprintf(DISPLAY_FORMAT_C, + PIPE, + pThisBinding->cDisplaySize, + pThisBinding->cDisplaySize, + L""); + } + } + wprintf(L" %c\n",PIPE); + } + } while (!fNoData); + + SetConsole(cDisplaySize+2, TRUE); + wprintf(L"%*.*s", cDisplaySize+2, cDisplaySize+2, L" "); + SetConsole(cDisplaySize+2, FALSE); + wprintf(L"\n"); + +Exit: + // Clean up the allocated buffers + + while (pFirstBinding) + { + pThisBinding = pFirstBinding->sNext; + free(pFirstBinding->wszBuffer); + free(pFirstBinding); + pFirstBinding = pThisBinding; + } +} + +/************************************************************************ +/* AllocateBindings: Get column information and allocate bindings +/* for each column. +/* +/* Parameters: +/* hStmt Statement handle +/* cCols Number of columns in the result set +/* *lppBinding Binding pointer (returned) +/* lpDisplay Display size of one line +/************************************************************************/ + +void AllocateBindings(HSTMT hStmt, + SQLSMALLINT cCols, + BINDING **ppBinding, + SQLSMALLINT *pDisplay) +{ + SQLSMALLINT iCol; + BINDING *pThisBinding, *pLastBinding = NULL; + SQLLEN cchDisplay, ssType; + SQLSMALLINT cchColumnNameLength; + + *pDisplay = 0; + + for (iCol = 1; iCol <= cCols; iCol++) + { + pThisBinding = (BINDING *)(malloc(sizeof(BINDING))); + if (!(pThisBinding)) + { + fwprintf(stderr, L"Out of memory!\n"); + exit(-100); + } + + if (iCol == 1) + { + *ppBinding = pThisBinding; + } + else + { + pLastBinding->sNext = pThisBinding; + } + pLastBinding = pThisBinding; + + + // Figure out the display length of the column (we will + // bind to char since we are only displaying data, in general + // you should bind to the appropriate C type if you are going + // to manipulate data since it is much faster...) + + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLColAttribute(hStmt, + iCol, + SQL_DESC_DISPLAY_SIZE, + NULL, + 0, + NULL, + &cchDisplay)); + + + // Figure out if this is a character or numeric column; this is + // used to determine if we want to display the data left- or right- + // aligned. + + // SQL_DESC_CONCISE_TYPE maps to the 1.x SQL_COLUMN_TYPE. + // This is what you must use if you want to work + // against a 2.x driver. + + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLColAttribute(hStmt, + iCol, + SQL_DESC_CONCISE_TYPE, + NULL, + 0, + NULL, + &ssType)); + + pThisBinding->fChar = (ssType == SQL_CHAR || + ssType == SQL_VARCHAR || + ssType == SQL_LONGVARCHAR); + + pThisBinding->sNext = NULL; + + // Arbitrary limit on display size + if (cchDisplay > DISPLAY_MAX) + cchDisplay = DISPLAY_MAX; + + // Allocate a buffer big enough to hold the text representation + // of the data. Add one character for the null terminator + + pThisBinding->wszBuffer = (WCHAR *)malloc((cchDisplay+1) * sizeof(WCHAR)); + + if (!(pThisBinding->wszBuffer)) + { + fwprintf(stderr, L"Out of memory!\n"); + exit(-100); + } + + // Map this buffer to the driver's buffer. At Fetch time, + // the driver will fill in this data. Note that the size is + // count of bytes (for Unicode). All ODBC functions that take + // SQLPOINTER use count of bytes; all functions that take only + // strings use count of characters. + + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLBindCol(hStmt, + iCol, + SQL_C_TCHAR, + (SQLPOINTER) pThisBinding->wszBuffer, + (cchDisplay + 1) * sizeof(WCHAR), + &pThisBinding->indPtr)); + + + // Now set the display size that we will use to display + // the data. Figure out the length of the column name + + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLColAttribute(hStmt, + iCol, + SQL_DESC_NAME, + NULL, + 0, + &cchColumnNameLength, + NULL)); + + pThisBinding->cDisplaySize = max((SQLSMALLINT)cchDisplay, cchColumnNameLength); + if (pThisBinding->cDisplaySize < NULL_SIZE) + pThisBinding->cDisplaySize = NULL_SIZE; + + *pDisplay += pThisBinding->cDisplaySize + DISPLAY_FORMAT_EXTRA; + + } + + return; + +Exit: + + exit(-1); + + return; +} + + +/************************************************************************ +/* DisplayTitles: print the titles of all the columns and set the +/* shell window's width +/* +/* Parameters: +/* hStmt Statement handle +/* cDisplaySize Total display size +/* pBinding list of binding information +/************************************************************************/ + +void DisplayTitles(HSTMT hStmt, + DWORD cDisplaySize, + BINDING *pBinding) +{ + WCHAR wszTitle[DISPLAY_MAX]; + SQLSMALLINT iCol = 1; + + SetConsole(cDisplaySize+2, TRUE); + + for (; pBinding; pBinding = pBinding->sNext) + { + TRYODBC(hStmt, + SQL_HANDLE_STMT, + SQLColAttribute(hStmt, + iCol++, + SQL_DESC_NAME, + wszTitle, + sizeof(wszTitle), // Note count of bytes! + NULL, + NULL)); + + wprintf(DISPLAY_FORMAT_C, + PIPE, + pBinding->cDisplaySize, + pBinding->cDisplaySize, + wszTitle); + } + +Exit: + + wprintf(L" %c", PIPE); + SetConsole(cDisplaySize+2, FALSE); + wprintf(L"\n"); + +} + + +/************************************************************************ +/* SetConsole: sets console display size and video mode +/* +/* Parameters +/* siDisplaySize Console display size +/* fInvert Invert video? +/************************************************************************/ + +void SetConsole(DWORD dwDisplaySize, + BOOL fInvert) +{ + HANDLE hConsole; + CONSOLE_SCREEN_BUFFER_INFO csbInfo; + + // Reset the console screen buffer size if necessary + + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + if (hConsole != INVALID_HANDLE_VALUE) + { + if (GetConsoleScreenBufferInfo(hConsole, &csbInfo)) + { + if (csbInfo.dwSize.X < (SHORT) dwDisplaySize) + { + csbInfo.dwSize.X = (SHORT) dwDisplaySize; + SetConsoleScreenBufferSize(hConsole, csbInfo.dwSize); + } + + gHeight = csbInfo.dwSize.Y; + } + + if (fInvert) + { + SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes | BACKGROUND_BLUE)); + } + else + { + SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes & ~(BACKGROUND_BLUE))); + } + } +} + + +/************************************************************************ +/* HandleDiagnosticRecord : display error/warning information +/* +/* Parameters: +/* hHandle ODBC handle +/* hType Type of handle (HANDLE_STMT, HANDLE_ENV, HANDLE_DBC) +/* RetCode Return code of failing command +/************************************************************************/ + +void HandleDiagnosticRecord (SQLHANDLE hHandle, + SQLSMALLINT hType, + RETCODE RetCode) +{ + SQLSMALLINT iRec = 0; + SQLINTEGER iError; + WCHAR wszMessage[1000]; + WCHAR wszState[SQL_SQLSTATE_SIZE+1]; + + + if (RetCode == SQL_INVALID_HANDLE) + { + fwprintf(stderr, L"Invalid handle!\n"); + return; + } + + while (SQLGetDiagRec(hType, + hHandle, + ++iRec, + wszState, + &iError, + wszMessage, + (SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)), + (SQLSMALLINT *)NULL) == SQL_SUCCESS) + { + // Hide data truncated.. + if (wcsncmp(wszState, L"01004", 5)) + { + fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError); + } + } +} diff --git a/src/connector/odbc/examples/go/odbc.go b/src/connector/odbc/examples/go/odbc.go new file mode 100644 index 0000000000..4d9c760c4e --- /dev/null +++ b/src/connector/odbc/examples/go/odbc.go @@ -0,0 +1,84 @@ +package main + +import ( + "context" + "database/sql" + "flag" + "log" + "os" + "os/signal" + "time" + _ "github.com/alexbrainman/odbc" +) + +var pool *sql.DB // Database connection pool. + +func main() { + id := flag.Int64("id", 32768, "person ID to find") + dsn := flag.String("dsn", os.Getenv("DSN"), "connection data source name") + flag.Parse() + + if len(*dsn) == 0 { + log.Fatal("missing dsn flag") + } + if *id == 0 { + log.Fatal("missing person ID") + } + var err error + + // Opening a driver typically will not attempt to connect to the database. + pool, err = sql.Open("odbc", *dsn) + if err != nil { + // This will not be a connection error, but a DSN parse error or + // another initialization error. + log.Fatal("unable to use data source name", err) + } + defer pool.Close() + + pool.SetConnMaxLifetime(0) + pool.SetMaxIdleConns(3) + pool.SetMaxOpenConns(3) + + ctx, stop := context.WithCancel(context.Background()) + defer stop() + + appSignal := make(chan os.Signal, 3) + signal.Notify(appSignal, os.Interrupt) + + go func() { + select { + case <-appSignal: + stop() + } + }() + + Ping(ctx) + + Query(ctx, *id) +} + +// Ping the database to verify DSN provided by the user is valid and the +// server accessible. If the ping fails exit the program with an error. +func Ping(ctx context.Context) { + ctx, cancel := context.WithTimeout(ctx, 1*time.Second) + defer cancel() + + if err := pool.PingContext(ctx); err != nil { + log.Fatalf("unable to connect to database: %v", err) + } +} + +// Query the database for the information requested and prints the results. +// If the query fails exit the program with an error. +func Query(ctx context.Context, id int64) { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + var name string + err := pool.QueryRowContext(ctx, "select name from m.t").Scan(&name) + if err != nil { + log.Fatal("unable to execute search query", err) + } + log.Println("name=", name) +} + diff --git a/src/connector/odbc/examples/js/.gitignore b/src/connector/odbc/examples/js/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/connector/odbc/examples/js/odbc.js b/src/connector/odbc/examples/js/odbc.js new file mode 100755 index 0000000000..78a4365c11 --- /dev/null +++ b/src/connector/odbc/examples/js/odbc.js @@ -0,0 +1,122 @@ +#!/usr/bin/env node + +const odbc = require('odbc'); +const path = require('path'); + +function usage() { + var arg = path.basename(process.argv[1]); + console.error(`usage:`); + console.error(`${arg} --DSN --UID --PWD --Server `); + console.error(`${arg} -C `); + console.error(` conn_str eg: 'DSN={TAOS_DSN};UID=root;PWD=taosdata;Server=host:port'`); +} + +var cfg = { }; + +if (process.argv.length==2) { + usage(); + process.exit(0); +} + +var i; +for (i=2; i=process.argv.length) { + console.error(`expecting after --DSN but got nothing`); + usage(process.argv[1]); + process.exit(1); + } + arg = process.argv[i]; + cfg.dsn = arg; + continue; + } + if (arg=="--UID") { + ++i; + if (i>=process.argv.length) { + console.error(`expecting after --UID but got nothing`); + usage(process.argv[1]); + process.exit(1); + } + arg = process.argv[i]; + cfg.uid = arg; + continue; + } + if (arg=="--PWD") { + ++i; + if (i>=process.argv.length) { + console.error(`expecting after --PWD but got nothing`); + usage(process.argv[1]); + process.exit(1); + } + arg = process.argv[i]; + cfg.pwd = arg; + continue; + } + if (arg=="--Server") { + ++i; + if (i>=process.argv.length) { + console.error(`expecting after --Server but got nothing`); + usage(process.argv[1]); + process.exit(1); + } + arg = process.argv[i]; + cfg.server = arg; + continue; + } + if (arg=="-C") { + ++i; + if (i>=process.argv.length) { + console.error(`expecting after -C but got nothing`); + console.error(` conn_str eg: 'DSN={TAOS_DSN};UID=root;PWD=taosdata;Server=host:port'`); + process.exit(1); + } + arg = process.argv[i]; + cfg.conn_str = arg; + continue; + } + console.error(`unknown argument: [${arg}]`); + usage(process.argv[1]); + process.exit(1); +} + +var connectionString = cfg.conn_str; + +if (!cfg.conn_str) { + connectionString = `DSN={${cfg.dsn}}; UID=${cfg.uid}; PWD=${cfg.pwd}; Server=${cfg.server}`; +} + +(async function () { + const connStr = connectionString; + try { + console.log(`connecting [${connStr}]...`); + const connection = await odbc.connect(connStr); + await connection.query('create database if not exists m'); + await connection.query('use m'); + await connection.query('drop table if exists t'); + await connection.query('create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(10), name nchar(3))'); + await connection.query('insert into t values("2020-01-02 12:34:56.781", 1, 127, 32767, 32768, 32769, 123.456, 789.987, "hello", "我和你")'); + console.log('.........'); + result = await connection.query('select * from t'); + console.log(result[0]); + + + statement = await connection.createStatement(); + await statement.prepare('INSERT INTO t (ts, v1) VALUES(?, ?)'); + await statement.bind(['2020-02-02 11:22:33.449', 89]); + result = await statement.execute(); + console.log(result); + + result = await connection.query('select * from t'); + console.log(result[0]); + console.log(result[1]); + } catch (e) { + console.log('error:', e); + } +})(); + diff --git a/src/connector/odbc/examples/js/package.json b/src/connector/odbc/examples/js/package.json new file mode 100644 index 0000000000..28a04dc32f --- /dev/null +++ b/src/connector/odbc/examples/js/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "odbc": "^2.3.6" + } +} diff --git a/src/connector/odbc/examples/lua/odbc.lua b/src/connector/odbc/examples/lua/odbc.lua new file mode 100644 index 0000000000..e3388358cd --- /dev/null +++ b/src/connector/odbc/examples/lua/odbc.lua @@ -0,0 +1,48 @@ +package.cpath = package.cpath .. ";/usr/local/lib/lib?.dylib" +-- load driver +local driver = require "luasql.odbc" +-- create environment object +env = assert (driver.odbc()) +-- connect to data source +con = assert (env:connect("TAOS_DSN", "root", "taosdata")) +-- reset our table +-- res = con:execute"DROP TABLE people" +-- res = assert (con:execute[[ +-- CREATE TABLE people( +-- name varchar(50), +-- email varchar(50) +-- ) +-- ]]) +-- -- add a few elements +-- list = { +-- { name="Jose das Couves", email="jose@couves.com", }, +-- { name="Manoel Joaquim", email="manoel.joaquim@cafundo.com", }, +-- { name="Maria das Dores", email="maria@dores.com", }, +-- } +-- for i, p in pairs (list) do +-- res = assert (con:execute(string.format([[ +-- INSERT INTO people +-- VALUES ('%s', '%s')]], p.name, p.email) +-- )) +-- end +-- -- retrieve a cursor +-- cur = assert (con:execute"SELECT name, email from people") +-- -- print all rows, the rows will be indexed by field names +-- row = cur:fetch ({}, "a") +-- while row do +-- print(string.format("Name: %s, E-mail: %s", row.name, row.email)) +-- -- reusing the table of results +-- row = cur:fetch (row, "a") +-- end +cur = assert(con:execute"select * from m.t") +row = cur:fetch({}, "a") +while row do + print(string.format("Name: %s", row.name)) + row = cur:fetch(row, "a") +end + +-- close everything +cur:close() -- already closed because all the result set was consumed +con:close() +env:close() + diff --git a/src/connector/odbc/examples/py/odbc.py b/src/connector/odbc/examples/py/odbc.py new file mode 100644 index 0000000000..e6a4bc73ae --- /dev/null +++ b/src/connector/odbc/examples/py/odbc.py @@ -0,0 +1,111 @@ +import pyodbc +import argparse +import sys + +parser = argparse.ArgumentParser(description='Access TDengine via ODBC.') +parser.add_argument('--DSN', help='DSN to use') +parser.add_argument('--UID', help='UID to use') +parser.add_argument('--PWD', help='PWD to use') +parser.add_argument('--Server', help='Server to use') +parser.add_argument('-C', metavar='CONNSTR', help='Connection string to use') + +args = parser.parse_args() + +a = 'DSN=%s'%args.DSN if args.DSN else None +b = 'UID=%s'%args.UID if args.UID else None +c = 'PWD=%s'%args.PWD if args.PWD else None +d = 'Server=%s'%args.Server if args.Server else None +conn_str = ';'.join(filter(None, [a,b,c,d])) if args.DSN else None +conn_str = conn_str if conn_str else args.C +if not conn_str: + parser.print_help(file=sys.stderr) + exit() + +print('connecting: [%s]' % conn_str) +cnxn = pyodbc.connect(conn_str, autocommit=True) +cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8') + +cursor = cnxn.cursor() +cursor.execute("drop database if exists db"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("create database db"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("create table db.mt (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(10), blob nchar(10))"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("insert into db.mt values('2020-10-13 06:44:00.123', 1, 127, 32767, 2147483647, 32769, 123.456, 789.987, 'hello', 'helloworld')") +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00.234", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo".encode('utf-8'), "wo哈rlxd129") +##cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", 1502535178128, 9223372036854775807, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo".encode('utf-8'), "wo哈rlxd123"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute(""" +INSERT INTO db.mt (ts,b,v1,v2,v4,v8,f4,f8,bin,blob) values (?,?,?,?,?,?,?,?,?,?) +""", +"2020-12-12 00:00:00", +'true', +'-127', +'-32767', +'-2147483647', +'-9223372036854775807', +'-1.23e10', +'-11.23e6', +'abcdefghij'.encode('utf-8'), +"人啊大发测试及abc") +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("drop database if exists db"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("create database db"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(4), blob nchar(4))"); +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hell', 'w我你z')") +cursor.close() + +cursor = cnxn.cursor() +cursor.execute("create table db.v (ts timestamp, v1 tinyint, v2 smallint, name nchar(10), ts2 timestamp)") +cursor.close() + +params = [ ('2020-10-16 00:00:00.123', 19, '2111-01-02 01:02:03.123'), + ('2020-10-16 00:00:01', 41, '2111-01-02 01:02:03.423'), + ('2020-10-16 00:00:02', 57, '2111-01-02 01:02:03.153'), + ('2020-10-16 00:00:03.009', 26, '2111-01-02 01:02:03.623') ] +cursor = cnxn.cursor() +cursor.fast_executemany = True +print('py:...................') +cursor.executemany("insert into db.v (ts, v1, ts2) values (?, ?, ?)", params) +print('py:...................') +cursor.close() + +## cursor = cnxn.cursor() +## cursor.execute("SELECT * from db.v where v1 > ?", 4) +## row = cursor.fetchone() +## while row: +## print(row) +## row = cursor.fetchone() +## cursor.close() +## +## cursor = cnxn.cursor() +## cursor.execute("SELECT * from db.v where v1 > ?", '5') +## row = cursor.fetchone() +## while row: +## print(row) +## row = cursor.fetchone() +## cursor.close() + diff --git a/src/connector/odbc/examples/rust/.gitignore b/src/connector/odbc/examples/rust/.gitignore new file mode 100644 index 0000000000..03314f77b5 --- /dev/null +++ b/src/connector/odbc/examples/rust/.gitignore @@ -0,0 +1 @@ +Cargo.lock diff --git a/src/connector/odbc/examples/rust/main/Cargo.toml b/src/connector/odbc/examples/rust/main/Cargo.toml new file mode 100644 index 0000000000..171dcf52b2 --- /dev/null +++ b/src/connector/odbc/examples/rust/main/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "main" +version = "0.1.0" +authors = ["freemine "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +odbc = "0.17.0" +env_logger = "0.8.2" + diff --git a/src/connector/odbc/examples/rust/main/src/main.rs b/src/connector/odbc/examples/rust/main/src/main.rs new file mode 100644 index 0000000000..112f0d309b --- /dev/null +++ b/src/connector/odbc/examples/rust/main/src/main.rs @@ -0,0 +1,49 @@ +extern crate odbc; +// Use this crate and set environmet variable RUST_LOG=odbc to see ODBC warnings +extern crate env_logger; +use odbc::*; +use odbc_safe::AutocommitOn; +use std::env; + +fn main() { + + env_logger::init(); + + let conn_str = env::var("DSN").unwrap(); + match connect(&conn_str) { + Ok(()) => println!("Success"), + Err(diag) => println!("Error: {}", diag), + } +} + +fn connect(conn_str: &str) -> std::result::Result<(), DiagnosticRecord> { + + let env = create_environment_v3().map_err(|e| e.unwrap())?; + + let conn = env.connect_with_connection_string(conn_str)?; + execute_statement(&conn) +} + +fn execute_statement<'env>(conn: &Connection<'env, AutocommitOn>) -> Result<()> { + let stmt = Statement::with_parent(conn)?; + + match stmt.exec_direct("select * from m.t")? { + Data(mut stmt) => { + let cols = stmt.num_result_cols()?; + println!("cols: {}", cols); + while let Some(mut cursor) = stmt.fetch()? { + for i in 1..(cols + 1) { + match cursor.get_data::<&str>(i as u16)? { + Some(val) => print!(" {}", val), + None => print!(" NULL"), + } + } + println!(""); + } + } + NoData(_) => println!("Query executed, no data returned"), + } + + Ok(()) +} + diff --git a/src/connector/odbc/tests/create_data.stmts b/src/connector/odbc/samples/create_data.stmts similarity index 51% rename from src/connector/odbc/tests/create_data.stmts rename to src/connector/odbc/samples/create_data.stmts index 549cb583d8..3d41c0db64 100644 --- a/src/connector/odbc/tests/create_data.stmts +++ b/src/connector/odbc/samples/create_data.stmts @@ -1,12 +1,17 @@ +#P: positive sample +#N: negative sample + P:drop database if exists m; P:create database m; P:use m; P:drop table if exists t; -P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1)); -P:insert into t (ts, blob, name) values('2020-10-10 00:00:00', 0, 1); -P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.001', 1, 2); +P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1), ts2 nchar(148)); +#P:insert into t (ts, blob, name) values('2020-10-10 00:00:00', 0, 1); +#P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.001', 1, 2); P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.002', '你', '好'); P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.003', 'abc', 'd'); P:select * from t; +P:create table v (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1), ts2 nchar(23)); + diff --git a/src/connector/odbc/tests/query_data.stmts b/src/connector/odbc/samples/query_data.stmts similarity index 100% rename from src/connector/odbc/tests/query_data.stmts rename to src/connector/odbc/samples/query_data.stmts diff --git a/src/connector/odbc/tests/select.stmts b/src/connector/odbc/samples/select.stmts similarity index 100% rename from src/connector/odbc/tests/select.stmts rename to src/connector/odbc/samples/select.stmts diff --git a/src/connector/odbc/tests/simples.stmts b/src/connector/odbc/samples/simples.stmts similarity index 100% rename from src/connector/odbc/tests/simples.stmts rename to src/connector/odbc/samples/simples.stmts diff --git a/src/connector/odbc/src/CMakeLists.txt b/src/connector/odbc/src/CMakeLists.txt index 2699e1bc90..f0e50415e2 100644 --- a/src/connector/odbc/src/CMakeLists.txt +++ b/src/connector/odbc/src/CMakeLists.txt @@ -1,6 +1,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) PROJECT(TDengine) +add_subdirectory(base) + IF (TD_LINUX_64) FLEX_TARGET(todbcFlexScanner todbc_scanner.l @@ -15,12 +17,35 @@ IF (TD_LINUX_64) ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src}) SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1) SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1) - TARGET_LINK_LIBRARIES(todbc taos odbcinst) + TARGET_LINK_LIBRARIES(todbc todbc_base taos odbcinst) target_include_directories(todbc PUBLIC .) install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})") ENDIF () +IF (TD_DARWIN) + FLEX_TARGET(todbcFlexScanner + todbc_scanner.l + ${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c + ) + set(todbc_flex_scanner_src + ${FLEX_todbcFlexScanner_OUTPUTS} + ) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c PROPERTIES COMPILE_OPTIONS "-Wno-conversion") + AUX_SOURCE_DIRECTORY(. SRC) + + # generate dynamic library (*.dylib) + ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src}) + SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1) + SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1) + TARGET_LINK_LIBRARIES(todbc todbc_base taos odbcinst) + target_include_directories(todbc PUBLIC .) + target_include_directories(todbc PRIVATE /usr/local/include) + target_link_directories(todbc PUBLIC /usr/local/lib) + + install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})") +ENDIF () + IF (TD_WINDOWS_64) FLEX_TARGET(todbcFlexScanner todbc_scanner.l @@ -37,7 +62,7 @@ IF (TD_WINDOWS_64) ${todbc_flex_scanner_src} ${CMAKE_CURRENT_BINARY_DIR}/todbc.rc todbc.def) - TARGET_LINK_LIBRARIES(todbc taos_static odbccp32 legacy_stdio_definitions) + TARGET_LINK_LIBRARIES(todbc todbc_base taos_static odbccp32 legacy_stdio_definitions) target_include_directories(todbc PUBLIC .) target_compile_definitions(todbc PRIVATE "todbc_EXPORT") @@ -52,3 +77,4 @@ IF (TD_WINDOWS_64) INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.exp DESTINATION driver) INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.dll DESTINATION driver) ENDIF () + diff --git a/src/connector/odbc/src/base.c b/src/connector/odbc/src/base.c new file mode 100644 index 0000000000..54b55b48ed --- /dev/null +++ b/src/connector/odbc/src/base.c @@ -0,0 +1,2713 @@ +#include "base.h" + +#include "base/env.h" +#include "base/null_conn.h" +#include "base/tsdb_impl.h" + +#include "todbc_flex.h" +#include "todbc_tls.h" +#include "todbc_util.h" + +#ifdef _MSC_VER +#include +#endif // _MSC_VER + +#define PROFILING 0 +#define LOGGING 0 + +#define PROFILE(r_0911, statement) \ +do { \ + if (!PROFILING) { \ + if (LOGGING) D(""); \ + statement; \ + if (LOGGING) D("r=%zx", (size_t)r_0911); \ + break; \ + } \ + if (LOGGING) D(""); \ + struct timeval tv0, tv1; \ + gettimeofday(&tv0, NULL); \ + statement; \ + gettimeofday(&tv1, NULL); \ + double delta = difftime(tv1.tv_sec, tv0.tv_sec); \ + delta *= 1000000; \ + delta += (double)(tv1.tv_usec-tv0.tv_usec); \ + delta /= 1000000; \ + D("%s: elapsed: [%.6f]s", #statement, delta); \ + if (LOGGING) D("r=%zx", (size_t)r_0911); \ +} while (0) + +#define P(fmt,...) do { \ + if (LOGGING) { \ + D(fmt, ##__VA_ARGS__); \ + } \ +} while (0) + + + +static SQLRETURN doSQLAllocConnect(SQLHENV EnvironmentHandle, SQLHDBC *ConnectionHandle); + +SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, SQLHDBC *ConnectionHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + PROFILE(r, r = doSQLAllocConnect(EnvironmentHandle, ConnectionHandle)); + todbc_tls_buf_reclaim(); + return r; +} + + +static SQLRETURN doSQLAllocEnv(SQLHENV *EnvironmentHandle); + +SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) +{ + SQLRETURN r; + PROFILE(r, r = doSQLAllocEnv(EnvironmentHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle); + +SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle) +{ + SQLRETURN r; + // HandleType is NOT the type of InputHandle + PROFILE(r, r = doSQLAllocHandle(HandleType, InputHandle, OutputHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLAllocStmt(SQLHDBC ConnectionHandle, SQLHSTMT *StatementHandle); + +SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, SQLHSTMT *StatementHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLAllocStmt(ConnectionHandle, StatementHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLBindCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, + SQLLEN BufferLength, SQLLEN *StrLen_or_IndPtr); + +SQLRETURN SQL_API SQLBindCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, + SQLLEN BufferLength, SQLLEN *StrLen_or_IndPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLBindCol(StatementHandle, ColumnNumber, TargetType, + TargetValue, BufferLength, StrLen_or_IndPtr)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLBindParam(SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, SQLULEN LengthPrecision, + SQLSMALLINT ParameterScale, SQLPOINTER ParameterValue, + SQLLEN *StrLen_or_IndPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLCancel(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLCancelHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle) +{ + SQLRETURN r; + errs_clear(HandleType, InputHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLCloseCursor(SQLHSTMT StatementHandle); + +SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLCloseCursor(StatementHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLColAttribute (SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, + SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength, SQLLEN *NumericAttribute) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLColumns(SQLHSTMT StatementHandle, + SQLCHAR *CatalogName, SQLSMALLINT NameLength1, + SQLCHAR *SchemaName, SQLSMALLINT NameLength2, + SQLCHAR *TableName, SQLSMALLINT NameLength3, + SQLCHAR *ColumnName, SQLSMALLINT NameLength4) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLCompleteAsync(SQLSMALLINT HandleType, SQLHANDLE Handle, RETCODE* AsyncRetCodePtr) +{ + SQLRETURN r; + errs_clear(HandleType, Handle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle, + SQLCHAR *ServerName, SQLSMALLINT NameLength1, + SQLCHAR *UserName, SQLSMALLINT NameLength2, + SQLCHAR *Authentication, SQLSMALLINT NameLength3); + +SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, + SQLCHAR *ServerName, SQLSMALLINT NameLength1, + SQLCHAR *UserName, SQLSMALLINT NameLength2, + SQLCHAR *Authentication, SQLSMALLINT NameLength3) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLConnect(ConnectionHandle, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLCopyDesc(SQLHDESC SourceDescHandle, SQLHDESC TargetDescHandle) +{ + SQLRETURN r; + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLDataSources(SQLHENV EnvironmentHandle, + SQLUSMALLINT Direction, SQLCHAR *ServerName, SQLSMALLINT BufferLength1, SQLSMALLINT *NameLength1Ptr, + SQLCHAR *Description, SQLSMALLINT BufferLength2, + SQLSMALLINT *NameLength2Ptr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLDescribeCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, SQLSMALLINT BufferLength, + SQLSMALLINT *NameLength, + SQLSMALLINT *DataType, SQLULEN *ColumnSize, + SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable); + +SQLRETURN SQL_API SQLDescribeCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, SQLSMALLINT BufferLength, + SQLSMALLINT *NameLength, + SQLSMALLINT *DataType, SQLULEN *ColumnSize, + SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLDescribeCol(StatementHandle, ColumnNumber, ColumnName, BufferLength, + NameLength, DataType, ColumnSize, DecimalDigits, Nullable)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLDisconnect(SQLHDBC ConnectionHandle); + +SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLDisconnect(ConnectionHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT CompletionType) +{ + SQLRETURN r; + errs_clear(HandleType, Handle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLError(SQLHENV EnvironmentHandle, + SQLHDBC ConnectionHandle, SQLHSTMT StatementHandle, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength); + +SQLRETURN SQL_API not_support_SQLError(SQLHENV EnvironmentHandle, + SQLHDBC ConnectionHandle, SQLHSTMT StatementHandle, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength) +{ + SQLRETURN r; + PROFILE(r, r = doSQLError(EnvironmentHandle, ConnectionHandle, StatementHandle, + Sqlstate, NativeError, MessageText, BufferLength, TextLength)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength); + +SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLExecDirect(StatementHandle, StatementText, TextLength)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLExecute(SQLHSTMT StatementHandle); + +SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLExecute(StatementHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLFetch(SQLHSTMT StatementHandle); + +SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLFetch(StatementHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLFetchScroll(SQLHSTMT StatementHandle, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLFreeConnect(SQLHDBC ConnectionHandle); + +SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLFreeConnect(ConnectionHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLFreeEnv(SQLHENV EnvironmentHandle); + +SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + PROFILE(r, r = doSQLFreeEnv(EnvironmentHandle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle); + +SQLRETURN SQL_API SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) +{ + SQLRETURN r; + errs_clear(HandleType, Handle); + PROFILE(r, r = doSQLFreeHandle(HandleType, Handle)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLFreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option); + +SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLFreeStmt(StatementHandle, Option)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetConnectAttr(SQLHDBC ConnectionHandle, + SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLengthPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetConnectOption(SQLHDBC ConnectionHandle, SQLUSMALLINT Option, SQLPOINTER Value) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetCursorName(SQLHSTMT StatementHandle, SQLCHAR *CursorName, SQLSMALLINT BufferLength, SQLSMALLINT *NameLengthPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, SQLLEN BufferLength, + SQLLEN *StrLen_or_IndPtr); + +SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, SQLLEN BufferLength, + SQLLEN *StrLen_or_IndPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLGetData(StatementHandle, ColumnNumber, TargetType, TargetValue, BufferLength, StrLen_or_IndPtr)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetDescField(SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, + SQLPOINTER Value, SQLINTEGER BufferLength, + SQLINTEGER *StringLength) +{ + SQLRETURN r; + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetDescRec(SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, SQLCHAR *Name, + SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr, + SQLSMALLINT *TypePtr, SQLSMALLINT *SubTypePtr, + SQLLEN *LengthPtr, SQLSMALLINT *PrecisionPtr, + SQLSMALLINT *ScalePtr, SQLSMALLINT *NullablePtr) +{ + SQLRETURN r; + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, + SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength); + +SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, + SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength) +{ + SQLRETURN r; + PROFILE(r, r = doSQLGetDiagField(HandleType, Handle, RecNumber, DiagIdentifier, + DiagInfo, BufferLength, StringLength)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR* MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength); + +SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR* MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) +{ + SQLRETURN r; + PROFILE(r, r = doSQLGetDiagRec(HandleType, Handle, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength); + +SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + PROFILE(r, r = doSQLGetEnvAttr(EnvironmentHandle, Attribute, Value, BufferLength, StringLength)); + todbc_tls_buf_reclaim(); + return r; +} + +// SQLRETURN SQL_API SQLGetFunctions(SQLHDBC ConnectionHandle, SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported) +// { +// SQLRETURN r; +// errs_clear(SQL_HANDLE_DBC, ConnectionHandle); +// PROFILE(r, r = SQL_ERROR); +// todbc_tls_buf_reclaim(); +// return r; +// } + +static SQLRETURN doSQLGetInfo(SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValue, + SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr); + +SQLRETURN SQL_API SQLGetInfo(SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValue, + SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLGetInfo(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLengthPtr)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength); + +SQLRETURN SQL_API SQLGetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLGetStmtAttr(StatementHandle, Attribute, Value, BufferLength, StringLength)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLGetStmtOption(SQLHSTMT StatementHandle, + SQLUSMALLINT Option, SQLPOINTER Value) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType); + +SQLRETURN SQL_API SQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLGetTypeInfo(StatementHandle, DataType)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLNumResultCols(SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount); + +SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLNumResultCols(StatementHandle, ColumnCount)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLParamData(SQLHSTMT StatementHandle, SQLPOINTER *Value) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength); + +SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLPrepare(StatementHandle, StatementText, TextLength)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLPutData(SQLHSTMT StatementHandle, SQLPOINTER Data, SQLLEN StrLen_or_Ind) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLRowCount(SQLHSTMT StatementHandle, SQLLEN* RowCount); + +SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle, SQLLEN* RowCount) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLRowCount(StatementHandle, RowCount)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetConnectOption(SQLHDBC ConnectionHandle, SQLUSMALLINT Option, SQLULEN Value) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetCursorName(SQLHSTMT StatementHandle, SQLCHAR* CursorName, SQLSMALLINT NameLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, + SQLPOINTER Value, SQLINTEGER BufferLength) +{ + SQLRETURN r; + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT Type, + SQLSMALLINT SubType, SQLLEN Length, SQLSMALLINT Precision, SQLSMALLINT Scale, + SQLPOINTER Data, SQLLEN *StringLength, SQLLEN *Indicator) +{ + SQLRETURN r; + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLSetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength); + +SQLRETURN SQL_API SQLSetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + PROFILE(r, r = doSQLSetEnvAttr(EnvironmentHandle, Attribute, Value, StringLength)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetParam(SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, SQLULEN LengthPrecision, SQLSMALLINT ParameterScale, SQLPOINTER ParameterValue, + SQLLEN *StrLen_or_IndPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLSetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength); + +SQLRETURN SQL_API SQLSetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLSetStmtAttr(StatementHandle, Attribute, Value, StringLength)); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSetStmtOption(SQLHSTMT StatementHandle, SQLUSMALLINT Option, SQLULEN Value) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLSpecialColumns(SQLHSTMT StatementHandle, SQLUSMALLINT IdentifierType, + SQLCHAR *CatalogName, SQLSMALLINT NameLength1, + SQLCHAR *SchemaName, SQLSMALLINT NameLength2, + SQLCHAR *TableName, SQLSMALLINT NameLength3, + SQLUSMALLINT Scope, SQLUSMALLINT Nullable) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLStatistics(SQLHSTMT StatementHandle, + SQLCHAR *CatalogName, SQLSMALLINT NameLength1, + SQLCHAR *SchemaName, SQLSMALLINT NameLength2, + SQLCHAR *TableName, SQLSMALLINT NameLength3, + SQLUSMALLINT Unique, SQLUSMALLINT Reserved) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLTables(SQLHSTMT StatementHandle, + SQLCHAR *CatalogName, SQLSMALLINT NameLength1, + SQLCHAR *SchemaName, SQLSMALLINT NameLength2, + SQLCHAR *TableName, SQLSMALLINT NameLength3, + SQLCHAR *TableType, SQLSMALLINT NameLength4) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + +SQLRETURN SQL_API SQLTransact(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, SQLUSMALLINT CompletionType) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_ENV, EnvironmentHandle); + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = SQL_ERROR); + todbc_tls_buf_reclaim(); + return r; +} + + + + +static SQLRETURN doSQLDriverConnect( + SQLHDBC ConnectionHandle, + SQLHWND WindowHandle, + SQLCHAR *InConnectionString, + SQLSMALLINT StringLength1, + SQLCHAR *OutConnectionString, + SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength2Ptr, + SQLUSMALLINT DriverCompletion); + +SQLRETURN SQL_API SQLDriverConnect( + SQLHDBC ConnectionHandle, + SQLHWND WindowHandle, + SQLCHAR *InConnectionString, + SQLSMALLINT StringLength1, + SQLCHAR *OutConnectionString, + SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength2Ptr, + SQLUSMALLINT DriverCompletion) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_DBC, ConnectionHandle); + PROFILE(r, r = doSQLDriverConnect(ConnectionHandle, WindowHandle, InConnectionString, StringLength1, + OutConnectionString, BufferLength, StringLength2Ptr, DriverCompletion)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLBindParameter( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT InputOutputType, + SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, + SQLULEN ColumnSize, + SQLSMALLINT DecimalDigits, + SQLPOINTER ParameterValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr); + +SQLRETURN SQL_API SQLBindParameter( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT InputOutputType, + SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, + SQLULEN ColumnSize, + SQLSMALLINT DecimalDigits, + SQLPOINTER ParameterValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr) +{ + SQLRETURN r; + P("ParameterNumber:[%d]; InputOutputType:[%d]%s; ValueType:[%d]%s; ParameterType:[%d]%s; " + "ColumnSize:[%ld]; DecimalDigits:[%d]; ParameterValuePtr:[%p]; BufferLength:[%ld]; StrLen_or_IndPtr:[%p]", + ParameterNumber, InputOutputType, sql_input_output_type(InputOutputType), + ValueType, sql_c_type(ValueType), + ParameterType, sql_sql_type(ParameterType), + ColumnSize, DecimalDigits, ParameterValuePtr, BufferLength, StrLen_or_IndPtr); + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLBindParameter(StatementHandle, ParameterNumber, InputOutputType, ValueType, ParameterType, + ColumnSize, DecimalDigits, ParameterValuePtr, BufferLength, StrLen_or_IndPtr)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLNumParams(SQLHSTMT StatementHandle, SQLSMALLINT *ParameterCountPtr); + +SQLRETURN SQL_API SQLNumParams(SQLHSTMT StatementHandle, SQLSMALLINT *ParameterCountPtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLNumParams(StatementHandle, ParameterCountPtr)); + todbc_tls_buf_reclaim(); + return r; +} + +static SQLRETURN doSQLDescribeParam( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT * DataTypePtr, + SQLULEN * ParameterSizePtr, + SQLSMALLINT * DecimalDigitsPtr, + SQLSMALLINT * NullablePtr); + +SQLRETURN SQL_API SQLDescribeParam( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT * DataTypePtr, + SQLULEN * ParameterSizePtr, + SQLSMALLINT * DecimalDigitsPtr, + SQLSMALLINT * NullablePtr) +{ + SQLRETURN r; + errs_clear(SQL_HANDLE_STMT, StatementHandle); + PROFILE(r, r = doSQLDescribeParam(StatementHandle, ParameterNumber, DataTypePtr, + ParameterSizePtr, DecimalDigitsPtr, NullablePtr)); + todbc_tls_buf_reclaim(); + return r; +} + + + + + +SQLRETURN SQL_API SQLBrowseConnect( + SQLHDBC hdbc, + SQLCHAR *szConnStrIn, + SQLSMALLINT cchConnStrIn, + SQLCHAR *szConnStrOut, + SQLSMALLINT cchConnStrOutMax, + SQLSMALLINT *pcchConnStrOut); + +SQLRETURN SQL_API SQLBulkOperations( + SQLHSTMT StatementHandle, + SQLSMALLINT Operation); + +SQLRETURN SQL_API SQLColAttributes( + SQLHSTMT hstmt, + SQLUSMALLINT icol, + SQLUSMALLINT fDescType, + SQLPOINTER rgbDesc, + SQLSMALLINT cbDescMax, + SQLSMALLINT *pcbDesc, + SQLLEN * pfDesc); + +SQLRETURN SQL_API SQLColumnPrivileges( + SQLHSTMT hstmt, + SQLCHAR *szCatalogName, + SQLSMALLINT cchCatalogName, + SQLCHAR *szSchemaName, + SQLSMALLINT cchSchemaName, + SQLCHAR *szTableName, + SQLSMALLINT cchTableName, + SQLCHAR *szColumnName, + SQLSMALLINT cchColumnName); + +SQLRETURN SQL_API SQLExtendedFetch( + SQLHSTMT hstmt, + SQLUSMALLINT fFetchType, + SQLLEN irow, + SQLULEN *pcrow, + SQLUSMALLINT *rgfRowStatus); + +SQLRETURN SQL_API SQLForeignKeys( + SQLHSTMT hstmt, + SQLCHAR *szPkCatalogName, + SQLSMALLINT cchPkCatalogName, + SQLCHAR *szPkSchemaName, + SQLSMALLINT cchPkSchemaName, + SQLCHAR *szPkTableName, + SQLSMALLINT cchPkTableName, + SQLCHAR *szFkCatalogName, + SQLSMALLINT cchFkCatalogName, + SQLCHAR *szFkSchemaName, + SQLSMALLINT cchFkSchemaName, + SQLCHAR *szFkTableName, + SQLSMALLINT cchFkTableName); + +SQLRETURN SQL_API SQLMoreResults( + SQLHSTMT hstmt); + +SQLRETURN SQL_API SQLNativeSql +( + SQLHDBC hdbc, + SQLCHAR* szSqlStrIn, + SQLINTEGER cchSqlStrIn, + SQLCHAR* szSqlStr, + SQLINTEGER cchSqlStrMax, + SQLINTEGER *pcbSqlStr +); + +SQLRETURN SQL_API SQLParamOptions( + SQLHSTMT hstmt, + SQLULEN crow, + SQLULEN *pirow); + +SQLRETURN SQL_API SQLPrimaryKeys( + SQLHSTMT hstmt, + SQLCHAR *szCatalogName, + SQLSMALLINT cchCatalogName, + SQLCHAR *szSchemaName, + SQLSMALLINT cchSchemaName, + SQLCHAR *szTableName, + SQLSMALLINT cchTableName); + +SQLRETURN SQL_API SQLProcedureColumns( + SQLHSTMT hstmt, + SQLCHAR *szCatalogName, + SQLSMALLINT cchCatalogName, + SQLCHAR *szSchemaName, + SQLSMALLINT cchSchemaName, + SQLCHAR *szProcName, + SQLSMALLINT cchProcName, + SQLCHAR *szColumnName, + SQLSMALLINT cchColumnName); + +SQLRETURN SQL_API SQLProcedures( + SQLHSTMT hstmt, + SQLCHAR *szCatalogName, + SQLSMALLINT cchCatalogName, + SQLCHAR *szSchemaName, + SQLSMALLINT cchSchemaName, + SQLCHAR *szProcName, + SQLSMALLINT cchProcName); + + + +SQLRETURN SQL_API SQLSetPos( + SQLHSTMT hstmt, + SQLSETPOSIROW irow, + SQLUSMALLINT fOption, + SQLUSMALLINT fLock); + +SQLRETURN SQL_API SQLTablePrivileges( + SQLHSTMT hstmt, + SQLCHAR *szCatalogName, + SQLSMALLINT cchCatalogName, + SQLCHAR *szSchemaName, + SQLSMALLINT cchSchemaName, + SQLCHAR *szTableName, + SQLSMALLINT cchTableName); + +SQLRETURN SQL_API SQLDrivers( + SQLHENV henv, + SQLUSMALLINT fDirection, + SQLCHAR *szDriverDesc, + SQLSMALLINT cchDriverDescMax, + SQLSMALLINT *pcchDriverDesc, + SQLCHAR *szDriverAttributes, + SQLSMALLINT cchDrvrAttrMax, + SQLSMALLINT *pcchDrvrAttr); + +SQLRETURN SQL_API SQLAllocHandleStd( + SQLSMALLINT fHandleType, + SQLHANDLE hInput, + SQLHANDLE *phOutput); +SQLRETURN SQL_API SQLSetScrollOptions( + SQLHSTMT hstmt, + SQLUSMALLINT fConcurrency, + SQLLEN crowKeyset, + SQLUSMALLINT crowRowset); + + + + +static SQLRETURN doSQLAllocEnv(SQLHENV *EnvironmentHandle) +{ + env_t *env = (env_t*)calloc(1, sizeof(*env)); + OILE(env, ""); + + int r = env_init(env); + if (r) return SQL_ERROR; + + *EnvironmentHandle = env; + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle) +{ + P("HandleType:[%d]%s", HandleType, sql_handle_type(HandleType)); + switch (HandleType) + { + case SQL_HANDLE_ENV: + { + return doSQLAllocEnv(OutputHandle); + } break; + case SQL_HANDLE_DBC: + { + errs_clear(SQL_HANDLE_ENV, InputHandle); + return doSQLAllocConnect(InputHandle, OutputHandle); + } break; + case SQL_HANDLE_STMT: + { + errs_clear(SQL_HANDLE_DBC, InputHandle); + return doSQLAllocStmt(InputHandle, OutputHandle); + } break; + default: + { + ONIY(0, ""); + } break; + } +} + +static SQLRETURN doSQLSetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) +{ + P("Attribute:[%d]%s", Attribute, sql_env_attr_type(Attribute)); + env_t *env = (env_t*)EnvironmentHandle; + OILE(env, ""); + + switch (Attribute) + { + case SQL_ATTR_ODBC_VERSION: + { + int32_t ver = (int32_t)(size_t)Value; + P("client odbc ver:[%d]", ver); + if (ver < env->odbc_ver) { + // fall back to lower version + env->odbc_ver = ver; + } + return SQL_SUCCESS; + } break; + default: + { + ONIY(0, ""); + } break; + } +} + +static SQLRETURN doSQLGetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength) +{ + P("Attribute:[%d]%s; Value:[%p]; BufferLength:[%d]; StringLength:[%p][%d]", + Attribute, sql_env_attr_type(Attribute), Value, BufferLength, + StringLength, StringLength ? *StringLength : 0); + env_t *env = (env_t*)EnvironmentHandle; + OILE(env, ""); + + switch (Attribute) + { + case SQL_ATTR_ODBC_VERSION: + { + *(int32_t*)Value = env->odbc_ver; + P("odbc ver:[%d]", env->odbc_ver); + return SQL_SUCCESS; + } break; + default: + { + ONIY(0, ""); + } break; + } +} + +static SQLRETURN doSQLAllocConnect(SQLHENV EnvironmentHandle, SQLHDBC *ConnectionHandle) +{ + env_t *env = (env_t*)EnvironmentHandle; + OILE(env, ""); + errs_t *errs = env_get_errs(env); + + conn_t *conn = conn_new(env); + if (!conn) { + SET_OOM(errs, "alloc conn failed"); + return SQL_ERROR; + } + + do { + *ConnectionHandle = conn; + + return SQL_SUCCESS; + } while (0); + + conn_free(conn); + + return SQL_ERROR; +} + +static SQLRETURN doSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) +{ + switch (HandleType) + { + case SQL_HANDLE_ENV: + { + return doSQLFreeEnv(Handle); + } break; + case SQL_HANDLE_DBC: + { + return doSQLFreeConnect(Handle); + } break; + case SQL_HANDLE_STMT: + { + stmt_t *stmt = (stmt_t*)Handle; + stmt_free(stmt); + return SQL_SUCCESS; + } break; + default: + { + ONIY(0, "HandleType:[%d]%s", HandleType, sql_handle_type(HandleType)); + } break; + } +} + +static SQLRETURN do_connect(conn_t *conn) { + errs_t *errs = &conn->errs; + + OD("enc:src/char/wchar/db/locale:[%s/%s/%s/%s/%s]", + conn->enc_src, conn->enc_char, conn->enc_wchar, conn->enc_db, conn->enc_locale); + + SQLRETURN r; + + r = conn_check_charset(conn, errs); + if (r!=SQL_SUCCESS) return r; + + if (0) { + // test with null_conn + if (conn_init_null_conn(conn)) { + SET_GENERAL(errs, "failed to init null conn for test"); + return SQL_ERROR; + } + } else { + if (conn_init_tsdb_conn(conn)) { + SET_GENERAL(errs, "failed to init taos conn for test"); + return SQL_ERROR; + } + } + + return conn_connect(conn); +} + +static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle, + SQLCHAR *ServerName, SQLSMALLINT NameLength1, + SQLCHAR *UserName, SQLSMALLINT NameLength2, + SQLCHAR *Authentication, SQLSMALLINT NameLength3) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + OILE(conn, ""); + ONIY(ServerName, ""); + + errs_t *errs = &conn->errs; + + const char *enc_to = conn->enc_locale; + const char *enc_from = conn->enc_char; + + SQLRETURN ok = SQL_ERROR; + + conn_val_t *val = &conn->val; + conn_val_reset(val); + + do { + if (ServerName) { + size_t slen = (size_t)NameLength1; + todbc_string_t dsn = todbc_tls_conv(NULL, enc_to, enc_from, (const unsigned char*)ServerName, &slen); + if (!dsn.buf) { + SET_OOM(errs, "alloc buf failed"); + return SQL_ERROR; + } + val->dsn = strdup((const char*)dsn.buf); + if (!val->dsn) { + SET_OOM(errs, "strdup failed"); + return SQL_ERROR; + } + } + if (UserName) { + size_t slen = (size_t)NameLength2; + todbc_string_t uid = todbc_tls_conv(NULL, enc_to, enc_from, (const unsigned char*)UserName, &slen); + if (!uid.buf) { + SET_OOM(errs, "alloc buf failed"); + return SQL_ERROR; + } + val->uid = strdup((const char*)uid.buf); + if (!val->uid) { + SET_OOM(errs, "strdup failed"); + return SQL_ERROR; + } + } + if (Authentication) { + size_t slen = (size_t)NameLength3; + todbc_string_t pwd = todbc_tls_conv(NULL, enc_to, enc_from, (const unsigned char*)Authentication, &slen); + if (!pwd.buf) { + SET_OOM(errs, "alloc buf failed"); + return SQL_ERROR; + } + val->pwd = strdup((const char*)pwd.buf); + if (!val->pwd) { + SET_OOM(errs, "strdup failed"); + return SQL_ERROR; + } + } + + OD("................."); + ok = do_connect(conn); + OD("................."); + if (ok!=SQL_SUCCESS) break; + + CONN_SET_CONNECTED(conn); + return SQL_SUCCESS; + } while (0); + + conn_val_reset(val); + + return ok; +} + +static SQLRETURN doSQLDriverConnect( + SQLHDBC ConnectionHandle, + SQLHWND WindowHandle, + SQLCHAR *InConnectionString, + SQLSMALLINT StringLength1, + SQLCHAR *OutConnectionString, + SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength2Ptr, + SQLUSMALLINT DriverCompletion) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + OILE(conn, ""); + ONIY(InConnectionString, ""); + + errs_t *errs = &conn->errs; + +#ifndef _MSC_VER + if (DriverCompletion!=SQL_DRIVER_NOPROMPT) { + SET_NIY(errs, "option[%d] other than SQL_DRIVER_NOPROMPT not supported yet", DriverCompletion); + return SQL_ERROR; + } +#endif + + const char *enc_to = conn->enc_locale; + const char *enc_from = conn->enc_char; + + size_t slen = (size_t)StringLength1; + todbc_string_t ts = todbc_tls_conv(NULL, enc_to, enc_from, (const unsigned char*)InConnectionString, &slen); + const char *connStr = (const char*)ts.buf; + if (!connStr) { + SET_OOM(errs, "alloc buf failed"); + return SQL_ERROR; + } + + SQLRETURN ok = SQL_ERROR; + + conn_val_t *val = &conn->val; + conn_val_reset(val); + + do { + // TO_DO: genralize + int n = todbc_parse_conn_string(connStr, val); + if (n) { + SET_GENERAL(errs, "unrecognized connection string:[%s]", connStr); + break; + } + + todbc_enc_t enc; + if (val->enc_char) { + enc = todbc_tls_iconv_enc(val->enc_char); + if (enc.enc[0]=='\0') { + SET_GENERAL(errs, "unrecognized charset:[%s]", val->enc_char); + break; + } + snprintf(conn->enc_char, sizeof(conn->enc_char), "%s", val->enc_char); + } + if (val->enc_wchar) { + enc = todbc_tls_iconv_enc(val->enc_wchar); + if (enc.enc[0]=='\0') { + SET_GENERAL(errs, "unrecognized charset:[%s]", val->enc_wchar); + break; + } + snprintf(conn->enc_wchar, sizeof(conn->enc_wchar), "%s", val->enc_wchar); + } + if (val->enc_db) { + enc = todbc_tls_iconv_enc(val->enc_db); + if (enc.enc[0]=='\0') { + SET_GENERAL(errs, "unrecognized charset:[%s]", val->enc_db); + break; + } + snprintf(conn->enc_db, sizeof(conn->enc_db), "%s", val->enc_db); + } + if (val->enc_local) { + enc = todbc_tls_iconv_enc(val->enc_local); + if (enc.enc[0]=='\0') { + SET_GENERAL(errs, "unrecognized charset:[%s]", val->enc_local); + break; + } + snprintf(conn->enc_locale, sizeof(conn->enc_locale), "%s", val->enc_local); + } + + ok = do_connect(conn); + if (ok!=SQL_SUCCESS) break; + ok = SQL_ERROR; + + n = 0; + if (OutConnectionString) { + n = snprintf((char*)OutConnectionString, (size_t)BufferLength, "%s", connStr); + } + if (StringLength2Ptr) { + *StringLength2Ptr = (SQLSMALLINT)n; + } + + CONN_SET_CONNECTED(conn); + return SQL_SUCCESS; + } while (0); + + conn_val_reset(val); + + return ok; +} + +static SQLRETURN doSQLGetInfo(SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValue, + SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr) +{ + P("InfoType:[%d]%s; BufferLength:[%d]; StringLengthPtr:[%p]%d", + InfoType, sql_info_type(InfoType), BufferLength, + StringLengthPtr, StringLengthPtr ? *StringLengthPtr : 0); + + switch (InfoType) + { + case SQL_DRIVER_ODBC_VER: + { + // how to sync with env->odbc_ver ? + const char *v = "03.00"; + int n = snprintf((char*)InfoValue, (size_t)BufferLength, "%s", v); + OILE(n>0, ""); + *StringLengthPtr = (SQLSMALLINT)n; + } break; + case SQL_DESCRIBE_PARAMETER: + { + const char *v = "Y"; + int n = snprintf((char*)InfoValue, (size_t)BufferLength, "%s", v); + OILE(n>0, ""); + *StringLengthPtr = (SQLSMALLINT)n; + } break; + case SQL_NEED_LONG_DATA_LEN: + { + const char *v = "Y"; + int n = snprintf((char*)InfoValue, (size_t)BufferLength, "%s", v); + OILE(n>0, ""); + *StringLengthPtr = (SQLSMALLINT)n; + } break; + case SQL_MAX_COLUMN_NAME_LEN: + { + SQLUSMALLINT v = 64; + OILE(BufferLength==sizeof(v), ""); + *(SQLUSMALLINT*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_TXN_ISOLATION_OPTION: + { + SQLUINTEGER v = SQL_TXN_READ_UNCOMMITTED; + OILE(BufferLength==sizeof(v), ""); + *(SQLUINTEGER*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_CURSOR_COMMIT_BEHAVIOR: + { + SQLUSMALLINT v = SQL_CB_PRESERVE; + OILE(BufferLength==sizeof(v), ""); + *(SQLUSMALLINT*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_CURSOR_ROLLBACK_BEHAVIOR: + { + SQLUSMALLINT v = SQL_CB_PRESERVE; + OILE(BufferLength==sizeof(v), ""); + *(SQLUSMALLINT*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_GETDATA_EXTENSIONS: + { + SQLUINTEGER v = SQL_GD_ANY_COLUMN; + OILE(BufferLength==sizeof(v), ""); + *(SQLUINTEGER*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_DTC_TRANSITION_COST: + { + SQLUINTEGER v = SQL_DTC_ENLIST_EXPENSIVE | SQL_DTC_UNENLIST_EXPENSIVE; + OILE(BufferLength==sizeof(v), ""); + *(SQLUINTEGER*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + case SQL_MAX_CONCURRENT_ACTIVITIES: + { + SQLUSMALLINT v = 10240; + OILE(BufferLength==sizeof(v), ""); + *(SQLUSMALLINT*)InfoValue = v; + if (StringLengthPtr) *StringLengthPtr = sizeof(v); + } break; + default: + { + ONIY(0, ""); + // return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_fill_error(errs_t *errs, const char *enc_to, const char *enc_from, + SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR* MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) +{ + if (errs_count(errs)<=0) return SQL_NO_DATA; + + const char *sql_state = NULL; + const char *err_str = NULL; + int r = errs_fetch(errs, RecNumber-1, &sql_state, &err_str); + if (r) return SQL_NO_DATA; + OILE(sql_state && err_str, ""); + const unsigned char *src = (const unsigned char*)err_str; + size_t slen = strlen(err_str); + unsigned char *dst = (unsigned char*)MessageText; + size_t dlen = (size_t)BufferLength; + // OILE(dst, ""); + if (!MessageText) { + OILE(TextLength, ""); + *TextLength = 4096; + return SQL_SUCCESS; + } + todbc_string_t s = todbc_tls_write(enc_to, enc_from, src, &slen, dst, dlen); + *NativeError = 0; + *TextLength = (SQLSMALLINT)s.bytes; + snprintf((char*)Sqlstate, 6, "%s", sql_state); + return SQL_SUCCESS; +} + +static SQLRETURN doSQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR* MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) +{ + OILE(RecNumber>0, ""); + OILE(Sqlstate, ""); + // OILE(NativeError, ""); + OILE(TextLength, ""); + switch (HandleType) + { + // case SQL_HANDLE_ENV: + // { + // env_t *env = (env_t*)Handle; + // FILL_ERROR(env); + // return SQL_SUCCESS; + // } break; + case SQL_HANDLE_DBC: + { + conn_t *conn = (conn_t*)Handle; + OILE(conn, ""); + errs_t *errs = conn_get_errs(conn); + OILE(errs, ""); + const char *enc_to = conn->enc_char; + const char *enc_from = conn->enc_src; + return do_fill_error(errs, enc_to, enc_from, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); + } break; + case SQL_HANDLE_STMT: + { + stmt_t *stmt = (stmt_t*)Handle; + OILE(stmt, ""); + if (!stmt->owner) return SQL_NO_DATA; + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + errs_t *errs = stmt_get_errs(stmt); + OILE(errs, ""); + const char *enc_to = conn->enc_char; + const char *enc_from = conn->enc_src; + return do_fill_error(errs, enc_to, enc_from, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); + } break; + default: + { + ONIY(0, "HandleType:[%d]%s", HandleType, sql_handle_type(HandleType)); + // return SQL_ERROR; + } break; + } +} + +static SQLRETURN doSQLAllocStmt(SQLHDBC ConnectionHandle, SQLHSTMT *StatementHandle) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + OILE(conn, ""); + + errs_t *errs = &conn->errs; + + stmt_t *stmt = stmt_new(conn); + if (!stmt) { + SET_OOM(errs, "alloc stmt failed"); + return SQL_ERROR; + } + + do { + if (!StatementHandle) break; + + *StatementHandle = stmt; + return SQL_SUCCESS; + } while (0); + + stmt_free(stmt); + OILE(0, ""); +} + +static SQLRETURN doSQLFreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option) +{ + P("Option:[%d]%s", Option, sql_freestmt_option_type(Option)); + + switch (Option) + { + case SQL_CLOSE: + { + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + if (STMT_IS_NORM(stmt)) break; + return doSQLCloseCursor(StatementHandle); + } break; + // case SQL_UNBIND: + // { + // } break; + case SQL_RESET_PARAMS: + { + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + stmt_reset_params(stmt); + } break; + default: + { + ONIY(0, ""); + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLGetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength) +{ + P("Attribute:[%d]%s; BufferLength:[%d]; StringLength:[%p][%d]", + Attribute, sql_stmt_attr_type(Attribute), BufferLength, + StringLength, StringLength ? *StringLength : 0); + stmt_t *stmt = (stmt_t*)StatementHandle; + descs_t *descs = &stmt->descs; + + switch (Attribute) + { + case SQL_ATTR_APP_ROW_DESC: + { + OILE(BufferLength==sizeof(descs->app_row) || BufferLength==SQL_IS_POINTER, ""); + *(void**)Value = descs->app_row; + } break; + case SQL_ATTR_APP_PARAM_DESC: + { + OILE(BufferLength==sizeof(descs->app_param) || BufferLength==SQL_IS_POINTER, ""); + *(void**)Value = descs->app_param; + } break; + case SQL_ATTR_IMP_ROW_DESC: + { + OILE(BufferLength==sizeof(descs->imp_row) || BufferLength==SQL_IS_POINTER, ""); + *(void**)Value = descs->imp_row; + } break; + case SQL_ATTR_IMP_PARAM_DESC: + { + OILE(BufferLength==sizeof(descs->imp_param) || BufferLength==SQL_IS_POINTER, ""); + *(void**)Value = descs->imp_param; + } break; + default: + { + ONIY(0, ""); + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength) +{ + P("TextLength:[%d]%s", TextLength, sql_soi_type(TextLength)); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + stmt_close_rs(stmt); + OILE(STMT_IS_NORM(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + errs_t *errs = &stmt->errs; + + const char *enc = conn->enc_char; + + OILE(StatementText, ""); + OILE(TextLength>=0 || TextLength==SQL_NTS, ""); + size_t slen = (TextLength>=0) ? (size_t)TextLength : (size_t)-1; + todbc_string_t sql = todbc_string_init(enc, StatementText, slen); + if (!sql.buf) { + SET_OOM(errs, ""); + return SQL_ERROR; + } + + return stmt_exec_direct(stmt, &sql); + + + // stmt_t *stmt = (stmt_t*)StatementHandle; + // rs_t *rs = &stmt->rs; + // rs_close(rs); + // OILE(rs->stmt==NULL); + + // if (1) { + // // taos_stmt_prepare fails to prepare a non-param-stmt-statement + // // thus we fall-back to use taos_query + // OILE(stmt->owner); + // conn_t *conn = stmt->owner->conn; + // OILE(conn); + + // OILE(rs->stmt==NULL); + // paramset_t *paramset = &stmt->paramset; + // paramset_close(paramset); + + // SQLRETURN e = stmt_set_statement(stmt, StatementText, TextLength); + // if (e!=SQL_SUCCESS) return e; + + // taos_rs_t *taos_rs = &rs->taos_rs; + + // const char *buf = (const char*)stmt->statement_db.buf; + // taos_rs->rs = taos_query(conn->taos, buf); + + // if (!taos_rs->rs) { + // int err = terrno; + // SET_ERROR(stmt, "HY000", "failed to execute statement:[%d]%s", err, tstrerror(err)); + // // keep executing/executed state unchanged + // return SQL_ERROR; + // } + + // taos_rs->owner = rs; + // taos_rs->rs_is_opened_by_taos_query = 1; + + // SET_EXECUTED(stmt); + // return stmt_after_exec(stmt); + // } else { + // SQLRETURN r = doSQLPrepare(StatementHandle, StatementText, TextLength); + // if (r!=SQL_SUCCESS) return r; + + // return doSQLExecute(StatementHandle); + // } +} + +static SQLRETURN doSQLRowCount(SQLHSTMT StatementHandle, SQLLEN* RowCount) +{ + OILE(RowCount, ""); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + OILE(stmt->ext.get_affected_rows, ""); + SQLRETURN r = stmt->ext.get_affected_rows(stmt, RowCount); + if (r!=SQL_SUCCESS) return r; + + P("RowCount:[%ld]", *RowCount); + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLNumResultCols(SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount) +{ + OILE(ColumnCount, ""); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + OILE(stmt->ext.get_fields_count, ""); + SQLRETURN r = stmt->ext.get_fields_count(stmt, ColumnCount); + if (r!=SQL_SUCCESS) return r; + + P("ColumnCount:[%d]", *ColumnCount); + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLDescribeCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, SQLSMALLINT BufferLength, + SQLSMALLINT *NameLength, + SQLSMALLINT *DataType, SQLULEN *ColumnSize, + SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) +{ + P("ColumnNumber:[%d]; BufferLength:[%d]", ColumnNumber, BufferLength); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + field_arg_t field_arg = {0}; + field_arg.ColumnNumber = ColumnNumber; + field_arg.ColumnName = ColumnName; + field_arg.BufferLength = BufferLength; + field_arg.NameLength = NameLength; + field_arg.DataType = DataType; + field_arg.ColumnSize = ColumnSize; + field_arg.DecimalDigits = DecimalDigits; + field_arg.Nullable = Nullable; + + OILE(stmt->ext.get_field, ""); + return stmt->ext.get_field(stmt, &field_arg); + + // sql_t *sql = (sql_t*)StatementHandle; + // rs_t *rs = &sql->rs; + // OILE(rs->sql==sql); + // OILE(BufferLength>=0); + // OILE(NameLength); + // OILE(DataType); + // OILE(ColumnSize); + // OILE(DecimalDigits); + // OILE(Nullable); + + // OILE(ColumnNumber>0 && ColumnNumber<=rs->n_fields); + // field_t *field = rs->fields + (ColumnNumber-1); + + // int n = snprintf((char*)ColumnName, (size_t)BufferLength, "%s", field->name); + // *NameLength = (SQLSMALLINT)n; + // *DataType = (SQLSMALLINT)field->data_type; + // *ColumnSize = (SQLUSMALLINT)field->col_size; + // *DecimalDigits = (SQLSMALLINT)field->decimal_digits; + // *Nullable = (SQLSMALLINT)field->nullable; + + + // P("ColumnNumber:[%d]; DataType:[%d]%s; Name:[%s]; ColumnSize:[%ld]; DecimalDigits:[%d]; Nullable:[%d]%s", + // ColumnNumber, *DataType, sql_sql_type(*DataType), field->name, + // *ColumnSize, *DecimalDigits, *Nullable, sql_nullable_type(*Nullable)); + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLDisconnect(SQLHDBC ConnectionHandle) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + OILE(conn, ""); + OILE(CONN_IS_CONNECTED(conn), ""); + + conn_disconnect(conn); + + CONN_SET_NORM(conn); + return SQL_SUCCESS; + + + // OILE(conn->taos); + + // // conn/stmts which ever to close first? + // // as for ODBC, it's suggested to close connection first, then release all dangling statements + // // but we are not sure if doing so will result in memory leakage for taos + // // thus we choose to close dangling statements before shutdown connection + // conn_release_sqls(conn); + + // taos_close(conn->taos); + // conn->taos = 0; + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength) +{ + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + stmt_close_rs(stmt); + OILE(STMT_IS_NORM(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + errs_t *errs = &stmt->errs; + + const char *enc = conn->enc_char; + + OILE(StatementText, ""); + OILE(TextLength>=0 || TextLength==SQL_NTS, ""); + size_t slen = (TextLength>=0) ? (size_t)TextLength : (size_t)-1; + todbc_string_t sql = todbc_string_init(enc, StatementText, slen); + if (!sql.buf) { + SET_OOM(errs, ""); + return SQL_ERROR; + } + + if (1) { + todbc_string_t l = todbc_string_conv_to(&sql, conn->enc_src, NULL); + P("prepare:[%s]", (const char*)l.buf); + } + + return stmt_prepare(stmt, &sql); + + // sql_t *sql = (sql_t*)StatementHandle; + // rs_t *rs = &sql->rs; + + // OILE(rs->taos_rs.rs_is_opened_by_taos_query==0); + + // OILE(sql->owner); + // conn_t *conn = sql->owner->conn; + // OILE(conn); + + // OILE(rs->sql==NULL); + // paramset_t *paramset = &sql->paramset; + // paramset_close(paramset); + + // SQLRETURN r = sql_set_statement(sql, StatementText, TextLength); + // if (r!=SQL_SUCCESS) return r; + // + // int n_params = 0; + // r = sql_prepare(sql, &n_params); + // if (r!=SQL_SUCCESS) return r; + + // paramset_init_params(paramset, n_params); + // if (!paramset->params_cache || !paramset->params || !paramset->taos_binds) { + // sql_close_taos_stmt(sql); + // SET_ERROR(sql, "HY001", ""); + // return SQL_ERROR; + // } + + // // for (int i=0; iparams + i; + + // // } + + // paramset->sql = sql; + // paramset->n_params = n_params; + + // return sql_after_prepare(sql); +} + +static SQLRETURN doSQLNumParams(SQLHSTMT StatementHandle, SQLSMALLINT *ParameterCountPtr) +{ + OILE(ParameterCountPtr, ""); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(stmt->prepared, ""); + + *ParameterCountPtr = (SQLSMALLINT)stmt->paramset.n_params; + + P("ParameterCount:[%d]", *ParameterCountPtr); + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLBindParameter( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT InputOutputType, + SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, + SQLULEN ColumnSize, + SQLSMALLINT DecimalDigits, + SQLPOINTER ParameterValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr) +{ + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + param_binding_t arg = {0}; + arg.ParameterNumber = ParameterNumber; + arg.InputOutputType = InputOutputType; + arg.ValueType = ValueType; // sql c data type + arg.ParameterType = ParameterType; // sql data type + arg.ColumnSize = ColumnSize; + arg.DecimalDigits = DecimalDigits; + arg.ParameterValuePtr = ParameterValuePtr; + arg.BufferLength = BufferLength; + arg.StrLen_or_IndPtr = StrLen_or_IndPtr; + + return stmt_bind_param(stmt, &arg); + + // sql_t *sql = (sql_t*)StatementHandle; + // rs_t *rs = &sql->rs; + // OILE(rs->sql==NULL); + // OILE(IS_PREPARED(sql)); + // paramset_t *paramset = &sql->paramset; + // OILE(ParameterNumber>0); + + // OILE(StrLen_or_IndPtr); + + // paramset_realloc_bps(paramset, ParameterNumber); + // if (!paramset->bps_cache || !paramset->bps || paramset->n_bpsbps + (ParameterNumber-1); + // bp->ParameterNumber = ParameterNumber; + // bp->InputOutputType = InputOutputType; + // bp->ValueType = ValueType; + // bp->ParameterType = ParameterType; + // bp->ColumnSize = ColumnSize; + // bp->DecimalDigits = DecimalDigits; + // bp->ParameterValuePtr = ParameterValuePtr; + // bp->BufferLength = BufferLength; + // bp->StrLen_or_IndPtr = StrLen_or_IndPtr; + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLSetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) +{ + P("Attribute:[%d]%s; Value:[%p]; StringLength:[%d]%s", + Attribute, sql_stmt_attr_type(Attribute), Value, + StringLength, sql_soi_type(StringLength)); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + stmt_attr_t *attr = &stmt->attr; + + errs_t *errs = &stmt->errs; + + switch (Attribute) + { + case SQL_ATTR_PARAM_BIND_TYPE: + { + SQLULEN v = (SQLULEN)Value; + ONIY(v!=SQL_PARAM_BIND_BY_COLUMN, ""); + attr->bind_type = v; + P("%s:[%ld]", sql_stmt_attr_type(Attribute), v); + } break; + case SQL_ATTR_PARAMSET_SIZE: + { + SQLULEN v = (SQLULEN)Value; + ONIY(v!=0, ""); + attr->paramset_size = v; + P("%s:[%ld]", sql_stmt_attr_type(Attribute), v); + } break; + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + SQLULEN *v = (SQLULEN*)Value; + attr->bind_offset_ptr = v; + P("%s:[%p]", sql_stmt_attr_type(Attribute), v); + } break; + default: + { + P("Attribute:[%d]%s not implemented yet", Attribute, sql_stmt_attr_type(Attribute)); + SET_NIY(errs, "Attribute:[%d]%s", Attribute, sql_stmt_attr_type(Attribute)); + // ONSP(0, "Attribute:[%d]%s", Attribute, sql_stmt_attr_type(Attribute)); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLExecute(SQLHSTMT StatementHandle) +{ + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + stmt_close_rs(stmt); + OILE(STMT_IS_NORM(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + return stmt_execute(stmt); + + // sql_t *sql = (sql_t*)StatementHandle; + // OILE(sql); + // OILE(IS_PREPARED(sql)); + // OILE(!IS_EXECUTING(sql)); + + // rs_t *rs = &sql->rs; + // OILE(rs->taos_rs.rs_is_opened_by_taos_query==0); + // rs_close(rs); + // OILE(rs->sql==NULL); + + // SET_EXECUTING(sql); + + // paramset_t *paramset = &sql->paramset; + // OILE(paramset); + + // // fetch parameters + // OILE(paramset->n_bps==paramset->n_params); + // if (paramset->paramset_size==0) { + // // nodejs workaround + // paramset->paramset_size = 1; + // } + // for (unsigned int i=0; iparamset_size; ++i) { + // for (unsigned int j=0; jn_bps && jn_params; ++j) { + // SQLRETURN r = sql_process_param(sql, i, j); + // if (r!=SQL_SUCCESS) return r; + // } + // OILE(paramset->taos_binds); + // int tr = taos_stmt_bind_param(sql->stmt, paramset->taos_binds); + // if (tr) { + // SET_ERROR(sql, "HY000", "failed to bind parameters[%d in total][%d]%s", paramset->n_params, tr, tstrerror(tr)); + // // keep executing/executed state unchanged + // return SQL_ERROR; + // } + + // tr = taos_stmt_add_batch(sql->stmt); + // if (tr) { + // SET_ERROR(sql, "HY000", "failed to add batch:[%d]%s", tr, tstrerror(tr)); + // // keep executing/executed state unchanged + // return SQL_ERROR; + // } + // } + + // if (1) { + // int r = taos_stmt_execute(sql->stmt); + // if (r) { + // SET_ERROR(sql, "HY000", "failed to execute statement:[%d]%s", r, tstrerror(r)); + // // keep executing/executed state unchanged + // return SQL_ERROR; + // } + + // taos_rs_t *taos_rs = &rs->taos_rs; + // OILE(taos_rs->owner==NULL); + // taos_rs->owner = rs; + // taos_rs->rs = taos_stmt_use_result(sql->stmt); + // } + + // SET_EXECUTED(sql); + + // return sql_after_exec(sql); +} + +static SQLRETURN doSQLFetch(SQLHSTMT StatementHandle) +{ + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + if (STMT_TYPEINFO(stmt)) { + return SQL_SUCCESS; + } + + return stmt_fetch(stmt); + // sql_t *sql = (sql_t*)StatementHandle; + // OILE(sql); + // rs_t *rs = &sql->rs; + // OILE(rs->n_rows==-1 || rs->curr_rown_rows); + // row_t *row = &rs->row; + // taos_rs_t *taos_rs = &rs->taos_rs; + // OA(rs->n_fields==taos_rs->n_fields, "%d/%d", rs->n_fields, taos_rs->n_fields); + + // if (rs->eof) return SQL_NO_DATA; + + // if (rs->n_rows!=-1 && rs->curr_row + 1 >= rs->n_rows) { + // row_release(row); + // taos_rs->row = NULL; + // rs->eof = 1; + // return SQL_NO_DATA; + // } + + // row_release(row); + // taos_rs->row = NULL; + // ++rs->curr_row; + // row->valid = 1; + // taos_rs->row = taos_fetch_row(taos_rs->rs); + // D("row:[%p]", taos_rs->row); + // if (!taos_rs->row) { + // row->valid = 0; + // rs->eof = 1; + // D("..."); + // return SQL_NO_DATA; + // } + + // // column bound? + // if (!rs->bcs) return SQL_SUCCESS; + // for (int i=0; in_fields; ++i) { + // SQLRETURN r = sql_get_data(sql, (unsigned int)i); + // if (r!=SQL_SUCCESS) return r; + // } + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, SQLLEN BufferLength, + SQLLEN *StrLen_or_IndPtr) +{ + P("ColumnNumber:[%d]; TargetType:[%d]%s; BufferLength:[%ld]; StrLen_or_IndPtr:[%p]", + ColumnNumber, + TargetType, sql_c_type(TargetType), + BufferLength, StrLen_or_IndPtr); + + OILE(TargetValue, ""); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + if (STMT_TYPEINFO(stmt)) { + ONIY(ColumnNumber==3, ""); + ONIY(TargetType==SQL_C_LONG, ""); + int32_t v = 255; + switch (stmt->typeinfo) { + case SQL_VARCHAR: + case SQL_WVARCHAR: + case SQL_VARBINARY: + break; + case SQL_TIMESTAMP: + case SQL_TYPE_TIMESTAMP: + v = 23; + break; + default: + { + OILE(0, ""); + } break; + } + *(int32_t*)TargetValue = v; + return SQL_SUCCESS; + } + + errs_t *errs = &stmt->errs; + + OILE(ColumnNumber>=0, ""); + if (ColumnNumber==0) { + SET_ERR(errs, "07009", "invalid ColumnNumber[%d]", ColumnNumber); + return SQL_ERROR; + } + + col_binding_t binding = { + .ColumnNumber = ColumnNumber, + .TargetType = TargetType, + .TargetValue = TargetValue, + .BufferLength = BufferLength, + .StrLen_or_IndPtr = StrLen_or_IndPtr + }; + + return stmt_get_data(stmt, &binding); + + // ONIY(TargetValue); + + // sql_t *sql = (sql_t*)StatementHandle; + // OILE(sql); + // rs_t *rs = &sql->rs; + // OILE(rs->sql==sql); + + // if (rs->eof) return SQL_NO_DATA; + // OILE(rs->curr_row>=0); + // OILE(rs->n_rows==-1 || rs->curr_rown_rows); + + // field_t *fields = rs->fields; + // if (!fields) return SQL_NO_DATA; + + // row_t *row = &rs->row; + // OILE(row->valid); + + // col_t *cols = row->cols; + + // if (cols==cols_timestamp || cols==cols_varchar || cols==cols_wvarchar || cols==cols_varbinary) { + // ONIY(ColumnNumber==3); + // ONIY(ColumnNumber<=row->n_cols); + // col_t *col = cols + (ColumnNumber-1); + // OILE(col->valid); + // ONIY(col->c_type==TargetType); + // OILE(col->c_type==SQL_C_LONG); + // int32_t v = col->u.c_long; + // ONIY(BufferLength>=sizeof(v)); + // ONIY(StrLen_or_IndPtr==0); + // *(int32_t*)TargetValue = v; + // return SQL_SUCCESS; + // } + + // OILE(StrLen_or_IndPtr); + // *StrLen_or_IndPtr = SQL_NULL_DATA; + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, + SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength) +{ + P("HandleType:[%d]%s; RecNumber:[%d]; DiagIdentifier:[%d]%s; BufferLength:[%d]", + HandleType, sql_handle_type(HandleType), RecNumber, + DiagIdentifier, sql_diag_identifier(DiagIdentifier), + BufferLength); + OILE(0, ""); + // terror_t *err = NULL; + // switch (HandleType) + // { + // case SQL_HANDLE_ENV: + // { + // env_t *env = (env_t*)Handle; + // err = &env->err; + // } break; + // case SQL_HANDLE_DBC: + // { + // conn_t *conn = (conn_t*)Handle; + // err = &conn->err; + // } break; + // case SQL_HANDLE_STMT: + // { + // sql_t *sql = (sql_t*)Handle; + // err = &sql->err; + // } break; + // default: + // { + // OILE(0); + // return SQL_ERROR; + // } break; + // } + + // OILE(err); + // return SQL_NO_DATA; +} + +static SQLRETURN doSQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType) +{ + P("DataType:[%d]%s", DataType, sql_sql_type(DataType)); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + stmt_close_rs(stmt); + OILE(STMT_IS_NORM(stmt), ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + switch (DataType) + { + case SQL_VARCHAR: + case SQL_WVARCHAR: + case SQL_VARBINARY: + case SQL_TIMESTAMP: + case SQL_TYPE_TIMESTAMP: + { + stmt->typeinfo = DataType; + } break; + default: + { + ONIY(0, ""); + return SQL_ERROR; + } break; + } + + STMT_SET_EXECUTED(stmt); + + return SQL_SUCCESS; +} + +static SQLRETURN doSQLDescribeParam( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT * DataTypePtr, + SQLULEN * ParameterSizePtr, + SQLSMALLINT * DecimalDigitsPtr, + SQLSMALLINT * NullablePtr) +{ + // SQLRETURN r; + + OILE(ParameterNumber>0, ""); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(stmt->prepared, ""); + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + errs_t *errs = &stmt->errs; + + // const char *enc = conn->enc_char; + + paramset_t *paramset = &stmt->paramset; + param_t *params = paramset->params; + int n_params = paramset->n_params; + + if (ParameterNumber>n_params) { + SET_ERR(errs, "07009", "invalid ParameterNumber/#params [%d/%d]", ParameterNumber, n_params); + return SQL_ERROR; + } + + param_t *param = params + (ParameterNumber-1); + if (DataTypePtr) *DataTypePtr = param->DataType; + if (ParameterSizePtr) *ParameterSizePtr = param->ParameterSize; + if (DecimalDigitsPtr) *DecimalDigitsPtr = param->DecimalDigits; + if (NullablePtr) *NullablePtr = param->Nullable; + + return SQL_SUCCESS; + + // sql_t *sql = (sql_t*)StatementHandle; + // rs_t *rs = &sql->rs; + // OILE(rs->sql==NULL); + // OILE(IS_PREPARED(sql)); + // OILE(DataTypePtr); + // OILE(ParameterSizePtr); + // OILE(DecimalDigitsPtr); + + // paramset_t *paramset = &sql->paramset; + // OILE(paramset->sql); + // OILE(ParameterNumber>0 && ParameterNumber<=paramset->n_params); + + // *DataTypePtr = SQL_C_CHAR; + // *ParameterSizePtr = 23; + // *DecimalDigitsPtr = 0; + // if (NullablePtr) *NullablePtr = SQL_NULLABLE; + + // param_t *param = paramset->params + (ParameterNumber-1); + // int taos_type = param->taos_type; + // switch (taos_type) + // { + // case TSDB_DATA_TYPE_TIMESTAMP: + // { + // *DataTypePtr = SQL_CHAR; + // *ParameterSizePtr = 23; + // *DecimalDigitsPtr = 0; + // if (NullablePtr) *NullablePtr = SQL_NULLABLE; + // } break; + // case TSDB_DATA_TYPE_TINYINT: + // { + // *DataTypePtr = SQL_TINYINT; + // *ParameterSizePtr = 1; + // *DecimalDigitsPtr = 0; + // if (NullablePtr) *NullablePtr = SQL_NULLABLE; + // } break; + // default: + // { + // OA(0, "taos param:[%d][%d]%s", ParameterNumber, taos_type, taos_data_type(taos_type)); + // return SQL_ERROR; + // } break; + // } + + // P("ParameterNumber:[%d]; DataTypePtr:[%p]%s; ParameterSizePtr:[%p]%ld; DecimalDigitsPtr:[%p]%d; NullablePtr:[%p]%d", + // ParameterNumber, + // DataTypePtr, DataTypePtr ? sql_sql_type(*DataTypePtr) : "UNKNOWN", + // ParameterSizePtr, ParameterSizePtr ? *ParameterSizePtr : 0, + // DecimalDigitsPtr, DecimalDigitsPtr ? *DecimalDigitsPtr : 0, + // NullablePtr, NullablePtr ? *NullablePtr : 0); + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLFreeConnect(SQLHDBC ConnectionHandle) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + OILE(conn->stmts.count==0, ""); + conn_free(conn); + return SQL_SUCCESS; +} + +static SQLRETURN doSQLFreeEnv(SQLHENV EnvironmentHandle) +{ + env_t *env = (env_t*)EnvironmentHandle; + env_dec_ref(env); + return SQL_SUCCESS; +} + +static SQLRETURN doSQLBindCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, + SQLLEN BufferLength, SQLLEN *StrLen_or_IndPtr) +{ + P("ColumnNumber:[%d]; TargetType:[%d]%s; BufferLength:[%ld]", + ColumnNumber, TargetType, sql_c_type(TargetType), BufferLength); + + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + errs_t *errs = &stmt->errs; + + OILE(ColumnNumber>=0, ""); + if (ColumnNumber==0) { + SET_ERR(errs, "07009", "invalid ColumnNumber[%d]", ColumnNumber); + return SQL_ERROR; + } + + col_binding_t binding = { + .ColumnNumber = ColumnNumber, + .TargetType = TargetType, + .TargetValue = TargetValue, + .BufferLength = BufferLength, + .StrLen_or_IndPtr = StrLen_or_IndPtr + }; + + return stmt_bind_col(stmt, &binding); + + + // OILE(ColumnNumber>0); + // sql_t *sql = (sql_t*)StatementHandle; + // OILE(!IS_EXECUTING(sql)); + + // rs_t *rs = &sql->rs; + // OILE(rs->fields); + // OILE(rs->n_fields>=ColumnNumber); + + // if (!rs->bcs_cache) { + // rs->bcs_cache = todbc_buf_create(); + // if (!rs->bcs_cache) { + // SET_ERROR(sql, "HY001", ""); + // return SQL_ERROR; + // } + // OILE(rs->bcs==NULL); + // rs->bcs = (bc_t*)todbc_buf_calloc(rs->bcs_cache, (size_t)rs->n_fields, sizeof(*rs->bcs)); + // if (!rs->bcs) { + // SET_ERROR(sql, "HY001", ""); + // return SQL_ERROR; + // } + // } + // OILE(rs->bcs); + + // bc_t *bc = rs->bcs + (ColumnNumber-1); + // bc->ColumnNumber = ColumnNumber; + // bc->TargetType = TargetType; + // bc->TargetValue = TargetValue; + // bc->BufferLength = BufferLength; + // bc->StrLen_or_IndPtr = StrLen_or_IndPtr; + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLCloseCursor(SQLHSTMT StatementHandle) +{ + stmt_t *stmt = (stmt_t*)StatementHandle; + OILE(stmt, ""); + errs_t *errs = &stmt->errs; + + if (STMT_IS_NORM(stmt)) { + OW("no cursor was opened previously"); + SET_ERR(errs, "24000", ""); + return SQL_ERROR; + } + + OILE(STMT_IS_EXECUTED(stmt), ""); + stmt_close_rs(stmt); + + return SQL_SUCCESS; + + // sql_t *sql = (sql_t*)StatementHandle; + // OILE(!IS_EXECUTING(sql)); + + // rs_t *rs = &sql->rs; + // if (!rs->sql) { + // SET_ERROR(sql, "24000", ""); + // OW("no cursor was opened previously"); + // return SQL_ERROR; + // } + + // OILE(rs->sql==sql); + // rs_close(rs); + + // return SQL_SUCCESS; +} + +static SQLRETURN doSQLError(SQLHENV EnvironmentHandle, + SQLHDBC ConnectionHandle, SQLHSTMT StatementHandle, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength) +{ + env_t *env = (env_t*)EnvironmentHandle; + conn_t *conn = (conn_t*)ConnectionHandle; + stmt_t *stmt = (stmt_t*)StatementHandle; + OD("env/conn/stmt:[%p/%p/%p]", env, conn, stmt); + + SQLSMALLINT HandleType; + SQLHANDLE Handle; + if (stmt) { + HandleType = SQL_HANDLE_STMT; + Handle = StatementHandle; + } else if (conn) { + HandleType = SQL_HANDLE_DBC; + Handle = ConnectionHandle; + } else if (env) { + HandleType = SQL_HANDLE_ENV; + Handle = EnvironmentHandle; + } else { + return SQL_NO_DATA; + } + + return doSQLGetDiagRec(HandleType, Handle, 1, Sqlstate, NativeError, MessageText, BufferLength, TextLength); +} + + +#ifdef _MSC_VER + +#define POST_INSTALLER_ERROR(hwndParent, code, fmt, ...) \ +do { \ + char buf[4096]; \ + snprintf(buf, sizeof(buf), "%s[%d]%s():" fmt "", \ + basename((char*)__FILE__), __LINE__, __func__, \ + ##__VA_ARGS__); \ + SQLPostInstallerError(code, buf); \ + if (hwndParent) { \ + MessageBox(hwndParent, buf, "Error", MB_OK|MB_ICONEXCLAMATION); \ + } \ +} while (0) + +typedef struct kv_s kv_t; +struct kv_s { + char *line; + size_t val; +}; + +static BOOL get_driver_dll_path(HWND hwndParent, char *buf, size_t len) +{ + HMODULE hm = NULL; + + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR) &ConfigDSN, &hm) == 0) + { + int ret = GetLastError(); + POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "GetModuleHandle failed, error = %d\n", ret); + return FALSE; + } + if (GetModuleFileName(hm, buf, (DWORD)len) == 0) + { + int ret = GetLastError(); + POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "GetModuleFileName failed, error = %d\n", ret); + return FALSE; + } + return TRUE; +} + +static BOOL doDSNAdd(HWND hwndParent, LPCSTR lpszDriver, LPCSTR lpszAttributes) +{ + BOOL r = TRUE; + + kv_t *kvs = NULL; + + kv_t dsn = {0}; + char *line = NULL; + + do { + char driver_dll[MAX_PATH + 1]; + r = get_driver_dll_path(hwndParent, driver_dll, sizeof(driver_dll)); + if (!r) break; + + dsn.line = strdup("DSN=TAOS_DEMO"); + if (!dsn.line) { r = FALSE; break; } + + const char *p = lpszAttributes; + int ikvs = 0; + while (p && *p) { + line = strdup(p); + if (!line) { r = FALSE; break; } + char *v = strchr(line, '='); + if (!v) { r = FALSE; break; } + + if (strstr(line, "DSN")==line) { + if (dsn.line) { + free(dsn.line); + dsn.line = NULL; + dsn.val = 0; + } + dsn.line = line; + line = NULL; + } else { + kv_t *t = (kv_t*)realloc(kvs, (ikvs+1)*sizeof(*t)); + if (!t) { r = FALSE; free(line); break; } + t[ikvs].line = line; + *v = '\0'; + if (v) t[ikvs].val = v - line + 1; + line = NULL; + + kvs = t; + ++ikvs; + } + + p += strlen(p) + 1; + } + + if (hwndParent) { + MessageBox(hwndParent, "Please use odbcconf to add DSN for TAOS ODBC Driver", "Warning!", MB_OK|MB_ICONEXCLAMATION); + } + if (!r) break; + + char *v = NULL; + v = strchr(dsn.line, '='); + if (!v) { r = FALSE; break; } + *v = '\0'; + dsn.val = v - dsn.line + 1; + + if ((!dsn.line)) { + if (!r) POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "lack of either DSN or Driver"); + } else { + if (r) r = SQLWritePrivateProfileString("ODBC Data Sources", dsn.line+dsn.val, lpszDriver, "Odbc.ini"); + if (r) r = SQLWritePrivateProfileString(dsn.line+dsn.val, "Driver", driver_dll, "Odbc.ini"); + } + + for (int i=0; r && i + * + * 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 _base_h_ +#define _base_h_ + +#include "todbc_buf.h" +#include "todbc_iconv.h" +#include "todbc_log.h" + +#include "taos.h" +#include "taoserror.h" + +#include +#include + +typedef struct errs_s errs_t; +typedef struct env_s env_t; +typedef struct conn_s conn_t; +typedef struct stmt_s stmt_t; +typedef struct param_s param_t; +typedef struct field_s field_t; +typedef struct rs_s rs_t; +typedef struct col_s col_t; + +#define GET_REF(obj) atomic_load_64(&obj->refcount) +#define INC_REF(obj) atomic_add_fetch_64(&obj->refcount, 1) +#define DEC_REF(obj) atomic_sub_fetch_64(&obj->refcount, 1) + +// public +#ifdef __GNUC__ + __attribute__((format(printf, 6, 7))) +#endif +SQLRETURN errs_append(errs_t *errs, const char sql_state[6], const char *file, int line, const char *func, const char *fmt, ...); +int errs_count(errs_t *errs); +// 0/-1: ok/no-error +int errs_fetch(errs_t *errs, int idx, const char **sql_state, const char **err_str); +void errs_clear(SQLSMALLINT HandleType, SQLHANDLE InputHandle); + +// err: if <>0, will generate strerror +#define SET_ERR(errs, sql_state, fmt, ...) \ + errs_append(errs, sql_state, __FILE__, __LINE__, __func__, "%s" fmt "", "", ##__VA_ARGS__) + +#define SET_OOM(errs, fmt, ...) SET_ERR(errs, "TD001", "OOM:" fmt, ##__VA_ARGS__) +#define SET_NIY(errs, fmt, ...) SET_ERR(errs, "TDC00", "NIY:" fmt, ##__VA_ARGS__) +#define SET_GENERAL(errs, fmt, ...) SET_ERR(errs, "TD000", "GEN:" fmt, ##__VA_ARGS__) + + +// public +errs_t* env_get_errs(env_t *env); +void env_clr_errs(env_t *env); +void env_inc_ref(env_t *env); +void env_dec_ref(env_t *env); + +// public +errs_t* conn_get_errs(conn_t *conn); +void conn_clr_errs(conn_t *conn); + +// public +errs_t* stmt_get_errs(stmt_t *stmt); +void stmt_clr_errs(stmt_t *stmt); + +#endif // _base_h_ + + diff --git a/src/connector/odbc/src/base/CMakeLists.txt b/src/connector/odbc/src/base/CMakeLists.txt new file mode 100644 index 0000000000..fa13f3e077 --- /dev/null +++ b/src/connector/odbc/src/base/CMakeLists.txt @@ -0,0 +1,10 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(TDengine) + +aux_source_directory(. SRC) +add_library(todbc_base STATIC ${SRC}) + +if (TD_DARWIN) + target_include_directories(todbc_base PRIVATE /usr/local/include) +endif () + diff --git a/src/connector/odbc/src/base/conn.c b/src/connector/odbc/src/base/conn.c new file mode 100644 index 0000000000..6e0554d885 --- /dev/null +++ b/src/connector/odbc/src/base/conn.c @@ -0,0 +1,223 @@ +/* + * 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 "conn.h" + +#include "env.h" + +#include "../todbc_tls.h" + +static void init_encodes(conn_t *conn, env_t *env) { + OILE(conn, ""); + OILE(env, ""); + const char *enc_charset = env->enc_charset; + + snprintf(conn->enc_src, sizeof(conn->enc_src), "%s", UTF8_ENC); // compile-time constant + snprintf(conn->enc_wchar, sizeof(conn->enc_wchar), "%s", UTF16_ENC); // compile-time constant + snprintf(conn->enc_char, sizeof(conn->enc_char), "%s", enc_charset); // runtime default + snprintf(conn->enc_db, sizeof(conn->enc_db), "%s", enc_charset); // runtime default + snprintf(conn->enc_locale, sizeof(conn->enc_locale), "%s", enc_charset); // runtime default + + OD("enc_src:[%s]; enc_wchar:[%s]; enc_char:[%s]; enc_db:[%s]; enc_locale:[%s]", + conn->enc_src, conn->enc_wchar, conn->enc_char, conn->enc_db, conn->enc_locale); +} + +static int conn_init(conn_t *conn, env_t *env) { + OILE(conn, ""); + OILE(env, ""); + errs_t *errs = &env->errs; + + OILE(conn->env==NULL, ""); + + int r = errs_init(&conn->errs); + if (r) return -1; + + init_encodes(conn, env); + if (SQL_SUCCESS!=conn_check_charset(conn, errs)) { + return -1; + } + + conn->env = env; + env_inc_ref(env); + + return 0; +}; + +static void conn_release(conn_t *conn) { + if (!conn) return; + env_t *env = conn->env; + if (!env) return; + + conn->env = NULL; + env_dec_ref(env); +} + +conn_t* conn_new(env_t *env) { + conn_t *conn = (conn_t*)calloc(1, sizeof(*conn)); + if (!conn) return NULL; + + if (conn_init(conn, env)) { + OILE(conn->env==NULL, ""); + free(conn); + return NULL; + } + + return conn; +} + +void conn_free(conn_t *conn) { + if (!conn) return; + + // clean ext stuff + if (conn->ext.free_conn) { + conn->ext.free_conn(conn); + } + + // clean conn stuffs + conn_release(conn); + + free(conn); +} + +static SQLRETURN do_check_charset(errs_t *errs, const char *enc_charset, todbc_enc_t *enc) { + *enc = todbc_tls_iconv_enc(enc_charset); + if (enc->enc[0]=='\0') { + if (errs) { + SET_GENERAL(errs, "unknown charset [%s]", enc_charset); + } + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +SQLRETURN conn_check_charset(conn_t *conn, errs_t *errs) { + OILE(conn, ""); + + todbc_enc_t enc; + + SQLRETURN r; + r = do_check_charset(errs, conn->enc_char, &enc); + if (r!=SQL_SUCCESS) return r; + r = do_check_charset(errs, conn->enc_db, &enc); + if (r!=SQL_SUCCESS) return r; + r = do_check_charset(errs, conn->enc_locale, &enc); + if (r!=SQL_SUCCESS) return r; + r = do_check_charset(errs, conn->enc_src, &enc); + if (r!=SQL_SUCCESS) return r; + + r = do_check_charset(errs, conn->enc_wchar, &enc); + if (r!=SQL_SUCCESS) return r; + + if (enc.variable_char_size!=-1) { + OE("does not support [%s] for WCHAR", conn->enc_wchar); + if (errs) { + SET_GENERAL(errs, "does not support [%s] for WCHAR", conn->enc_wchar); + } + return SQL_ERROR; + } + if (enc.char_size<=0) { + if (errs) { + SET_GENERAL(errs, "unknown [%s] for WCHAR", conn->enc_wchar); + } + return SQL_ERROR; + } + + conn->wchar_size = (size_t)enc.char_size; + + return SQL_SUCCESS; +} + +int conn_add_stmt(conn_t *conn, stmt_t *stmt) { + OILE(conn, ""); + OILE(stmt, ""); + OILE(stmt->owner==NULL, ""); + OILE(stmt->next==NULL, ""); + OILE(stmt->prev==NULL, ""); + OILE(conn->ext.init_stmt, ""); + + if (conn->ext.init_stmt(stmt)) { + return -1; + } + + stmts_t *owner = &conn->stmts; + + stmt->owner = owner; + + stmt->prev = owner->tail; + if (owner->tail) owner->tail->next = stmt; + else owner->head = stmt; + owner->tail = stmt; + + ++owner->count; + owner->conn = conn; + + return 0; +} + +void conn_del_stmt(conn_t *conn, stmt_t *stmt) { + OILE(conn, ""); + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(stmt->owner==&conn->stmts, ""); + OILE(stmt->owner->conn==conn, ""); + + stmts_t *owner = stmt->owner; + + stmt_t *next = stmt->next; + stmt_t *prev = stmt->prev; + + if (next) next->prev = prev; + else owner->tail = prev; + + if (prev) prev->next = next; + else owner->head = next; + + --owner->count; + + stmt->next = NULL; + stmt->prev = NULL; + stmt->owner = NULL; +} + +SQLRETURN conn_connect(conn_t *conn) { + OILE(conn, ""); + OILE(conn->ext.connect, ""); + return conn->ext.connect(conn); +} + +void conn_disconnect(conn_t *conn) { + OILE(conn, ""); + OILE(conn->ext.disconnect, ""); + conn->ext.disconnect(conn); +} + +// public +errs_t* conn_get_errs(conn_t *conn) { + OILE(conn, ""); + + return &conn->errs; +} + +void conn_clr_errs(conn_t *conn) { + if (!conn) return; + + errs_reclaim(&conn->errs); +} + + + + + diff --git a/src/connector/odbc/src/base/conn.h b/src/connector/odbc/src/base/conn.h new file mode 100644 index 0000000000..d82cbc37d4 --- /dev/null +++ b/src/connector/odbc/src/base/conn.h @@ -0,0 +1,81 @@ +/* + * 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 _conn_h_ +#define _conn_h_ + +#include "../base.h" + +#include "stmt.h" + + +#include "../todbc_flex.h" + +typedef struct conn_ext_s conn_ext_t; +struct conn_ext_s { + void *ext; + void (*free_conn)(conn_t *conn); + int (*init_stmt)(stmt_t *stmt); + + SQLRETURN (*connect)(conn_t *conn); + void (*disconnect)(conn_t *conn); +}; + +struct conn_s { + env_t *env; + + char enc_src[64]; // c source file encoding + char enc_char[64]; // SQL_CHAR encoding + char enc_wchar[64]; // SQL_WCHAR encoding + char enc_db[64]; // taos client encoding + // use this for system i/o, such as reading from stdin, writing to stdout/stderr + char enc_locale[64]; // default: current localee + + size_t wchar_size; // shall be fix-length + + conn_val_t val; + + stmts_t stmts; + + errs_t errs; + + conn_ext_t ext; + + unsigned int connect:2; +}; + +#define CONN_SET_CONNECTING(conn) (conn->connect=0x01) +#define CONN_SET_CONNECTED(conn) (conn->connect=0x02) +#define CONN_SET_NORM(conn) (conn->connect=0x00) + +#define CONN_IS_CONNECTING(conn) (conn->connect==0x01) +#define CONN_IS_CONNECTED(conn) (conn->connect==0x02) +#define CONN_IS_NORM(conn) (conn->connect==0x00) + +conn_t* conn_new(env_t *env); +void conn_free(conn_t *conn); + +SQLRETURN conn_check_charset(conn_t *conn, errs_t *errs); + +int conn_add_stmt(conn_t *conn, stmt_t *stmt); +void conn_del_stmt(conn_t *conn, stmt_t *stmt); + +SQLRETURN conn_connect(conn_t *conn); +void conn_disconnect(conn_t *conn); + + +#endif // _conn_h_ + + diff --git a/src/connector/odbc/src/base/env.c b/src/connector/odbc/src/base/env.c new file mode 100644 index 0000000000..75b5b83602 --- /dev/null +++ b/src/connector/odbc/src/base/env.c @@ -0,0 +1,117 @@ +/* + * 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 "env.h" + +#include + +static pthread_once_t init_once = PTHREAD_ONCE_INIT; +static char default_charset[64] = {0}; + +static void init_routine(void) { + OD("compiled with ODBCVER:[0x%04x]", ODBCVER); + + const char *charset = NULL; + setlocale(LC_ALL, ""); + const char *locale = setlocale(LC_CTYPE, NULL); + if (locale) { + const char *dot = strrchr(locale, '.'); + if (dot) charset = dot + 1; + } + if (!charset) { +#ifdef _MSC_VER + charset = "CP936"; +#else + charset = "UTF-8"; +#endif + OD("failed to find original locale, fall back to [%s]", charset); + } else { +#ifdef _MSC_VER + char buf[64]; + snprintf(buf, sizeof(buf), "CP%s", charset); + charset = buf; +#endif + OD("system default charset: [%s]", charset); + } + + snprintf(default_charset, sizeof(default_charset), "%s", charset); +} + + +static void env_release(env_t *env) { + if (!env) return; + OILE(env->refcount==0, ""); + + env_clr_errs(env); +} + +int env_init(env_t *env) { + OILE(env, ""); + OILE(env->refcount==0, ""); + + pthread_once(&init_once, init_routine); + + int r = errs_init(&env->errs); + if (r) return -1; + + snprintf(env->enc_charset, sizeof(env->enc_charset), "%s", default_charset); + env->odbc_ver = SQL_OV_ODBC3; + + env->refcount = 1; + + return 0; +} + +// public +errs_t* env_get_errs(env_t *env) { + OILE(env, ""); + + return &env->errs; +} + +void env_clr_errs(env_t *env) { + if (!env) return; + + errs_reclaim(&env->errs); +} + +void env_inc_ref(env_t *env) { + OILE(env, ""); + int64_t rc = INC_REF(env); + OILE(rc>=2, ""); +} + +void env_dec_ref(env_t *env) { + OILE(env, ""); + int64_t rc = DEC_REF(env); + if (rc>0) return; + OILE(rc==0, ""); + + env_release(env); + free(env); +} + +env_t* env_create(void) { + env_t *env = (env_t*)calloc(1, sizeof(*env)); + if (!env) return NULL; + + if (env_init(env)) { + free(env); + return NULL; + } + + return env; +} + diff --git a/src/connector/odbc/src/base/env.h b/src/connector/odbc/src/base/env.h new file mode 100644 index 0000000000..b4f420ad64 --- /dev/null +++ b/src/connector/odbc/src/base/env.h @@ -0,0 +1,43 @@ +/* + * 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 _env_h_ +#define _env_h_ + +#include "../base.h" + +#include "err.h" + +struct env_s { + int64_t refcount; + + char enc_charset[64]; // default charset from system locale + int32_t odbc_ver; // default SQL_OV_ODBC3 + + errs_t errs; + + void (*env_free)(env_t* env); +}; + +int env_init(env_t *env); + +env_t* env_create(void); + + + + +#endif // _env_h_ + + diff --git a/src/connector/odbc/src/base/err.c b/src/connector/odbc/src/base/err.c new file mode 100644 index 0000000000..c154728807 --- /dev/null +++ b/src/connector/odbc/src/base/err.c @@ -0,0 +1,177 @@ +/* + * 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 "err.h" + +#include "env.h" +#include "conn.h" +#include "stmt.h" + +struct err_s { + char sql_state[6]; + char *err_str; // no ownership +}; + +static void errs_clr(errs_t *errs) { + if (!errs) return; + + errs->count = 0; + errs->errs = NULL; +} + +int errs_init(errs_t *errs) { + OILE(errs && errs->cache==NULL, ""); + OILE(errs->count==0 && errs->errs==NULL, ""); + + errs->cache = todbc_buf_create(); + + return errs->cache ? 0 : -1; +} + +void errs_reclaim(errs_t *errs) { + if (!errs) return; + if (!errs->cache) return; + + errs_clr(errs); + + todbc_buf_reclaim(errs->cache); +} + +void errs_release(errs_t *errs) { + if (!errs) return; + if (!errs->cache) return; + + errs_clr(errs); + + todbc_buf_free(errs->cache); + errs->cache = NULL; +} + +// public +#ifdef __GNUC__ + __attribute__((format(printf, 6, 7))) +#endif +SQLRETURN errs_append(errs_t *errs, const char sql_state[6], const char *file, int line, const char *func, const char *fmt, ...) +{ + OILE(errs, ""); + OILE(errs->cache, ""); + todbc_buf_t *cache = errs->cache; + + const char *name = basename((char*)file); + + char *buf = NULL; + size_t blen = 0; + while (1) { + char *p = buf; + size_t bytes = blen; + + int count = 0; + int n = 0; + + va_list ap; + va_start(ap, fmt); + if (bytes<0) bytes = 0; + n = vsnprintf(p, bytes, fmt, ap); + va_end(ap); + + OILE(n>=0, ""); + + count += n; + if (p) p += n; + if (bytes) bytes -= (size_t)n; + + if (bytes<0) bytes = 0; + n = snprintf(p, bytes, "@%s[%d]%s()\n", name, line, func); + + OILE(n>=0, ""); + count += n; + + if (p) break; + + buf = todbc_buf_alloc(cache, (size_t)count + 1); + if (!buf) return SQL_ERROR; + blen = (size_t)count; + } + + size_t bytes = (size_t)(errs->count + 1) * sizeof(err_t); + + err_t *es = (err_t*)todbc_buf_realloc(cache, errs->errs, bytes); + if (!es) return SQL_ERROR; + errs->errs = es; + errs->count += 1; + + err_t *err = errs->errs + errs->count - 1; + snprintf(err->sql_state, sizeof(err->sql_state), "%s", sql_state); + err->err_str = buf; + + + return SQL_SUCCESS; +} + +int errs_count(errs_t *errs) { + OILE(errs, ""); + OILE(errs->cache, ""); + + return errs->count; +} + +// 0/-1: ok/no-error +int errs_fetch(errs_t *errs, int idx, const char **sql_state, const char **err_str) { + OILE(errs, ""); + OILE(errs->cache, ""); + + if (errs->count<=0) return -1; + if (idx<0 || idx>=errs->count) return -1; + + err_t *err = errs->errs + idx; + + if (sql_state) *sql_state = err->sql_state; + if (err_str) *err_str = err->err_str; + + return 0; +} + +void errs_clear(SQLSMALLINT HandleType, SQLHANDLE InputHandle) { + errs_t *errs = NULL; + + if (InputHandle==NULL) return; + + switch (HandleType) + { + case SQL_HANDLE_ENV: + { + env_t *env = (env_t*)InputHandle; + errs = &env->errs; + } break; + case SQL_HANDLE_DBC: + { + conn_t *conn = (conn_t*)InputHandle; + errs = &conn->errs; + } break; + case SQL_HANDLE_STMT: + { + stmt_t *stmt = (stmt_t*)InputHandle; + errs = &stmt->errs; + } break; + default: + { + ONIY(0, ""); + } break; + } + + if (!errs) return; + errs_reclaim(errs); +} + diff --git a/src/connector/odbc/src/base/err.h b/src/connector/odbc/src/base/err.h new file mode 100644 index 0000000000..ae8f9a8085 --- /dev/null +++ b/src/connector/odbc/src/base/err.h @@ -0,0 +1,35 @@ +/* + * 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 _err_h_ +#define _err_h_ + +#include "../base.h" + +typedef struct err_s err_t; + +struct errs_s { + todbc_buf_t *cache; + + int count; + err_t *errs; +}; + +int errs_init(errs_t *errs); +void errs_reclaim(errs_t *errs); +void errs_release(errs_t *errs); + +#endif // _err_h_ + diff --git a/src/connector/odbc/src/base/field.c b/src/connector/odbc/src/base/field.c new file mode 100644 index 0000000000..41a466069f --- /dev/null +++ b/src/connector/odbc/src/base/field.c @@ -0,0 +1,78 @@ +/* + * 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 "field.h" + +static void fieldset_clr_fields(fieldset_t *fieldset) { + if (!fieldset) return; + + fieldset->fields = NULL; + fieldset->n_fields = 0; +} + +static void fieldset_clr_bindings(fieldset_t *fieldset) { + if (!fieldset) return; + + fieldset->bindings = NULL; + fieldset->n_bindings = 0; +} + +void fieldset_init_fields(fieldset_t *fieldset) { + if (!fieldset) return; + if (fieldset->fields_cache) return; + fieldset->fields_cache = todbc_buf_create(); +} + +void fieldset_init_bindings(fieldset_t *fieldset) { + if (!fieldset) return; + if (fieldset->bindings_cache) return; + fieldset->bindings_cache = todbc_buf_create(); +} + +void fieldset_reclaim_fields(fieldset_t *fieldset) { + if (!fieldset) return; + + if (!fieldset->fields_cache) return; + + todbc_buf_reclaim(fieldset->fields_cache); + fieldset_clr_fields(fieldset); +} + +void fieldset_reclaim_bindings(fieldset_t *fieldset) { + if (!fieldset) return; + + if (!fieldset->bindings_cache) return; + + todbc_buf_reclaim(fieldset->bindings_cache); + fieldset_clr_bindings(fieldset); +} + +void fieldset_release(fieldset_t *fieldset) { + if (!fieldset) return; + + fieldset_reclaim_fields(fieldset); + fieldset_reclaim_bindings(fieldset); + + if (fieldset->fields_cache) { + todbc_buf_free(fieldset->fields_cache); + fieldset->fields_cache = NULL; + } + + if (fieldset->bindings_cache) { + todbc_buf_free(fieldset->bindings_cache); + fieldset->bindings_cache = NULL; + } +} + diff --git a/src/connector/odbc/src/base/field.h b/src/connector/odbc/src/base/field.h new file mode 100644 index 0000000000..667dc65ff6 --- /dev/null +++ b/src/connector/odbc/src/base/field.h @@ -0,0 +1,77 @@ +/* + * 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 _field_h_ +#define _field_h_ + +#include "../base.h" + +typedef struct fieldset_s fieldset_t; +typedef struct col_binding_s col_binding_t; +typedef struct field_arg_s field_arg_t; + +// SQLDescribeCol +struct field_arg_s { + SQLUSMALLINT ColumnNumber; + SQLCHAR *ColumnName; + SQLSMALLINT BufferLength; + SQLSMALLINT *NameLength; + SQLSMALLINT *DataType; // sql data type + SQLULEN *ColumnSize; + SQLSMALLINT *DecimalDigits; + SQLSMALLINT *Nullable; +}; + +struct field_s { + SQLUSMALLINT ColumnNumber; + SQLCHAR ColumnName[64]; // hard-coded + SQLSMALLINT DataType; // sql data type + SQLULEN ColumnSize; + SQLSMALLINT DecimalDigits; + SQLSMALLINT Nullable; +}; + +// SQLBindCol; SQLGetData +struct col_binding_s { + SQLUSMALLINT ColumnNumber; + SQLSMALLINT TargetType; // sql c data type + SQLPOINTER TargetValue; + SQLLEN BufferLength; + SQLLEN *StrLen_or_IndPtr; +}; + + +struct fieldset_s { + todbc_buf_t *fields_cache; + field_t *fields; + int n_fields; + + todbc_buf_t *bindings_cache; + col_binding_t *bindings; + int n_bindings; +}; + +void fieldset_init_fields(fieldset_t *fieldset); +void fieldset_init_bindings(fieldset_t *fieldset); + +void fieldset_reclaim_fields(fieldset_t *fieldset); +void fieldset_reclaim_bindings(fieldset_t *fieldset); + +void fieldset_release(fieldset_t *fields); + +#endif // _field_h_ + + + diff --git a/src/connector/odbc/src/base/null_conn.c b/src/connector/odbc/src/base/null_conn.c new file mode 100644 index 0000000000..29fe86991a --- /dev/null +++ b/src/connector/odbc/src/base/null_conn.c @@ -0,0 +1,115 @@ +/* + * 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 "null_conn.h" + +#include "env.h" + +// null_conn + +static void null_conn_free(conn_t *conn) { + OILE(conn, ""); + null_conn_t *null_conn = (null_conn_t*)conn->ext.ext; + OILE(null_conn, ""); + + conn->ext.ext = NULL; + conn->ext.free_conn = NULL; + + free(null_conn); +} + +static SQLRETURN null_conn_connect(conn_t *conn) { + OILE(conn, ""); + null_conn_t *null_conn = (null_conn_t*)conn->ext.ext; + OILE(null_conn && null_conn->conn==conn, ""); + OILE(CONN_IS_NORM(conn), ""); + return SQL_SUCCESS; +} + +static void null_conn_disconnect(conn_t *conn) { + OILE(conn, ""); + OILE(CONN_IS_CONNECTED(conn), ""); +} + +static void null_conn_free_stmt(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); +} + +static SQLRETURN null_conn_exec_direct(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(!STMT_IS_EXECUTED(stmt), ""); + STMT_SET_EXECUTED(stmt); + return SQL_SUCCESS; +} + +static SQLRETURN null_conn_prepare(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + return SQL_SUCCESS; +} + +static SQLRETURN null_conn_proc_param(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + return SQL_SUCCESS; +} + +static SQLRETURN null_conn_execute(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(!STMT_IS_EXECUTED(stmt), ""); + STMT_SET_EXECUTED(stmt); + return SQL_SUCCESS; +} + +static int null_conn_init_stmt(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->ext.ext==NULL, ""); + OILE(stmt->ext.free_stmt==NULL, ""); + + OILE(stmt->owner==NULL, ""); + + stmt->ext.ext = NULL; + stmt->ext.free_stmt = null_conn_free_stmt; + stmt->ext.exec_direct = null_conn_exec_direct; + stmt->ext.prepare = null_conn_prepare; + stmt->ext.proc_param = null_conn_proc_param; + stmt->ext.execute = null_conn_execute; + + return 0; +} + +int conn_init_null_conn(conn_t *conn) { + OILE(conn, ""); + OILE(conn->ext.ext==NULL, ""); + OILE(conn->ext.free_conn==NULL, ""); + + null_conn_t *null_conn = (null_conn_t*)calloc(1, sizeof(*null_conn)); + if (!null_conn) return -1; + + null_conn->conn = conn; + conn->ext.ext = null_conn; + conn->ext.free_conn = null_conn_free; + conn->ext.connect = null_conn_connect; + conn->ext.disconnect = null_conn_disconnect; + conn->ext.init_stmt = null_conn_init_stmt; + + return 0; +} + + + diff --git a/src/connector/odbc/src/base/null_conn.h b/src/connector/odbc/src/base/null_conn.h new file mode 100644 index 0000000000..9940cda584 --- /dev/null +++ b/src/connector/odbc/src/base/null_conn.h @@ -0,0 +1,33 @@ +/* + * 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 _null_conn_h_ +#define _null_conn_h_ + +#include "../base.h" + +#include "conn.h" + +typedef struct null_conn_s null_conn_t; +struct null_conn_s { + conn_t *conn; +}; + +int conn_init_null_conn(conn_t *conn); + + +#endif // _null_conn_h_ + + diff --git a/src/connector/odbc/src/base/param.c b/src/connector/odbc/src/base/param.c new file mode 100644 index 0000000000..59b2871f6e --- /dev/null +++ b/src/connector/odbc/src/base/param.c @@ -0,0 +1,89 @@ +/* + * 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 "param.h" + +static void paramset_clr_params(paramset_t *paramset) { + if (!paramset) return; + + paramset->params = NULL; + paramset->n_params = 0; + + paramset->i_row = 0; + paramset->i_col = 0; +} + +static void paramset_clr_bindings(paramset_t *paramset) { + if (!paramset) return; + + paramset->bindings = NULL; + paramset->n_bindings = 0; +} + +void paramset_reclaim_params(paramset_t *paramset) { + if (!paramset) return; + + if (!paramset->params_cache) return; + + todbc_buf_reclaim(paramset->params_cache); + paramset_clr_params(paramset); +} + +void paramset_reclaim_bindings(paramset_t *paramset) { + if (!paramset) return; + + if (!paramset->bindings_cache) return; + + todbc_buf_reclaim(paramset->bindings_cache); + paramset_clr_bindings(paramset); +} + +void paramset_init_params_cache(paramset_t *paramset) { + if (!paramset) return; + if (paramset->params_cache) return; + + OILE(paramset->params==NULL, ""); + OILE(paramset->n_params==0, ""); + + paramset->params_cache = todbc_buf_create(); +} + +void paramset_init_bindings_cache(paramset_t *paramset) { + if (!paramset) return; + if (paramset->bindings_cache) return; + + OILE(paramset->bindings==NULL, ""); + OILE(paramset->n_bindings==0, ""); + + paramset->bindings_cache = todbc_buf_create(); +} + +void paramset_release(paramset_t *paramset) { + if (!paramset) return; + + paramset_reclaim_params(paramset); + paramset_reclaim_bindings(paramset); + + if (paramset->params_cache) { + todbc_buf_free(paramset->params_cache); + paramset->params_cache = NULL; + } + + if (paramset->bindings_cache) { + todbc_buf_free(paramset->bindings_cache); + paramset->bindings_cache = NULL; + } +} + diff --git a/src/connector/odbc/src/base/param.h b/src/connector/odbc/src/base/param.h new file mode 100644 index 0000000000..6175add47b --- /dev/null +++ b/src/connector/odbc/src/base/param.h @@ -0,0 +1,71 @@ +/* + * 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 _param_h_ +#define _param_h_ + +#include "../base.h" + +typedef struct paramset_s paramset_t; +typedef struct param_binding_s param_binding_t; +typedef struct param_val_s param_val_t; + +// SQLDescribeParam +struct param_s { + SQLUSMALLINT ParameterNumber; + SQLSMALLINT DataType; // sql data type + SQLULEN ParameterSize; + SQLSMALLINT DecimalDigits; + SQLSMALLINT Nullable; +}; + +// SQLBindParameter +struct param_binding_s { + SQLUSMALLINT ParameterNumber; + SQLSMALLINT InputOutputType; + SQLSMALLINT ValueType; // sql c data type + SQLSMALLINT ParameterType; // sql data type + SQLULEN ColumnSize; + SQLSMALLINT DecimalDigits; + SQLPOINTER ParameterValuePtr; + SQLLEN BufferLength; + SQLLEN *StrLen_or_IndPtr; +}; + +struct paramset_s { + todbc_buf_t *params_cache; + param_t *params; + int n_params; + + todbc_buf_t *bindings_cache; + param_binding_t *bindings; + int n_bindings; + + int i_row; + int i_col; +}; + +void paramset_reclaim_params(paramset_t *paramset); +void paramset_reclaim_bindings(paramset_t *paramset); + +void paramset_init_params_cache(paramset_t *paramset); +void paramset_init_bindings_cache(paramset_t *paramset); + +void paramset_release(paramset_t *paramset); + +#endif // _param_h_ + + + diff --git a/src/connector/odbc/src/base/rs.c b/src/connector/odbc/src/base/rs.c new file mode 100644 index 0000000000..068cdec4fd --- /dev/null +++ b/src/connector/odbc/src/base/rs.c @@ -0,0 +1,18 @@ +/* + * 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 "rs.h" + + diff --git a/src/connector/odbc/src/base/rs.h b/src/connector/odbc/src/base/rs.h new file mode 100644 index 0000000000..6a7e0a2b3a --- /dev/null +++ b/src/connector/odbc/src/base/rs.h @@ -0,0 +1,29 @@ +/* + * 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 _rs_h_ +#define _rs_h_ + +#include "../base.h" + + +struct rs_s { + int affected_rows; +}; + + + +#endif // _rs_h_ + diff --git a/src/connector/odbc/src/base/stmt.c b/src/connector/odbc/src/base/stmt.c new file mode 100644 index 0000000000..2818b46ed2 --- /dev/null +++ b/src/connector/odbc/src/base/stmt.c @@ -0,0 +1,465 @@ +/* + * 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 "stmt.h" + +#include "conn.h" +#include "param.h" + +static int static_app_row; // SQL_ATTR_APP_ROW_DESC +static int static_app_param; // SQL_ATTR_APP_PARAM_DESC +static int static_imp_row; // SQL_ATTR_IMP_ROW_DESC +static int static_imp_param; // SQL_ATTR_IMP_PARAM_DESC + +static int stmt_init_descs(stmt_t *stmt) { + OILE(stmt, ""); + descs_t *descs = &stmt->descs; + + descs->app_row = &static_app_row; // SQL_ATTR_APP_ROW_DESC + descs->app_param = &static_app_param; // SQL_ATTR_APP_PARAM_DESC + descs->imp_row = &static_imp_row; // SQL_ATTR_IMP_ROW_DESC + descs->imp_param = &static_imp_param; // SQL_ATTR_IMP_PARAM_DESC + + return 0; +} + +static int stmt_init_sql(stmt_t *stmt) { + OILE(stmt, ""); + sql_t *sql = &stmt->sql; + OILE(sql->cache==NULL, ""); + OILE(sql->txt.buf==NULL, ""); + OILE(sql->txt.bytes==0, ""); + OILE(sql->txt.total_bytes==0, ""); + + sql->cache = todbc_buf_create(); + if (!sql->cache) return -1; + + return 0; +} + +static void stmt_release_sql(stmt_t *stmt) { + OILE(stmt, ""); + sql_t *sql = &stmt->sql; + if (!sql->cache) return; + todbc_buf_free(sql->cache); + sql->cache = NULL; + sql->txt.buf = NULL; + sql->txt.bytes = 0; + sql->txt.total_bytes = 0; +} + +static int stmt_init(stmt_t *stmt, conn_t *conn) { + OILE(stmt, ""); + OILE(conn, ""); + OILE(stmt->owner==NULL, ""); + + stmt->typeinfo = SQL_UNKNOWN_TYPE; + + int r = errs_init(&stmt->errs); + if (r) return -1; + + r = stmt_init_descs(stmt); + if (r) return -1; + + r = stmt_init_sql(stmt); + if (r) return -1; + + stmt->attr.bind_type = SQL_PARAM_BIND_BY_COLUMN; + + r = conn_add_stmt(conn, stmt); + OILE(r==0, ""); + OILE(stmt->owner && stmt->owner->conn==conn, ""); + + return 0; +} + +static void stmt_release(stmt_t *stmt) { + if (!stmt) return; + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + + conn_del_stmt(conn, stmt); + + paramset_release(&stmt->paramset); + fieldset_release(&stmt->fieldset); + stmt_release_sql(stmt); + errs_release(&stmt->errs); +} + +static SQLRETURN do_process_param(stmt_t *stmt) { + OILE(stmt->ext.proc_param, ""); + return stmt->ext.proc_param(stmt); +} + +static SQLRETURN do_process_param_row(stmt_t *stmt) { + paramset_t *paramset = &stmt->paramset; + int n_params = paramset->n_params; + + SQLRETURN r = SQL_SUCCESS; + + paramset->i_col = 0; + for (; paramset->i_coli_col) { + r = do_process_param(stmt); + if (r!=SQL_SUCCESS) return r; + } + + return SQL_SUCCESS; +} + +stmt_t* stmt_new(conn_t *conn) { + stmt_t *stmt = (stmt_t*)calloc(1, sizeof(*stmt)); + if (!stmt) return NULL; + + if (stmt_init(stmt, conn)) { + free(stmt); + return NULL; + } + + return stmt; +} + +void stmt_free(stmt_t *stmt) { + if (!stmt) return; + + // clean ext stuff + if (stmt->ext.free_stmt) { + stmt->ext.free_stmt(stmt); + stmt->ext.free_stmt = NULL; + } + + // clean stmt stuff + stmt_release(stmt); + + free(stmt); +} + +conn_t* stmt_get_conn(stmt_t *stmt) { + if (!stmt) return NULL; + if (!stmt->owner) return NULL; + + return stmt->owner->conn; +} + +void stmt_reclaim_params(stmt_t *stmt) { + if (!stmt) return; + paramset_reclaim_params(&stmt->paramset); +} + +void stmt_reclaim_param_bindings(stmt_t *stmt) { + if (!stmt) return; + paramset_reclaim_bindings(&stmt->paramset); +} + +void stmt_reclaim_field_bindings(stmt_t *stmt) { + if (!stmt) return; + fieldset_reclaim_bindings(&stmt->fieldset); +} + +void stmt_close_rs(stmt_t *stmt) { + if (!stmt) return; + + OILE(stmt->ext.close_rs, ""); + stmt->ext.close_rs(stmt); + + stmt->typeinfo = SQL_UNKNOWN_TYPE; + + stmt->eof = 0; + + fieldset_reclaim_fields(&stmt->fieldset); + // for the performance + // we don't reclaim field-binds here + // https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindcol-function?view=sql-server-ver15 + STMT_SET_NORM(stmt); +} + +void stmt_reset_params(stmt_t *stmt) { + if (!stmt) return; + + stmt->attr.paramset_size = 0; + stmt_reclaim_param_bindings(stmt); +} + +static SQLRETURN stmt_set_sql(stmt_t *stmt, todbc_string_t *txt) { + OILE(stmt, ""); + OILE(txt, ""); + errs_t *errs = &stmt->errs; + sql_t *sql = &stmt->sql; + + OILE(txt!=&sql->txt, ""); + + todbc_buf_t *cache = sql->cache; + OILE(sql->cache, ""); + + conn_t *conn = stmt_get_conn(stmt); + OILE(conn, ""); + const char *enc = conn->enc_db; + + todbc_buf_reclaim(cache); + + sql->txt = todbc_string_conv_to(txt, enc, cache); + if (!sql->txt.buf) { + SET_OOM(errs, ""); + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_stmt_prepare(stmt_t *stmt) { + OILE(stmt->ext.prepare, ""); + return stmt->ext.prepare(stmt); +} + +static void do_stmt_clear_param_vals(stmt_t *stmt) { + OILE(stmt->ext.clear_param_vals, ""); + stmt->ext.clear_param_vals(stmt); +} + +static void do_stmt_clear_params(stmt_t *stmt) { + stmt->prepared = 0; + paramset_t *paramset = &stmt->paramset; + paramset_reclaim_params(paramset); + do_stmt_clear_param_vals(stmt); +} + +SQLRETURN stmt_exec_direct(stmt_t *stmt, todbc_string_t *txt) { + OILE(stmt, ""); + OILE(txt, ""); + + SQLRETURN r = stmt_set_sql(stmt, txt); + if (r!=SQL_SUCCESS) return r; + + do_stmt_clear_params(stmt); + + if (stmt->ext.exec_direct) { + r = stmt->ext.exec_direct(stmt); + } else { + r = do_stmt_prepare(stmt); + if (r!=SQL_SUCCESS) return r; + stmt->prepared = 1; + OILE(0, ""); + } + + return r; +} + +SQLRETURN stmt_prepare(stmt_t *stmt, todbc_string_t *txt) { + OILE(stmt, ""); + OILE(txt, ""); + + SQLRETURN r = stmt_set_sql(stmt, txt); + if (r!=SQL_SUCCESS) return r; + + do_stmt_clear_params(stmt); + + r = do_stmt_prepare(stmt); + if (r!=SQL_SUCCESS) return r; + stmt->prepared = 1; + + return SQL_SUCCESS; +} + +SQLRETURN stmt_bind_param(stmt_t *stmt, param_binding_t *arg) { + OILE(stmt, ""); + OILE(arg, ""); + OILE(arg->ParameterNumber>0, ""); + int idx = arg->ParameterNumber - 1; + + errs_t *errs = &stmt->errs; + paramset_t *paramset = &stmt->paramset; + + paramset_init_bindings_cache(paramset); + if (!paramset->bindings_cache) { + SET_OOM(errs, "failed to alloc cache for param binds"); + return SQL_ERROR; + } + + todbc_buf_t *cache = paramset->bindings_cache; + OILE(cache, ""); + + param_binding_t *bindings = paramset->bindings; + if (idx>=paramset->n_bindings) { + size_t num = (size_t)(idx + 1); + // align + const size_t block = 10; + num = (num + block-1) / block * block; + bindings = (param_binding_t*)todbc_buf_realloc(cache, bindings, num * sizeof(*bindings)); + if (!bindings) { + SET_OOM(errs, "failed to realloc buf for param binds"); + return SQL_ERROR; + } + paramset->bindings = bindings; + paramset->n_bindings = idx + 1; + } + OILE(paramset->bindings, ""); + OILE(idxn_bindings, ""); + + param_binding_t *binding = bindings + idx; + *binding = *arg; + + if (paramset->n_bindings>paramset->n_params) return SQL_SUCCESS; + + OILE(stmt->ext.set_param_conv, ""); + return stmt->ext.set_param_conv(stmt, idx); +} + +SQLRETURN stmt_execute(stmt_t *stmt) { + OILE(stmt, ""); + OILE(!STMT_IS_EXECUTING(stmt), ""); + + SQLRETURN r = SQL_SUCCESS; + + if (stmt->prepared==0) { + do_stmt_clear_params(stmt); + + r = do_stmt_prepare(stmt); + if (r!=SQL_SUCCESS) return r; + stmt->prepared = 1; + } + OILE(stmt->prepared==1, ""); + + + errs_t *errs = &stmt->errs; + + paramset_t *paramset = &stmt->paramset; + int n_params = paramset->n_params; + int n_bindings = paramset->n_bindings; + + if (n_params>n_bindings) { + SET_GENERAL(errs, "parameters need to be bound first"); + return SQL_ERROR; + } + + if (n_params>0) { + int paramset_size = (int)stmt->attr.paramset_size; + if (paramset_size==0) paramset_size = 1; + stmt->attr.paramset_size = (SQLULEN)paramset_size; + + paramset->i_row = 0; + for (; paramset->i_rowi_row) { + r = do_process_param_row(stmt); + if (r) return r; + + OILE(stmt->ext.param_row_processed, ""); + r = stmt->ext.param_row_processed(stmt); + if (r) return r; + } + } + + OILE(stmt->ext.execute, ""); + return stmt->ext.execute(stmt); +} + +SQLRETURN stmt_fetch(stmt_t *stmt) { + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + if (stmt->eof) return SQL_NO_DATA; + + OILE(stmt->ext.fetch, ""); + SQLRETURN r = stmt->ext.fetch(stmt); + if (r!=SQL_SUCCESS) return r; + + fieldset_t *fieldset = &stmt->fieldset; + if (fieldset->n_bindings==0) return SQL_SUCCESS; + OILE(fieldset->n_bindings>0, ""); + + for (size_t i=0; in_bindings; ++i) { + OILE(fieldset->bindings, ""); + col_binding_t *binding = fieldset->bindings + i; + if (binding->ColumnNumber!=i+1) { + OILE(binding->ColumnNumber==0, ""); + continue; + } + OILE(stmt->ext.get_data, ""); + r = stmt->ext.get_data(stmt, binding); + if (r!=SQL_SUCCESS) return r; + } + + return SQL_SUCCESS; +} + +SQLRETURN stmt_get_data(stmt_t *stmt, col_binding_t *binding) { + OILE(stmt, ""); + OILE(STMT_IS_EXECUTED(stmt), ""); + + OILE(stmt->eof==0, ""); + + OILE(stmt->ext.get_data, ""); + return stmt->ext.get_data(stmt, binding); +} + +SQLRETURN stmt_bind_col(stmt_t *stmt, col_binding_t *binding) { + OILE(stmt, ""); + // shall we check execute state? + + errs_t *errs = &stmt->errs; + + fieldset_t *fieldset = &stmt->fieldset; + + todbc_buf_t *cache = fieldset->bindings_cache; + if (cache==NULL) { + fieldset_init_bindings(fieldset); + cache = fieldset->bindings_cache; + if (!cache) { + SET_OOM(errs, ""); + return SQL_ERROR; + } + } + OILE(cache, ""); + + col_binding_t *bindings = fieldset->bindings; + + OILE(binding->ColumnNumber>0, ""); + if (binding->ColumnNumber>=fieldset->n_bindings) { + size_t num = (size_t)binding->ColumnNumber; + const size_t block = 10; + size_t align = (num+block-1)/block*block; + size_t total = align * sizeof(*bindings); + bindings = (col_binding_t*)todbc_buf_realloc(cache, bindings, total); + if (!bindings) { + SET_OOM(errs, ""); + return SQL_ERROR; + } + for (size_t i = (size_t)fieldset->n_bindings; ibindings = bindings; + fieldset->n_bindings = (int)num; + } + OILE(bindings, ""); + OILE(binding->ColumnNumber<=fieldset->n_bindings, ""); + bindings[binding->ColumnNumber-1] = *binding; + + return SQL_SUCCESS; +} + + + + +// public +errs_t* stmt_get_errs(stmt_t *stmt) { + OILE(stmt, ""); + + return &stmt->errs; +} + +void stmt_clr_errs(stmt_t *stmt) { + if (!stmt) return; + + errs_reclaim(&stmt->errs); +} + diff --git a/src/connector/odbc/src/base/stmt.h b/src/connector/odbc/src/base/stmt.h new file mode 100644 index 0000000000..905cb6a003 --- /dev/null +++ b/src/connector/odbc/src/base/stmt.h @@ -0,0 +1,143 @@ +/* + * 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 _stmt_h_ +#define _stmt_h_ + +#include "../base.h" + +#include "err.h" +#include "field.h" +#include "param.h" +#include "rs.h" + +typedef struct descs_s descs_t; +typedef struct stmts_s stmts_t; +typedef struct stmt_ext_s stmt_ext_t; +typedef struct stmt_attr_s stmt_attr_t; +typedef struct sql_s sql_t; + +struct descs_s { + void *app_row; // SQL_ATTR_APP_ROW_DESC + void *app_param; // SQL_ATTR_APP_PARAM_DESC + void *imp_row; // SQL_ATTR_IMP_ROW_DESC + void *imp_param; // SQL_ATTR_IMP_PARAM_DESC +}; + +struct stmt_ext_s { + void *ext; + void (*free_stmt)(stmt_t *stmt); + + void (*clear_params)(stmt_t *stmt); + void (*clear_param_vals)(stmt_t *stmt); + + SQLRETURN (*get_param)(stmt_t *stmt, param_t *arg); + SQLRETURN (*set_param_conv)(stmt_t *stmt, int idx); + + SQLRETURN (*exec_direct)(stmt_t *stmt); + SQLRETURN (*prepare)(stmt_t *stmt); + SQLRETURN (*proc_param)(stmt_t *stmt); + SQLRETURN (*param_row_processed)(stmt_t *stmt); + SQLRETURN (*execute)(stmt_t *stmt); + SQLRETURN (*get_affected_rows)(stmt_t *stmt, SQLLEN *RowCount); + SQLRETURN (*get_fields_count)(stmt_t *stmt, SQLSMALLINT *ColumnCount); + SQLRETURN (*get_field)(stmt_t *stmt, field_arg_t *arg); + SQLRETURN (*fetch)(stmt_t *stmt); + SQLRETURN (*get_data)(stmt_t *stmt, col_binding_t *col); + void (*close_rs)(stmt_t *stmt); +}; + +struct stmt_attr_s { + // SQL_ATTR_PARAM_BIND_TYPE: SQL_PARAM_BIND_BY_COLUMN or row size + SQLULEN bind_type; // default: SQL_PARAM_BIND_BY_COLUMN + // SQL_ATTR_PARAM_BIND_OFFSET_PTR + SQLULEN *bind_offset_ptr; // default: NULL + // SQL_ATTR_PARAMSET_SIZE + SQLULEN paramset_size; // default: 0 +}; + +struct sql_s { + todbc_buf_t *cache; + todbc_string_t txt; +}; + +struct stmt_s { + stmts_t *owner; + stmt_t *next; + stmt_t *prev; + + SQLSMALLINT typeinfo; + + descs_t descs; + + sql_t sql; + + stmt_attr_t attr; + + paramset_t paramset; + fieldset_t fieldset; + + int affected_rows; + rs_t rs; + + errs_t errs; + + stmt_ext_t ext; + + unsigned int prepared:1; + unsigned int execute:2; + unsigned int eof:1; +}; + +struct stmts_s { + conn_t *conn; + + int count; + stmt_t *head; + stmt_t *tail; +}; + +#define STMT_TYPEINFO(stmt) (stmt->typeinfo!=SQL_UNKNOWN_TYPE) + +#define STMT_SET_EXECUTING(stmt) (stmt->execute=0x01) +#define STMT_SET_EXECUTED(stmt) (stmt->execute=0x02) +#define STMT_SET_NORM(stmt) (stmt->execute=0x00) + +#define STMT_IS_EXECUTING(stmt) (stmt->execute==0x01) +#define STMT_IS_EXECUTED(stmt) (stmt->execute==0x02) +#define STMT_IS_NORM(stmt) (stmt->execute==0x00) + +stmt_t* stmt_new(conn_t *conn); +void stmt_free(stmt_t *stmt); + +conn_t* stmt_get_conn(stmt_t *stmt); + +void stmt_reclaim_params(stmt_t *stmt); +void stmt_reclaim_param_binds(stmt_t *stmt); +void stmt_reclaim_field_binds(stmt_t *stmt); +void stmt_close_rs(stmt_t *stmt); +void stmt_reset_params(stmt_t *stmt); +SQLRETURN stmt_exec_direct(stmt_t *stmt, todbc_string_t *txt); +SQLRETURN stmt_prepare(stmt_t *stmt, todbc_string_t *txt); +SQLRETURN stmt_bind_param(stmt_t *stmt, param_binding_t *arg); +SQLRETURN stmt_execute(stmt_t *stmt); +SQLRETURN stmt_fetch(stmt_t *stmt); +SQLRETURN stmt_get_data(stmt_t *stmt, col_binding_t *binding); +SQLRETURN stmt_bind_col(stmt_t *stmt, col_binding_t *binding); + +#endif // _stmt_h_ + + + diff --git a/src/connector/odbc/src/base/tsdb_impl.c b/src/connector/odbc/src/base/tsdb_impl.c new file mode 100644 index 0000000000..d913aebd7d --- /dev/null +++ b/src/connector/odbc/src/base/tsdb_impl.c @@ -0,0 +1,2598 @@ +/* + * 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 "tsdb_impl.h" + +#include "env.h" +#include "../todbc_tls.h" +#include "../todbc_util.h" + +#include "ttype.h" + + +#include + +// tsdb_conn + +typedef struct tsdb_conn_s tsdb_conn_t; +typedef struct tsdb_stmt_s tsdb_stmt_t; +typedef struct tsdb_param_s tsdb_param_t; +typedef struct tsdb_param_val_s tsdb_param_val_t; +typedef struct tsdb_param_conv_arg_s tsdb_param_conv_arg_t; + +struct tsdb_conn_s { + conn_t *conn; + + char svr_info[64]; + char cli_info[64]; + + TAOS *taos; +}; + +struct tsdb_param_s { + int tsdb_type; // TSDB_DATA_TYPE_xxx + int tsdb_bytes; + + SQLRETURN (*conv)(stmt_t *stmt, tsdb_param_conv_arg_t *arg); +}; + +struct tsdb_param_val_s { + SQLUSMALLINT ParameterNumber; + int is_null; +}; + +struct tsdb_stmt_s { + stmt_t *stmt; + + TAOS_STMT *tsdb_stmt; // prepared-statement + TAOS_RES *tsdb_res; + + tsdb_param_t *tsdb_params; + + todbc_buf_t *tsdb_param_vals_cache; + tsdb_param_val_t *tsdb_param_vals; + TAOS_BIND *taos_binds; + + TAOS_FIELD *tsdb_fields; + TAOS_ROW tsdb_curr; + + unsigned int by_query:1; +}; + +struct tsdb_param_conv_arg_s { + conn_t *conn; + todbc_buf_t *cache; + int idx; + SQLPOINTER val; + SQLLEN soi; + tsdb_param_t *tsdb_param; + tsdb_param_val_t *tsdb_param_val; + TAOS_BIND *taos_bind; +}; + +static void tsdb_stmt_init_param_vals_cache(tsdb_stmt_t *tsdb_stmt) { + OILE(tsdb_stmt, ""); + if (tsdb_stmt->tsdb_param_vals_cache) return; + tsdb_stmt->tsdb_param_vals_cache = todbc_buf_create(); +} + +static void tsdb_stmt_reclaim_param_vals(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt) return; + if (tsdb_stmt->tsdb_param_vals_cache) { + tsdb_stmt->tsdb_param_vals = NULL; + tsdb_stmt->taos_binds = NULL; + todbc_buf_reclaim(tsdb_stmt->tsdb_param_vals_cache); + } + OILE(tsdb_stmt->tsdb_param_vals==NULL, ""); + OILE(tsdb_stmt->taos_binds==NULL, ""); +} + +static void tsdb_stmt_cleanup_param_vals(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt) return; + tsdb_stmt_reclaim_param_vals(tsdb_stmt); + + if (tsdb_stmt->tsdb_param_vals_cache) { + todbc_buf_free(tsdb_stmt->tsdb_param_vals_cache); + } +} + +static void tsdb_stmt_calloc_param_vals(tsdb_stmt_t *tsdb_stmt) { + OILE(tsdb_stmt, ""); + stmt_t *stmt = tsdb_stmt->stmt; + OILE(stmt, ""); + paramset_t *paramset = &stmt->paramset; + int n_params = paramset->n_params; + OILE(n_params>0, ""); + todbc_buf_t *cache = tsdb_stmt->tsdb_param_vals_cache; + OILE(cache, ""); + OILE(tsdb_stmt->tsdb_param_vals==NULL, ""); + OILE(tsdb_stmt->taos_binds==NULL, ""); + tsdb_stmt->tsdb_param_vals = (tsdb_param_val_t*)todbc_buf_calloc(cache, (size_t)n_params, sizeof(*tsdb_stmt->tsdb_param_vals)); + tsdb_stmt->taos_binds = (TAOS_BIND*)todbc_buf_calloc(cache, (size_t)n_params, sizeof(*tsdb_stmt->taos_binds)); +} + +static SQLRETURN tsdb_stmt_init_stmt(tsdb_stmt_t *tsdb_stmt) { + OILE(tsdb_stmt && tsdb_stmt->stmt, ""); + errs_t *errs = &tsdb_stmt->stmt->errs; + + if (tsdb_stmt->tsdb_stmt) return SQL_SUCCESS; + OILE(tsdb_stmt->stmt->owner, ""); + conn_t *conn = tsdb_stmt->stmt->owner->conn; + OILE(conn, ""); + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn && tsdb_conn->taos, ""); + tsdb_stmt->tsdb_stmt = taos_stmt_init(tsdb_conn->taos); + if (!tsdb_stmt->tsdb_stmt) { + SET_GENERAL(errs, "failed to init taos stmt"); + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +static void tsdb_stmt_close_stmt(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt) return; + if (!tsdb_stmt->tsdb_stmt) return; + + int r = taos_stmt_close(tsdb_stmt->tsdb_stmt); + tsdb_stmt->tsdb_stmt= NULL; + tsdb_stmt->stmt->prepared = 0; + if (r) OD("[%d]%s", r, tstrerror(r)); +} + +static void tsdb_stmt_close_rs(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt) return; + if (!tsdb_stmt->tsdb_res) return; + + tsdb_stmt->tsdb_curr = NULL; + + if (tsdb_stmt->by_query) { + taos_stop_query(tsdb_stmt->tsdb_res); + } else { + OILE(tsdb_stmt->tsdb_stmt==NULL, ""); + taos_free_result(tsdb_stmt->tsdb_res); + } + tsdb_stmt->tsdb_res = NULL; +} + +static void tsdb_conn_free(conn_t *conn) { + OILE(conn, ""); + + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn, ""); + OILE(tsdb_conn->taos==NULL, ""); + + conn->ext.ext = NULL; + conn->ext.free_conn = NULL; + + free(tsdb_conn); +} + +static SQLRETURN tsdb_conn_connect(conn_t *conn) { + OILE(conn, ""); + OILE(CONN_IS_NORM(conn), ""); + errs_t *errs = &conn->errs; + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn, ""); + OILE(tsdb_conn->conn==conn, ""); + + conn_val_t *val = &conn->val; + const char *dsn = val->dsn; + const char *uid = val->uid; + const char *pwd = val->pwd; + const char *db = val->db; + const char *svr = val->server; + + OILE(dsn, ""); + + int use_default = 0; + char server[4096]; server[0] = '\0'; + if (!svr || !svr[0]) { + int n = SQLGetPrivateProfileString(dsn, "Server", "", server, sizeof(server)-1, "Odbc.ini"); + if (n<=0) { + snprintf(server, sizeof(server), DEFAULT_SERVER); + n = (int)strlen(server); + use_default = 1; + } else { + server[n] = '\0'; + } + svr = server; + + if (!svr || !svr[0]) { + SET_GENERAL(errs, "please specify Server entry in connection string or odbc.ini or windows registry for DSN:[%s]", dsn); + return SQL_ERROR; + } + } + + char *ip = NULL; + int port = 0; + char *p = strchr(svr, ':'); + if (p) { + ip = todbc_tls_strndup(svr, (size_t)(p-svr)); + port = atoi(p+1); + } + + tsdb_conn->taos = taos_connect(ip, uid, pwd, db, (uint16_t)port); + if (!tsdb_conn->taos) { + int e = terrno; + const char * es = tstrerror(e); + if (use_default) { + SET_GENERAL(errs, "no Server entry in odbc.ini or windows registry for DSN[%s], fallback to svr[%s:%d] db[%s]", dsn, ip, port, db); + } + SET_GENERAL(errs, "connect to DSN[%s] svr[%s:%d] db[%s] failed", dsn, ip, port, db); + SET_GENERAL(errs, "[%x]%s", e, es); + return SQL_ERROR; + } + + const char *svr_info = taos_get_server_info(tsdb_conn->taos); + const char *cli_info = taos_get_client_info(tsdb_conn->taos); + snprintf(tsdb_conn->svr_info, sizeof(tsdb_conn->svr_info), "%s", svr_info); + snprintf(tsdb_conn->cli_info, sizeof(tsdb_conn->cli_info), "%s", cli_info); + + return SQL_SUCCESS; +} + +static void tsdb_conn_disconnect(conn_t *conn) { + OILE(conn, ""); + OILE(CONN_IS_CONNECTED(conn), ""); + + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn, ""); + OILE(tsdb_conn->conn==conn, ""); + + TAOS *taos = tsdb_conn->taos; + + if (!taos) return; + taos_close(taos); + taos = NULL; + tsdb_conn->taos = NULL; +} + +static void tsdb_conn_free_stmt(stmt_t *stmt) { + OILE(stmt, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + + tsdb_stmt_close_rs(tsdb_stmt); + tsdb_stmt_close_stmt(tsdb_stmt); + tsdb_stmt_cleanup_param_vals(tsdb_stmt); + + tsdb_stmt->tsdb_params = NULL; + + stmt_ext_t ext = {0}; + stmt->ext = ext; + + free(tsdb_stmt); +} + +static void tsdb_conn_clear_param_vals(stmt_t *stmt) { + OILE(stmt, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + + tsdb_stmt_reclaim_param_vals(tsdb_stmt); +} + +static SQLRETURN tsdb_conn_exec_direct(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(!STMT_IS_EXECUTED(stmt), ""); + + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn && tsdb_conn->conn==conn, ""); + TAOS *taos = tsdb_conn->taos; + OILE(taos, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + OILE(tsdb_stmt->tsdb_stmt==NULL, ""); + OILE(tsdb_stmt->tsdb_res==NULL, ""); + + errs_t *errs = &stmt->errs; + + tsdb_stmt_reclaim_param_vals(tsdb_stmt); + + const char *txt = (const char*)stmt->sql.txt.buf; + TAOS_RES *tsdb_res = taos_query(taos, txt); + OILE(tsdb_res, ""); + int r = taos_errno(tsdb_res); + if (r) { + SET_GENERAL(errs, "taos query failed:[%d]%s", r, tstrerror(r)); + taos_stop_query(tsdb_res); + STMT_SET_NORM(stmt); + return SQL_ERROR; + } + + tsdb_stmt->tsdb_res = tsdb_res; + tsdb_stmt->by_query = 1; + + STMT_SET_EXECUTED(stmt); + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_tsdb_timestamp(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + taos_bind->u.ts = v; + taos_bind->buffer_length = sizeof(taos_bind->u.ts); + taos_bind->buffer = &taos_bind->u.ts; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_tsdb_tinyint(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + errs_t *errs = &stmt->errs; + + if (vINT8_MAX) { + SET_GENERAL(errs, "integer overflow for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_TINYINT; + taos_bind->u.v1 = (int8_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v1); + taos_bind->buffer = &taos_bind->u.v1; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_tsdb_smallint(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + errs_t *errs = &stmt->errs; + + if (vINT16_MAX) { + SET_GENERAL(errs, "integer overflow for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_SMALLINT; + taos_bind->u.v2 = (int16_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v2); + taos_bind->buffer = &taos_bind->u.v2; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_tsdb_int(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + errs_t *errs = &stmt->errs; + + if (vINT32_MAX) { + SET_GENERAL(errs, "integer overflow for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_INT; + taos_bind->u.v4 = (int32_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v4); + taos_bind->buffer = &taos_bind->u.v4; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_tsdb_bigint(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_BIGINT; + taos_bind->u.v8 = v; + taos_bind->buffer_length = sizeof(taos_bind->u.v8); + taos_bind->buffer = &taos_bind->u.v8; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_double_to_tsdb_float(stmt_t *stmt, const double v, tsdb_param_conv_arg_t *arg) { + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_FLOAT; + taos_bind->u.f4 = (float)v; + taos_bind->buffer_length = sizeof(taos_bind->u.f4); + taos_bind->buffer = &taos_bind->u.f4; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_double_to_tsdb_double(stmt_t *stmt, const double v, tsdb_param_conv_arg_t *arg) { + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_DOUBLE; + taos_bind->u.f8 = v; + taos_bind->buffer_length = sizeof(taos_bind->u.f8); + taos_bind->buffer = &taos_bind->u.f8; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + + +static SQLRETURN do_conv_sql_string_to_int64(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg, int64_t *v) { + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt.buf; + int bytes = 0; + int64_t i64 = 0; + sscanf(buf, "%" PRId64 " %n", &i64, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + *v = i64; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_double(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg, double *v) { + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt.buf; + int bytes = 0; + double dbl = 0.0; + sscanf(buf, "%lf%n", &dbl, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to double for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + *v = dbl; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_timestamp(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + char *buf = (char*)txt.buf; + int32_t bytes = (int32_t)txt.bytes; + + int64_t ts = 0; + int r = taosParseTime(buf, &ts, bytes, TSDB_TIME_PRECISION_MILLI, 0); + if (r) { + SET_GENERAL(errs, "failed to parse as timestamp for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + taos_bind->u.ts = ts; + taos_bind->buffer_length = sizeof(taos_bind->u.ts); + taos_bind->buffer = &taos_bind->u.ts; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_nchar(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_db; + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + char *buf = (char*)txt_db.buf; + int32_t bytes = (int32_t)txt_db.bytes; + if (bytes > arg->tsdb_param->tsdb_bytes) { + SET_OOM(errs, "failed to convert from [%s->%s] for param [%d], string too long [%d/%d]", + enc_from, enc_to, arg->idx+1, bytes, arg->tsdb_param->tsdb_bytes); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_NCHAR; + taos_bind->u.nchar = buf; + taos_bind->buffer_length = (uintptr_t)((size_t)bytes); + taos_bind->buffer = taos_bind->u.nchar; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_bool(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + int64_t v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + if (strcasecmp(buf, "true")==0) { + v = 1; + } else if (strcasecmp(buf, "false")==0) { + v = 0; + } else { + sscanf(buf, "%" PRId64 " %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_BOOL; + taos_bind->u.b = v ? 1 : 0; + taos_bind->buffer_length = sizeof(taos_bind->u.b); + taos_bind->buffer = &taos_bind->u.b; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_tinyint(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + int64_t v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%" PRId64 " %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + if (vINT8_MAX) { + SET_GENERAL(errs, "failed to convert to tinyint for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_TINYINT; + taos_bind->u.v1 = (int8_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v1); + taos_bind->buffer = &taos_bind->u.v1; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_smallint(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + int64_t v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%" PRId64 " %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + if (vINT16_MAX) { + SET_GENERAL(errs, "failed to convert to smallint for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_SMALLINT; + taos_bind->u.v2 = (int16_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v2); + taos_bind->buffer = &taos_bind->u.v2; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_int(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + int64_t v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%" PRId64 " %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + if (vINT32_MAX) { + SET_GENERAL(errs, "failed to convert to int for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_INT; + taos_bind->u.v4 = (int32_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v4); + taos_bind->buffer = &taos_bind->u.v4; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_bigint(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + int64_t v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%" PRId64 " %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_BIGINT; + taos_bind->u.v8 = (int64_t)v; + taos_bind->buffer_length = sizeof(taos_bind->u.v8); + taos_bind->buffer = &taos_bind->u.v8; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_float(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + double v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%lf %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_FLOAT; + taos_bind->u.f4 = (float)v; + taos_bind->buffer_length = sizeof(taos_bind->u.f4); + taos_bind->buffer = &taos_bind->u.f4; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_string_to_tsdb_double(stmt_t *stmt, const char *enc_from, tsdb_param_conv_arg_t *arg) { + double v = 0; + + todbc_buf_t *cache = arg->cache; + const char *enc_to = arg->conn->enc_src; // ?locale or src?, windows iconv!!! + const unsigned char *src = (const unsigned char*)arg->val; + size_t slen = (size_t)arg->soi; + + errs_t *errs = &stmt->errs; + + todbc_string_t txt_db = todbc_tls_conv(cache, enc_to, enc_from, src, &slen); + if (!txt_db.buf) { + SET_OOM(errs, "failed to alloc space to convert from [%s->%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + if (txt_db.bytes%s] for param [%d]", enc_from, enc_to, arg->idx+1); + return SQL_ERROR; + } + + const char *buf = (const char*)txt_db.buf; + int bytes = 0; + sscanf(buf, "%lf %n", &v, &bytes); + if (strlen(buf)!=bytes) { + SET_GENERAL(errs, "failed to convert to integer for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_DOUBLE; + taos_bind->u.f8 = v; + taos_bind->buffer_length = sizeof(taos_bind->u.f8); + taos_bind->buffer = &taos_bind->u.f8; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_timestamp(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + return do_conv_sql_string_to_tsdb_timestamp(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_nchar(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + return do_conv_sql_string_to_tsdb_nchar(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_bool(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + return do_conv_sql_string_to_tsdb_bool(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + int64_t v = 0; + SQLRETURN r = do_conv_sql_string_to_int64(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_int64_to_tsdb_tinyint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_smallint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + int64_t v = 0; + SQLRETURN r = do_conv_sql_string_to_int64(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_int64_to_tsdb_smallint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + int64_t v = 0; + SQLRETURN r = do_conv_sql_string_to_int64(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_int64_to_tsdb_int(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + int64_t v = 0; + SQLRETURN r = do_conv_sql_string_to_int64(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_int64_to_tsdb_bigint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_float(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + double v = 0; + SQLRETURN r = do_conv_sql_string_to_double(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_double_to_tsdb_float(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_wchar_to_tsdb_double(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_wchar; + double v = 0; + SQLRETURN r = do_conv_sql_string_to_double(stmt, enc_from, arg, &v); + if (r!=SQL_SUCCESS) return r; + return do_conv_double_to_tsdb_double(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_timestamp(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_timestamp(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_nchar(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_nchar(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_bool(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_bool(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_tinyint(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_smallint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_smallint(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_int(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_bigint(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_float(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_float(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_sql_char_to_tsdb_double(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + const char *enc_from = arg->conn->enc_char; + return do_conv_sql_string_to_tsdb_double(stmt, enc_from, arg); +} + +static SQLRETURN do_conv_int64_to_tsdb_bool(stmt_t *stmt, const int64_t v, tsdb_param_conv_arg_t *arg) { + errs_t *errs = &stmt->errs; + + if (v!=1 && v!=0) { + SET_GENERAL(errs, "integer overflow for param [%d]", arg->idx+1); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_BOOL; + taos_bind->u.b = v ? 1 : 0; + taos_bind->buffer_length = sizeof(taos_bind->u.b); + taos_bind->buffer = &taos_bind->u.b; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_sql_sbigint_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int64_t v = *(int64_t*)arg->val; + + return do_conv_int64_to_tsdb_bigint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_sbigint_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int64_t v = *(int64_t*)arg->val; + + return do_conv_int64_to_tsdb_tinyint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_sbigint_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int64_t v = *(int64_t*)arg->val; + + return do_conv_int64_to_tsdb_int(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_sbigint_to_tsdb_timestamp(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int64_t v = *(int64_t*)arg->val; + + return do_conv_int64_to_tsdb_timestamp(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_long_to_tsdb_bool(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int32_t v = *(int32_t*)arg->val; + + return do_conv_int64_to_tsdb_bool(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_long_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int32_t v = *(int32_t*)arg->val; + + return do_conv_int64_to_tsdb_tinyint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_long_to_tsdb_smallint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int32_t v = *(int32_t*)arg->val; + + return do_conv_int64_to_tsdb_smallint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_long_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int32_t v = *(int32_t*)arg->val; + + return do_conv_int64_to_tsdb_int(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_long_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int32_t v = *(int32_t*)arg->val; + + return do_conv_int64_to_tsdb_bigint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_tinyint_to_tsdb_bool(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int8_t v = *(int8_t*)arg->val; + + return do_conv_int64_to_tsdb_bool(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_tinyint_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int8_t v = *(int8_t*)arg->val; + + return do_conv_int64_to_tsdb_tinyint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_tinyint_to_tsdb_smallint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int8_t v = *(int8_t*)arg->val; + + return do_conv_int64_to_tsdb_smallint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_tinyint_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int8_t v = *(int8_t*)arg->val; + + return do_conv_int64_to_tsdb_int(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_tinyint_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int8_t v = *(int8_t*)arg->val; + + return do_conv_int64_to_tsdb_bigint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_short_to_tsdb_bool(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int16_t v = *(int16_t*)arg->val; + + return do_conv_int64_to_tsdb_bool(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_short_to_tsdb_tinyint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int16_t v = *(int16_t*)arg->val; + + return do_conv_int64_to_tsdb_tinyint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_short_to_tsdb_smallint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int16_t v = *(int16_t*)arg->val; + + return do_conv_int64_to_tsdb_smallint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_short_to_tsdb_int(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int16_t v = *(int16_t*)arg->val; + + return do_conv_int64_to_tsdb_int(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_short_to_tsdb_bigint(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + int16_t v = *(int16_t*)arg->val; + + return do_conv_int64_to_tsdb_bigint(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_double_to_tsdb_float(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + double v = *(double*)arg->val; + + return do_conv_double_to_tsdb_float(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_double_to_tsdb_double(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + double v = *(double*)arg->val; + + return do_conv_double_to_tsdb_double(stmt, v, arg); +} + +static SQLRETURN do_conv_sql_binary_to_tsdb_binary(stmt_t *stmt, tsdb_param_conv_arg_t *arg) { + unsigned char *buf = (unsigned char*)arg->val; + size_t len = (size_t)arg->soi; + OILE(len>0, ""); + + errs_t *errs = &stmt->errs; + + if (len > arg->tsdb_param->tsdb_bytes) { + SET_OOM(errs, "failed to convert binary for param [%d], binary too long [%zd/%d]", arg->idx+1, len, arg->tsdb_param->tsdb_bytes); + return SQL_ERROR; + } + + tsdb_param_val_t *tsdb_param_val = arg->tsdb_param_val; + TAOS_BIND *taos_bind = arg->taos_bind; + + taos_bind->buffer_type = TSDB_DATA_TYPE_BINARY; + taos_bind->u.bin = buf; + taos_bind->buffer_length = len; + taos_bind->buffer = taos_bind->u.bin; + taos_bind->length = &taos_bind->buffer_length; + taos_bind->is_null = &tsdb_param_val->is_null; + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_wchar_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_TIMESTAMP: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_timestamp; + } break; + case TSDB_DATA_TYPE_NCHAR: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_nchar; + } break; + case TSDB_DATA_TYPE_BOOL: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_bool; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_smallint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_bigint; + } break; + case TSDB_DATA_TYPE_FLOAT: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_float; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + tsdb_param->conv = do_conv_sql_wchar_to_tsdb_double; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_char_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_TIMESTAMP: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_timestamp; + } break; + case TSDB_DATA_TYPE_NCHAR: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_nchar; + } break; + case TSDB_DATA_TYPE_BOOL: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_bool; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_smallint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_bigint; + } break; + case TSDB_DATA_TYPE_FLOAT: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_float; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + tsdb_param->conv = do_conv_sql_char_to_tsdb_double; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_sbigint_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_sbigint_to_tsdb_bigint; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_sbigint_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_sbigint_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_TIMESTAMP: + { + tsdb_param->conv = do_conv_sql_sbigint_to_tsdb_timestamp; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_long_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_BOOL: + { + tsdb_param->conv = do_conv_sql_long_to_tsdb_bool; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_long_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + tsdb_param->conv = do_conv_sql_long_to_tsdb_smallint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_long_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_long_to_tsdb_bigint; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_tinyint_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_BOOL: + { + tsdb_param->conv = do_conv_sql_tinyint_to_tsdb_bool; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_tinyint_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + tsdb_param->conv = do_conv_sql_tinyint_to_tsdb_smallint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_tinyint_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_tinyint_to_tsdb_bigint; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_short_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_BOOL: + { + tsdb_param->conv = do_conv_sql_short_to_tsdb_bool; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + tsdb_param->conv = do_conv_sql_short_to_tsdb_tinyint; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + tsdb_param->conv = do_conv_sql_short_to_tsdb_smallint; + } break; + case TSDB_DATA_TYPE_INT: + { + tsdb_param->conv = do_conv_sql_short_to_tsdb_int; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + tsdb_param->conv = do_conv_sql_short_to_tsdb_bigint; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_double_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_FLOAT: + { + tsdb_param->conv = do_conv_sql_double_to_tsdb_float; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + tsdb_param->conv = do_conv_sql_double_to_tsdb_double; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_set_param_binary_conv_func(stmt_t *stmt, int idx, param_binding_t *binding, tsdb_param_t *tsdb_param) { + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + int tsdb_type = tsdb_param->tsdb_type; + + switch (tsdb_type) + { + case TSDB_DATA_TYPE_BINARY: + { + tsdb_param->conv = do_conv_sql_binary_to_tsdb_binary; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for param [%d]", + valueType, sql_c_type(valueType), + tsdb_type, taos_data_type(tsdb_type), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + + +static SQLRETURN do_set_param_conv_func(stmt_t *stmt, int idx, param_binding_t *binding) { + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + tsdb_param_t *tsdb_params = tsdb_stmt->tsdb_params; + tsdb_param_t *tsdb_param = tsdb_params + idx; + + errs_t *errs = &stmt->errs; + + SQLSMALLINT valueType = binding->ValueType; + + switch (valueType) + { + case SQL_C_CHAR: + { + return do_set_param_char_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_WCHAR: + { + return do_set_param_wchar_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_SBIGINT: + { + return do_set_param_sbigint_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_LONG: + { + return do_set_param_long_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_TINYINT: + { + return do_set_param_tinyint_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_SHORT: + { + return do_set_param_short_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_DOUBLE: + { + return do_set_param_double_conv_func(stmt, idx, binding, tsdb_param); + } break; + case SQL_C_BINARY: + { + return do_set_param_binary_conv_func(stmt, idx, binding, tsdb_param); + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s for param [%d]", + valueType, sql_c_type(valueType), idx+1); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN tsdb_conn_set_param_conv(stmt_t *stmt, int idx) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + OILE(tsdb_stmt->tsdb_res==NULL, ""); + OILE(idx>=0, ""); + + paramset_t *paramset = &stmt->paramset; + param_t *params = paramset->params; + if (!params || idx>=paramset->n_params) return SQL_SUCCESS; + param_binding_t *bindings = paramset->bindings; + if (!bindings || idx>=paramset->n_bindings) return SQL_SUCCESS; + tsdb_param_t *tsdb_params = tsdb_stmt->tsdb_params; + OILE(tsdb_params, ""); + + param_binding_t *binding = bindings + idx; + + return do_set_param_conv_func(stmt, idx, binding); +} + +static SQLRETURN do_fill_param(stmt_t *stmt, int idx) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + OILE(tsdb_stmt->tsdb_res==NULL, ""); + + paramset_t *paramset = &stmt->paramset; + param_t *params = paramset->params; + tsdb_param_t *tsdb_params = tsdb_stmt->tsdb_params; + OILE(params, ""); + OILE(tsdb_params, ""); + OILE(idx>=0, ""); + OILE(idxn_params, ""); + param_t *param = params + idx; + tsdb_param_t *tsdb_param = tsdb_params + idx; + + errs_t *errs = &stmt->errs; + + int tsdb_type = 0; + int tsdb_bytes = 0; + int r = taos_stmt_get_param(tsdb_stmt->tsdb_stmt, idx, &tsdb_type, &tsdb_bytes); + if (r) { + SET_GENERAL(errs, "failed to get param[%d]", idx+1); + return SQL_ERROR; + } + + // https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/column-size-decimal-digits-transfer-octet-length-and-display-size?view=sql-server-ver15 + param->DecimalDigits = 0; + param->Nullable = SQL_NULLABLE; + tsdb_param->tsdb_type = tsdb_type; + tsdb_param->tsdb_bytes = tsdb_bytes; + switch (tsdb_type) + { + case TSDB_DATA_TYPE_TIMESTAMP: + { + param->DataType = SQL_CHAR; + param->ParameterSize = 23; + } break; + case TSDB_DATA_TYPE_NCHAR: + { + size_t bytes = ((size_t)tsdb_bytes - VARSTR_HEADER_SIZE); + size_t chars = bytes / TSDB_NCHAR_SIZE; + tsdb_param->tsdb_bytes = (int)bytes; + param->DataType = SQL_WCHAR; + param->ParameterSize = (SQLULEN)chars; + } break; + case TSDB_DATA_TYPE_BINARY: + { + size_t bytes = ((size_t)tsdb_bytes - VARSTR_HEADER_SIZE); + tsdb_param->tsdb_bytes = (int)bytes; + param->DataType = SQL_BINARY; + param->ParameterSize = (SQLULEN)bytes; + } break; + case TSDB_DATA_TYPE_BOOL: + { + param->DataType = SQL_BIT; + param->ParameterSize = 1; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + param->DataType = SQL_TINYINT; + param->ParameterSize = 3; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + param->DataType = SQL_SMALLINT; + param->ParameterSize = 5; + } break; + case TSDB_DATA_TYPE_INT: + { + param->DataType = SQL_INTEGER; + param->ParameterSize = 10; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + param->DataType = SQL_BIGINT; + param->ParameterSize = 20; + } break; + case TSDB_DATA_TYPE_FLOAT: + { + param->DataType = SQL_FLOAT; + param->ParameterSize = 15; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + param->DataType = SQL_DOUBLE; + param->ParameterSize = 15; + } break; + default: + { + SET_GENERAL(errs, "failed to map param[%d] type[%d]%s to SQL DATA TYPE", + idx+1, tsdb_type, taos_data_type(tsdb_type)); + return SQL_ERROR; + } break; + } + + param->ParameterNumber = (SQLUSMALLINT)(idx + 1); + + param_binding_t *bindings = paramset->bindings; + if (!bindings) return SQL_SUCCESS; + if (idx>=paramset->n_bindings) return SQL_SUCCESS; + + param_binding_t *binding = bindings + idx; + + return do_set_param_conv_func(stmt, idx, binding); +} + +static SQLRETURN tsdb_conn_prepare(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(stmt->prepared==0, ""); + OILE(STMT_IS_NORM(stmt), ""); + errs_t *errs = &stmt->errs; + + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)conn->ext.ext; + OILE(tsdb_conn && tsdb_conn->conn==conn, ""); + TAOS *taos = tsdb_conn->taos; + OILE(taos, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + OILE(tsdb_stmt->tsdb_res==NULL, ""); + // OILE(tsdb_stmt->tsdb_stmt==NULL, ""); + + tsdb_stmt->tsdb_params = NULL; + + if (!tsdb_stmt->tsdb_stmt) { + SQLRETURN r = tsdb_stmt_init_stmt(tsdb_stmt); + if (r!=SQL_SUCCESS) return r; + } + OILE(tsdb_stmt->tsdb_stmt, ""); + + tsdb_stmt_reclaim_param_vals(tsdb_stmt); + + do { + const char *txt = (const char*)stmt->sql.txt.buf; + size_t len = stmt->sql.txt.bytes; + OILE(txt, ""); + OILE(len>0, ""); + int r = taos_stmt_prepare(tsdb_stmt->tsdb_stmt, txt, (unsigned int)len); + if (r) { + SET_GENERAL(errs, "failed to prepare taos stmt:[%d]%s", r, tstrerror(r)); + break; + } + + int nums = 0; + r = taos_stmt_num_params(tsdb_stmt->tsdb_stmt, &nums); + if (r) { + SET_GENERAL(errs, "failed to prepare taos stmt:[%d]%s", r, tstrerror(r)); + break; + } + + paramset_t *paramset = &stmt->paramset; + OILE(paramset->params==NULL, ""); + OILE(paramset->n_params==0, ""); + OILE(tsdb_stmt->tsdb_params==NULL, ""); + + if (nums>0) { + paramset_init_params_cache(paramset); + tsdb_stmt_init_param_vals_cache(tsdb_stmt); + + if (!tsdb_stmt->tsdb_param_vals_cache) { + SET_OOM(errs, "failed to alloc val cache for params"); + return SQL_ERROR; + } + + todbc_buf_t *cache = stmt->paramset.params_cache; + if (!cache) { + SET_OOM(errs, "failed to alloc cache buffer for params"); + return SQL_ERROR; + } + OILE(cache, ""); + + param_t *params = (param_t*)todbc_buf_calloc(cache, (size_t)nums, sizeof(*params)); + if (!params) { + SET_OOM(errs, "failed to alloc buffer for params"); + return SQL_ERROR; + } + + tsdb_param_t *tsdb_params = (tsdb_param_t*)todbc_buf_calloc(cache, (size_t)nums, sizeof(*tsdb_params)); + if (!tsdb_params) { + SET_OOM(errs, "failed to alloc buffer for tsdb params"); + return SQL_ERROR; + } + + paramset->params = params; + paramset->n_params = nums; + tsdb_stmt->tsdb_params = tsdb_params; + + for (int i=0; iowner, ""); + + errs_t *errs = &stmt->errs; + + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + const char *enc_to = conn->enc_char; + const char *enc_from = conn->enc_src; // UTF8 + const unsigned char *src = (const unsigned char*)buf; + size_t slen = strlen(buf); + unsigned char *dst = (unsigned char*)col->TargetValue; + size_t dlen = (size_t)col->BufferLength; + todbc_string_t s = todbc_tls_write(enc_to, enc_from, src, &slen, dst, dlen); + if (!s.buf) { + SET_OOM(errs, "failed to convert timestamp"); + return SQL_ERROR; + } + OILE(s.bytes==s.total_bytes, ""); + if (col->StrLen_or_IndPtr) { + *col->StrLen_or_IndPtr = (SQLLEN)s.bytes; + } + for(size_t i=s.bytes; ierrs; + + switch (binding->TargetType) + { + case SQL_C_CHAR: + { + size_t len = (size_t)binding->BufferLength; + OILE(len>0, ""); + if (bytesTargetValue) { + memcpy(binding->TargetValue, val, len); + } + if (binding->StrLen_or_IndPtr) { + *binding->StrLen_or_IndPtr = (SQLLEN)len; + } + // do we really need this? + size_t dlen = (size_t)binding->BufferLength; + unsigned char *dst = (unsigned char*)binding->TargetValue; + for(size_t i=len; iBufferLength; + OILE(len>0, ""); + if (bytesTargetValue) { + memcpy(binding->TargetValue, val, len); + } + if (binding->StrLen_or_IndPtr) { + *binding->StrLen_or_IndPtr = (SQLLEN)len; + } + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for binding[%d]", + field->type, taos_data_type(field->type), + binding->TargetType, sql_c_type(binding->TargetType), + binding->ColumnNumber); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_nchar_to_sql_c(stmt_t *stmt, TAOS_FIELD *field, void *val, size_t bytes, col_binding_t *binding) { + errs_t *errs = &stmt->errs; + + OILE(stmt->owner, ""); + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + switch (binding->TargetType) + { + case SQL_C_CHAR: + { + const char *enc_to = conn->enc_char; + const char *enc_from = conn->enc_db; + const unsigned char *src = (const unsigned char*)val; + size_t slen = bytes; + unsigned char *dst = (unsigned char*)binding->TargetValue; + size_t dlen = (size_t)binding->BufferLength; + todbc_string_t s = todbc_tls_write(enc_to, enc_from, src, &slen, dst, dlen); + if (!s.buf) { + SET_OOM(errs, "failed to convert nchar"); + return SQL_ERROR; + } + OILE(s.bytes==s.total_bytes, ""); + if (binding->StrLen_or_IndPtr) { + *binding->StrLen_or_IndPtr = (SQLLEN)s.bytes; // com-on, it's NOT character-size + } + for(size_t i=s.bytes; ienc_wchar; + const char *enc_from = conn->enc_db; + const unsigned char *src = (const unsigned char*)val; + size_t slen = bytes; + unsigned char *dst = (unsigned char*)binding->TargetValue; + size_t dlen = (size_t)binding->BufferLength; + todbc_string_t s = todbc_tls_write(enc_to, enc_from, src, &slen, dst, dlen); + if (!s.buf) { + SET_OOM(errs, "failed to convert nchar"); + return SQL_ERROR; + } + OILE(s.bytes==s.total_bytes, ""); + if (binding->StrLen_or_IndPtr) { + *binding->StrLen_or_IndPtr = (SQLLEN)s.bytes; // com-on, it's NOT character-size + } + for(size_t i=s.bytes; itype, taos_data_type(field->type), + binding->TargetType, sql_c_type(binding->TargetType), + binding->ColumnNumber); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_int64_to_sql_c(stmt_t *stmt, TAOS_FIELD *field, int64_t val, col_binding_t *binding) { + errs_t *errs = &stmt->errs; + + char buf[128]; + + switch (binding->TargetType) + { + case SQL_C_CHAR: + { + snprintf(buf, sizeof(buf), "%" PRId64 "", val); + return do_conv_utf8_to_sql_c_char(stmt, buf, binding); + } break; + case SQL_C_UTINYINT: + { + if (val>UINT8_MAX || val<0) { + SET_GENERAL(errs, ""); + return SQL_ERROR; + } + if (binding->TargetValue) { + *(uint8_t*)binding->TargetValue = (uint8_t)val; + } + } break; + case SQL_C_USHORT: + { + if (val>UINT16_MAX || val<0) { + SET_GENERAL(errs, ""); + return SQL_ERROR; + } + if (binding->TargetValue) { + *(uint16_t*)binding->TargetValue = (uint16_t)val; + } + } break; + case SQL_C_SLONG: + { + if (val>INT32_MAX || valTargetValue) { + *(int32_t*)binding->TargetValue = (int32_t)val; + } + } break; + case SQL_C_UBIGINT: + { + if (binding->TargetValue) { + *(uint64_t*)binding->TargetValue = (uint64_t)val; + } + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for binding[%d]", + field->type, taos_data_type(field->type), + binding->TargetType, sql_c_type(binding->TargetType), + binding->ColumnNumber); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_timestamp_to_utf8(stmt_t *stmt, int64_t v, char *buf, size_t len) { + errs_t *errs = &stmt->errs; + + // microsecond precision, based on test + time_t secs = v / 1000; + int msecs = (int)(v % 1000); + + struct tm vtm = {0}; + if (&vtm!=localtime_r(&secs, &vtm)) { + SET_ERR(errs, "22007", "invalid timestamp"); + return SQL_ERROR; // ? SQL_SUCCESS_WITH_INFO + } + + char *p = buf; + size_t bytes = len; + + OILE(bytes>0, ""); + size_t n = strftime(p, bytes, "%Y-%m-%d %H:%M:%S", &vtm); + if (n==0) { + SET_GENERAL(errs, "failed to convert timestamp"); + return SQL_ERROR; // ? SQL_SUCCESS_WITH_INFO + } + p += n; + bytes -= n; + + OILE(bytes>0, ""); + int m = snprintf(p, bytes, ".%03d", msecs); + if (m>=bytes) { + SET_GENERAL(errs, "failed to convert timestamp"); + return SQL_ERROR; // ? SQL_SUCCESS_WITH_INFO + } + p += (size_t)m; + bytes -= (size_t)m; + + OILE(bytes>=0, ""); + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_timestamp_to_sql_c(stmt_t *stmt, TAOS_FIELD *field, int64_t val, col_binding_t *col) { + errs_t *errs = &stmt->errs; + + OILE(stmt, ""); + OILE(stmt->owner, ""); + + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + + SQLRETURN r; + char buf[128]; + + switch (col->TargetType) + { + case SQL_C_CHAR: + { + r = do_conv_timestamp_to_utf8(stmt, val, buf, sizeof(buf)); + if (r!=SQL_SUCCESS) return r; + return do_conv_utf8_to_sql_c_char(stmt, buf, col); + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for col[%d]", + field->type, taos_data_type(field->type), + col->TargetType, sql_c_type(col->TargetType), + col->ColumnNumber); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN do_conv_double_to_sql_c(stmt_t *stmt, TAOS_FIELD *field, double val, col_binding_t *binding) { + errs_t *errs = &stmt->errs; + + char buf[256]; + + switch (binding->TargetType) + { + case SQL_C_DOUBLE: + { + if (binding->TargetValue) { + *(double*)binding->TargetValue = val; + } + } break; + case SQL_C_FLOAT: + { + // shall we check overflow/underflow here? + if (binding->TargetValue) { + *(float*)binding->TargetValue = (float)val; + } + } break; + case SQL_C_CHAR: + { + snprintf(buf, sizeof(buf), "%lf", val); + return do_conv_utf8_to_sql_c_char(stmt, buf, binding); + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s to [%d] %s for binding[%d]", + field->type, taos_data_type(field->type), + binding->TargetType, sql_c_type(binding->TargetType), + binding->ColumnNumber); + return SQL_ERROR; + } break; + } + + return SQL_SUCCESS; +} + +static SQLRETURN tsdb_conn_proc_param(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + + paramset_t *paramset = &stmt->paramset; + param_t *params = paramset->params; + int n_params = paramset->n_params; + param_binding_t *bindings = paramset->bindings; + int n_bindings = paramset->n_bindings; + tsdb_param_t *tsdb_params = tsdb_stmt->tsdb_params; + int i_row = paramset->i_row; + int i_col = paramset->i_col; + + OILE(params && n_params>0, ""); + OILE(bindings && n_bindings>=0, ""); + OILE(tsdb_params, ""); + OILE(n_params==n_bindings, ""); + OILE(i_row>=0, ""); + OILE(i_col>=0 && i_colattr.bind_type; // default: SQL_PARAM_BIND_BY_COLUMN + // SQL_ATTR_PARAM_BIND_OFFSET_PTR + SQLULEN *bind_offset_ptr = stmt->attr.bind_offset_ptr; // default: NULL + // SQL_ATTR_PARAMSET_SIZE + SQLULEN paramset_size = stmt->attr.paramset_size; // default: 0 + + // OILE(bind_type && bind_type!=SQL_PARAM_BIND_BY_COLUMN, "[%ld]", bind_type); + // OILE(bind_offset_ptr, ""); + OILE(paramset_size>0, ""); + + OILE(i_rowParameterNumber>0 && param->ParameterNumber<=n_params, ""); + tsdb_param_t *tsdb_param = tsdb_params + i_col; + OILE(tsdb_param->conv, ""); + + tsdb_param_val_t *tsdb_param_vals = tsdb_stmt->tsdb_param_vals; + if (!tsdb_param_vals) { + errs_t *errs = &stmt->errs; + tsdb_stmt_calloc_param_vals(tsdb_stmt); + if (tsdb_stmt->tsdb_param_vals==NULL) { + SET_OOM(errs, "failed to alloc tsdb param vals for tsdb params"); + return SQL_ERROR; + } + if (tsdb_stmt->taos_binds==NULL) { + SET_OOM(errs, "failed to alloc taos binds for tsdb params"); + return SQL_ERROR; + } + tsdb_param_vals = tsdb_stmt->tsdb_param_vals; + } + OILE(tsdb_param_vals, ""); + TAOS_BIND *taos_binds = tsdb_stmt->taos_binds; + OILE(taos_binds, ""); + + + tsdb_param_val_t *tsdb_param_val = tsdb_param_vals + i_col; + tsdb_param_val->ParameterNumber = (SQLUSMALLINT)(i_col + 1); + tsdb_param_val->is_null = 1; + TAOS_BIND *taos_bind = taos_binds + i_col; + + param_binding_t *binding = bindings + (size_t)i_col; + OILE(binding->ParameterNumber==i_col+1, ""); + if (binding->ParameterValuePtr==NULL) return SQL_SUCCESS; + + SQLPOINTER val = binding->ParameterValuePtr; + SQLLEN *soip = binding->StrLen_or_IndPtr; + OILE(soip, ""); + + size_t offset = (size_t)i_row * (size_t)bind_type; + size_t bind_offset = 0; + if (bind_offset_ptr) bind_offset = *bind_offset_ptr; + + val = (SQLPOINTER)(((char*)val) + offset + bind_offset); + soip = (SQLLEN*)(((char*)soip) + offset + bind_offset); + + SQLLEN soi = *soip; + + if (soi == SQL_NULL_DATA) return SQL_SUCCESS; + + OILE(soi>=0 || soi==SQL_NTS, ""); + + tsdb_param_val->is_null = 0; + + conn_t *conn = stmt->owner->conn; + OILE(conn, ""); + todbc_buf_t *cache = tsdb_stmt->tsdb_param_vals_cache; + OILE(cache, ""); + + tsdb_param_conv_arg_t arg = { + .conn = conn, + .cache = cache, + .idx = i_col, + .val = val, + .soi = soi, + .tsdb_param = tsdb_param, + .tsdb_param_val = tsdb_param_val, + .taos_bind = taos_bind + }; + return tsdb_param->conv(stmt, &arg); +} + +static SQLRETURN tsdb_conn_param_row_processed(stmt_t *stmt) { + paramset_t *paramset = &stmt->paramset; + OILE(paramset->n_params>0, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + TAOS_BIND *taos_binds = tsdb_stmt->taos_binds; + OILE(taos_binds, ""); + OILE(tsdb_stmt->tsdb_stmt, ""); + + errs_t *errs = &stmt->errs; + + if (1) { + int r = taos_stmt_bind_param(tsdb_stmt->tsdb_stmt, taos_binds); + if (r) { + SET_GENERAL(errs, "failed to bind params:[%d]%s", r, tstrerror(r)); + // keep executing/executed state unchanged + return SQL_ERROR; + } + + r = taos_stmt_add_batch(tsdb_stmt->tsdb_stmt); + if (r) { + SET_GENERAL(errs, "failed to add batch params:[%d]%s", r, tstrerror(r)); + // keep executing/executed state unchanged + return SQL_ERROR; + } + } + + return SQL_SUCCESS; +} + +static SQLRETURN tsdb_conn_execute(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + OILE(!STMT_IS_EXECUTED(stmt), ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + if (!tsdb_stmt->tsdb_stmt) { + SQLRETURN r = tsdb_stmt_init_stmt(tsdb_stmt); + if (r!=SQL_SUCCESS) return r; + OILE(0, ""); + } + OILE(tsdb_stmt->tsdb_stmt, ""); + + errs_t * errs = &stmt->errs; + + if (1) { + int r = 0; + + r = taos_stmt_execute(tsdb_stmt->tsdb_stmt); + if (r) { + SET_GENERAL(errs, "failed to execute:[%d]%s", r, tstrerror(r)); + // keep executing/executed state unchanged + return SQL_ERROR; + } + + tsdb_stmt->by_query = 0; + } + + STMT_SET_EXECUTED(stmt); + return SQL_SUCCESS; +} + +static void do_fetch_tsdb_res(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt->tsdb_res) { + OILE(tsdb_stmt->by_query==0, ""); + OILE(tsdb_stmt->tsdb_stmt, ""); + tsdb_stmt->tsdb_res = taos_stmt_use_result(tsdb_stmt->tsdb_stmt); + OILE(tsdb_stmt->tsdb_res, ""); + // currently, TAOS_STMT does NOT co-exist with TAOS_RES + tsdb_stmt_close_stmt(tsdb_stmt); + } +} + +SQLRETURN tsdb_conn_get_affected_rows(stmt_t *stmt, SQLLEN *RowCount) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + + do_fetch_tsdb_res(tsdb_stmt); + + int rows = taos_affected_rows(tsdb_stmt->tsdb_res); + OILE(RowCount, ""); + *RowCount = rows; + + return SQL_SUCCESS; +} + +static void do_fetch_tsdb_fields(tsdb_stmt_t *tsdb_stmt) { + if (!tsdb_stmt->tsdb_fields) { + tsdb_stmt->tsdb_fields = taos_fetch_fields(tsdb_stmt->tsdb_res); + } +} + +SQLRETURN tsdb_conn_get_fields_count(stmt_t *stmt, SQLSMALLINT *ColumnCount) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + + do_fetch_tsdb_res(tsdb_stmt); + OILE(tsdb_stmt->tsdb_res, ""); + + int n_fields = taos_num_fields(tsdb_stmt->tsdb_res); + OILE(ColumnCount, ""); + *ColumnCount = (SQLSMALLINT)n_fields; + + return SQL_SUCCESS; +} + +SQLRETURN tsdb_conn_get_field(stmt_t *stmt, field_arg_t *arg) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + + errs_t *errs = &stmt->errs; + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + + do_fetch_tsdb_res(tsdb_stmt); + OILE(tsdb_stmt->tsdb_res, ""); + + int n_fields = taos_num_fields(tsdb_stmt->tsdb_res); + OILE(arg->ColumnNumber>0, ""); + OILE(arg->ColumnNumber<=n_fields, ""); + do_fetch_tsdb_fields(tsdb_stmt); + OILE(tsdb_stmt->tsdb_fields, ""); + + TAOS_FIELD *field = tsdb_stmt->tsdb_fields + (arg->ColumnNumber-1); + int len = 0; + // charset ? + len = snprintf((char*)arg->ColumnName, (size_t)arg->BufferLength, "%s", field->name); + if (arg->NameLength) *arg->NameLength = (SQLSMALLINT)len; + if (arg->DecimalDigits) *arg->DecimalDigits = 0; + if (arg->Nullable) *arg->Nullable = SQL_NULLABLE; + + SQLSMALLINT DataType; + SQLULEN ColumnSize; + + // https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/column-size-decimal-digits-transfer-octet-length-and-display-size?view=sql-server-ver15 + switch (field->type) { + case TSDB_DATA_TYPE_TIMESTAMP: + { + DataType = SQL_CHAR; + ColumnSize = 23; + } break; + case TSDB_DATA_TYPE_NCHAR: + { + DataType = SQL_WCHAR; + ColumnSize = (SQLULEN)field->bytes; + } break; + case TSDB_DATA_TYPE_BINARY: + { + DataType = SQL_BINARY; + ColumnSize = (SQLULEN)field->bytes; + } break; + case TSDB_DATA_TYPE_BOOL: + { + DataType = SQL_BIT; + ColumnSize = 1; + } break; + case TSDB_DATA_TYPE_TINYINT: + { + DataType = SQL_TINYINT; + ColumnSize = 3; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + DataType = SQL_SMALLINT; + ColumnSize = 5; + } break; + case TSDB_DATA_TYPE_INT: + { + DataType = SQL_INTEGER; + ColumnSize = 10; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + DataType = SQL_BIGINT; + ColumnSize = 20; + } break; + case TSDB_DATA_TYPE_FLOAT: + { + DataType = SQL_FLOAT; + ColumnSize = 15; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + DataType = SQL_DOUBLE; + ColumnSize = 15; + } break; + default: + { + SET_GENERAL(errs, "failed to map field[%d] type[%d]%s to SQL DATA TYPE", + arg->ColumnNumber, field->type, taos_data_type(field->type)); + return SQL_ERROR; + } break; + } + + if (arg->DataType) *arg->DataType = DataType; + if (arg->ColumnSize) *arg->ColumnSize = ColumnSize; + + return SQL_SUCCESS; +} + +SQLRETURN tsdb_conn_fetch(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + + OILE(stmt->eof==0, ""); + + do_fetch_tsdb_res(tsdb_stmt); + OILE(tsdb_stmt->tsdb_res, ""); + + tsdb_stmt->tsdb_curr = taos_fetch_row(tsdb_stmt->tsdb_res); + if (!tsdb_stmt->tsdb_curr) { + stmt->eof = 1; + return SQL_NO_DATA; + } + + return SQL_SUCCESS; +} + +static SQLRETURN tsdb_conn_get_data(stmt_t *stmt, col_binding_t *col) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt, ""); + + OILE(stmt->eof==0, ""); + OILE(tsdb_stmt->tsdb_curr, ""); + OILE(tsdb_stmt->tsdb_res, ""); + + int n_fields = taos_num_fields(tsdb_stmt->tsdb_res); + int idx = (int)(col->ColumnNumber-1); + OILE(idx>=0, ""); + OILE(idxtsdb_fields, ""); + + TAOS_FIELD *field = tsdb_stmt->tsdb_fields + idx; + + OILE(col->StrLen_or_IndPtr, ""); + void *val = tsdb_stmt->tsdb_curr[idx]; + if (!val) { + *col->StrLen_or_IndPtr = SQL_NULL_DATA; + return SQL_SUCCESS; + } + + errs_t *errs = &stmt->errs; + + int64_t i64; + double dbl; + int is_dbl = 0; + + switch (field->type) + { + case TSDB_DATA_TYPE_TINYINT: + { + i64 = *(int8_t*)val; + } break; + case TSDB_DATA_TYPE_SMALLINT: + { + i64 = *(int16_t*)val; + } break; + case TSDB_DATA_TYPE_INT: + { + i64 = *(int32_t*)val; + } break; + case TSDB_DATA_TYPE_BIGINT: + { + i64 = *(int64_t*)val; + } break; + case TSDB_DATA_TYPE_FLOAT: + { + dbl = GET_FLOAT_VAL(val); + is_dbl = 1; + } break; + case TSDB_DATA_TYPE_DOUBLE: + { + dbl = GET_DOUBLE_VAL(val); + is_dbl = 1; + } break; + case TSDB_DATA_TYPE_BINARY: + { + size_t bytes = (size_t)varDataLen((char*)val - VARSTR_HEADER_SIZE); + return do_conv_binary_to_sql_c(stmt, field, val, bytes, col); + } break; + case TSDB_DATA_TYPE_NCHAR: + { + size_t bytes = (size_t)varDataLen((char*)val - VARSTR_HEADER_SIZE); + return do_conv_nchar_to_sql_c(stmt, field, val, bytes, col); + } break; + case TSDB_DATA_TYPE_TIMESTAMP: + { + i64 = *(int64_t*)val; + return do_conv_timestamp_to_sql_c(stmt, field, i64, col); + break; + } + case TSDB_DATA_TYPE_BOOL: + { + i64 = *(int8_t*)val; + } break; + default: + { + SET_GENERAL(errs, "not convertion from [%d]%s for col[%d]", + field->type, taos_data_type(field->type), col->ColumnNumber); + return SQL_ERROR; + } break; + } + if (is_dbl) return do_conv_double_to_sql_c(stmt, field, dbl, col); + else return do_conv_int64_to_sql_c(stmt, field, i64, col); +} + +static void tsdb_conn_close_rs(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->owner, ""); + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)stmt->ext.ext; + OILE(tsdb_stmt && tsdb_stmt->stmt==stmt, ""); + + tsdb_stmt_close_rs(tsdb_stmt); +} + +static int tsdb_conn_init_stmt(stmt_t *stmt) { + OILE(stmt, ""); + OILE(stmt->ext.ext==NULL, ""); + OILE(stmt->ext.free_stmt==NULL, ""); + + OILE(stmt->owner==NULL, ""); + + tsdb_stmt_t *tsdb_stmt = (tsdb_stmt_t*)calloc(1, sizeof(*tsdb_stmt)); + if (!tsdb_stmt) return -1; + + stmt_ext_t *ext = &stmt->ext; + + tsdb_stmt->stmt = stmt; + ext->ext = tsdb_stmt; + ext->free_stmt = tsdb_conn_free_stmt; + ext->clear_param_vals = tsdb_conn_clear_param_vals; + ext->exec_direct = tsdb_conn_exec_direct; + ext->prepare = tsdb_conn_prepare; + ext->set_param_conv = tsdb_conn_set_param_conv; + ext->proc_param = tsdb_conn_proc_param; + ext->param_row_processed = tsdb_conn_param_row_processed; + ext->execute = tsdb_conn_execute; + ext->get_affected_rows = tsdb_conn_get_affected_rows; + ext->get_fields_count = tsdb_conn_get_fields_count; + ext->get_field = tsdb_conn_get_field; + ext->fetch = tsdb_conn_fetch; + ext->get_data = tsdb_conn_get_data; + ext->close_rs = tsdb_conn_close_rs; + + return 0; +} + +static pthread_once_t init_once = PTHREAD_ONCE_INIT; +static int inited = 0; +// static char tsdb_svr_info[128] = ""; +// static char tsdb_cli_info[128] = ""; + +static void init_routine(void) { + int r = taos_init(); + if (r) { + OW("taos init failed: [%d]%s", r, tstrerror(r)); + return; + } + OI("taos inited"); + inited = 1; +} + +int conn_init_tsdb_conn(conn_t *conn) { + OILE(conn, ""); + OILE(conn->ext.ext==NULL, ""); + OILE(conn->ext.free_conn==NULL, ""); + + pthread_once(&init_once, init_routine); + if (!inited) return -1; + + tsdb_conn_t *tsdb_conn = (tsdb_conn_t*)calloc(1, sizeof(*tsdb_conn)); + if (!tsdb_conn) return -1; + + tsdb_conn->conn = conn; + conn->ext.ext = tsdb_conn; + conn->ext.free_conn = tsdb_conn_free; + conn->ext.connect = tsdb_conn_connect; + conn->ext.disconnect = tsdb_conn_disconnect; + conn->ext.init_stmt = tsdb_conn_init_stmt; + + return 0; +} + + diff --git a/src/connector/odbc/src/base/tsdb_impl.h b/src/connector/odbc/src/base/tsdb_impl.h new file mode 100644 index 0000000000..f217a4be41 --- /dev/null +++ b/src/connector/odbc/src/base/tsdb_impl.h @@ -0,0 +1,30 @@ +/* + * 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 _tsdb_impl_h_ +#define _tsdb_impl_h_ + +#include "../base.h" + +#include "conn.h" + +#define DEFAULT_SERVER "localhost:6030" + +int conn_init_tsdb_conn(conn_t *conn); + + +#endif // _tsdb_impl_h_ + + diff --git a/src/connector/odbc/src/col.h b/src/connector/odbc/src/col.h new file mode 100644 index 0000000000..f7cdc24081 --- /dev/null +++ b/src/connector/odbc/src/col.h @@ -0,0 +1,28 @@ +/* + * 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 _col_h_ +#define _col_h_ + +#include "base.h" + +struct col_s { +}; + + +#endif // _col_h_ + + + diff --git a/src/connector/odbc/src/install.cmd b/src/connector/odbc/src/install.cmd new file mode 100644 index 0000000000..4da8a2d976 --- /dev/null +++ b/src/connector/odbc/src/install.cmd @@ -0,0 +1,6 @@ +@echo off +REM install driver +odbcconf /A {INSTALLDRIVER "TAOS|Driver=C:\TDengine\driver\todbc.dll|ConnectFunctions=YYN|DriverODBCVer=03.00|FileUsage=0|SQLLevel=0"} +REM config user dsn +odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN"} + diff --git a/src/connector/odbc/src/install.sh b/src/connector/odbc/src/install.sh index 02f31de70e..c08ac9208e 100755 --- a/src/connector/odbc/src/install.sh +++ b/src/connector/odbc/src/install.sh @@ -2,6 +2,13 @@ set -u +EXT="so" +[[ `uname` == 'Darwin' ]] && EXT="dylib" + +SUDO="sudo" +[[ `uname` == 'Darwin' ]] && SUDO="" + + BLD_DIR="$1" rm -f "${BLD_DIR}/template.ini" @@ -10,18 +17,30 @@ rm -f "${BLD_DIR}/template.dsn" cat > "${BLD_DIR}/template.ini" < "${BLD_DIR}/template.dsn" < - * - * 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 . - */ - -// #define _BSD_SOURCE -#define _XOPEN_SOURCE -#define _DEFAULT_SOURCE -#define _GNU_SOURCE - -#include "todbc_log.h" -#include "todbc_flex.h" - -#include "taos.h" - -#include "tglobal.h" -#include "taoserror.h" -#include "todbc_util.h" -#include "todbc_conv.h" - -#include "os.h" - -#include -#include - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#define UTF8_ENC "UTF-8" -#define UTF16_ENC "UCS-2LE" -#define UNICODE_ENC "UCS-4LE" -#define GB18030_ENC "GB18030" - -#define GET_REF(obj) atomic_load_64(&obj->refcount) -#define INC_REF(obj) atomic_add_fetch_64(&obj->refcount, 1) -#define DEC_REF(obj) atomic_sub_fetch_64(&obj->refcount, 1) - -#define LOCK(obj) pthread_mutex_lock(&obj->lock); -#define UNLOCK(obj) pthread_mutex_unlock(&obj->lock); - -#define SET_ERROR(obj, sqlstate, eno, err_fmt, ...) \ -do { \ - obj->err.err_no = eno; \ - const char* estr = tstrerror(eno); \ - if (!estr) estr = "Unknown error"; \ - int n = snprintf(NULL, 0, "[TSDB:%x]%s: @%s[%d]" err_fmt "", \ - eno, estr, \ - basename((char*)__FILE__), __LINE__, \ - ##__VA_ARGS__); \ - if (n<0) break; \ - char *err_str = (char*)realloc(obj->err.err_str, (size_t)n+1); \ - if (!err_str) break; \ - obj->err.err_str = err_str; \ - snprintf(obj->err.err_str, (size_t)n+1, "[TSDB:%x]%s: @%s[%d]" err_fmt "", \ - eno, estr, \ - basename((char*)__FILE__), __LINE__, \ - ##__VA_ARGS__); \ - snprintf((char*)obj->err.sql_state, sizeof(obj->err.sql_state), "%s", sqlstate); \ -} while (0) - - -#define CLR_ERROR(obj) \ -do { \ - obj->err.err_no = TSDB_CODE_SUCCESS; \ - if (obj->err.err_str) obj->err.err_str[0] = '\0'; \ - obj->err.sql_state[0] = '\0'; \ -} while (0) - -#define FILL_ERROR(obj) \ -do { \ - size_t n = sizeof(obj->err.sql_state); \ - if (Sqlstate) strncpy((char*)Sqlstate, (char*)obj->err.sql_state, n); \ - if (NativeError) *NativeError = obj->err.err_no; \ - snprintf((char*)MessageText, (size_t)BufferLength, "%s", obj->err.err_str); \ - if (TextLength && obj->err.err_str) *TextLength = (SQLSMALLINT)utf8_chars(obj->err.err_str); \ -} while (0) - -#define FREE_ERROR(obj) \ -do { \ - obj->err.err_no = TSDB_CODE_SUCCESS; \ - if (obj->err.err_str) { \ - free(obj->err.err_str); \ - obj->err.err_str = NULL; \ - } \ - obj->err.sql_state[0] = '\0'; \ -} while (0) - -#define SET_UNSUPPORT_ERROR(obj, sqlstate, err_fmt, ...) \ -do { \ - SET_ERROR(obj, sqlstate, TSDB_CODE_ODBC_NOT_SUPPORT, err_fmt, ##__VA_ARGS__); \ -} while (0) \ - -#define SET_HANDLE_INVALID(obj, sqlstate, err_fmt, ...) \ -do { \ - SET_ERROR(obj, sqlstate, TSDB_CODE_QRY_INVALID_QHANDLE, err_fmt, ##__VA_ARGS__); \ -} while (0); - -#define SDUP(s,n) (s ? (s[(size_t)n] ? (const char*)strndup((const char*)s,(size_t)n) : (const char*)s) : strdup("")) -#define SFRE(x,s,n) \ -do { \ - if (x==(const char*)s) break; \ - if (x) { \ - free((char*)x); \ - x = NULL; \ - } \ -} while (0) - -#define CHK_CONN(obj) \ -do { \ - if (!obj->conn) { \ - SET_ERROR(obj, "HY000", TSDB_CODE_ODBC_INVALID_HANDLE, "connection closed or not ready"); \ - return SQL_ERROR; \ - } \ -} while (0); - -#define CHK_CONN_TAOS(obj) \ -do { \ - if (!obj->conn->taos) { \ - SET_ERROR(obj, "HY000", TSDB_CODE_ODBC_INVALID_HANDLE, "connection to data source closed or not ready"); \ - return SQL_ERROR; \ - } \ -} while (0); - -#define CHK_RS(r_091c, sql_091c, fmt_091c, ...) \ -do { \ - r_091c = SQL_ERROR; \ - int e = sql_091c->rs ? taos_errno(sql_091c->rs) : terrno; \ - if (e != TSDB_CODE_SUCCESS) { \ - SET_ERROR(sql_091c, "HY000", e, fmt_091c, ##__VA_ARGS__); \ - break; \ - } \ - r_091c = SQL_SUCCESS; \ -} while (0) - -#define NORM_STR_LENGTH(obj, ptr, len) \ -do { \ - if ((len) < 0 && (len)!=SQL_NTS) { \ - SET_ERROR((obj), "HY090", TSDB_CODE_ODBC_BAD_ARG, ""); \ - return SQL_ERROR; \ - } \ - if (len==SQL_NTS) len = (ptr) ? (SQLSMALLINT)strlen((const char*)(ptr)) : 0; \ -} while (0) - -#define PROFILING 0 - -#define PROFILE(statement) \ -do { \ - if (!PROFILING) { \ - statement; \ - break; \ - } \ - struct timeval tv0, tv1; \ - gettimeofday(&tv0, NULL); \ - statement; \ - gettimeofday(&tv1, NULL); \ - double delta = difftime(tv1.tv_sec, tv0.tv_sec); \ - delta *= 1000000; \ - delta += (double)(tv1.tv_usec-tv0.tv_usec); \ - delta /= 1000000; \ - D("%s: elapsed: [%.6f]s", #statement, delta); \ -} while (0) - -#define CHK_CONV(todb, statement) \ -do { \ - TSDB_CONV_CODE code_0c80 = (statement); \ - switch (code_0c80) { \ - case TSDB_CONV_OK: return SQL_SUCCESS; \ - case TSDB_CONV_OOM: \ - case TSDB_CONV_NOT_AVAIL: { \ - SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_OOR: { \ - SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_OOR, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_CHAR_NOT_NUM: \ - case TSDB_CONV_CHAR_NOT_TS: { \ - SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_CHAR_NOT_NUM, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_NOT_VALID_TS: { \ - SET_ERROR(sql, "22007", TSDB_CODE_ODBC_CONV_NOT_VALID_TS, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_TRUNC_FRACTION: { \ - SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC_FRAC, ""); \ - return todb ? SQL_ERROR : SQL_SUCCESS_WITH_INFO; \ - } break; \ - case TSDB_CONV_TRUNC: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_TRUNC, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_SRC_TOO_LARGE: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_SRC_TOO_LARGE, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_SRC_BAD_SEQ: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_SRC_BAD_SEQ, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_SRC_INCOMPLETE: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_SRC_INCOMPLETE, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_SRC_GENERAL: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_SRC_GENERAL, ""); \ - return SQL_ERROR; \ - } break; \ - case TSDB_CONV_BAD_CHAR: { \ - SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_TRUNC, ""); \ - return SQL_ERROR; \ - } break; \ - default: { \ - DASSERTX(0, "internal logic error: %d", code_0c80); \ - return SQL_ERROR; /* never reached here */ \ - } break; \ - } \ -} while (0) - -typedef struct env_s env_t; -typedef struct conn_s conn_t; -typedef struct sql_s sql_t; -typedef struct taos_error_s taos_error_t; -typedef struct param_bind_s param_bind_t; - -struct param_bind_s { - SQLUSMALLINT ParameterNumber; - SQLSMALLINT ValueType; - SQLSMALLINT ParameterType; - SQLULEN LengthPrecision; - SQLSMALLINT ParameterScale; - SQLPOINTER ParameterValue; - SQLLEN *StrLen_or_Ind; - - unsigned int valid; -}; - -struct taos_error_s { - char *err_str; - int err_no; - - SQLCHAR sql_state[6]; -}; - -struct env_s { - uint64_t refcount; - unsigned int destroying:1; - - char env_locale[64]; - char env_charset[64]; - - taos_error_t err; -}; - -struct conn_s { - uint64_t refcount; - env_t *env; - - char client_enc[64]; // ODBC client that communicates with this driver - char server_enc[64]; // taos dynamic library that's loaded by this driver - - tsdb_conv_t *client_to_server; - tsdb_conv_t *server_to_client; - tsdb_conv_t *utf8_to_client; - tsdb_conv_t *utf16_to_utf8; - tsdb_conv_t *utf16_to_server; - tsdb_conv_t *client_to_utf8; - - TAOS *taos; - - taos_error_t err; -}; - -struct sql_s { - uint64_t refcount; - conn_t *conn; - - TAOS_STMT *stmt; - param_bind_t *params; - int n_params; - size_t rowlen; - size_t n_rows; - size_t ptr_offset; - - TAOS_RES *rs; - TAOS_ROW row; - - taos_error_t err; - unsigned int is_prepared:1; - unsigned int is_insert:1; - unsigned int is_executed:1; -}; - -typedef struct c_target_s c_target_t; -struct c_target_s { - SQLUSMALLINT col; - SQLSMALLINT ct; // c type: SQL_C_XXX - char *ptr; - SQLLEN len; - SQLLEN *soi; -}; - -static pthread_once_t init_once = PTHREAD_ONCE_INIT; -static void init_routine(void); - -static size_t do_field_display_size(TAOS_FIELD *field); - -static tsdb_conv_t* tsdb_conn_client_to_server(conn_t *conn) { - if (!conn->client_to_server) { - conn->client_to_server = tsdb_conv_open(conn->client_enc, conn->server_enc); - } - return conn->client_to_server; -} - -static tsdb_conv_t* tsdb_conn_server_to_client(conn_t *conn) { - if (!conn->server_to_client) { - conn->server_to_client = tsdb_conv_open(conn->server_enc, conn->client_enc); - } - return conn->server_to_client; -} - -static tsdb_conv_t* tsdb_conn_utf8_to_client(conn_t *conn) { - if (!conn->utf8_to_client) { - conn->utf8_to_client = tsdb_conv_open(UTF8_ENC, conn->client_enc); - } - return conn->utf8_to_client; -} - -static tsdb_conv_t* tsdb_conn_utf16_to_utf8(conn_t *conn) { - if (!conn->utf16_to_utf8) { - conn->utf16_to_utf8 = tsdb_conv_open(UTF16_ENC, UTF8_ENC); - } - return conn->utf16_to_utf8; -} - -static tsdb_conv_t* tsdb_conn_utf16_to_server(conn_t *conn) { - if (!conn->utf16_to_server) { - conn->utf16_to_server = tsdb_conv_open(UTF16_ENC, conn->server_enc); - } - return conn->utf16_to_server; -} - -static tsdb_conv_t* tsdb_conn_client_to_utf8(conn_t *conn) { - if (!conn->client_to_utf8) { - conn->client_to_utf8 = tsdb_conv_open(conn->client_enc, UTF8_ENC); - } - return conn->client_to_utf8; -} - -static void tsdb_conn_close_convs(conn_t *conn) { - if (conn->client_to_server) { - tsdb_conv_close(conn->client_to_server); - conn->client_to_server = NULL; - } - if (conn->server_to_client) { - tsdb_conv_close(conn->server_to_client); - conn->server_to_client = NULL; - } - if (conn->utf8_to_client) { - tsdb_conv_close(conn->utf8_to_client); - conn->utf8_to_client = NULL; - } - if (conn->utf16_to_utf8) { - tsdb_conv_close(conn->utf16_to_utf8); - conn->utf16_to_utf8 = NULL; - } - if (conn->utf16_to_server) { - tsdb_conv_close(conn->utf16_to_server); - conn->utf16_to_server = NULL; - } - if (conn->client_to_utf8) { - tsdb_conv_close(conn->client_to_utf8); - conn->client_to_utf8 = NULL; - } -} - -#define SFREE(buffer, v, src) \ -do { \ - const char *v_096a = (const char*)(v); \ - const char *src_6a = (const char*)(src); \ - if (v_096a && v_096a!=src_6a && !is_owned_by_stack_buffer((buffer), v_096a)) { \ - free((char*)v_096a); \ - } \ -} while (0) - -static SQLRETURN doSQLAllocEnv(SQLHENV *EnvironmentHandle) -{ - pthread_once(&init_once, init_routine); - - env_t *env = (env_t*)calloc(1, sizeof(*env)); - if (!env) return SQL_INVALID_HANDLE; - - DASSERT(INC_REF(env)>0); - - snprintf(env->env_locale, sizeof(env->env_locale), "%s", tsLocale); - snprintf(env->env_charset, sizeof(env->env_charset), "%s", tsCharset); - - *EnvironmentHandle = env; - - CLR_ERROR(env); - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) -{ - SQLRETURN r; - r = doSQLAllocEnv(EnvironmentHandle); - return r; -} - -static SQLRETURN doSQLFreeEnv(SQLHENV EnvironmentHandle) -{ - env_t *env = (env_t*)EnvironmentHandle; - if (!env) return SQL_INVALID_HANDLE; - - DASSERT(GET_REF(env)==1); - - DASSERT(!env->destroying); - - env->destroying = 1; - DASSERT(env->destroying == 1); - - DASSERT(DEC_REF(env)==0); - - FREE_ERROR(env); - free(env); - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) -{ - SQLRETURN r; - r = doSQLFreeEnv(EnvironmentHandle); - return r; -} - -static SQLRETURN doSQLAllocConnect(SQLHENV EnvironmentHandle, - SQLHDBC *ConnectionHandle) -{ - env_t *env = (env_t*)EnvironmentHandle; - if (!env) return SQL_INVALID_HANDLE; - - if (!ConnectionHandle) { - SET_ERROR(env, "HY009", TSDB_CODE_ODBC_BAD_ARG, "ConnectionHandle [%p] not valid", ConnectionHandle); - return SQL_ERROR; - } - - DASSERT(INC_REF(env)>1); - - conn_t *conn = NULL; - do { - conn = (conn_t*)calloc(1, sizeof(*conn)); - if (!conn) { - SET_ERROR(env, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - - conn->env = env; - - snprintf(conn->client_enc, sizeof(conn->client_enc), "%s", conn->env->env_charset); - snprintf(conn->server_enc, sizeof(conn->server_enc), "%s", conn->env->env_charset); - - *ConnectionHandle = conn; - - DASSERT(INC_REF(conn)>0); - - return SQL_SUCCESS; - } while (0); - - DASSERT(DEC_REF(env)>0); - - return SQL_ERROR; -} - -SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, - SQLHDBC *ConnectionHandle) -{ - SQLRETURN r; - r = doSQLAllocConnect(EnvironmentHandle, ConnectionHandle); - return r; -} - -static SQLRETURN doSQLFreeConnect(SQLHDBC ConnectionHandle) -{ - conn_t *conn = (conn_t*)ConnectionHandle; - if (!conn) return SQL_INVALID_HANDLE; - - DASSERT(GET_REF(conn)==1); - - DASSERT(conn->env); - - do { - if (conn->taos) { - taos_close(conn->taos); - conn->taos = NULL; - } - - DASSERT(DEC_REF(conn->env)>0); - DASSERT(DEC_REF(conn)==0); - - conn->env = NULL; - FREE_ERROR(conn); - tsdb_conn_close_convs(conn); - free(conn); - } while (0); - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) -{ - SQLRETURN r; - r = doSQLFreeConnect(ConnectionHandle); - return r; -} - -static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle, - SQLCHAR *ServerName, SQLSMALLINT NameLength1, - SQLCHAR *UserName, SQLSMALLINT NameLength2, - SQLCHAR *Authentication, SQLSMALLINT NameLength3) -{ - stack_buffer_t buffer; buffer.next = 0; - - conn_t *conn = (conn_t*)ConnectionHandle; - if (!conn) return SQL_ERROR; - - if (conn->taos) { - SET_ERROR(conn, "08002", TSDB_CODE_ODBC_CONNECTION_BUSY, "connection still in use"); - return SQL_ERROR; - } - - NORM_STR_LENGTH(conn, ServerName, NameLength1); - NORM_STR_LENGTH(conn, UserName, NameLength2); - NORM_STR_LENGTH(conn, Authentication, NameLength3); - - if (NameLength1>SQL_MAX_DSN_LENGTH) { - SET_ERROR(conn, "HY090", TSDB_CODE_ODBC_BAD_ARG, ""); - return SQL_ERROR; - } - - tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn); - const char *dsn = NULL; - const char *uid = NULL; - const char *pwd = NULL; - const char *svr = NULL; - char server[4096]; server[0] = '\0'; - - do { - tsdb_conv(client_to_server, &buffer, (const char*)ServerName, (size_t)NameLength1, &dsn, NULL); - tsdb_conv(client_to_server, &buffer, (const char*)UserName, (size_t)NameLength2, &uid, NULL); - tsdb_conv(client_to_server, &buffer, (const char*)Authentication, (size_t)NameLength3, &pwd, NULL); - int n = SQLGetPrivateProfileString(dsn, "Server", "", server, sizeof(server)-1, "Odbc.ini"); - if (n<=0) { - snprintf(server, sizeof(server), "localhost:6030"); // all 7-bit ascii - } - tsdb_conv(client_to_server, &buffer, (const char*)server, (size_t)strlen(server), &svr, NULL); - - if ((!dsn) || (!uid) || (!pwd) || (!svr)) { - SET_ERROR(conn, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - - char *ip = NULL; - int port = 0; - char *p = strchr(svr, ':'); - if (p) { - ip = strndup(svr, (size_t)(p-svr)); - port = atoi(p+1); - } - - // TODO: data-race - // TODO: shall receive ip/port from odbc.ini - conn->taos = taos_connect(ip, uid, pwd, NULL, (uint16_t)port); - if (!conn->taos) { - SET_ERROR(conn, "08001", terrno, "failed to connect to data source for DSN[%s] @[%s:%d]", dsn, ip, port); - break; - } - } while (0); - - tsdb_conv_free(client_to_server, dsn, &buffer, (const char*)ServerName); - tsdb_conv_free(client_to_server, uid, &buffer, (const char*)UserName); - tsdb_conv_free(client_to_server, pwd, &buffer, (const char*)Authentication); - tsdb_conv_free(client_to_server, svr, &buffer, (const char*)server); - - return conn->taos ? SQL_SUCCESS : SQL_ERROR; -} - -SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, - SQLCHAR *ServerName, SQLSMALLINT NameLength1, - SQLCHAR *UserName, SQLSMALLINT NameLength2, - SQLCHAR *Authentication, SQLSMALLINT NameLength3) -{ - SQLRETURN r; - r = doSQLConnect(ConnectionHandle, ServerName, NameLength1, - UserName, NameLength2, - Authentication, NameLength3); - return r; -} - -static SQLRETURN doSQLDisconnect(SQLHDBC ConnectionHandle) -{ - conn_t *conn = (conn_t*)ConnectionHandle; - if (!conn) return SQL_INVALID_HANDLE; - - if (conn->taos) { - taos_close(conn->taos); - conn->taos = NULL; - } - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) -{ - SQLRETURN r; - r = doSQLDisconnect(ConnectionHandle); - return r; -} - -static SQLRETURN doSQLAllocStmt(SQLHDBC ConnectionHandle, - SQLHSTMT *StatementHandle) -{ - conn_t *conn = (conn_t*)ConnectionHandle; - if (!conn) return SQL_INVALID_HANDLE; - - if (!StatementHandle) { - SET_ERROR(conn, "HY009", TSDB_CODE_ODBC_BAD_ARG, "StatementHandle [%p] not valid", StatementHandle); - return SQL_ERROR; - } - - DASSERT(INC_REF(conn)>1); - - do { - sql_t *sql = (sql_t*)calloc(1, sizeof(*sql)); - if (!sql) { - SET_ERROR(conn, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - - sql->conn = conn; - DASSERT(INC_REF(sql)>0); - - *StatementHandle = sql; - - return SQL_SUCCESS; - } while (0); - - DASSERT(DEC_REF(conn)>0); - - return SQL_ERROR; -} - -SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, - SQLHSTMT *StatementHandle) -{ - SQLRETURN r; - r = doSQLAllocStmt(ConnectionHandle, StatementHandle); - return r; -} - -static SQLRETURN doSQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle) -{ - switch (HandleType) { - case SQL_HANDLE_ENV: { - SQLHENV env = {0}; - if (!OutputHandle) return SQL_ERROR; - SQLRETURN r = doSQLAllocEnv(&env); - if (r==SQL_SUCCESS) *OutputHandle = env; - return r; - } break; - case SQL_HANDLE_DBC: { - SQLRETURN r = doSQLAllocConnect(InputHandle, OutputHandle); - return r; - } break; - case SQL_HANDLE_STMT: { - SQLRETURN r = doSQLAllocStmt(InputHandle, OutputHandle); - return r; - } break; - default: { - return SQL_ERROR; - } break; - } -} - -SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle) -{ - SQLRETURN r; - r = doSQLAllocHandle(HandleType, InputHandle, OutputHandle); - return r; -} - -static SQLRETURN doSQLFreeStmt(SQLHSTMT StatementHandle, - SQLUSMALLINT Option) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - switch (Option) { - case SQL_CLOSE: return SQL_SUCCESS; - case SQL_DROP: break; - case SQL_UNBIND: - case SQL_RESET_PARAMS: { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "free statement with Option[%x] not supported yet", Option); - return SQL_ERROR; - } break; - default: { - SET_ERROR(sql, "HY092", TSDB_CODE_ODBC_OUT_OF_RANGE, "free statement with Option[%x] not supported yet", Option); - return SQL_ERROR; - } break; - } - - DASSERT(GET_REF(sql)==1); - - if (sql->rs) { - taos_free_result(sql->rs); - sql->rs = NULL; - } - - if (sql->stmt) { - taos_stmt_close(sql->stmt); - sql->stmt = NULL; - } - - if (sql->params) { - free(sql->params); - sql->params = NULL; - } - sql->n_params = 0; - - DASSERT(DEC_REF(sql->conn)>0); - DASSERT(DEC_REF(sql)==0); - - sql->conn = NULL; - - FREE_ERROR(sql); - - free(sql); - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, - SQLUSMALLINT Option) -{ - SQLRETURN r; - r = doSQLFreeStmt(StatementHandle, Option); - return r; -} - -static SQLRETURN do_exec_direct(sql_t *sql, TSDB_CONV_CODE code, const char *statement) { - if (code) CHK_CONV(1, code); - DASSERT(code==TSDB_CONV_OK); - - SQLRETURN r = SQL_ERROR; - do { - sql->rs = taos_query(sql->conn->taos, statement); - CHK_RS(r, sql, "failed to execute"); - } while (0); - - return r; -} - -static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - conn_t *conn = sql->conn; - - NORM_STR_LENGTH(sql, StatementText, TextLength); - - if (sql->rs) { - taos_free_result(sql->rs); - sql->rs = NULL; - sql->row = NULL; - } - - if (sql->stmt) { - taos_stmt_close(sql->stmt); - sql->stmt = NULL; - } - - if (sql->params) { - free(sql->params); - sql->params = NULL; - } - sql->n_params = 0; - - SQLRETURN r = SQL_SUCCESS; - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn); - const char *stxt = NULL; - do { - TSDB_CONV_CODE code = tsdb_conv(client_to_server, &buffer, (const char*)StatementText, (size_t)TextLength, &stxt, NULL); - r = do_exec_direct(sql, code, stxt); - } while (0); - tsdb_conv_free(client_to_server, stxt, &buffer, (const char*)StatementText); - - return r; -} - -SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) -{ - SQLRETURN r; - r = doSQLExecDirect(StatementHandle, StatementText, TextLength); - return r; -} - -static SQLRETURN doSQLExecDirectW(SQLHSTMT hstmt, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStr) -{ - sql_t *sql = (sql_t*)hstmt; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - conn_t *conn = sql->conn; - - if (!szSqlStr) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "szSqlStr [%p] not allowed", szSqlStr); - return SQL_ERROR; - } - if (cbSqlStr < 0) { - SET_ERROR(sql, "HY090", TSDB_CODE_ODBC_BAD_ARG, ""); - return SQL_ERROR; - } - - SQLRETURN r = SQL_SUCCESS; - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_server = tsdb_conn_utf16_to_server(conn); - const char *stxt = NULL; - do { - size_t slen = (size_t)cbSqlStr * sizeof(*szSqlStr); - TSDB_CONV_CODE code = tsdb_conv(utf16_to_server, &buffer, (const char*)szSqlStr, slen, &stxt, NULL); - r = do_exec_direct(sql, code, stxt); - } while (0); - tsdb_conv_free(utf16_to_server, stxt, &buffer, (const char*)szSqlStr); - - return r; -} - -SQLRETURN SQL_API SQLExecDirectW(SQLHSTMT hstmt, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStr) -{ - SQLRETURN r = doSQLExecDirectW(hstmt, szSqlStr, cbSqlStr); - return r; -} - -static SQLRETURN doSQLNumResultCols(SQLHSTMT StatementHandle, - SQLSMALLINT *ColumnCount) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (sql->is_insert) { - if (ColumnCount) { - *ColumnCount = 0; - } - return SQL_SUCCESS; - } - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - int fields = taos_field_count(sql->rs); - if (ColumnCount) { - *ColumnCount = (SQLSMALLINT)fields; - } - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, - SQLSMALLINT *ColumnCount) -{ - SQLRETURN r; - r = doSQLNumResultCols(StatementHandle, ColumnCount); - return r; -} - -static SQLRETURN doSQLRowCount(SQLHSTMT StatementHandle, - SQLLEN *RowCount) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_ERROR; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - // ref: https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlrowcount-function?view=sql-server-ver15 - // Summary - // SQLRowCount returns the number of rows affected by an UPDATE, INSERT, or DELETE statement; - // an SQL_ADD, SQL_UPDATE_BY_BOOKMARK, or SQL_DELETE_BY_BOOKMARK operation in SQLBulkOperations; - // or an SQL_UPDATE or SQL_DELETE operation in SQLSetPos. - - // how to fetch affected rows from taos? - // taos_affected_rows? - - if (1) { - SET_ERROR(sql, "IM001", TSDB_CODE_ODBC_NOT_SUPPORT, ""); - // if (RowCount) *RowCount = 0; - return SQL_SUCCESS_WITH_INFO; - } - - if (!sql->is_insert) { - if (RowCount) *RowCount = 0; - return SQL_SUCCESS; - } - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - int rows = taos_affected_rows(sql->rs); - if (RowCount) { - *RowCount = rows; - } - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle, - SQLLEN *RowCount) -{ - SQLRETURN r; - r = doSQLRowCount(StatementHandle, RowCount); - return r; -} - -static SQLRETURN doSQLColAttribute(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, - SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_ERROR; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - int nfields = taos_field_count(sql->rs); - TAOS_FIELD *fields = taos_fetch_fields(sql->rs); - - if (nfields==0 || fields==NULL) { - SET_ERROR(sql, "07005", TSDB_CODE_ODBC_NO_FIELDS, ""); - return SQL_ERROR; - } - - if (ColumnNumber<=0 || ColumnNumber>nfields) { - SET_ERROR(sql, "07009", TSDB_CODE_ODBC_OUT_OF_RANGE, "invalid column number [%d]", ColumnNumber); - return SQL_ERROR; - } - - TAOS_FIELD *field = fields + ColumnNumber-1; - - switch (FieldIdentifier) { - case SQL_COLUMN_DISPLAY_SIZE: { - *NumericAttribute = (SQLLEN)do_field_display_size(field); - } break; - case SQL_COLUMN_LABEL: { - // todo: check BufferLength - size_t n = sizeof(field->name); - strncpy(CharacterAttribute, field->name, (n>BufferLength ? (size_t)BufferLength : n)); - } break; - case SQL_COLUMN_UNSIGNED: { - *NumericAttribute = SQL_FALSE; - } break; - default: { - SET_ERROR(sql, "HY091", TSDB_CODE_ODBC_OUT_OF_RANGE, - "FieldIdentifier[%d/0x%x] for Column [%d] not supported yet", - FieldIdentifier, FieldIdentifier, ColumnNumber); - return SQL_ERROR; - } break; - } - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLColAttribute(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, - SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) -{ - SQLRETURN r; - r = doSQLColAttribute(StatementHandle, ColumnNumber, FieldIdentifier, - CharacterAttribute, BufferLength, - StringLength, NumericAttribute); - return r; -} - -static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, - SQLPOINTER TargetValue, SQLLEN BufferLength, - SQLLEN *StrLen_or_Ind) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - conn_t *conn = sql->conn; - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - if (!sql->row) { - SET_ERROR(sql, "24000", TSDB_CODE_ODBC_INVALID_CURSOR, ""); - return SQL_ERROR; - } - - int nfields = taos_field_count(sql->rs); - TAOS_FIELD *fields = taos_fetch_fields(sql->rs); - - if (ColumnNumber<=0 || ColumnNumber>nfields) { - SET_ERROR(sql, "07009", TSDB_CODE_ODBC_OUT_OF_RANGE, "invalid column number [%d]", ColumnNumber); - return SQL_ERROR; - } - - if (TargetValue == NULL) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "NULL TargetValue not allowed for col [%d]", ColumnNumber); - return SQL_ERROR; - } - if (BufferLength<0) { - SET_ERROR(sql, "HY090", TSDB_CODE_ODBC_BAD_ARG, ""); - return SQL_ERROR; - } - - TAOS_FIELD *field = fields + ColumnNumber-1; - void *row = sql->row[ColumnNumber-1]; - - if (!row) { - if (!StrLen_or_Ind) { - SET_ERROR(sql, "22002", TSDB_CODE_ODBC_BAD_ARG, "NULL StrLen_or_Ind not allowed for col [%d]", ColumnNumber); - return SQL_ERROR; - } - *StrLen_or_Ind = SQL_NULL_DATA; - return SQL_SUCCESS; - } - - c_target_t target = {0}; - target.col = ColumnNumber; - target.ct = TargetType; - target.ptr = TargetValue; - target.len = BufferLength; - target.soi = StrLen_or_Ind; - - switch (field->type) { - case TSDB_DATA_TYPE_BOOL: - case TSDB_DATA_TYPE_TINYINT: - case TSDB_DATA_TYPE_SMALLINT: - case TSDB_DATA_TYPE_INT: - case TSDB_DATA_TYPE_BIGINT: { - int64_t v; - switch (field->type) { - case TSDB_DATA_TYPE_BOOL: v = *(int8_t*)row; if (v) v = 1; break; - case TSDB_DATA_TYPE_TINYINT: v = *(int8_t*)row; break; - case TSDB_DATA_TYPE_SMALLINT: v = *(int16_t*)row; break; - case TSDB_DATA_TYPE_INT: v = *(int32_t*)row; break; - case TSDB_DATA_TYPE_BIGINT: // fall through - default: v = *(int64_t*)row; break; - } - switch (target.ct) { - case SQL_C_BIT: { - CHK_CONV(0, tsdb_int64_to_bit(v, TargetValue)); - } break; - case SQL_C_TINYINT: { - CHK_CONV(0, tsdb_int64_to_tinyint(v, TargetValue)); - } break; - case SQL_C_SHORT: { - CHK_CONV(0, tsdb_int64_to_smallint(v, TargetValue)); - } break; - case SQL_C_LONG: { - CHK_CONV(0, tsdb_int64_to_int(v, TargetValue)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(0, tsdb_int64_to_bigint(v, TargetValue)); - } break; - case SQL_C_FLOAT: { - CHK_CONV(0, tsdb_int64_to_float(v, TargetValue)); - } break; - case SQL_C_DOUBLE: { - CHK_CONV(0, tsdb_int64_to_double(v, TargetValue)); - } break; - case SQL_C_CHAR: { - tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write_int64(utf8_to_client, v, (char*)TargetValue, &len); - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len; - CHK_CONV(0, code); - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - case TSDB_DATA_TYPE_FLOAT: { - float v = *(float*)row; - switch (target.ct) { - case SQL_C_FLOAT: { - *(float*)TargetValue = v; - return SQL_SUCCESS; - } break; - case SQL_C_DOUBLE: { - *(double*)TargetValue = v; - return SQL_SUCCESS; - } break; - case SQL_C_CHAR: { - tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write_double(utf8_to_client, v, (char*)TargetValue, &len); - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len; - CHK_CONV(0, code); - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - case TSDB_DATA_TYPE_DOUBLE: { - double v = *(double*)row; - switch (target.ct) { - case SQL_C_DOUBLE: { - *(double*)TargetValue = v; - return SQL_SUCCESS; - } break; - case SQL_C_CHAR: { - tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write_double(utf8_to_client, v, (char*)TargetValue, &len); - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len; - CHK_CONV(0, code); - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - case TSDB_DATA_TYPE_TIMESTAMP: { - SQL_TIMESTAMP_STRUCT ts = {0}; - int64_t v = *(int64_t*)row; - time_t t = v/1000; - struct tm vtm = {0}; - localtime_r(&t, &vtm); - ts.year = (SQLSMALLINT)(vtm.tm_year + 1900); - ts.month = (SQLUSMALLINT)(vtm.tm_mon + 1); - ts.day = (SQLUSMALLINT)(vtm.tm_mday); - ts.hour = (SQLUSMALLINT)(vtm.tm_hour); - ts.minute = (SQLUSMALLINT)(vtm.tm_min); - ts.second = (SQLUSMALLINT)(vtm.tm_sec); - ts.fraction = (SQLUINTEGER)(v%1000 * 1000000); - switch (target.ct) { - case SQL_C_SBIGINT: { - *(int64_t*)TargetValue = v; - return SQL_SUCCESS; - } break; - case SQL_C_CHAR: { - tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write_timestamp(utf8_to_client, ts, (char*)TargetValue, &len); - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len; - CHK_CONV(0, code); - } break; - case SQL_C_TYPE_TIMESTAMP: { - *(SQL_TIMESTAMP_STRUCT*)TargetValue = ts; - return SQL_SUCCESS; - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - case TSDB_DATA_TYPE_BINARY: { - size_t field_bytes = (size_t)field->bytes; - field_bytes -= VARSTR_HEADER_SIZE; - switch (target.ct) { - case SQL_C_CHAR: { - // taos cares nothing about what would be stored in 'binary' as most sql implementations do - // but the client requires to fetch it as a SQL_C_CHAR - // thus, we first try to decode binary to client charset - // if failed, we then do hex-serialization - - tsdb_conv_t *server_to_client = tsdb_conn_server_to_client(conn); - size_t slen = strnlen((const char*)row, field_bytes); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write(server_to_client, - (const char*)row, &slen, - (char*)TargetValue, &len); - if (code==TSDB_CONV_OK) { - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)((size_t)BufferLength - len); - CHK_CONV(0, code); - // code never reached here - } - - // todo: hex-serialization - const char *bad = ""; - int n = snprintf((char*)TargetValue, (size_t)BufferLength, "%s", bad); - // what if n < 0 ? - if (StrLen_or_Ind) *StrLen_or_Ind = n; - CHK_CONV(0, n>=BufferLength ? TSDB_CONV_TRUNC : TSDB_CONV_OK); - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - case TSDB_DATA_TYPE_NCHAR: { - size_t field_bytes = (size_t)field->bytes; - field_bytes -= VARSTR_HEADER_SIZE; - switch (target.ct) { - case SQL_C_CHAR: { - tsdb_conv_t *server_to_client = tsdb_conn_server_to_client(conn); - size_t slen = strnlen((const char*)row, field_bytes); - size_t len = (size_t)BufferLength; - TSDB_CONV_CODE code = tsdb_conv_write(server_to_client, - (const char*)row, &slen, - (char*)TargetValue, &len); - if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)((size_t)BufferLength - len); - CHK_CONV(0, code); - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, - "no convertion from [%s] to [%s[%d][0x%x]] for col [%d]", - taos_data_type(field->type), sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } - } - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for col [%d]", - taos_data_type(field->type), field->type, field->type, - sql_c_type(target.ct), target.ct, target.ct, ColumnNumber); - return SQL_ERROR; - } break; - } -} - -SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, - SQLPOINTER TargetValue, SQLLEN BufferLength, - SQLLEN *StrLen_or_Ind) -{ - SQLRETURN r; - r = doSQLGetData(StatementHandle, ColumnNumber, TargetType, - TargetValue, BufferLength, - StrLen_or_Ind); - return r; -} - -static SQLRETURN doSQLFetch(SQLHSTMT StatementHandle) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - sql->row = taos_fetch_row(sql->rs); - return sql->row ? SQL_SUCCESS : SQL_NO_DATA; -} - -SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) -{ - SQLRETURN r; - r = doSQLFetch(StatementHandle); - return r; -} - -static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) -{ - stack_buffer_t buffer; buffer.next = 0; - - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - conn_t *conn = sql->conn; - - NORM_STR_LENGTH(sql, StatementText, TextLength); - - if (sql->rs) { - taos_free_result(sql->rs); - sql->rs = NULL; - sql->row = NULL; - } - - if (sql->stmt) { - taos_stmt_close(sql->stmt); - sql->stmt = NULL; - } - - if (sql->params) { - free(sql->params); - sql->params = NULL; - } - sql->n_params = 0; - sql->is_insert = 0; - - do { - sql->stmt = taos_stmt_init(sql->conn->taos); - if (!sql->stmt) { - SET_ERROR(sql, "HY001", terrno, "failed to initialize TAOS statement internally"); - break; - } - - tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn); - const char *stxt = NULL; - int ok = 0; - do { - tsdb_conv(client_to_server, &buffer, (const char*)StatementText, (size_t)TextLength, &stxt, NULL); - if ((!stxt)) { - SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - - int r = taos_stmt_prepare(sql->stmt, stxt, (unsigned long)strlen(stxt)); - if (r) { - SET_ERROR(sql, "HY000", r, "failed to prepare a TAOS statement"); - break; - } - sql->is_prepared = 1; - - int is_insert = 0; - r = taos_stmt_is_insert(sql->stmt, &is_insert); - if (r) { - SET_ERROR(sql, "HY000", r, "failed to determine if a prepared-statement is of insert"); - break; - } - sql->is_insert = is_insert ? 1 : 0; - - int params = 0; - r = taos_stmt_num_params(sql->stmt, ¶ms); - if (r) { - SET_ERROR(sql, "HY000", terrno, "fetch num of statement params failed"); - break; - } - DASSERT(params>=0); - - if (params>0) { - param_bind_t *ar = (param_bind_t*)calloc(1, ((size_t)params) * sizeof(*ar)); - if (!ar) { - SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - sql->params = ar; - } - - sql->n_params = params; - - ok = 1; - } while (0); - - tsdb_conv_free(client_to_server, stxt, &buffer, (const char*)StatementText); - - if (!ok) { - taos_stmt_close(sql->stmt); - sql->stmt = NULL; - sql->is_prepared = 0; - sql->is_insert = 0; - sql->is_executed = 0; - } - } while (0); - - return sql->stmt ? SQL_SUCCESS : SQL_ERROR; -} - -SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) -{ - SQLRETURN r; - r = doSQLPrepare(StatementHandle, StatementText, TextLength); - return r; -} - -static const int yes = 1; -static const int no = 0; - -static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bind_t *param, TAOS_BIND *bind) -{ - if (!param->valid) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "parameter [@%d] not bound yet", idx+1); - return SQL_ERROR; - } - if (param->ParameterValue==NULL) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "ParameterValue [@%p] not allowed", param->ParameterValue); - return SQL_ERROR; - } - if (param->StrLen_or_Ind==NULL) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "StrLen_or_Ind [@%p] not allowed", param->StrLen_or_Ind); - return SQL_ERROR; - } - - conn_t *conn = sql->conn; - - unsigned char *paramValue = param->ParameterValue; - SQLSMALLINT valueType = param->ValueType; - SQLLEN *soi = param->StrLen_or_Ind; - - size_t offset = ((size_t)idx_row) * sql->rowlen + sql->ptr_offset; - - paramValue += offset; - soi = (SQLLEN*)((char*)soi + offset); - - - if (*soi == SQL_NULL_DATA) { - bind->is_null = (int*)&yes; - return SQL_SUCCESS; - } - bind->is_null = (int*)&no; - int tsdb_type = 0; // taos internal data tsdb_type to be bound to - int tsdb_bytes = 0; // we don't rely much on 'tsdb_bytes' here, we delay until taos to check it internally - if (sql->is_insert) { - int r = taos_stmt_get_param(sql->stmt, idx, &tsdb_type, &tsdb_bytes); - if (r) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_OUT_OF_RANGE, "parameter [@%d] not valid", idx+1); - return SQL_ERROR; - } - } else { - // we don't have correspondent data type from taos api - // we have to give a good guess here - switch (valueType) { - case SQL_C_BIT: { - tsdb_type = TSDB_DATA_TYPE_BOOL; - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - tsdb_type = TSDB_DATA_TYPE_TINYINT; - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - tsdb_type = TSDB_DATA_TYPE_SMALLINT; - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - tsdb_type = TSDB_DATA_TYPE_INT; - } break; - case SQL_C_SBIGINT: { - tsdb_type = TSDB_DATA_TYPE_BIGINT; - } break; - case SQL_C_FLOAT: { - tsdb_type = TSDB_DATA_TYPE_FLOAT; - } break; - case SQL_C_DOUBLE: { - tsdb_type = TSDB_DATA_TYPE_DOUBLE; - } break; - case SQL_C_TIMESTAMP: { - tsdb_type = TSDB_DATA_TYPE_TIMESTAMP; - } break; - case SQL_C_CHAR: { - tsdb_type = TSDB_DATA_TYPE_BINARY; - tsdb_bytes = SQL_NTS; - } break; - case SQL_C_WCHAR: { - tsdb_type = TSDB_DATA_TYPE_NCHAR; - tsdb_bytes = SQL_NTS; - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - idx+1); - return SQL_ERROR; - } break; - } - } - - // ref: https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/converting-data-from-c-to-sql-data-types?view=sql-server-ver15 - switch (tsdb_type) { - case TSDB_DATA_TYPE_BOOL: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.b); - bind->buffer = &bind->u.b; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_bit(*(int8_t*)paramValue, &bind->u.b)); - } break; - case SQL_C_TINYINT: - case SQL_C_STINYINT: { - CHK_CONV(1, tsdb_int64_to_bit(*(int8_t*)paramValue, &bind->u.b)); - } break; - case SQL_C_SHORT: - case SQL_C_SSHORT: { - CHK_CONV(1, tsdb_int64_to_bit(*(int16_t*)paramValue, &bind->u.b)); - } break; - case SQL_C_LONG: - case SQL_C_SLONG: { - CHK_CONV(1, tsdb_int64_to_bit(*(int32_t*)paramValue, &bind->u.b)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_bit(*(int64_t*)paramValue, &bind->u.b)); - } break; - case SQL_C_FLOAT: { - CHK_CONV(1, tsdb_double_to_bit(*(float*)paramValue, &bind->u.b)); - } break; - case SQL_C_DOUBLE: { - CHK_CONV(1, tsdb_double_to_bit(*(double*)paramValue, &bind->u.b)); - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_bit(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.b)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_bit(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.b)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_TINYINT: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.v1); - bind->buffer = &bind->u.v1; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_tinyint(*(int8_t*)paramValue, &bind->u.v1)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_tinyint(*(int8_t*)paramValue, &bind->u.v1)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_tinyint(*(int16_t*)paramValue, &bind->u.v1)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_tinyint(*(int32_t*)paramValue, &bind->u.v1)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_tinyint(*(int64_t*)paramValue, &bind->u.v1)); - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_tinyint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v1)); - // CHK_CONV(1, tsdb_chars_to_tinyint((const char *)paramValue, (size_t)*soi, &bind->u.v1)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_tinyint(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v1)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_SMALLINT: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.v2); - bind->buffer = &bind->u.v2; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_smallint(*(int8_t*)paramValue, &bind->u.v2)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_smallint(*(int8_t*)paramValue, &bind->u.v2)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_smallint(*(int16_t*)paramValue, &bind->u.v2)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_smallint(*(int32_t*)paramValue, &bind->u.v2)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_smallint(*(int64_t*)paramValue, &bind->u.v2)); - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_smallint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v2)); - // CHK_CONV(1, tsdb_chars_to_smallint((const char*)paramValue, (size_t)*soi, &bind->u.v2)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_smallint(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v2)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_INT: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.v4); - bind->buffer = &bind->u.v4; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_int(*(int8_t*)paramValue, &bind->u.v4)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_int(*(int8_t*)paramValue, &bind->u.v4)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_int(*(int16_t*)paramValue, &bind->u.v4)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_int(*(int32_t*)paramValue, &bind->u.v4)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_int(*(int64_t*)paramValue, &bind->u.v4)); - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_int(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v4)); - // CHK_CONV(1, tsdb_chars_to_int((const char*)paramValue, (size_t)*soi, &bind->u.v4)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_int(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v4)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_BIGINT: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.v8); - bind->buffer = &bind->u.v8; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_bigint(*(int8_t*)paramValue, &bind->u.v8)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_bigint(*(int8_t*)paramValue, &bind->u.v8)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_bigint(*(int16_t*)paramValue, &bind->u.v8)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_bigint(*(int32_t*)paramValue, &bind->u.v8)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_bigint(*(int64_t*)paramValue, &bind->u.v8)); - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_bigint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8)); - // CHK_CONV(1, tsdb_chars_to_bigint((const char*)paramValue, (size_t)*soi, &bind->u.v8)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_bigint(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_FLOAT: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.f4); - bind->buffer = &bind->u.f4; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_float(*(int8_t*)paramValue, &bind->u.f4)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_float(*(int8_t*)paramValue, &bind->u.f4)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_float(*(int16_t*)paramValue, &bind->u.f4)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_float(*(int32_t*)paramValue, &bind->u.f4)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_float(*(int64_t*)paramValue, &bind->u.f4)); - } break; - case SQL_C_FLOAT: { - bind->u.f4 = *(float*)paramValue; - } break; - case SQL_C_DOUBLE: { - bind->u.f4 = (float)*(double*)paramValue; - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_float(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f4)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_float(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f4)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_DOUBLE: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.f8); - bind->buffer = &bind->u.f8; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_BIT: { - CHK_CONV(1, tsdb_int64_to_double(*(int8_t*)paramValue, &bind->u.f8)); - } break; - case SQL_C_STINYINT: - case SQL_C_TINYINT: { - CHK_CONV(1, tsdb_int64_to_double(*(int8_t*)paramValue, &bind->u.f8)); - } break; - case SQL_C_SSHORT: - case SQL_C_SHORT: { - CHK_CONV(1, tsdb_int64_to_double(*(int16_t*)paramValue, &bind->u.f8)); - } break; - case SQL_C_SLONG: - case SQL_C_LONG: { - CHK_CONV(1, tsdb_int64_to_double(*(int32_t*)paramValue, &bind->u.f8)); - } break; - case SQL_C_SBIGINT: { - CHK_CONV(1, tsdb_int64_to_double(*(int64_t*)paramValue, &bind->u.f8)); - } break; - case SQL_C_FLOAT: { - bind->u.f8 = *(float*)paramValue; - } break; - case SQL_C_DOUBLE: { - bind->u.f8 = *(double*)paramValue; - } break; - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - CHK_CONV(1, tsdb_conv_chars_to_double(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f8)); - // CHK_CONV(1, tsdb_chars_to_double((const char*)paramValue, (size_t)*soi, &bind->u.f8)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_double(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f8)); - } break; - case SQL_C_USHORT: - case SQL_C_ULONG: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_TIMESTAMP: { - bind->buffer_type = tsdb_type; - bind->buffer_length = sizeof(bind->u.v8); - bind->buffer = &bind->u.v8; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_CHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_timestamp_ts(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8)); - } break; - case SQL_C_WCHAR: { - stack_buffer_t buffer; buffer.next = 0; - tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn); - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - CHK_CONV(1, tsdb_conv_chars_to_timestamp_ts(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8)); - } break; - case SQL_C_SBIGINT: { - int64_t t = *(int64_t*)paramValue; - bind->u.v8 = t; - } break; - case SQL_C_TYPE_TIMESTAMP: { - SQL_TIMESTAMP_STRUCT ts = *(SQL_TIMESTAMP_STRUCT*)paramValue; - struct tm vtm = {0}; - vtm.tm_year = ts.year - 1900; - vtm.tm_mon = ts.month - 1; - vtm.tm_mday = ts.day; - vtm.tm_hour = ts.hour; - vtm.tm_min = ts.minute; - vtm.tm_sec = ts.second; - int64_t t = (int64_t) mktime(&vtm); - if (t==-1) { - CHK_CONV(1, TSDB_CONV_NOT_VALID_TS); - // code never reached here - } - bind->u.ts = t * 1000 + ts.fraction / 1000000; - } break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - case SQL_C_USHORT: - case SQL_C_LONG: - case SQL_C_SLONG: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: - case SQL_C_UTINYINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_BINARY: { - bind->buffer_type = tsdb_type; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_WCHAR: { - // taos cares nothing about what would be stored in 'binary' as most sql implementations do - // thus, we just copy it as is - // it's caller's responsibility to maintain data-consistency - // if he/she is going to use 'binary' to store characters - // taos might extend it's sql syntax to let user specify - // what charset is to be used for specific 'binary' field when - // table is to be created - // in such way, 'binary' would be 'internationalized' - // but actually speaking, normally, 'char' field is a better - // one for this purpose - size_t slen = (size_t)*soi; - DASSERT(slen != SQL_NTS); - bind->u.bin = (unsigned char*)malloc(slen + 1); // add null-terminator, just for case of use - if (!bind->u.bin) { - CHK_CONV(1, TSDB_CONV_OOM); - // code never reached here - } - memcpy(bind->u.bin, paramValue, slen); - bind->buffer_length = slen; - bind->buffer = bind->u.bin; - CHK_CONV(1, TSDB_CONV_OK); - - // tsdb_conv_t *utf16_to_server = tsdb_conn_utf16_to_server(conn); - // size_t slen = (size_t)*soi; - // DASSERT(slen != SQL_NTS); - // const char *buf = NULL; - // size_t blen = 0; - // TSDB_CONV_CODE code = tsdb_conv(utf16_to_server, NULL, (const char *)paramValue, slen, &buf, &blen); - // if (code==TSDB_CONV_OK) { - // if (buf!=(const char*)paramValue) { - // bind->allocated = 1; - // } - // bind->u.bin = (unsigned char*)buf; - // bind->buffer_length = blen; - // bind->buffer = bind->u.bin; - // } - // CHK_CONV(1, code); - } break; - case SQL_C_CHAR: { - // taos cares nothing about what would be stored in 'binary' as most sql implementations do - // thus, we just copy it as is - // it's caller's responsibility to maintain data-consistency - // if he/she is going to use 'binary' to store characters - // taos might extend it's sql syntax to let user specify - // what charset is to be used for specific 'binary' field when - // table is to be created - // in such way, 'binary' would be 'internationalized' - // but actually speaking, normally, 'char' field is a better - // one for this purpose - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - // we can not use strndup, because ODBC client might pass in a buffer without null-terminated - bind->u.bin = (unsigned char*)malloc(slen + 1); // add null-terminator, just for case of use - if (!bind->u.bin) { - CHK_CONV(1, TSDB_CONV_OOM); - // code never reached here - } - memcpy(bind->u.bin, paramValue, slen); - bind->buffer_length = slen; - bind->buffer = bind->u.bin; - CHK_CONV(1, TSDB_CONV_OK); - // code never reached here - - // tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn); - // size_t slen = (size_t)*soi; - // if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - // const char *buf = NULL; - // size_t blen = 0; - // TSDB_CONV_CODE code = tsdb_conv(client_to_server, NULL, (const char *)paramValue, slen, &buf, &blen); - // if (code==TSDB_CONV_OK) { - // if (buf!=(const char*)paramValue) { - // bind->allocated = 1; - // } - // bind->u.bin = (unsigned char*)buf; - // bind->buffer_length = blen; - // bind->buffer = bind->u.bin; - // } - // CHK_CONV(1, code); - } break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - case SQL_C_USHORT: - case SQL_C_LONG: - case SQL_C_SLONG: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: - case SQL_C_UTINYINT: - case SQL_C_SBIGINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: // we don't provide auto-converstion - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - case TSDB_DATA_TYPE_NCHAR: { - bind->buffer_type = tsdb_type; - bind->length = &bind->buffer_length; - switch (valueType) { - case SQL_C_WCHAR: { - tsdb_conv_t *utf16_to_server = tsdb_conn_utf16_to_server(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - const char *buf = NULL; - size_t blen = 0; - TSDB_CONV_CODE code = tsdb_conv(utf16_to_server, NULL, (const char *)paramValue, slen, &buf, &blen); - if (code==TSDB_CONV_OK) { - if (buf!=(const char*)paramValue) { - bind->allocated = 1; - } - bind->u.nchar = (char*)buf; - bind->buffer_length = blen; - bind->buffer = bind->u.nchar; - } - CHK_CONV(1, code); - } break; - case SQL_C_CHAR: { - tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn); - size_t slen = (size_t)*soi; - if (slen==SQL_NTS) slen = strlen((const char*)paramValue); - const char *buf = NULL; - size_t blen = 0; - TSDB_CONV_CODE code = tsdb_conv(client_to_server, NULL, (const char *)paramValue, slen, &buf, &blen); - if (code==TSDB_CONV_OK) { - if (buf!=(const char*)paramValue) { - bind->allocated = 1; - } - bind->u.bin = (unsigned char*)buf; - bind->buffer_length = blen; - bind->buffer = bind->u.bin; - } - CHK_CONV(1, code); - } break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - case SQL_C_USHORT: - case SQL_C_LONG: - case SQL_C_SLONG: - case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: - case SQL_C_UTINYINT: - case SQL_C_SBIGINT: - case SQL_C_UBIGINT: - case SQL_C_BINARY: - case SQL_C_DATE: - case SQL_C_TIME: - case SQL_C_TIMESTAMP: - case SQL_C_TYPE_DATE: - case SQL_C_TYPE_TIME: - case SQL_C_TYPE_TIMESTAMP: // we don't provide auto-converstion - case SQL_C_NUMERIC: - case SQL_C_GUID: - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - } break; - default: { - SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_OUT_OF_RANGE, - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", - sql_c_type(valueType), valueType, valueType, - taos_data_type(tsdb_type), tsdb_type, tsdb_type, idx+1); - return SQL_ERROR; - } break; - } - return SQL_SUCCESS; -} - -static SQLRETURN do_bind_batch(sql_t *sql, int idx_row, TAOS_BIND *binds) -{ - for (int j=0; jn_params; ++j) { - SQLRETURN r = do_bind_param_value(sql, idx_row, j, sql->params+j, binds+j); - if (r==SQL_SUCCESS) continue; - return r; - } - if (sql->n_params > 0) { - int tr = 0; - PROFILE(tr = taos_stmt_bind_param(sql->stmt, binds)); - if (tr) { - SET_ERROR(sql, "HY000", tr, "failed to bind parameters[%d in total]", sql->n_params); - return SQL_ERROR; - } - - if (sql->is_insert) { - int r = 0; - PROFILE(r = taos_stmt_add_batch(sql->stmt)); - if (r) { - SET_ERROR(sql, "HY000", r, "failed to add batch"); - return SQL_ERROR; - } - } - } - return SQL_SUCCESS; -} - -static SQLRETURN do_execute(sql_t *sql) -{ - int tr = TSDB_CODE_SUCCESS; - if (sql->n_rows==0) sql->n_rows = 1; - for (int i=0; in_rows; ++i) { - TAOS_BIND *binds = NULL; - if (sql->n_params>0) { - binds = (TAOS_BIND*)calloc((size_t)sql->n_params, sizeof(*binds)); - if (!binds) { - SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); - return SQL_ERROR; - } - } - - SQLRETURN r = do_bind_batch(sql, i, binds); - - if (binds) { - for (int i = 0; in_params; ++i) { - TAOS_BIND *bind = binds + i; - if (bind->allocated) { - free(bind->u.nchar); - bind->u.nchar = NULL; - } - } - free(binds); - } - - if (r) return r; - } - - PROFILE(tr = taos_stmt_execute(sql->stmt)); - if (tr) { - SET_ERROR(sql, "HY000", tr, "failed to execute statement"); - return SQL_ERROR; - } - - sql->is_executed = 1; - // if (sql->is_insert) return SQL_SUCCESS; - - SQLRETURN r = SQL_SUCCESS; - PROFILE(sql->rs = taos_stmt_use_result(sql->stmt)); - CHK_RS(r, sql, "failed to use result"); - - return r; -} - -static SQLRETURN doSQLExecute(SQLHSTMT StatementHandle) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_ERROR; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->stmt) { - SET_ERROR(sql, "HY010", TSDB_CODE_ODBC_STATEMENT_NOT_READY, ""); - return SQL_ERROR; - } - - if (sql->rs) { - taos_free_result(sql->rs); - sql->rs = NULL; - sql->row = NULL; - } - - SQLRETURN r = do_execute(sql); - - return r; -} - -SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) -{ - SQLRETURN r; - PROFILE(r = doSQLExecute(StatementHandle)); - return r; -} - -static SQLRETURN doSQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, - SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, - SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength) -{ - switch (DiagIdentifier) { - case SQL_DIAG_CLASS_ORIGIN: { - *StringLength = 0; - } break; - } - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, - SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, - SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength) -{ - SQLRETURN r; - r = doSQLGetDiagField(HandleType, Handle, - RecNumber, DiagIdentifier, - DiagInfo, BufferLength, - StringLength); - return r; -} - -static SQLRETURN doSQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, - SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, - SQLINTEGER *NativeError, SQLCHAR *MessageText, - SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) -{ - if (RecNumber>1) return SQL_NO_DATA; - - switch (HandleType) { - case SQL_HANDLE_ENV: { - env_t *env = (env_t*)Handle; - if (!env) break; - FILL_ERROR(env); - return SQL_SUCCESS; - } break; - case SQL_HANDLE_DBC: { - conn_t *conn = (conn_t*)Handle; - if (!conn) break; - FILL_ERROR(conn); - return SQL_SUCCESS; - } break; - case SQL_HANDLE_STMT: { - sql_t *sql = (sql_t*)Handle; - if (!sql) break; - FILL_ERROR(sql); - return SQL_SUCCESS; - } break; - default: { - } break; - } - - // how to return error? - return SQL_ERROR; -} - -SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, - SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, - SQLINTEGER *NativeError, SQLCHAR *MessageText, - SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) -{ - SQLRETURN r; - r = doSQLGetDiagRec(HandleType, Handle, - RecNumber, Sqlstate, - NativeError, MessageText, - BufferLength, TextLength); - return r; -} - -static SQLRETURN doSQLBindParameter( - SQLHSTMT StatementHandle, - SQLUSMALLINT ParameterNumber, - SQLSMALLINT fParamType, - SQLSMALLINT ValueType, - SQLSMALLINT ParameterType, - SQLULEN LengthPrecision, - SQLSMALLINT ParameterScale, - SQLPOINTER ParameterValue, - SQLLEN cbValueMax, // ignore for now, since only SQL_PARAM_INPUT is supported now - SQLLEN *StrLen_or_Ind) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->stmt) { - SET_ERROR(sql, "HY010", TSDB_CODE_ODBC_STATEMENT_NOT_READY, ""); - return SQL_ERROR; - } - - if (ParameterNumber<=0 || ParameterNumber>sql->n_params) { - SET_ERROR(sql, "07009", TSDB_CODE_ODBC_BAD_ARG, - "parameter [@%d] invalid", ParameterNumber); - return SQL_ERROR; - } - - if (fParamType != SQL_PARAM_INPUT) { - SET_ERROR(sql, "HY105", TSDB_CODE_ODBC_NOT_SUPPORT, "non-input parameter [@%d] not supported yet", ParameterNumber); - return SQL_ERROR; - } - - if (ValueType == SQL_C_DEFAULT) { - SET_ERROR(sql, "HY003", TSDB_CODE_ODBC_NOT_SUPPORT, "default value for parameter [@%d] not supported yet", ParameterNumber); - return SQL_ERROR; - } - - if (!is_valid_sql_c_type(ValueType)) { - SET_ERROR(sql, "HY003", TSDB_CODE_ODBC_NOT_SUPPORT, - "SQL_C_TYPE [%s/%d/0x%x] for parameter [@%d] unknown", - sql_c_type(ValueType), ValueType, ValueType, ParameterNumber); - return SQL_ERROR; - } - - if (!is_valid_sql_sql_type(ParameterType)) { - SET_ERROR(sql, "HY004", TSDB_CODE_ODBC_NOT_SUPPORT, - "SQL_TYPE [%s/%d/0x%x] for parameter [@%d] unknown", - sql_c_type(ParameterType), ParameterType, ParameterType, ParameterNumber); - return SQL_ERROR; - } - - if (ParameterValue==NULL) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "ParameterValue [@%p] not allowed", ParameterValue); - return SQL_ERROR; - } - - if (StrLen_or_Ind==NULL) { - SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "StrLen_or_Ind [@%p] not allowed", StrLen_or_Ind); - return SQL_ERROR; - } - - param_bind_t *pb = sql->params + ParameterNumber - 1; - - pb->ParameterNumber = ParameterNumber; - pb->ValueType = ValueType; - pb->ParameterType = ParameterType; - pb->LengthPrecision = LengthPrecision; - pb->ParameterScale = ParameterScale; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - - pb->valid = 1; - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLBindParameter( - SQLHSTMT StatementHandle, - SQLUSMALLINT ParameterNumber, - SQLSMALLINT fParamType, - SQLSMALLINT ValueType, - SQLSMALLINT ParameterType, - SQLULEN LengthPrecision, - SQLSMALLINT ParameterScale, - SQLPOINTER ParameterValue, - SQLLEN cbValueMax, // ignore for now, since only SQL_PARAM_INPUT is supported now - SQLLEN *StrLen_or_Ind) -{ - SQLRETURN r; - r = doSQLBindParameter(StatementHandle, ParameterNumber, fParamType, ValueType, ParameterType, - LengthPrecision, ParameterScale, ParameterValue, cbValueMax, StrLen_or_Ind); - return r; -} - -static SQLRETURN doSQLDriverConnect( - SQLHDBC hdbc, - SQLHWND hwnd, - SQLCHAR *szConnStrIn, - SQLSMALLINT cbConnStrIn, - SQLCHAR *szConnStrOut, - SQLSMALLINT cbConnStrOutMax, - SQLSMALLINT *pcbConnStrOut, - SQLUSMALLINT fDriverCompletion) -{ - conn_t *conn = (conn_t*)hdbc; - if (!conn) return SQL_INVALID_HANDLE; - - if (conn->taos) { - SET_ERROR(conn, "08002", TSDB_CODE_ODBC_CONNECTION_BUSY, "connection still in use"); - return SQL_ERROR; - } - - if (fDriverCompletion!=SQL_DRIVER_NOPROMPT) { - SET_ERROR(conn, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, "option[%d] other than SQL_DRIVER_NOPROMPT not supported yet", fDriverCompletion); - return SQL_ERROR; - } - - NORM_STR_LENGTH(conn, szConnStrIn, cbConnStrIn); - - // DSN=; UID=; PWD= - - const char *connStr = SDUP(szConnStrIn, cbConnStrIn); - - conn_val_t val = {0}; - - do { - if (szConnStrIn && !connStr) { - SET_ERROR(conn, "HY001", TSDB_CODE_ODBC_OOM, ""); - break; - } - - int n = todbc_parse_conn_string((const char *)connStr, &val); - if (n) { - SET_ERROR(conn, "HY000", TSDB_CODE_ODBC_BAD_CONNSTR, "unrecognized connection string: [%s]", (const char*)szConnStrIn); - break; - } - char *ip = NULL; - int port = 0; - if (val.server) { - char *p = strchr(val.server, ':'); - if (p) { - ip = strndup(val.server, (size_t)(p-val.server)); - port = atoi(p+1); - } - } - - if ((val.cli_enc && strcmp(val.cli_enc, conn->client_enc)) || - (val.svr_enc && strcmp(val.svr_enc, conn->server_enc)) ) - { - tsdb_conn_close_convs(conn); - if (val.cli_enc) { - snprintf(conn->client_enc, sizeof(conn->client_enc), "%s", val.cli_enc); - } - if (val.svr_enc) { - snprintf(conn->server_enc, sizeof(conn->server_enc), "%s", val.svr_enc); - } - } - - // TODO: data-race - // TODO: shall receive ip/port from odbc.ini - // shall we support non-ansi uid/pwd/db etc? - conn->taos = taos_connect(ip ? ip : "localhost", val.uid, val.pwd, val.db, (uint16_t)port); - free(ip); ip = NULL; - if (!conn->taos) { - SET_ERROR(conn, "HY000", terrno, "failed to connect to data source"); - break; - } - - if (szConnStrOut) { - snprintf((char*)szConnStrOut, (size_t)cbConnStrOutMax, "%s", connStr); - } - if (pcbConnStrOut) { - *pcbConnStrOut = cbConnStrIn; - } - } while (0); - - conn_val_reset(&val); - - SFRE(connStr, szConnStrIn, cbConnStrIn); - - return conn->taos ? SQL_SUCCESS : SQL_ERROR; -} - -SQLRETURN SQL_API SQLDriverConnect( - SQLHDBC hdbc, - SQLHWND hwnd, - SQLCHAR *szConnStrIn, - SQLSMALLINT cbConnStrIn, - SQLCHAR *szConnStrOut, - SQLSMALLINT cbConnStrOutMax, - SQLSMALLINT *pcbConnStrOut, - SQLUSMALLINT fDriverCompletion) -{ - SQLRETURN r; - r = doSQLDriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); - return r; -} - -static SQLRETURN doSQLSetConnectAttr(SQLHDBC ConnectionHandle, - SQLINTEGER Attribute, SQLPOINTER Value, - SQLINTEGER StringLength) -{ - conn_t *conn = (conn_t*)ConnectionHandle; - if (!conn) return SQL_INVALID_HANDLE; - - if (Attribute != SQL_ATTR_AUTOCOMMIT) { - SET_ERROR(conn, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, "Attribute other than SQL_ATTR_AUTOCOMMIT not supported yet"); - return SQL_ERROR; - } - if (Value != (SQLPOINTER)SQL_AUTOCOMMIT_ON) { - SET_ERROR(conn, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT, "Attribute Value other than SQL_AUTOCOMMIT_ON not supported yet[%p]", Value); - return SQL_ERROR; - } - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC ConnectionHandle, - SQLINTEGER Attribute, SQLPOINTER Value, - SQLINTEGER StringLength) -{ - SQLRETURN r; - r = doSQLSetConnectAttr(ConnectionHandle, Attribute, Value, StringLength); - return r; -} - -static SQLRETURN doSQLDescribeCol(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, - SQLSMALLINT BufferLength, SQLSMALLINT *NameLength, - SQLSMALLINT *DataType, SQLULEN *ColumnSize, - SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->rs) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, ""); - return SQL_ERROR; - } - - int nfields = taos_field_count(sql->rs); - TAOS_FIELD *fields = taos_fetch_fields(sql->rs); - - if (ColumnNumber<=0 || ColumnNumber>nfields) { - SET_ERROR(sql, "07009", TSDB_CODE_ODBC_OUT_OF_RANGE, "invalid column number [%d]", ColumnNumber); - return SQL_ERROR; - } - if (BufferLength<0) { - SET_ERROR(sql, "HY090", TSDB_CODE_ODBC_BAD_ARG, ""); - return SQL_ERROR; - } - - TAOS_FIELD *field = fields + ColumnNumber - 1; - if (ColumnName) { - size_t n = sizeof(field->name); - if (n>BufferLength) n = (size_t)BufferLength; - strncpy((char*)ColumnName, field->name, n); - } - if (NameLength) { - *NameLength = (SQLSMALLINT)strnlen(field->name, sizeof(field->name)); - } - if (ColumnSize) *ColumnSize = (SQLULEN)field->bytes; - if (DecimalDigits) *DecimalDigits = 0; - - if (DataType) { - switch (field->type) { - case TSDB_DATA_TYPE_BOOL: { - *DataType = SQL_TINYINT; - } break; - - case TSDB_DATA_TYPE_TINYINT: { - *DataType = SQL_TINYINT; - } break; - - case TSDB_DATA_TYPE_SMALLINT: { - *DataType = SQL_SMALLINT; - } break; - - case TSDB_DATA_TYPE_INT: { - *DataType = SQL_INTEGER; - } break; - - case TSDB_DATA_TYPE_BIGINT: { - *DataType = SQL_BIGINT; - } break; - - case TSDB_DATA_TYPE_FLOAT: { - *DataType = SQL_FLOAT; - } break; - - case TSDB_DATA_TYPE_DOUBLE: { - *DataType = SQL_DOUBLE; - } break; - - case TSDB_DATA_TYPE_TIMESTAMP: { - *DataType = SQL_TIMESTAMP; - if (ColumnSize) *ColumnSize = sizeof(SQL_TIMESTAMP_STRUCT); - if (DecimalDigits) *DecimalDigits = 0; - } break; - - case TSDB_DATA_TYPE_NCHAR: { - *DataType = SQL_CHAR; // unicode ? - if (ColumnSize) *ColumnSize -= VARSTR_HEADER_SIZE; - } break; - - case TSDB_DATA_TYPE_BINARY: { - *DataType = SQL_CHAR; - if (ColumnSize) *ColumnSize -= VARSTR_HEADER_SIZE; - } break; - - default: - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, - "unknown [%s[%d/0x%x]]", taos_data_type(field->type), field->type, field->type); - return SQL_ERROR; - break; - } - } - if (Nullable) { - *Nullable = SQL_NULLABLE_UNKNOWN; - } - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLDescribeCol(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, - SQLSMALLINT BufferLength, SQLSMALLINT *NameLength, - SQLSMALLINT *DataType, SQLULEN *ColumnSize, - SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) -{ - SQLRETURN r; - r = doSQLDescribeCol(StatementHandle, ColumnNumber, ColumnName, - BufferLength, NameLength, - DataType, ColumnSize, - DecimalDigits, Nullable); - return r; -} - -static SQLRETURN doSQLNumParams(SQLHSTMT hstmt, SQLSMALLINT *pcpar) -{ - sql_t *sql = (sql_t*)hstmt; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->stmt) { - SET_ERROR(sql, "HY010", TSDB_CODE_ODBC_STATEMENT_NOT_READY, ""); - return SQL_ERROR; - } - - int insert = 0; - int r = taos_stmt_is_insert(sql->stmt, &insert); - if (r) { - SET_ERROR(sql, "HY000", terrno, ""); - return SQL_ERROR; - } - // if (!insert) { - // SET_ERROR(sql, "HY000", terrno, "taos does not provide count of parameters for statement other than insert"); - // return SQL_ERROR; - // } - - int params = 0; - r = taos_stmt_num_params(sql->stmt, ¶ms); - if (r) { - SET_ERROR(sql, "HY000", terrno, "fetch num of statement params failed"); - return SQL_ERROR; - } - - if (pcpar) *pcpar = (SQLSMALLINT)params; - - return SQL_SUCCESS; -} - -SQLRETURN SQL_API SQLNumParams(SQLHSTMT hstmt, SQLSMALLINT *pcpar) -{ - SQLRETURN r; - r = doSQLNumParams(hstmt, pcpar); - return r; -} - -static SQLRETURN doSQLSetStmtAttr(SQLHSTMT StatementHandle, - SQLINTEGER Attribute, SQLPOINTER Value, - SQLINTEGER StringLength) -{ - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_INVALID_HANDLE; - - CHK_CONN(sql); - CHK_CONN_TAOS(sql); - - if (!sql->stmt) { - SET_ERROR(sql, "HY010", TSDB_CODE_ODBC_STATEMENT_NOT_READY, ""); - return SQL_ERROR; - } - - if (sql->is_executed) { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "change attr after executing statement not supported yet"); - return SQL_ERROR; - } - - switch (Attribute) { - case SQL_ATTR_PARAM_BIND_TYPE: { - SQLULEN val = (SQLULEN)Value; - if (val==SQL_BIND_BY_COLUMN) { - sql->rowlen = 0; - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "SQL_ATTR_PARAM_BIND_TYPE/SQL_BIND_BY_COLUMN"); - return SQL_ERROR; - } - sql->rowlen = val; - return SQL_SUCCESS; - } break; - case SQL_ATTR_PARAMSET_SIZE: { - SQLULEN val = (SQLULEN)Value; - DASSERT(val>0); - sql->n_rows = val; - return SQL_SUCCESS; - } break; - case SQL_ATTR_PARAM_BIND_OFFSET_PTR: { - if (Value) { - SQLULEN val = *(SQLULEN*)Value; - sql->ptr_offset = val; - } else { - sql->ptr_offset = 0; - } - return SQL_SUCCESS; - } break; - default: { - SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "Attribute:%d", Attribute); - } break; - } - return SQL_ERROR; -} - -SQLRETURN SQL_API SQLSetStmtAttr(SQLHSTMT StatementHandle, - SQLINTEGER Attribute, SQLPOINTER Value, - SQLINTEGER StringLength) -{ - SQLRETURN r; - r = doSQLSetStmtAttr(StatementHandle, Attribute, Value, StringLength); - return r; -} - -#ifdef _MSC_VER - -#define POST_INSTALLER_ERROR(hwndParent, code, fmt, ...) \ -do { \ - char buf[4096]; \ - snprintf(buf, sizeof(buf), "%s[%d]%s():" fmt "", \ - basename((char*)__FILE__), __LINE__, __func__, \ - ##__VA_ARGS__); \ - SQLPostInstallerError(code, buf); \ - if (hwndParent) { \ - MessageBox(hwndParent, buf, "Error", MB_OK|MB_ICONEXCLAMATION); \ - } \ -} while (0) - -typedef struct kv_s kv_t; -struct kv_s { - char *line; - size_t val; -}; - -static BOOL get_driver_dll_path(HWND hwndParent, char *buf, size_t len) -{ - HMODULE hm = NULL; - - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (LPCSTR) &ConfigDSN, &hm) == 0) - { - int ret = GetLastError(); - POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "GetModuleHandle failed, error = %d\n", ret); - return FALSE; - } - if (GetModuleFileName(hm, buf, (DWORD)len) == 0) - { - int ret = GetLastError(); - POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "GetModuleFileName failed, error = %d\n", ret); - return FALSE; - } - return TRUE; -} - -static BOOL doDSNAdd(HWND hwndParent, LPCSTR lpszDriver, LPCSTR lpszAttributes) -{ - BOOL r = TRUE; - - kv_t *kvs = NULL; - - kv_t dsn = {0}; - char *line = NULL; - - do { - char driver_dll[MAX_PATH + 1]; - r = get_driver_dll_path(hwndParent, driver_dll, sizeof(driver_dll)); - if (!r) break; - - dsn.line = strdup("DSN=TAOS_DEMO"); - if (!dsn.line) { r = FALSE; break; } - - const char *p = lpszAttributes; - int ikvs = 0; - while (p && *p) { - line = strdup(p); - if (!line) { r = FALSE; break; } - char *v = strchr(line, '='); - if (!v) { r = FALSE; break; } - - if (strstr(line, "DSN")==line) { - if (dsn.line) { - free(dsn.line); - dsn.line = NULL; - dsn.val = 0; - } - dsn.line = line; - line = NULL; - } else { - kv_t *t = (kv_t*)realloc(kvs, (ikvs+1)*sizeof(*t)); - if (!t) { r = FALSE; free(line); break; } - t[ikvs].line = line; - *v = '\0'; - if (v) t[ikvs].val = v - line + 1; - line = NULL; - - kvs = t; - ++ikvs; - } - - p += strlen(p) + 1; - } - - if (hwndParent) { - MessageBox(hwndParent, "Please use odbcconf to add DSN for TAOS ODBC Driver", "Warning!", MB_OK|MB_ICONEXCLAMATION); - } - if (!r) break; - - char *v = NULL; - v = strchr(dsn.line, '='); - if (!v) { r = FALSE; break; } - *v = '\0'; - dsn.val = v - dsn.line + 1; - - if ((!dsn.line)) { - if (!r) POST_INSTALLER_ERROR(hwndParent, ODBC_ERROR_REQUEST_FAILED, "lack of either DSN or Driver"); - } else { - if (r) r = SQLWritePrivateProfileString("ODBC Data Sources", dsn.line+dsn.val, lpszDriver, "Odbc.ini"); - if (r) r = SQLWritePrivateProfileString(dsn.line+dsn.val, "Driver", driver_dll, "Odbc.ini"); - } - - for (int i=0; r && itype) { - case TSDB_DATA_TYPE_TINYINT: - return 5; - break; - - case TSDB_DATA_TYPE_SMALLINT: - return 7; - break; - - case TSDB_DATA_TYPE_INT: - return 12; - break; - - case TSDB_DATA_TYPE_BIGINT: - return 22; - break; - - case TSDB_DATA_TYPE_FLOAT: { - return 12; - } break; - - case TSDB_DATA_TYPE_DOUBLE: { - return 20; - } break; - - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_NCHAR: { - return 3*((size_t)field->bytes - VARSTR_HEADER_SIZE) + 2; - } break; - - case TSDB_DATA_TYPE_TIMESTAMP: - return 26; - break; - - case TSDB_DATA_TYPE_BOOL: - return 7; - default: - break; - } - - return 10; -} - - - diff --git a/src/connector/odbc/src/todbc.def b/src/connector/odbc/src/todbc.def index 1e080f0198..2485e5df11 100644 --- a/src/connector/odbc/src/todbc.def +++ b/src/connector/odbc/src/todbc.def @@ -3,13 +3,19 @@ SQLAllocEnv SQLFreeEnv SQLAllocConnect SQLFreeConnect +SQLGetEnvAttr +SQLSetEnvAttr +SQLGetConnectAttr +SQLGetConnectOption +SQLGetInfo SQLConnect SQLDisconnect SQLAllocStmt SQLAllocHandle +SQLFreeHandle SQLFreeStmt SQLExecDirect -SQLExecDirectW +;SQLExecDirectW SQLNumResultCols SQLRowCount SQLColAttribute @@ -17,14 +23,45 @@ SQLGetData SQLFetch SQLPrepare SQLExecute -SQLGetDiagField +SQLParamData +SQLPutData +;SQLGetDiagField SQLGetDiagRec SQLBindParameter +SQLDescribeParam SQLDriverConnect SQLSetConnectAttr SQLDescribeCol +SQLBindCol SQLNumParams SQLSetStmtAttr +SQLBindParam +SQLCancel +SQLCancelHandle +SQLCloseCursor +SQLColumns +SQLCopyDesc +SQLDataSources +SQLEndTran +;SQLError +SQLFetchScroll +SQLGetCursorName +SQLGetDescField +SQLGetDescRec +;SQLGetFunctions +SQLGetStmtAttr +SQLGetStmtOption +SQLGetTypeInfo +SQLSetConnectOption +SQLSetCursorName +SQLSetDescField +SQLSetDescRec +SQLSetParam +SQLSetStmtOption +SQLSpecialColumns +SQLStatistics +SQLTables +SQLTransact ConfigDSN ConfigTranslator ConfigDriver diff --git a/src/connector/odbc/src/todbc_buf.c b/src/connector/odbc/src/todbc_buf.c new file mode 100644 index 0000000000..1fce74299c --- /dev/null +++ b/src/connector/odbc/src/todbc_buf.c @@ -0,0 +1,410 @@ +/* + * 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 "todbc_buf.h" + +#include "todbc_list.h" +#include "todbc_log.h" +#include "todbc_tls.h" + +#include +#include + +#define BLOCK_SIZE (1024*16) + +// alignment for holding whatever struct would be +#define ALIGN(size) ((size==0?1:size) + sizeof(size_t) - 1) / sizeof(size_t) * sizeof(size_t); + +typedef struct buf_rec_s buf_rec_t; +typedef struct buf_block_s buf_block_t; + +struct buf_rec_s { + size_t size; // payload size couting from ptr[0] + buf_block_t *owner; + char ptr[0]; // place-holder +}; + +#define PTR_OFFSET() ((size_t)(((buf_rec_t*)0)->ptr)) + +struct buf_block_s { + todbc_buf_t *owner; + size_t cap; // total payload space available for allocation + size_t ptr; // beginning of free space + char base[0]; // place-holder +}; + +#define BASE_OFFSET() ((size_t)(((buf_block_t*)0)->base)) + +struct todbc_buf_s { + char buf[BLOCK_SIZE]; + buf_block_t *block; // mapped to &buf[0] + todbc_list_t *list; // dynamic allocated blocks list +}; + +#define BASE_STATIC(block) (block->owner->buf + BASE_OFFSET()==block->base) + + +typedef struct arg_s arg_t; +struct arg_s { + todbc_buf_t *buf; + + // input + char *arg_ptr; + size_t arg_size; + buf_rec_t *arg_rec; + size_t arg_align; + + // output + buf_rec_t *rec; +}; + +static buf_rec_t* ptr_rec(todbc_buf_t *buf, void *ptr) { + char *p = (char*)ptr; + char *begin = p-PTR_OFFSET(); + buf_rec_t *rec = (buf_rec_t*)begin; + OILE(rec, ""); + OILE(rec->size, ""); + OILE((rec->size)%sizeof(void*)==0, ""); + buf_block_t *block = rec->owner; + OILE(block, ""); + OILE(block->owner==buf, ""); + OILE(block->base, ""); + + char *end = begin + sizeof(buf_rec_t) + rec->size; + OILE(begin>=block->base, ""); + OILE(end<=block->base+block->ptr, ""); + + return rec; +} + +static buf_block_t* buf_block_create(size_t align); +static buf_rec_t* buf_block_realloc(buf_block_t *block, arg_t *arg); +static void buf_block_free(buf_block_t *block); +static void buf_block_reclaim(buf_block_t *block); + +#define ALLOC_LIST() do { \ + if (buf->list) break; \ + todbc_list_conf_t conf = {0}; \ + conf.arg = buf; \ + conf.val_free = do_free_buf_block; \ + buf->list = todbc_list_create(conf); \ +} while (0) + + +todbc_buf_t* todbc_buf_create(void) { + todbc_buf_t *buf = (todbc_buf_t*)calloc(1, sizeof(*buf)); + if (!buf) return NULL; + + buf_block_t *block = (buf_block_t*)(buf->buf); + + block->owner = buf; + block->cap = sizeof(buf->buf) - sizeof(buf_block_t); + block->ptr = 0; + + buf->block = block; + + OILE(BASE_STATIC(buf->block), ""); + + return buf; +} + +void todbc_buf_free(todbc_buf_t *buf) { + if (!buf) return; + + todbc_list_free(buf->list); + buf->list = NULL; + + free(buf); +} + +void* todbc_buf_alloc(todbc_buf_t *buf, size_t size) { + return todbc_buf_realloc(buf, NULL, size); +} + +void* todbc_buf_calloc(todbc_buf_t *buf, size_t count, size_t size) { + size_t align = ALIGN(size); + size_t total = count * align; + if (total > INT64_MAX) return NULL; + void *ptr = todbc_buf_realloc(buf, NULL, total); + if (!ptr) return NULL; + memset(ptr, 0, total); + return ptr; +} + +static void do_free_buf_block(todbc_list_t *list, void *val, void *arg); + +static int alloc_space_by(todbc_list_t *list, void *val, void *arg); + +void* todbc_buf_realloc(todbc_buf_t *buf, void *ptr, size_t size) { + OILE(buf, ""); + OILE(sizeof(buf_block_t)%sizeof(void*)==0, ""); + OILE(sizeof(buf_rec_t)%sizeof(void*)==0, ""); + + size_t align = ALIGN(size); + size_t req_size = align + sizeof(buf_rec_t); + + buf_rec_t *rec = NULL; + buf_block_t *block = NULL; + if (ptr) { + rec = ptr_rec(buf, ptr); + if (align<=rec->size) return ptr; + + block = rec->owner; + char *tail_rec = rec->ptr + rec->size; + char *tail_block = block->base + block->ptr; + if (tail_rec==tail_block) { + char *end_rec = rec->ptr + align; + char *end_block = block->base + block->cap; + if (end_rec<=end_block) { + rec->size = align; + block->ptr = (size_t)(end_rec - block->base); + return ptr; + } + } else { + size_t remain = block->cap - block->ptr; + if (req_size<=remain) { + char *new_ptr = block->base + block->ptr; + block->ptr += req_size; + buf_rec_t *new_rec = (buf_rec_t*)new_ptr; + new_rec->size = align; + new_rec->owner = block; + memcpy(new_rec->ptr, ptr, rec->size); + return new_rec->ptr; + } + } + } + + arg_t arg = {0}; + arg.buf = buf; + arg.arg_ptr = ptr; + arg.arg_size = size; + arg.arg_rec = rec; + arg.arg_align = align; + + if (block!=buf->block) { + buf_rec_t *new_rec = buf_block_realloc(buf->block, &arg); + if (new_rec) return new_rec->ptr; + } + + ALLOC_LIST(); + if (!buf->list) return NULL; + + int r = todbc_list_traverse(buf->list, alloc_space_by, &arg); + if (r) { + OILE(arg.rec, ""); + OILE(arg.rec->ptr, ""); + return arg.rec->ptr; + } + + block = buf_block_create(arg.arg_align); + if (!block) return NULL; + OILE(block->owner==NULL, ""); + r = todbc_list_pushfront(buf->list, block); + OILE(r==0, ""); + block->owner = buf; + buf_rec_t *p = buf_block_realloc(block, &arg); + OILE(p, ""); + + return p->ptr; +} + +static int do_reclaim(todbc_list_t *list, void *val, void *arg); + +void todbc_buf_reclaim(todbc_buf_t *buf) { + if (!buf) return; + + buf_block_reclaim(buf->block); + + if (!buf->list) return; + + todbc_list_traverse(buf->list, do_reclaim, buf); +} + +static int do_reclaim(todbc_list_t *list, void *val, void *arg) { + todbc_buf_t *buf = (todbc_buf_t*)arg; + buf_block_t *block = (buf_block_t*)val; + OILE(list, ""); + OILE(block, ""); + OILE(block->owner==buf, ""); + buf_block_reclaim(block); + return 0; +} + +static void buf_block_reclaim(buf_block_t *block) { + block->ptr = 0; +} + +static void buf_block_free(buf_block_t *block) { + if (!block) return; + + buf_block_reclaim(block); + + if (BASE_STATIC(block)) return; + + block->owner = NULL; + block->cap = 0; + block->ptr = 0; + + free(block); +} + +static void do_free_buf_block(todbc_list_t *list, void *val, void *arg) { + todbc_buf_t *buf = (todbc_buf_t*)arg; + OILE(buf && buf->list==list, ""); + buf_block_t *block = (buf_block_t*)val; + OILE(block, ""); + OILE(buf==block->owner, ""); + + buf_block_free(block); +} + +static int alloc_space_by(todbc_list_t *list, void *val, void *arg) { + buf_block_t *block = (buf_block_t*)val; + arg_t *targ = (arg_t*)arg; + + buf_rec_t *rec = targ->arg_rec; + if (rec && rec->owner == block) return 0; + + buf_rec_t *new_rec = buf_block_realloc(block, targ); + if (!new_rec) return 0; + return 1; +} + +static buf_block_t* buf_block_create(size_t size) { + size_t align = ALIGN(size); + size_t req_size = sizeof(buf_block_t) + sizeof(buf_rec_t) + align; + req_size = (req_size + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE; + + buf_block_t *block = (buf_block_t*)malloc(req_size); + if (!block) return NULL; + + block->owner = NULL; + block->cap = req_size - sizeof(buf_block_t); + block->ptr = 0; + + return block; +} + +static buf_rec_t* buf_block_realloc(buf_block_t *block, arg_t *arg) { + OILE(block, ""); + OILE(arg, ""); + OILE(block->base, ""); + OILE(block->cap >= block->ptr, ""); + + char *ptr = arg->arg_ptr; + buf_rec_t *rec = arg->arg_rec; + OILE(rec==NULL || rec->owner!=block, ""); + + size_t align = arg->arg_align; + size_t req_size = sizeof(buf_rec_t) + align; + + OILE(req_size>0, ""); + + size_t remain = block->cap - block->ptr; + if (req_size > remain) { + return NULL; + } + + char *p = block->base + block->ptr; + buf_rec_t *new_rec = (buf_rec_t*)p; + new_rec->size = align; + new_rec->owner = block; + + block->ptr += req_size; + + if (ptr) { + memcpy(new_rec->ptr, ptr, arg->arg_rec->size); + } + + arg->rec = new_rec; + + return new_rec; +} + + + + + + +// test + +void todbc_buf_test_random(size_t iterates, size_t size, int raw) { + size_t n_reallocs = 0; + todbc_buf_t *cache = NULL; + OD("use %s", raw ? "realloc" : "todbc_buf_t"); + if (!raw) { + cache = todbc_buf_create(); + OILE(cache, ""); + } + srand((unsigned)time(0)); + char *buf = NULL; + size_t blen = 0; + while (iterates-- > 0) { + char *p = NULL; + size_t i = 0; + size_t len = (size_t)rand()%size; + if (raw) { + p = realloc(buf, len); + } else { + p = todbc_buf_realloc(cache, buf, len); + } + OILE(p, ""); + for (i=blen; i 0) { + size_t i = 0; + char *buf = NULL; + while (i + * + * 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 _todbc_buf_h_ +#define _todbc_buf_h_ + +#include +#include + +// non-thread-safe +typedef struct todbc_buf_s todbc_buf_t; + +todbc_buf_t* todbc_buf_create(void); +void todbc_buf_free(todbc_buf_t *buf); + +void* todbc_buf_alloc(todbc_buf_t *buf, size_t size); +void* todbc_buf_calloc(todbc_buf_t *buf, size_t count, size_t size); +void* todbc_buf_realloc(todbc_buf_t *buf, void *ptr, size_t size); +char* todbc_buf_strdup(todbc_buf_t *buf, const char *str); +void todbc_buf_reclaim(todbc_buf_t *buf); + +void todbc_buf_test_random(size_t iterates, size_t size, int raw); +void todbc_buf_test(size_t iterates, size_t size, int raw); + +#endif // _todbc_buf_h_ + diff --git a/src/connector/odbc/src/todbc_conv.c b/src/connector/odbc/src/todbc_conv.c deleted file mode 100644 index 9c0f19764c..0000000000 --- a/src/connector/odbc/src/todbc_conv.c +++ /dev/null @@ -1,660 +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 . - */ - -#include "todbc_conv.h" - -#include "todbc_log.h" - -#include -#include -#include -#include -#include - -const char* tsdb_conv_code_str(TSDB_CONV_CODE code) { - switch (code) { - case TSDB_CONV_OK: return "TSDB_CONV_OK"; - case TSDB_CONV_NOT_AVAIL: return "TSDB_CONV_NOT_AVAIL"; - case TSDB_CONV_OOM: return "TSDB_CONV_OOM"; - case TSDB_CONV_OOR: return "TSDB_CONV_OOR"; - case TSDB_CONV_TRUNC_FRACTION: return "TSDB_CONV_TRUNC_FRACTION"; - case TSDB_CONV_TRUNC: return "TSDB_CONV_TRUNC"; - case TSDB_CONV_CHAR_NOT_NUM: return "TSDB_CONV_CHAR_NOT_NUM"; - case TSDB_CONV_CHAR_NOT_TS: return "TSDB_CONV_CHAR_NOT_TS"; - case TSDB_CONV_NOT_VALID_TS: return "TSDB_CONV_NOT_VALID_TS"; - case TSDB_CONV_GENERAL: return "TSDB_CONV_GENERAL"; - case TSDB_CONV_SRC_TOO_LARGE: return "TSDB_CONV_SRC_TOO_LARGE"; - case TSDB_CONV_SRC_BAD_SEQ: return "TSDB_CONV_SRC_BAD_SEQ"; - case TSDB_CONV_SRC_INCOMPLETE: return "TSDB_CONV_SRC_INCOMPLETE"; - case TSDB_CONV_SRC_GENERAL: return "TSDB_CONV_SRC_GENERAL"; - case TSDB_CONV_BAD_CHAR: return "TSDB_CONV_BAD_CHAR"; - default: return "UNKNOWN"; - }; -} - -// src: int -TSDB_CONV_CODE tsdb_int64_to_bit(int64_t src, int8_t *dst) { - *dst = (int8_t)src; - if (src==0 || src==1) return TSDB_CONV_OK; - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_tinyint(int64_t src, int8_t *dst) { - *dst = (int8_t)src; - if (src == *dst) return TSDB_CONV_OK; - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_smallint(int64_t src, int16_t *dst) { - *dst = (int16_t)src; - if (src == *dst) return TSDB_CONV_OK; - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_int(int64_t src, int32_t *dst) { - *dst = (int32_t)src; - if (src == *dst) return TSDB_CONV_OK; - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_bigint(int64_t src, int64_t *dst) { - *dst = src; - return TSDB_CONV_OK; -} - -TSDB_CONV_CODE tsdb_int64_to_ts(int64_t src, int64_t *dst) { - *dst = src; - - time_t t = (time_t)(src / 1000); - struct tm tm = {0}; - if (localtime_r(&t, &tm)) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_float(int64_t src, float *dst) { - *dst = (float)src; - - int64_t v = (int64_t)*dst; - if (v==src) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_double(int64_t src, double *dst) { - *dst = (double)src; - - int64_t v = (int64_t)*dst; - if (v==src) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_int64_to_char(int64_t src, char *dst, size_t dlen) { - int n = snprintf(dst, dlen, "%" PRId64 "", src); - DASSERT(n>=0); - - if (n=2) return TSDB_CONV_OOR; - if (src == *dst) return TSDB_CONV_OK; - - int64_t v = (int64_t)src; - if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -TSDB_CONV_CODE tsdb_double_to_tinyint(double src, int8_t *dst) { - *dst = (int8_t)src; - - if (srcSCHAR_MAX) return TSDB_CONV_OOR; - if (src == *dst) return TSDB_CONV_OK; - - int64_t v = (int64_t)src; - if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -TSDB_CONV_CODE tsdb_double_to_smallint(double src, int16_t *dst) { - *dst = (int16_t)src; - - if (srcSHRT_MAX) return TSDB_CONV_OOR; - if (src == *dst) return TSDB_CONV_OK; - - int64_t v = (int64_t)src; - if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -TSDB_CONV_CODE tsdb_double_to_int(double src, int32_t *dst) { - *dst = (int32_t)src; - - if (srcLONG_MAX) return TSDB_CONV_OOR; - if (src == *dst) return TSDB_CONV_OK; - - int64_t v = (int64_t)src; - if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -TSDB_CONV_CODE tsdb_double_to_bigint(double src, int64_t *dst) { - *dst = (int64_t)src; - - if (srcLLONG_MAX) return TSDB_CONV_OOR; - if (src == *dst) return TSDB_CONV_OK; - - int64_t v = (int64_t)src; - if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -TSDB_CONV_CODE tsdb_double_to_ts(double src, int64_t *dst) { - TSDB_CONV_CODE code = tsdb_double_to_bigint(src, dst); - - if (code==TSDB_CONV_OK || code==TSDB_CONV_TRUNC_FRACTION) { - int64_t v = (int64_t)src; - time_t t = (time_t)(v / 1000); - struct tm tm = {0}; - if (localtime_r(&t, &tm)) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; - } - - return code; -} - -TSDB_CONV_CODE tsdb_double_to_char(double src, char *dst, size_t dlen) { - int n = snprintf(dst, dlen, "%lg", src); - DASSERT(n>=0); - - if (n=0); - if (n=19) return TSDB_CONV_TRUNC_FRACTION; - - return TSDB_CONV_TRUNC; -} - -// src: chars -TSDB_CONV_CODE tsdb_chars_to_bit(const char *src, size_t smax, int8_t *dst) { - if (strcmp(src, "0")==0) { - *dst = 0; - return TSDB_CONV_OK; - } - - if (strcmp(src, "1")==0) { - *dst = 1; - return TSDB_CONV_OK; - } - - double v; - int bytes; - int n = sscanf(src, "%lg%n", &v, &bytes); - - if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; - if (bytes!=strlen(src)) return TSDB_CONV_CHAR_NOT_NUM; - - if (v<0 || v>=2) return TSDB_CONV_OOR; - - return TSDB_CONV_TRUNC_FRACTION; -} - -TSDB_CONV_CODE tsdb_chars_to_tinyint(const char *src, size_t smax, int8_t *dst) { - int64_t v; - TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v); - if (code!=TSDB_CONV_OK) return code; - - *dst = (int8_t)v; - - if (v==*dst) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_chars_to_smallint(const char *src, size_t smax, int16_t *dst) { - int64_t v; - TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v); - if (code!=TSDB_CONV_OK) return code; - - *dst = (int16_t)v; - - if (v==*dst) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_chars_to_int(const char *src, size_t smax, int32_t *dst) { - int64_t v; - TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v); - if (code!=TSDB_CONV_OK) return code; - - *dst = (int32_t)v; - - if (v==*dst) return TSDB_CONV_OK; - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_chars_to_bigint(const char *src, size_t smax, int64_t *dst) { - int bytes; - int n = sscanf(src, "%" PRId64 "%n", dst, &bytes); - - if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; - if (bytes==strlen(src)) { - return TSDB_CONV_OK; - } - - double v; - n = sscanf(src, "%lg%n", &v, &bytes); - if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; - if (bytes==strlen(src)) { - return TSDB_CONV_TRUNC_FRACTION; - } - - return TSDB_CONV_OK; -} - -TSDB_CONV_CODE tsdb_chars_to_ts(const char *src, size_t smax, int64_t *dst) { - int64_t v; - TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v); - if (code!=TSDB_CONV_OK) return code; - - *dst = v; - - if (v==*dst) { - time_t t = (time_t)(v / 1000); - struct tm tm = {0}; - if (localtime_r(&t, &tm)) return TSDB_CONV_OK; - } - - return TSDB_CONV_OOR; -} - -TSDB_CONV_CODE tsdb_chars_to_float(const char *src, size_t smax, float *dst) { - int bytes; - int n = sscanf(src, "%g%n", dst, &bytes); - - if (n==1 && bytes==strlen(src)) { - return TSDB_CONV_OK; - } - - return TSDB_CONV_CHAR_NOT_NUM; -} - -TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst) { - int bytes; - int n = sscanf(src, "%lg%n", dst, &bytes); - - if (n==1 && bytes==strlen(src)) { - return TSDB_CONV_OK; - } - - return TSDB_CONV_CHAR_NOT_NUM; -} - -TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst) { - int64_t v = 0; - // why cast to 'char*' ? - int r = taosParseTime((char*)src, &v, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0); - - if (r) { - return TSDB_CONV_CHAR_NOT_TS; - } - - time_t t = v/1000; - struct tm vtm = {0}; - localtime_r(&t, &vtm); - dst->year = (SQLSMALLINT)(vtm.tm_year + 1900); - dst->month = (SQLUSMALLINT)(vtm.tm_mon + 1); - dst->day = (SQLUSMALLINT)(vtm.tm_mday); - dst->hour = (SQLUSMALLINT)(vtm.tm_hour); - dst->minute = (SQLUSMALLINT)(vtm.tm_min); - dst->second = (SQLUSMALLINT)(vtm.tm_sec); - dst->fraction = (SQLUINTEGER)(v%1000 * 1000000); - - return TSDB_CONV_OK; -} - -TSDB_CONV_CODE tsdb_chars_to_timestamp_ts(const char *src, size_t smax, int64_t *dst) { - // why cast to 'char*' ? - int r = taosParseTime((char*)src, dst, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0); - - if (r) { - return TSDB_CONV_CHAR_NOT_TS; - } - - return TSDB_CONV_OK; -} - -TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax) { - int n = snprintf(dst, dmax, "%s", src); - DASSERT(n>=0); - if (nnext + bytes; - if (next>sizeof(buffer->buf)) return NULL; - - char *p = buffer->buf + buffer->next; - buffer->next = next; - return p; -} - -int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr) { - if (!buffer) return 0; - if (ptr>=buffer->buf && ptrbuf+buffer->next) return 1; - return 0; -} - - -struct tsdb_conv_s { - iconv_t cnv; - unsigned int direct:1; -}; - -static tsdb_conv_t no_conversion = {0}; -static pthread_once_t once = PTHREAD_ONCE_INIT; -static void once_init(void) { - no_conversion.cnv = (iconv_t)-1; - no_conversion.direct = 1; -} - -tsdb_conv_t* tsdb_conv_direct() { // get a non-conversion-converter - pthread_once(&once, once_init); - return &no_conversion; -} - -tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc) { - pthread_once(&once, once_init); - tsdb_conv_t *cnv = (tsdb_conv_t*)calloc(1, sizeof(*cnv)); - if (!cnv) return NULL; - if (strcmp(from_enc, to_enc)==0 && 0) { - cnv->cnv = (iconv_t)-1; - cnv->direct = 1; - return cnv; - } - cnv->cnv = iconv_open(to_enc, from_enc); - if (cnv->cnv == (iconv_t)-1) { - free(cnv); - return NULL; - } - cnv->direct = 0; - return cnv; -} - -void tsdb_conv_close(tsdb_conv_t *cnv) { - if (!cnv) return; - if (cnv == &no_conversion) return; - if (!cnv->direct) { - if (cnv->cnv != (iconv_t)-1) { - iconv_close(cnv->cnv); - } - } - cnv->cnv = (iconv_t)-1; - cnv->direct = 0; - free(cnv); -} - -TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen) { - if (!cnv) return TSDB_CONV_NOT_AVAIL; - if (cnv->direct) { - size_t n = (*slen > *dlen) ? *dlen : *slen; - memcpy(dst, src, n); - *slen -= n; - *dlen -= n; - if (*dlen) dst[n] = '\0'; - return TSDB_CONV_OK; - } - if (!cnv->cnv) return TSDB_CONV_NOT_AVAIL; - size_t r = iconv(cnv->cnv, (char**)&src, slen, &dst, dlen); - if (r==(size_t)-1) return TSDB_CONV_BAD_CHAR; - if (*slen) return TSDB_CONV_TRUNC; - if (*dlen) *dst = '\0'; - return TSDB_CONV_OK; -} - -TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen) { - char utf8[64]; - int n = snprintf(utf8, sizeof(utf8), "%" PRId64 "", val); - DASSERT(n>=0); - DASSERT(n=0); - DASSERT(n=0); - DASSERT(ndirect) { - if (src[slen]=='\0') { // access violation? - *dst = src; - if (dlen) *dlen = slen; - return TSDB_CONV_OK; - } - blen = slen + 1; - } else { - blen = (slen + 1) * 4; - } - - buf = stack_buffer_alloc(buffer, blen); - if (!buf) { - buf = (char*)malloc(blen); - if (!buf) return TSDB_CONV_OOM; - } - - if (cnv->direct) { - size_t n = slen; - DASSERT(blen > n); - memcpy(buf, src, n); - buf[n] = '\0'; - *dst = buf; - if (dlen) *dlen = n; - return TSDB_CONV_OK; - } - - const char *orig_s = src; - char *orig_d = buf; - size_t orig_blen = blen; - - TSDB_CONV_CODE code; - size_t r = iconv(cnv->cnv, (char**)&src, &slen, &buf, &blen); - do { - if (r==(size_t)-1) { - switch(errno) { - case E2BIG: { - code = TSDB_CONV_SRC_TOO_LARGE; - } break; - case EILSEQ: { - code = TSDB_CONV_SRC_BAD_SEQ; - } break; - case EINVAL: { - code = TSDB_CONV_SRC_INCOMPLETE; - } break; - default: { - code = TSDB_CONV_SRC_GENERAL; - } break; - } - break; - } - if (slen) { - code = TSDB_CONV_TRUNC; - break; - } - DASSERT(blen); - *buf = '\0'; - *dst = orig_d; - if (dlen) *dlen = orig_blen - blen; - return TSDB_CONV_OK; - } while (0); - - if (orig_d!=(char*)orig_s && !is_owned_by_stack_buffer(buffer, orig_d)) free(orig_d); - return code; -} - -void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src) { - if (ptr!=src && !is_owned_by_stack_buffer(buffer, ptr)) free((char*)ptr); -} - diff --git a/src/connector/odbc/src/todbc_conv.h b/src/connector/odbc/src/todbc_conv.h deleted file mode 100644 index 2941f3e496..0000000000 --- a/src/connector/odbc/src/todbc_conv.h +++ /dev/null @@ -1,109 +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 . - */ - -#ifndef _todbc_conv_h_ -#define _todbc_conv_h_ - -#include "os.h" -#include -#include - - -typedef enum { - TSDB_CONV_OK = 0, - TSDB_CONV_NOT_AVAIL, - TSDB_CONV_OOM, - TSDB_CONV_OOR, - TSDB_CONV_TRUNC_FRACTION, - TSDB_CONV_TRUNC, - TSDB_CONV_CHAR_NOT_NUM, - TSDB_CONV_CHAR_NOT_TS, - TSDB_CONV_NOT_VALID_TS, - TSDB_CONV_GENERAL, - TSDB_CONV_BAD_CHAR, - TSDB_CONV_SRC_TOO_LARGE, - TSDB_CONV_SRC_BAD_SEQ, - TSDB_CONV_SRC_INCOMPLETE, - TSDB_CONV_SRC_GENERAL, -} TSDB_CONV_CODE; - -const char* tsdb_conv_code_str(TSDB_CONV_CODE code); - -typedef struct stack_buffer_s stack_buffer_t; -struct stack_buffer_s { - char buf[1024*16]; - size_t next; -}; - -char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes); -int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr); - -typedef struct tsdb_conv_s tsdb_conv_t; -tsdb_conv_t* tsdb_conv_direct(); // get a non-conversion-converter -tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc); -void tsdb_conv_close(tsdb_conv_t *cnv); - -TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen); -TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen); -TSDB_CONV_CODE tsdb_conv_write_double(tsdb_conv_t *cnv, double val, char *dst, size_t *dlen); -TSDB_CONV_CODE tsdb_conv_write_timestamp(tsdb_conv_t *cnv, SQL_TIMESTAMP_STRUCT val, char *dst, size_t *dlen); - -TSDB_CONV_CODE tsdb_conv_chars_to_bit(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_tinyint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_smallint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int16_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_int(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int32_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_bigint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_float(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, float *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_double(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, double *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_timestamp(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, SQL_TIMESTAMP_STRUCT *dst); -TSDB_CONV_CODE tsdb_conv_chars_to_timestamp_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst); -TSDB_CONV_CODE tsdb_conv(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, const char **dst, size_t *dlen); -void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src); - - -TSDB_CONV_CODE tsdb_int64_to_bit(int64_t src, int8_t *dst); -TSDB_CONV_CODE tsdb_int64_to_tinyint(int64_t src, int8_t *dst); -TSDB_CONV_CODE tsdb_int64_to_smallint(int64_t src, int16_t *dst); -TSDB_CONV_CODE tsdb_int64_to_int(int64_t src, int32_t *dst); -TSDB_CONV_CODE tsdb_int64_to_bigint(int64_t src, int64_t *dst); -TSDB_CONV_CODE tsdb_int64_to_ts(int64_t src, int64_t *dst); -TSDB_CONV_CODE tsdb_int64_to_float(int64_t src, float *dst); -TSDB_CONV_CODE tsdb_int64_to_double(int64_t src, double *dst); -TSDB_CONV_CODE tsdb_int64_to_char(int64_t src, char *dst, size_t dlen); - -TSDB_CONV_CODE tsdb_double_to_bit(double src, int8_t *dst); -TSDB_CONV_CODE tsdb_double_to_tinyint(double src, int8_t *dst); -TSDB_CONV_CODE tsdb_double_to_smallint(double src, int16_t *dst); -TSDB_CONV_CODE tsdb_double_to_int(double src, int32_t *dst); -TSDB_CONV_CODE tsdb_double_to_bigint(double src, int64_t *dst); -TSDB_CONV_CODE tsdb_double_to_ts(double src, int64_t *dst); -TSDB_CONV_CODE tsdb_double_to_char(double src, char *dst, size_t dlen); - -TSDB_CONV_CODE tsdb_timestamp_to_char(SQL_TIMESTAMP_STRUCT src, char *dst, size_t dlen); - -TSDB_CONV_CODE tsdb_chars_to_bit(const char *src, size_t smax, int8_t *dst); -TSDB_CONV_CODE tsdb_chars_to_tinyint(const char *src, size_t smax, int8_t *dst); -TSDB_CONV_CODE tsdb_chars_to_smallint(const char *src, size_t smax, int16_t *dst); -TSDB_CONV_CODE tsdb_chars_to_int(const char *src, size_t smax, int32_t *dst); -TSDB_CONV_CODE tsdb_chars_to_bigint(const char *src, size_t smax, int64_t *dst); -TSDB_CONV_CODE tsdb_chars_to_ts(const char *src, size_t smax, int64_t *dst); -TSDB_CONV_CODE tsdb_chars_to_float(const char *src, size_t smax, float *dst); -TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst); -TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst); -TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax); - -#endif // _todbc_conv_h_ - diff --git a/src/connector/odbc/src/todbc_flex.h b/src/connector/odbc/src/todbc_flex.h index a13f1f4d2e..762ffba0be 100644 --- a/src/connector/odbc/src/todbc_flex.h +++ b/src/connector/odbc/src/todbc_flex.h @@ -16,16 +16,40 @@ #ifndef _TODBC_FLEX_H_ #define _TODBC_FLEX_H_ +#include +#include + +// TSDB predefined field types +// TINYINT SMALLINT INT BIGINT FLOAT DOUBLE BOOL TIMESTAMP BINARY NCHAR + +typedef struct map_tsdb_type_s map_tsdb_type_t; +struct map_tsdb_type_s { + SQLSMALLINT tsdb_tinyint; + SQLSMALLINT tsdb_smallint; + SQLSMALLINT tsdb_int; + SQLSMALLINT tsdb_bigint; + SQLULEN tsdb_bigint_size; + SQLSMALLINT tsdb_float; + SQLSMALLINT tsdb_double; + SQLSMALLINT tsdb_bool; + SQLSMALLINT tsdb_timestamp; + SQLSMALLINT tsdb_binary; + SQLSMALLINT tsdb_nchar; +}; + typedef struct conn_val_s conn_val_t; struct conn_val_s { - char *key; - char *dsn; - char *uid; - char *pwd; - char *db; - char *server; - char *svr_enc; - char *cli_enc; + char *dsn; + char *uid; + char *pwd; + char *db; + char *server; + char *enc_local; + char *enc_char; + char *enc_wchar; + char *enc_db; + + map_tsdb_type_t tsdb_map; }; diff --git a/src/connector/odbc/src/todbc_hash.c b/src/connector/odbc/src/todbc_hash.c new file mode 100644 index 0000000000..1f64a490fd --- /dev/null +++ b/src/connector/odbc/src/todbc_hash.c @@ -0,0 +1,195 @@ +/* + * 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 "todbc_hash.h" + +#include "todbc_list.h" +#include "todbc_log.h" + +#include + +typedef struct todbc_hash_slot_s todbc_hash_slot_t; + +struct todbc_hash_s { + todbc_hash_conf_t conf; + + todbc_hash_slot_t *slots; + size_t n_slots; +}; + +struct todbc_hash_slot_s { + todbc_list_t *list; +}; + +todbc_hash_t* todbc_hash_create(todbc_hash_conf_t conf) { + if (!conf.key_hash) return NULL; + if (!conf.key_comp) return NULL; + if (!conf.val_free) return NULL; + + todbc_hash_t *hash = (todbc_hash_t*)calloc(1, sizeof(*hash)); + if (!hash) return NULL; + + hash->conf = conf; + if (hash->conf.slots==0) { + hash->conf.slots = 33; + } + + hash->slots = (todbc_hash_slot_t*)calloc(hash->conf.slots, sizeof(*hash->slots)); + do { + if (!hash->slots) break; + hash->n_slots = hash->conf.slots; + return hash; + } while (0); + + todbc_hash_free(hash); + return NULL; +} + +void todbc_hash_free(todbc_hash_t *hash) { + if (!hash) return; + for (int i=0; in_slots; ++i) { + todbc_hash_slot_t *slot = hash->slots + i; + if (!slot->list) continue; + todbc_list_free(slot->list); + slot->list = NULL; + } + free(hash->slots); + hash->n_slots = 0; +} + +typedef struct kv_s kv_t; +struct kv_s { + todbc_hash_t *hash; + void *key; + void *val; +}; + +static void do_val_free(todbc_list_t *list, void *val, void *arg) { + todbc_hash_t *hash = (todbc_hash_t*)arg; + DASSERT(list); + DASSERT(hash); + DASSERT(hash->conf.val_free); + hash->conf.val_free(hash, val, hash->conf.arg); +} + +int todbc_hash_put(todbc_hash_t *hash, void *key, void *val) { + if (!hash) return -1; + if (!hash->slots) return -1; + if (!key) return -1; + if (!val) return -1; + + void *old = NULL; + int found = 0; + int r = todbc_hash_get(hash, key, &old, &found); + if (r) return r; + if (found) return -1; + + unsigned long hash_val = hash->conf.key_hash(hash, key); + todbc_hash_slot_t *slot = hash->slots + (hash_val % hash->n_slots); + if (!slot->list) { + todbc_list_conf_t conf = {0}; + conf.arg = hash; + conf.val_free = do_val_free; + + slot->list = todbc_list_create(conf); + if (!slot->list) return -1; + } + + r = todbc_list_pushback(slot->list, val); + + return r; +} + +static int do_comp(todbc_list_t *list, void *old, void *val, void *arg) { + kv_t *kv = (kv_t*)arg; + DASSERT(kv); + DASSERT(kv->hash); + DASSERT(kv->key); + DASSERT(kv->hash->conf.key_comp); + DASSERT(kv->key == val); + int r = kv->hash->conf.key_comp(kv->hash, kv->key, old); + if (r==0) { + kv->val = old; + } + return r; +} + +int todbc_hash_get(todbc_hash_t *hash, void *key, void **val, int *found) { + if (!hash) return -1; + if (!hash->slots) return -1; + if (!key) return -1; + if (!val) return -1; + if (!found) return -1; + + *found = 0; + + unsigned long hash_val = hash->conf.key_hash(hash, key); + todbc_hash_slot_t *slot = hash->slots + (hash_val % hash->n_slots); + if (slot->list) { + kv_t kv = {0}; + kv.hash = hash; + kv.key = key; + kv.val = NULL; + int r = todbc_list_find(slot->list, key, found, do_comp, &kv); + if (*found) { + DASSERT(r==0); + DASSERT(kv.val); + *val = kv.val; + } + return r; + } + + return 0; +} + +int todbc_hash_del(todbc_hash_t *hash, void *key) { + return -1; +} + +typedef struct arg_s arg_t; +struct arg_s { + todbc_hash_t *hash; + void *arg; + int (*iterate)(todbc_hash_t *hash, void *val, void *arg); +}; + +static int do_iterate(todbc_list_t *list, void *val, void *arg); + +int todbc_hash_traverse(todbc_hash_t *hash, int (*iterate)(todbc_hash_t *hash, void *val, void *arg), void *arg) { + if (!hash) return -1; + if (!iterate) return -1; + + for (int i=0; in_slots; ++i) { + todbc_hash_slot_t *slot = hash->slots + i; + if (!slot->list) continue; + arg_t targ = {0}; + targ.hash = hash; + targ.arg = arg; + targ.iterate = iterate; + int r = todbc_list_traverse(slot->list, do_iterate, &targ); + if (r) return r; + } + + return 0; +} + +static int do_iterate(todbc_list_t *list, void *val, void *arg) { + arg_t *targ = (arg_t*)arg; + DASSERT(targ); + DASSERT(targ->iterate); + DASSERT(targ->hash); + return targ->iterate(targ->hash, val, targ->arg); +} + diff --git a/src/connector/odbc/src/todbc_hash.h b/src/connector/odbc/src/todbc_hash.h new file mode 100644 index 0000000000..9172c8b7f9 --- /dev/null +++ b/src/connector/odbc/src/todbc_hash.h @@ -0,0 +1,53 @@ +/* + * 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 _todbc_hash_h_ +#define _todbc_hash_h_ + + +#include +#include + +// non-thread-safe + +typedef struct todbc_hash_conf_s todbc_hash_conf_t; +typedef struct todbc_hash_s todbc_hash_t; + +typedef void (*hash_val_free_f)(todbc_hash_t *hash, void *val, void *arg); +typedef unsigned long (*hash_key_hash_f)(todbc_hash_t *hash, void *key); +typedef int (*hash_key_comp_f)(todbc_hash_t *hash, void *key, void *val); + +struct todbc_hash_conf_s { + void *arg; + hash_val_free_f val_free; + + hash_key_hash_f key_hash; + hash_key_comp_f key_comp; + + size_t slots; +}; + +todbc_hash_t* todbc_hash_create(todbc_hash_conf_t conf); +void todbc_hash_free(todbc_hash_t *hash); + +// fail if key exists +int todbc_hash_put(todbc_hash_t *hash, void *key, void *val); +int todbc_hash_get(todbc_hash_t *hash, void *key, void **val, int *found); +int todbc_hash_del(todbc_hash_t *hash, void *key); +typedef int (*hash_iterate_f)(todbc_hash_t *hash, void *val, void *arg); +int todbc_hash_traverse(todbc_hash_t *hash, hash_iterate_f iterate, void *arg); + +#endif // _todbc_hash_h_ + diff --git a/src/connector/odbc/src/todbc_iconv.c b/src/connector/odbc/src/todbc_iconv.c new file mode 100644 index 0000000000..968cc870f8 --- /dev/null +++ b/src/connector/odbc/src/todbc_iconv.c @@ -0,0 +1,682 @@ +/* + * 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 "todbc_iconv.h" + +#include "todbc_hash.h" +#include "todbc_log.h" +#include "todbc_string.h" +#include "todbc_tls.h" + +#define invalid_iconv() ((iconv_t)-1) + +struct todbc_iconvset_s { + todbc_hash_t *iconv_hash; + + todbc_hash_t *enc_hash; +}; + +typedef struct todbc_iconv_key_s todbc_iconv_key_t; +struct todbc_iconv_key_s { + const char *enc_to; + const char *enc_from; +}; + +struct todbc_iconv_s { + char enc_to[64]; + char enc_from[64]; + todbc_iconv_key_t key; + iconv_t cnv; + + todbc_enc_t from; + todbc_enc_t to; + + unsigned int direct:1; +}; + +static void todbc_iconv_free(todbc_iconv_t *val); + +todbc_iconvset_t* todbc_iconvset_create(void) { + todbc_iconvset_t *cnvset = (todbc_iconvset_t*)calloc(1, sizeof(*cnvset)); + if (!cnvset) return NULL; + + return cnvset; +} + +void todbc_iconvset_free(todbc_iconvset_t *cnvset) { + if (!cnvset) return; + if (cnvset->iconv_hash) { + todbc_hash_free(cnvset->iconv_hash); + cnvset->iconv_hash = NULL; + } + if (cnvset->enc_hash) { + todbc_hash_free(cnvset->enc_hash); + cnvset->enc_hash = NULL; + } + free(cnvset); +} + +static void do_iconv_hash_val_free(todbc_hash_t *hash, void *val, void *arg); +static unsigned long do_iconv_hash_key_hash(todbc_hash_t *hash, void *key); +static int do_iconv_hash_key_comp(todbc_hash_t *hash, void *key, void *val); + +static void do_enc_hash_val_free(todbc_hash_t *hash, void *val, void *arg); +static unsigned long do_enc_hash_key_hash(todbc_hash_t *hash, void *key); +static int do_enc_hash_key_comp(todbc_hash_t *hash, void *key, void *val); + +#define CHK(x, y, n) if (strcasecmp(x, y)==0) return n + +#define SET_SIZES(cs, enc, a,b) do { \ + if (strcasecmp(enc->enc, cs)==0) { \ + enc->char_size = a; \ + enc->variable_char_size = b; \ + return; \ + } \ +} while (0) + +static void do_set_sizes(todbc_enc_t *enc) { + if (!enc) return; + + SET_SIZES("ISO-10646-UCS-2", enc, 2, -1); + SET_SIZES("UCS-2", enc, 2, -1); + SET_SIZES("CSUNICODE", enc, 2, -1); + SET_SIZES("UCS-2BE", enc, 2, -1); + SET_SIZES("UNICODE-1-1", enc, 2, -1); + SET_SIZES("UNICODEBIG", enc, 2, -1); + SET_SIZES("CSUNICODE11", enc, 2, -1); + SET_SIZES("UCS-2LE", enc, 2, -1); + SET_SIZES("UNICODELITTLE", enc, 2, -1); + SET_SIZES("UTF-16", enc, 2, -1); + SET_SIZES("UTF-16BE", enc, 2, -1); + SET_SIZES("UTF-16LE", enc, 2, -1); + SET_SIZES("UCS-2-INTERNAL", enc, 2, -1); + SET_SIZES("UCS-2-SWAPPED", enc, 2, -1); + SET_SIZES("ISO-10646-UCS-4", enc, 4, -1); + SET_SIZES("UCS-4", enc, 4, -1); + SET_SIZES("CSUCS4", enc, 4, -1); + SET_SIZES("UCS-4BE", enc, 4, -1); + SET_SIZES("UCS-4LE", enc, 4, -1); + SET_SIZES("UTF-32", enc, 4, -1); + SET_SIZES("UTF-32BE", enc, 4, -1); + SET_SIZES("UTF-32LE", enc, 4, -1); + SET_SIZES("UCS-4-INTERNAL", enc, 4, -1); + SET_SIZES("UCS-4-SWAPPED", enc, 4, -1); + + SET_SIZES("UTF-8", enc, -1, 3); + SET_SIZES("UTF8", enc, -1, 3); + SET_SIZES("UTF-8-MAC", enc, -1, 3); + SET_SIZES("UTF8-MAC", enc, -1, 3); + + SET_SIZES("CN-GB", enc, 2, -1); + SET_SIZES("EUC-CN", enc, 2, -1); + SET_SIZES("EUCCN", enc, 2, -1); + SET_SIZES("GB2312", enc, 2, -1); + SET_SIZES("CSGB2312", enc, 2, -1); + SET_SIZES("GBK", enc, 2, -1); + SET_SIZES("CP936", enc, 2, -1); + SET_SIZES("MS936", enc, 2, -1); + SET_SIZES("WINDOWS-936", enc, 2, -1); + SET_SIZES("GB18030", enc, 2, -1); + + // add more setup here after + + enc->char_size = -1; + enc->variable_char_size = -1; +} + +static int do_get_null_size(const char *enc, int *null_size); + +// static int do_get_unicode_char_size(const char *enc) { +// if (!enc) return -1; +// +// CHK("ISO-10646-UCS-2", enc, 2); +// CHK("UCS-2", enc, 2); +// CHK("CSUNICODE", enc, 2); +// CHK("UCS-2BE", enc, 2); +// CHK("UNICODE-1-1", enc, 2); +// CHK("UNICODEBIG", enc, 2); +// CHK("CSUNICODE11", enc, 2); +// CHK("UCS-2LE", enc, 2); +// CHK("UNICODELITTLE", enc, 2); +// CHK("UTF-16", enc, 2); +// CHK("UTF-16BE", enc, 2); +// CHK("UTF-16LE", enc, 2); +// CHK("UCS-2-INTERNAL", enc, 2); +// CHK("UCS-2-SWAPPED", enc, 2); +// CHK("ISO-10646-UCS-4", enc, 4); +// CHK("UCS-4", enc, 4); +// CHK("CSUCS4", enc, 4); +// CHK("UCS-4BE", enc, 4); +// CHK("UCS-4LE", enc, 4); +// CHK("UTF-32", enc, 4); +// CHK("UTF-32BE", enc, 4); +// CHK("UTF-32LE", enc, 4); +// CHK("UCS-4-INTERNAL", enc, 4); +// CHK("UCS-4-SWAPPED", enc, 4); +// +// return -1; +// } + +todbc_enc_t todbc_iconvset_enc(todbc_iconvset_t *cnvset, const char *enc) { + do { + if (!cnvset) break; + if (!enc) break; + + if (!cnvset->enc_hash) { + todbc_hash_conf_t conf = {0}; + conf.arg = cnvset; + conf.val_free = do_enc_hash_val_free; + conf.key_hash = do_enc_hash_key_hash; + conf.key_comp = do_enc_hash_key_comp; + conf.slots = 7; + cnvset->enc_hash = todbc_hash_create(conf); + if (!cnvset->enc_hash) break; + } + + void *old = NULL; + int found = 0; + int r = todbc_hash_get(cnvset->enc_hash, (void*)enc, &old, &found); + if (r) { + DASSERT(found==0); + DASSERT(old==NULL); + break; + } + + if (found) { + DASSERT(old); + todbc_enc_t *val = (todbc_enc_t*)old; + return *val; + } + + todbc_enc_t *val = (todbc_enc_t*)calloc(1, sizeof(*val)); + if (!val) break; + do { + if (snprintf(val->enc, sizeof(val->enc), "%s", enc)>=sizeof(val->enc)) { + break; + } + do_set_sizes(val); + + if (do_get_null_size(val->enc, &val->null_size)) break; + + return *val; + } while (0); + + free(val); + } while (0); + + todbc_enc_t v = {0}; + v.char_size = -1; + v.null_size = -1; + + return v; +} + +todbc_iconv_t* todbc_iconvset_get(todbc_iconvset_t *cnvset, const char *enc_to, const char *enc_from) { + if (!cnvset) return NULL; + if (!enc_to) return NULL; + if (!enc_from) return NULL; + todbc_iconv_key_t key; + key.enc_to = enc_to; + key.enc_from = enc_from; + + if (!cnvset->iconv_hash) { + todbc_hash_conf_t conf = {0}; + conf.arg = cnvset; + conf.val_free = do_iconv_hash_val_free; + conf.key_hash = do_iconv_hash_key_hash; + conf.key_comp = do_iconv_hash_key_comp; + conf.slots = 7; + cnvset->iconv_hash = todbc_hash_create(conf); + if (!cnvset->iconv_hash) return NULL; + } + + void *old = NULL; + int found = 0; + int r = todbc_hash_get(cnvset->iconv_hash, &key, &old, &found); + if (r) { + DASSERT(found==0); + DASSERT(old==NULL); + return NULL; + } + + if (found) { + DASSERT(old); + todbc_iconv_t *val = (todbc_iconv_t*)old; + // D("found [%p] for [%s->%s]", val, enc_from, enc_to); + return val; + } + + todbc_iconv_t *val = (todbc_iconv_t*)calloc(1, sizeof(*val)); + if (!val) return NULL; + do { + if (snprintf(val->enc_to, sizeof(val->enc_to), "%s", enc_to)>=sizeof(val->enc_to)) { + break; + } + if (snprintf(val->enc_from, sizeof(val->enc_from), "%s", enc_from)>=sizeof(val->enc_from)) { + break; + } + val->key.enc_to = val->enc_to; + val->key.enc_from = val->enc_from; + if (strcasecmp(enc_to, enc_from)==0) { + val->direct = 1; + } + + val->from = todbc_tls_iconv_enc(enc_from); + val->to = todbc_tls_iconv_enc(enc_to); + + val->cnv = iconv_open(enc_to, enc_from); + if (val->cnv==invalid_iconv()) break; + + r = todbc_hash_put(cnvset->iconv_hash, &key, val); + + if (r) break; + + // D("created [%p] for [%s->%s]", val, enc_from, enc_to); + return val; + } while (0); + + todbc_iconv_free(val); + return NULL; +} + +iconv_t todbc_iconv_get(todbc_iconv_t *cnv) { + if (!cnv) return invalid_iconv(); + return cnv->cnv; +} + +// static int todbc_legal_chars_by_cnv(iconv_t cnv, const unsigned char *str, todbc_bytes_t *bc); + +int todbc_iconv_get_legal_chars(todbc_iconv_t *cnv, const unsigned char *str, todbc_bytes_t *bc) { + DASSERT(0); + // if (!cnv) return -1; + // if (bc->inbytes==0 || bc->inbytes > INT64_MAX) { + // DASSERT(bc->chars<=INT64_MAX); + // if (bc->chars > 0) { + // DASSERT(cnv->from_char_size==2 || cnv->from_char_size==4); + // bc->inbytes = ((size_t)cnv->from_char_size) * bc->chars; + // bc->chars = 0; + // } + // } else { + // DASSERT(bc->chars==0); + // } + // return todbc_legal_chars_by_cnv(todbc_iconv_get(cnv), str, bc); +} + +// static int todbc_legal_chars_by_block(iconv_t cnv, const unsigned char *str, todbc_bytes_t *bc); + +// static int todbc_legal_chars_by_cnv(iconv_t cnv, const unsigned char *str, todbc_bytes_t *bc) { +// size_t max_bytes = bc->inbytes; +// if (max_bytes > INT64_MAX) max_bytes = (size_t)-1; +// +// if (max_bytes != (size_t)-1) { +// return todbc_legal_chars_by_block(cnv, str, bc); +// } +// +// memset(bc, 0, sizeof(*bc)); +// +// size_t nbytes = 0; +// size_t ch_bytes = 0; +// +// char buf[16]; +// char *inbuf = (char*)str; +// char *outbuf; +// size_t outbytes; +// size_t inbytes; +// +// size_t n = 0; +// +// int r = 0; +// inbytes = 1; +// while (1) { +// if (nbytes==max_bytes) break; +// outbytes = sizeof(buf); +// outbuf = buf; +// +// ch_bytes = inbytes; +// n = iconv(cnv, &inbuf, &inbytes, &outbuf, &outbytes); +// nbytes += 1; +// if (n==(size_t)-1) { +// int err = errno; +// if (err!=EINVAL) { +// E("......."); +// r = -1; +// break; +// } +// inbytes = ch_bytes + 1; +// continue; +// } +// DASSERT(inbytes==0); +// n = sizeof(buf) - outbytes; +// +// DASSERT(n==2); +// if (buf[0]=='\0' && buf[1]=='\0') { +// ch_bytes = 0; +// break; +// } +// +// bc->inbytes += ch_bytes; +// bc->chars += 1; +// bc->outbytes += 2; +// +// ch_bytes = 0; +// inbytes = 1; +// } +// +// outbytes = sizeof(buf); +// outbuf = buf; +// n = iconv(cnv, NULL, NULL, &outbuf, &outbytes); +// +// if (r) return -1; +// if (n==(size_t)-1) return -1; +// if (outbytes!=sizeof(buf)) return -1; +// if (outbuf!=buf) return -1; +// if (ch_bytes) return -1; +// return 0; +// } + +unsigned char* todbc_iconv_conv(todbc_iconv_t *cnv, todbc_buf_t *buf, const unsigned char *src, todbc_bytes_t *bc) { + if (!buf) { + buf = todbc_tls_buf(); + if (!buf) return NULL; + } + if (bc==NULL) { + todbc_bytes_t x = {0}; + x.inbytes = (size_t)-1; + return todbc_iconv_conv(cnv, buf, src, &x); + } + + DASSERT(buf); + DASSERT(cnv); + DASSERT(src); + + todbc_string_t s = todbc_string_init(cnv->from.enc, src, bc->inbytes); + // D("total_bytes/bytes: %d/%zu/%zu", s.total_bytes, s.bytes); + DASSERT(s.buf==src); + todbc_string_t t = todbc_string_conv_to(&s, cnv->to.enc, NULL); + DASSERT(t.buf); + // bc->outbytes not counting size of null-terminator + bc->outbytes = t.bytes; + return (unsigned char*)t.buf; +} + +size_t todbc_iconv_est_bytes(todbc_iconv_t *cnv, size_t inbytes) { + DASSERT(cnv); + DASSERT(inbytes<=INT64_MAX); + const todbc_enc_t *from = &cnv->from; + const todbc_enc_t *to = &cnv->to; + + size_t outbytes = inbytes; + do { + if (from == to) break; + + size_t inchars = inbytes; + if (from->char_size > 1) { + inchars = (inbytes + (size_t)from->char_size - 1) / (size_t)from->char_size; + } + outbytes = inchars; + size_t char_size = MAX_CHARACTER_SIZE; + if (to->char_size > 0) { + char_size = (size_t)to->char_size; + } else if (to->variable_char_size > 0) { + char_size = (size_t)to->variable_char_size; + } + outbytes *= char_size; + } while (0); + + size_t nullbytes = MAX_CHARACTER_SIZE; + if (to->null_size > 0) { + nullbytes = (size_t)to->null_size; + } + // D("%s->%s: %zu->%zu", from->enc, to->enc, inbytes, outbytes); + outbytes += nullbytes; + // D("%s->%s: %zu->%zu", from->enc, to->enc, inbytes, outbytes); + + return outbytes; +} + +size_t todbc_iconv_bytes(todbc_iconv_t *cnv, size_t inchars) { + DASSERT(cnv); + if (inchars >= INT64_MAX) return (size_t)-1; + const todbc_enc_t *from = &cnv->from; + if (from->char_size > 0) { + return inchars * (size_t)from->char_size; + } + return (size_t)-1; +} + +todbc_enc_t todbc_iconv_from(todbc_iconv_t *cnv) { + DASSERT(cnv); + return cnv->from; +} + +todbc_enc_t todbc_iconv_to(todbc_iconv_t *cnv) { + DASSERT(cnv); + return cnv->to; +} + +int todbc_iconv_raw(todbc_iconv_t *cnv, const unsigned char *src, size_t *slen, unsigned char *dst, size_t *dlen) { + DASSERT(cnv); + DASSERT(src && dst); + DASSERT(slen && *slen < INT64_MAX); + DASSERT(dlen && *dlen < INT64_MAX); + + const int null_bytes = todbc_iconv_to(cnv).null_size; + + if (*dlen<=null_bytes) { + D("target buffer too small to hold even null-terminator"); + *dlen = 0; // while slen does not change + return -1; + } + + char *inbuf = (char*)src; + size_t inbytes = *slen; + char *outbuf = (char*)dst; + size_t outbytes = *dlen; + + size_t n = iconv(cnv->cnv, &inbuf, &inbytes, &outbuf, &outbytes); + int e = 0; + if (n==(size_t)-1) { + e = errno; + D("iconv failed: [%s->%s]:[%d]%s", cnv->from.enc, cnv->to.enc, e, strerror(e)); + } else { + DASSERT(n==0); + } + + const size_t inremain = inbytes; + const size_t outremain = outbytes; + *slen = inremain; + *dlen = outremain; + + // writing null-terminator to make dest a real string + DASSERT(outbytes <= INT64_MAX); + if (outbytes < null_bytes) { + D("target buffer too small to hold null-terminator"); + return -1; + } else { + for (int i=0; icnv, NULL, NULL, NULL, NULL); + + return 0; +} + +todbc_string_t todbc_iconv_conv2(todbc_iconv_t *cnv, todbc_buf_t *buf, const unsigned char *src, size_t *slen) { + const todbc_string_t nul = {0}; + if (!buf) { + buf = todbc_tls_buf(); + if (!buf) return nul; + } + DASSERT(cnv); + DASSERT(src); + + size_t inbytes = (size_t)-1; + if (slen && *slen <= INT64_MAX) inbytes = *slen; + + todbc_string_t in = todbc_string_init(todbc_iconv_from(cnv).enc, src, inbytes); + if (in.buf!=src) return nul; + if (in.bytes > INT64_MAX) return nul; + inbytes = in.bytes; + + size_t outblock = todbc_iconv_est_bytes(cnv, in.bytes); + if (outblock > INT64_MAX) return nul; + + unsigned char *out = todbc_buf_alloc(buf, outblock); + if (!out) return nul; + + const unsigned char *inbuf = src; + unsigned char *outbuf = out; + + + size_t outbytes = outblock; + int r = todbc_iconv_raw(cnv, inbuf, &inbytes, outbuf, &outbytes); + if (slen) *slen = inbytes; + if (r) return nul; + todbc_string_t s = {0}; + s.buf = outbuf; + s.bytes = outblock - outbytes; + s.total_bytes = s.bytes; + return s; +} + +// static int todbc_legal_chars_by_block(iconv_t cnv, const unsigned char *str, todbc_bytes_t *bc) { +// int r = 0; +// size_t max_bytes = bc->inbytes; +// char buf[1024*16]; +// memset(bc, 0, sizeof(*bc)); +// char *inbuf = (char*)str; +// while (bc->inbytesinbytes; +// size_t outbytes = sizeof(buf); +// char *outbuf = buf; +// size_t n = iconv(cnv, &inbuf, &inbytes, &outbuf, &outbytes); +// int err = 0; +// if (n==(size_t)-1) { +// err = errno; +// if (err!=E2BIG && err!=EINVAL) r = -1; +// } else { +// DASSERT(n==0); +// } +// if (inbytes == max_bytes - bc->inbytes) { +// r = -1; +// } +// bc->inbytes += max_bytes - bc->inbytes - inbytes; +// bc->outbytes += sizeof(buf) - outbytes; +// if (r) break; +// } +// bc->chars = bc->outbytes / 2; +// iconv(cnv, NULL, NULL, NULL, NULL); +// return r ? -1 : 0; +// } + +static void todbc_iconv_free(todbc_iconv_t *val) { + if (!val) return; + if (val->cnv!=invalid_iconv()) { + iconv_close(val->cnv); + val->cnv = invalid_iconv(); + } + free(val); +} + +// http://www.cse.yorku.ca/~oz/hash.html +static const unsigned long hash_seed = 5381; +static unsigned long hashing(unsigned long hash, const unsigned char *str); + +static void do_enc_hash_val_free(todbc_hash_t *hash, void *val, void *arg) { + todbc_iconvset_t *cnv = (todbc_iconvset_t*)arg; + todbc_enc_t *v = (todbc_enc_t*)val; + DASSERT(hash); + DASSERT(cnv); + DASSERT(v); + free(v); +} + +static unsigned long do_enc_hash_key_hash(todbc_hash_t *hash, void *key) { + const char *k = (const char*)key; + DASSERT(k); + unsigned long h = hash_seed; + h = hashing(h, (const unsigned char*)k); + return h; +} + +static int do_enc_hash_key_comp(todbc_hash_t *hash, void *key, void *val) { + const char *k = (const char*)key; + todbc_enc_t *v = (todbc_enc_t*)val; + if (strcasecmp(k, v->enc)) return 1; + return 0; +} + +static int do_get_null_size(const char *enc, int *null_size) { + iconv_t cnv = iconv_open(enc, UTF8_ENC); + if (cnv==(iconv_t)-1) return -1; + + char src[] = ""; + char dst[64]; + + char *inbuf = src; + size_t inbytes = 1; + char *outbuf = dst; + size_t outbytes = sizeof(dst); + + size_t n = iconv(cnv, &inbuf, &inbytes, &outbuf, &outbytes); + DASSERT(n==0); + DASSERT(inbytes==0); + + int size = (int)(sizeof(dst) - outbytes); + + iconv_close(cnv); + + if (null_size) *null_size = size; + + return 0; +} + +static void do_iconv_hash_val_free(todbc_hash_t *hash, void *val, void *arg) { + todbc_iconvset_t *cnv = (todbc_iconvset_t*)arg; + todbc_iconv_t *v = (todbc_iconv_t*)val; + DASSERT(hash); + DASSERT(cnv); + DASSERT(v); + todbc_iconv_free(v); +} + +static unsigned long do_iconv_hash_key_hash(todbc_hash_t *hash, void *key) { + todbc_iconv_key_t *k = (todbc_iconv_key_t*)key; + DASSERT(k); + unsigned long h = hash_seed; + h = hashing(h, (const unsigned char*)k->enc_to); + h = hashing(h, (const unsigned char*)k->enc_from); + return h; +} + +static int do_iconv_hash_key_comp(todbc_hash_t *hash, void *key, void *val) { + todbc_iconv_key_t *k = (todbc_iconv_key_t*)key; + todbc_iconv_t *v = (todbc_iconv_t*)val; + if (strcasecmp(k->enc_to, v->key.enc_to)) return 1; + if (strcasecmp(k->enc_from, v->key.enc_from)) return 1; + return 0; +} + +static unsigned long hashing(unsigned long hash, const unsigned char *str) { + unsigned long c; + while ((c = *str++)!=0) { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + + return hash; +} + diff --git a/src/connector/odbc/src/todbc_iconv.h b/src/connector/odbc/src/todbc_iconv.h new file mode 100644 index 0000000000..269900f8f1 --- /dev/null +++ b/src/connector/odbc/src/todbc_iconv.h @@ -0,0 +1,114 @@ +/* + * 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 _todbc_iconv_h_ +#define _todbc_iconv_h_ + +#include "todbc_buf.h" +#include "todbc_string.h" + +#include + +// non-thread-safe + +#define ASCII_ENC "ASCII" +#define UTF8_ENC "UTF-8" +#define UTF16_ENC "UCS-2LE" +#define UNICODE_ENC "UCS-4LE" +#define GB18030_ENC "GB18030" + +#define MAX_CHARACTER_SIZE 6 + +typedef enum { + TSDB_CONV_OK = 0, + TSDB_CONV_NOT_AVAIL, + TSDB_CONV_OOM, + TSDB_CONV_OOR, + TSDB_CONV_TRUNC_FRACTION, + TSDB_CONV_TRUNC, + TSDB_CONV_CHAR_NOT_NUM, + TSDB_CONV_CHAR_NOT_TS, + TSDB_CONV_NOT_VALID_TS, + TSDB_CONV_GENERAL, + TSDB_CONV_BAD_CHAR, + TSDB_CONV_SRC_TOO_LARGE, + TSDB_CONV_SRC_BAD_SEQ, + TSDB_CONV_SRC_INCOMPLETE, + TSDB_CONV_SRC_GENERAL, +} TSDB_CONV_CODE; + +typedef struct todbc_iconvset_s todbc_iconvset_t; +typedef struct todbc_iconv_s todbc_iconv_t; +typedef struct todbc_enc_s todbc_enc_t; +struct todbc_enc_s { + int char_size; // character size at most + int null_size; // size for null terminator + int variable_char_size; // such as 3 for UTF8 + char enc[64]; // move here to satisfy todbc_enc_t enc = {0}; +}; + +todbc_iconvset_t* todbc_iconvset_create(void); +void todbc_iconvset_free(todbc_iconvset_t *cnvset); +todbc_iconv_t* todbc_iconvset_get(todbc_iconvset_t *cnvset, const char *enc_to, const char *enc_from); +todbc_enc_t todbc_iconvset_enc(todbc_iconvset_t *cnvset, const char *enc); + +typedef struct todbc_bytes_s todbc_bytes_t; +typedef struct todbc_err_s todbc_err_t; + +struct todbc_err_s { + unsigned int einval:1; // EINVAL + unsigned int eilseq:1; // EILSEQ + unsigned int etoobig:1; // E2BIG + unsigned int eoom:1; // ENOMEM +}; + +struct todbc_bytes_s { + size_t inbytes, outbytes; + size_t chars; + + todbc_err_t err; +}; + +typedef struct todbc_iconv_arg_s todbc_iconv_arg_t; +struct todbc_iconv_arg_s { + const unsigned char *inbuf; + size_t inbytes; // -1: not set + unsigned char *outbuf; + size_t outbytes; // -1: not set + + size_t chars; // -1: not set +}; + +iconv_t todbc_iconv_get(todbc_iconv_t *cnv); +int todbc_iconv_get_legal_chars(todbc_iconv_t *cnv, const unsigned char *str, todbc_bytes_t *bc); +// non-thread-safe +// use todbc_buf_t as mem-allocator, if NULL, fall-back to thread-local version +unsigned char* todbc_iconv_conv(todbc_iconv_t *cnv, todbc_buf_t *buf, const unsigned char *src, todbc_bytes_t *bc); +// null-terminator-inclusive +size_t todbc_iconv_est_bytes(todbc_iconv_t *cnv, size_t inbytes); +// if inchars>=0 && enc_from has fixed-char-size, returns inchars * char_size +// otherwise -1 +size_t todbc_iconv_bytes(todbc_iconv_t *cnv, size_t inchars); +todbc_enc_t todbc_iconv_from(todbc_iconv_t *cnv); +todbc_enc_t todbc_iconv_to(todbc_iconv_t *cnv); + +// at return, *slen/*dlen stores the remaining # +int todbc_iconv_raw(todbc_iconv_t *cnv, const unsigned char *src, size_t *slen, unsigned char *dst, size_t *dlen); +// use todbc_buf_t as mem-allocator, if NULL, fall-back to thread-local version +// at return, *slen stores the remaining # +todbc_string_t todbc_iconv_conv2(todbc_iconv_t *cnv, todbc_buf_t *buf, const unsigned char *src, size_t *slen); + +#endif // _todbc_iconv_h_ + diff --git a/src/connector/odbc/src/todbc_list.c b/src/connector/odbc/src/todbc_list.c new file mode 100644 index 0000000000..447ce4826c --- /dev/null +++ b/src/connector/odbc/src/todbc_list.c @@ -0,0 +1,256 @@ +/* + * 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 "todbc_list.h" + +#include "todbc_log.h" + +#include + +struct todbc_list_s { + todbc_list_conf_t conf; + + todbc_list_node_t *head; + todbc_list_node_t *tail; + size_t count; +}; + +struct todbc_list_node_s { + void *val; + + todbc_list_t *list; + todbc_list_node_t *next; + todbc_list_node_t *prev; +}; + +static void do_remove(todbc_list_t *list, todbc_list_node_t *node); + +static void do_pushback(todbc_list_t *list, todbc_list_node_t *node); +static void do_pushfront(todbc_list_t *list, todbc_list_node_t *node); + +todbc_list_t* todbc_list_create(todbc_list_conf_t conf) { + todbc_list_t *list = (todbc_list_t*)calloc(1, sizeof(*list)); + if (!list) return NULL; + + list->conf = conf; + + return list; +} + +void todbc_list_free(todbc_list_t *list) { + if (!list) return; + + while (list->head) { + void *val = list->head->val; + do_remove(list, list->head); + if (!list->conf.val_free) continue; + list->conf.val_free(list, val, list->conf.arg); + } + + DASSERT(list->count == 0); +} + +size_t todbc_list_count(todbc_list_t *list) { + if (!list) return 0; + return list->count; +} + +int todbc_list_pushback(todbc_list_t *list, void *val) { + if (!list) return -1; + + todbc_list_node_t *node = (todbc_list_node_t*)calloc(1, sizeof(*node)); + if (!node) return -1; + node->val = val; + + do_pushback(list, node); + + return 0; +} + +int todbc_list_pushfront(todbc_list_t *list, void *val) { + if (!list) return -1; + + todbc_list_node_t *node = (todbc_list_node_t*)calloc(1, sizeof(*node)); + if (!node) return -1; + node->val = val; + + do_pushfront(list, node); + + return 0; +} + +int todbc_list_popback(todbc_list_t *list, void **val, int *found) { + if (!list) return -1; + if (!found) return -1; + + *found = 0; + + todbc_list_node_t *node = list->tail; + if (!node) return 0; + + if (val) *val = node->val; + do_remove(list, node); + + *found = 1; + + return 0; +} + +int todbc_list_popfront(todbc_list_t *list, void **val, int *found) { + if (!list) return -1; + if (!found) return -1; + + *found = 0; + + todbc_list_node_t *node = list->head; + if (!node) return 0; + + if (val) *val = node->val; + do_remove(list, node); + + *found = 1; + + return 0; +} + +int todbc_list_pop(todbc_list_t *list, void *val, int *found) { + if (!list) return -1; + if (!found) return -1; + + *found = 0; + + todbc_list_node_t *node = list->head; + while (node) { + if (node->val == val) break; + node = node->next; + } + + if (!node) return 0; + + do_remove(list, node); + + *found = 1; + + return 0; +} + +int todbc_list_traverse(todbc_list_t *list, list_iterate_f iterate, void *arg) { + if (!list) return -1; + if (!iterate) return -1; + + todbc_list_node_t *node = list->head; + while (node) { + int r = iterate(list, node->val, arg); + if (r) return r; + node = node->next; + } + + return 0; +} + +typedef struct comp_s comp_t; +struct comp_s { + list_comp_f comp; + void *arg; + int found; + void *val; +}; + +static int do_comp(todbc_list_t *list, void *val, void *arg); + +int todbc_list_find(todbc_list_t *list, void *val, int *found, list_comp_f comp, void *arg) { + if (!list) return -1; + if (!found) return -1; + if (!comp) return -1; + + *found = 0; + + comp_t sarg = {0}; + sarg.comp = comp; + sarg.arg = arg; + sarg.val = val; + todbc_list_traverse(list, do_comp, &sarg); + if (sarg.found) { + *found = 1; + } + return 0; +} + +static int do_comp(todbc_list_t *list, void *val, void *arg) { + comp_t *sarg = (comp_t*)arg; + + int r = sarg->comp(list, val, sarg->val, sarg->arg); + if (r==0) { + sarg->found = 1; + } + + return r; +} + +static void do_remove(todbc_list_t *list, todbc_list_node_t *node) { + DASSERT(node); + DASSERT(list); + DASSERT(list == node->list); + + todbc_list_node_t *prev = node->prev; + todbc_list_node_t *next = node->next; + if (prev) prev->next = next; + else list->head = next; + if (next) next->prev = prev; + else list->tail = prev; + node->prev = NULL; + node->next = NULL; + node->list = NULL; + node->val = NULL; + + list->count -= 1; + DASSERT(list->count <= INT64_MAX); + + free(node); +} + +static void do_pushback(todbc_list_t *list, todbc_list_node_t *node) { + DASSERT(list); + DASSERT(node); + DASSERT(node->list == NULL); + DASSERT(node->prev == NULL); + DASSERT(node->next == NULL); + + node->list = list; + node->prev = list->tail; + if (list->tail) list->tail->next = node; + else list->head = node; + list->tail = node; + + list->count += 1; + DASSERT(list->count > 0); +} + +static void do_pushfront(todbc_list_t *list, todbc_list_node_t *node) { + DASSERT(node); + DASSERT(node->list == NULL); + DASSERT(node->prev == NULL); + DASSERT(node->next == NULL); + + node->list = list; + node->next = list->head; + if (list->head) list->head->prev = node; + else list->tail = node; + list->head = node; + + list->count += 1; + DASSERT(list->count > 0); +} + diff --git a/src/connector/odbc/src/todbc_list.h b/src/connector/odbc/src/todbc_list.h new file mode 100644 index 0000000000..d84ffd88a0 --- /dev/null +++ b/src/connector/odbc/src/todbc_list.h @@ -0,0 +1,53 @@ +/* + * 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 _todbc_list_h_ +#define _todbc_list_h_ + +#include +#include + +// non-thread-safe + +typedef struct todbc_list_s todbc_list_t; +typedef struct todbc_list_node_s todbc_list_node_t; + +typedef struct todbc_list_conf_s todbc_list_conf_t; + +typedef void (*list_val_free_f)(todbc_list_t *list, void *val, void *arg); + +struct todbc_list_conf_s { + void *arg; + list_val_free_f val_free; +}; + +todbc_list_t* todbc_list_create(todbc_list_conf_t conf); +void todbc_list_free(todbc_list_t *list); + +size_t todbc_list_count(todbc_list_t *list); + +int todbc_list_pushback(todbc_list_t *list, void *val); +int todbc_list_pushfront(todbc_list_t *list, void *val); +int todbc_list_popback(todbc_list_t *list, void **val, int *found); +int todbc_list_popfront(todbc_list_t *list, void **val, int *found); +int todbc_list_pop(todbc_list_t *list, void *val, int *found); +typedef int (*list_iterate_f)(todbc_list_t *list, void *val, void *arg); +int todbc_list_traverse(todbc_list_t *list, list_iterate_f iterate, void *arg); +typedef int (*list_comp_f)(todbc_list_t *list, void *old, void *val, void *arg); +int todbc_list_find(todbc_list_t *list, void *val, int *found, list_comp_f comp, void *arg); + + +#endif // _todbc_list_h_ + diff --git a/src/connector/odbc/src/todbc_log.c b/src/connector/odbc/src/todbc_log.c new file mode 100644 index 0000000000..c83ad2d62d --- /dev/null +++ b/src/connector/odbc/src/todbc_log.c @@ -0,0 +1,94 @@ +/* + * 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 "todbc_log.h" + +uint64_t todbc_get_threadid(void) { + uint64_t tid = 0; +#ifdef __APPLE__ + pthread_threadid_np(NULL, &tid); +#elif defined(__linux__) + tid = (uint64_t)syscall(__NR_gettid); +#elif defined(_MSC_VER) + tid = GetCurrentThreadId(); +#else +#error you have to check the target API for thread id +#endif + return tid; +} + +#ifdef _MSC_VER +static __declspec(thread) uint64_t thread_id = 0; +#else +static __thread uint64_t thread_id = 0; +#endif + +#ifdef __GNUC__ + __attribute__((format(printf, 6, 7))) +#endif +void todbc_log(const char *file, int line, const char *func, const char tag, int err, const char *fmt, ...) { + struct tm stm = {0}; + struct timeval tv; + + if (thread_id==0) { + thread_id = todbc_get_threadid(); + } + + gettimeofday(&tv, NULL); + time_t tt = tv.tv_sec; + localtime_r(&tt, &stm); + + char buf[4096]; + size_t bytes = sizeof(buf); + + char *p = buf; + int n = 0; + + n = snprintf(p, bytes, "%C%02d:%02d:%02d.%06d[%" PRIx64 "]%s[%d]%s()", + tag, stm.tm_hour, stm.tm_min, stm.tm_sec, (int)tv.tv_usec, + thread_id, basename((char*)file), line, func); + if (n>0) { + bytes -= (size_t)n; + p += n; + } + + if (bytes>0) { + if (tag=='E' && err) { + n = snprintf(p, bytes, "[%d]%s", err, strerror(err)); + if (n>0) { + bytes -= (size_t)n; + p += n; + } + } + } + + if (bytes>0) { + n = snprintf(p, bytes, ": "); + if (n>0) { + bytes -= (size_t)n; + p += n; + } + } + + if (bytes>0) { + va_list ap; + va_start(ap, fmt); + n = vsnprintf(p, bytes, fmt, ap); + va_end(ap); + } + + fprintf(stderr, "%s\n", buf); +} + diff --git a/src/connector/odbc/src/todbc_log.h b/src/connector/odbc/src/todbc_log.h index 391a690ccc..30ef8436e1 100644 --- a/src/connector/odbc/src/todbc_log.h +++ b/src/connector/odbc/src/todbc_log.h @@ -18,25 +18,35 @@ #include "os.h" -#define D(fmt, ...) \ - fprintf(stderr, \ - "%s[%d]:%s() " fmt "\n", \ - basename((char*)__FILE__), __LINE__, __func__, \ - ##__VA_ARGS__) +#ifdef __GNUC__ + __attribute__((format(printf, 6, 7))) +#endif +void todbc_log(const char *file, int line, const char *func, const char tag, int err, const char *fmt, ...); -#define DASSERT(statement) \ -do { \ - if (statement) break; \ - D("Assertion failure: %s", #statement); \ - abort(); \ +#define OL(tag, err, fmt, ...) todbc_log(__FILE__, __LINE__, __func__, tag, err, "%s" fmt "", "", ##__VA_ARGS__) +#define OD(fmt, ...) OL('D', 0, fmt, ##__VA_ARGS__) +#define OE(fmt, ...) OL('E', errno, fmt, ##__VA_ARGS__) +#define OW(fmt, ...) OL('W', 0, fmt, ##__VA_ARGS__) +#define OI(fmt, ...) OL('I', 0, fmt, ##__VA_ARGS__) +#define OV(fmt, ...) OL('V', 0, fmt, ##__VA_ARGS__) +#define OA(statement, fmt, ...) do { \ + if (statement) break; \ + OL('A', 0, "Assertion failure:[%s]; " fmt "", #statement, ##__VA_ARGS__); \ + abort(); \ } while (0) +#define OILE(statement, fmt, ...) OA(statement, "internal logic error: [" fmt "]", ##__VA_ARGS__) +#define ONIY(statement, fmt, ...) OA(statement, "not implemented yet: [" fmt "]", ##__VA_ARGS__) +#define ONSP(statement, fmt, ...) OA(statement, "not support yet: [" fmt "]", ##__VA_ARGS__) + +#define D(fmt, ...) OD(fmt, ##__VA_ARGS__) +#define E(fmt, ...) OE(fmt, ##__VA_ARGS__) +#define DASSERT(statement) OA(statement, "") +#define DASSERTX(statement, fmt, ...) OA(statement, fmt, ##__VA_ARGS__) + + +uint64_t todbc_get_threadid(void); + -#define DASSERTX(statement, fmt, ...) \ -do { \ - if (statement) break; \ - D("Assertion failure: %s, " fmt "", #statement, ##__VA_ARGS__); \ - abort(); \ -} while (0) #endif // _todbc_log_h_ diff --git a/src/connector/odbc/src/todbc_scanner.l b/src/connector/odbc/src/todbc_scanner.l index f8c6a15d92..b36c894f73 100644 --- a/src/connector/odbc/src/todbc_scanner.l +++ b/src/connector/odbc/src/todbc_scanner.l @@ -1,11 +1,18 @@ %{ +#ifdef _MSC_VER +#include +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#define basename PathFindFileNameA +#else +#include +#endif + #include "todbc_flex.h" #include +#include -#ifdef _MSC_VER -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif +static int process_map(const char *cfg, map_tsdb_type_t *tsdb_map, int type); #define PUSH_STATE(state) yy_push_state(state, yyscanner) #define POP_STATE() yy_pop_state(yyscanner) @@ -28,50 +35,73 @@ do { \ while (yyleng) unput(yytext[yyleng-1]); \ } while (0) -#define set_key() \ -do { \ - free(yyextra->key); \ - yyextra->key = strdup(yytext); \ +#define set_val() \ +do { \ + int r = 0; \ + int curr; TOP_STATE(curr); \ + POP_STATE(); \ + int state; TOP_STATE(state); \ + switch(state) { \ + case DSN: { \ + free(yyextra->dsn); \ + yyextra->dsn = strdup(yytext); \ + } break; \ + case UID: { \ + free(yyextra->uid); \ + yyextra->uid = strdup(yytext); \ + } break; \ + case PWD: { \ + free(yyextra->pwd); \ + yyextra->pwd = strdup(yytext); \ + } break; \ + case SERVER: { \ + free(yyextra->server); \ + yyextra->server = strdup(yytext); \ + } break; \ + case DB: { \ + free(yyextra->db); \ + yyextra->db = strdup(yytext); \ + } break; \ + case ENC_CHAR: { \ + free(yyextra->enc_char); \ + yyextra->enc_char = strdup(yytext); \ + } break; \ + case ENC_WCHAR: { \ + free(yyextra->enc_wchar); \ + yyextra->enc_wchar = strdup(yytext); \ + } break; \ + case ENC_DB: { \ + free(yyextra->enc_db); \ + yyextra->enc_db = strdup(yytext); \ + } break; \ + case ENC_LOCAL: { \ + free(yyextra->enc_local); \ + yyextra->enc_local = strdup(yytext); \ + } break; \ + case TSDB_FLOAT: { \ + if (process_map(yytext, &yyextra->tsdb_map, TSDB_FLOAT)) { \ + r = -1; \ + } \ + } break; \ + case TSDB_BIGINT: { \ + if (process_map(yytext, &yyextra->tsdb_map, TSDB_BIGINT)) { \ + r = -1; \ + } \ + } break; \ + case KEY: { \ + } break; \ + default: { \ + r = -1; \ + } break; \ + } \ + PUSH_STATE(curr); \ + if (r) return r; \ } while (0) -#define set_val() \ -do { \ - if (!yyextra->key) break; \ - if (strcasecmp(yyextra->key, "DSN")==0) { \ - free(yyextra->dsn); \ - yyextra->dsn = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "UID")==0) { \ - free(yyextra->uid); \ - yyextra->uid = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "PWD")==0) { \ - free(yyextra->pwd); \ - yyextra->pwd = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "DB")==0) { \ - free(yyextra->db); \ - yyextra->pwd = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "Server")==0) { \ - free(yyextra->server); \ - yyextra->server = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "SERVER_ENC")==0) { \ - free(yyextra->svr_enc); \ - yyextra->svr_enc = strdup(yytext); \ - break; \ - } \ - if (strcasecmp(yyextra->key, "CLIENT_ENC")==0) { \ - free(yyextra->cli_enc); \ - yyextra->cli_enc = strdup(yytext); \ - break; \ - } \ +#define FAIL() \ +do { \ + /*fprintf(stderr, "==%s[%d]%s()==\n", basename(__FILE__), __LINE__, __func__);*/ \ + return -1; \ } while (0) %} @@ -89,57 +119,85 @@ do { \ %option warn %option perf-report %option 8bit +%option case-insensitive +%x DSN UID PWD SERVER DB +%x ENC_CHAR ENC_WCHAR ENC_DB ENC_LOCAL +%x TSDB_FLOAT TSDB_BIGINT %x KEY EQ BRACE1 BRACE2 VAL %% <> { int state; TOP_STATE(state); if (state == INITIAL) yyterminate(); if (state == VAL) yyterminate(); - return -1; } + FAIL(); } [[:space:]]+ { } -[[:alnum:]_]+ { set_key(); PUSH_STATE(KEY); } -.|\n { return -1; } +"DSN" { PUSH_STATE(DSN); } +"UID" { PUSH_STATE(UID); } +"PWD" { PUSH_STATE(PWD); } +"Server" { PUSH_STATE(SERVER); } +"DB" { PUSH_STATE(DB); } +"ENC_CHAR" { PUSH_STATE(ENC_CHAR); } +"ENC_WCHAR" { PUSH_STATE(ENC_WCHAR); } +"ENC_DB" { PUSH_STATE(ENC_DB); } +"ENC_LOCAL" { PUSH_STATE(ENC_LOCAL); } +"map.float" { PUSH_STATE(TSDB_FLOAT); } +"map.bigint" { PUSH_STATE(TSDB_BIGINT); } +[[:alnum:]_]+ { PUSH_STATE(KEY); } +.|\n { FAIL(); } -[[:space:]]+ { } -[=] { CHG_STATE(EQ); } -.|\n { return -1; } +[[:space:]]+ { } +[=] { PUSH_STATE(EQ); } +.|\n { FAIL(); } [[:space:]]+ { } -[^][{}(),;?*=!@/\\\n[:space:]]+ { set_val(); CHG_STATE(VAL); } [{] { CHG_STATE(BRACE1); } -.|\n { return -1; } +[^][{}(),;?*=!@/\\\n[:space:]]+ { set_val(); POP_STATE(); CHG_STATE(VAL); } +.|\n { FAIL(); } [^{}\n]+ { set_val(); CHG_STATE(BRACE2); } -.|\n { return -1; } +.|\n { FAIL(); } [[:space:]]+ { } -[}] { CHG_STATE(VAL); } -.|\n { return -1; } +[}] { POP_STATE(); CHG_STATE(VAL); } +.|\n { FAIL(); } [;] { POP_STATE(); } -.|\n { return -1; } +.|\n { FAIL(); } %% +static char* get_val_by_key_from_odbc_ini(const char *dsn, const char *key); + +static void conn_val_init(conn_val_t *val); + int todbc_parse_conn_string(const char *conn, conn_val_t *val) { yyscan_t arg = {0}; yylex_init(&arg); yyset_debug(0, arg); yyset_extra(val, arg); + + conn_val_init(val); + yy_scan_string(conn, arg); int ret =yylex(arg); yylex_destroy(arg); - if (val->key) free(val->key); val->key = NULL; - if (ret) { + if (ret || !val->dsn) { conn_val_reset(val); + } else { + if (!val->uid) { + val->uid = get_val_by_key_from_odbc_ini(val->dsn, "UID"); + } + if (!val->pwd) { + val->pwd = get_val_by_key_from_odbc_ini(val->dsn, "PWD"); + } + if (!val->server) { + val->server = get_val_by_key_from_odbc_ini(val->dsn, "Server"); + } } return ret ? -1 : 0; } void conn_val_reset(conn_val_t *val) { - if (val->key) { - free(val->key); val->key = NULL; - } if (val->dsn) { free(val->dsn); val->dsn = NULL; } @@ -155,11 +213,68 @@ void conn_val_reset(conn_val_t *val) { if (val->server) { free(val->server); val->server = NULL; } - if (val->svr_enc) { - free(val->svr_enc); val->svr_enc = NULL; + if (val->enc_local) { + free(val->enc_local); val->enc_local = NULL; } - if (val->cli_enc) { - free(val->cli_enc); val->cli_enc = NULL; + if (val->enc_db) { + free(val->enc_db); val->enc_db = NULL; + } + if (val->enc_char) { + free(val->enc_char); val->enc_char = NULL; + } + if (val->enc_wchar) { + free(val->enc_wchar); val->enc_wchar = NULL; } } +static char* get_val_by_key_from_odbc_ini(const char *dsn, const char *key) { + char Val[4096]; + Val[0] = '\0'; + int n = SQLGetPrivateProfileString(dsn, key, "", Val, sizeof(Val), "odbc.ini"); + if (n<=0) return NULL; + if (Val[0]=='\0') return NULL; + return strdup(Val); +} + +static int process_map(const char *cfg, map_tsdb_type_t *tsdb_map, int type) { + switch (type) { + case TSDB_FLOAT: { + if (strcmp(cfg, "SQL_DOUBLE")==0) { + tsdb_map->tsdb_float = SQL_DOUBLE; + return 0; + } + } break; + case TSDB_BIGINT: { + if (strcmp(cfg, "SQL_C_SBIGINT")==0) { + tsdb_map->tsdb_bigint = SQL_C_SBIGINT; + return 0; + } + if (strcmp(cfg, "SQL_C_UBIGINT")==0) { + tsdb_map->tsdb_bigint = SQL_C_UBIGINT; + return 0; + } + if (strcmp(cfg, "SQL_CHAR")==0) { + tsdb_map->tsdb_bigint = SQL_CHAR; + return 0; + } + } break; + default: { + } break; + } + return -1; +} + +static void conn_val_init(conn_val_t *val) { + if (!val) return; + val->tsdb_map.tsdb_tinyint = SQL_TINYINT; + val->tsdb_map.tsdb_smallint = SQL_SMALLINT; + val->tsdb_map.tsdb_int = SQL_INTEGER; + val->tsdb_map.tsdb_bigint = SQL_BIGINT; + val->tsdb_map.tsdb_float = SQL_REAL; + val->tsdb_map.tsdb_double = SQL_DOUBLE; + val->tsdb_map.tsdb_bool = SQL_TINYINT; + val->tsdb_map.tsdb_timestamp = SQL_CHAR; + val->tsdb_map.tsdb_binary = SQL_BINARY; + val->tsdb_map.tsdb_nchar = SQL_WCHAR; +} + diff --git a/src/connector/odbc/src/todbc_string.c b/src/connector/odbc/src/todbc_string.c new file mode 100644 index 0000000000..96e9a6d8c3 --- /dev/null +++ b/src/connector/odbc/src/todbc_string.c @@ -0,0 +1,218 @@ +/* + * 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 "todbc_string.h" + +#include "todbc_log.h" +#include "todbc_tls.h" + +#include + +static int do_calc_bytes(todbc_string_t *str); + +todbc_string_t todbc_string_init(const char *enc, const unsigned char *src, const size_t bytes) { + DASSERT(enc); + DASSERT(src); + + todbc_string_t s = {0}; + todbc_string_t *str = &s; + + todbc_iconv_t *cnv = todbc_tls_iconv_get(enc, UTF8_ENC); + if (!cnv) return s; + + if (snprintf(str->enc, sizeof(str->enc), "%s", enc)>=sizeof(str->enc)) { + return s; + } + str->buf = src; + str->total_bytes = bytes; // need to recalc + str->bytes = 0; + + if (do_calc_bytes(str)) { + str->buf = NULL; + str->total_bytes = 0; + str->bytes = 0; + } + + return s; +} + +todbc_string_t todbc_string_copy(todbc_string_t *str, const char *enc, unsigned char *dst, const size_t target_bytes) { + todbc_string_t val = {0}; + DASSERT(str); + DASSERT(dst); + DASSERT(str->buf); + DASSERT(str->bytes<=INT64_MAX); + DASSERT(str->total_bytes<=INT64_MAX); + + if (snprintf(val.enc, sizeof(val.enc), "%s", enc)>=sizeof(val.enc)) { + return val; + } + + todbc_iconv_t *icnv = todbc_tls_iconv_get(enc, str->enc); + if (!icnv) return val; + iconv_t cnv = todbc_iconv_get(icnv); + if (cnv==(iconv_t)-1) return val; + + val.buf = dst; + val.total_bytes = target_bytes; + + const int null_bytes = todbc_iconv_to(icnv).null_size; + + if (target_bytes<=null_bytes) return val; + size_t estsize = todbc_iconv_est_bytes(icnv, str->bytes); + if (estsize>INT64_MAX) return val; + + // smaller is better!!! + const size_t outblock = (estsize > target_bytes) ? estsize = target_bytes : estsize; + + char *inbuf = (char*)str->buf; + size_t inbytes = str->bytes; // not counting null-terminator + char *outbuf = (char*)dst; + size_t outbytes = outblock; + + int r = todbc_iconv_raw(icnv, (const unsigned char*)inbuf, &inbytes, (unsigned char*)outbuf, &outbytes); + if (r) { + DASSERT(outbytes > 0); + val.bytes = outblock - outbytes; + val.total_bytes = outblock; + return val; + } else { + val.bytes = outblock - outbytes; + val.total_bytes = val.bytes; + if (inbytes > 0) { + val.total_bytes += 1; // to indicate truncation + } + return val; + } +} + +todbc_string_t todbc_copy(const char *from_enc, const unsigned char *src, size_t *inbytes, const char *to_enc, unsigned char *dst, const size_t dlen) { + DASSERT(from_enc); + DASSERT(src); + DASSERT(inbytes); + DASSERT(to_enc); + DASSERT(dst); + DASSERT(dlen <= INT64_MAX); + + todbc_string_t s_from = todbc_string_init(from_enc, src, *inbytes); + DASSERT(s_from.buf == src); + + return todbc_string_copy(&s_from, to_enc, dst, dlen); +} + +todbc_string_t todbc_string_conv_to(todbc_string_t *str, const char *enc, todbc_buf_t *buf) { + DASSERT(str); + DASSERT(str->buf); + DASSERT(str->bytes<=INT64_MAX); + DASSERT(str->total_bytes<=INT64_MAX); + + todbc_string_t nul = {0}; + + todbc_iconv_t *icnv = todbc_tls_iconv_get(enc, str->enc); + if (!icnv) return nul; + + size_t estsize = todbc_iconv_est_bytes(icnv, str->bytes); + if (estsize>INT64_MAX) return nul; + char *out = NULL; + if (!buf) out = (char*)todbc_tls_buf_alloc(estsize); + else out = (char*)todbc_buf_alloc(buf, estsize); + if (!out) return nul; + + return todbc_string_copy(str, enc, (unsigned char*)out, estsize); +} + +static int do_calc_bytes(todbc_string_t *str) { + iconv_t cnv = todbc_tls_iconv(UTF8_ENC, str->enc); + if (cnv == (iconv_t)-1) return -1; + + size_t total_bytes = 0; + + char buf[1024*16]; + + char *inbuf = (char*)str->buf; + + while (1) { + size_t outblock = sizeof(buf); + + size_t inblock = outblock; + size_t remain = (size_t)-1; + if (str->total_bytes <= INT64_MAX) { + remain = str->total_bytes - total_bytes; + if (remain==0) break; + if (inblock > remain) inblock = remain; + } + + size_t inbytes = inblock; + char *outbuf = buf; + size_t outbytes = outblock; + + size_t n = iconv(cnv, &inbuf, &inbytes, &outbuf, &outbytes); + total_bytes += inblock - inbytes; + + int e = 0; + if (n==(size_t)-1) { + e = errno; + if (str->total_bytes<=INT64_MAX) { + D("iconv failed @[%zu], inbytes[%zd->%zd], outbytes[%zd->%zd]: [%d]%s", + (inblock-inbytes), inblock, inbytes, outblock, outbytes, e, strerror(e)); + } + DASSERT(e==EILSEQ || e==E2BIG || e==EINVAL); + } + if (n>0 && n<=INT64_MAX) { + D("iconv found non-reversible seq"); + } + + size_t outlen = outblock - outbytes; + size_t utf8len = strnlen(buf, outlen); + if (utf8len < outlen) { + // null-terminator found + // revert + inbuf -= inblock - inbytes; + total_bytes -= inblock - inbytes; + + if (utf8len==0) break; + + inbytes = inblock; + outbuf = buf; + outbytes = utf8len; + + n = iconv(cnv, &inbuf, &inbytes, &outbuf, &outbytes); + total_bytes += inblock - inbytes; + DASSERT(n==(size_t)-1); + e = errno; + DASSERT(e==E2BIG); + + break; + } + + if (e==EILSEQ) break; + if (e==EINVAL) { + if (inbytes == remain) { + // this is the last stuff + break; + } + } + } + + if (str->total_bytes > INT64_MAX) { + str->total_bytes = total_bytes; + } + str->bytes = total_bytes; + + iconv(cnv, NULL, NULL, NULL, NULL); + + return 0; +} + diff --git a/src/connector/odbc/src/todbc_string.h b/src/connector/odbc/src/todbc_string.h new file mode 100644 index 0000000000..eed3356847 --- /dev/null +++ b/src/connector/odbc/src/todbc_string.h @@ -0,0 +1,54 @@ +/* + * 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 _todbc_string_h_ +#define _todbc_string_h_ + +#include +#include + +#include "todbc_buf.h" + +// non-thread-safe + +typedef struct todbc_string_s todbc_string_t; +struct todbc_string_s { + // null if init failed because of internal resources shortage + const unsigned char *buf; // null-terminator inclusive + size_t total_bytes; // not counting null-terminator + + // <= total_bytes + // truncated if < total_bytes + size_t bytes; // not counting null-terminator + + // move here to satisfy todbc_string_t dummy = {0}; + char enc[64]; +}; + + +// does not copy internally +// bytes: not characters, <0 means bytes unknown +todbc_string_t todbc_string_init(const char *enc, const unsigned char *src, const size_t bytes); +// conv and copy to dst not more than target_bytes (null-terminator-inclusive) +// return'd val->buf == dst, total_bytes + * + * 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 "todbc_tls.h" + +#include "todbc_buf.h" +#include "todbc_iconv.h" +#include "todbc_log.h" + + +typedef struct todbc_tls_s todbc_tls_t; + +struct todbc_tls_s { + todbc_buf_t *buf; + todbc_iconvset_t *cnvset; +}; + + +static void todbc_tls_free(todbc_tls_t *value); + +static pthread_key_t key_this; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; +static int key_err = 0; + + +static void key_init(void); +static void key_destructor(void *arg); + + +static void key_init(void) { + key_err = pthread_key_create(&key_this, key_destructor); + if (key_err) { + D("thread local initialization failed: [%d]%s", key_err, strerror(key_err)); + } +} + +static todbc_tls_t* todbc_tls_create(void); + +static todbc_tls_t* key_value(void) { + pthread_once(&key_once, key_init); + if (key_err) return NULL; + + int err = 0; + + todbc_tls_t *value = pthread_getspecific(key_this); + if (value) return value; + + value = todbc_tls_create(); + if (!value) return NULL; + + do { + err = pthread_setspecific(key_this, value); + if (err) { + D("thread local setup failed: [%d]%s", err, strerror(err)); + break; + } + + return value; + } while (0); + + todbc_tls_free(value); + + return NULL; +} + +static void key_destructor(void *arg) { + todbc_tls_t *value = (todbc_tls_t*)arg; + todbc_tls_free(value); +} + +static todbc_tls_t* todbc_tls_create(void) { + int err = 0; + todbc_tls_t *value = (todbc_tls_t*)calloc(1, sizeof(*value)); + if (!value) { + err = errno; + D("thread local creation failed: [%d]%s", err, strerror(err)); + return NULL; + } + do { + return value; + } while (0); + + todbc_tls_free(value); + return NULL; +} + +static void todbc_tls_free(todbc_tls_t *value) { + if (value->cnvset) { + todbc_iconvset_free(value->cnvset); + value->cnvset = NULL; + } + + if (value->buf) { + todbc_buf_free(value->buf); + value->buf = NULL; + } + + free(value); +} + +static todbc_iconvset_t* do_get_iconvset(void); + +// iconv +int todbc_legal_chars(const char *enc, const unsigned char *str, todbc_bytes_t *bc) { + todbc_iconvset_t *icnv = do_get_iconvset(); + if (!icnv) return -1; + todbc_iconv_t *cnv = todbc_iconvset_get(icnv, UTF16_ENC, enc); + if (!cnv) return -1; + return todbc_iconv_get_legal_chars(cnv, str, bc); +} + +todbc_iconv_t* todbc_tls_iconv_get(const char *to_enc, const char *from_enc) { + todbc_iconvset_t *cnvset = do_get_iconvset(); + if (!cnvset) return NULL; + todbc_iconv_t *cnv = todbc_iconvset_get(cnvset, to_enc, from_enc); + return cnv; +} + +iconv_t todbc_tls_iconv(const char *to_enc, const char *from_enc) { + todbc_iconv_t *icnv = todbc_tls_iconv_get(to_enc, from_enc); + if (!icnv) return (iconv_t)-1; + return todbc_iconv_get(icnv); +} + +todbc_enc_t todbc_tls_iconv_enc(const char *enc) { + do { + todbc_iconvset_t *cnvset = do_get_iconvset(); + if (!cnvset) break; + return todbc_iconvset_enc(cnvset, enc); + } while (0); + + todbc_enc_t v = {0}; + v.char_size = -1; + v.null_size = -1; + + return v; +} + +todbc_string_t todbc_tls_conv(todbc_buf_t *buf, const char *enc_to, const char *enc_from, const unsigned char *src, size_t *slen) { + todbc_iconv_t *cnv = todbc_tls_iconv_get(enc_to, enc_from); + if (!cnv) { + todbc_string_t nul = {0}; + return nul; + } + return todbc_iconv_conv2(cnv, buf, src, slen); +} + +todbc_string_t todbc_tls_write(const char *enc_to, const char *enc_from, + const unsigned char *src, size_t *slen, unsigned char *dst, size_t dlen) +{ + todbc_iconv_t *cnv = todbc_tls_iconv_get(enc_to, enc_from); + if (!cnv) { + todbc_string_t nul = {0}; + return nul; + } + todbc_string_t s = {0}; + s.buf = dst; + s.total_bytes = dlen; + size_t inbytes = *slen; + size_t outbytes = dlen; + todbc_iconv_raw(cnv, src, &inbytes, dst, &outbytes); + s.bytes = dlen - outbytes; + s.total_bytes = s.bytes; + if (inbytes) { + s.total_bytes += 1; + } + *slen = inbytes; + + return s; +} + +char* todbc_tls_strndup(const char *src, size_t n) { + todbc_buf_t *buf = todbc_tls_buf(); + if (!buf) return NULL; + n = strnlen(src, n); + char *d = todbc_buf_alloc(buf, (n+1)); + if (!d) return NULL; + snprintf(d, n+1, "%s", src); + return d; +} + +static todbc_iconvset_t* do_get_iconvset(void) { + todbc_tls_t *tls = key_value(); + if (!tls) return NULL; + if (!tls->cnvset) { + tls->cnvset = todbc_iconvset_create(); + } + return tls->cnvset; +} + +// tls_buf +void* todbc_tls_buf_alloc(size_t size) { + todbc_tls_t *tls = key_value(); + if (!tls) return NULL; + if (!tls->buf) { + tls->buf = todbc_buf_create(); + if (!tls->buf) return NULL; + } + return todbc_buf_alloc(tls->buf, size); +} + +void* todbc_tls_buf_calloc(size_t count, size_t size) { + todbc_tls_t *tls = key_value(); + if (!tls) return NULL; + if (!tls->buf) { + tls->buf = todbc_buf_create(); + if (!tls->buf) return NULL; + } + return todbc_buf_calloc(tls->buf, count, size); +} + +void* todbc_tls_buf_realloc(void *ptr, size_t size) { + todbc_tls_t *tls = key_value(); + if (!tls) return NULL; + if (!tls->buf) { + tls->buf = todbc_buf_create(); + if (!tls->buf) return NULL; + } + return todbc_buf_realloc(tls->buf, ptr, size); +} + +void todbc_tls_buf_reclaim(void) { + todbc_tls_t *tls = key_value(); + if (!tls) return; + if (!tls->buf) return; + + todbc_buf_reclaim(tls->buf); +} + +todbc_buf_t* todbc_tls_buf(void) { + todbc_tls_t *tls = key_value(); + if (!tls) return NULL; + if (!tls->buf) { + tls->buf = todbc_buf_create(); + } + return tls->buf; +} + diff --git a/src/connector/odbc/src/todbc_tls.h b/src/connector/odbc/src/todbc_tls.h new file mode 100644 index 0000000000..e636f6ae6c --- /dev/null +++ b/src/connector/odbc/src/todbc_tls.h @@ -0,0 +1,56 @@ +/* + * 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 _todbc_tls_h_ +#define _todbc_tls_h_ + +// !!! functions exported in this header file are all non-thread-safe !!! + +#include "taos.h" + +#include "todbc_buf.h" +#include "todbc_iconv.h" +#include "todbc_string.h" + +// thread local buffers +// non-thread-safe +// returned-buf are all thread-local-accessible until todbc_tls_buf_reclaim +void* todbc_tls_buf_alloc(size_t size); +void* todbc_tls_buf_calloc(size_t count, size_t size); +void* todbc_tls_buf_realloc(void *ptr, size_t size); +// reclaim all above thread-local-buf(s) +void todbc_tls_buf_reclaim(void); + +// return local-thread-buf +todbc_buf_t* todbc_tls_buf(void); + +// thread local iconv +// non-thread-safe +todbc_iconv_t* todbc_tls_iconv_get(const char *to_enc, const char *from_enc); +iconv_t todbc_tls_iconv(const char *to_enc, const char *from_enc); + +todbc_enc_t todbc_tls_iconv_enc(const char *enc); + +// non-thread-safe +int todbc_legal_chars(const char *enc, const unsigned char *str, todbc_bytes_t *bc); + +// at return, *slen stores the remaining # +todbc_string_t todbc_tls_conv(todbc_buf_t *buf, const char *enc_to, const char *enc_from, const unsigned char *src, size_t *slen); +todbc_string_t todbc_tls_write(const char *enc_to, const char *enc_from, const unsigned char *src, size_t *slen, unsigned char *dst, size_t dlen); + +char* todbc_tls_strndup(const char *src, size_t n); + +#endif // _todbc_tls_h_ + diff --git a/src/connector/odbc/src/todbc_util.c b/src/connector/odbc/src/todbc_util.c index 9c130b4f2f..d0b5abe093 100644 --- a/src/connector/odbc/src/todbc_util.c +++ b/src/connector/odbc/src/todbc_util.c @@ -15,86 +15,576 @@ #include "todbc_util.h" #include "todbc_log.h" + #include #include +#define SQL_CASE(type) case type: return #type + const char* sql_sql_type(int type) { switch (type) { - case SQL_BIT: return "SQL_BIT"; - case SQL_TINYINT: return "SQL_TINYINT"; - case SQL_SMALLINT: return "SQL_SMALLINT"; - case SQL_INTEGER: return "SQL_INTEGER"; - case SQL_BIGINT: return "SQL_BIGINT"; - case SQL_FLOAT: return "SQL_FLOAT"; - case SQL_DOUBLE: return "SQL_DOUBLE"; - case SQL_DECIMAL: return "SQL_DECIMAL"; - case SQL_NUMERIC: return "SQL_NUMERIC"; - case SQL_REAL: return "SQL_REAL"; - case SQL_CHAR: return "SQL_CHAR"; - case SQL_VARCHAR: return "SQL_VARCHAR"; - case SQL_LONGVARCHAR: return "SQL_LONGVARCHAR"; - case SQL_WCHAR: return "SQL_WCHAR"; - case SQL_WVARCHAR: return "SQL_WVARCHAR"; - case SQL_WLONGVARCHAR: return "SQL_WLONGVARCHAR"; - case SQL_BINARY: return "SQL_BINARY"; - case SQL_VARBINARY: return "SQL_VARBINARY"; - case SQL_LONGVARBINARY: return "SQL_LONGVARBINARY"; - case SQL_DATE: return "SQL_DATE"; - case SQL_TIME: return "SQL_TIME"; - case SQL_TIMESTAMP: return "SQL_TIMESTAMP"; - case SQL_TYPE_DATE: return "SQL_TYPE_DATE"; - case SQL_TYPE_TIME: return "SQL_TYPE_TIME"; - case SQL_TYPE_TIMESTAMP: return "SQL_TYPE_TIMESTAMP"; - case SQL_INTERVAL_MONTH: return "SQL_INTERVAL_MONTH"; - case SQL_INTERVAL_YEAR: return "SQL_INTERVAL_YEAR"; - case SQL_INTERVAL_YEAR_TO_MONTH: return "SQL_INTERVAL_YEAR_TO_MONTH"; - case SQL_INTERVAL_DAY: return "SQL_INTERVAL_DAY"; - case SQL_INTERVAL_HOUR: return "SQL_INTERVAL_HOUR"; - case SQL_INTERVAL_MINUTE: return "SQL_INTERVAL_MINUTE"; - case SQL_INTERVAL_SECOND: return "SQL_INTERVAL_SECOND"; - case SQL_INTERVAL_DAY_TO_HOUR: return "SQL_INTERVAL_DAY_TO_HOUR"; - case SQL_INTERVAL_DAY_TO_MINUTE: return "SQL_INTERVAL_DAY_TO_MINUTE"; - case SQL_INTERVAL_DAY_TO_SECOND: return "SQL_INTERVAL_DAY_TO_SECOND"; - case SQL_INTERVAL_HOUR_TO_MINUTE: return "SQL_INTERVAL_HOUR_TO_MINUTE"; - case SQL_INTERVAL_HOUR_TO_SECOND: return "SQL_INTERVAL_HOUR_TO_SECOND"; - case SQL_INTERVAL_MINUTE_TO_SECOND: return "SQL_INTERVAL_MINUTE_TO_SECOND"; - case SQL_GUID: return "SQL_GUID"; + SQL_CASE(SQL_BIT); + SQL_CASE(SQL_TINYINT); + SQL_CASE(SQL_SMALLINT); + SQL_CASE(SQL_INTEGER); + SQL_CASE(SQL_BIGINT); + SQL_CASE(SQL_FLOAT); + SQL_CASE(SQL_DOUBLE); + SQL_CASE(SQL_DECIMAL); + SQL_CASE(SQL_NUMERIC); + SQL_CASE(SQL_REAL); + SQL_CASE(SQL_CHAR); + SQL_CASE(SQL_VARCHAR); + SQL_CASE(SQL_LONGVARCHAR); + SQL_CASE(SQL_WCHAR); + SQL_CASE(SQL_WVARCHAR); + SQL_CASE(SQL_WLONGVARCHAR); + SQL_CASE(SQL_BINARY); + SQL_CASE(SQL_VARBINARY); + SQL_CASE(SQL_LONGVARBINARY); + SQL_CASE(SQL_DATE); + SQL_CASE(SQL_TIME); + SQL_CASE(SQL_TIMESTAMP); + SQL_CASE(SQL_TYPE_DATE); + SQL_CASE(SQL_TYPE_TIME); + SQL_CASE(SQL_TYPE_TIMESTAMP); + SQL_CASE(SQL_INTERVAL_MONTH); + SQL_CASE(SQL_INTERVAL_YEAR); + SQL_CASE(SQL_INTERVAL_YEAR_TO_MONTH); + SQL_CASE(SQL_INTERVAL_DAY); + SQL_CASE(SQL_INTERVAL_HOUR); + SQL_CASE(SQL_INTERVAL_MINUTE); + SQL_CASE(SQL_INTERVAL_SECOND); + SQL_CASE(SQL_INTERVAL_DAY_TO_HOUR); + SQL_CASE(SQL_INTERVAL_DAY_TO_MINUTE); + SQL_CASE(SQL_INTERVAL_DAY_TO_SECOND); + SQL_CASE(SQL_INTERVAL_HOUR_TO_MINUTE); + SQL_CASE(SQL_INTERVAL_HOUR_TO_SECOND); + SQL_CASE(SQL_INTERVAL_MINUTE_TO_SECOND); + SQL_CASE(SQL_GUID); + SQL_CASE(SQL_ALL_TYPES); default: return "UNKNOWN"; } } const char* sql_c_type(int type) { switch (type) { - case SQL_C_CHAR: return "SQL_C_CHAR"; - case SQL_C_WCHAR: return "SQL_C_WCHAR"; - case SQL_C_SHORT: return "SQL_C_SHORT"; - case SQL_C_SSHORT: return "SQL_C_SSHORT"; - case SQL_C_USHORT: return "SQL_C_USHORT"; - case SQL_C_LONG: return "SQL_C_LONG"; - case SQL_C_SLONG: return "SQL_C_SLONG"; - case SQL_C_ULONG: return "SQL_C_ULONG"; - case SQL_C_FLOAT: return "SQL_C_FLOAT"; - case SQL_C_DOUBLE: return "SQL_C_DOUBLE"; - case SQL_C_BIT: return "SQL_C_BIT"; - case SQL_C_TINYINT: return "SQL_C_TINYINT"; - case SQL_C_STINYINT: return "SQL_C_STINYINT"; - case SQL_C_UTINYINT: return "SQL_C_UTINYINT"; - case SQL_C_SBIGINT: return "SQL_C_SBIGINT"; - case SQL_C_UBIGINT: return "SQL_C_UBIGINT"; - case SQL_C_BINARY: return "SQL_C_BINARY"; - case SQL_C_DATE: return "SQL_C_DATE"; - case SQL_C_TIME: return "SQL_C_TIME"; - case SQL_C_TIMESTAMP: return "SQL_C_TIMESTAMP"; - case SQL_C_TYPE_DATE: return "SQL_C_TYPE_DATE"; - case SQL_C_TYPE_TIME: return "SQL_C_TYPE_TIME"; - case SQL_C_TYPE_TIMESTAMP: return "SQL_C_TYPE_TIMESTAMP"; - case SQL_C_NUMERIC: return "SQL_C_NUMERIC"; - case SQL_C_GUID: return "SQL_C_GUID"; + SQL_CASE(SQL_C_CHAR); + SQL_CASE(SQL_C_WCHAR); + SQL_CASE(SQL_C_SHORT); + SQL_CASE(SQL_C_SSHORT); + SQL_CASE(SQL_C_USHORT); + SQL_CASE(SQL_C_LONG); + SQL_CASE(SQL_C_SLONG); + SQL_CASE(SQL_C_ULONG); + SQL_CASE(SQL_C_FLOAT); + SQL_CASE(SQL_C_DOUBLE); + SQL_CASE(SQL_C_BIT); + SQL_CASE(SQL_C_TINYINT); + SQL_CASE(SQL_C_STINYINT); + SQL_CASE(SQL_C_UTINYINT); + SQL_CASE(SQL_C_SBIGINT); + SQL_CASE(SQL_C_UBIGINT); + SQL_CASE(SQL_C_BINARY); + SQL_CASE(SQL_C_DATE); + SQL_CASE(SQL_C_TIME); + SQL_CASE(SQL_C_TIMESTAMP); + SQL_CASE(SQL_C_TYPE_DATE); + SQL_CASE(SQL_C_TYPE_TIME); + SQL_CASE(SQL_C_TYPE_TIMESTAMP); + SQL_CASE(SQL_C_NUMERIC); + SQL_CASE(SQL_C_GUID); default: return "UNKNOWN"; } } +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdiagfield-function?view=sql-server-ver15 +const char* sql_diag_identifier(int type) { + switch (type) { + // header fields + SQL_CASE(SQL_DIAG_CURSOR_ROW_COUNT); + SQL_CASE(SQL_DIAG_DYNAMIC_FUNCTION); + SQL_CASE(SQL_DIAG_DYNAMIC_FUNCTION_CODE); + SQL_CASE(SQL_DIAG_NUMBER); + SQL_CASE(SQL_DIAG_RETURNCODE); + SQL_CASE(SQL_DIAG_ROW_COUNT); + // record fields + SQL_CASE(SQL_DIAG_CLASS_ORIGIN); + SQL_CASE(SQL_DIAG_COLUMN_NUMBER); + SQL_CASE(SQL_DIAG_CONNECTION_NAME); + SQL_CASE(SQL_DIAG_MESSAGE_TEXT); + SQL_CASE(SQL_DIAG_NATIVE); + SQL_CASE(SQL_DIAG_ROW_NUMBER); + SQL_CASE(SQL_DIAG_SERVER_NAME); + SQL_CASE(SQL_DIAG_SQLSTATE); + SQL_CASE(SQL_DIAG_SUBCLASS_ORIGIN); + default: return "UNKNOWN"; + } +} + +const char* sql_handle_type(int type) { + switch(type) { + SQL_CASE(SQL_HANDLE_ENV); + SQL_CASE(SQL_HANDLE_DBC); + SQL_CASE(SQL_HANDLE_STMT); + SQL_CASE(SQL_HANDLE_DESC); + // SQL_CASE(SQL_HANDLE_DBC_INFO_TOKEN); + default: return "UNKNOWN"; + } +} + +const char* sql_env_attr_type(int type) { + switch(type) { + SQL_CASE(SQL_ATTR_OUTPUT_NTS); + SQL_CASE(SQL_ATTR_ODBC_VERSION); + SQL_CASE(SQL_ATTR_CONNECTION_POOLING); + SQL_CASE(SQL_ATTR_CP_MATCH); + default: return "UNKNOWN"; + } +} + +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetconnectattr-function?view=sql-server-ver15 +const char* sql_conn_attr_type(int type) { + switch(type) { + SQL_CASE(SQL_ATTR_ACCESS_MODE); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_ASYNC_DBC_EVENT); + SQL_CASE(SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_ASYNC_DBC_PCALLBACK); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_ASYNC_DBC_PCONTEXT); + SQL_CASE(SQL_ATTR_ASYNC_ENABLE); + SQL_CASE(SQL_ATTR_AUTO_IPD); + SQL_CASE(SQL_ATTR_AUTOCOMMIT); + SQL_CASE(SQL_ATTR_CONNECTION_DEAD); + SQL_CASE(SQL_ATTR_CONNECTION_TIMEOUT); + SQL_CASE(SQL_ATTR_CURRENT_CATALOG); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_DBC_INFO_TOKEN); + SQL_CASE(SQL_ATTR_ENLIST_IN_DTC); + SQL_CASE(SQL_ATTR_LOGIN_TIMEOUT); + SQL_CASE(SQL_ATTR_METADATA_ID); + SQL_CASE(SQL_ATTR_ODBC_CURSORS); + SQL_CASE(SQL_ATTR_PACKET_SIZE); + SQL_CASE(SQL_ATTR_QUIET_MODE); + SQL_CASE(SQL_ATTR_TRACE); + SQL_CASE(SQL_ATTR_TRACEFILE); + SQL_CASE(SQL_ATTR_TRANSLATE_LIB); + SQL_CASE(SQL_ATTR_TRANSLATE_OPTION); + SQL_CASE(SQL_ATTR_TXN_ISOLATION); + default: return "UNKNOWN"; + } +} + +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetinfo-function?view=sql-server-ver15 +const char* sql_info_type(int type) { + switch(type) { + SQL_CASE(SQL_ACTIVE_ENVIRONMENTS); + SQL_CASE(SQL_ASYNC_DBC_FUNCTIONS); + SQL_CASE(SQL_ASYNC_MODE); + SQL_CASE(SQL_ASYNC_NOTIFICATION); + SQL_CASE(SQL_BATCH_ROW_COUNT); + SQL_CASE(SQL_BATCH_SUPPORT); + SQL_CASE(SQL_DATA_SOURCE_NAME); + SQL_CASE(SQL_DRIVER_AWARE_POOLING_SUPPORTED); + SQL_CASE(SQL_DRIVER_HDBC); + SQL_CASE(SQL_DRIVER_HDESC); + SQL_CASE(SQL_DRIVER_HENV); + SQL_CASE(SQL_DRIVER_HLIB); + SQL_CASE(SQL_DRIVER_HSTMT); + SQL_CASE(SQL_DRIVER_NAME); + SQL_CASE(SQL_DRIVER_ODBC_VER); + SQL_CASE(SQL_DRIVER_VER); + SQL_CASE(SQL_DYNAMIC_CURSOR_ATTRIBUTES1); + SQL_CASE(SQL_DYNAMIC_CURSOR_ATTRIBUTES2); + SQL_CASE(SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1); + SQL_CASE(SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2); + SQL_CASE(SQL_FILE_USAGE); + SQL_CASE(SQL_GETDATA_EXTENSIONS); + SQL_CASE(SQL_INFO_SCHEMA_VIEWS); + SQL_CASE(SQL_KEYSET_CURSOR_ATTRIBUTES1); + SQL_CASE(SQL_KEYSET_CURSOR_ATTRIBUTES2); + SQL_CASE(SQL_MAX_ASYNC_CONCURRENT_STATEMENTS); + SQL_CASE(SQL_MAX_CONCURRENT_ACTIVITIES); + SQL_CASE(SQL_MAX_DRIVER_CONNECTIONS); + SQL_CASE(SQL_ODBC_INTERFACE_CONFORMANCE); + // SQL_CASE(SQL_ODBC_STANDARD_CLI_CONFORMANCE); + SQL_CASE(SQL_ODBC_VER); + SQL_CASE(SQL_PARAM_ARRAY_ROW_COUNTS); + SQL_CASE(SQL_PARAM_ARRAY_SELECTS); + SQL_CASE(SQL_ROW_UPDATES); + SQL_CASE(SQL_SEARCH_PATTERN_ESCAPE); + SQL_CASE(SQL_SERVER_NAME); + SQL_CASE(SQL_STATIC_CURSOR_ATTRIBUTES1); + SQL_CASE(SQL_STATIC_CURSOR_ATTRIBUTES2); + + SQL_CASE(SQL_DATABASE_NAME); + SQL_CASE(SQL_DBMS_NAME); + SQL_CASE(SQL_DBMS_VER); + + SQL_CASE(SQL_ACCESSIBLE_PROCEDURES); + SQL_CASE(SQL_ACCESSIBLE_TABLES); + SQL_CASE(SQL_BOOKMARK_PERSISTENCE); + SQL_CASE(SQL_CATALOG_TERM); + SQL_CASE(SQL_COLLATION_SEQ); + SQL_CASE(SQL_CONCAT_NULL_BEHAVIOR); + SQL_CASE(SQL_CURSOR_COMMIT_BEHAVIOR); + SQL_CASE(SQL_CURSOR_ROLLBACK_BEHAVIOR); + SQL_CASE(SQL_CURSOR_SENSITIVITY); + SQL_CASE(SQL_DATA_SOURCE_READ_ONLY); + SQL_CASE(SQL_DEFAULT_TXN_ISOLATION); + SQL_CASE(SQL_DESCRIBE_PARAMETER); + SQL_CASE(SQL_MULT_RESULT_SETS); + SQL_CASE(SQL_MULTIPLE_ACTIVE_TXN); + SQL_CASE(SQL_NEED_LONG_DATA_LEN); + SQL_CASE(SQL_NULL_COLLATION); + SQL_CASE(SQL_PROCEDURE_TERM); + SQL_CASE(SQL_SCHEMA_TERM); + SQL_CASE(SQL_SCROLL_OPTIONS); + SQL_CASE(SQL_TABLE_TERM); + SQL_CASE(SQL_TXN_CAPABLE); + SQL_CASE(SQL_TXN_ISOLATION_OPTION); + SQL_CASE(SQL_USER_NAME); + + SQL_CASE(SQL_AGGREGATE_FUNCTIONS); + SQL_CASE(SQL_ALTER_DOMAIN); + // SQL_CASE(SQL_ALTER_SCHEMA); + SQL_CASE(SQL_ALTER_TABLE); + // SQL_CASE(SQL_ANSI_SQL_DATETIME_LITERALS); + SQL_CASE(SQL_CATALOG_LOCATION); + SQL_CASE(SQL_CATALOG_NAME); + SQL_CASE(SQL_CATALOG_NAME_SEPARATOR); + SQL_CASE(SQL_CATALOG_USAGE); + SQL_CASE(SQL_COLUMN_ALIAS); + SQL_CASE(SQL_CORRELATION_NAME); + SQL_CASE(SQL_CREATE_ASSERTION); + SQL_CASE(SQL_CREATE_CHARACTER_SET); + SQL_CASE(SQL_CREATE_COLLATION); + SQL_CASE(SQL_CREATE_DOMAIN); + SQL_CASE(SQL_CREATE_SCHEMA); + SQL_CASE(SQL_CREATE_TABLE); + SQL_CASE(SQL_CREATE_TRANSLATION); + SQL_CASE(SQL_DDL_INDEX); + SQL_CASE(SQL_DROP_ASSERTION); + SQL_CASE(SQL_DROP_CHARACTER_SET); + SQL_CASE(SQL_DROP_COLLATION); + SQL_CASE(SQL_DROP_DOMAIN); + SQL_CASE(SQL_DROP_SCHEMA); + + SQL_CASE(SQL_DROP_TABLE); + SQL_CASE(SQL_DROP_TRANSLATION); + SQL_CASE(SQL_DROP_VIEW); + SQL_CASE(SQL_EXPRESSIONS_IN_ORDERBY); + SQL_CASE(SQL_GROUP_BY); + SQL_CASE(SQL_IDENTIFIER_CASE); + SQL_CASE(SQL_IDENTIFIER_QUOTE_CHAR); + SQL_CASE(SQL_INDEX_KEYWORDS); + SQL_CASE(SQL_INSERT_STATEMENT); + SQL_CASE(SQL_INTEGRITY); + SQL_CASE(SQL_KEYWORDS); + SQL_CASE(SQL_LIKE_ESCAPE_CLAUSE); + SQL_CASE(SQL_NON_NULLABLE_COLUMNS); + SQL_CASE(SQL_OJ_CAPABILITIES); + SQL_CASE(SQL_ORDER_BY_COLUMNS_IN_SELECT); + SQL_CASE(SQL_OUTER_JOINS); + SQL_CASE(SQL_PROCEDURES); + SQL_CASE(SQL_QUOTED_IDENTIFIER_CASE); + SQL_CASE(SQL_SCHEMA_USAGE); + SQL_CASE(SQL_SPECIAL_CHARACTERS); + SQL_CASE(SQL_SQL_CONFORMANCE); + SQL_CASE(SQL_SUBQUERIES); + SQL_CASE(SQL_UNION); + + SQL_CASE(SQL_MAX_BINARY_LITERAL_LEN); + SQL_CASE(SQL_MAX_CATALOG_NAME_LEN); + SQL_CASE(SQL_MAX_CHAR_LITERAL_LEN); + SQL_CASE(SQL_MAX_COLUMN_NAME_LEN); + SQL_CASE(SQL_MAX_COLUMNS_IN_GROUP_BY); + SQL_CASE(SQL_MAX_COLUMNS_IN_INDEX); + SQL_CASE(SQL_MAX_COLUMNS_IN_ORDER_BY); + SQL_CASE(SQL_MAX_COLUMNS_IN_SELECT); + SQL_CASE(SQL_MAX_COLUMNS_IN_TABLE); + SQL_CASE(SQL_MAX_CURSOR_NAME_LEN); + + SQL_CASE(SQL_MAX_IDENTIFIER_LEN); + SQL_CASE(SQL_MAX_INDEX_SIZE); + SQL_CASE(SQL_MAX_PROCEDURE_NAME_LEN); + SQL_CASE(SQL_MAX_ROW_SIZE); + SQL_CASE(SQL_MAX_ROW_SIZE_INCLUDES_LONG); + SQL_CASE(SQL_MAX_SCHEMA_NAME_LEN); + SQL_CASE(SQL_MAX_STATEMENT_LEN); + SQL_CASE(SQL_MAX_TABLE_NAME_LEN); + SQL_CASE(SQL_MAX_TABLES_IN_SELECT); + SQL_CASE(SQL_MAX_USER_NAME_LEN); + + SQL_CASE(SQL_CONVERT_FUNCTIONS); + SQL_CASE(SQL_NUMERIC_FUNCTIONS); + SQL_CASE(SQL_STRING_FUNCTIONS); + SQL_CASE(SQL_SYSTEM_FUNCTIONS); + + SQL_CASE(SQL_TIMEDATE_ADD_INTERVALS); + SQL_CASE(SQL_TIMEDATE_DIFF_INTERVALS); + SQL_CASE(SQL_TIMEDATE_FUNCTIONS); + + SQL_CASE(SQL_CONVERT_BIGINT); + SQL_CASE(SQL_CONVERT_BINARY); + SQL_CASE(SQL_CONVERT_BIT); + SQL_CASE(SQL_CONVERT_CHAR); + SQL_CASE(SQL_CONVERT_DATE); + SQL_CASE(SQL_CONVERT_DECIMAL); + SQL_CASE(SQL_CONVERT_DOUBLE); + SQL_CASE(SQL_CONVERT_FLOAT); + SQL_CASE(SQL_CONVERT_INTEGER); + SQL_CASE(SQL_CONVERT_INTERVAL_DAY_TIME); + SQL_CASE(SQL_CONVERT_INTERVAL_YEAR_MONTH); + + SQL_CASE(SQL_CONVERT_LONGVARBINARY); + SQL_CASE(SQL_CONVERT_LONGVARCHAR); + SQL_CASE(SQL_CONVERT_NUMERIC); + SQL_CASE(SQL_CONVERT_REAL); + SQL_CASE(SQL_CONVERT_SMALLINT); + SQL_CASE(SQL_CONVERT_TIME); + SQL_CASE(SQL_CONVERT_TIMESTAMP); + SQL_CASE(SQL_CONVERT_TINYINT); + SQL_CASE(SQL_CONVERT_VARBINARY); + SQL_CASE(SQL_CONVERT_VARCHAR); + + SQL_CASE(SQL_DM_VER); + + SQL_CASE(SQL_XOPEN_CLI_YEAR); + + SQL_CASE(SQL_DTC_TRANSITION_COST); + + default: return "UNKNOWN"; + } +} + +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcolattribute-function?view=sql-server-ver15 +const char* sql_field_identifier(int type) { + switch (type) { + SQL_CASE(SQL_DESC_AUTO_UNIQUE_VALUE); + SQL_CASE(SQL_DESC_BASE_COLUMN_NAME); + SQL_CASE(SQL_DESC_BASE_TABLE_NAME); + SQL_CASE(SQL_DESC_CASE_SENSITIVE); + SQL_CASE(SQL_DESC_CATALOG_NAME); + SQL_CASE(SQL_DESC_CONCISE_TYPE); + SQL_CASE(SQL_DESC_COUNT); + SQL_CASE(SQL_DESC_DISPLAY_SIZE); + SQL_CASE(SQL_DESC_FIXED_PREC_SCALE); + SQL_CASE(SQL_DESC_LABEL); + SQL_CASE(SQL_DESC_LENGTH); + SQL_CASE(SQL_DESC_LITERAL_PREFIX); + SQL_CASE(SQL_DESC_LITERAL_SUFFIX); + SQL_CASE(SQL_DESC_LOCAL_TYPE_NAME); + SQL_CASE(SQL_DESC_NAME); + SQL_CASE(SQL_DESC_NULLABLE); + SQL_CASE(SQL_DESC_NUM_PREC_RADIX); + SQL_CASE(SQL_DESC_OCTET_LENGTH); + SQL_CASE(SQL_DESC_PRECISION); + SQL_CASE(SQL_DESC_SCALE); + SQL_CASE(SQL_DESC_SCHEMA_NAME); + SQL_CASE(SQL_DESC_SEARCHABLE); + SQL_CASE(SQL_DESC_TABLE_NAME); + SQL_CASE(SQL_DESC_TYPE); + SQL_CASE(SQL_DESC_TYPE_NAME); + SQL_CASE(SQL_DESC_UNNAMED); + SQL_CASE(SQL_DESC_UNSIGNED); + SQL_CASE(SQL_DESC_UPDATABLE); + default: return "UNKNOWN"; + } +} + +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver15 +const char* sql_input_output_type(int type) { + switch (type) { + SQL_CASE(SQL_PARAM_INPUT); + SQL_CASE(SQL_PARAM_OUTPUT); + SQL_CASE(SQL_PARAM_OUTPUT_STREAM); + SQL_CASE(SQL_PARAM_INPUT_OUTPUT); + SQL_CASE(SQL_PARAM_INPUT_OUTPUT_STREAM); + default: return "UNKNOWN"; + } +} + +// https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function?view=sql-server-ver15 +const char* sql_stmt_attr_type(int type) { + switch (type) { + SQL_CASE(SQL_ATTR_APP_PARAM_DESC); + SQL_CASE(SQL_ATTR_APP_ROW_DESC); + SQL_CASE(SQL_ATTR_ASYNC_ENABLE); + SQL_CASE(SQL_ATTR_ASYNC_STMT_EVENT); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_ASYNC_STMT_PCALLBACK); + // ODBC 3.8 + // SQL_CASE(SQL_ATTR_ASYNC_STMT_PCONTEXT); + SQL_CASE(SQL_ATTR_CONCURRENCY); + SQL_CASE(SQL_ATTR_CURSOR_SCROLLABLE); + SQL_CASE(SQL_ATTR_CURSOR_SENSITIVITY); + SQL_CASE(SQL_ATTR_CURSOR_TYPE); + SQL_CASE(SQL_ATTR_ENABLE_AUTO_IPD); + SQL_CASE(SQL_ATTR_FETCH_BOOKMARK_PTR); + SQL_CASE(SQL_ATTR_IMP_PARAM_DESC); + SQL_CASE(SQL_ATTR_IMP_ROW_DESC); + SQL_CASE(SQL_ATTR_KEYSET_SIZE); + SQL_CASE(SQL_ATTR_MAX_LENGTH); + SQL_CASE(SQL_ATTR_MAX_ROWS); + SQL_CASE(SQL_ATTR_METADATA_ID); + SQL_CASE(SQL_ATTR_NOSCAN); + SQL_CASE(SQL_ATTR_PARAM_BIND_OFFSET_PTR); + SQL_CASE(SQL_ATTR_PARAM_BIND_TYPE); + SQL_CASE(SQL_ATTR_PARAM_OPERATION_PTR); + SQL_CASE(SQL_ATTR_PARAM_STATUS_PTR); + SQL_CASE(SQL_ATTR_PARAMS_PROCESSED_PTR); + SQL_CASE(SQL_ATTR_PARAMSET_SIZE); + SQL_CASE(SQL_ATTR_QUERY_TIMEOUT); + SQL_CASE(SQL_ATTR_RETRIEVE_DATA); + SQL_CASE(SQL_ATTR_ROW_ARRAY_SIZE); + SQL_CASE(SQL_ATTR_ROW_BIND_OFFSET_PTR); + SQL_CASE(SQL_ATTR_ROW_BIND_TYPE); + SQL_CASE(SQL_ATTR_ROW_NUMBER); + SQL_CASE(SQL_ATTR_ROW_OPERATION_PTR); + SQL_CASE(SQL_ATTR_ROW_STATUS_PTR); + SQL_CASE(SQL_ATTR_ROWS_FETCHED_PTR); + SQL_CASE(SQL_ATTR_SIMULATE_CURSOR); + SQL_CASE(SQL_ATTR_USE_BOOKMARKS); + default: return "UNKNOWN"; + } +} + +const char* sql_function_type(int type) { + switch (type) { + // + SQL_CASE(SQL_API_ALL_FUNCTIONS); + SQL_CASE(SQL_API_ODBC3_ALL_FUNCTIONS); + + // ISO 92 standards-compliance + SQL_CASE(SQL_API_SQLALLOCHANDLE); + SQL_CASE(SQL_API_SQLGETDESCFIELD); + SQL_CASE(SQL_API_SQLBINDCOL); + SQL_CASE(SQL_API_SQLGETDESCREC); + SQL_CASE(SQL_API_SQLCANCEL); + SQL_CASE(SQL_API_SQLGETDIAGFIELD); + SQL_CASE(SQL_API_SQLCLOSECURSOR); + SQL_CASE(SQL_API_SQLGETDIAGREC); + SQL_CASE(SQL_API_SQLCOLATTRIBUTE); + SQL_CASE(SQL_API_SQLGETENVATTR); + SQL_CASE(SQL_API_SQLCONNECT); + SQL_CASE(SQL_API_SQLGETFUNCTIONS); + SQL_CASE(SQL_API_SQLCOPYDESC); + SQL_CASE(SQL_API_SQLGETINFO); + SQL_CASE(SQL_API_SQLDATASOURCES); + SQL_CASE(SQL_API_SQLGETSTMTATTR); + SQL_CASE(SQL_API_SQLDESCRIBECOL); + SQL_CASE(SQL_API_SQLGETTYPEINFO); + SQL_CASE(SQL_API_SQLDISCONNECT); + SQL_CASE(SQL_API_SQLNUMRESULTCOLS); + SQL_CASE(SQL_API_SQLDRIVERS); + SQL_CASE(SQL_API_SQLPARAMDATA); + SQL_CASE(SQL_API_SQLENDTRAN); + SQL_CASE(SQL_API_SQLPREPARE); + SQL_CASE(SQL_API_SQLEXECDIRECT); + SQL_CASE(SQL_API_SQLPUTDATA); + SQL_CASE(SQL_API_SQLEXECUTE); + SQL_CASE(SQL_API_SQLROWCOUNT); + SQL_CASE(SQL_API_SQLFETCH); + SQL_CASE(SQL_API_SQLSETCONNECTATTR); + SQL_CASE(SQL_API_SQLFETCHSCROLL); + SQL_CASE(SQL_API_SQLSETCURSORNAME); + SQL_CASE(SQL_API_SQLFREEHANDLE); + SQL_CASE(SQL_API_SQLSETDESCFIELD); + SQL_CASE(SQL_API_SQLFREESTMT); + SQL_CASE(SQL_API_SQLSETDESCREC); + SQL_CASE(SQL_API_SQLGETCONNECTATTR); + SQL_CASE(SQL_API_SQLSETENVATTR); + SQL_CASE(SQL_API_SQLGETCURSORNAME); + SQL_CASE(SQL_API_SQLSETSTMTATTR); + SQL_CASE(SQL_API_SQLGETDATA); + + // Open Group standards-compliance); + SQL_CASE(SQL_API_SQLCOLUMNS); + SQL_CASE(SQL_API_SQLSTATISTICS); + SQL_CASE(SQL_API_SQLSPECIALCOLUMNS); + SQL_CASE(SQL_API_SQLTABLES); + + // ODBC standards-compliance); + SQL_CASE(SQL_API_SQLBINDPARAMETER); + SQL_CASE(SQL_API_SQLNATIVESQL); + SQL_CASE(SQL_API_SQLBROWSECONNECT); + SQL_CASE(SQL_API_SQLNUMPARAMS); + SQL_CASE(SQL_API_SQLBULKOPERATIONS); + SQL_CASE(SQL_API_SQLPRIMARYKEYS); + SQL_CASE(SQL_API_SQLCOLUMNPRIVILEGES); + SQL_CASE(SQL_API_SQLPROCEDURECOLUMNS); + SQL_CASE(SQL_API_SQLDESCRIBEPARAM); + SQL_CASE(SQL_API_SQLPROCEDURES); + SQL_CASE(SQL_API_SQLDRIVERCONNECT); + SQL_CASE(SQL_API_SQLSETPOS); + SQL_CASE(SQL_API_SQLFOREIGNKEYS); + SQL_CASE(SQL_API_SQLTABLEPRIVILEGES); + SQL_CASE(SQL_API_SQLMORERESULTS); + + SQL_CASE(SQL_API_SQLALLOCCONNECT); + SQL_CASE(SQL_API_SQLALLOCENV); + SQL_CASE(SQL_API_SQLALLOCSTMT); + SQL_CASE(SQL_API_SQLBINDPARAM); + SQL_CASE(SQL_API_SQLERROR); + SQL_CASE(SQL_API_SQLFREECONNECT); + SQL_CASE(SQL_API_SQLFREEENV); + SQL_CASE(SQL_API_SQLGETCONNECTOPTION); + SQL_CASE(SQL_API_SQLGETSTMTOPTION); + SQL_CASE(SQL_API_SQLSETCONNECTOPTION); + SQL_CASE(SQL_API_SQLSETPARAM); + SQL_CASE(SQL_API_SQLSETSTMTOPTION); + SQL_CASE(SQL_API_SQLTRANSACT); + SQL_CASE(SQL_API_SQLCANCELHANDLE); + + default: return "UNKNOWN"; + } +} + +const char* sql_freestmt_option_type(int type) { + switch (type) { + SQL_CASE(SQL_CLOSE); + SQL_CASE(SQL_DROP); + SQL_CASE(SQL_UNBIND); + SQL_CASE(SQL_RESET_PARAMS); + default: return "UNKNOWN"; + } +} + +const char* sql_soi_type(int soi) { + switch (soi) { + SQL_CASE(SQL_NTS); + SQL_CASE(SQL_NULL_DATA); + SQL_CASE(SQL_DEFAULT_PARAM); + SQL_CASE(SQL_DATA_AT_EXEC); + default: { + if (soi >= 0) return ""; + return "SQL_LEN_DATA_AT_EXEC(?)"; + } break; + } +} + +const char* sql_nullable_type(int type) { + switch (type) { + SQL_CASE(SQL_NO_NULLS); + SQL_CASE(SQL_NULLABLE); + SQL_CASE(SQL_NULLABLE_UNKNOWN); + default: { + return "UNKNOWN"; + } break; + } +} + + + + + + + + int is_valid_sql_c_type(int type) { const char *ctype = sql_c_type(type); if (strcmp(ctype, "UNKNOWN")==0) return 0; @@ -127,3 +617,46 @@ int utf8_chars(const char *src) return (int)chars; } +static int do_charset_chars(iconv_t cnv, const unsigned char *src) +{ + int chars = 0; + char *ps = (char*)src; + char buf[16]; + size_t sn = 1; + while (1) { + char *ds = buf; + size_t dn = sizeof(buf); + size_t n = iconv(cnv, &ps, &sn, &ds, &dn); + if (n==(size_t)-1) { + int e = errno; + switch (e) { + case EILSEQ: return -1; + case E2BIG: return -1; + case EINVAL: sn += 1; continue; + default: return -1; + } + } + if (sn) return -1; + if (n>0) return -1; + int i=0; + for (i=0; i<(sizeof(buf)-dn); ++i) { + if (buf[i]) break; + } + if (i>=(sizeof(buf)-dn)) break; + chars += (int)1; + sn = 1; + } + return chars; +} + +int charset_chars(const char *charset, const unsigned char *src) { + iconv_t cnv = iconv_open(charset, charset); + if (cnv==(iconv_t)-1) return -1; + + int chars = do_charset_chars(cnv, src); + + iconv_close(cnv); + + return chars; +} + diff --git a/src/connector/odbc/src/todbc_util.h b/src/connector/odbc/src/todbc_util.h index ead0d73489..a340c32546 100644 --- a/src/connector/odbc/src/todbc_util.h +++ b/src/connector/odbc/src/todbc_util.h @@ -23,11 +23,24 @@ const char* sql_sql_type(int type); const char* sql_c_type(int type); +const char* sql_handle_type(int type); +const char* sql_env_attr_type(int type); +const char* sql_conn_attr_type(int type); +const char* sql_info_type(int type); +const char* sql_field_identifier(int type); +const char* sql_diag_identifier(int type); +const char* sql_input_output_type(int type); +const char* sql_stmt_attr_type(int type); +const char* sql_function_type(int type); +const char* sql_freestmt_option_type(int type); +const char* sql_soi_type(int soi); +const char* sql_nullable_type(int type); int is_valid_sql_c_type(int type); int is_valid_sql_sql_type(int type); int utf8_chars(const char *src); +int charset_chars(const char *charset, const unsigned char *src); #endif // _TODBC_UTIL_H_ diff --git a/src/connector/odbc/tests/CMakeLists.txt b/src/connector/odbc/tests/CMakeLists.txt deleted file mode 100644 index 1cc6acaf4b..0000000000 --- a/src/connector/odbc/tests/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -PROJECT(TDengine) - -IF (TD_LINUX) - # AUX_SOURCE_DIRECTORY(. SRC) - ADD_EXECUTABLE(tcodbc main.c) - TARGET_LINK_LIBRARIES(tcodbc odbc) - ADD_EXECUTABLE(tconv tconv.c) -ENDIF () - -IF (TD_WINDOWS_64) - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /GL") - SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL") - # AUX_SOURCE_DIRECTORY(. SRC) - ADD_EXECUTABLE(tcodbc main.c) - TARGET_LINK_LIBRARIES(tcodbc odbc32 odbccp32 user32 legacy_stdio_definitions os) - ADD_EXECUTABLE(tconv tconv.c) - TARGET_LINK_LIBRARIES(tconv tutil) -ENDIF () diff --git a/src/connector/odbc/tests/main.c b/src/connector/odbc/tests/main.c deleted file mode 100644 index 417de00d55..0000000000 --- a/src/connector/odbc/tests/main.c +++ /dev/null @@ -1,673 +0,0 @@ -#include "../src/todbc_log.h" - -#ifdef _MSC_VER -#include -#include -#include "os.h" -#endif -#include -#include -#include - -#include -#include - -#define CHK_TEST(statement) \ -do { \ - D("testing: %s", #statement); \ - int r = (statement); \ - if (r) { \ - D("testing failed: %s", #statement); \ - return 1; \ - } \ -} while (0); - -typedef struct db_column_s db_column_t; -struct db_column_s { - SQLSMALLINT nameLength; - char name[4096]; // seems enough - SQLSMALLINT dataType; - SQLULEN columnSize; - SQLSMALLINT decimalDigits; - SQLSMALLINT nullable; -}; - -static db_column_t *columns = NULL; - -typedef struct data_s data_t; -struct data_s { - int64_t ts; - int8_t b; - int8_t v1; - int16_t v2; - int32_t v4; - int64_t v8; - float f4; - double f8; - char bin[40+1]; - char blob[40+1]; // why 80? ref: tests/examples/c/apitest.c -}; - -static const char *pre_stmts[] = { - "create database db", - "use db", - "create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))" -}; - -static const char *pro_stmts[] = { - // "insert into t values ('2019-07-15 00:00:00', 1)", - // "insert into t values ('2019-07-15 01:00:00', 2)", - "select * from t" - // "drop database db" -}; - -#define CHK_RESULT(r, ht, h, fmt, ...) \ -do { \ - if (r==0) break; \ - SQLCHAR ss[10]; \ - SQLINTEGER ne = 0; \ - SQLCHAR es[4096]; \ - SQLSMALLINT n = 0; \ - ss[0] = '\0'; \ - es[0] = '\0'; \ - SQLRETURN ret = SQLGetDiagRec(ht, h, 1, ss, &ne, es, sizeof(es), &n); \ - if (ret) break; \ - D("[%s]%s: " fmt "", ss, es, ##__VA_ARGS__); \ -} while (0) - -static int open_connect(const char *dsn, const char *uid, const char *pwd, SQLHENV *pEnv, SQLHDBC *pConn) { - SQLRETURN r; - SQLHENV env = {0}; - SQLHDBC conn = {0}; - r = SQLAllocEnv(&env); - if (r!=SQL_SUCCESS) return 1; - do { - r = SQLAllocConnect(env, &conn); - CHK_RESULT(r, SQL_HANDLE_ENV, env, ""); - if (r!=SQL_SUCCESS) break; - do { - r = SQLConnect(conn, (SQLCHAR*)dsn, (SQLSMALLINT)(dsn ? strlen(dsn) : 0), - (SQLCHAR*)uid, (SQLSMALLINT)(uid ? strlen(uid) : 0), - (SQLCHAR*)pwd, (SQLSMALLINT)(pwd ? strlen(pwd) : 0)); - CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); - if (r==SQL_SUCCESS) { - *pEnv = env; - *pConn = conn; - return 0; - } - } while (0); - SQLFreeConnect(conn); - } while (0); - SQLFreeEnv(env); - - return 1; -} - -static int open_driver_connect(const char *connstr, SQLHENV *pEnv, SQLHDBC *pConn) { - SQLRETURN r; - SQLHENV env = {0}; - SQLHDBC conn = {0}; - r = SQLAllocEnv(&env); - if (r!=SQL_SUCCESS) return 1; - do { - r = SQLAllocConnect(env, &conn); - CHK_RESULT(r, SQL_HANDLE_ENV, env, ""); - if (r!=SQL_SUCCESS) break; - do { - SQLCHAR buf[4096]; - SQLSMALLINT blen = 0; - SQLHDBC ConnectionHandle = conn; - SQLHWND WindowHandle = NULL; - SQLCHAR * InConnectionString = (SQLCHAR*)connstr; - SQLSMALLINT StringLength1 = (SQLSMALLINT)(connstr ? strlen(connstr) : 0); - SQLCHAR * OutConnectionString = buf; - SQLSMALLINT BufferLength = sizeof(buf); - SQLSMALLINT * StringLength2Ptr = &blen; - SQLUSMALLINT DriverCompletion = SQL_DRIVER_NOPROMPT; - r = SQLDriverConnect(ConnectionHandle, WindowHandle, InConnectionString, - StringLength1, OutConnectionString, BufferLength, - StringLength2Ptr, DriverCompletion); - CHK_RESULT(r, SQL_HANDLE_DBC, conn, ""); - if (r==SQL_SUCCESS) { - *pEnv = env; - *pConn = conn; - return 0; - } - } while (0); - SQLFreeConnect(conn); - } while (0); - SQLFreeEnv(env); - - return 1; -} - -static SQLRETURN traverse_cols(SQLHSTMT stmt, SQLSMALLINT cols) { - SQLRETURN r = SQL_ERROR; - for (SQLSMALLINT i=0; i0) fprintf(stdout, "\n"); - return r; - } - } - if (soi==SQL_NULL_DATA) { - fprintf(stdout, "%snull", i==0?"":","); - } else { - fprintf(stdout, "%s\"%s\"", i==0?"":",", buf); - } - } - fprintf(stdout, "\n"); - } - - // r = SQLFetch(stmt); - // if (r==SQL_NO_DATA) { - // D(".........."); - // r = SQL_SUCCESS; - // break; - // } - // CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); - // if (r) break; - // r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement)); - // CHK_RESULT(r, SQL_HANDLE_STMT, stmt, ""); - // if (r) break; - // r = SQLExecute(stmt); - // CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - // if (r) break; - } while (0); - return r; -} - -static int do_insert(SQLHSTMT stmt, data_t data) { - SQLRETURN r = 0; - SQLLEN lbin; - SQLLEN lblob; - - const char *statement = "insert into t values (?, ?, ?, ?, ?, ?, ?, ?, ?,?)"; - #define ignored 0 - - do { - r = SQLPrepare(stmt, (SQLCHAR*)statement, (SQLINTEGER)strlen(statement)); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_TIMESTAMP, ignored, ignored, &data.ts, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, ignored, ignored, &data.b, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_TINYINT, SQL_TINYINT, ignored, ignored, &data.v1, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, ignored, ignored, &data.v2, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, ignored, ignored, &data.v4, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, ignored, ignored, &data.v8, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, ignored, ignored, &data.f4, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, ignored, ignored, &data.f8, ignored, NULL); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - lbin = SQL_NTS; - r = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sizeof(data.bin)-1, ignored, &data.bin, ignored, &lbin); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - lblob = SQL_NTS; - r = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(data.blob)-1, ignored, &data.blob, ignored, &lblob); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - r = SQLExecute(stmt); - CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement); - if (r) break; - - // ts += 1; - // v = 2; - // r = SQLExecute(stmt); - // if (r) break; - } while (0); - - #undef ignored - return r; -} - -static int test1(const char *dsn, const char *uid, const char *pwd) { - SQLHENV env = {0}; - SQLHDBC conn = {0}; - int n = open_connect(dsn, uid, pwd, &env, &conn); - if (n) return 1; - - int ok = 0; - do { - SQLRETURN r = SQL_SUCCESS; - SQLHSTMT stmt = {0}; - r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt); - if (r!=SQL_SUCCESS) break; - do { - if (do_statement(stmt, "drop database if exists db")) { - break; - } - for (size_t i=0; i0 && line[n-1] == '\n') line[n-1]='\0'; - if (n>0 && line[n-1] == '\r') line[n-1]='\0'; - if (n>1 && line[n-2] == '\r') line[n-2]='\0'; - p = line; - while (isspace(*p)) ++p; - - if (*p==0) break; - - int positive = 1; - if (strncmp(p, "N:", 2)==0) { - positive = 0; - p += 2; - } else if (strncmp(p, "P:", 2)==0) { - p += 2; - } - - D("statement: [%s]", p); - r = do_statement(stmt, p); - - if (positive && r==0) break; - if (!positive && r) { r = 0; break; } - if (positive) return r; - D("expecting negative result, but got positive"); - return -1; - } while (0); - - free(line); - - if (r) break; - } - - fclose(f); - return r ? 1 : 0; -} - -int test_sqls_in_conn(SQLHENV env, SQLHDBC conn, const char *sqls) { - SQLHSTMT stmt = {0}; - CHK_TEST(create_statement(env, conn, &stmt)); - int r = test_sqls_in_stmt(env, conn, stmt, sqls); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - return r ? 1 : 0; -} - -int test_sqls(const char *dsn, const char *uid, const char *pwd, const char *connstr, const char *sqls) { - int r = 0; - SQLHENV env = {0}; - SQLHDBC conn = {0}; - if (dsn) { - CHK_TEST(open_connect(dsn, uid, pwd, &env, &conn)); - } else { - CHK_TEST(open_driver_connect(connstr, &env, &conn)); - } - if (sqls) { - r = test_sqls_in_conn(env, conn, sqls); - } - SQLDisconnect(conn); - SQLFreeConnect(conn); - SQLFreeEnv(env); - return r ? 1 : 0; -} - -void usage(const char *arg0) { - fprintf(stdout, "%s usage:\n", arg0); - fprintf(stdout, "%s [--dsn ] [--uid ] [--pwd ] [--dcs ] [--sts ]\n", arg0); - fprintf(stdout, " --dsn : DSN\n"); - fprintf(stdout, " --uid : UID\n"); - fprintf(stdout, " --pwd : PWD\n"); - fprintf(stdout, " --dcs : driver connection string\n"); - fprintf(stdout, " --sts : file where statements store\n"); -} - -int main(int argc, char *argv[]) { - // if (argc==1) { - // CHK_TEST(test_env()); - // CHK_TEST(test1("TAOS_DSN", "root", "taoxsdata")); - // D("Done!"); - // return 0; - // } - - const char *dsn = NULL; - const char *uid = NULL; - const char *pwd = NULL; - const char *dcs = NULL; // driver connection string - const char *sts = NULL; // statements file - for (size_t i=1; i=argc) { - D(" expected but got nothing"); - return 1; - } - if (dcs) { - D("--dcs has already been specified"); - return 1; - } - dsn = argv[i]; - continue; - } - if (strcmp(arg, "--uid")==0) { - ++i; - if (i>=argc) { - D(" expected but got nothing"); - return 1; - } - uid = argv[i]; - continue; - } - if (strcmp(arg, "--pwd")==0) { - ++i; - if (i>=argc) { - D(" expected but got nothing"); - return 1; - } - pwd = argv[i]; - continue; - } - if (strcmp(arg, "--dcs")==0) { - ++i; - if (i>=argc) { - D(" expected but got nothing"); - return 1; - } - if (dsn || uid || pwd) { - D("either of --dsn/--uid/--pwd has already been specified"); - return 1; - } - dcs = argv[i]; - continue; - } - if (strcmp(arg, "--sts")==0) { - ++i; - if (i>=argc) { - D(" expected but got nothing"); - return 1; - } - sts = argv[i]; - continue; - } - } - CHK_TEST(test_sqls(dsn, uid, pwd, dcs, sts)); - D("Done!"); - return 0; - - if (0) { - const char *dsn = (argc>1) ? argv[1] : NULL; - const char *uid = (argc>2) ? argv[2] : NULL; - const char *pwd = (argc>3) ? argv[3] : NULL; - const char *connstr = (argc>4) ? argv[4] : NULL; - const char *sqls = (argc>5) ? argv[5] : NULL; - - dsn = NULL; - uid = NULL; - pwd = NULL; - connstr = argv[1]; - sqls = argv[2]; - if (0) { - CHK_TEST(test_env()); - - CHK_TEST(test1(dsn, uid, pwd)); - - const char *statements[] = { - "drop database if exists m", - "create database m", - "use m", - "drop database m", - NULL - }; - CHK_TEST(test_statements(dsn, uid, pwd, statements)); - - if (connstr) - CHK_TEST(test_driver_connect(connstr)); - - if (connstr) { - SQLHENV env = {0}; - SQLHDBC conn = {0}; - CHK_TEST(open_driver_connect(connstr, &env, &conn)); - int r = tests(env, conn); - SQLDisconnect(conn); - SQLFreeConnect(conn); - SQLFreeEnv(env); - if (r) return 1; - } - } - - if ((dsn || connstr) && 1) { - CHK_TEST(test_sqls(dsn, uid, pwd, connstr, sqls)); - } - - D("Done!"); - return 0; - } -} - diff --git a/src/connector/odbc/tests/odbc.py b/src/connector/odbc/tests/odbc.py deleted file mode 100644 index c137905775..0000000000 --- a/src/connector/odbc/tests/odbc.py +++ /dev/null @@ -1,131 +0,0 @@ -import pyodbc -# cnxn = pyodbc.connect('DSN={TAOS_DSN};UID={ root };PWD={ taosdata };HOST={ localhost:6030 }', autocommit=True) -cnxn = pyodbc.connect('DSN={TAOS_DSN}; UID=root;PWD=taosdata; HOST=localhost:6030', autocommit=True) -cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8') -#cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8') -#cnxn.setencoding(encoding='utf-8') - -#cursor = cnxn.cursor() -#cursor.execute("SELECT * from db.t") -#row = cursor.fetchone() -#while row: -# print(row) -# row = cursor.fetchone() -#cursor.close() - -#cursor = cnxn.cursor() -#cursor.execute(""" -#INSERT INTO db.t values (?,?,?,?,?,?,?,?,?,?) -#""", -#"2020-12-12 00:00:00", -#1, -#27, -#32767, -#147483647, -#223372036854775807, -#23.456, -#899.999999, -#"foo", -#"bar") - -cursor = cnxn.cursor() -cursor.execute("drop database if exists db"); -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("create database db"); -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("create table db.mt (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))"); -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("insert into db.mt values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hello', 'world')") -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo", "wo哈rld"); -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("SELECT * from db.mt") -row = cursor.fetchone() -while row: - print(row) - row = cursor.fetchone() -cursor.close() - -#cursor = cnxn.cursor() -#cursor.execute("drop database if exists db"); -#cursor.close() -# -#cursor = cnxn.cursor() -#cursor.execute("create database db"); -#cursor.close() - -cursor = cnxn.cursor() -cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(4), blob nchar(4))"); -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hell', 'worl')") -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("SELECT * from db.t") -row = cursor.fetchone() -while row: - print(row) - row = cursor.fetchone() -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("create table db.v (ts timestamp, v1 tinyint)") -cursor.close() - -params = [ ('A', 1), ('B', 2), ('C', 3) ] -params = [ ('A', 1), ('B', 2), ('C', 3) ] -params = [ ('2020-10-16 00:00:00', 1), - ('2020-10-16 00:00:01', 4), - ('2020-10-16 00:00:02', 5), - ('2020-10-16 00:00:03.009', 6) ] -cursor = cnxn.cursor() -cursor.fast_executemany = True -cursor.executemany("insert into db.v values (?, ?)", params) -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("SELECT * from db.v") -row = cursor.fetchone() -while row: - print(row) - row = cursor.fetchone() -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("SELECT * from db.v where v1 > ?", 4) -row = cursor.fetchone() -while row: - print(row) - row = cursor.fetchone() -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("SELECT * from db.v where v1 > ?", '5') -row = cursor.fetchone() -while row: - print(row) - row = cursor.fetchone() -cursor.close() - -cursor = cnxn.cursor() -cursor.execute("create table db.f (ts timestamp, v1 float)") -cursor.close() - -params = [ ('2020-10-20 00:00:10', '123.3') ] -cursor = cnxn.cursor() -cursor.fast_executemany = True -cursor.executemany("insert into db.f values (?, ?)", params) -cursor.close() - diff --git a/src/connector/odbc/tools/CMakeLists.txt b/src/connector/odbc/tools/CMakeLists.txt index a0aafb1f3c..e543d245c8 100644 --- a/src/connector/odbc/tools/CMakeLists.txt +++ b/src/connector/odbc/tools/CMakeLists.txt @@ -1,12 +1,23 @@ PROJECT(TDengine) -IF (TD_LINUX) - ADD_EXECUTABLE(todbcinst main.c) +ADD_EXECUTABLE(todbcinst main.c) +ADD_EXECUTABLE(tconv tconv.c) + +IF (TD_LINUX OR TD_DARWIN) TARGET_LINK_LIBRARIES(todbcinst odbc odbcinst) ENDIF () +IF (TD_DARWIN) + target_include_directories(todbcinst PRIVATE /usr/local/include) + target_link_directories(todbcinst PUBLIC /usr/local/lib) + target_include_directories(tconv PRIVATE /usr/local/include) + target_link_directories(tconv PUBLIC /usr/local/lib) + TARGET_LINK_LIBRARIES(tconv iconv) +ENDIF () + IF (TD_WINDOWS_64) - ADD_EXECUTABLE(todbcinst main.c) TARGET_LINK_LIBRARIES(todbcinst odbc32 odbccp32 user32 legacy_stdio_definitions os) + TARGET_LINK_LIBRARIES(tconv taos) INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/todbcinst.exe DESTINATION .) ENDIF () + diff --git a/src/connector/odbc/tests/tconv.c b/src/connector/odbc/tools/tconv.c similarity index 100% rename from src/connector/odbc/tests/tconv.c rename to src/connector/odbc/tools/tconv.c diff --git a/src/dnode/CMakeLists.txt b/src/dnode/CMakeLists.txt index 516e5b4d1f..dd18f00920 100644 --- a/src/dnode/CMakeLists.txt +++ b/src/dnode/CMakeLists.txt @@ -35,6 +35,10 @@ IF (TD_TOPIC) TARGET_LINK_LIBRARIES(taosd topic) ENDIF () +IF (TD_MODULE AND TD_LINUX) + TARGET_LINK_LIBRARIES(taosd module dl) +ENDIF () + SET(PREPARE_ENV_CMD "prepare_env_cmd") SET(PREPARE_ENV_TARGET "prepare_env_target") ADD_CUSTOM_COMMAND(OUTPUT ${PREPARE_ENV_CMD} diff --git a/src/dnode/src/dnodeMain.c b/src/dnode/src/dnodeMain.c index 952f220c57..2cd5c637e5 100644 --- a/src/dnode/src/dnodeMain.c +++ b/src/dnode/src/dnodeMain.c @@ -39,6 +39,13 @@ #include "dnodeMPeer.h" #include "dnodeShell.h" #include "dnodeTelemetry.h" +#include "module.h" + +#if !defined(_MODULE) || !defined(_TD_LINUX) +int32_t moduleStart() { return 0; } +void moduleStop() {} +#endif + void *tsDnodeTmr = NULL; static SRunStatus tsRunStatus = TSDB_RUN_STATUS_STOPPED; @@ -149,6 +156,7 @@ int32_t dnodeInitSystem() { } dnodeSetRunStatus(TSDB_RUN_STATUS_RUNING); + moduleStart(); dnodeReportStep("TDengine", "initialized successfully", 1); dInfo("TDengine is initialized successfully"); @@ -158,6 +166,7 @@ int32_t dnodeInitSystem() { void dnodeCleanUpSystem() { if (dnodeGetRunStatus() != TSDB_RUN_STATUS_STOPPED) { + moduleStop(); dnodeSetRunStatus(TSDB_RUN_STATUS_STOPPED); dnodeCleanupTmr(); dnodeCleanupComponents(); diff --git a/src/dnode/src/dnodePeer.c b/src/dnode/src/dnodePeer.c index 79c60874f9..b8ce1c802b 100644 --- a/src/dnode/src/dnodePeer.c +++ b/src/dnode/src/dnodePeer.c @@ -43,6 +43,7 @@ int32_t dnodeInitServer() { dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_CREATE_VNODE] = dnodeDispatchToVMgmtQueue; dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_ALTER_VNODE] = dnodeDispatchToVMgmtQueue; + dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_SYNC_VNODE] = dnodeDispatchToVMgmtQueue; dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_DROP_VNODE] = dnodeDispatchToVMgmtQueue; dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_ALTER_STREAM] = dnodeDispatchToVMgmtQueue; dnodeProcessReqMsgFp[TSDB_MSG_TYPE_MD_CONFIG_DNODE] = dnodeDispatchToVMgmtQueue; diff --git a/src/dnode/src/dnodeShell.c b/src/dnode/src/dnodeShell.c index 60d9c38c05..50343cfd32 100644 --- a/src/dnode/src/dnodeShell.c +++ b/src/dnode/src/dnodeShell.c @@ -49,6 +49,7 @@ int32_t dnodeInitShell() { dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_CREATE_DB] = dnodeDispatchToMWriteQueue; dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_CREATE_TP] = dnodeDispatchToMWriteQueue; dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_DROP_DB] = dnodeDispatchToMWriteQueue; + dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_SYNC_DB] = dnodeDispatchToMWriteQueue; dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_DROP_TP] = dnodeDispatchToMWriteQueue; dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_ALTER_DB] = dnodeDispatchToMWriteQueue; dnodeProcessShellMsgFp[TSDB_MSG_TYPE_CM_ALTER_TP] = dnodeDispatchToMWriteQueue; diff --git a/src/dnode/src/dnodeVMgmt.c b/src/dnode/src/dnodeVMgmt.c index 1e428fc8b1..66c94bf675 100644 --- a/src/dnode/src/dnodeVMgmt.c +++ b/src/dnode/src/dnodeVMgmt.c @@ -30,6 +30,7 @@ static taos_queue tsVMgmtQueue = NULL; static void * dnodeProcessMgmtQueue(void *param); static int32_t dnodeProcessCreateVnodeMsg(SRpcMsg *pMsg); static int32_t dnodeProcessAlterVnodeMsg(SRpcMsg *pMsg); +static int32_t dnodeProcessSyncVnodeMsg(SRpcMsg *pMsg); static int32_t dnodeProcessDropVnodeMsg(SRpcMsg *pMsg); static int32_t dnodeProcessAlterStreamMsg(SRpcMsg *pMsg); static int32_t dnodeProcessConfigDnodeMsg(SRpcMsg *pMsg); @@ -39,6 +40,7 @@ static int32_t (*dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MAX])(SRpcMsg *pMsg); int32_t dnodeInitVMgmt() { dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_CREATE_VNODE] = dnodeProcessCreateVnodeMsg; dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_ALTER_VNODE] = dnodeProcessAlterVnodeMsg; + dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_SYNC_VNODE] = dnodeProcessSyncVnodeMsg; dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_DROP_VNODE] = dnodeProcessDropVnodeMsg; dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_ALTER_STREAM] = dnodeProcessAlterStreamMsg; dnodeProcessMgmtMsgFp[TSDB_MSG_TYPE_MD_CONFIG_DNODE] = dnodeProcessConfigDnodeMsg; @@ -179,6 +181,13 @@ static int32_t dnodeProcessAlterVnodeMsg(SRpcMsg *rpcMsg) { } } +static int32_t dnodeProcessSyncVnodeMsg(SRpcMsg *rpcMsg) { + SSyncVnodeMsg *pSyncVnode = rpcMsg->pCont; + pSyncVnode->vgId = htonl(pSyncVnode->vgId); + + return vnodeSync(pSyncVnode->vgId); +} + static int32_t dnodeProcessDropVnodeMsg(SRpcMsg *rpcMsg) { SDropVnodeMsg *pDrop = rpcMsg->pCont; pDrop->vgId = htonl(pDrop->vgId); diff --git a/src/dnode/src/dnodeVnodes.c b/src/dnode/src/dnodeVnodes.c index d00314fcbc..d96251cebe 100644 --- a/src/dnode/src/dnodeVnodes.c +++ b/src/dnode/src/dnodeVnodes.c @@ -202,10 +202,11 @@ static void dnodeProcessStatusRsp(SRpcMsg *pMsg) { char clusterId[TSDB_CLUSTER_ID_LEN]; dnodeGetClusterId(clusterId); if (clusterId[0] != '\0') { - dError("exit zombie dropped dnode"); - exit(EXIT_FAILURE); + dError("exit zombie dropped dnode"); + exit(EXIT_FAILURE); } } + taosTmrReset(dnodeSendStatusMsg, tsStatusInterval * 1000, NULL, tsDnodeTmr, &tsStatusTimer); return; } diff --git a/src/inc/module.h b/src/inc/module.h new file mode 100644 index 0000000000..b9b64c493e --- /dev/null +++ b/src/inc/module.h @@ -0,0 +1,30 @@ +/* + * 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_MODULE +#define TDENGINE_MODULE + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t moduleStart(); +void moduleStop(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/inc/query.h b/src/inc/query.h index 77a12ebfc5..c9dabcef54 100644 --- a/src/inc/query.h +++ b/src/inc/query.h @@ -38,7 +38,7 @@ int32_t qCreateQueryInfo(void* tsdb, int32_t vgId, SQueryTableMsg* pQueryTableMs * @param qinfo * @return */ -bool qTableQuery(qinfo_t qinfo); +bool qTableQuery(qinfo_t qinfo, uint64_t *qId); /** * Retrieve the produced results information, if current query is not paused or completed, diff --git a/src/inc/taosdef.h b/src/inc/taosdef.h index d9a50e8914..252e37a5d9 100644 --- a/src/inc/taosdef.h +++ b/src/inc/taosdef.h @@ -259,7 +259,7 @@ do { \ #define TSDB_MIN_TABLES 4 #define TSDB_MAX_TABLES 10000000 #define TSDB_DEFAULT_TABLES 1000000 -#define TSDB_TABLES_STEP 1000 +#define TSDB_TABLES_STEP 100 #define TSDB_MIN_DAYS_PER_FILE 1 #define TSDB_MAX_DAYS_PER_FILE 3650 @@ -317,7 +317,7 @@ do { \ #define TSDB_MAX_DB_QUORUM_OPTION 2 #define TSDB_DEFAULT_DB_QUORUM_OPTION 1 -#define TSDB_MAX_JOIN_TABLE_NUM 5 +#define TSDB_MAX_JOIN_TABLE_NUM 10 #define TSDB_MAX_UNION_CLAUSE 5 #define TSDB_MAX_BINARY_LEN (TSDB_MAX_BYTES_PER_ROW-TSDB_KEYSIZE) diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index e069d0295a..8daccee1f2 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -187,6 +187,8 @@ int32_t* taosGetErrno(); #define TSDB_CODE_MND_INVALID_TOPIC TAOS_DEF_ERROR_CODE(0, 0x0392) //"Invalid topic name) #define TSDB_CODE_MND_INVALID_TOPIC_OPTION TAOS_DEF_ERROR_CODE(0, 0x0393) //"Invalid topic option) +#define TSDB_CODE_MND_INVALID_TOPIC_PARTITONS TAOS_DEF_ERROR_CODE(0, 0x0394) //"Invalid topic partitons num, valid range: [1, 1000]) +#define TSDB_CODE_MND_TOPIC_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x0395) //"Topic already exists) // dnode #define TSDB_CODE_DND_MSG_NOT_PROCESSED TAOS_DEF_ERROR_CODE(0, 0x0400) //"Message not processed") diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index 00f64eba77..99f4e1518f 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -59,6 +59,7 @@ TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_DROP_STABLE, "drop-stable" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_ALTER_STREAM, "alter-stream" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_CONFIG_DNODE, "config-dnode" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_ALTER_VNODE, "alter-vnode" ) +TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_SYNC_VNODE, "sync-vnode" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_MD_CREATE_MNODE, "create-mnode" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_DUMMY6, "dummy6" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_DUMMY7, "dummy7" ) @@ -77,6 +78,7 @@ TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_CREATE_DB, "create-db" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_DROP_DB, "drop-db" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_USE_DB, "use-db" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_ALTER_DB, "alter-db" ) +TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_SYNC_DB, "sync-db-replica" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_CREATE_TABLE, "create-table" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_DROP_TABLE, "drop-table" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CM_ALTER_TABLE, "alter-table" ) @@ -388,7 +390,7 @@ typedef struct { typedef struct { int32_t vgId; -} SDropVnodeMsg; +} SDropVnodeMsg, SSyncVnodeMsg; typedef struct SColIndex { int16_t colId; // column id @@ -513,12 +515,13 @@ typedef struct { typedef struct { int32_t code; - uint64_t qhandle; // query handle + union{uint64_t qhandle; uint64_t qId;}; // query handle } SQueryTableRsp; +// todo: the show handle should be replaced with id typedef struct { SMsgHead header; - uint64_t qhandle; + union{uint64_t qhandle; uint64_t qId;}; // query handle uint16_t free; } SRetrieveTableMsg; @@ -574,7 +577,7 @@ typedef struct { typedef struct { char db[TSDB_TABLE_FNAME_LEN]; uint8_t ignoreNotExists; -} SDropDbMsg, SUseDbMsg; +} SDropDbMsg, SUseDbMsg, SSyncDbMsg; // IMPORTANT: sizeof(SVnodeStatisticInfo) should not exceed // TSDB_FILE_HEADER_LEN/4 - TSDB_FILE_HEADER_VERSION_SIZE diff --git a/src/inc/tsdb.h b/src/inc/tsdb.h index 493bdbe5de..495bfa2384 100644 --- a/src/inc/tsdb.h +++ b/src/inc/tsdb.h @@ -245,7 +245,7 @@ typedef struct { * @param qinfo query info handle from query processor * @return */ -TsdbQueryHandleT *tsdbQueryTables(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *tableInfoGroup, void *qinfo, +TsdbQueryHandleT *tsdbQueryTables(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *tableInfoGroup, uint64_t qId, SMemRef *pRef); /** @@ -258,7 +258,7 @@ TsdbQueryHandleT *tsdbQueryTables(STsdbRepo *tsdb, STsdbQueryCond *pCond, STable * @param tableInfo table list. * @return */ -TsdbQueryHandleT tsdbQueryLastRow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *tableInfo, void *qinfo, +TsdbQueryHandleT tsdbQueryLastRow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *tableInfo, uint64_t qId, SMemRef *pRef); /** @@ -277,7 +277,7 @@ SArray *tsdbGetQueriedTableList(TsdbQueryHandleT *pHandle); * @return */ TsdbQueryHandleT tsdbQueryRowsInExternalWindow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList, - void *qinfo, SMemRef *pRef); + uint64_t qId, SMemRef *pRef); /** diff --git a/src/inc/ttokendef.h b/src/inc/ttokendef.h index 91c08fa26a..e9f95660f7 100644 --- a/src/inc/ttokendef.h +++ b/src/inc/ttokendef.h @@ -152,56 +152,57 @@ #define TK_NOW 133 #define TK_RESET 134 #define TK_QUERY 135 -#define TK_ADD 136 -#define TK_COLUMN 137 -#define TK_TAG 138 -#define TK_CHANGE 139 -#define TK_SET 140 -#define TK_KILL 141 -#define TK_CONNECTION 142 -#define TK_STREAM 143 -#define TK_COLON 144 -#define TK_ABORT 145 -#define TK_AFTER 146 -#define TK_ATTACH 147 -#define TK_BEFORE 148 -#define TK_BEGIN 149 -#define TK_CASCADE 150 -#define TK_CLUSTER 151 -#define TK_CONFLICT 152 -#define TK_COPY 153 -#define TK_DEFERRED 154 -#define TK_DELIMITERS 155 -#define TK_DETACH 156 -#define TK_EACH 157 -#define TK_END 158 -#define TK_EXPLAIN 159 -#define TK_FAIL 160 -#define TK_FOR 161 -#define TK_IGNORE 162 -#define TK_IMMEDIATE 163 -#define TK_INITIALLY 164 -#define TK_INSTEAD 165 -#define TK_MATCH 166 -#define TK_KEY 167 -#define TK_OF 168 -#define TK_RAISE 169 -#define TK_REPLACE 170 -#define TK_RESTRICT 171 -#define TK_ROW 172 -#define TK_STATEMENT 173 -#define TK_TRIGGER 174 -#define TK_VIEW 175 -#define TK_SEMI 176 -#define TK_NONE 177 -#define TK_PREV 178 -#define TK_LINEAR 179 -#define TK_IMPORT 180 -#define TK_TBNAME 181 -#define TK_JOIN 182 -#define TK_INSERT 183 -#define TK_INTO 184 -#define TK_VALUES 185 +#define TK_SYNCDB 136 +#define TK_ADD 137 +#define TK_COLUMN 138 +#define TK_TAG 139 +#define TK_CHANGE 140 +#define TK_SET 141 +#define TK_KILL 142 +#define TK_CONNECTION 143 +#define TK_STREAM 144 +#define TK_COLON 145 +#define TK_ABORT 146 +#define TK_AFTER 147 +#define TK_ATTACH 148 +#define TK_BEFORE 149 +#define TK_BEGIN 150 +#define TK_CASCADE 151 +#define TK_CLUSTER 152 +#define TK_CONFLICT 153 +#define TK_COPY 154 +#define TK_DEFERRED 155 +#define TK_DELIMITERS 156 +#define TK_DETACH 157 +#define TK_EACH 158 +#define TK_END 159 +#define TK_EXPLAIN 160 +#define TK_FAIL 161 +#define TK_FOR 162 +#define TK_IGNORE 163 +#define TK_IMMEDIATE 164 +#define TK_INITIALLY 165 +#define TK_INSTEAD 166 +#define TK_MATCH 167 +#define TK_KEY 168 +#define TK_OF 169 +#define TK_RAISE 170 +#define TK_REPLACE 171 +#define TK_RESTRICT 172 +#define TK_ROW 173 +#define TK_STATEMENT 174 +#define TK_TRIGGER 175 +#define TK_VIEW 176 +#define TK_SEMI 177 +#define TK_NONE 178 +#define TK_PREV 179 +#define TK_LINEAR 180 +#define TK_IMPORT 181 +#define TK_TBNAME 182 +#define TK_JOIN 183 +#define TK_INSERT 184 +#define TK_INTO 185 +#define TK_VALUES 186 #define TK_SPACE 300 diff --git a/src/inc/vnode.h b/src/inc/vnode.h index dddec83da8..39bd2f46c3 100644 --- a/src/inc/vnode.h +++ b/src/inc/vnode.h @@ -60,6 +60,7 @@ int32_t vnodeCreate(SCreateVnodeMsg *pVnodeCfg); int32_t vnodeDrop(int32_t vgId); int32_t vnodeOpen(int32_t vgId); int32_t vnodeAlter(void *pVnode, SCreateVnodeMsg *pVnodeCfg); +int32_t vnodeSync(int32_t vgId); int32_t vnodeClose(int32_t vgId); // vnodeMgmt @@ -89,4 +90,4 @@ int32_t vnodeProcessRead(void *pVnode, SVReadMsg *pRead); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/kit/shell/inc/shell.h b/src/kit/shell/inc/shell.h index 019f3e5d92..d0b7149541 100644 --- a/src/kit/shell/inc/shell.h +++ b/src/kit/shell/inc/shell.h @@ -74,6 +74,7 @@ void source_file(TAOS* con, char* fptr); void source_dir(TAOS* con, SShellArguments* args); void shellCheck(TAOS* con, SShellArguments* args); void get_history_path(char* history); +void shellCheck(TAOS* con, SShellArguments* args); void cleanup_handler(void* arg); void exitShell(); int shellDumpResult(TAOS_RES* con, char* fname, int* error_no, bool printMode); diff --git a/src/kit/shell/src/shellEngine.c b/src/kit/shell/src/shellEngine.c index b9529aac8e..0eb1248fad 100644 --- a/src/kit/shell/src/shellEngine.c +++ b/src/kit/shell/src/shellEngine.c @@ -132,7 +132,6 @@ TAOS *shellInit(SShellArguments *args) { return con; } - static bool isEmptyCommand(const char* cmd) { for (char c = *cmd++; c != 0; c = *cmd++) { if (c != ' ' && c != '\t' && c != ';') { diff --git a/src/kit/taosdemo/CMakeLists.txt b/src/kit/taosdemo/CMakeLists.txt index a75157b94c..ba27044a87 100644 --- a/src/kit/taosdemo/CMakeLists.txt +++ b/src/kit/taosdemo/CMakeLists.txt @@ -3,6 +3,55 @@ PROJECT(TDengine) INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/client/inc) +FIND_PACKAGE(Git) +IF (GIT_FOUND) + MESSAGE("Git found") + EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} log --pretty=oneline -n 1 ${CMAKE_CURRENT_LIST_DIR}/taosdemo.c + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE TAOSDEMO_COMMIT) + EXECUTE_PROCESS( + COMMAND bash "-c" "echo '${TAOSDEMO_COMMIT}' | awk '{print $1}' | cut -c -9" + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE TAOSDEMO_COMMIT_SHA1) + EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} status -z -s ${CMAKE_CURRENT_LIST_DIR}/taosdemo.c + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE TAOSDEMO_STATUS) + EXECUTE_PROCESS( + COMMAND bash "-c" "echo '${TAOSDEMO_STATUS}' | awk '{print $1}'" + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE TAOSDEMO_STATUS) + MESSAGE("taosdemo.c status: " ${TAOSDEMO_STATUS}) +ELSE() + MESSAGE("Git not found") + SET(TAOSDEMO_COMMIT_SHA1 "unknown") + SET(TAOSDEMO_STATUS "unknown") +ENDIF (GIT_FOUND) + +STRING(STRIP ${TAOSDEMO_COMMIT_SHA1} TAOSDEMO_COMMIT_SHA1) +MESSAGE("taosdemo's latest commit in short is:" ${TAOSDEMO_COMMIT_SHA1}) +STRING(STRIP ${TAOSDEMO_STATUS} TAOSDEMO_STATUS) + +IF (TAOSDEMO_STATUS MATCHES "M") + SET(TAOSDEMO_STATUS "modified") +ELSE() + SET(TAOSDEMO_STATUS "") +ENDIF () +MESSAGE("taosdemo's status is:" ${TAOSDEMO_STATUS}) + +ADD_DEFINITIONS(-DTAOSDEMO_COMMIT_SHA1="${TAOSDEMO_COMMIT_SHA1}") +ADD_DEFINITIONS(-DTAOSDEMO_STATUS="${TAOSDEMO_STATUS}") + +MESSAGE("VERNUMBER is:" ${VERNUMBER}) +IF ("${VERNUMBER}" STREQUAL "") + SET(TD_VERSION_NUMBER "TDengine-version-unknown") +ELSE() + SET(TD_VERSION_NUMBER ${VERNUMBER}) +ENDIF () +MESSAGE("TD_VERSION_NUMBER is:" ${TD_VERSION_NUMBER}) +ADD_DEFINITIONS(-DTD_VERNUMBER="${TD_VERSION_NUMBER}") + IF (TD_LINUX) AUX_SOURCE_DIRECTORY(. SRC) ADD_EXECUTABLE(taosdemo ${SRC}) diff --git a/src/kit/taosdemo/insert-interlace.json b/src/kit/taosdemo/insert-interlace.json index 0f54f008fb..344db4fd00 100644 --- a/src/kit/taosdemo/insert-interlace.json +++ b/src/kit/taosdemo/insert-interlace.json @@ -41,7 +41,7 @@ "insert_mode": "taosc", "insert_rows": 1000, "multi_thread_write_one_tbl": "no", - "rows_per_tbl": 20, + "interlace_rows": 20, "max_sql_len": 1024000, "disorder_ratio": 0, "disorder_range": 1000, diff --git a/src/kit/taosdemo/insert.json b/src/kit/taosdemo/insert.json index e6b1895043..f0e3ab1d50 100644 --- a/src/kit/taosdemo/insert.json +++ b/src/kit/taosdemo/insert.json @@ -41,7 +41,7 @@ "insert_mode": "taosc", "insert_rows": 100000, "multi_thread_write_one_tbl": "no", - "rows_per_tbl": 0, + "interlace_rows": 0, "max_sql_len": 1024000, "disorder_ratio": 0, "disorder_range": 1000, diff --git a/src/kit/taosdemo/taosdemo.c b/src/kit/taosdemo/taosdemo.c index 95cdf422f9..00a88a5bfd 100644 --- a/src/kit/taosdemo/taosdemo.c +++ b/src/kit/taosdemo/taosdemo.c @@ -37,10 +37,10 @@ #include #include #include -#else +#else #include #include -#endif +#endif #include #include @@ -69,7 +69,10 @@ enum TEST_MODE { #define MAX_SQL_SIZE 65536 #define BUFFER_SIZE (65536*2) +#define MAX_USERNAME_SIZE 64 +#define MAX_PASSWORD_SIZE 64 #define MAX_DB_NAME_SIZE 64 +#define MAX_HOSTNAME_SIZE 64 #define MAX_TB_NAME_SIZE 64 #define MAX_DATA_SIZE 16000 #define MAX_NUM_DATATYPE 10 @@ -86,20 +89,21 @@ enum TEST_MODE { #define MAX_COLUMN_COUNT 1024 #define MAX_TAG_COUNT 128 -#define MAX_QUERY_SQL_COUNT 10 +#define MAX_QUERY_SQL_COUNT 100 #define MAX_QUERY_SQL_LENGTH 256 #define MAX_DATABASE_COUNT 256 #define INPUT_BUF_LEN 256 -#define DEFAULT_TIMESTAMP_STEP 10 +#define DEFAULT_TIMESTAMP_STEP 1 + typedef enum CREATE_SUB_TALBE_MOD_EN { PRE_CREATE_SUBTBL, AUTO_CREATE_SUBTBL, NO_CREATE_SUBTBL } CREATE_SUB_TALBE_MOD_EN; - + typedef enum TALBE_EXISTS_EN { TBL_NO_EXISTS, TBL_ALREADY_EXISTS, @@ -107,7 +111,7 @@ typedef enum TALBE_EXISTS_EN { } TALBE_EXISTS_EN; enum MODE { - SYNC, + SYNC, ASYNC, MODE_BUT }; @@ -118,11 +122,11 @@ typedef enum enum_INSERT_MODE { INVALID_INSERT_MODE } INSERT_MODE; -enum QUERY_TYPE { +typedef enum enumQUERY_TYPE { NO_INSERT_TYPE, INSERT_TYPE, QUERY_TYPE_BUT -} ; +} QUERY_TYPE; enum _show_db_index { TSDB_SHOW_DB_NAME_INDEX, @@ -130,7 +134,7 @@ enum _show_db_index { TSDB_SHOW_DB_NTABLES_INDEX, TSDB_SHOW_DB_VGROUPS_INDEX, TSDB_SHOW_DB_REPLICA_INDEX, - TSDB_SHOW_DB_QUORUM_INDEX, + TSDB_SHOW_DB_QUORUM_INDEX, TSDB_SHOW_DB_DAYS_INDEX, TSDB_SHOW_DB_KEEP_INDEX, TSDB_SHOW_DB_CACHE_INDEX, @@ -141,7 +145,7 @@ enum _show_db_index { TSDB_SHOW_DB_FSYNC_INDEX, TSDB_SHOW_DB_COMP_INDEX, TSDB_SHOW_DB_CACHELAST_INDEX, - TSDB_SHOW_DB_PRECISION_INDEX, + TSDB_SHOW_DB_PRECISION_INDEX, TSDB_SHOW_DB_UPDATE_INDEX, TSDB_SHOW_DB_STATUS_INDEX, TSDB_MAX_SHOW_DB @@ -152,10 +156,10 @@ enum _show_stables_index { TSDB_SHOW_STABLES_NAME_INDEX, TSDB_SHOW_STABLES_CREATED_TIME_INDEX, TSDB_SHOW_STABLES_COLUMNS_INDEX, - TSDB_SHOW_STABLES_METRIC_INDEX, - TSDB_SHOW_STABLES_UID_INDEX, + TSDB_SHOW_STABLES_METRIC_INDEX, + TSDB_SHOW_STABLES_UID_INDEX, TSDB_SHOW_STABLES_TID_INDEX, - TSDB_SHOW_STABLES_VGID_INDEX, + TSDB_SHOW_STABLES_VGID_INDEX, TSDB_MAX_SHOW_STABLES }; @@ -187,6 +191,7 @@ typedef struct SArguments_S { char * tb_prefix; char * sqlFile; bool use_metric; + bool drop_database; bool insert_only; bool answer_yes; bool debug_print; @@ -199,7 +204,8 @@ typedef struct SArguments_S { int num_of_CPR; int num_of_threads; int insert_interval; - int rows_per_tbl; + int query_times; + int interlace_rows; int num_of_RPR; int max_sql_len; int num_of_tables; @@ -217,13 +223,12 @@ typedef struct SColumn_S { char field[TSDB_COL_NAME_LEN + 1]; char dataType[MAX_TB_NAME_SIZE]; int dataLen; - char note[128]; + char note[128]; } StrColumn; typedef struct SSuperTable_S { char sTblName[MAX_TB_NAME_SIZE+1]; int childTblCount; - bool superTblExists; // 0: no, 1: yes bool childTblExists; // 0: no, 1: yes int batchCreateTableNum; // 0: no batch, > 0: batch table number in one sql int8_t autoCreateTable; // 0: create sub table, 1: auto create sub table @@ -234,7 +239,7 @@ typedef struct SSuperTable_S { int childTblOffset; int multiThreadWriteOneTbl; // 0: no, 1: yes - int rowsPerTbl; // + int interlaceRows; // int disorderRatio; // 0: no disorder, >0: x% int disorderRange; // ms or us by database precision int maxSqlLen; // @@ -267,7 +272,7 @@ typedef struct SSuperTable_S { int tagSampleCount; int tagUsePos; - // statistics + // statistics int64_t totalInsertRows; int64_t totalAffectedRows; } SSuperTable; @@ -276,10 +281,10 @@ typedef struct { char name[TSDB_DB_NAME_LEN + 1]; char create_time[32]; int32_t ntables; - int32_t vgroups; + int32_t vgroups; int16_t replica; int16_t quorum; - int16_t days; + int16_t days; char keeplist[32]; int32_t cache; //MB int32_t blocks; @@ -294,14 +299,14 @@ typedef struct { char status[16]; } SDbInfo; -typedef struct SDbCfg_S { +typedef struct SDbCfg_S { // int maxtablesPerVnode; - int minRows; + int minRows; int maxRows; int comp; int walLevel; int cacheLast; - int fsync; + int fsync; int replica; int update; int keep; @@ -309,12 +314,12 @@ typedef struct SDbCfg_S { int cache; int blocks; int quorum; - char precision[MAX_TB_NAME_SIZE]; + char precision[MAX_TB_NAME_SIZE]; } SDbCfg; typedef struct SDataBase_S { char dbName[MAX_DB_NAME_SIZE]; - int drop; // 0: use exists, 1: if exists, drop then new create + bool drop; // 0: use exists, 1: if exists, drop then new create SDbCfg dbCfg; int superTblCount; SSuperTable superTbls[MAX_SUPER_TABLE_COUNT]; @@ -322,16 +327,16 @@ typedef struct SDataBase_S { typedef struct SDbs_S { char cfgDir[MAX_FILE_NAME_LEN+1]; - char host[MAX_DB_NAME_SIZE]; + char host[MAX_HOSTNAME_SIZE]; uint16_t port; - char user[MAX_DB_NAME_SIZE]; - char password[MAX_DB_NAME_SIZE]; + char user[MAX_USERNAME_SIZE]; + char password[MAX_PASSWORD_SIZE]; char resultFile[MAX_FILE_NAME_LEN+1]; bool use_metric; bool insert_only; bool do_aggreFunc; bool queryMode; - + int threadCount; int threadCountByCreateTbl; int dbCount; @@ -343,68 +348,71 @@ typedef struct SDbs_S { } SDbs; -typedef struct SuperQueryInfo_S { +typedef struct SpecifiedQueryInfo_S { int rate; // 0: unlimit > 0 loop/s int concurrent; int sqlCount; int subscribeMode; // 0: sync, 1: async int subscribeInterval; // ms + int queryTimes; int subscribeRestart; int subscribeKeepProgress; - char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH+1]; + char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH+1]; char result[MAX_QUERY_SQL_COUNT][MAX_FILE_NAME_LEN+1]; TAOS_SUB* tsub[MAX_QUERY_SQL_COUNT]; -} SuperQueryInfo; +} SpecifiedQueryInfo; -typedef struct SubQueryInfo_S { +typedef struct SuperQueryInfo_S { char sTblName[MAX_TB_NAME_SIZE+1]; int rate; // 0: unlimit > 0 loop/s - int threadCnt; + int threadCnt; int subscribeMode; // 0: sync, 1: async int subscribeInterval; // ms int subscribeRestart; int subscribeKeepProgress; + int queryTimes; int childTblCount; char childTblPrefix[MAX_TB_NAME_SIZE]; int sqlCount; - char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH+1]; + char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH+1]; char result[MAX_QUERY_SQL_COUNT][MAX_FILE_NAME_LEN+1]; TAOS_SUB* tsub[MAX_QUERY_SQL_COUNT]; - + char* childTblName; -} SubQueryInfo; +} SuperQueryInfo; typedef struct SQueryMetaInfo_S { char cfgDir[MAX_FILE_NAME_LEN+1]; - char host[MAX_DB_NAME_SIZE]; + char host[MAX_HOSTNAME_SIZE]; uint16_t port; - char user[MAX_DB_NAME_SIZE]; - char password[MAX_DB_NAME_SIZE]; + char user[MAX_USERNAME_SIZE]; + char password[MAX_PASSWORD_SIZE]; char dbName[MAX_DB_NAME_SIZE+1]; char queryMode[MAX_TB_NAME_SIZE]; // taosc, restful - SuperQueryInfo superQueryInfo; - SubQueryInfo subQueryInfo; + SpecifiedQueryInfo specifiedQueryInfo; + SuperQueryInfo superQueryInfo; } SQueryMetaInfo; typedef struct SThreadInfo_S { TAOS *taos; int threadID; char db_name[MAX_DB_NAME_SIZE+1]; + uint32_t time_precision; char fp[4096]; char tb_prefix[MAX_TB_NAME_SIZE]; int start_table_from; int end_table_to; int ntables; int data_of_rate; - uint64_t start_time; - char* cols; - bool use_metric; + uint64_t start_time; + char* cols; + bool use_metric; SSuperTable* superTblInfo; // for async insert tsem_t lock_sem; - int64_t counter; + int64_t counter; uint64_t st; uint64_t et; int64_t lastTs; @@ -421,7 +429,7 @@ typedef struct SThreadInfo_S { int64_t avgDelay; int64_t maxDelay; int64_t minDelay; - + } threadInfo; #ifdef WINDOWS @@ -460,12 +468,12 @@ static void setupForAnsiEscape(void) { if(!SetConsoleMode(g_stdoutHandle, mode)) { exit(GetLastError()); - } + } } static void resetAfterAnsiEscape(void) { // Reset colors - printf("\x1b[0m"); + printf("\x1b[0m"); // Reset console mode if(!SetConsoleMode(g_stdoutHandle, g_consoleMode)) { @@ -488,16 +496,19 @@ static void resetAfterAnsiEscape(void) { printf("\x1b[0m"); } +#include + static int taosRandom() { - return random(); + srand(time(NULL)); + return rand(); } #endif static int createDatabases(); static void createChildTables(); -static int queryDbExec(TAOS *taos, char *command, int type); +static int queryDbExec(TAOS *taos, char *command, QUERY_TYPE type, bool quiet); /* ************ Global variables ************ */ @@ -505,7 +516,7 @@ int32_t randint[MAX_PREPARED_RAND]; int64_t randbigint[MAX_PREPARED_RAND]; float randfloat[MAX_PREPARED_RAND]; double randdouble[MAX_PREPARED_RAND]; -char *aggreFunc[] = {"*", "count(*)", "avg(col0)", "sum(col0)", +char *aggreFunc[] = {"*", "count(*)", "avg(col0)", "sum(col0)", "max(col0)", "min(col0)", "first(col0)", "last(col0)"}; SArguments g_args = { @@ -514,7 +525,7 @@ SArguments g_args = { "127.0.0.1", // host 6030, // port "root", // user - #ifdef _TD_POWER_ + #ifdef _TD_POWER_ "powerdb", // password #else "taosdata", // password @@ -523,8 +534,9 @@ SArguments g_args = { 1, // replica "t", // tb_prefix NULL, // sqlFile - false, // use_metric - false, // insert_only + true, // use_metric + true, // drop_database + true, // insert_only false, // debug_print false, // verbose_print false, // performance statistic print @@ -547,7 +559,8 @@ SArguments g_args = { 10, // num_of_CPR 10, // num_of_connections/thread 0, // insert_interval - 0, // rows_per_tbl; + 1, // query_times + 0, // interlace_rows; 100, // num_of_RPR TSDB_PAYLOAD_SIZE, // max_sql_len 10000, // num_of_tables @@ -586,63 +599,91 @@ static FILE * g_fpOfInsertResult = NULL; static void ERROR_EXIT(const char *msg) { perror(msg); exit(-1); } +#ifndef TAOSDEMO_COMMIT_SHA1 +#define TAOSDEMO_COMMIT_SHA1 "unknown" +#endif + +#ifndef TD_VERNUMBER +#define TD_VERNUMBER "unknown" +#endif + +#ifndef TAOSDEMO_STATUS +#define TAOSDEMO_STATUS "unknown" +#endif + +static void printVersion() { + char tdengine_ver[] = TD_VERNUMBER; + char taosdemo_ver[] = TAOSDEMO_COMMIT_SHA1; + char taosdemo_status[] = TAOSDEMO_STATUS; + + if (strlen(taosdemo_status) == 0) { + printf("taosdemo verison %s-%s\n", + tdengine_ver, taosdemo_ver); + } else { + printf("taosdemo verison %s-%s, status:%s\n", + tdengine_ver, taosdemo_ver, taosdemo_status); + } +} + static void printHelp() { char indent[10] = " "; - printf("%s%s%s%s\n", indent, "-f", indent, + printf("%s%s%s%s\n", indent, "-f", indent, "The meta file to the execution procedure. Default is './meta.json'."); - printf("%s%s%s%s\n", indent, "-u", indent, + printf("%s%s%s%s\n", indent, "-u", indent, "The TDengine user name to use when connecting to the server. Default is 'root'."); #ifdef _TD_POWER_ - printf("%s%s%s%s\n", indent, "-P", indent, + printf("%s%s%s%s\n", indent, "-P", indent, "The password to use when connecting to the server. Default is 'powerdb'."); - printf("%s%s%s%s\n", indent, "-c", indent, + printf("%s%s%s%s\n", indent, "-c", indent, "Configuration directory. Default is '/etc/power/'."); #else - printf("%s%s%s%s\n", indent, "-P", indent, + printf("%s%s%s%s\n", indent, "-P", indent, "The password to use when connecting to the server. Default is 'taosdata'."); - printf("%s%s%s%s\n", indent, "-c", indent, + printf("%s%s%s%s\n", indent, "-c", indent, "Configuration directory. Default is '/etc/taos/'."); #endif - printf("%s%s%s%s\n", indent, "-h", indent, + printf("%s%s%s%s\n", indent, "-h", indent, "The host to connect to TDengine. Default is localhost."); - printf("%s%s%s%s\n", indent, "-p", indent, + printf("%s%s%s%s\n", indent, "-p", indent, "The TCP/IP port number to use for the connection. Default is 0."); - printf("%s%s%s%s\n", indent, "-d", indent, + printf("%s%s%s%s\n", indent, "-d", indent, "Destination database. Default is 'test'."); - printf("%s%s%s%s\n", indent, "-a", indent, + printf("%s%s%s%s\n", indent, "-a", indent, "Set the replica parameters of the database, Default 1, min: 1, max: 3."); - printf("%s%s%s%s\n", indent, "-m", indent, + printf("%s%s%s%s\n", indent, "-m", indent, "Table prefix name. Default is 't'."); printf("%s%s%s%s\n", indent, "-s", indent, "The select sql file."); - printf("%s%s%s%s\n", indent, "-M", indent, "Use metric flag."); - printf("%s%s%s%s\n", indent, "-o", indent, + printf("%s%s%s%s\n", indent, "-N", indent, "Use normal table flag."); + printf("%s%s%s%s\n", indent, "-o", indent, "Direct output to the named file. Default is './output.txt'."); - printf("%s%s%s%s\n", indent, "-q", indent, + printf("%s%s%s%s\n", indent, "-q", indent, "Query mode--0: SYNC, 1: ASYNC. Default is SYNC."); - printf("%s%s%s%s\n", indent, "-b", indent, + printf("%s%s%s%s\n", indent, "-b", indent, "The data_type of columns, default: TINYINT,SMALLINT,INT,BIGINT,FLOAT,DOUBLE,BINARY,NCHAR,BOOL,TIMESTAMP."); - printf("%s%s%s%s\n", indent, "-w", indent, + printf("%s%s%s%s\n", indent, "-w", indent, "The length of data_type 'BINARY' or 'NCHAR'. Default is 16"); - printf("%s%s%s%s\n", indent, "-l", indent, + printf("%s%s%s%s\n", indent, "-l", indent, "The number of columns per record. Default is 10."); - printf("%s%s%s%s\n", indent, "-T", indent, + printf("%s%s%s%s\n", indent, "-T", indent, "The number of threads. Default is 10."); - printf("%s%s%s%s\n", indent, "-i", indent, + printf("%s%s%s%s\n", indent, "-i", indent, "The sleep time (ms) between insertion. Default is 0."); - printf("%s%s%s%s\n", indent, "-r", indent, + printf("%s%s%s%s\n", indent, "-r", indent, "The number of records per request. Default is 100."); - printf("%s%s%s%s\n", indent, "-t", indent, + printf("%s%s%s%s\n", indent, "-t", indent, "The number of tables. Default is 10000."); - printf("%s%s%s%s\n", indent, "-n", indent, + printf("%s%s%s%s\n", indent, "-n", indent, "The number of records per table. Default is 10000."); printf("%s%s%s%s\n", indent, "-x", indent, "Not insert only flag."); printf("%s%s%s%s\n", indent, "-y", indent, "Default input yes for prompt."); - printf("%s%s%s%s\n", indent, "-O", indent, + printf("%s%s%s%s\n", indent, "-O", indent, "Insert mode--0: In order, > 0: disorder ratio. Default is in order."); - printf("%s%s%s%s\n", indent, "-R", indent, + printf("%s%s%s%s\n", indent, "-R", indent, "Out of order data's range, ms, default is 1000."); - printf("%s%s%s%s\n", indent, "-g", indent, + printf("%s%s%s%s\n", indent, "-g", indent, "Print debug info."); + printf("%s%s%s%s\n", indent, "-V, --version", indent, + "Print version info."); /* printf("%s%s%s%s\n", indent, "-D", indent, "if elete database if exists. 0: no, 1: yes, default is 1"); */ @@ -663,6 +704,7 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { } taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); wordfree(&full_path); + } else if (strcmp(argv[i], "-h") == 0) { arguments->host = argv[++i]; } else if (strcmp(argv[i], "-p") == 0) { @@ -681,8 +723,10 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { arguments->num_of_threads = atoi(argv[++i]); } else if (strcmp(argv[i], "-i") == 0) { arguments->insert_interval = atoi(argv[++i]); + } else if (strcmp(argv[i], "-qt") == 0) { + arguments->query_times = atoi(argv[++i]); } else if (strcmp(argv[i], "-B") == 0) { - arguments->rows_per_tbl = atoi(argv[++i]); + arguments->interlace_rows = atoi(argv[++i]); } else if (strcmp(argv[i], "-r") == 0) { arguments->num_of_RPR = atoi(argv[++i]); } else if (strcmp(argv[i], "-t") == 0) { @@ -742,10 +786,10 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { arguments->len_of_binary = atoi(argv[++i]); } else if (strcmp(argv[i], "-m") == 0) { arguments->tb_prefix = argv[++i]; - } else if (strcmp(argv[i], "-M") == 0) { - arguments->use_metric = true; + } else if (strcmp(argv[i], "-N") == 0) { + arguments->use_metric = false; } else if (strcmp(argv[i], "-x") == 0) { - arguments->insert_only = true; + arguments->insert_only = false; } else if (strcmp(argv[i], "-y") == 0) { arguments->answer_yes = true; } else if (strcmp(argv[i], "-g") == 0) { @@ -758,7 +802,7 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { strcpy(configDir, argv[++i]); } else if (strcmp(argv[i], "-O") == 0) { arguments->disorderRatio = atoi(argv[++i]); - if (arguments->disorderRatio > 1 + if (arguments->disorderRatio > 1 || arguments->disorderRatio < 0) { arguments->disorderRatio = 0; } else if (arguments->disorderRatio == 1) { @@ -766,8 +810,8 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { } } else if (strcmp(argv[i], "-R") == 0) { arguments->disorderRange = atoi(argv[++i]); - if (arguments->disorderRange == 1 - && (arguments->disorderRange > 50 + if (arguments->disorderRange == 1 + && (arguments->disorderRange > 50 || arguments->disorderRange <= 0)) { arguments->disorderRange = 10; } @@ -782,6 +826,10 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { || arguments->method_of_delete > 3) { arguments->method_of_delete = 0; } + } else if ((strcmp(argv[i], "--version") == 0) || + (strcmp(argv[i], "-V") == 0)){ + printVersion(); + exit(0); } else if (strcmp(argv[i], "--help") == 0) { printHelp(); exit(0); @@ -796,7 +844,7 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { || arguments->verbose_print) { printf("###################################################################\n"); printf("# meta file: %s\n", arguments->metaFile); - printf("# Server IP: %s:%hu\n", + printf("# Server IP: %s:%hu\n", arguments->host == NULL ? "localhost" : arguments->host, arguments->port ); printf("# User: %s\n", arguments->user); @@ -823,7 +871,7 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) { if (arguments->disorderRatio) { printf("# Data order: %d\n", arguments->disorderRatio); printf("# Data out of order rate: %d\n", arguments->disorderRange); - + } printf("# Delete method: %d\n", arguments->method_of_delete); printf("# Answer yes when prompt: %d\n", arguments->answer_yes); @@ -853,7 +901,7 @@ static void tmfree(char *buf) { } } -static int queryDbExec(TAOS *taos, char *command, int type) { +static int queryDbExec(TAOS *taos, char *command, QUERY_TYPE type, bool quiet) { int i; TAOS_RES *res = NULL; int32_t code = -1; @@ -868,12 +916,14 @@ static int queryDbExec(TAOS *taos, char *command, int type) { code = taos_errno(res); if (0 == code) { break; - } + } } if (code != 0) { - debugPrint("%s() LN%d - command: %s\n", __func__, __LINE__, command); - errorPrint( "Failed to run %s, reason: %s\n", command, taos_errstr(res)); + if (!quiet) { + debugPrint("%s() LN%d - command: %s\n", __func__, __LINE__, command); + errorPrint("Failed to run %s, reason: %s\n", command, taos_errstr(res)); + } taos_free_result(res); //taos_close(taos); return -1; @@ -884,12 +934,12 @@ static int queryDbExec(TAOS *taos, char *command, int type) { taos_free_result(res); return affectedRows; } - + taos_free_result(res); return 0; } -static void getResult(TAOS_RES *res, char* resultFileName) { +static void getResult(TAOS_RES *res, char* resultFileName) { TAOS_ROW row = NULL; int num_rows = 0; int num_fields = taos_field_count(res); @@ -899,13 +949,15 @@ static void getResult(TAOS_RES *res, char* resultFileName) { if (resultFileName[0] != 0) { fp = fopen(resultFileName, "at"); if (fp == NULL) { - errorPrint("%s() LN%d, failed to open result file: %s, result will not save to file\n", __func__, __LINE__, resultFileName); + errorPrint("%s() LN%d, failed to open result file: %s, result will not save to file\n", + __func__, __LINE__, resultFileName); } } - + char* databuf = (char*) calloc(1, 100*1024*1024); if (databuf == NULL) { - errorPrint("%s() LN%d, failed to malloc, warning: save result to file slowly!\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to malloc, warning: save result to file slowly!\n", + __func__, __LINE__); if (fp) fclose(fp); return ; @@ -941,7 +993,7 @@ static void selectAndGetResult(TAOS *taos, char *command, char* resultFileName) taos_free_result(res); return; } - + getResult(res, resultFileName); taos_free_result(res); } @@ -989,14 +1041,13 @@ static int64_t rand_bigint(){ cursor++; cursor = cursor % MAX_PREPARED_RAND; return randbigint[cursor]; - } static float rand_float(){ static int cursor; cursor++; cursor = cursor % MAX_PREPARED_RAND; - return randfloat[cursor]; + return randfloat[cursor]; } static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; @@ -1059,18 +1110,19 @@ static int printfInsertMeta() { printf("resultFile: \033[33m%s\033[0m\n", g_Dbs.resultFile); printf("thread num of insert data: \033[33m%d\033[0m\n", g_Dbs.threadCount); printf("thread num of create table: \033[33m%d\033[0m\n", g_Dbs.threadCountByCreateTbl); - printf("insert interval: \033[33m%d\033[0m\n", g_args.insert_interval); + printf("top insert interval: \033[33m%d\033[0m\n", g_args.insert_interval); printf("number of records per req: \033[33m%d\033[0m\n", g_args.num_of_RPR); printf("max sql length: \033[33m%d\033[0m\n", g_args.max_sql_len); printf("database count: \033[33m%d\033[0m\n", g_Dbs.dbCount); + for (int i = 0; i < g_Dbs.dbCount; i++) { printf("database[\033[33m%d\033[0m]:\n", i); printf(" database[%d] name: \033[33m%s\033[0m\n", i, g_Dbs.db[i].dbName); if (0 == g_Dbs.db[i].drop) { - printf(" drop: \033[33mno\033[0m\n"); - }else { - printf(" drop: \033[33myes\033[0m\n"); + printf(" drop: \033[33mno\033[0m\n"); + } else { + printf(" drop: \033[33myes\033[0m\n"); } if (g_Dbs.db[i].dbCfg.blocks > 0) { @@ -1123,8 +1175,8 @@ static int printfInsertMeta() { printf(" super table count: \033[33m%d\033[0m\n", g_Dbs.db[i].superTblCount); for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { printf(" super table[\033[33m%d\033[0m]:\n", j); - - printf(" stbName: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].sTblName); + + printf(" stbName: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].sTblName); if (PRE_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { printf(" autoCreateTable: \033[33m%s\033[0m\n", "no"); @@ -1133,7 +1185,7 @@ static int printfInsertMeta() { } else { printf(" autoCreateTable: \033[33m%s\033[0m\n", "error"); } - + if (TBL_NO_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { printf(" childTblExists: \033[33m%s\033[0m\n", "no"); } else if (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { @@ -1159,8 +1211,14 @@ static int printfInsertMeta() { }else { printf(" multiThreadWriteOneTbl: \033[33myes\033[0m\n"); } - printf(" rowsPerTbl: \033[33m%d\033[0m\n", - g_Dbs.db[i].superTbls[j].rowsPerTbl); + printf(" interlaceRows: \033[33m%d\033[0m\n", + g_Dbs.db[i].superTbls[j].interlaceRows); + + if (g_Dbs.db[i].superTbls[j].interlaceRows > 0) { + printf(" stable insert interval: \033[33m%d\033[0m\n", + g_Dbs.db[i].superTbls[j].insertInterval); + } + printf(" disorderRange: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].disorderRange); printf(" disorderRatio: \033[33m%d\033[0m\n", @@ -1220,23 +1278,25 @@ static int printfInsertMeta() { } static void printfInsertMetaToFile(FILE* fp) { - SHOW_PARSE_RESULT_START_TO_FILE(fp); + + SHOW_PARSE_RESULT_START_TO_FILE(fp); fprintf(fp, "host: %s:%u\n", g_Dbs.host, g_Dbs.port); fprintf(fp, "user: %s\n", g_Dbs.user); - fprintf(fp, "password: %s\n", g_Dbs.password); fprintf(fp, "resultFile: %s\n", g_Dbs.resultFile); fprintf(fp, "thread num of insert data: %d\n", g_Dbs.threadCount); fprintf(fp, "thread num of create table: %d\n", g_Dbs.threadCountByCreateTbl); - + fprintf(fp, "number of records per req: %d\n", g_args.num_of_RPR); + fprintf(fp, "max sql length: %d\n", g_args.max_sql_len); fprintf(fp, "database count: %d\n", g_Dbs.dbCount); + for (int i = 0; i < g_Dbs.dbCount; i++) { fprintf(fp, "database[%d]:\n", i); fprintf(fp, " database[%d] name: %s\n", i, g_Dbs.db[i].dbName); if (0 == g_Dbs.db[i].drop) { - fprintf(fp, " drop: no\n"); + fprintf(fp, " drop: no\n"); }else { - fprintf(fp, " drop: yes\n"); + fprintf(fp, " drop: yes\n"); } if (g_Dbs.db[i].dbCfg.blocks > 0) { @@ -1287,8 +1347,8 @@ static void printfInsertMetaToFile(FILE* fp) { fprintf(fp, " super table count: %d\n", g_Dbs.db[i].superTblCount); for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { fprintf(fp, " super table[%d]:\n", j); - - fprintf(fp, " stbName: %s\n", g_Dbs.db[i].superTbls[j].sTblName); + + fprintf(fp, " stbName: %s\n", g_Dbs.db[i].superTbls[j].sTblName); if (PRE_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { fprintf(fp, " autoCreateTable: %s\n", "no"); @@ -1297,7 +1357,7 @@ static void printfInsertMetaToFile(FILE* fp) { } else { fprintf(fp, " autoCreateTable: %s\n", "error"); } - + if (TBL_NO_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { fprintf(fp, " childTblExists: %s\n", "no"); } else if (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { @@ -1305,30 +1365,41 @@ static void printfInsertMetaToFile(FILE* fp) { } else { fprintf(fp, " childTblExists: %s\n", "error"); } - - fprintf(fp, " childTblCount: %d\n", g_Dbs.db[i].superTbls[j].childTblCount); - fprintf(fp, " childTblPrefix: %s\n", g_Dbs.db[i].superTbls[j].childTblPrefix); - fprintf(fp, " dataSource: %s\n", g_Dbs.db[i].superTbls[j].dataSource); - fprintf(fp, " insertMode: %s\n", g_Dbs.db[i].superTbls[j].insertMode); - fprintf(fp, " insertRows: %"PRId64"\n", g_Dbs.db[i].superTbls[j].insertRows); - fprintf(fp, " insert interval: %d\n", g_Dbs.db[i].superTbls[j].insertInterval); + + fprintf(fp, " childTblCount: %d\n", + g_Dbs.db[i].superTbls[j].childTblCount); + fprintf(fp, " childTblPrefix: %s\n", + g_Dbs.db[i].superTbls[j].childTblPrefix); + fprintf(fp, " dataSource: %s\n", + g_Dbs.db[i].superTbls[j].dataSource); + fprintf(fp, " insertMode: %s\n", + g_Dbs.db[i].superTbls[j].insertMode); + fprintf(fp, " insertRows: %"PRId64"\n", + g_Dbs.db[i].superTbls[j].insertRows); + fprintf(fp, " interlace rows: %d\n", + g_Dbs.db[i].superTbls[j].interlaceRows); + if (g_Dbs.db[i].superTbls[j].interlaceRows > 0) { + fprintf(fp, " stable insert interval: %d\n", + g_Dbs.db[i].superTbls[j].insertInterval); + } if (0 == g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl) { - fprintf(fp, " multiThreadWriteOneTbl: no\n"); + fprintf(fp, " multiThreadWriteOneTbl: no\n"); }else { - fprintf(fp, " multiThreadWriteOneTbl: yes\n"); + fprintf(fp, " multiThreadWriteOneTbl: yes\n"); } - fprintf(fp, " rowsPerTbl: %d\n", g_Dbs.db[i].superTbls[j].rowsPerTbl); - fprintf(fp, " disorderRange: %d\n", g_Dbs.db[i].superTbls[j].disorderRange); + fprintf(fp, " interlaceRows: %d\n", + g_Dbs.db[i].superTbls[j].interlaceRows); + fprintf(fp, " disorderRange: %d\n", g_Dbs.db[i].superTbls[j].disorderRange); fprintf(fp, " disorderRatio: %d\n", g_Dbs.db[i].superTbls[j].disorderRatio); - fprintf(fp, " maxSqlLen: %d\n", g_Dbs.db[i].superTbls[j].maxSqlLen); - - fprintf(fp, " timeStampStep: %d\n", g_Dbs.db[i].superTbls[j].timeStampStep); - fprintf(fp, " startTimestamp: %s\n", g_Dbs.db[i].superTbls[j].startTimestamp); + fprintf(fp, " maxSqlLen: %d\n", g_Dbs.db[i].superTbls[j].maxSqlLen); + + fprintf(fp, " timeStampStep: %d\n", g_Dbs.db[i].superTbls[j].timeStampStep); + fprintf(fp, " startTimestamp: %s\n", g_Dbs.db[i].superTbls[j].startTimestamp); fprintf(fp, " sampleFormat: %s\n", g_Dbs.db[i].superTbls[j].sampleFormat); - fprintf(fp, " sampleFile: %s\n", g_Dbs.db[i].superTbls[j].sampleFile); - fprintf(fp, " tagsFile: %s\n", g_Dbs.db[i].superTbls[j].tagsFile); - + fprintf(fp, " sampleFile: %s\n", g_Dbs.db[i].superTbls[j].sampleFile); + fprintf(fp, " tagsFile: %s\n", g_Dbs.db[i].superTbls[j].tagsFile); + fprintf(fp, " columnCount: %d\n ", g_Dbs.db[i].superTbls[j].columnCount); for (int k = 0; k < g_Dbs.db[i].superTbls[j].columnCount; k++) { //printf("dataType:%s, dataLen:%d\t", g_Dbs.db[i].superTbls[j].columns[k].dataType, g_Dbs.db[i].superTbls[j].columns[k].dataLen); @@ -1364,22 +1435,45 @@ static void printfInsertMetaToFile(FILE* fp) { } fprintf(fp, "\n"); } + SHOW_PARSE_RESULT_END_TO_FILE(fp); } static void printfQueryMeta() { + SHOW_PARSE_RESULT_START(); + printf("host: \033[33m%s:%u\033[0m\n", g_queryInfo.host, g_queryInfo.port); printf("user: \033[33m%s\033[0m\n", g_queryInfo.user); - printf("password: \033[33m%s\033[0m\n", g_queryInfo.password); printf("database name: \033[33m%s\033[0m\n", g_queryInfo.dbName); printf("\n"); - printf("specified table query info: \n"); + printf("specified table query info: \n"); + printf("query interval: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.rate); + printf("top query times:\033[33m%d\033[0m\n", g_args.query_times); + printf("concurrent: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.concurrent); + printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.sqlCount); + printf("specified tbl query times:\n"); + printf(" \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.queryTimes); + + if (SUBSCRIBE_TEST == g_args.test_mode) { + printf("mod: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.subscribeMode); + printf("interval: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.subscribeInterval); + printf("restart: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.subscribeRestart); + printf("keepProgress: \033[33m%d\033[0m\n", g_queryInfo.specifiedQueryInfo.subscribeKeepProgress); + } + + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.sqlCount; i++) { + printf(" sql[%d]: \033[33m%s\033[0m\n", i, g_queryInfo.specifiedQueryInfo.sql[i]); + } + printf("\n"); + printf("super table query info: \n"); printf("query interval: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.rate); - printf("concurrent: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.concurrent); - printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.sqlCount); + printf("threadCnt: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.threadCnt); + printf("childTblCount: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.childTblCount); + printf("stable name: \033[33m%s\033[0m\n", g_queryInfo.superQueryInfo.sTblName); + printf("stb query times:\033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.queryTimes); if (SUBSCRIBE_TEST == g_args.test_mode) { printf("mod: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeMode); @@ -1388,34 +1482,16 @@ static void printfQueryMeta() { printf("keepProgress: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeKeepProgress); } + printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.sqlCount); for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { printf(" sql[%d]: \033[33m%s\033[0m\n", i, g_queryInfo.superQueryInfo.sql[i]); } printf("\n"); - printf("super table query info: \n"); - printf("query interval: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.rate); - printf("threadCnt: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.threadCnt); - printf("childTblCount: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.childTblCount); - printf("stable name: \033[33m%s\033[0m\n", g_queryInfo.subQueryInfo.sTblName); - if (SUBSCRIBE_TEST == g_args.test_mode) { - printf("mod: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeMode); - printf("interval: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeInterval); - printf("restart: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeRestart); - printf("keepProgress: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeKeepProgress); - } - - printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.sqlCount); - for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { - printf(" sql[%d]: \033[33m%s\033[0m\n", i, g_queryInfo.subQueryInfo.sql[i]); - } - printf("\n"); - - SHOW_PARSE_RESULT_END(); + SHOW_PARSE_RESULT_END(); } - -static char* xFormatTimestamp(char* buf, int64_t val, int precision) { +static char* formatTimestamp(char* buf, int64_t val, int precision) { time_t tt; if (precision == TSDB_TIME_PRECISION_MICRO) { tt = (time_t)(val / 1000000); @@ -1447,7 +1523,9 @@ static char* xFormatTimestamp(char* buf, int64_t val, int precision) { return buf; } -static void xDumpFieldToFile(FILE* fp, const char* val, TAOS_FIELD* field, int32_t length, int precision) { +static void xDumpFieldToFile(FILE* fp, const char* val, + TAOS_FIELD* field, int32_t length, int precision) { + if (val == NULL) { fprintf(fp, "%s", TSDB_DATA_NULL_STR); return; @@ -1483,7 +1561,7 @@ static void xDumpFieldToFile(FILE* fp, const char* val, TAOS_FIELD* field, int32 fprintf(fp, "\'%s\'", buf); break; case TSDB_DATA_TYPE_TIMESTAMP: - xFormatTimestamp(buf, *(int64_t*)val, precision); + formatTimestamp(buf, *(int64_t*)val, precision); fprintf(fp, "'%s'", buf); break; default: @@ -1514,7 +1592,7 @@ static int xDumpResultToFile(const char* fname, TAOS_RES* tres) { fprintf(fp, "%s", fields[col].name); } fputc('\n', fp); - + int numOfRows = 0; do { int32_t* length = taos_fetch_lengths(tres); @@ -1535,14 +1613,14 @@ static int xDumpResultToFile(const char* fname, TAOS_RES* tres) { return numOfRows; } -static int getDbFromServer(TAOS * taos, SDbInfo** dbInfos) { - TAOS_RES * res; +static int getDbFromServer(TAOS * taos, SDbInfo** dbInfos) { + TAOS_RES * res; TAOS_ROW row = NULL; int count = 0; - - res = taos_query(taos, "show databases;"); + + res = taos_query(taos, "show databases;"); int32_t code = taos_errno(res); - + if (code != 0) { errorPrint( "failed to run , reason: %s\n", taos_errstr(res)); return -1; @@ -1562,17 +1640,17 @@ static int getDbFromServer(TAOS * taos, SDbInfo** dbInfos) { tstrncpy(dbInfos[count]->name, (char *)row[TSDB_SHOW_DB_NAME_INDEX], fields[TSDB_SHOW_DB_NAME_INDEX].bytes); - xFormatTimestamp(dbInfos[count]->create_time, + formatTimestamp(dbInfos[count]->create_time, *(int64_t*)row[TSDB_SHOW_DB_CREATED_TIME_INDEX], TSDB_TIME_PRECISION_MILLI); dbInfos[count]->ntables = *((int32_t *)row[TSDB_SHOW_DB_NTABLES_INDEX]); - dbInfos[count]->vgroups = *((int32_t *)row[TSDB_SHOW_DB_VGROUPS_INDEX]); + dbInfos[count]->vgroups = *((int32_t *)row[TSDB_SHOW_DB_VGROUPS_INDEX]); dbInfos[count]->replica = *((int16_t *)row[TSDB_SHOW_DB_REPLICA_INDEX]); dbInfos[count]->quorum = *((int16_t *)row[TSDB_SHOW_DB_QUORUM_INDEX]); - dbInfos[count]->days = *((int16_t *)row[TSDB_SHOW_DB_DAYS_INDEX]); + dbInfos[count]->days = *((int16_t *)row[TSDB_SHOW_DB_DAYS_INDEX]); tstrncpy(dbInfos[count]->keeplist, (char *)row[TSDB_SHOW_DB_KEEP_INDEX], - fields[TSDB_SHOW_DB_KEEP_INDEX].bytes); + fields[TSDB_SHOW_DB_KEEP_INDEX].bytes); dbInfos[count]->cache = *((int32_t *)row[TSDB_SHOW_DB_CACHE_INDEX]); dbInfos[count]->blocks = *((int32_t *)row[TSDB_SHOW_DB_BLOCKS_INDEX]); dbInfos[count]->minrows = *((int32_t *)row[TSDB_SHOW_DB_MINROWS_INDEX]); @@ -1582,16 +1660,16 @@ static int getDbFromServer(TAOS * taos, SDbInfo** dbInfos) { dbInfos[count]->comp = (int8_t)(*((int8_t *)row[TSDB_SHOW_DB_COMP_INDEX])); dbInfos[count]->cachelast = (int8_t)(*((int8_t *)row[TSDB_SHOW_DB_CACHELAST_INDEX])); - tstrncpy(dbInfos[count]->precision, + tstrncpy(dbInfos[count]->precision, (char *)row[TSDB_SHOW_DB_PRECISION_INDEX], - fields[TSDB_SHOW_DB_PRECISION_INDEX].bytes); + fields[TSDB_SHOW_DB_PRECISION_INDEX].bytes); dbInfos[count]->update = *((int8_t *)row[TSDB_SHOW_DB_UPDATE_INDEX]); tstrncpy(dbInfos[count]->status, (char *)row[TSDB_SHOW_DB_STATUS_INDEX], - fields[TSDB_SHOW_DB_STATUS_INDEX].bytes); + fields[TSDB_SHOW_DB_STATUS_INDEX].bytes); count++; if (count > MAX_DATABASE_COUNT) { - errorPrint( "The database count overflow than %d\n", MAX_DATABASE_COUNT); + errorPrint( "The database count overflow than %d\n", MAX_DATABASE_COUNT); break; } } @@ -1613,11 +1691,11 @@ static void printfDbInfoForQueryToFile(char* filename, SDbInfo* dbInfos, int ind fprintf(fp, "name: %s\n", dbInfos->name); fprintf(fp, "created_time: %s\n", dbInfos->create_time); fprintf(fp, "ntables: %d\n", dbInfos->ntables); - fprintf(fp, "vgroups: %d\n", dbInfos->vgroups); + fprintf(fp, "vgroups: %d\n", dbInfos->vgroups); fprintf(fp, "replica: %d\n", dbInfos->replica); fprintf(fp, "quorum: %d\n", dbInfos->quorum); - fprintf(fp, "days: %d\n", dbInfos->days); - fprintf(fp, "keep0,keep1,keep(D): %s\n", dbInfos->keeplist); + fprintf(fp, "days: %d\n", dbInfos->days); + fprintf(fp, "keep0,keep1,keep(D): %s\n", dbInfos->keeplist); fprintf(fp, "cache(MB): %d\n", dbInfos->cache); fprintf(fp, "blocks: %d\n", dbInfos->blocks); fprintf(fp, "minrows: %d\n", dbInfos->minrows); @@ -1625,10 +1703,10 @@ static void printfDbInfoForQueryToFile(char* filename, SDbInfo* dbInfos, int ind fprintf(fp, "wallevel: %d\n", dbInfos->wallevel); fprintf(fp, "fsync: %d\n", dbInfos->fsync); fprintf(fp, "comp: %d\n", dbInfos->comp); - fprintf(fp, "cachelast: %d\n", dbInfos->cachelast); - fprintf(fp, "precision: %s\n", dbInfos->precision); + fprintf(fp, "cachelast: %d\n", dbInfos->cachelast); + fprintf(fp, "precision: %s\n", dbInfos->precision); fprintf(fp, "update: %d\n", dbInfos->update); - fprintf(fp, "status: %s\n", dbInfos->status); + fprintf(fp, "status: %s\n", dbInfos->status); fprintf(fp, "\n"); fclose(fp); @@ -1678,7 +1756,7 @@ static void printfQuerySystemInfo(TAOS * taos) { snprintf(buffer, MAX_QUERY_SQL_LENGTH, "show %s.vgroups;", dbInfos[i]->name); res = taos_query(taos, buffer); xDumpResultToFile(filename, res); - + // show db.stables snprintf(buffer, MAX_QUERY_SQL_LENGTH, "show %s.stables;", dbInfos[i]->name); res = taos_query(taos, buffer); @@ -1688,7 +1766,6 @@ static void printfQuerySystemInfo(TAOS * taos) { } free(dbInfos); - } static int postProceSql(char* host, uint16_t port, char* sqlstr) @@ -1940,17 +2017,17 @@ static char* generateTagVaulesForStb(SSuperTable* stbInfo) { } dataLen -= 2; - dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, ")"); + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, ")"); return dataBuf; } -static int calcRowLen(SSuperTable* superTbls) { +static int calcRowLen(SSuperTable* superTbls) { int colIndex; int lenOfOneRow = 0; - + for (colIndex = 0; colIndex < superTbls->columnCount; colIndex++) { char* dataType = superTbls->columns[colIndex].dataType; - + if (strcasecmp(dataType, "BINARY") == 0) { lenOfOneRow += superTbls->columns[colIndex].dataLen + 3; } else if (strcasecmp(dataType, "NCHAR") == 0) { @@ -1967,9 +2044,9 @@ static int calcRowLen(SSuperTable* superTbls) { lenOfOneRow += 6; } else if (strcasecmp(dataType, "FLOAT") == 0) { lenOfOneRow += 22; - } else if (strcasecmp(dataType, "DOUBLE") == 0) { + } else if (strcasecmp(dataType, "DOUBLE") == 0) { lenOfOneRow += 42; - } else if (strcasecmp(dataType, "TIMESTAMP") == 0) { + } else if (strcasecmp(dataType, "TIMESTAMP") == 0) { lenOfOneRow += 21; } else { printf("get error data type : %s\n", dataType); @@ -2009,7 +2086,7 @@ static int calcRowLen(SSuperTable* superTbls) { } superTbls->lenOfTagOfOneRow = lenOfTagOfOneRow; - + return 0; } @@ -2021,7 +2098,7 @@ static int getChildNameOfSuperTableWithLimitAndOffset(TAOS * taos, char command[BUFFER_SIZE] = "\0"; char limitBuf[100] = "\0"; - TAOS_RES * res; + TAOS_RES * res; TAOS_ROW row = NULL; char* childTblName = *childTblNameOfSuperTbl; @@ -2030,21 +2107,31 @@ static int getChildNameOfSuperTableWithLimitAndOffset(TAOS * taos, snprintf(limitBuf, 100, " limit %d offset %d", limit, offset); } - //get all child table name use cmd: select tbname from superTblName; + //get all child table name use cmd: select tbname from superTblName; snprintf(command, BUFFER_SIZE, "select tbname from %s.%s %s", dbName, sTblName, limitBuf); - res = taos_query(taos, command); + res = taos_query(taos, command); int32_t code = taos_errno(res); if (code != 0) { - printf("failed to run command %s\n", command); taos_free_result(res); taos_close(taos); + errorPrint("%s() LN%d, failed to run command %s\n", + __func__, __LINE__, command); exit(-1); } int childTblCount = (limit < 0)?10000:limit; int count = 0; -// childTblName = (char*)calloc(1, childTblCount * TSDB_TABLE_NAME_LEN); + if (childTblName == NULL) { + childTblName = (char*)calloc(1, childTblCount * TSDB_TABLE_NAME_LEN); + if (NULL == childTblName) { + taos_free_result(res); + taos_close(taos); + errorPrint("%s() LN%d, failed to allocate memory!\n", __func__, __LINE__); + exit(-1); + } + } + char* pTblName = childTblName; while ((row = taos_fetch_row(res)) != NULL) { int32_t* len = taos_fetch_lengths(res); @@ -2090,8 +2177,9 @@ static int getAllChildNameOfSuperTable(TAOS * taos, char* dbName, static int getSuperTableFromServer(TAOS * taos, char* dbName, SSuperTable* superTbls) { + char command[BUFFER_SIZE] = "\0"; - TAOS_RES * res; + TAOS_RES * res; TAOS_ROW row = NULL; int count = 0; @@ -2295,7 +2383,7 @@ static int createSuperTable(TAOS * taos, char* dbName, SSuperTable* superTbls, dbName, superTbls->sTblName, cols, tags); verbosePrint("%s() LN%d: %s\n", __func__, __LINE__, command); - if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE, false)) { errorPrint( "create supertable %s failed!\n\n", superTbls->sTblName); return -1; @@ -2315,18 +2403,18 @@ static int createDatabases() { } char command[BUFFER_SIZE] = "\0"; - for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int i = 0; i < g_Dbs.dbCount; i++) { if (g_Dbs.db[i].drop) { sprintf(command, "drop database if exists %s;", g_Dbs.db[i].dbName); verbosePrint("%s() %d command: %s\n", __func__, __LINE__, command); - if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE, false)) { taos_close(taos); return -1; } } int dataLen = 0; - dataLen += snprintf(command + dataLen, + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "create database if not exists %s", g_Dbs.db[i].dbName); if (g_Dbs.db[i].dbCfg.blocks > 0) { @@ -2393,7 +2481,7 @@ static int createDatabases() { } debugPrint("%s() %d command: %s\n", __func__, __LINE__, command); - if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE, false)) { taos_close(taos); errorPrint( "\ncreate database %s failed!\n\n", g_Dbs.db[i].dbName); return -1; @@ -2403,38 +2491,41 @@ static int createDatabases() { debugPrint("%s() %d supertbl count:%d\n", __func__, __LINE__, g_Dbs.db[i].superTblCount); for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { - // describe super table, if exists sprintf(command, "describe %s.%s;", g_Dbs.db[i].dbName, g_Dbs.db[i].superTbls[j].sTblName); verbosePrint("%s() %d command: %s\n", __func__, __LINE__, command); - if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { - g_Dbs.db[i].superTbls[j].superTblExists = TBL_NO_EXISTS; + + ret = queryDbExec(taos, command, NO_INSERT_TYPE, true); + + if ((ret != 0) || (g_Dbs.db[i].drop)) { ret = createSuperTable(taos, g_Dbs.db[i].dbName, &g_Dbs.db[i].superTbls[j], g_Dbs.use_metric); - } else { - g_Dbs.db[i].superTbls[j].superTblExists = TBL_ALREADY_EXISTS; - if (g_Dbs.db[i].superTbls[j].childTblExists != TBL_ALREADY_EXISTS) { - ret = getSuperTableFromServer(taos, g_Dbs.db[i].dbName, - &g_Dbs.db[i].superTbls[j]); + if (0 != ret) { + errorPrint("\ncreate super table %d failed!\n\n", j); + taos_close(taos); + return -1; } } + ret = getSuperTableFromServer(taos, g_Dbs.db[i].dbName, + &g_Dbs.db[i].superTbls[j]); if (0 != ret) { - printf("\ncreate super table %d failed!\n\n", j); + errorPrint("\nget super table %s.%s info failed!\n\n", + g_Dbs.db[i].dbName, g_Dbs.db[i].superTbls[j].sTblName); taos_close(taos); return -1; } - } + } } taos_close(taos); return 0; } -static void* createTable(void *sarg) -{ - threadInfo *winfo = (threadInfo *)sarg; +static void* createTable(void *sarg) +{ + threadInfo *winfo = (threadInfo *)sarg; SSuperTable* superTblInfo = winfo->superTblInfo; int64_t lastPrintTime = taosGetTimestampMs(); @@ -2454,57 +2545,64 @@ static void* createTable(void *sarg) int len = 0; int batchNum = 0; - verbosePrint("%s() LN%d: Creating table from %d to %d\n", + verbosePrint("%s() LN%d: Creating table from %d to %d\n", __func__, __LINE__, winfo->start_table_from, winfo->end_table_to); for (int i = winfo->start_table_from; i <= winfo->end_table_to; i++) { if (0 == g_Dbs.use_metric) { - snprintf(buffer, buff_len, + snprintf(buffer, buff_len, "create table if not exists %s.%s%d %s;", winfo->db_name, g_args.tb_prefix, i, winfo->cols); } else { - if (0 == len) { - batchNum = 0; - memset(buffer, 0, buff_len); - len += snprintf(buffer + len, - buff_len - len, "create table "); - } - - char* tagsValBuf = NULL; - if (0 == superTblInfo->tagSource) { - tagsValBuf = generateTagVaulesForStb(superTblInfo); - } else { - tagsValBuf = getTagValueFromTagSample( - superTblInfo, - i % superTblInfo->tagSampleCount); - } - if (NULL == tagsValBuf) { + if (superTblInfo == NULL) { + errorPrint("%s() LN%d, use metric, but super table info is NULL\n", + __func__, __LINE__); free(buffer); - return NULL; - } - - len += snprintf(buffer + len, - superTblInfo->maxSqlLen - len, - "if not exists %s.%s%d using %s.%s tags %s ", - winfo->db_name, superTblInfo->childTblPrefix, - i, winfo->db_name, - superTblInfo->sTblName, tagsValBuf); - free(tagsValBuf); - batchNum++; - - if ((batchNum < superTblInfo->batchCreateTableNum) - && ((superTblInfo->maxSqlLen - len) - >= (superTblInfo->lenOfTagOfOneRow + 256))) { - continue; + exit(-1); + } else { + if (0 == len) { + batchNum = 0; + memset(buffer, 0, buff_len); + len += snprintf(buffer + len, + buff_len - len, "create table "); + } + + char* tagsValBuf = NULL; + if (0 == superTblInfo->tagSource) { + tagsValBuf = generateTagVaulesForStb(superTblInfo); + } else { + tagsValBuf = getTagValueFromTagSample( + superTblInfo, + i % superTblInfo->tagSampleCount); + } + if (NULL == tagsValBuf) { + free(buffer); + return NULL; + } + + len += snprintf(buffer + len, + superTblInfo->maxSqlLen - len, + "if not exists %s.%s%d using %s.%s tags %s ", + winfo->db_name, superTblInfo->childTblPrefix, + i, winfo->db_name, + superTblInfo->sTblName, tagsValBuf); + free(tagsValBuf); + batchNum++; + + if ((batchNum < superTblInfo->batchCreateTableNum) + && ((superTblInfo->maxSqlLen - len) + >= (superTblInfo->lenOfTagOfOneRow + 256))) { + continue; + } } } len = 0; verbosePrint("%s() LN%d %s\n", __func__, __LINE__, buffer); - if (0 != queryDbExec(winfo->taos, buffer, NO_INSERT_TYPE)){ + if (0 != queryDbExec(winfo->taos, buffer, NO_INSERT_TYPE, false)){ errorPrint( "queryDbExec() failed. buffer:\n%s\n", buffer); free(buffer); return NULL; @@ -2520,7 +2618,7 @@ static void* createTable(void *sarg) if (0 != len) { verbosePrint("%s() %d buffer: %s\n", __func__, __LINE__, buffer); - if (0 != queryDbExec(winfo->taos, buffer, NO_INSERT_TYPE)) { + if (0 != queryDbExec(winfo->taos, buffer, NO_INSERT_TYPE, false)) { errorPrint( "queryDbExec() failed. buffer:\n%s\n", buffer); } } @@ -2532,6 +2630,7 @@ static void* createTable(void *sarg) static int startMultiThreadCreateChildTable( char* cols, int threads, int startFrom, int ntables, char* db_name, SSuperTable* superTblInfo) { + pthread_t *pids = malloc(threads * sizeof(pthread_t)); threadInfo *infos = malloc(threads * sizeof(threadInfo)); @@ -2552,7 +2651,7 @@ static int startMultiThreadCreateChildTable( int b = 0; b = ntables % threads; - + for (int i = 0; i < threads; i++) { threadInfo *t_info = infos + i; t_info->threadID = i; @@ -2568,7 +2667,7 @@ static int startMultiThreadCreateChildTable( if (t_info->taos == NULL) { errorPrint( "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); free(pids); - free(infos); + free(infos); return -1; } @@ -2576,12 +2675,12 @@ static int startMultiThreadCreateChildTable( t_info->ntables = iend_table_to = i < b ? startFrom + a : startFrom + a - 1; startFrom = t_info->end_table_to + 1; - t_info->use_metric = 1; + t_info->use_metric = true; t_info->cols = cols; t_info->minDelay = INT16_MAX; pthread_create(pids + i, NULL, createTable, t_info); } - + for (int i = 0; i < threads; i++) { pthread_join(pids[i], NULL); } @@ -2592,12 +2691,11 @@ static int startMultiThreadCreateChildTable( } free(pids); - free(infos); + free(infos); return 0; } - static void createChildTables() { char tblColsBuf[MAX_SQL_SIZE]; int len; @@ -2616,13 +2714,13 @@ static void createChildTables() { int startFrom = 0; g_totalChildTables += g_Dbs.db[i].superTbls[j].childTblCount; - verbosePrint("%s() LN%d: create %d child tables from %d\n", __func__, __LINE__, - g_totalChildTables, startFrom); + verbosePrint("%s() LN%d: create %d child tables from %d\n", + __func__, __LINE__, g_totalChildTables, startFrom); startMultiThreadCreateChildTable( g_Dbs.db[i].superTbls[j].colsOfCreateChildTable, g_Dbs.threadCountByCreateTbl, startFrom, - g_totalChildTables, + g_Dbs.db[i].superTbls[j].childTblCount, g_Dbs.db[i].dbName, &(g_Dbs.db[i].superTbls[j])); } } else { @@ -2633,10 +2731,10 @@ static void createChildTables() { if ((strncasecmp(g_args.datatype[j], "BINARY", strlen("BINARY")) == 0) || (strncasecmp(g_args.datatype[j], "NCHAR", strlen("NCHAR")) == 0)) { - len = snprintf(tblColsBuf + len, MAX_SQL_SIZE, + snprintf(tblColsBuf + len, MAX_SQL_SIZE - len, ", COL%d %s(60)", j, g_args.datatype[j]); } else { - len = snprintf(tblColsBuf + len, MAX_SQL_SIZE, + snprintf(tblColsBuf + len, MAX_SQL_SIZE - len, ", COL%d %s", j, g_args.datatype[j]); } len = strlen(tblColsBuf); @@ -2741,7 +2839,7 @@ static int readSampleFromCsvFileToMem( ssize_t readLen = 0; char * line = NULL; int getRows = 0; - + FILE* fp = fopen(superTblInfo->sampleFile, "r"); if (fp == NULL) { errorPrint( "Failed to open sample file: %s, reason:%s\n", @@ -2763,7 +2861,7 @@ static int readSampleFromCsvFileToMem( } continue; } - + if (('\r' == line[readLen - 1]) || ('\n' == line[readLen - 1])) { line[--readLen] = 0; } @@ -2874,7 +2972,7 @@ static bool getColumnAndTagTypeFromInsertJsonFile( debugPrint("%s() LN%d, failed to read json, tags not found\n", __func__, __LINE__); goto PARSE_OVER; } - + int tagSize = cJSON_GetArraySize(tags); if (tagSize > MAX_TAG_COUNT) { debugPrint("%s() LN%d, failed to read json, tags size overflow, max tag size is %d\n", __func__, __LINE__, MAX_TAG_COUNT); @@ -2943,9 +3041,9 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { cJSON* host = cJSON_GetObjectItem(root, "host"); if (host && host->type == cJSON_String && host->valuestring != NULL) { - tstrncpy(g_Dbs.host, host->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.host, host->valuestring, MAX_HOSTNAME_SIZE); } else if (!host) { - tstrncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.host, "127.0.0.1", MAX_HOSTNAME_SIZE); } else { printf("ERROR: failed to read json, host not found\n"); goto PARSE_OVER; @@ -2960,16 +3058,16 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { cJSON* user = cJSON_GetObjectItem(root, "user"); if (user && user->type == cJSON_String && user->valuestring != NULL) { - tstrncpy(g_Dbs.user, user->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.user, user->valuestring, MAX_USERNAME_SIZE); } else if (!user) { - tstrncpy(g_Dbs.user, "root", MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.user, "root", MAX_USERNAME_SIZE); } cJSON* password = cJSON_GetObjectItem(root, "password"); if (password && password->type == cJSON_String && password->valuestring != NULL) { - tstrncpy(g_Dbs.password, password->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.password, password->valuestring, MAX_PASSWORD_SIZE); } else if (!password) { - tstrncpy(g_Dbs.password, "taosdata", MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.password, "taosdata", MAX_PASSWORD_SIZE); } cJSON* resultfile = cJSON_GetObjectItem(root, "result_file"); @@ -2987,17 +3085,18 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, threads not found\n"); goto PARSE_OVER; - } - + } + cJSON* threads2 = cJSON_GetObjectItem(root, "thread_count_create_tbl"); if (threads2 && threads2->type == cJSON_Number) { g_Dbs.threadCountByCreateTbl = threads2->valueint; } else if (!threads2) { - g_Dbs.threadCountByCreateTbl = 1; + g_Dbs.threadCountByCreateTbl = g_args.num_of_threads; } else { - printf("ERROR: failed to read json, threads2 not found\n"); + errorPrint("%s() LN%d, failed to read json, threads2 not found\n", + __func__, __LINE__); goto PARSE_OVER; - } + } cJSON* gInsertInterval = cJSON_GetObjectItem(root, "insert_interval"); if (gInsertInterval && gInsertInterval->type == cJSON_Number) { @@ -3009,15 +3108,26 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { goto PARSE_OVER; } - cJSON* rowsPerTbl = cJSON_GetObjectItem(root, "rows_per_tbl"); - if (rowsPerTbl && rowsPerTbl->type == cJSON_Number) { - g_args.rows_per_tbl = rowsPerTbl->valueint; - } else if (!rowsPerTbl) { - g_args.rows_per_tbl = 0; // 0 means progressive mode, > 0 mean interlace mode. max value is less or equ num_of_records_per_req + cJSON* interlaceRows = cJSON_GetObjectItem(root, "interlace_rows"); + if (interlaceRows && interlaceRows->type == cJSON_Number) { + g_args.interlace_rows = interlaceRows->valueint; + + // rows per table need be less than insert batch + if (g_args.interlace_rows > g_args.num_of_RPR) { + printf("NOTICE: interlace rows value %d > num_of_records_per_request %d\n\n", + g_args.interlace_rows, g_args.num_of_RPR); + printf(" interlace rows value will be set to num_of_records_per_request %d\n\n", + g_args.num_of_RPR); + printf(" press Enter key to continue or Ctrl+C to stop."); + (void)getchar(); + g_args.interlace_rows = g_args.num_of_RPR; + } + } else if (!interlaceRows) { + g_args.interlace_rows = 0; // 0 means progressive mode, > 0 mean interlace mode. max value is less or equ num_of_records_per_req } else { - errorPrint("%s() LN%d, failed to read json, rows_per_tbl input mistake\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to read json, interlace_rows input mistake\n", __func__, __LINE__); goto PARSE_OVER; - } + } cJSON* maxSqlLen = cJSON_GetObjectItem(root, "max_sql_len"); if (maxSqlLen && maxSqlLen->type == cJSON_Number) { @@ -3028,7 +3138,6 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { errorPrint("%s() LN%d, failed to read json, max_sql_len input mistake\n", __func__, __LINE__); goto PARSE_OVER; } - cJSON* numRecPerReq = cJSON_GetObjectItem(root, "num_of_records_per_req"); if (numRecPerReq && numRecPerReq->type == cJSON_Number) { @@ -3041,7 +3150,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } cJSON *answerPrompt = cJSON_GetObjectItem(root, "confirm_parameter_prompt"); // yes, no, - if (answerPrompt + if (answerPrompt && answerPrompt->type == cJSON_String && answerPrompt->valuestring != NULL) { if (0 == strncasecmp(answerPrompt->valuestring, "yes", 3)) { @@ -3056,7 +3165,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, confirm_parameter_prompt not found\n"); goto PARSE_OVER; - } + } cJSON* dbs = cJSON_GetObjectItem(root, "databases"); if (!dbs || dbs->type != cJSON_Array) { @@ -3083,7 +3192,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { printf("ERROR: failed to read json, dbinfo not found\n"); goto PARSE_OVER; } - + cJSON *dbName = cJSON_GetObjectItem(dbinfo, "name"); if (!dbName || dbName->type != cJSON_String || dbName->valuestring == NULL) { printf("ERROR: failed to read json, db name not found\n"); @@ -3093,15 +3202,16 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { cJSON *drop = cJSON_GetObjectItem(dbinfo, "drop"); if (drop && drop->type == cJSON_String && drop->valuestring != NULL) { - if (0 == strncasecmp(drop->valuestring, "yes", 3)) { - g_Dbs.db[i].drop = 1; + if (0 == strncasecmp(drop->valuestring, "yes", strlen("yes"))) { + g_Dbs.db[i].drop = true; } else { - g_Dbs.db[i].drop = 0; - } + g_Dbs.db[i].drop = false; + } } else if (!drop) { - g_Dbs.db[i].drop = 0; + g_Dbs.db[i].drop = g_args.drop_database; } else { - printf("ERROR: failed to read json, drop not found\n"); + errorPrint("%s() LN%d, failed to read json, drop input mistake\n", + __func__, __LINE__); goto PARSE_OVER; } @@ -3147,7 +3257,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { printf("ERROR: failed to read json, keep not found\n"); goto PARSE_OVER; } - + cJSON* days = cJSON_GetObjectItem(dbinfo, "days"); if (days && days->type == cJSON_Number) { g_Dbs.db[i].dbCfg.days = days->valueint; @@ -3157,7 +3267,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { printf("ERROR: failed to read json, days not found\n"); goto PARSE_OVER; } - + cJSON* cache = cJSON_GetObjectItem(dbinfo, "cache"); if (cache && cache->type == cJSON_Number) { g_Dbs.db[i].dbCfg.cache = cache->valueint; @@ -3167,7 +3277,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { printf("ERROR: failed to read json, cache not found\n"); goto PARSE_OVER; } - + cJSON* blocks= cJSON_GetObjectItem(dbinfo, "blocks"); if (blocks && blocks->type == cJSON_Number) { g_Dbs.db[i].dbCfg.blocks = blocks->valueint; @@ -3256,15 +3366,15 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, fsync not found\n"); goto PARSE_OVER; - } + } - // super_talbes + // super_talbes cJSON *stables = cJSON_GetObjectItem(dbinfos, "super_tables"); if (!stables || stables->type != cJSON_Array) { printf("ERROR: failed to read json, super_tables not found\n"); goto PARSE_OVER; - } - + } + int stbSize = cJSON_GetArraySize(stables); if (stbSize > MAX_SUPER_TABLE_COUNT) { errorPrint( @@ -3277,15 +3387,15 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { for (int j = 0; j < stbSize; ++j) { cJSON* stbInfo = cJSON_GetArrayItem(stables, j); if (stbInfo == NULL) continue; - - // dbinfo + + // dbinfo cJSON *stbName = cJSON_GetObjectItem(stbInfo, "name"); if (!stbName || stbName->type != cJSON_String || stbName->valuestring == NULL) { printf("ERROR: failed to read json, stb name not found\n"); goto PARSE_OVER; } tstrncpy(g_Dbs.db[i].superTbls[j].sTblName, stbName->valuestring, MAX_TB_NAME_SIZE); - + cJSON *prefix = cJSON_GetObjectItem(stbInfo, "childtable_prefix"); if (!prefix || prefix->type != cJSON_String || prefix->valuestring == NULL) { printf("ERROR: failed to read json, childtable_prefix not found\n"); @@ -3310,7 +3420,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { printf("ERROR: failed to read json, auto_create_table not found\n"); goto PARSE_OVER; } - + cJSON* batchCreateTbl = cJSON_GetObjectItem(stbInfo, "batch_create_tbl_num"); if (batchCreateTbl && batchCreateTbl->type == cJSON_Number) { g_Dbs.db[i].superTbls[j].batchCreateTableNum = batchCreateTbl->valueint; @@ -3319,7 +3429,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, batch_create_tbl_num not found\n"); goto PARSE_OVER; - } + } cJSON *childTblExists = cJSON_GetObjectItem(stbInfo, "child_table_exists"); // yes, no if (childTblExists @@ -3335,13 +3445,15 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else if (!childTblExists) { g_Dbs.db[i].superTbls[j].childTblExists = TBL_NO_EXISTS; } else { - errorPrint("%s() LN%d, failed to read json, child_table_exists not found\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to read json, child_table_exists not found\n", + __func__, __LINE__); goto PARSE_OVER; } - + cJSON* count = cJSON_GetObjectItem(stbInfo, "childtable_count"); if (!count || count->type != cJSON_Number || 0 >= count->valueint) { - errorPrint("%s() LN%d, failed to read json, childtable_count not found\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to read json, childtable_count not found\n", + __func__, __LINE__); goto PARSE_OVER; } g_Dbs.db[i].superTbls[j].childTblCount = count->valueint; @@ -3425,10 +3537,11 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, sample_buf_size not found\n"); goto PARSE_OVER; - } + } cJSON *sampleFormat = cJSON_GetObjectItem(stbInfo, "sample_format"); - if (sampleFormat && sampleFormat->type == cJSON_String && sampleFormat->valuestring != NULL) { + if (sampleFormat && sampleFormat->type + == cJSON_String && sampleFormat->valuestring != NULL) { tstrncpy(g_Dbs.db[i].superTbls[j].sampleFormat, sampleFormat->valuestring, MAX_DB_NAME_SIZE); } else if (!sampleFormat) { @@ -3436,7 +3549,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, sample_format not found\n"); goto PARSE_OVER; - } + } cJSON *sampleFile = cJSON_GetObjectItem(stbInfo, "sample_file"); if (sampleFile && sampleFile->type == cJSON_String && sampleFile->valuestring != NULL) { @@ -3447,7 +3560,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, sample_file not found\n"); goto PARSE_OVER; - } + } cJSON *tagsFile = cJSON_GetObjectItem(stbInfo, "tags_file"); if (tagsFile && tagsFile->type == cJSON_String && tagsFile->valuestring != NULL) { @@ -3473,14 +3586,14 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { len = TSDB_MAX_ALLOWED_SQL_LEN; } else if (len < TSDB_MAX_SQL_LEN) { len = TSDB_MAX_SQL_LEN; - } + } g_Dbs.db[i].superTbls[j].maxSqlLen = len; } else if (!maxSqlLen) { g_Dbs.db[i].superTbls[j].maxSqlLen = TSDB_MAX_SQL_LEN; } else { printf("ERROR: failed to read json, maxSqlLen not found\n"); goto PARSE_OVER; - } + } cJSON *multiThreadWriteOneTbl = cJSON_GetObjectItem(stbInfo, "multi_thread_write_one_tbl"); // no , yes @@ -3491,7 +3604,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 1; } else { g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 0; - } + } } else if (!multiThreadWriteOneTbl) { g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 0; } else { @@ -3499,15 +3612,27 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { goto PARSE_OVER; } - cJSON* rowsPerTbl = cJSON_GetObjectItem(stbInfo, "rows_per_tbl"); - if (rowsPerTbl && rowsPerTbl->type == cJSON_Number) { - g_Dbs.db[i].superTbls[j].rowsPerTbl = rowsPerTbl->valueint; - } else if (!rowsPerTbl) { - g_Dbs.db[i].superTbls[j].rowsPerTbl = 0; // 0 means progressive mode, > 0 mean interlace mode. max value is less or equ num_of_records_per_req + cJSON* interlaceRows = cJSON_GetObjectItem(stbInfo, "interlace_rows"); + if (interlaceRows && interlaceRows->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].interlaceRows = interlaceRows->valueint; + // rows per table need be less than insert batch + if (g_Dbs.db[i].superTbls[j].interlaceRows > g_args.num_of_RPR) { + printf("NOTICE: db[%d].superTbl[%d]'s interlace rows value %d > num_of_records_per_request %d\n\n", + i, j, g_Dbs.db[i].superTbls[j].interlaceRows, g_args.num_of_RPR); + printf(" interlace rows value will be set to num_of_records_per_request %d\n\n", + g_args.num_of_RPR); + printf(" press Enter key to continue or Ctrl+C to stop."); + (void)getchar(); + g_Dbs.db[i].superTbls[j].interlaceRows = g_args.num_of_RPR; + } + } else if (!interlaceRows) { + g_Dbs.db[i].superTbls[j].interlaceRows = 0; // 0 means progressive mode, > 0 mean interlace mode. max value is less or equ num_of_records_per_req } else { - errorPrint("%s() LN%d, failed to read json, rowsPerTbl input mistake\n", __func__, __LINE__); + errorPrint( + "%s() LN%d, failed to read json, interlace rows input mistake\n", + __func__, __LINE__); goto PARSE_OVER; - } + } cJSON* disorderRatio = cJSON_GetObjectItem(stbInfo, "disorder_ratio"); if (disorderRatio && disorderRatio->type == cJSON_Number) { @@ -3517,7 +3642,7 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, disorderRatio not found\n"); goto PARSE_OVER; - } + } cJSON* disorderRange = cJSON_GetObjectItem(stbInfo, "disorder_range"); if (disorderRange && disorderRange->type == cJSON_Number) { @@ -3535,7 +3660,8 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { } else if (!insertRows) { g_Dbs.db[i].superTbls[j].insertRows = 0x7FFFFFFFFFFFFFFF; } else { - errorPrint("%s() LN%d, failed to read json, insert_rows input mistake\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to read json, insert_rows input mistake\n", + __func__, __LINE__); goto PARSE_OVER; } @@ -3543,26 +3669,21 @@ static bool getMetaFromInsertJsonFile(cJSON* root) { if (insertInterval && insertInterval->type == cJSON_Number) { g_Dbs.db[i].superTbls[j].insertInterval = insertInterval->valueint; } else if (!insertInterval) { - debugPrint("%s() LN%d: stable insert interval be overrided by global %d.\n", + verbosePrint("%s() LN%d: stable insert interval be overrided by global %d.\n", __func__, __LINE__, g_args.insert_interval); g_Dbs.db[i].superTbls[j].insertInterval = g_args.insert_interval; } else { - errorPrint("%s() LN%d, failed to read json, insert_interval input mistake\n", __func__, __LINE__); + errorPrint("%s() LN%d, failed to read json, insert_interval input mistake\n", + __func__, __LINE__); goto PARSE_OVER; } -/* CBD if (NO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable - || (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists)) { - continue; - } - */ - int retVal = getColumnAndTagTypeFromInsertJsonFile( stbInfo, &g_Dbs.db[i].superTbls[j]); if (false == retVal) { goto PARSE_OVER; - } - } + } + } } ret = true; @@ -3584,9 +3705,9 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { cJSON* host = cJSON_GetObjectItem(root, "host"); if (host && host->type == cJSON_String && host->valuestring != NULL) { - tstrncpy(g_queryInfo.host, host->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.host, host->valuestring, MAX_HOSTNAME_SIZE); } else if (!host) { - tstrncpy(g_queryInfo.host, "127.0.0.1", MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.host, "127.0.0.1", MAX_HOSTNAME_SIZE); } else { printf("ERROR: failed to read json, host not found\n"); goto PARSE_OVER; @@ -3601,16 +3722,16 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { cJSON* user = cJSON_GetObjectItem(root, "user"); if (user && user->type == cJSON_String && user->valuestring != NULL) { - tstrncpy(g_queryInfo.user, user->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.user, user->valuestring, MAX_USERNAME_SIZE); } else if (!user) { - tstrncpy(g_queryInfo.user, "root", MAX_DB_NAME_SIZE); ; + tstrncpy(g_queryInfo.user, "root", MAX_USERNAME_SIZE); ; } cJSON* password = cJSON_GetObjectItem(root, "password"); if (password && password->type == cJSON_String && password->valuestring != NULL) { - tstrncpy(g_queryInfo.password, password->valuestring, MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.password, password->valuestring, MAX_PASSWORD_SIZE); } else if (!password) { - tstrncpy(g_queryInfo.password, "taosdata", MAX_DB_NAME_SIZE);; + tstrncpy(g_queryInfo.password, "taosdata", MAX_PASSWORD_SIZE);; } cJSON *answerPrompt = cJSON_GetObjectItem(root, "confirm_parameter_prompt"); // yes, no, @@ -3628,7 +3749,17 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { } else { printf("ERROR: failed to read json, confirm_parameter_prompt not found\n"); goto PARSE_OVER; - } + } + + cJSON* gQueryTimes = cJSON_GetObjectItem(root, "query_times"); + if (gQueryTimes && gQueryTimes->type == cJSON_Number) { + g_args.query_times = gQueryTimes->valueint; + } else if (!gQueryTimes) { + g_args.query_times = 1; + } else { + errorPrint("%s() LN%d, failed to read json, query_times input mistake\n", __func__, __LINE__); + goto PARSE_OVER; + } cJSON* dbs = cJSON_GetObjectItem(root, "databases"); if (dbs && dbs->type == cJSON_String && dbs->valuestring != NULL) { @@ -3647,35 +3778,186 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { printf("ERROR: failed to read json, query_mode not found\n"); goto PARSE_OVER; } - + // super_table_query - cJSON *superQuery = cJSON_GetObjectItem(root, "specified_table_query"); - if (!superQuery) { - g_queryInfo.superQueryInfo.concurrent = 0; - g_queryInfo.superQueryInfo.sqlCount = 0; - } else if (superQuery->type != cJSON_Object) { + cJSON *specifiedQuery = cJSON_GetObjectItem(root, "specified_table_query"); + if (!specifiedQuery) { + g_queryInfo.specifiedQueryInfo.concurrent = 0; + g_queryInfo.specifiedQueryInfo.sqlCount = 0; + } else if (specifiedQuery->type != cJSON_Object) { printf("ERROR: failed to read json, super_table_query not found\n"); goto PARSE_OVER; - } else { - cJSON* rate = cJSON_GetObjectItem(superQuery, "query_interval"); + } else { + cJSON* rate = cJSON_GetObjectItem(specifiedQuery, "query_interval"); if (rate && rate->type == cJSON_Number) { - g_queryInfo.superQueryInfo.rate = rate->valueint; + g_queryInfo.specifiedQueryInfo.rate = rate->valueint; } else if (!rate) { + g_queryInfo.specifiedQueryInfo.rate = 0; + } + + cJSON* specifiedQueryTimes = cJSON_GetObjectItem(specifiedQuery, "query_times"); + if (specifiedQueryTimes && specifiedQueryTimes->type == cJSON_Number) { + g_queryInfo.specifiedQueryInfo.queryTimes = specifiedQueryTimes->valueint; + } else if (!specifiedQueryTimes) { + g_queryInfo.specifiedQueryInfo.queryTimes = g_args.query_times; + } else { + errorPrint("%s() LN%d, failed to read json, query_times input mistake\n", __func__, __LINE__); + goto PARSE_OVER; + } + + cJSON* concurrent = cJSON_GetObjectItem(specifiedQuery, "concurrent"); + if (concurrent && concurrent->type == cJSON_Number) { + g_queryInfo.specifiedQueryInfo.concurrent = concurrent->valueint; + } else if (!concurrent) { + g_queryInfo.specifiedQueryInfo.concurrent = 1; + } + + cJSON* mode = cJSON_GetObjectItem(specifiedQuery, "mode"); + if (mode && mode->type == cJSON_String && mode->valuestring != NULL) { + if (0 == strcmp("sync", mode->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeMode = 0; + } else if (0 == strcmp("async", mode->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeMode = 1; + } else { + printf("ERROR: failed to read json, subscribe mod error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.specifiedQueryInfo.subscribeMode = 0; + } + + cJSON* interval = cJSON_GetObjectItem(specifiedQuery, "interval"); + if (interval && interval->type == cJSON_Number) { + g_queryInfo.specifiedQueryInfo.subscribeInterval = interval->valueint; + } else if (!interval) { + //printf("failed to read json, subscribe interval no found\n"); + //goto PARSE_OVER; + g_queryInfo.specifiedQueryInfo.subscribeInterval = 10000; + } + + cJSON* restart = cJSON_GetObjectItem(specifiedQuery, "restart"); + if (restart && restart->type == cJSON_String && restart->valuestring != NULL) { + if (0 == strcmp("yes", restart->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeRestart = 1; + } else if (0 == strcmp("no", restart->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeRestart = 0; + } else { + printf("ERROR: failed to read json, subscribe restart error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.specifiedQueryInfo.subscribeRestart = 1; + } + + cJSON* keepProgress = cJSON_GetObjectItem(specifiedQuery, "keepProgress"); + if (keepProgress + && keepProgress->type == cJSON_String + && keepProgress->valuestring != NULL) { + if (0 == strcmp("yes", keepProgress->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeKeepProgress = 1; + } else if (0 == strcmp("no", keepProgress->valuestring)) { + g_queryInfo.specifiedQueryInfo.subscribeKeepProgress = 0; + } else { + printf("ERROR: failed to read json, subscribe keepProgress error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.specifiedQueryInfo.subscribeKeepProgress = 0; + } + + // sqls + cJSON* superSqls = cJSON_GetObjectItem(specifiedQuery, "sqls"); + if (!superSqls) { + g_queryInfo.specifiedQueryInfo.sqlCount = 0; + } else if (superSqls->type != cJSON_Array) { + printf("ERROR: failed to read json, super sqls not found\n"); + goto PARSE_OVER; + } else { + int superSqlSize = cJSON_GetArraySize(superSqls); + if (superSqlSize > MAX_QUERY_SQL_COUNT) { + printf("ERROR: failed to read json, query sql size overflow, max is %d\n", MAX_QUERY_SQL_COUNT); + goto PARSE_OVER; + } + + g_queryInfo.specifiedQueryInfo.sqlCount = superSqlSize; + for (int j = 0; j < superSqlSize; ++j) { + cJSON* sql = cJSON_GetArrayItem(superSqls, j); + if (sql == NULL) continue; + + cJSON *sqlStr = cJSON_GetObjectItem(sql, "sql"); + if (!sqlStr || sqlStr->type != cJSON_String || sqlStr->valuestring == NULL) { + printf("ERROR: failed to read json, sql not found\n"); + goto PARSE_OVER; + } + tstrncpy(g_queryInfo.specifiedQueryInfo.sql[j], sqlStr->valuestring, MAX_QUERY_SQL_LENGTH); + + cJSON *result = cJSON_GetObjectItem(sql, "result"); + if (NULL != result && result->type == cJSON_String && result->valuestring != NULL) { + tstrncpy(g_queryInfo.specifiedQueryInfo.result[j], result->valuestring, MAX_FILE_NAME_LEN); + } else if (NULL == result) { + memset(g_queryInfo.specifiedQueryInfo.result[j], 0, MAX_FILE_NAME_LEN); + } else { + printf("ERROR: failed to read json, super query result file not found\n"); + goto PARSE_OVER; + } + } + } + } + + // sub_table_query + cJSON *superQuery = cJSON_GetObjectItem(root, "super_table_query"); + if (!superQuery) { + g_queryInfo.superQueryInfo.threadCnt = 0; + g_queryInfo.superQueryInfo.sqlCount = 0; + } else if (superQuery->type != cJSON_Object) { + printf("ERROR: failed to read json, sub_table_query not found\n"); + ret = true; + goto PARSE_OVER; + } else { + cJSON* subrate = cJSON_GetObjectItem(superQuery, "query_interval"); + if (subrate && subrate->type == cJSON_Number) { + g_queryInfo.superQueryInfo.rate = subrate->valueint; + } else if (!subrate) { g_queryInfo.superQueryInfo.rate = 0; } - - cJSON* concurrent = cJSON_GetObjectItem(superQuery, "concurrent"); - if (concurrent && concurrent->type == cJSON_Number) { - g_queryInfo.superQueryInfo.concurrent = concurrent->valueint; - } else if (!concurrent) { - g_queryInfo.superQueryInfo.concurrent = 1; + + cJSON* superQueryTimes = cJSON_GetObjectItem(superQuery, "query_times"); + if (superQueryTimes && superQueryTimes->type == cJSON_Number) { + g_queryInfo.superQueryInfo.queryTimes = superQueryTimes->valueint; + } else if (!superQueryTimes) { + g_queryInfo.superQueryInfo.queryTimes = g_args.query_times; + } else { + errorPrint("%s() LN%d, failed to read json, query_times input mistake\n", __func__, __LINE__); + goto PARSE_OVER; } - - cJSON* mode = cJSON_GetObjectItem(superQuery, "mode"); - if (mode && mode->type == cJSON_String && mode->valuestring != NULL) { - if (0 == strcmp("sync", mode->valuestring)) { + + cJSON* threads = cJSON_GetObjectItem(superQuery, "threads"); + if (threads && threads->type == cJSON_Number) { + g_queryInfo.superQueryInfo.threadCnt = threads->valueint; + } else if (!threads) { + g_queryInfo.superQueryInfo.threadCnt = 1; + } + + //cJSON* subTblCnt = cJSON_GetObjectItem(superQuery, "childtable_count"); + //if (subTblCnt && subTblCnt->type == cJSON_Number) { + // g_queryInfo.superQueryInfo.childTblCount = subTblCnt->valueint; + //} else if (!subTblCnt) { + // g_queryInfo.superQueryInfo.childTblCount = 0; + //} + + cJSON* stblname = cJSON_GetObjectItem(superQuery, "stblname"); + if (stblname && stblname->type == cJSON_String && stblname->valuestring != NULL) { + tstrncpy(g_queryInfo.superQueryInfo.sTblName, stblname->valuestring, MAX_TB_NAME_SIZE); + } else { + printf("ERROR: failed to read json, super table name not found\n"); + goto PARSE_OVER; + } + + cJSON* submode = cJSON_GetObjectItem(superQuery, "mode"); + if (submode && submode->type == cJSON_String && submode->valuestring != NULL) { + if (0 == strcmp("sync", submode->valuestring)) { g_queryInfo.superQueryInfo.subscribeMode = 0; - } else if (0 == strcmp("async", mode->valuestring)) { + } else if (0 == strcmp("async", submode->valuestring)) { g_queryInfo.superQueryInfo.subscribeMode = 1; } else { printf("ERROR: failed to read json, subscribe mod error\n"); @@ -3684,21 +3966,21 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { } else { g_queryInfo.superQueryInfo.subscribeMode = 0; } - - cJSON* interval = cJSON_GetObjectItem(superQuery, "interval"); - if (interval && interval->type == cJSON_Number) { - g_queryInfo.superQueryInfo.subscribeInterval = interval->valueint; - } else if (!interval) { + + cJSON* subinterval = cJSON_GetObjectItem(superQuery, "interval"); + if (subinterval && subinterval->type == cJSON_Number) { + g_queryInfo.superQueryInfo.subscribeInterval = subinterval->valueint; + } else if (!subinterval) { //printf("failed to read json, subscribe interval no found\n"); //goto PARSE_OVER; g_queryInfo.superQueryInfo.subscribeInterval = 10000; } - - cJSON* restart = cJSON_GetObjectItem(superQuery, "restart"); - if (restart && restart->type == cJSON_String && restart->valuestring != NULL) { - if (0 == strcmp("yes", restart->valuestring)) { + + cJSON* subrestart = cJSON_GetObjectItem(superQuery, "restart"); + if (subrestart && subrestart->type == cJSON_String && subrestart->valuestring != NULL) { + if (0 == strcmp("yes", subrestart->valuestring)) { g_queryInfo.superQueryInfo.subscribeRestart = 1; - } else if (0 == strcmp("no", restart->valuestring)) { + } else if (0 == strcmp("no", subrestart->valuestring)) { g_queryInfo.superQueryInfo.subscribeRestart = 0; } else { printf("ERROR: failed to read json, subscribe restart error\n"); @@ -3707,14 +3989,14 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { } else { g_queryInfo.superQueryInfo.subscribeRestart = 1; } - - cJSON* keepProgress = cJSON_GetObjectItem(superQuery, "keepProgress"); - if (keepProgress - && keepProgress->type == cJSON_String - && keepProgress->valuestring != NULL) { - if (0 == strcmp("yes", keepProgress->valuestring)) { + + cJSON* subkeepProgress = cJSON_GetObjectItem(superQuery, "keepProgress"); + if (subkeepProgress && + subkeepProgress->type == cJSON_String + && subkeepProgress->valuestring != NULL) { + if (0 == strcmp("yes", subkeepProgress->valuestring)) { g_queryInfo.superQueryInfo.subscribeKeepProgress = 1; - } else if (0 == strcmp("no", keepProgress->valuestring)) { + } else if (0 == strcmp("no", subkeepProgress->valuestring)) { g_queryInfo.superQueryInfo.subscribeKeepProgress = 0; } else { printf("ERROR: failed to read json, subscribe keepProgress error\n"); @@ -3724,15 +4006,15 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { g_queryInfo.superQueryInfo.subscribeKeepProgress = 0; } - // sqls - cJSON* superSqls = cJSON_GetObjectItem(superQuery, "sqls"); - if (!superSqls) { + // sqls + cJSON* subsqls = cJSON_GetObjectItem(superQuery, "sqls"); + if (!subsqls) { g_queryInfo.superQueryInfo.sqlCount = 0; - } else if (superSqls->type != cJSON_Array) { + } else if (subsqls->type != cJSON_Array) { printf("ERROR: failed to read json, super sqls not found\n"); goto PARSE_OVER; - } else { - int superSqlSize = cJSON_GetArraySize(superSqls); + } else { + int superSqlSize = cJSON_GetArraySize(subsqls); if (superSqlSize > MAX_QUERY_SQL_COUNT) { printf("ERROR: failed to read json, query sql size overflow, max is %d\n", MAX_QUERY_SQL_COUNT); goto PARSE_OVER; @@ -3740,9 +4022,9 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { g_queryInfo.superQueryInfo.sqlCount = superSqlSize; for (int j = 0; j < superSqlSize; ++j) { - cJSON* sql = cJSON_GetArrayItem(superSqls, j); + cJSON* sql = cJSON_GetArrayItem(subsqls, j); if (sql == NULL) continue; - + cJSON *sqlStr = cJSON_GetObjectItem(sql, "sql"); if (!sqlStr || sqlStr->type != cJSON_String || sqlStr->valuestring == NULL) { printf("ERROR: failed to read json, sql not found\n"); @@ -3751,145 +4033,14 @@ static bool getMetaFromQueryJsonFile(cJSON* root) { tstrncpy(g_queryInfo.superQueryInfo.sql[j], sqlStr->valuestring, MAX_QUERY_SQL_LENGTH); cJSON *result = cJSON_GetObjectItem(sql, "result"); - if (NULL != result && result->type == cJSON_String && result->valuestring != NULL) { + if (result != NULL && result->type == cJSON_String && result->valuestring != NULL){ tstrncpy(g_queryInfo.superQueryInfo.result[j], result->valuestring, MAX_FILE_NAME_LEN); } else if (NULL == result) { memset(g_queryInfo.superQueryInfo.result[j], 0, MAX_FILE_NAME_LEN); - } else { - printf("ERROR: failed to read json, super query result file not found\n"); - goto PARSE_OVER; - } - } - } - } - - // sub_table_query - cJSON *subQuery = cJSON_GetObjectItem(root, "super_table_query"); - if (!subQuery) { - g_queryInfo.subQueryInfo.threadCnt = 0; - g_queryInfo.subQueryInfo.sqlCount = 0; - } else if (subQuery->type != cJSON_Object) { - printf("ERROR: failed to read json, sub_table_query not found\n"); - ret = true; - goto PARSE_OVER; - } else { - cJSON* subrate = cJSON_GetObjectItem(subQuery, "query_interval"); - if (subrate && subrate->type == cJSON_Number) { - g_queryInfo.subQueryInfo.rate = subrate->valueint; - } else if (!subrate) { - g_queryInfo.subQueryInfo.rate = 0; - } - - cJSON* threads = cJSON_GetObjectItem(subQuery, "threads"); - if (threads && threads->type == cJSON_Number) { - g_queryInfo.subQueryInfo.threadCnt = threads->valueint; - } else if (!threads) { - g_queryInfo.subQueryInfo.threadCnt = 1; - } - - //cJSON* subTblCnt = cJSON_GetObjectItem(subQuery, "childtable_count"); - //if (subTblCnt && subTblCnt->type == cJSON_Number) { - // g_queryInfo.subQueryInfo.childTblCount = subTblCnt->valueint; - //} else if (!subTblCnt) { - // g_queryInfo.subQueryInfo.childTblCount = 0; - //} - - cJSON* stblname = cJSON_GetObjectItem(subQuery, "stblname"); - if (stblname && stblname->type == cJSON_String && stblname->valuestring != NULL) { - tstrncpy(g_queryInfo.subQueryInfo.sTblName, stblname->valuestring, MAX_TB_NAME_SIZE); - } else { - printf("ERROR: failed to read json, super table name not found\n"); - goto PARSE_OVER; - } - - cJSON* submode = cJSON_GetObjectItem(subQuery, "mode"); - if (submode && submode->type == cJSON_String && submode->valuestring != NULL) { - if (0 == strcmp("sync", submode->valuestring)) { - g_queryInfo.subQueryInfo.subscribeMode = 0; - } else if (0 == strcmp("async", submode->valuestring)) { - g_queryInfo.subQueryInfo.subscribeMode = 1; - } else { - printf("ERROR: failed to read json, subscribe mod error\n"); - goto PARSE_OVER; - } - } else { - g_queryInfo.subQueryInfo.subscribeMode = 0; - } - - cJSON* subinterval = cJSON_GetObjectItem(subQuery, "interval"); - if (subinterval && subinterval->type == cJSON_Number) { - g_queryInfo.subQueryInfo.subscribeInterval = subinterval->valueint; - } else if (!subinterval) { - //printf("failed to read json, subscribe interval no found\n"); - //goto PARSE_OVER; - g_queryInfo.subQueryInfo.subscribeInterval = 10000; - } - - cJSON* subrestart = cJSON_GetObjectItem(subQuery, "restart"); - if (subrestart && subrestart->type == cJSON_String && subrestart->valuestring != NULL) { - if (0 == strcmp("yes", subrestart->valuestring)) { - g_queryInfo.subQueryInfo.subscribeRestart = 1; - } else if (0 == strcmp("no", subrestart->valuestring)) { - g_queryInfo.subQueryInfo.subscribeRestart = 0; - } else { - printf("ERROR: failed to read json, subscribe restart error\n"); - goto PARSE_OVER; - } - } else { - g_queryInfo.subQueryInfo.subscribeRestart = 1; - } - - cJSON* subkeepProgress = cJSON_GetObjectItem(subQuery, "keepProgress"); - if (subkeepProgress && - subkeepProgress->type == cJSON_String - && subkeepProgress->valuestring != NULL) { - if (0 == strcmp("yes", subkeepProgress->valuestring)) { - g_queryInfo.subQueryInfo.subscribeKeepProgress = 1; - } else if (0 == strcmp("no", subkeepProgress->valuestring)) { - g_queryInfo.subQueryInfo.subscribeKeepProgress = 0; - } else { - printf("ERROR: failed to read json, subscribe keepProgress error\n"); - goto PARSE_OVER; - } - } else { - g_queryInfo.subQueryInfo.subscribeKeepProgress = 0; - } - - // sqls - cJSON* subsqls = cJSON_GetObjectItem(subQuery, "sqls"); - if (!subsqls) { - g_queryInfo.subQueryInfo.sqlCount = 0; - } else if (subsqls->type != cJSON_Array) { - printf("ERROR: failed to read json, super sqls not found\n"); - goto PARSE_OVER; - } else { - int superSqlSize = cJSON_GetArraySize(subsqls); - if (superSqlSize > MAX_QUERY_SQL_COUNT) { - printf("ERROR: failed to read json, query sql size overflow, max is %d\n", MAX_QUERY_SQL_COUNT); - goto PARSE_OVER; - } - - g_queryInfo.subQueryInfo.sqlCount = superSqlSize; - for (int j = 0; j < superSqlSize; ++j) { - cJSON* sql = cJSON_GetArrayItem(subsqls, j); - if (sql == NULL) continue; - - cJSON *sqlStr = cJSON_GetObjectItem(sql, "sql"); - if (!sqlStr || sqlStr->type != cJSON_String || sqlStr->valuestring == NULL) { - printf("ERROR: failed to read json, sql not found\n"); - goto PARSE_OVER; - } - tstrncpy(g_queryInfo.subQueryInfo.sql[j], sqlStr->valuestring, MAX_QUERY_SQL_LENGTH); - - cJSON *result = cJSON_GetObjectItem(sql, "result"); - if (result != NULL && result->type == cJSON_String && result->valuestring != NULL){ - tstrncpy(g_queryInfo.subQueryInfo.result[j], result->valuestring, MAX_FILE_NAME_LEN); - } else if (NULL == result) { - memset(g_queryInfo.subQueryInfo.result[j], 0, MAX_FILE_NAME_LEN); } else { printf("ERROR: failed to read json, sub query result file not found\n"); goto PARSE_OVER; - } + } } } } @@ -3951,14 +4102,14 @@ static bool getInfoFromJsonFile(char* file) { if (INSERT_TEST == g_args.test_mode) { ret = getMetaFromInsertJsonFile(root); - } else if (QUERY_TEST == g_args.test_mode) { - ret = getMetaFromQueryJsonFile(root); - } else if (SUBSCRIBE_TEST == g_args.test_mode) { + } else if ((QUERY_TEST == g_args.test_mode) + || (SUBSCRIBE_TEST == g_args.test_mode)) { ret = getMetaFromQueryJsonFile(root); } else { - errorPrint("%s() LN%d, input json file type error! please input correct file type: insert or query or subscribe\n", __func__, __LINE__); + errorPrint("%s() LN%d, input json file type error! please input correct file type: insert or query or subscribe\n", + __func__, __LINE__); goto PARSE_OVER; - } + } PARSE_OVER: free(content); @@ -3968,7 +4119,7 @@ PARSE_OVER: } static void prepareSampleData() { - for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int i = 0; i < g_Dbs.dbCount; i++) { for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { if (g_Dbs.db[i].superTbls[j].tagsFile[0] != 0) { (void)readTagFromCsvFileToMem(&g_Dbs.db[i].superTbls[j]); @@ -3979,7 +4130,7 @@ static void prepareSampleData() { static void postFreeResource() { tmfclose(g_fpOfInsertResult); - for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int i = 0; i < g_Dbs.dbCount; i++) { for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { if (0 != g_Dbs.db[i].superTbls[j].colsOfCreateChildTable) { free(g_Dbs.db[i].superTbls[j].colsOfCreateChildTable); @@ -4030,7 +4181,7 @@ static int getRowDataFromSample(char* dataBuf, int maxLen, int64_t timestamp, static int generateRowData(char* dataBuf, int maxLen, int64_t timestamp, SSuperTable* stbInfo) { int dataLen = 0; dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "(%" PRId64 ", ", timestamp); - for (int i = 0; i < stbInfo->columnCount; i++) { + for (int i = 0; i < stbInfo->columnCount; i++) { if ((0 == strncasecmp(stbInfo->columns[i].dataType, "binary", 6)) || (0 == strncasecmp(stbInfo->columns[i].dataType, "nchar", 5))) { if (stbInfo->columns[i].dataLen > TSDB_MAX_BINARY_LEN) { @@ -4177,7 +4328,7 @@ static int execInsert(threadInfo *pThreadInfo, char *buffer, int k) __func__, __LINE__, buffer); if (superTblInfo) { if (0 == strncasecmp(superTblInfo->insertMode, "taosc", strlen("taosc"))) { - affectedRows = queryDbExec(pThreadInfo->taos, buffer, INSERT_TYPE); + affectedRows = queryDbExec(pThreadInfo->taos, buffer, INSERT_TYPE, false); } else { if (0 != postProceSql(g_Dbs.host, g_Dbs.port, buffer)) { affectedRows = -1; @@ -4187,7 +4338,7 @@ static int execInsert(threadInfo *pThreadInfo, char *buffer, int k) } } } else { - affectedRows = queryDbExec(pThreadInfo->taos, buffer, 1); + affectedRows = queryDbExec(pThreadInfo->taos, buffer, INSERT_TYPE, false); } return affectedRows; @@ -4212,7 +4363,7 @@ static void getTableName(char *pTblName, threadInfo* pThreadInfo, int tableSeq) } } else { snprintf(pTblName, TSDB_TABLE_NAME_LEN, "%s%d", - superTblInfo?superTblInfo->childTblPrefix:g_args.tb_prefix, tableSeq); + g_args.tb_prefix, tableSeq); } } @@ -4241,28 +4392,28 @@ static int generateDataTail(char *tableName, int32_t tableSeq, if (0 == strncasecmp(superTblInfo->dataSource, "sample", strlen("sample"))) { retLen = getRowDataFromSample( - buffer + len, - superTblInfo->maxSqlLen - len, + buffer + len, + superTblInfo->maxSqlLen - len, startTime + superTblInfo->timeStampStep * k, - superTblInfo, + superTblInfo, pSamplePos); } else if (0 == strncasecmp(superTblInfo->dataSource, "rand", strlen("rand"))) { int rand_num = rand_tinyint() % 100; - if (0 != superTblInfo->disorderRatio + if (0 != superTblInfo->disorderRatio && rand_num < superTblInfo->disorderRatio) { int64_t d = startTime + superTblInfo->timeStampStep * k - taosRandom() % superTblInfo->disorderRange; retLen = generateRowData( - buffer + len, + buffer + len, superTblInfo->maxSqlLen - len, - d, + d, superTblInfo); } else { retLen = generateRowData( - buffer + len, - superTblInfo->maxSqlLen - len, + buffer + len, + superTblInfo->maxSqlLen - len, startTime + superTblInfo->timeStampStep * k, superTblInfo); } @@ -4286,14 +4437,15 @@ static int generateDataTail(char *tableName, int32_t tableSeq, if ((g_args.disorderRatio != 0) && (rand_num < g_args.disorderRange)) { - - int64_t d = startTime - taosRandom() % 1000000 + rand_num; + + int64_t d = startTime + DEFAULT_TIMESTAMP_STEP * k + - taosRandom() % 1000000 + rand_num; len = generateData(data, data_type, ncols_per_record, d, lenOfBinary); } else { len = generateData(data, data_type, ncols_per_record, - startTime + DEFAULT_TIMESTAMP_STEP * startFrom, + startTime + DEFAULT_TIMESTAMP_STEP * k, lenOfBinary); } @@ -4319,7 +4471,8 @@ static int generateDataTail(char *tableName, int32_t tableSeq, return k; } -static int generateSQLHead(char *tableName, int32_t tableSeq, threadInfo* pThreadInfo, SSuperTable* superTblInfo, char *buffer) +static int generateSQLHead(char *tableName, int32_t tableSeq, + threadInfo* pThreadInfo, SSuperTable* superTblInfo, char *buffer) { int len; if (superTblInfo) { @@ -4354,7 +4507,7 @@ static int generateSQLHead(char *tableName, int32_t tableSeq, threadInfo* pThrea tableName); } else { len = snprintf(buffer, - (superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len), + superTblInfo->maxSqlLen, "insert into %s.%s values", pThreadInfo->db_name, tableName); @@ -4370,7 +4523,7 @@ static int generateSQLHead(char *tableName, int32_t tableSeq, threadInfo* pThrea return len; } -static int generateDataBuffer(char *pTblName, +static int generateProgressiveDataBuffer(char *pTblName, int32_t tableSeq, threadInfo *pThreadInfo, char *buffer, int64_t insertRows, @@ -4401,7 +4554,8 @@ static int generateDataBuffer(char *pTblName, int k; int dataLen; k = generateDataTail(pTblName, tableSeq, pThreadInfo, superTblInfo, - g_args.num_of_RPR, pstr, insertRows, startFrom, startTime, + g_args.num_of_RPR, pstr, insertRows, startFrom, + startTime, pSamplePos, &dataLen); return k; } @@ -4411,6 +4565,18 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) { pThreadInfo->threadID, __func__, __LINE__); SSuperTable* superTblInfo = pThreadInfo->superTblInfo; + int interlaceRows = superTblInfo?superTblInfo->interlaceRows:g_args.interlace_rows; + + int insertMode; + + if (interlaceRows > 0) { + insertMode = INTERLACE_INSERT_MODE; + } else { + insertMode = PROGRESSIVE_INSERT_MODE; + } + + // TODO: prompt tbl count multple interlace rows and batch + // char* buffer = calloc(superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len, 1); if (NULL == buffer) { @@ -4419,28 +4585,16 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) { strerror(errno)); return NULL; } - - int insertMode; + + char tableName[TSDB_TABLE_NAME_LEN]; - int rowsPerTbl = superTblInfo?superTblInfo->rowsPerTbl:g_args.rows_per_tbl; - - if (rowsPerTbl > 0) { - insertMode = INTERLACE_INSERT_MODE; - } else { - insertMode = PROGRESSIVE_INSERT_MODE; - } - - // rows per table need be less than insert batch - if (rowsPerTbl > g_args.num_of_RPR) - rowsPerTbl = g_args.num_of_RPR; - pThreadInfo->totalInsertRows = 0; pThreadInfo->totalAffectedRows = 0; int64_t insertRows = (superTblInfo)?superTblInfo->insertRows:g_args.num_of_DPT; - int insert_interval = superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; - int timeStempStep = superTblInfo?superTblInfo->timeStampStep:DEFAULT_TIMESTAMP_STEP; + int insert_interval = + superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; uint64_t st = 0; uint64_t et = 0xffffffff; @@ -4461,13 +4615,13 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) { assert(pThreadInfo->ntables > 0); - if (rowsPerTbl > g_args.num_of_RPR) - rowsPerTbl = g_args.num_of_RPR; + if (interlaceRows > g_args.num_of_RPR) + interlaceRows = g_args.num_of_RPR; - batchPerTbl = rowsPerTbl; - if ((rowsPerTbl > 0) && (pThreadInfo->ntables > 1)) { + batchPerTbl = interlaceRows; + if ((interlaceRows > 0) && (pThreadInfo->ntables > 1)) { batchPerTblTimes = - (g_args.num_of_RPR / (rowsPerTbl * pThreadInfo->ntables)) + 1; + (g_args.num_of_RPR / (interlaceRows * pThreadInfo->ntables)) + 1; } else { batchPerTblTimes = 1; } @@ -4509,13 +4663,23 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) { verbosePrint("[%d] %s() LN%d i=%d batchPerTblTimes=%d batchPerTbl = %d\n", pThreadInfo->threadID, __func__, __LINE__, i, batchPerTblTimes, batchPerTbl); + + if (superTblInfo) { + if (0 == strncasecmp(superTblInfo->startTimestamp, "now", 3)) { + startTime = taosGetTimestamp(pThreadInfo->time_precision); + } + } else { + startTime = 1500000000000; + } generateDataTail( tableName, tableSeq, pThreadInfo, superTblInfo, batchPerTbl, pstr, insertRows, 0, - startTime + sleepTimeTotal + 0 * timeStempStep, + startTime, &(pThreadInfo->samplePos), &dataLen); + pstr += dataLen; recOfBatch += batchPerTbl; + startTime += batchPerTbl * superTblInfo->timeStampStep; pThreadInfo->totalInsertRows += batchPerTbl; verbosePrint("[%d] %s() LN%d batchPerTbl=%d recOfBatch=%d\n", pThreadInfo->threadID, __func__, __LINE__, @@ -4525,6 +4689,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) { if (insertMode == INTERLACE_INSERT_MODE) { if (tableSeq == pThreadInfo->start_table_from + pThreadInfo->ntables) { // turn to first table + startTime += batchPerTbl * superTblInfo->timeStampStep; tableSeq = pThreadInfo->start_table_from; generatedRecPerTbl += batchPerTbl; flagSleep = true; @@ -4631,22 +4796,26 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) { strerror(errno)); return NULL; } - + int64_t lastPrintTime = taosGetTimestampMs(); int64_t startTs = taosGetTimestampUs(); int64_t endTs; - int timeStampStep = superTblInfo?superTblInfo->timeStampStep:DEFAULT_TIMESTAMP_STEP; - int insert_interval = superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; + int timeStampStep = + superTblInfo?superTblInfo->timeStampStep:DEFAULT_TIMESTAMP_STEP; +/* int insert_interval = + superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; uint64_t st = 0; uint64_t et = 0xffffffff; + */ pThreadInfo->totalInsertRows = 0; pThreadInfo->totalAffectedRows = 0; pThreadInfo->samplePos = 0; - for (uint32_t tableSeq = pThreadInfo->start_table_from; tableSeq <= pThreadInfo->end_table_to; + for (uint32_t tableSeq = + pThreadInfo->start_table_from; tableSeq <= pThreadInfo->end_table_to; tableSeq ++) { int64_t start_time = pThreadInfo->start_time; @@ -4654,9 +4823,11 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) { verbosePrint("%s() LN%d insertRows=%"PRId64"\n", __func__, __LINE__, insertRows); for (int64_t i = 0; i < insertRows;) { + /* if (insert_interval) { st = taosGetTimestampUs(); } + */ char tableName[TSDB_TABLE_NAME_LEN]; getTableName(tableName, pThreadInfo, tableSeq); @@ -4664,15 +4835,16 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) { __func__, __LINE__, pThreadInfo->threadID, tableSeq, tableName); - int generated = generateDataBuffer( + int generated = generateProgressiveDataBuffer( tableName, tableSeq, pThreadInfo, buffer, insertRows, - i, start_time + pThreadInfo->totalInsertRows * timeStampStep, + i, start_time, &(pThreadInfo->samplePos)); if (generated > 0) i += generated; else goto free_and_statistics_2; + start_time += generated * timeStampStep; pThreadInfo->totalInsertRows += generated; startTs = taosGetTimestampUs(); @@ -4705,7 +4877,7 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) { if (i >= insertRows) break; - +/* if (insert_interval) { et = taosGetTimestampUs(); @@ -4716,6 +4888,7 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) { taosMsleep(sleep_time); // ms } } + */ } // num_of_DPT if ((tableSeq == pThreadInfo->ntables - 1) && superTblInfo && @@ -4741,9 +4914,9 @@ static void* syncWrite(void *sarg) { threadInfo *winfo = (threadInfo *)sarg; SSuperTable* superTblInfo = winfo->superTblInfo; - int rowsPerTbl = superTblInfo?superTblInfo->rowsPerTbl:g_args.rows_per_tbl; + int interlaceRows = superTblInfo?superTblInfo->interlaceRows:g_args.interlace_rows; - if (rowsPerTbl > 0) { + if (interlaceRows > 0) { // interlace mode return syncWriteInterlace(winfo); } else { @@ -4756,14 +4929,15 @@ static void callBack(void *param, TAOS_RES *res, int code) { threadInfo* winfo = (threadInfo*)param; SSuperTable* superTblInfo = winfo->superTblInfo; - int insert_interval = superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; + int insert_interval = + superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; if (insert_interval) { winfo->et = taosGetTimestampUs(); if (((winfo->et - winfo->st)/1000) < insert_interval) { taosMsleep(insert_interval - (winfo->et - winfo->st)/1000); // ms } } - + char *buffer = calloc(1, winfo->superTblInfo->maxSqlLen); char *data = calloc(1, MAX_DATA_SIZE); char *pstr = buffer; @@ -4781,17 +4955,17 @@ static void callBack(void *param, TAOS_RES *res, int code) { taos_free_result(res); return; } - + for (int i = 0; i < g_args.num_of_RPR; i++) { int rand_num = taosRandom() % 100; - if (0 != winfo->superTblInfo->disorderRatio && rand_num < winfo->superTblInfo->disorderRatio) - { + if (0 != winfo->superTblInfo->disorderRatio + && rand_num < winfo->superTblInfo->disorderRatio) { int64_t d = winfo->lastTs - taosRandom() % 1000000 + rand_num; //generateData(data, datatype, ncols_per_record, d, len_of_binary); - (void)generateRowData(data, MAX_DATA_SIZE, d, winfo->superTblInfo); + generateRowData(data, MAX_DATA_SIZE, d, winfo->superTblInfo); } else { //generateData(data, datatype, ncols_per_record, start_time += 1000, len_of_binary); - (void)generateRowData(data, MAX_DATA_SIZE, winfo->lastTs += 1000, winfo->superTblInfo); + generateRowData(data, MAX_DATA_SIZE, winfo->lastTs += 1000, winfo->superTblInfo); } pstr += sprintf(pstr, "%s", data); winfo->counter++; @@ -4818,8 +4992,9 @@ static void *asyncWrite(void *sarg) { winfo->st = 0; winfo->et = 0; winfo->lastTs = winfo->start_time; - - int insert_interval = superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; + + int insert_interval = + superTblInfo?superTblInfo->insertInterval:g_args.insert_interval; if (insert_interval) { winfo->st = taosGetTimestampUs(); } @@ -4845,7 +5020,7 @@ static void startMultiThreadInsertData(int threads, char* db_name, int ntables = 0; if (superTblInfo) { - if ((superTblInfo->childTblOffset >= 0) + if ((superTblInfo->childTblOffset >= 0) && (superTblInfo->childTblLimit > 0)) { ntables = superTblInfo->childTblLimit; @@ -4883,12 +5058,12 @@ static void startMultiThreadInsertData(int threads, char* db_name, } else if (0 == strncasecmp(precision, "us", 2)) { timePrec = TSDB_TIME_PRECISION_MICRO; } else { - errorPrint( "No support precision: %s\n", precision); + errorPrint("Not support precision: %s\n", precision); exit(-1); } } - int64_t start_time; + int64_t start_time; if (superTblInfo) { if (0 == strncasecmp(superTblInfo->startTimestamp, "now", 3)) { start_time = taosGetTimestamp(timePrec); @@ -4906,7 +5081,7 @@ static void startMultiThreadInsertData(int threads, char* db_name, } double start = getCurrentTime(); - + int startFrom; if ((superTblInfo) && (superTblInfo->childTblOffset >= 0)) @@ -4915,19 +5090,21 @@ static void startMultiThreadInsertData(int threads, char* db_name, startFrom = 0; // read sample data from file first - if ((superTblInfo) && (0 == strncasecmp(superTblInfo->dataSource, + if ((superTblInfo) && (0 == strncasecmp(superTblInfo->dataSource, "sample", strlen("sample")))) { if (0 != prepareSampleDataForSTable(superTblInfo)) { - errorPrint("%s() LN%d, prepare sample data for stable failed!\n", __func__, __LINE__); + errorPrint("%s() LN%d, prepare sample data for stable failed!\n", + __func__, __LINE__); exit(-1); } } // read sample data from file first - if ((superTblInfo) && (0 == strncasecmp(superTblInfo->dataSource, + if ((superTblInfo) && (0 == strncasecmp(superTblInfo->dataSource, "sample", strlen("sample")))) { if (0 != prepareSampleDataForSTable(superTblInfo)) { - errorPrint("%s() LN%d, prepare sample data for stable failed!\n", __func__, __LINE__); + errorPrint("%s() LN%d, prepare sample data for stable failed!\n", + __func__, __LINE__); exit(-1); } } @@ -4975,6 +5152,7 @@ static void startMultiThreadInsertData(int threads, char* db_name, threadInfo *t_info = infos + i; t_info->threadID = i; tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE); + t_info->time_precision = timePrec; t_info->superTblInfo = superTblInfo; t_info->start_time = start_time; @@ -4987,7 +5165,8 @@ static void startMultiThreadInsertData(int threads, char* db_name, g_Dbs.host, g_Dbs.user, g_Dbs.password, db_name, g_Dbs.port); if (NULL == t_info->taos) { - errorPrint( "connect to server fail from insert sub thread, reason: %s\n", + errorPrint( + "connect to server fail from insert sub thread, reason: %s\n", taos_errstr(NULL)); exit(-1); } @@ -5086,7 +5265,7 @@ static void startMultiThreadInsertData(int threads, char* db_name, avgDelay/1000.0, (double)maxDelay/1000.0, (double)minDelay/1000.0); fprintf(g_fpOfInsertResult, "insert delay, avg:%10.6fms, max: %10.6fms, min: %10.6fms\n\n", avgDelay/1000.0, (double)maxDelay/1000.0, (double)minDelay/1000.0); - + //taos_close(taos); free(pids); @@ -5094,7 +5273,7 @@ static void startMultiThreadInsertData(int threads, char* db_name, } static void *readTable(void *sarg) { -#if 1 +#if 1 threadInfo *rinfo = (threadInfo *)sarg; TAOS *taos = rinfo->taos; char command[BUFFER_SIZE] = "\0"; @@ -5129,7 +5308,8 @@ static void *readTable(void *sarg) { double totalT = 0; int count = 0; for (int i = 0; i < num_of_tables; i++) { - sprintf(command, "select %s from %s%d where ts>= %" PRId64, aggreFunc[j], tb_prefix, i, sTime); + sprintf(command, "select %s from %s%d where ts>= %" PRId64, + aggreFunc[j], tb_prefix, i, sTime); double t = getCurrentTime(); TAOS_RES *pSql = taos_query(taos, command); @@ -5260,7 +5440,7 @@ static int insertTestProcess() { printf("Press enter key to continue\n\n"); (void)getchar(); } - + init_rand_data(); // create database and super tables @@ -5282,10 +5462,10 @@ static int insertTestProcess() { if (g_totalChildTables > 0) { printf("Spent %.4f seconds to create %d tables with %d thread(s)\n\n", - end - start, g_totalChildTables, g_Dbs.threadCount); + end - start, g_totalChildTables, g_Dbs.threadCountByCreateTbl); fprintf(g_fpOfInsertResult, "Spent %.4f seconds to create %d tables with %d thread(s)\n\n", - end - start, g_totalChildTables, g_Dbs.threadCount); + end - start, g_totalChildTables, g_Dbs.threadCountByCreateTbl); } taosMsleep(1000); @@ -5299,16 +5479,16 @@ static int insertTestProcess() { continue; } startMultiThreadInsertData( - g_Dbs.threadCount, - g_Dbs.db[i].dbName, - g_Dbs.db[i].dbCfg.precision, + g_Dbs.threadCount, + g_Dbs.db[i].dbName, + g_Dbs.db[i].dbCfg.precision, superTblInfo); } } else { startMultiThreadInsertData( - g_Dbs.threadCount, - g_Dbs.db[i].dbName, - g_Dbs.db[i].dbCfg.precision, + g_Dbs.threadCount, + g_Dbs.db[i].dbName, + g_Dbs.db[i].dbCfg.precision, NULL); } } @@ -5328,48 +5508,69 @@ static int insertTestProcess() { } static void *superQueryProcess(void *sarg) { - threadInfo *winfo = (threadInfo *)sarg; + threadInfo *winfo = (threadInfo *)sarg; + + if (winfo->taos == NULL) { + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + NULL, + g_queryInfo.port); + if (taos == NULL) { + errorPrint("[%d] Failed to connect to TDengine, reason:%s\n", + winfo->threadID, taos_errstr(NULL)); + return NULL; + } else { + winfo->taos = taos; + } + } //char sqlStr[MAX_TB_NAME_SIZE*2]; //sprintf(sqlStr, "use %s", g_queryInfo.dbName); //queryDB(winfo->taos, sqlStr); - + int64_t st = 0; int64_t et = 0; - while (1) { - if (g_queryInfo.superQueryInfo.rate && (et - st) < (int64_t)g_queryInfo.superQueryInfo.rate*1000) { - taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms + + int queryTimes = g_queryInfo.specifiedQueryInfo.queryTimes; + + while(queryTimes --) { + if (g_queryInfo.specifiedQueryInfo.rate && (et - st) < + (int64_t)g_queryInfo.specifiedQueryInfo.rate*1000) { + taosMsleep(g_queryInfo.specifiedQueryInfo.rate*1000 - (et - st)); // ms //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_from, winfo->end_table_to); } st = taosGetTimestampUs(); - for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { - if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", 5)) { + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.sqlCount; i++) { + if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", 5)) { int64_t t1 = taosGetTimestampUs(); char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; - if (g_queryInfo.superQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", g_queryInfo.superQueryInfo.result[i], winfo->threadID); + if (g_queryInfo.specifiedQueryInfo.result[i][0] != 0) { + sprintf(tmpFile, "%s-%d", + g_queryInfo.specifiedQueryInfo.result[i], winfo->threadID); } - selectAndGetResult(winfo->taos, g_queryInfo.superQueryInfo.sql[i], tmpFile); - int64_t t2 = taosGetTimestampUs(); - printf("=[taosc] thread[%"PRId64"] complete one sql, Spent %f s\n", + selectAndGetResult(winfo->taos, g_queryInfo.specifiedQueryInfo.sql[i], tmpFile); + int64_t t2 = taosGetTimestampUs(); + printf("=[taosc] thread[%"PRId64"] complete one sql, Spent %f s\n", taosGetSelfPthreadId(), (t2 - t1)/1000000.0); } else { int64_t t1 = taosGetTimestampUs(); - int retCode = postProceSql(g_queryInfo.host, - g_queryInfo.port, g_queryInfo.superQueryInfo.sql[i]); - int64_t t2 = taosGetTimestampUs(); - printf("=[restful] thread[%"PRId64"] complete one sql, Spent %f s\n", + int retCode = postProceSql(g_queryInfo.host, + g_queryInfo.port, g_queryInfo.specifiedQueryInfo.sql[i]); + int64_t t2 = taosGetTimestampUs(); + printf("=[restful] thread[%"PRId64"] complete one sql, Spent %f s\n", taosGetSelfPthreadId(), (t2 - t1)/1000000.0); - + if (0 != retCode) { printf("====restful return fail, threadID[%d]\n", winfo->threadID); return NULL; } - } + } } et = taosGetTimestampUs(); - printf("==thread[%"PRId64"] complete all sqls to specify tables once queries duration:%.6fs\n\n", + printf("==thread[%"PRId64"] complete all sqls to specify tables once queries duration:%.6fs\n\n", taosGetSelfPthreadId(), (double)(et - st)/1000.0); } return NULL; @@ -5378,302 +5579,299 @@ static void *superQueryProcess(void *sarg) { static void replaceSubTblName(char* inSql, char* outSql, int tblIndex) { char sourceString[32] = "xxxx"; char subTblName[MAX_TB_NAME_SIZE*3]; - sprintf(subTblName, "%s.%s", - g_queryInfo.dbName, - g_queryInfo.subQueryInfo.childTblName + tblIndex*TSDB_TABLE_NAME_LEN); + sprintf(subTblName, "%s.%s", + g_queryInfo.dbName, + g_queryInfo.superQueryInfo.childTblName + tblIndex*TSDB_TABLE_NAME_LEN); //printf("inSql: %s\n", inSql); - + char* pos = strstr(inSql, sourceString); if (0 == pos) { - return; + return; } - + tstrncpy(outSql, inSql, pos - inSql + 1); //printf("1: %s\n", outSql); - strcat(outSql, subTblName); - //printf("2: %s\n", outSql); - strcat(outSql, pos+strlen(sourceString)); - //printf("3: %s\n", outSql); + strcat(outSql, subTblName); + //printf("2: %s\n", outSql); + strcat(outSql, pos+strlen(sourceString)); + //printf("3: %s\n", outSql); } static void *subQueryProcess(void *sarg) { char sqlstr[1024]; - threadInfo *winfo = (threadInfo *)sarg; + threadInfo *winfo = (threadInfo *)sarg; + + if (winfo->taos == NULL) { + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + NULL, + g_queryInfo.port); + if (taos == NULL) { + errorPrint("[%d] Failed to connect to TDengine, reason:%s\n", + winfo->threadID, taos_errstr(NULL)); + return NULL; + } else { + winfo->taos = taos; + } + } + int64_t st = 0; - int64_t et = (int64_t)g_queryInfo.subQueryInfo.rate*1000; - while (1) { - if (g_queryInfo.subQueryInfo.rate - && (et - st) < (int64_t)g_queryInfo.subQueryInfo.rate*1000) { - taosMsleep(g_queryInfo.subQueryInfo.rate*1000 - (et - st)); // ms + int64_t et = (int64_t)g_queryInfo.superQueryInfo.rate*1000; + + int queryTimes = g_queryInfo.superQueryInfo.queryTimes; + + while(queryTimes --) { + if (g_queryInfo.superQueryInfo.rate + && (et - st) < (int64_t)g_queryInfo.superQueryInfo.rate*1000) { + taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_from, winfo->end_table_to); } st = taosGetTimestampUs(); for (int i = winfo->start_table_from; i <= winfo->end_table_to; i++) { - for (int j = 0; j < g_queryInfo.subQueryInfo.sqlCount; j++) { + for (int j = 0; j < g_queryInfo.superQueryInfo.sqlCount; j++) { memset(sqlstr,0,sizeof(sqlstr)); - replaceSubTblName(g_queryInfo.subQueryInfo.sql[j], sqlstr, i); + replaceSubTblName(g_queryInfo.superQueryInfo.sql[j], sqlstr, i); char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; - if (g_queryInfo.subQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", - g_queryInfo.subQueryInfo.result[i], + if (g_queryInfo.superQueryInfo.result[j][0] != 0) { + sprintf(tmpFile, "%s-%d", + g_queryInfo.superQueryInfo.result[j], winfo->threadID); } - selectAndGetResult(winfo->taos, sqlstr, tmpFile); + selectAndGetResult(winfo->taos, sqlstr, tmpFile); } } et = taosGetTimestampUs(); - printf("####thread[%"PRId64"] complete all sqls to allocate all sub-tables[%d - %d] once queries duration:%.4fs\n\n", - taosGetSelfPthreadId(), - winfo->start_table_from, - winfo->end_table_to, + printf("####thread[%"PRId64"] complete all sqls to allocate all sub-tables[%d - %d] once queries duration:%.4fs\n\n", + taosGetSelfPthreadId(), + winfo->start_table_from, + winfo->end_table_to, (double)(et - st)/1000000.0); } + return NULL; } static int queryTestProcess() { - TAOS * taos = NULL; - taos = taos_connect(g_queryInfo.host, - g_queryInfo.user, - g_queryInfo.password, - NULL, + + setupForAnsiEscape(); + printfQueryMeta(); + resetAfterAnsiEscape(); + + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + NULL, g_queryInfo.port); if (taos == NULL) { - errorPrint( "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + errorPrint( "Failed to connect to TDengine, reason:%s\n", + taos_errstr(NULL)); exit(-1); } - if (0 != g_queryInfo.subQueryInfo.sqlCount) { + if (0 != g_queryInfo.superQueryInfo.sqlCount) { getAllChildNameOfSuperTable(taos, g_queryInfo.dbName, - g_queryInfo.subQueryInfo.sTblName, - &g_queryInfo.subQueryInfo.childTblName, - &g_queryInfo.subQueryInfo.childTblCount); - } - - printfQueryMeta(); - + g_queryInfo.superQueryInfo.sTblName, + &g_queryInfo.superQueryInfo.childTblName, + &g_queryInfo.superQueryInfo.childTblCount); + } + if (!g_args.answer_yes) { printf("Press enter key to continue\n\n"); (void)getchar(); } - + printfQuerySystemInfo(taos); - + pthread_t *pids = NULL; threadInfo *infos = NULL; //==== create sub threads for query from specify table - if (g_queryInfo.superQueryInfo.sqlCount > 0 - && g_queryInfo.superQueryInfo.concurrent > 0) { + if (g_queryInfo.specifiedQueryInfo.sqlCount > 0 + && g_queryInfo.specifiedQueryInfo.concurrent > 0) { - pids = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(pthread_t)); - infos = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(threadInfo)); - if ((NULL == pids) || (NULL == infos)) { - printf("malloc failed for create threads\n"); + pids = malloc(g_queryInfo.specifiedQueryInfo.concurrent * sizeof(pthread_t)); + if (NULL == pids) { + taos_close(taos); + ERROR_EXIT("memory allocation failed\n"); + } + infos = malloc(g_queryInfo.specifiedQueryInfo.concurrent * sizeof(threadInfo)); + if (NULL == infos) { taos_close(taos); - exit(-1); + free(pids); + ERROR_EXIT("memory allocation failed for create threads\n"); } - for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.concurrent; i++) { threadInfo *t_info = infos + i; t_info->threadID = i; - + if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", 5)) { - t_info->taos = taos; char sqlStr[MAX_TB_NAME_SIZE*2]; sprintf(sqlStr, "use %s", g_queryInfo.dbName); verbosePrint("%s() %d sqlStr: %s\n", __func__, __LINE__, sqlStr); - (void)queryDbExec(t_info->taos, sqlStr, NO_INSERT_TYPE); - } else { - t_info->taos = NULL; + if (0 != queryDbExec(taos, sqlStr, NO_INSERT_TYPE, false)) { + taos_close(taos); + free(infos); + free(pids); + errorPrint( "use database %s failed!\n\n", + g_queryInfo.dbName); + return -1; + } } - + + t_info->taos = NULL;// TODO: workaround to use separate taos connection; + pthread_create(pids + i, NULL, superQueryProcess, t_info); } - }else { - g_queryInfo.superQueryInfo.concurrent = 0; + } else { + g_queryInfo.specifiedQueryInfo.concurrent = 0; } + taos_close(taos); + pthread_t *pidsOfSub = NULL; threadInfo *infosOfSub = NULL; //==== create sub threads for query from all sub table of the super table - if ((g_queryInfo.subQueryInfo.sqlCount > 0) - && (g_queryInfo.subQueryInfo.threadCnt > 0)) { - pidsOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(pthread_t)); - infosOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(threadInfo)); - if ((NULL == pidsOfSub) || (NULL == infosOfSub)) { - printf("malloc failed for create threads\n"); - taos_close(taos); - exit(-1); + if ((g_queryInfo.superQueryInfo.sqlCount > 0) + && (g_queryInfo.superQueryInfo.threadCnt > 0)) { + pidsOfSub = malloc(g_queryInfo.superQueryInfo.threadCnt * sizeof(pthread_t)); + if (NULL == pidsOfSub) { + free(infos); + free(pids); + + ERROR_EXIT("memory allocation failed for create threads\n"); } - int ntables = g_queryInfo.subQueryInfo.childTblCount; - int threads = g_queryInfo.subQueryInfo.threadCnt; - + infosOfSub = malloc(g_queryInfo.superQueryInfo.threadCnt * sizeof(threadInfo)); + if (NULL == infosOfSub) { + free(pidsOfSub); + free(infos); + free(pids); + ERROR_EXIT("memory allocation failed for create threads\n"); + } + + int ntables = g_queryInfo.superQueryInfo.childTblCount; + int threads = g_queryInfo.superQueryInfo.threadCnt; + int a = ntables / threads; if (a < 1) { threads = ntables; a = 1; } - + int b = 0; if (threads != 0) { b = ntables % threads; } int startFrom = 0; - for (int i = 0; i < threads; i++) { + for (int i = 0; i < threads; i++) { threadInfo *t_info = infosOfSub + i; t_info->threadID = i; - + t_info->start_table_from = startFrom; t_info->ntables = iend_table_to = i < b ? startFrom + a : startFrom + a - 1; startFrom = t_info->end_table_to + 1; - t_info->taos = taos; + t_info->taos = NULL; // TODO: workaround to use separate taos connection; pthread_create(pidsOfSub + i, NULL, subQueryProcess, t_info); } - g_queryInfo.subQueryInfo.threadCnt = threads; - }else { - g_queryInfo.subQueryInfo.threadCnt = 0; - } - - for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + g_queryInfo.superQueryInfo.threadCnt = threads; + } else { + g_queryInfo.superQueryInfo.threadCnt = 0; + } + + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.concurrent; i++) { pthread_join(pids[i], NULL); } tmfree((char*)pids); - tmfree((char*)infos); - - for (int i = 0; i < g_queryInfo.subQueryInfo.threadCnt; i++) { + tmfree((char*)infos); + + for (int i = 0; i < g_queryInfo.superQueryInfo.threadCnt; i++) { pthread_join(pidsOfSub[i], NULL); } tmfree((char*)pidsOfSub); - tmfree((char*)infosOfSub); - - taos_close(taos); + tmfree((char*)infosOfSub); + +// taos_close(taos);// TODO: workaround to use separate taos connection; return 0; } -static void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) { +static void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) { if (res == NULL || taos_errno(res) != 0) { - printf("failed to subscribe result, code:%d, reason:%s\n", code, taos_errstr(res)); + errorPrint("%s() LN%d, failed to subscribe result, code:%d, reason:%s\n", + __func__, __LINE__, code, taos_errstr(res)); return; } - + getResult(res, (char*)param); taos_free_result(res); } static TAOS_SUB* subscribeImpl(TAOS *taos, char *sql, char* topic, char* resultFileName) { - TAOS_SUB* tsub = NULL; + TAOS_SUB* tsub = NULL; - if (g_queryInfo.superQueryInfo.subscribeMode) { - tsub = taos_subscribe(taos, - g_queryInfo.superQueryInfo.subscribeRestart, - topic, sql, subscribe_callback, (void*)resultFileName, - g_queryInfo.superQueryInfo.subscribeInterval); + if (g_queryInfo.specifiedQueryInfo.subscribeMode) { + tsub = taos_subscribe(taos, + g_queryInfo.specifiedQueryInfo.subscribeRestart, + topic, sql, subscribe_callback, (void*)resultFileName, + g_queryInfo.specifiedQueryInfo.subscribeInterval); } else { - tsub = taos_subscribe(taos, - g_queryInfo.superQueryInfo.subscribeRestart, + tsub = taos_subscribe(taos, + g_queryInfo.specifiedQueryInfo.subscribeRestart, topic, sql, NULL, NULL, 0); } if (tsub == NULL) { printf("failed to create subscription. topic:%s, sql:%s\n", topic, sql); return NULL; - } + } return tsub; } static void *subSubscribeProcess(void *sarg) { - threadInfo *winfo = (threadInfo *)sarg; + threadInfo *winfo = (threadInfo *)sarg; char subSqlstr[1024]; - char sqlStr[MAX_TB_NAME_SIZE*2]; - sprintf(sqlStr, "use %s", g_queryInfo.dbName); - debugPrint("%s() %d sqlStr: %s\n", __func__, __LINE__, sqlStr); - if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE)){ - return NULL; - } - - //int64_t st = 0; - //int64_t et = 0; - do { - //if (g_queryInfo.superQueryInfo.rate && (et - st) < g_queryInfo.superQueryInfo.rate*1000) { - // taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms - // //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_from, winfo->end_table_to); - //} - - //st = taosGetTimestampMs(); - char topic[32] = {0}; - for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { - sprintf(topic, "taosdemo-subscribe-%d", i); - memset(subSqlstr,0,sizeof(subSqlstr)); - replaceSubTblName(g_queryInfo.subQueryInfo.sql[i], subSqlstr, i); - char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; - if (g_queryInfo.subQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", g_queryInfo.subQueryInfo.result[i], winfo->threadID); - } - g_queryInfo.subQueryInfo.tsub[i] = subscribeImpl(winfo->taos, subSqlstr, topic, tmpFile); - if (NULL == g_queryInfo.subQueryInfo.tsub[i]) { - return NULL; - } - } - //et = taosGetTimestampMs(); - //printf("========thread[%"PRId64"] complete all sqls to super table once queries duration:%.4fs\n", taosGetSelfPthreadId(), (double)(et - st)/1000.0); - } while (0); - - // start loop to consume result - TAOS_RES* res = NULL; - while (1) { - for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { - if (1 == g_queryInfo.subQueryInfo.subscribeMode) { - continue; - } - - res = taos_consume(g_queryInfo.subQueryInfo.tsub[i]); - if (res) { - char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; - if (g_queryInfo.subQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", - g_queryInfo.subQueryInfo.result[i], - winfo->threadID); - } - getResult(res, tmpFile); - } + if (winfo->taos == NULL) { + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + g_queryInfo.dbName, + g_queryInfo.port); + if (taos == NULL) { + errorPrint("[%d] Failed to connect to TDengine, reason:%s\n", + winfo->threadID, taos_errstr(NULL)); + return NULL; + } else { + winfo->taos = taos; } } - taos_free_result(res); - - for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { - taos_unsubscribe(g_queryInfo.subQueryInfo.tsub[i], - g_queryInfo.subQueryInfo.subscribeKeepProgress); - } - return NULL; -} - -static void *superSubscribeProcess(void *sarg) { - threadInfo *winfo = (threadInfo *)sarg; char sqlStr[MAX_TB_NAME_SIZE*2]; sprintf(sqlStr, "use %s", g_queryInfo.dbName); debugPrint("%s() %d sqlStr: %s\n", __func__, __LINE__, sqlStr); - if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE)) { + if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE, false)) { + taos_close(winfo->taos); return NULL; } - + //int64_t st = 0; //int64_t et = 0; do { - //if (g_queryInfo.superQueryInfo.rate && (et - st) < g_queryInfo.superQueryInfo.rate*1000) { - // taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms + //if (g_queryInfo.specifiedQueryInfo.rate && (et - st) < g_queryInfo.specifiedQueryInfo.rate*1000) { + // taosMsleep(g_queryInfo.specifiedQueryInfo.rate*1000 - (et - st)); // ms // //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_from, winfo->end_table_to); //} @@ -5681,16 +5879,17 @@ static void *superSubscribeProcess(void *sarg) { char topic[32] = {0}; for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { sprintf(topic, "taosdemo-subscribe-%d", i); + memset(subSqlstr,0,sizeof(subSqlstr)); + replaceSubTblName(g_queryInfo.superQueryInfo.sql[i], subSqlstr, i); char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; - if (g_queryInfo.subQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", + if (g_queryInfo.superQueryInfo.result[i][0] != 0) { + sprintf(tmpFile, "%s-%d", g_queryInfo.superQueryInfo.result[i], winfo->threadID); } - g_queryInfo.superQueryInfo.tsub[i] = - subscribeImpl(winfo->taos, - g_queryInfo.superQueryInfo.sql[i], - topic, tmpFile); + g_queryInfo.superQueryInfo.tsub[i] = subscribeImpl( + winfo->taos, subSqlstr, topic, tmpFile); if (NULL == g_queryInfo.superQueryInfo.tsub[i]) { + taos_close(winfo->taos); return NULL; } } @@ -5705,13 +5904,14 @@ static void *superSubscribeProcess(void *sarg) { if (1 == g_queryInfo.superQueryInfo.subscribeMode) { continue; } - + res = taos_consume(g_queryInfo.superQueryInfo.tsub[i]); if (res) { char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; if (g_queryInfo.superQueryInfo.result[i][0] != 0) { - sprintf(tmpFile, "%s-%d", - g_queryInfo.superQueryInfo.result[i], winfo->threadID); + sprintf(tmpFile, "%s-%d", + g_queryInfo.superQueryInfo.result[i], + winfo->threadID); } getResult(res, tmpFile); } @@ -5720,89 +5920,188 @@ static void *superSubscribeProcess(void *sarg) { taos_free_result(res); for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { - taos_unsubscribe(g_queryInfo.superQueryInfo.tsub[i], + taos_unsubscribe(g_queryInfo.superQueryInfo.tsub[i], g_queryInfo.superQueryInfo.subscribeKeepProgress); } + + taos_close(winfo->taos); + return NULL; +} + +static void *superSubscribeProcess(void *sarg) { + threadInfo *winfo = (threadInfo *)sarg; + + if (winfo->taos == NULL) { + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + g_queryInfo.dbName, + g_queryInfo.port); + if (taos == NULL) { + errorPrint("[%d] Failed to connect to TDengine, reason:%s\n", + winfo->threadID, taos_errstr(NULL)); + return NULL; + } else { + winfo->taos = taos; + } + } + + char sqlStr[MAX_TB_NAME_SIZE*2]; + sprintf(sqlStr, "use %s", g_queryInfo.dbName); + debugPrint("%s() %d sqlStr: %s\n", __func__, __LINE__, sqlStr); + if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE, false)) { + taos_close(winfo->taos); + return NULL; + } + + //int64_t st = 0; + //int64_t et = 0; + do { + //if (g_queryInfo.specifiedQueryInfo.rate && (et - st) < g_queryInfo.specifiedQueryInfo.rate*1000) { + // taosMsleep(g_queryInfo.specifiedQueryInfo.rate*1000 - (et - st)); // ms + // //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_from, winfo->end_table_to); + //} + + //st = taosGetTimestampMs(); + char topic[32] = {0}; + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.sqlCount; i++) { + sprintf(topic, "taosdemo-subscribe-%d", i); + char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; + if (g_queryInfo.superQueryInfo.result[i][0] != 0) { + sprintf(tmpFile, "%s-%d", + g_queryInfo.specifiedQueryInfo.result[i], winfo->threadID); + } + g_queryInfo.specifiedQueryInfo.tsub[i] = + subscribeImpl(winfo->taos, + g_queryInfo.specifiedQueryInfo.sql[i], + topic, tmpFile); + if (NULL == g_queryInfo.specifiedQueryInfo.tsub[i]) { + taos_close(winfo->taos); + return NULL; + } + } + //et = taosGetTimestampMs(); + //printf("========thread[%"PRId64"] complete all sqls to super table once queries duration:%.4fs\n", taosGetSelfPthreadId(), (double)(et - st)/1000.0); + } while (0); + + // start loop to consume result + TAOS_RES* res = NULL; + while (1) { + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.sqlCount; i++) { + if (1 == g_queryInfo.specifiedQueryInfo.subscribeMode) { + continue; + } + + res = taos_consume(g_queryInfo.specifiedQueryInfo.tsub[i]); + if (res) { + char tmpFile[MAX_FILE_NAME_LEN*2] = {0}; + if (g_queryInfo.specifiedQueryInfo.result[i][0] != 0) { + sprintf(tmpFile, "%s-%d", + g_queryInfo.specifiedQueryInfo.result[i], winfo->threadID); + } + getResult(res, tmpFile); + } + } + } + taos_free_result(res); + + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.sqlCount; i++) { + taos_unsubscribe(g_queryInfo.specifiedQueryInfo.tsub[i], + g_queryInfo.specifiedQueryInfo.subscribeKeepProgress); + } + + taos_close(winfo->taos); return NULL; } static int subscribeTestProcess() { + setupForAnsiEscape(); printfQueryMeta(); + resetAfterAnsiEscape(); if (!g_args.answer_yes) { printf("Press enter key to continue\n\n"); - (void)getchar(); + (void) getchar(); } - TAOS * taos = NULL; - taos = taos_connect(g_queryInfo.host, - g_queryInfo.user, - g_queryInfo.password, - g_queryInfo.dbName, + TAOS * taos = NULL; + taos = taos_connect(g_queryInfo.host, + g_queryInfo.user, + g_queryInfo.password, + g_queryInfo.dbName, g_queryInfo.port); if (taos == NULL) { - errorPrint( "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + errorPrint( "Failed to connect to TDengine, reason:%s\n", + taos_errstr(NULL)); exit(-1); } - if (0 != g_queryInfo.subQueryInfo.sqlCount) { - getAllChildNameOfSuperTable(taos, - g_queryInfo.dbName, - g_queryInfo.subQueryInfo.sTblName, - &g_queryInfo.subQueryInfo.childTblName, - &g_queryInfo.subQueryInfo.childTblCount); + if (0 != g_queryInfo.superQueryInfo.sqlCount) { + getAllChildNameOfSuperTable(taos, + g_queryInfo.dbName, + g_queryInfo.superQueryInfo.sTblName, + &g_queryInfo.superQueryInfo.childTblName, + &g_queryInfo.superQueryInfo.childTblCount); } + taos_close(taos); // TODO: workaround to use separate taos connection; + pthread_t *pids = NULL; threadInfo *infos = NULL; //==== create sub threads for query from super table - if (g_queryInfo.superQueryInfo.sqlCount > 0 - && g_queryInfo.superQueryInfo.concurrent > 0) { - pids = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(pthread_t)); - infos = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(threadInfo)); - if ((NULL == pids) || (NULL == infos)) { - printf("malloc failed for create threads\n"); - taos_close(taos); - exit(-1); - } + if ((g_queryInfo.specifiedQueryInfo.sqlCount <= 0) || + (g_queryInfo.specifiedQueryInfo.concurrent <= 0)) { + errorPrint("%s() LN%d, query sqlCount %d or concurrent %d is not correct.\n", + __func__, __LINE__, g_queryInfo.specifiedQueryInfo.sqlCount, + g_queryInfo.specifiedQueryInfo.concurrent); + exit(-1); + } - for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + pids = malloc(g_queryInfo.specifiedQueryInfo.concurrent * sizeof(pthread_t)); + infos = malloc(g_queryInfo.specifiedQueryInfo.concurrent * sizeof(threadInfo)); + if ((NULL == pids) || (NULL == infos)) { + errorPrint("%s() LN%d, malloc failed for create threads\n", __func__, __LINE__); + exit(-1); + } + + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.concurrent; i++) { threadInfo *t_info = infos + i; t_info->threadID = i; - t_info->taos = taos; + t_info->taos = NULL; // TODO: workaround to use separate taos connection; pthread_create(pids + i, NULL, superSubscribeProcess, t_info); - } } - - //==== create sub threads for query from sub table + + //==== create sub threads for query from sub table pthread_t *pidsOfSub = NULL; threadInfo *infosOfSub = NULL; - if ((g_queryInfo.subQueryInfo.sqlCount > 0) - && (g_queryInfo.subQueryInfo.threadCnt > 0)) { - pidsOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * + if ((g_queryInfo.superQueryInfo.sqlCount > 0) + && (g_queryInfo.superQueryInfo.threadCnt > 0)) { + pidsOfSub = malloc(g_queryInfo.superQueryInfo.threadCnt * sizeof(pthread_t)); - infosOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * + infosOfSub = malloc(g_queryInfo.superQueryInfo.threadCnt * sizeof(threadInfo)); if ((NULL == pidsOfSub) || (NULL == infosOfSub)) { - printf("malloc failed for create threads\n"); - taos_close(taos); + errorPrint("%s() LN%d, malloc failed for create threads\n", + __func__, __LINE__); + // taos_close(taos); exit(-1); } - int ntables = g_queryInfo.subQueryInfo.childTblCount; - int threads = g_queryInfo.subQueryInfo.threadCnt; - + int ntables = g_queryInfo.superQueryInfo.childTblCount; + int threads = g_queryInfo.superQueryInfo.threadCnt; + int a = ntables / threads; if (a < 1) { threads = ntables; a = 1; } - + int b = 0; if (threads != 0) { b = ntables % threads; } - + int startFrom = 0; for (int i = 0; i < threads; i++) { threadInfo *t_info = infosOfSub + i; @@ -5812,69 +6111,71 @@ static int subscribeTestProcess() { t_info->ntables = iend_table_to = i < b ? startFrom + a : startFrom + a - 1; startFrom = t_info->end_table_to + 1; - t_info->taos = taos; + t_info->taos = NULL; // TODO: workaround to use separate taos connection; pthread_create(pidsOfSub + i, NULL, subSubscribeProcess, t_info); } - g_queryInfo.subQueryInfo.threadCnt = threads; + + g_queryInfo.superQueryInfo.threadCnt = threads; + + for (int i = 0; i < g_queryInfo.superQueryInfo.threadCnt; i++) { + pthread_join(pidsOfSub[i], NULL); + } } - - for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + + for (int i = 0; i < g_queryInfo.specifiedQueryInfo.concurrent; i++) { pthread_join(pids[i], NULL); - } + } tmfree((char*)pids); tmfree((char*)infos); - for (int i = 0; i < g_queryInfo.subQueryInfo.threadCnt; i++) { - pthread_join(pidsOfSub[i], NULL); - } - tmfree((char*)pidsOfSub); tmfree((char*)infosOfSub); - taos_close(taos); +// taos_close(taos); return 0; } static void initOfInsertMeta() { memset(&g_Dbs, 0, sizeof(SDbs)); - + // set default values - tstrncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.host, "127.0.0.1", MAX_HOSTNAME_SIZE); g_Dbs.port = 6030; - tstrncpy(g_Dbs.user, TSDB_DEFAULT_USER, MAX_DB_NAME_SIZE); - tstrncpy(g_Dbs.password, TSDB_DEFAULT_PASS, MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.user, TSDB_DEFAULT_USER, MAX_USERNAME_SIZE); + tstrncpy(g_Dbs.password, TSDB_DEFAULT_PASS, MAX_PASSWORD_SIZE); g_Dbs.threadCount = 2; - g_Dbs.use_metric = true; + + g_Dbs.use_metric = g_args.use_metric; } static void initOfQueryMeta() { memset(&g_queryInfo, 0, sizeof(SQueryMetaInfo)); - + // set default values - tstrncpy(g_queryInfo.host, "127.0.0.1", MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.host, "127.0.0.1", MAX_HOSTNAME_SIZE); g_queryInfo.port = 6030; - tstrncpy(g_queryInfo.user, TSDB_DEFAULT_USER, MAX_DB_NAME_SIZE); - tstrncpy(g_queryInfo.password, TSDB_DEFAULT_PASS, MAX_DB_NAME_SIZE); + tstrncpy(g_queryInfo.user, TSDB_DEFAULT_USER, MAX_USERNAME_SIZE); + tstrncpy(g_queryInfo.password, TSDB_DEFAULT_PASS, MAX_PASSWORD_SIZE); } static void setParaFromArg(){ if (g_args.host) { - strcpy(g_Dbs.host, g_args.host); + tstrncpy(g_Dbs.host, g_args.host, MAX_HOSTNAME_SIZE); } else { - tstrncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + tstrncpy(g_Dbs.host, "127.0.0.1", MAX_HOSTNAME_SIZE); } if (g_args.user) { - strcpy(g_Dbs.user, g_args.user); - } + tstrncpy(g_Dbs.user, g_args.user, MAX_USERNAME_SIZE); + } if (g_args.password) { - strcpy(g_Dbs.password, g_args.password); - } - + tstrncpy(g_Dbs.password, g_args.password, MAX_PASSWORD_SIZE); + } + if (g_args.port) { g_Dbs.port = g_args.port; - } + } g_Dbs.threadCount = g_args.num_of_threads; g_Dbs.threadCountByCreateTbl = g_args.num_of_threads; @@ -5895,11 +6196,11 @@ static void setParaFromArg(){ char dataString[STRING_LEN]; char **data_type = g_args.datatype; - + memset(dataString, 0, STRING_LEN); - if (strcasecmp(data_type[0], "BINARY") == 0 - || strcasecmp(data_type[0], "BOOL") == 0 + if (strcasecmp(data_type[0], "BINARY") == 0 + || strcasecmp(data_type[0], "BOOL") == 0 || strcasecmp(data_type[0], "NCHAR") == 0 ) { g_Dbs.do_aggreFunc = false; } @@ -5909,22 +6210,21 @@ static void setParaFromArg(){ tstrncpy(g_Dbs.db[0].superTbls[0].sTblName, "meters", MAX_TB_NAME_SIZE); g_Dbs.db[0].superTbls[0].childTblCount = g_args.num_of_tables; g_Dbs.threadCount = g_args.num_of_threads; - g_Dbs.threadCountByCreateTbl = 1; + g_Dbs.threadCountByCreateTbl = g_args.num_of_threads; g_Dbs.queryMode = g_args.mode; - + g_Dbs.db[0].superTbls[0].autoCreateTable = PRE_CREATE_SUBTBL; - g_Dbs.db[0].superTbls[0].superTblExists = TBL_NO_EXISTS; g_Dbs.db[0].superTbls[0].childTblExists = TBL_NO_EXISTS; g_Dbs.db[0].superTbls[0].disorderRange = g_args.disorderRange; g_Dbs.db[0].superTbls[0].disorderRatio = g_args.disorderRatio; - tstrncpy(g_Dbs.db[0].superTbls[0].childTblPrefix, + tstrncpy(g_Dbs.db[0].superTbls[0].childTblPrefix, g_args.tb_prefix, MAX_TB_NAME_SIZE); tstrncpy(g_Dbs.db[0].superTbls[0].dataSource, "rand", MAX_TB_NAME_SIZE); tstrncpy(g_Dbs.db[0].superTbls[0].insertMode, "taosc", MAX_TB_NAME_SIZE); - tstrncpy(g_Dbs.db[0].superTbls[0].startTimestamp, + tstrncpy(g_Dbs.db[0].superTbls[0].startTimestamp, "2017-07-14 10:40:00.000", MAX_TB_NAME_SIZE); g_Dbs.db[0].superTbls[0].timeStampStep = DEFAULT_TIMESTAMP_STEP; - + g_Dbs.db[0].superTbls[0].insertRows = g_args.num_of_DPT; g_Dbs.db[0].superTbls[0].maxSqlLen = TSDB_PAYLOAD_SIZE; @@ -5933,34 +6233,33 @@ static void setParaFromArg(){ if (data_type[i] == NULL) { break; } - - tstrncpy(g_Dbs.db[0].superTbls[0].columns[i].dataType, + + tstrncpy(g_Dbs.db[0].superTbls[0].columns[i].dataType, data_type[i], MAX_TB_NAME_SIZE); - g_Dbs.db[0].superTbls[0].columns[i].dataLen = g_args.len_of_binary; + g_Dbs.db[0].superTbls[0].columns[i].dataLen = g_args.len_of_binary; g_Dbs.db[0].superTbls[0].columnCount++; } - + if (g_Dbs.db[0].superTbls[0].columnCount > g_args.num_of_CPR) { g_Dbs.db[0].superTbls[0].columnCount = g_args.num_of_CPR; } else { for (int i = g_Dbs.db[0].superTbls[0].columnCount; i < g_args.num_of_CPR; i++) { tstrncpy(g_Dbs.db[0].superTbls[0].columns[i].dataType, "INT", MAX_TB_NAME_SIZE); - g_Dbs.db[0].superTbls[0].columns[i].dataLen = 0; + g_Dbs.db[0].superTbls[0].columns[i].dataLen = 0; g_Dbs.db[0].superTbls[0].columnCount++; } } tstrncpy(g_Dbs.db[0].superTbls[0].tags[0].dataType, "INT", MAX_TB_NAME_SIZE); - g_Dbs.db[0].superTbls[0].tags[0].dataLen = 0; - - tstrncpy(g_Dbs.db[0].superTbls[0].tags[1].dataType, "BINARY", MAX_TB_NAME_SIZE); - g_Dbs.db[0].superTbls[0].tags[1].dataLen = g_args.len_of_binary; - g_Dbs.db[0].superTbls[0].tagCount = 2; - } else { - g_Dbs.threadCountByCreateTbl = 1; - g_Dbs.db[0].superTbls[0].tagCount = 0; - } + g_Dbs.db[0].superTbls[0].tags[0].dataLen = 0; + tstrncpy(g_Dbs.db[0].superTbls[0].tags[1].dataType, "BINARY", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].tags[1].dataLen = g_args.len_of_binary; + g_Dbs.db[0].superTbls[0].tagCount = 2; + } else { + g_Dbs.threadCountByCreateTbl = g_args.num_of_threads; + g_Dbs.db[0].superTbls[0].tagCount = 0; + } } /* Function to do regular expression check */ @@ -6031,9 +6330,9 @@ static void querySqlFile(TAOS* taos, char* sqlFile) memcpy(cmd + cmd_len, line, read_len); verbosePrint("%s() LN%d cmd: %s\n", __func__, __LINE__, cmd); - queryDbExec(taos, cmd, NO_INSERT_TYPE); - if (0 != queryDbExec(taos, cmd, NO_INSERT_TYPE)) { - printf("queryDbExec %s failed!\n", cmd); + if (0 != queryDbExec(taos, cmd, NO_INSERT_TYPE, false)) { + errorPrint("%s() LN%d, queryDbExec %s failed!\n", + __func__, __LINE__, cmd); tmfree(cmd); tmfree(line); tmfclose(fp); @@ -6054,16 +6353,23 @@ static void querySqlFile(TAOS* taos, char* sqlFile) static void testMetaFile() { if (INSERT_TEST == g_args.test_mode) { - if (g_Dbs.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_Dbs.cfgDir); + if (g_Dbs.cfgDir[0]) + taos_options(TSDB_OPTION_CONFIGDIR, g_Dbs.cfgDir); + insertTestProcess(); + } else if (QUERY_TEST == g_args.test_mode) { if (g_queryInfo.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_queryInfo.cfgDir); + queryTestProcess(); + } else if (SUBSCRIBE_TEST == g_args.test_mode) { if (g_queryInfo.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_queryInfo.cfgDir); + subscribeTestProcess(); + } else { ; } @@ -6084,27 +6390,28 @@ static void queryResult() { rInfo->ntables = g_Dbs.db[0].superTbls[0].childTblCount; rInfo->end_table_to = g_Dbs.db[0].superTbls[0].childTblCount - 1; rInfo->superTblInfo = &g_Dbs.db[0].superTbls[0]; - strcpy(rInfo->tb_prefix, - g_Dbs.db[0].superTbls[0].childTblPrefix); + tstrncpy(rInfo->tb_prefix, + g_Dbs.db[0].superTbls[0].childTblPrefix, MAX_TB_NAME_SIZE); } else { rInfo->ntables = g_args.num_of_tables; rInfo->end_table_to = g_args.num_of_tables -1; - strcpy(rInfo->tb_prefix, g_args.tb_prefix); + tstrncpy(rInfo->tb_prefix, g_args.tb_prefix, MAX_TB_NAME_SIZE); } rInfo->taos = taos_connect( - g_Dbs.host, - g_Dbs.user, - g_Dbs.password, - g_Dbs.db[0].dbName, + g_Dbs.host, + g_Dbs.user, + g_Dbs.password, + g_Dbs.db[0].dbName, g_Dbs.port); if (rInfo->taos == NULL) { - errorPrint( "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + errorPrint( "Failed to connect to TDengine, reason:%s\n", + taos_errstr(NULL)); free(rInfo); exit(-1); } - strcpy(rInfo->fp, g_Dbs.resultFile); + tstrncpy(rInfo->fp, g_Dbs.resultFile, MAX_FILE_NAME_LEN); if (!g_Dbs.use_metric) { pthread_create(&read_id, NULL, readTable, rInfo); @@ -6119,13 +6426,13 @@ static void queryResult() { static void testCmdLine() { - g_args.test_mode = INSERT_TEST; - insertTestProcess(); + g_args.test_mode = INSERT_TEST; + insertTestProcess(); - if (g_Dbs.insert_only) - return; - else - queryResult(); + if (g_Dbs.insert_only) + return; + else + queryResult(); } int main(int argc, char *argv[]) { @@ -6135,7 +6442,7 @@ int main(int argc, char *argv[]) { if (g_args.metaFile) { initOfInsertMeta(); - initOfQueryMeta(); + initOfQueryMeta(); if (false == getInfoFromJsonFile(g_args.metaFile)) { printf("Failed to read %s\n", g_args.metaFile); @@ -6149,12 +6456,12 @@ int main(int argc, char *argv[]) { if (NULL != g_args.sqlFile) { TAOS* qtaos = taos_connect( - g_Dbs.host, - g_Dbs.user, - g_Dbs.password, - g_Dbs.db[0].dbName, + g_Dbs.host, + g_Dbs.user, + g_Dbs.password, + g_Dbs.db[0].dbName, g_Dbs.port); - querySqlFile(qtaos, g_args.sqlFile); + querySqlFile(qtaos, g_args.sqlFile); taos_close(qtaos); } else { diff --git a/src/mnode/inc/mnodeVgroup.h b/src/mnode/inc/mnodeVgroup.h index e052cdb83c..7b798c23f8 100644 --- a/src/mnode/inc/mnodeVgroup.h +++ b/src/mnode/inc/mnodeVgroup.h @@ -49,6 +49,7 @@ void mnodeRemoveTableFromVgroup(SVgObj *pVgroup, SCTableObj *pTable); void mnodeSendDropVnodeMsg(int32_t vgId, SRpcEpSet *epSet, void *ahandle); void mnodeSendCreateVgroupMsg(SVgObj *pVgroup, void *ahandle); void mnodeSendAlterVgroupMsg(SVgObj *pVgroup); +void mnodeSendSyncVgroupMsg(SVgObj *pVgroup); SRpcEpSet mnodeGetEpSetFromVgroup(SVgObj *pVgroup); SRpcEpSet mnodeGetEpSetFromIp(char *ep); diff --git a/src/mnode/src/mnodeDb.c b/src/mnode/src/mnodeDb.c index b1c88ca718..909ca7cac6 100644 --- a/src/mnode/src/mnodeDb.c +++ b/src/mnode/src/mnodeDb.c @@ -50,6 +50,7 @@ static int32_t mnodeGetDbMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *pConn static int32_t mnodeRetrieveDbs(SShowObj *pShow, char *data, int32_t rows, void *pConn); static int32_t mnodeProcessCreateDbMsg(SMnodeMsg *pMsg); static int32_t mnodeProcessDropDbMsg(SMnodeMsg *pMsg); +static int32_t mnodeProcessSyncDbMsg(SMnodeMsg *pMsg); int32_t mnodeProcessAlterDbMsg(SMnodeMsg *pMsg); #ifndef _TOPIC @@ -178,6 +179,7 @@ int32_t mnodeInitDbs() { mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_CREATE_DB, mnodeProcessCreateDbMsg); mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_ALTER_DB, mnodeProcessAlterDbMsg); mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_DROP_DB, mnodeProcessDropDbMsg); + mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_SYNC_DB, mnodeProcessSyncDbMsg); mnodeAddShowMetaHandle(TSDB_MGMT_TABLE_DB, mnodeGetDbMeta); mnodeAddShowRetrieveHandle(TSDB_MGMT_TABLE_DB, mnodeRetrieveDbs); mnodeAddShowFreeIterHandle(TSDB_MGMT_TABLE_DB, mnodeCancelGetNextDb); @@ -1184,6 +1186,46 @@ static int32_t mnodeProcessDropDbMsg(SMnodeMsg *pMsg) { return mnodeDropDb(pMsg); } +static int32_t mnodeSyncDb(SDbObj *pDb, SMnodeMsg *pMsg) { + void *pIter = NULL; + SVgObj *pVgroup = NULL; + while (1) { + pIter = mnodeGetNextVgroup(pIter, &pVgroup); + if (pVgroup == NULL) break; + if (pVgroup->pDb == pDb) { + mnodeSendSyncVgroupMsg(pVgroup); + } + mnodeDecVgroupRef(pVgroup); + } + + mLInfo("db:%s, is synced by %s", pDb->name, mnodeGetUserFromMsg(pMsg)); + + return TSDB_CODE_SUCCESS; +} + +static int32_t mnodeProcessSyncDbMsg(SMnodeMsg *pMsg) { + SSyncDbMsg *pSyncDb = pMsg->rpcMsg.pCont; + mDebug("db:%s, syncdb is received from thandle:%p, ignore:%d", pSyncDb->db, pMsg->rpcMsg.handle, pSyncDb->ignoreNotExists); + + if (pMsg->pDb == NULL) pMsg->pDb = mnodeGetDb(pSyncDb->db); + if (pMsg->pDb == NULL) { + if (pSyncDb->ignoreNotExists) { + mDebug("db:%s, db is not exist, treat as success", pSyncDb->db); + return TSDB_CODE_SUCCESS; + } else { + mError("db:%s, failed to sync, invalid db", pSyncDb->db); + return TSDB_CODE_MND_INVALID_DB; + } + } + + if (pMsg->pDb->status != TSDB_DB_STATUS_READY) { + mError("db:%s, status:%d, in dropping", pSyncDb->db, pMsg->pDb->status); + return TSDB_CODE_MND_DB_IN_DROPPING; + } + + return mnodeSyncDb(pMsg->pDb, pMsg); +} + void mnodeDropAllDbs(SAcctObj *pAcct) { int32_t numOfDbs = 0; SDbObj *pDb = NULL; diff --git a/src/mnode/src/mnodeVgroup.c b/src/mnode/src/mnodeVgroup.c index fdbf7ae398..7eb3122d83 100644 --- a/src/mnode/src/mnodeVgroup.c +++ b/src/mnode/src/mnodeVgroup.c @@ -60,6 +60,7 @@ static int32_t mnodeGetVgroupMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *p static int32_t mnodeRetrieveVgroups(SShowObj *pShow, char *data, int32_t rows, void *pConn); static void mnodeProcessCreateVnodeRsp(SRpcMsg *rpcMsg); static void mnodeProcessAlterVnodeRsp(SRpcMsg *rpcMsg); +static void mnodeProcessSyncVnodeRsp(SRpcMsg *rpcMsg); static void mnodeProcessDropVnodeRsp(SRpcMsg *rpcMsg); static int32_t mnodeProcessVnodeCfgMsg(SMnodeMsg *pMsg) ; static void mnodeSendDropVgroupMsg(SVgObj *pVgroup, void *ahandle); @@ -236,6 +237,7 @@ int32_t mnodeInitVgroups() { mnodeAddShowFreeIterHandle(TSDB_MGMT_TABLE_VGROUP, mnodeCancelGetNextVgroup); mnodeAddPeerRspHandle(TSDB_MSG_TYPE_MD_CREATE_VNODE_RSP, mnodeProcessCreateVnodeRsp); mnodeAddPeerRspHandle(TSDB_MSG_TYPE_MD_ALTER_VNODE_RSP, mnodeProcessAlterVnodeRsp); + mnodeAddPeerRspHandle(TSDB_MSG_TYPE_MD_ALTER_VNODE_RSP, mnodeProcessSyncVnodeRsp); mnodeAddPeerRspHandle(TSDB_MSG_TYPE_MD_DROP_VNODE_RSP, mnodeProcessDropVnodeRsp); mnodeAddPeerMsgHandle(TSDB_MSG_TYPE_DM_CONFIG_VNODE, mnodeProcessVnodeCfgMsg); @@ -967,6 +969,38 @@ void mnodeSendAlterVgroupMsg(SVgObj *pVgroup) { } } +static SSyncVnodeMsg *mnodeBuildSyncVnodeMsg(int32_t vgId) { + SSyncVnodeMsg *pSyncVnode = rpcMallocCont(sizeof(SSyncVnodeMsg)); + if (pSyncVnode == NULL) return NULL; + + pSyncVnode->vgId = htonl(vgId); + return pSyncVnode; +} + +static void mnodeSendSyncVnodeMsg(SVgObj *pVgroup, SRpcEpSet *epSet) { + SSyncVnodeMsg *pSyncVnode = mnodeBuildSyncVnodeMsg(pVgroup->vgId); + SRpcMsg rpcMsg = { + .ahandle = NULL, + .pCont = pSyncVnode, + .contLen = pSyncVnode ? sizeof(SSyncVnodeMsg) : 0, + .code = 0, + .msgType = TSDB_MSG_TYPE_MD_SYNC_VNODE + }; + + dnodeSendMsgToDnode(epSet, &rpcMsg); +} + +void mnodeSendSyncVgroupMsg(SVgObj *pVgroup) { + mDebug("vgId:%d, send sync all vnodes msg, numOfVnodes:%d db:%s", pVgroup->vgId, pVgroup->numOfVnodes, + pVgroup->dbName); + for (int32_t i = 0; i < pVgroup->numOfVnodes; ++i) { + SRpcEpSet epSet = mnodeGetEpSetFromIp(pVgroup->vnodeGid[i].pDnode->dnodeEp); + mDebug("vgId:%d, index:%d, send sync vnode msg to dnode %s", pVgroup->vgId, i, + pVgroup->vnodeGid[i].pDnode->dnodeEp); + mnodeSendSyncVnodeMsg(pVgroup, &epSet); + } +} + static void mnodeSendCreateVnodeMsg(SVgObj *pVgroup, SRpcEpSet *epSet, void *ahandle) { SCreateVnodeMsg *pCreate = mnodeBuildVnodeMsg(pVgroup); SRpcMsg rpcMsg = { @@ -994,6 +1028,10 @@ static void mnodeProcessAlterVnodeRsp(SRpcMsg *rpcMsg) { mDebug("alter vnode rsp received"); } +static void mnodeProcessSyncVnodeRsp(SRpcMsg *rpcMsg) { + mDebug("sync vnode rsp received"); +} + static void mnodeProcessCreateVnodeRsp(SRpcMsg *rpcMsg) { if (rpcMsg->ahandle == NULL) return; diff --git a/src/query/inc/qResultbuf.h b/src/query/inc/qResultbuf.h index e46af8c298..ef43a9621a 100644 --- a/src/query/inc/qResultbuf.h +++ b/src/query/inc/qResultbuf.h @@ -72,7 +72,7 @@ typedef struct SDiskbasedResultBuf { bool comp; // compressed before flushed to disk int32_t nextPos; // next page flush position - const void* handle; // for debug purpose + uint64_t qId; // for debug purpose SResultBufStatis statis; } SDiskbasedResultBuf; @@ -88,7 +88,7 @@ typedef struct SDiskbasedResultBuf { * @param handle * @return */ -int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pagesize, int32_t inMemBufSize, const void* handle); +int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId); /** * diff --git a/src/query/inc/qUtil.h b/src/query/inc/qUtil.h index 31dfc350a3..cdd8b0707a 100644 --- a/src/query/inc/qUtil.h +++ b/src/query/inc/qUtil.h @@ -25,6 +25,7 @@ } while (0) #define GET_RES_WINDOW_KEY_LEN(_l) ((_l) + sizeof(uint64_t)) +#define GET_QID(_r) (((SQInfo*)((_r)->qinfo))->qId) #define curTimeWindowIndex(_winres) ((_winres)->curIndex) #define GET_ROW_PARAM_FOR_MULTIOUTPUT(_q, tbq, sq) (((tbq) && (!(sq)))? (_q)->pExpr1[1].base.arg->argValue.i64:1) diff --git a/src/query/inc/sql.y b/src/query/inc/sql.y index 7f6aa1ca5f..b026f90235 100644 --- a/src/query/inc/sql.y +++ b/src/query/inc/sql.y @@ -726,6 +726,9 @@ expritem(A) ::= . {A = 0;} ///////////////////////////////////reset query cache////////////////////////////////////// cmd ::= RESET QUERY CACHE. { setDCLSqlElems(pInfo, TSDB_SQL_RESET_CACHE, 0);} +///////////////////////////////////sync replica database////////////////////////////////// +cmd ::= SYNCDB ids(X) REPLICA.{ setDCLSqlElems(pInfo, TSDB_SQL_SYNC_DB_REPLICA, 1, &X);} + ///////////////////////////////////ALTER TABLE statement////////////////////////////////// cmd ::= ALTER TABLE ids(X) cpxName(F) ADD COLUMN columnlist(A). { X.n += F.n; diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index 59e04c9cac..7ba629cfc2 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -1332,7 +1332,7 @@ static void doHashGroupbyAgg(SOperatorInfo* pOperator, SGroupbyOperatorInfo *pIn int16_t type = pColInfoData->info.type; if (type == TSDB_DATA_TYPE_FLOAT || type == TSDB_DATA_TYPE_DOUBLE) { - qError("QInfo:%p group by not supported on double/float columns, abort", pRuntimeEnv->qinfo); + qError("QInfo:%"PRIu64" group by not supported on double/float columns, abort", GET_QID(pRuntimeEnv)); return; } @@ -1715,7 +1715,7 @@ static void* destroySQLFunctionCtx(SQLFunctionCtx* pCtx, int32_t numOfOutput) { } static int32_t setupQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv, int32_t numOfTables) { - qDebug("QInfo:%p setup runtime env", pRuntimeEnv->qinfo); + qDebug("QInfo:%"PRIu64" setup runtime env", GET_QID(pRuntimeEnv)); SQuery *pQuery = pRuntimeEnv->pQuery; pRuntimeEnv->prevGroupId = INT32_MIN; @@ -1748,7 +1748,7 @@ static int32_t setupQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv, int32_t numOf *(int64_t*) pRuntimeEnv->prevRow[0] = INT64_MIN; } - qDebug("QInfo:%p init runtime environment completed", pRuntimeEnv->qinfo); + qDebug("QInfo:%"PRIu64" init runtime environment completed", GET_QID(pRuntimeEnv)); // group by normal column, sliding window query, interval query are handled by interval query processor // interval (down sampling operation) @@ -1847,7 +1847,7 @@ static void teardownQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv) { SQuery *pQuery = pRuntimeEnv->pQuery; SQInfo* pQInfo = (SQInfo*) pRuntimeEnv->qinfo; - qDebug("QInfo:%p teardown runtime env", pQInfo); + qDebug("QInfo:%"PRIu64" teardown runtime env", pQInfo->qId); if (pRuntimeEnv->sasArray != NULL) { for(int32_t i = 0; i < pQuery->numOfOutput; ++i) { @@ -1895,8 +1895,8 @@ bool isQueryKilled(SQInfo *pQInfo) { (!needBuildResAfterQueryComplete(pQInfo))) { assert(pQInfo->startExecTs != 0); - qDebug("QInfo:%p retrieve not arrive beyond %d sec, abort current query execution, start:%"PRId64", current:%d", pQInfo, 1, - pQInfo->startExecTs, taosGetTimestampSec()); + qDebug("QInfo:%" PRIu64 " retrieve not arrive beyond %d sec, abort current query execution, start:%" PRId64 + ", current:%d", pQInfo->qId, 1, pQInfo->startExecTs, taosGetTimestampSec()); return true; } @@ -2066,11 +2066,11 @@ static void setScanLimitationByResultBuffer(SQuery *pQuery) { /* * todo add more parameters to check soon.. */ -bool colIdCheck(SQuery *pQuery, void* qinfo) { +bool colIdCheck(SQuery *pQuery, uint64_t qId) { // load data column information is incorrect for (int32_t i = 0; i < pQuery->numOfCols - 1; ++i) { if (pQuery->colList[i].colId == pQuery->colList[i + 1].colId) { - qError("QInfo:%p invalid data load column for query", qinfo); + qError("QInfo:%"PRIu64" invalid data load column for query", qId); return false; } } @@ -2123,13 +2123,13 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo SQuery* pQuery = pQInfo->runtimeEnv.pQuery; // in case of point-interpolation query, use asc order scan - char msg[] = "QInfo:%p scan order changed for %s query, old:%d, new:%d, qrange exchanged, old qrange:%" PRId64 + char msg[] = "QInfo:%"PRIu64" scan order changed for %s query, old:%d, new:%d, qrange exchanged, old qrange:%" PRId64 "-%" PRId64 ", new qrange:%" PRId64 "-%" PRId64; // todo handle the case the the order irrelevant query type mixed up with order critical query type // descending order query for last_row query if (isFirstLastRowQuery(pQuery)) { - qDebug("QInfo:%p scan order changed for last_row query, old:%d, new:%d", pQInfo, pQuery->order.order, TSDB_ORDER_ASC); + qDebug("QInfo:%"PRIu64" scan order changed for last_row query, old:%d, new:%d", pQInfo->qId, pQuery->order.order, TSDB_ORDER_ASC); pQuery->order.order = TSDB_ORDER_ASC; if (pQuery->window.skey > pQuery->window.ekey) { @@ -2151,7 +2151,7 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo if (isPointInterpoQuery(pQuery) && pQuery->interval.interval == 0) { if (!QUERY_IS_ASC_QUERY(pQuery)) { - qDebug(msg, pQInfo, "interp", pQuery->order.order, TSDB_ORDER_ASC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); + qDebug(msg, pQInfo->qId, "interp", pQuery->order.order, TSDB_ORDER_ASC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); SWAP(pQuery->window.skey, pQuery->window.ekey, TSKEY); } @@ -2162,7 +2162,7 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo if (pQuery->interval.interval == 0) { if (onlyFirstQuery(pQuery)) { if (!QUERY_IS_ASC_QUERY(pQuery)) { - qDebug(msg, pQInfo, "only-first", pQuery->order.order, TSDB_ORDER_ASC, pQuery->window.skey, + qDebug(msg, pQInfo->qId, "only-first", pQuery->order.order, TSDB_ORDER_ASC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); SWAP(pQuery->window.skey, pQuery->window.ekey, TSKEY); @@ -2172,7 +2172,7 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo pQuery->order.order = TSDB_ORDER_ASC; } else if (onlyLastQuery(pQuery)) { if (QUERY_IS_ASC_QUERY(pQuery)) { - qDebug(msg, pQInfo, "only-last", pQuery->order.order, TSDB_ORDER_DESC, pQuery->window.skey, + qDebug(msg, pQInfo->qId, "only-last", pQuery->order.order, TSDB_ORDER_DESC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); SWAP(pQuery->window.skey, pQuery->window.ekey, TSKEY); @@ -2186,7 +2186,7 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo if (stableQuery) { if (onlyFirstQuery(pQuery)) { if (!QUERY_IS_ASC_QUERY(pQuery)) { - qDebug(msg, pQInfo, "only-first stable", pQuery->order.order, TSDB_ORDER_ASC, + qDebug(msg, pQInfo->qId, "only-first stable", pQuery->order.order, TSDB_ORDER_ASC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); SWAP(pQuery->window.skey, pQuery->window.ekey, TSKEY); @@ -2196,7 +2196,7 @@ static void changeExecuteScanOrder(SQInfo *pQInfo, SQueryTableMsg* pQueryMsg, bo pQuery->order.order = TSDB_ORDER_ASC; } else if (onlyLastQuery(pQuery)) { if (QUERY_IS_ASC_QUERY(pQuery)) { - qDebug(msg, pQInfo, "only-last stable", pQuery->order.order, TSDB_ORDER_DESC, + qDebug(msg, pQInfo->qId, "only-last stable", pQuery->order.order, TSDB_ORDER_DESC, pQuery->window.skey, pQuery->window.ekey, pQuery->window.ekey, pQuery->window.skey); SWAP(pQuery->window.skey, pQuery->window.ekey, TSKEY); @@ -2604,7 +2604,7 @@ int32_t loadDataBlockOnDemand(SQueryRuntimeEnv* pRuntimeEnv, STableScanInfo* pTa SDataBlockInfo* pBlockInfo = &pBlock->info; if ((*status) == BLK_DATA_NO_NEEDED) { - qDebug("QInfo:%p data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo, pBlockInfo->window.skey, + qDebug("QInfo:%"PRIu64" data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo->qId, pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows); pCost->discardBlocks += 1; } else if ((*status) == BLK_DATA_STATIS_NEEDED) { @@ -2632,7 +2632,7 @@ int32_t loadDataBlockOnDemand(SQueryRuntimeEnv* pRuntimeEnv, STableScanInfo* pTa (char*)&(pBlock->pBlockStatis[i].max)); if (!load) { // current block has been discard due to filter applied pCost->discardBlocks += 1; - qDebug("QInfo:%p data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo, + qDebug("QInfo:%"PRIu64" data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo->qId, pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows); (*status) = BLK_DATA_DISCARD; return TSDB_CODE_SUCCESS; @@ -2644,7 +2644,7 @@ int32_t loadDataBlockOnDemand(SQueryRuntimeEnv* pRuntimeEnv, STableScanInfo* pTa // current block has been discard due to filter applied if (!doFilterByBlockStatistics(pRuntimeEnv, pBlock->pBlockStatis, pTableScanInfo->pCtx, pBlockInfo->rows)) { pCost->discardBlocks += 1; - qDebug("QInfo:%p data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo, pBlockInfo->window.skey, + qDebug("QInfo:%"PRIu64" data block discard, brange:%" PRId64 "-%" PRId64 ", rows:%d", pQInfo->qId, pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows); (*status) = BLK_DATA_DISCARD; return TSDB_CODE_SUCCESS; @@ -3311,10 +3311,10 @@ void setCtxTagForJoin(SQueryRuntimeEnv* pRuntimeEnv, SQLFunctionCtx* pCtx, SExpr int16_t tagType = pCtx[0].tag.nType; if (tagType == TSDB_DATA_TYPE_BINARY || tagType == TSDB_DATA_TYPE_NCHAR) { - qDebug("QInfo:%p set tag value for join comparison, colId:%" PRId64 ", val:%s", pRuntimeEnv->qinfo, + qDebug("QInfo:%"PRIu64" set tag value for join comparison, colId:%" PRId64 ", val:%s", GET_QID(pRuntimeEnv), pExprInfo->base.arg->argValue.i64, pCtx[0].tag.pz); } else { - qDebug("QInfo:%p set tag value for join comparison, colId:%" PRId64 ", val:%" PRId64, pRuntimeEnv->qinfo, + qDebug("QInfo:%"PRIu64" set tag value for join comparison, colId:%" PRId64 ", val:%" PRId64, GET_QID(pRuntimeEnv), pExprInfo->base.arg->argValue.i64, pCtx[0].tag.i64); } } @@ -3334,9 +3334,9 @@ int32_t setTimestampListJoinInfo(SQueryRuntimeEnv* pRuntimeEnv, tVariant* pTag, // failed to find data with the specified tag value and vnodeId if (!tsBufIsValidElem(&elem)) { if (pTag->nType == TSDB_DATA_TYPE_BINARY || pTag->nType == TSDB_DATA_TYPE_NCHAR) { - qError("QInfo:%p failed to find tag:%s in ts_comp", pRuntimeEnv->qinfo, pTag->pz); + qError("QInfo:%"PRIu64" failed to find tag:%s in ts_comp", GET_QID(pRuntimeEnv), pTag->pz); } else { - qError("QInfo:%p failed to find tag:%" PRId64 " in ts_comp", pRuntimeEnv->qinfo, pTag->i64); + qError("QInfo:%"PRIu64" failed to find tag:%" PRId64 " in ts_comp", GET_QID(pRuntimeEnv), pTag->i64); } return -1; @@ -3345,17 +3345,17 @@ int32_t setTimestampListJoinInfo(SQueryRuntimeEnv* pRuntimeEnv, tVariant* pTag, // Keep the cursor info of current table pTableQueryInfo->cur = tsBufGetCursor(pRuntimeEnv->pTsBuf); if (pTag->nType == TSDB_DATA_TYPE_BINARY || pTag->nType == TSDB_DATA_TYPE_NCHAR) { - qDebug("QInfo:%p find tag:%s start pos in ts_comp, blockIndex:%d, tsIndex:%d", pRuntimeEnv->qinfo, pTag->pz, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); + qDebug("QInfo:%"PRIu64" find tag:%s start pos in ts_comp, blockIndex:%d, tsIndex:%d", GET_QID(pRuntimeEnv), pTag->pz, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); } else { - qDebug("QInfo:%p find tag:%"PRId64" start pos in ts_comp, blockIndex:%d, tsIndex:%d", pRuntimeEnv->qinfo, pTag->i64, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); + qDebug("QInfo:%"PRIu64" find tag:%"PRId64" start pos in ts_comp, blockIndex:%d, tsIndex:%d", GET_QID(pRuntimeEnv), pTag->i64, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); } } else { tsBufSetCursor(pRuntimeEnv->pTsBuf, &pTableQueryInfo->cur); if (pTag->nType == TSDB_DATA_TYPE_BINARY || pTag->nType == TSDB_DATA_TYPE_NCHAR) { - qDebug("QInfo:%p find tag:%s start pos in ts_comp, blockIndex:%d, tsIndex:%d", pRuntimeEnv->qinfo, pTag->pz, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); + qDebug("QInfo:%"PRIu64" find tag:%s start pos in ts_comp, blockIndex:%d, tsIndex:%d", GET_QID(pRuntimeEnv), pTag->pz, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); } else { - qDebug("QInfo:%p find tag:%"PRId64" start pos in ts_comp, blockIndex:%d, tsIndex:%d", pRuntimeEnv->qinfo, pTag->i64, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); + qDebug("QInfo:%"PRIu64" find tag:%"PRId64" start pos in ts_comp, blockIndex:%d, tsIndex:%d", GET_QID(pRuntimeEnv), pTag->i64, pTableQueryInfo->cur.blockIndex, pTableQueryInfo->cur.tsIndex); } } @@ -3459,7 +3459,7 @@ static int32_t doCopyToSDataBlock(SQueryRuntimeEnv* pRuntimeEnv, SGroupResInfo* int32_t start = 0; int32_t step = -1; - qDebug("QInfo:%p start to copy data from windowResInfo to output buf", pRuntimeEnv->qinfo); + qDebug("QInfo:%"PRIu64" start to copy data from windowResInfo to output buf", GET_QID(pRuntimeEnv)); if (orderType == TSDB_ORDER_ASC) { start = pGroupResInfo->index; step = 1; @@ -3499,7 +3499,7 @@ static int32_t doCopyToSDataBlock(SQueryRuntimeEnv* pRuntimeEnv, SGroupResInfo* } } - qDebug("QInfo:%p copy data to query buf completed", pRuntimeEnv->qinfo); + qDebug("QInfo:%"PRIu64" copy data to query buf completed", GET_QID(pRuntimeEnv)); pBlock->info.rows = numOfResult; return 0; } @@ -3585,11 +3585,11 @@ static void doCopyQueryResultToMsg(SQInfo *pQInfo, int32_t numOfRows, char *data data += sizeof(STableIdInfo); total++; - qDebug("QInfo:%p set subscribe info, tid:%d, uid:%"PRIu64", skey:%"PRId64, pQInfo, item->tid, item->uid, item->key); + qDebug("QInfo:%"PRIu64" set subscribe info, tid:%d, uid:%"PRIu64", skey:%"PRId64, pQInfo->qId, item->tid, item->uid, item->key); item = taosHashIterate(pRuntimeEnv->pTableRetrieveTsMap, item); } - qDebug("QInfo:%p set %d subscribe info", pQInfo, total); + qDebug("QInfo:%"PRIu64" set %d subscribe info", pQInfo->qId, total); // Check if query is completed or not for stable query or normal table query respectively. if (Q_STATUS_EQUAL(pRuntimeEnv->status, QUERY_COMPLETED) && pRuntimeEnv->proot->status == OP_EXEC_DONE) { setQueryStatus(pRuntimeEnv, QUERY_OVER); @@ -3628,12 +3628,12 @@ void queryCostStatis(SQInfo *pQInfo) { pSummary->numOfTimeWindows = 0; } - qDebug("QInfo:%p :cost summary: elapsed time:%"PRId64" us, first merge:%"PRId64" us, total blocks:%d, " + qDebug("QInfo:%"PRIu64" :cost summary: elapsed time:%"PRId64" us, first merge:%"PRId64" us, total blocks:%d, " "load block statis:%d, load data block:%d, total rows:%"PRId64 ", check rows:%"PRId64, - pQInfo, pSummary->elapsedTime, pSummary->firstStageMergeTime, pSummary->totalBlocks, pSummary->loadBlockStatis, + pQInfo->qId, pSummary->elapsedTime, pSummary->firstStageMergeTime, pSummary->totalBlocks, pSummary->loadBlockStatis, pSummary->loadBlocks, pSummary->totalRows, pSummary->totalCheckedRows); - qDebug("QInfo:%p :cost summary: winResPool size:%.2f Kb, numOfWin:%"PRId64", tableInfoSize:%.2f Kb, hashTable:%.2f Kb", pQInfo, pSummary->winInfoSize/1024.0, + qDebug("QInfo:%"PRIu64" :cost summary: winResPool size:%.2f Kb, numOfWin:%"PRId64", tableInfoSize:%.2f Kb, hashTable:%.2f Kb", pQInfo->qId, pSummary->winInfoSize/1024.0, pSummary->numOfTimeWindows, pSummary->tableInfoSize/1024.0, pSummary->hashSize/1024.0); } @@ -3669,7 +3669,7 @@ void queryCostStatis(SQInfo *pQInfo) { // // int32_t numOfRes = tableApplyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, NULL, binarySearchForKey, pDataBlock); // -// qDebug("QInfo:%p check data block, brange:%" PRId64 "-%" PRId64 ", numOfRows:%d, numOfRes:%d, lastKey:%"PRId64, pRuntimeEnv->qinfo, +// qDebug("QInfo:%"PRIu64" check data block, brange:%" PRId64 "-%" PRId64 ", numOfRows:%d, numOfRes:%d, lastKey:%"PRId64, GET_QID(pRuntimeEnv), // pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows, numOfRes, pQuery->current->lastKey); //} @@ -3699,7 +3699,7 @@ void queryCostStatis(SQInfo *pQInfo) { // pTableQueryInfo->lastKey = (QUERY_IS_ASC_QUERY(pQuery)) ? blockInfo.window.ekey : blockInfo.window.skey; // pTableQueryInfo->lastKey += step; // -// qDebug("QInfo:%p skip rows:%d, offset:%" PRId64, pRuntimeEnv->qinfo, blockInfo.rows, +// qDebug("QInfo:%"PRIu64" skip rows:%d, offset:%" PRId64, GET_QID(pRuntimeEnv), blockInfo.rows, // pQuery->limit.offset); // } else { // find the appropriated start position in current block // updateOffsetVal(pRuntimeEnv, &blockInfo); @@ -3747,8 +3747,8 @@ void queryCostStatis(SQInfo *pQInfo) { // int32_t numOfRes = tableApplyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, NULL, binarySearchForKey, pDataBlock); // pRuntimeEnv->resultRowInfo.curIndex = index; // restore the window index // -// qDebug("QInfo:%p check data block, brange:%" PRId64 "-%" PRId64 ", numOfRows:%d, numOfRes:%d, lastKey:%" PRId64, -// pRuntimeEnv->qinfo, pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows, numOfRes, +// qDebug("QInfo:%"PRIu64" check data block, brange:%" PRId64 "-%" PRId64 ", numOfRows:%d, numOfRes:%d, lastKey:%" PRId64, +// GET_QID(pRuntimeEnv), pBlockInfo->window.skey, pBlockInfo->window.ekey, pBlockInfo->rows, numOfRes, // pQuery->current->lastKey); // // return key; @@ -3903,7 +3903,7 @@ static int32_t setupQueryHandle(void* tsdb, SQInfo* pQInfo, bool isSTableQuery) terrno = TSDB_CODE_SUCCESS; if (isFirstLastRowQuery(pQuery)) { - pRuntimeEnv->pQueryHandle = tsdbQueryLastRow(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo, &pQuery->memRef); + pRuntimeEnv->pQueryHandle = tsdbQueryLastRow(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo->qId, &pQuery->memRef); // update the query time window pQuery->window = cond.twindow; @@ -3924,9 +3924,9 @@ static int32_t setupQueryHandle(void* tsdb, SQInfo* pQInfo, bool isSTableQuery) } } } else if (isPointInterpoQuery(pQuery)) { - pRuntimeEnv->pQueryHandle = tsdbQueryRowsInExternalWindow(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo, &pQuery->memRef); + pRuntimeEnv->pQueryHandle = tsdbQueryRowsInExternalWindow(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo->qId, &pQuery->memRef); } else { - pRuntimeEnv->pQueryHandle = tsdbQueryTables(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo, &pQuery->memRef); + pRuntimeEnv->pQueryHandle = tsdbQueryTables(tsdb, &cond, &pQuery->tableGroupInfo, pQInfo->qId, &pQuery->memRef); } return terrno; @@ -3969,7 +3969,6 @@ int32_t doInitQInfo(SQInfo *pQInfo, STSBuf *pTsBuf, SArray* prevResult, void *ts pQuery->stabledev = isStabledev(pQuery); pRuntimeEnv->prevResult = prevResult; - pRuntimeEnv->qinfo = pQInfo; setScanLimitationByResultBuffer(pQuery); @@ -4013,7 +4012,7 @@ int32_t doInitQInfo(SQInfo *pQInfo, STSBuf *pTsBuf, SArray* prevResult, void *ts getIntermediateBufInfo(pRuntimeEnv, &ps, &pQuery->intermediateResultRowSize); int32_t TENMB = 1024*1024*10; - code = createDiskbasedResultBuffer(&pRuntimeEnv->pResultBuf, ps, TENMB, pQInfo); + code = createDiskbasedResultBuffer(&pRuntimeEnv->pResultBuf, ps, TENMB, pQInfo->qId); if (code != TSDB_CODE_SUCCESS) { return code; } @@ -4181,8 +4180,8 @@ static SSDataBlock* doTableScan(void* param) { pResultRowInfo->prevSKey = pResultRowInfo->pResult[0]->win.skey; } - qDebug("QInfo:%p start to repeat scan data blocks due to query func required, qrange:%" PRId64 "-%" PRId64, - pRuntimeEnv->qinfo, cond.twindow.skey, cond.twindow.ekey); + qDebug("QInfo:%"PRIu64" start to repeat scan data blocks due to query func required, qrange:%" PRId64 "-%" PRId64, + GET_QID(pRuntimeEnv), cond.twindow.skey, cond.twindow.ekey); } if (pTableScanInfo->reverseTimes > 0) { @@ -4191,8 +4190,8 @@ static SSDataBlock* doTableScan(void* param) { STsdbQueryCond cond = createTsdbQueryCond(pQuery, &pQuery->window); tsdbResetQueryHandle(pTableScanInfo->pQueryHandle, &cond); - qDebug("QInfo:%p start to reverse scan data blocks due to query func required, qrange:%" PRId64 "-%" PRId64, - pRuntimeEnv->qinfo, cond.twindow.skey, cond.twindow.ekey); + qDebug("QInfo:%"PRIu64" start to reverse scan data blocks due to query func required, qrange:%" PRId64 "-%" PRId64, + GET_QID(pRuntimeEnv), cond.twindow.skey, cond.twindow.ekey); pRuntimeEnv->scanFlag = REVERSE_SCAN; @@ -5261,14 +5260,14 @@ static SSDataBlock* doTagScan(void* param) { count += 1; } - qDebug("QInfo:%p create (tableId, tag) info completed, rows:%d", pRuntimeEnv->qinfo, count); + qDebug("QInfo:%"PRIu64" create (tableId, tag) info completed, rows:%d", GET_QID(pRuntimeEnv), count); } else if (functionId == TSDB_FUNC_COUNT) {// handle the "count(tbname)" query SColumnInfoData* pColInfo = taosArrayGet(pRes->pDataBlock, 0); *(int64_t*)pColInfo->pData = pInfo->totalTables; count = 1; pOperator->status = OP_EXEC_DONE; - qDebug("QInfo:%p create count(tbname) query, res:%d rows:1", pRuntimeEnv->qinfo, count); + qDebug("QInfo:%"PRIu64" create count(tbname) query, res:%d rows:1", GET_QID(pRuntimeEnv), count); } else { // return only the tags|table name etc. SExprInfo* pExprInfo = pOperator->pExpr; // todo use the column list instead of exprinfo @@ -5307,7 +5306,7 @@ static SSDataBlock* doTagScan(void* param) { pOperator->status = OP_EXEC_DONE; } - qDebug("QInfo:%p create tag values results completed, rows:%d", pRuntimeEnv->qinfo, count); + qDebug("QInfo:%"PRIu64" create tag values results completed, rows:%d", GET_QID(pRuntimeEnv), count); } pRes->info.rows = count; @@ -5994,7 +5993,7 @@ SSqlGroupbyExpr *createGroupbyExprFromMsg(SQueryTableMsg *pQueryMsg, SColIndex * return pGroupbyExpr; } -static int32_t createFilterInfo(void *pQInfo, SQuery *pQuery) { +static int32_t createFilterInfo(SQuery *pQuery, uint64_t qId) { for (int32_t i = 0; i < pQuery->numOfCols; ++i) { if (pQuery->colList[i].numOfFilters > 0) { pQuery->numOfFilterCols++; @@ -6030,13 +6029,13 @@ static int32_t createFilterInfo(void *pQInfo, SQuery *pQuery) { int32_t lower = pSingleColFilter->filterInfo.lowerRelOptr; int32_t upper = pSingleColFilter->filterInfo.upperRelOptr; if (lower == TSDB_RELATION_INVALID && upper == TSDB_RELATION_INVALID) { - qError("QInfo:%p invalid filter info", pQInfo); + qError("QInfo:%"PRIu64" invalid filter info", qId); return TSDB_CODE_QRY_INVALID_MSG; } pSingleColFilter->fp = getFilterOperator(lower, upper); if (pSingleColFilter->fp == NULL) { - qError("QInfo:%p invalid filter info", pQInfo); + qError("QInfo:%"PRIu64" invalid filter info", qId); return TSDB_CODE_QRY_INVALID_MSG; } @@ -6181,7 +6180,7 @@ SQInfo* createQInfoImpl(SQueryTableMsg* pQueryMsg, SSqlGroupbyExpr* pGroupbyExpr } doUpdateExprColumnIndex(pQuery); - int32_t ret = createFilterInfo(pQInfo, pQuery); + int32_t ret = createFilterInfo(pQuery, pQInfo->qId); if (ret != TSDB_CODE_SUCCESS) { goto _cleanup; } @@ -6256,7 +6255,7 @@ SQInfo* createQInfoImpl(SQueryTableMsg* pQueryMsg, SSqlGroupbyExpr* pGroupbyExpr } } - colIdCheck(pQuery, pQInfo); + colIdCheck(pQuery, pQInfo->qId); // todo refactor pQInfo->query.queryBlockDist = (numOfOutput == 1 && pExprs[0].base.colInfo.colId == TSDB_BLOCK_DIST_COLUMN_INDEX); @@ -6308,7 +6307,9 @@ int32_t initQInfo(SQueryTableMsg *pQueryMsg, void *tsdb, int32_t vgId, SQInfo *p int32_t code = TSDB_CODE_SUCCESS; SQueryRuntimeEnv* pRuntimeEnv = &pQInfo->runtimeEnv; - SQuery *pQuery = pQInfo->runtimeEnv.pQuery; + pRuntimeEnv->qinfo = pQInfo; + + SQuery *pQuery = pRuntimeEnv->pQuery; STSBuf *pTsBuf = NULL; if (pQueryMsg->tsLen > 0) { // open new file to save the result @@ -6330,7 +6331,7 @@ int32_t initQInfo(SQueryTableMsg *pQueryMsg, void *tsdb, int32_t vgId, SQInfo *p if ((QUERY_IS_ASC_QUERY(pQuery) && (pQuery->window.skey > pQuery->window.ekey)) || (!QUERY_IS_ASC_QUERY(pQuery) && (pQuery->window.ekey > pQuery->window.skey))) { - qDebug("QInfo:%p no result in time range %" PRId64 "-%" PRId64 ", order %d", pQInfo, pQuery->window.skey, + qDebug("QInfo:%"PRIu64" no result in time range %" PRId64 "-%" PRId64 ", order %d", pQInfo->qId, pQuery->window.skey, pQuery->window.ekey, pQuery->order.order); setQueryStatus(pRuntimeEnv, QUERY_COMPLETED); pRuntimeEnv->tableqinfoGroupInfo.numOfTables = 0; @@ -6339,7 +6340,7 @@ int32_t initQInfo(SQueryTableMsg *pQueryMsg, void *tsdb, int32_t vgId, SQInfo *p } if (pRuntimeEnv->tableqinfoGroupInfo.numOfTables == 0) { - qDebug("QInfo:%p no table qualified for tag filter, abort query", pQInfo); + qDebug("QInfo:%"PRIu64" no table qualified for tag filter, abort query", pQInfo->qId); setQueryStatus(pRuntimeEnv, QUERY_COMPLETED); return TSDB_CODE_SUCCESS; } @@ -6416,7 +6417,7 @@ void freeQInfo(SQInfo *pQInfo) { return; } - qDebug("QInfo:%p start to free QInfo", pQInfo); + qDebug("QInfo:%"PRIu64" start to free QInfo", pQInfo->qId); SQueryRuntimeEnv* pRuntimeEnv = &pQInfo->runtimeEnv; releaseQueryBuf(pRuntimeEnv->tableqinfoGroupInfo.numOfTables); @@ -6465,7 +6466,7 @@ void freeQInfo(SQInfo *pQInfo) { taosArrayDestroy(pRuntimeEnv->groupResInfo.pRows); pQInfo->signature = 0; - qDebug("QInfo:%p QInfo is freed", pQInfo); + qDebug("QInfo:%"PRIu64" QInfo is freed", pQInfo->qId); tfree(pQInfo); } @@ -6485,7 +6486,7 @@ int32_t doDumpQueryResult(SQInfo *pQInfo, char *data) { off_t s = lseek(fileno(f), 0, SEEK_END); assert(s == pRuntimeEnv->outputBuf->info.rows); - qDebug("QInfo:%p ts comp data return, file:%p, size:%"PRId64, pQInfo, f, (uint64_t)s); + qDebug("QInfo:%"PRIu64" ts comp data return, file:%p, size:%"PRId64, pQInfo->qId, f, (uint64_t)s); if (fseek(f, 0, SEEK_SET) >= 0) { size_t sz = fread(data, 1, s, f); if(sz < s) { // todo handle error @@ -6516,11 +6517,11 @@ int32_t doDumpQueryResult(SQInfo *pQInfo, char *data) { } pRuntimeEnv->resultInfo.total += pRuntimeEnv->outputBuf->info.rows; - qDebug("QInfo:%p current numOfRes rows:%d, total:%" PRId64, pQInfo, + qDebug("QInfo:%"PRIu64" current numOfRes rows:%d, total:%" PRId64, pQInfo->qId, pRuntimeEnv->outputBuf->info.rows, pRuntimeEnv->resultInfo.total); if (pQuery->limit.limit > 0 && pQuery->limit.limit == pRuntimeEnv->resultInfo.total) { - qDebug("QInfo:%p results limitation reached, limitation:%"PRId64, pQInfo, pQuery->limit.limit); + qDebug("QInfo:%"PRIu64" results limitation reached, limitation:%"PRId64, pQInfo->qId, pQuery->limit.limit); setQueryStatus(pRuntimeEnv, QUERY_OVER); } diff --git a/src/query/src/qPercentile.c b/src/query/src/qPercentile.c index d366646172..e3326cc26b 100644 --- a/src/query/src/qPercentile.c +++ b/src/query/src/qPercentile.c @@ -254,7 +254,7 @@ tMemBucket *tMemBucketCreate(int16_t nElemSize, int16_t dataType, double minval, resetSlotInfo(pBucket); - int32_t ret = createDiskbasedResultBuffer(&pBucket->pBuffer, pBucket->bufPageSize, pBucket->bufPageSize * 512, NULL); + int32_t ret = createDiskbasedResultBuffer(&pBucket->pBuffer, pBucket->bufPageSize, pBucket->bufPageSize * 512, 1); if (ret != TSDB_CODE_SUCCESS) { tMemBucketDestroy(pBucket); return NULL; diff --git a/src/query/src/qResultbuf.c b/src/query/src/qResultbuf.c index ed7f8c6719..c5dd6b3cac 100644 --- a/src/query/src/qResultbuf.c +++ b/src/query/src/qResultbuf.c @@ -9,7 +9,7 @@ #define GET_DATA_PAYLOAD(_p) ((char *)(_p)->pData + POINTER_BYTES) #define NO_IN_MEM_AVAILABLE_PAGES(_b) (listNEles((_b)->lruList) >= (_b)->inMemPages) -int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pagesize, int32_t inMemBufSize, const void* handle) { +int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId) { *pResultBuf = calloc(1, sizeof(SDiskbasedResultBuf)); SDiskbasedResultBuf* pResBuf = *pResultBuf; @@ -24,7 +24,7 @@ int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pa pResBuf->allocateId = -1; pResBuf->comp = true; pResBuf->file = NULL; - pResBuf->handle = handle; + pResBuf->qId = qId; pResBuf->fileSize = 0; // at least more than 2 pages must be in memory @@ -43,7 +43,7 @@ int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t pa pResBuf->emptyDummyIdList = taosArrayInit(1, sizeof(int32_t)); - qDebug("QInfo:%p create resBuf for output, page size:%d, inmem buf pages:%d, file:%s", handle, pResBuf->pageSize, + qDebug("QInfo:%"PRIu64" create resBuf for output, page size:%d, inmem buf pages:%d, file:%s", qId, pResBuf->pageSize, pResBuf->inMemPages, pResBuf->path); return TSDB_CODE_SUCCESS; @@ -406,13 +406,13 @@ void destroyResultBuf(SDiskbasedResultBuf* pResultBuf) { } if (pResultBuf->file != NULL) { - qDebug("QInfo:%p res output buffer closed, total:%.2f Kb, inmem size:%.2f Kb, file size:%.2f Kb", - pResultBuf->handle, pResultBuf->totalBufSize/1024.0, listNEles(pResultBuf->lruList) * pResultBuf->pageSize / 1024.0, + qDebug("QInfo:%"PRIu64" res output buffer closed, total:%.2f Kb, inmem size:%.2f Kb, file size:%.2f Kb", + pResultBuf->qId, pResultBuf->totalBufSize/1024.0, listNEles(pResultBuf->lruList) * pResultBuf->pageSize / 1024.0, pResultBuf->fileSize/1024.0); fclose(pResultBuf->file); } else { - qDebug("QInfo:%p res output buffer closed, total:%.2f Kb, no file created", pResultBuf->handle, + qDebug("QInfo:%"PRIu64" res output buffer closed, total:%.2f Kb, no file created", pResultBuf->qId, pResultBuf->totalBufSize/1024.0); } diff --git a/src/query/src/qSqlParser.c b/src/query/src/qSqlParser.c index e76b78c523..a5fc45fa9c 100644 --- a/src/query/src/qSqlParser.c +++ b/src/query/src/qSqlParser.c @@ -911,6 +911,7 @@ void setDCLSqlElems(SSqlInfo *pInfo, int32_t type, int32_t nParam, ...) { SStrToken *pToken = va_arg(va, SStrToken *); taosArrayPush(pInfo->pMiscInfo->a, pToken); } + va_end(va); } diff --git a/src/query/src/qTokenizer.c b/src/query/src/qTokenizer.c index 013eaaf2a9..52b2fdbb82 100644 --- a/src/query/src/qTokenizer.c +++ b/src/query/src/qTokenizer.c @@ -100,6 +100,7 @@ static SKeyword keywordTable[] = { {"ACCOUNT", TK_ACCOUNT}, {"USE", TK_USE}, {"DESCRIBE", TK_DESCRIBE}, + {"SYNCDB", TK_SYNCDB}, {"ALTER", TK_ALTER}, {"PASS", TK_PASS}, {"PRIVILEGE", TK_PRIVILEGE}, diff --git a/src/query/src/qUtil.c b/src/query/src/qUtil.c index 1e7d3c9b58..da7dbcd501 100644 --- a/src/query/src/qUtil.c +++ b/src/query/src/qUtil.c @@ -468,7 +468,7 @@ static int32_t mergeIntoGroupResultImpl(SQueryRuntimeEnv *pRuntimeEnv, SGroupRes pTableQueryInfoList = malloc(POINTER_BYTES * size); if (pTableQueryInfoList == NULL || posList == NULL || pGroupResInfo->pRows == NULL || pGroupResInfo->pRows == NULL) { - qError("QInfo:%p failed alloc memory", pRuntimeEnv->qinfo); + qError("QInfo:%"PRIu64" failed alloc memory", GET_QID(pRuntimeEnv)); code = TSDB_CODE_QRY_OUT_OF_MEMORY; goto _end; } @@ -540,7 +540,7 @@ static int32_t mergeIntoGroupResultImpl(SQueryRuntimeEnv *pRuntimeEnv, SGroupRes int64_t endt = taosGetTimestampMs(); - qDebug("QInfo:%p result merge completed for group:%d, elapsed time:%" PRId64 " ms", pRuntimeEnv->qinfo, + qDebug("QInfo:%"PRIu64" result merge completed for group:%d, elapsed time:%" PRId64 " ms", GET_QID(pRuntimeEnv), pGroupResInfo->currentGroup, endt - startt); _end: @@ -567,13 +567,13 @@ int32_t mergeIntoGroupResult(SGroupResInfo* pGroupResInfo, SQueryRuntimeEnv* pRu break; } - qDebug("QInfo:%p no result in group %d, continue", pRuntimeEnv->qinfo, pGroupResInfo->currentGroup); + qDebug("QInfo:%"PRIu64" no result in group %d, continue", GET_QID(pRuntimeEnv), pGroupResInfo->currentGroup); cleanupGroupResInfo(pGroupResInfo); incNextGroup(pGroupResInfo); } int64_t elapsedTime = taosGetTimestampUs() - st; - qDebug("QInfo:%p merge res data into group, index:%d, total group:%d, elapsed time:%" PRId64 "us", pRuntimeEnv->qinfo, + qDebug("QInfo:%"PRIu64" merge res data into group, index:%d, total group:%d, elapsed time:%" PRId64 "us", GET_QID(pRuntimeEnv), pGroupResInfo->currentGroup, pGroupResInfo->totalGroup, elapsedTime); // pQInfo->summary.firstStageMergeTime += elapsedTime; diff --git a/src/query/src/queryMain.c b/src/query/src/queryMain.c index bba6a10df3..9d2fb70d96 100644 --- a/src/query/src/queryMain.c +++ b/src/query/src/queryMain.c @@ -197,29 +197,30 @@ int32_t qCreateQueryInfo(void* tsdb, int32_t vgId, SQueryTableMsg* pQueryMsg, qi return code; } -bool qTableQuery(qinfo_t qinfo) { +bool qTableQuery(qinfo_t qinfo, uint64_t *qId) { SQInfo *pQInfo = (SQInfo *)qinfo; assert(pQInfo && pQInfo->signature == pQInfo); int64_t threadId = taosGetSelfPthreadId(); int64_t curOwner = 0; if ((curOwner = atomic_val_compare_exchange_64(&pQInfo->owner, 0, threadId)) != 0) { - qError("QInfo:%p qhandle is now executed by thread:%p", pQInfo, (void*) curOwner); + qError("QInfo:%"PRIu64"-%p qhandle is now executed by thread:%p", pQInfo->qId, pQInfo, (void*) curOwner); pQInfo->code = TSDB_CODE_QRY_IN_EXEC; return false; } + *qId = pQInfo->qId; pQInfo->startExecTs = taosGetTimestampSec(); if (isQueryKilled(pQInfo)) { - qDebug("QInfo:%p it is already killed, abort", pQInfo); + qDebug("QInfo:%"PRIu64" it is already killed, abort", pQInfo->qId); return doBuildResCheck(pQInfo); } SQueryRuntimeEnv* pRuntimeEnv = &pQInfo->runtimeEnv; if (pRuntimeEnv->tableqinfoGroupInfo.numOfTables == 0) { - qDebug("QInfo:%p no table exists for query, abort", pQInfo); + qDebug("QInfo:%"PRIu64" no table exists for query, abort", pQInfo->qId); setQueryStatus(pRuntimeEnv, QUERY_COMPLETED); return doBuildResCheck(pQInfo); } @@ -228,22 +229,22 @@ bool qTableQuery(qinfo_t qinfo) { int32_t ret = setjmp(pQInfo->runtimeEnv.env); if (ret != TSDB_CODE_SUCCESS) { pQInfo->code = ret; - qDebug("QInfo:%p query abort due to error/cancel occurs, code:%s", pQInfo, tstrerror(pQInfo->code)); + qDebug("QInfo:%"PRIu64" query abort due to error/cancel occurs, code:%s", pQInfo->qId, tstrerror(pQInfo->code)); return doBuildResCheck(pQInfo); } - qDebug("QInfo:%p query task is launched", pQInfo); + qDebug("QInfo:%"PRIu64" query task is launched", pQInfo->qId); pRuntimeEnv->outputBuf = pRuntimeEnv->proot->exec(pRuntimeEnv->proot); if (isQueryKilled(pQInfo)) { - qDebug("QInfo:%p query is killed", pQInfo); + qDebug("QInfo:%"PRIu64" query is killed", pQInfo->qId); } else if (GET_NUM_OF_RESULTS(pRuntimeEnv) == 0) { - qDebug("QInfo:%p over, %u tables queried, %"PRId64" rows are returned", pQInfo, pRuntimeEnv->tableqinfoGroupInfo.numOfTables, + qDebug("QInfo:%"PRIu64" over, %u tables queried, %"PRId64" rows are returned", pQInfo->qId, pRuntimeEnv->tableqinfoGroupInfo.numOfTables, pRuntimeEnv->resultInfo.total); } else { - qDebug("QInfo:%p query paused, %d rows returned, numOfTotal:%" PRId64 " rows", - pQInfo, GET_NUM_OF_RESULTS(pRuntimeEnv), pRuntimeEnv->resultInfo.total + GET_NUM_OF_RESULTS(pRuntimeEnv)); + qDebug("QInfo:%"PRIu64" query paused, %d rows returned, numOfTotal:%" PRId64 " rows", + pQInfo->qId, GET_NUM_OF_RESULTS(pRuntimeEnv), pRuntimeEnv->resultInfo.total + GET_NUM_OF_RESULTS(pRuntimeEnv)); } return doBuildResCheck(pQInfo); @@ -253,13 +254,13 @@ int32_t qRetrieveQueryResultInfo(qinfo_t qinfo, bool* buildRes, void* pRspContex SQInfo *pQInfo = (SQInfo *)qinfo; if (pQInfo == NULL || !isValidQInfo(pQInfo)) { - qError("QInfo:%p invalid qhandle", pQInfo); + qError("QInfo:%"PRIu64" invalid qhandle", pQInfo->qId); return TSDB_CODE_QRY_INVALID_QHANDLE; } *buildRes = false; if (IS_QUERY_KILLED(pQInfo)) { - qDebug("QInfo:%p query is killed, code:0x%08x", pQInfo, pQInfo->code); + qDebug("QInfo:%"PRIu64" query is killed, code:0x%08x", pQInfo->qId, pQInfo->code); return pQInfo->code; } @@ -279,11 +280,11 @@ int32_t qRetrieveQueryResultInfo(qinfo_t qinfo, bool* buildRes, void* pRspContex assert(pQInfo->rspContext == NULL); if (pQInfo->dataReady == QUERY_RESULT_READY) { *buildRes = true; - qDebug("QInfo:%p retrieve result info, rowsize:%d, rows:%d, code:%s", pQInfo, pQuery->resultRowSize, + qDebug("QInfo:%"PRIu64" retrieve result info, rowsize:%d, rows:%d, code:%s", pQInfo->qId, pQuery->resultRowSize, GET_NUM_OF_RESULTS(pRuntimeEnv), tstrerror(pQInfo->code)); } else { *buildRes = false; - qDebug("QInfo:%p retrieve req set query return result after paused", pQInfo); + qDebug("QInfo:%"PRIu64" retrieve req set query return result after paused", pQInfo->qId); pQInfo->rspContext = pRspContext; assert(pQInfo->rspContext != NULL); } @@ -342,9 +343,10 @@ int32_t qDumpRetrieveResult(qinfo_t qinfo, SRetrieveTableRsp **pRsp, int32_t *co // here current thread hold the refcount, so it is safe to free tsdbQueryHandle. *continueExec = false; (*pRsp)->completed = 1; // notify no more result to client + qDebug("QInfo:%"PRIu64" no more results to retrieve", pQInfo->qId); } else { *continueExec = true; - qDebug("QInfo:%p has more results to retrieve", pQInfo); + qDebug("QInfo:%"PRIu64" has more results to retrieve", pQInfo->qId); } // the memory should be freed if the code of pQInfo is not TSDB_CODE_SUCCESS @@ -397,7 +399,7 @@ void qDestroyQueryInfo(qinfo_t qHandle) { return; } - qDebug("QInfo:%p query completed", pQInfo); + qDebug("QInfo:%"PRIu64" query completed", pQInfo->qId); queryCostStatis(pQInfo); // print the query cost summary freeQInfo(pQInfo); } @@ -480,7 +482,7 @@ void** qRegisterQInfo(void* pMgmt, uint64_t qId, uint64_t qInfo) { SQueryMgmt *pQueryMgmt = pMgmt; if (pQueryMgmt->qinfoPool == NULL) { - qError("QInfo:%p failed to add qhandle into qMgmt, since qMgmt is closed", (void *)qInfo); + qError("QInfo:%"PRIu64"-%p failed to add qhandle into qMgmt, since qMgmt is closed", qId, (void*)qInfo); terrno = TSDB_CODE_VND_INVALID_VGROUP_ID; return NULL; } @@ -488,7 +490,7 @@ void** qRegisterQInfo(void* pMgmt, uint64_t qId, uint64_t qInfo) { pthread_mutex_lock(&pQueryMgmt->lock); if (pQueryMgmt->closed) { pthread_mutex_unlock(&pQueryMgmt->lock); - qError("QInfo:%p failed to add qhandle into cache, since qMgmt is colsing", (void *)qInfo); + qError("QInfo:%"PRIu64"-%p failed to add qhandle into cache, since qMgmt is colsing", qId, (void*)qInfo); terrno = TSDB_CODE_VND_INVALID_VGROUP_ID; return NULL; } else { diff --git a/src/query/src/sql.c b/src/query/src/sql.c index 98304d636f..df7aaaf001 100644 --- a/src/query/src/sql.c +++ b/src/query/src/sql.c @@ -97,28 +97,28 @@ #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int -#define YYNOCODE 263 +#define YYNOCODE 264 #define YYACTIONTYPE unsigned short int #define ParseTOKENTYPE SStrToken typedef union { int yyinit; ParseTOKENTYPE yy0; - SLimitVal yy18; - SFromInfo* yy70; - SSessionWindowVal yy87; - SCreateDbInfo yy94; - int yy116; - SSubclauseInfo* yy141; - tSqlExpr* yy170; - SCreateTableSql* yy194; - tVariant yy218; - SIntervalVal yy220; - SCreatedTableInfo yy252; - SQuerySqlNode* yy254; - SCreateAcctInfo yy419; - SArray* yy429; - TAOS_FIELD yy451; - int64_t yy481; + SCreateTableSql* yy14; + int yy20; + tSqlExpr* yy118; + SArray* yy159; + SIntervalVal yy184; + SCreatedTableInfo yy206; + SSessionWindowVal yy249; + SQuerySqlNode* yy272; + int64_t yy317; + SCreateDbInfo yy322; + SCreateAcctInfo yy351; + SSubclauseInfo* yy391; + TAOS_FIELD yy407; + SLimitVal yy440; + tVariant yy488; + SFromInfo* yy514; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -128,17 +128,17 @@ typedef union { #define ParseARG_FETCH SSqlInfo* pInfo = yypParser->pInfo #define ParseARG_STORE yypParser->pInfo = pInfo #define YYFALLBACK 1 -#define YYNSTATE 313 -#define YYNRULE 265 -#define YYNTOKEN 186 -#define YY_MAX_SHIFT 312 -#define YY_MIN_SHIFTREDUCE 502 -#define YY_MAX_SHIFTREDUCE 766 -#define YY_ERROR_ACTION 767 -#define YY_ACCEPT_ACTION 768 -#define YY_NO_ACTION 769 -#define YY_MIN_REDUCE 770 -#define YY_MAX_REDUCE 1034 +#define YYNSTATE 315 +#define YYNRULE 266 +#define YYNTOKEN 187 +#define YY_MAX_SHIFT 314 +#define YY_MIN_SHIFTREDUCE 505 +#define YY_MAX_SHIFTREDUCE 770 +#define YY_ERROR_ACTION 771 +#define YY_ACCEPT_ACTION 772 +#define YY_NO_ACTION 773 +#define YY_MIN_REDUCE 774 +#define YY_MAX_REDUCE 1039 /************* End control #defines *******************************************/ /* Define the yytestcase() macro to be a no-op if is not already defined @@ -204,259 +204,259 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (676) +#define YY_ACTTAB_COUNT (679) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 910, 549, 201, 310, 205, 139, 937, 3, 166, 550, - /* 10 */ 768, 312, 17, 47, 48, 139, 51, 52, 30, 180, - /* 20 */ 213, 41, 180, 50, 260, 55, 53, 57, 54, 1016, - /* 30 */ 916, 208, 1017, 46, 45, 178, 180, 44, 43, 42, - /* 40 */ 47, 48, 219, 51, 52, 207, 1017, 213, 41, 549, - /* 50 */ 50, 260, 55, 53, 57, 54, 928, 550, 184, 202, - /* 60 */ 46, 45, 913, 218, 44, 43, 42, 48, 934, 51, - /* 70 */ 52, 240, 968, 213, 41, 549, 50, 260, 55, 53, - /* 80 */ 57, 54, 969, 550, 255, 220, 46, 45, 276, 916, - /* 90 */ 44, 43, 42, 503, 504, 505, 506, 507, 508, 509, - /* 100 */ 510, 511, 512, 513, 514, 515, 311, 628, 84, 230, - /* 110 */ 69, 916, 1013, 47, 48, 30, 51, 52, 296, 30, - /* 120 */ 213, 41, 549, 50, 260, 55, 53, 57, 54, 64, - /* 130 */ 550, 306, 714, 46, 45, 286, 285, 44, 43, 42, - /* 140 */ 47, 49, 904, 51, 52, 224, 1012, 213, 41, 65, - /* 150 */ 50, 260, 55, 53, 57, 54, 216, 916, 902, 913, - /* 160 */ 46, 45, 222, 912, 44, 43, 42, 23, 274, 305, - /* 170 */ 304, 273, 272, 271, 303, 270, 302, 301, 300, 269, - /* 180 */ 299, 298, 876, 139, 864, 865, 866, 867, 868, 869, - /* 190 */ 870, 871, 872, 873, 874, 875, 877, 878, 51, 52, - /* 200 */ 815, 139, 213, 41, 165, 50, 260, 55, 53, 57, - /* 210 */ 54, 1011, 18, 81, 226, 46, 45, 283, 282, 44, - /* 220 */ 43, 42, 212, 727, 928, 25, 718, 68, 721, 189, - /* 230 */ 724, 223, 212, 727, 278, 190, 718, 276, 721, 203, - /* 240 */ 724, 117, 116, 188, 899, 900, 29, 903, 257, 233, - /* 250 */ 77, 44, 43, 42, 209, 210, 237, 236, 259, 901, - /* 260 */ 23, 197, 305, 304, 209, 210, 225, 303, 78, 302, - /* 270 */ 301, 300, 73, 299, 298, 884, 104, 30, 882, 883, - /* 280 */ 36, 296, 720, 885, 723, 887, 888, 886, 667, 889, - /* 290 */ 890, 55, 53, 57, 54, 132, 309, 308, 125, 46, - /* 300 */ 45, 914, 239, 44, 43, 42, 102, 107, 30, 196, - /* 310 */ 664, 73, 96, 106, 112, 115, 105, 24, 217, 36, - /* 320 */ 674, 913, 109, 5, 155, 56, 261, 79, 243, 33, - /* 330 */ 154, 91, 86, 90, 30, 56, 173, 169, 726, 30, - /* 340 */ 70, 30, 171, 168, 120, 119, 118, 12, 726, 279, - /* 350 */ 211, 83, 913, 80, 725, 824, 46, 45, 245, 165, - /* 360 */ 44, 43, 42, 198, 725, 816, 671, 652, 182, 165, - /* 370 */ 649, 719, 650, 722, 651, 280, 1, 153, 913, 716, - /* 380 */ 284, 61, 288, 913, 183, 913, 241, 695, 696, 680, - /* 390 */ 31, 686, 687, 134, 6, 60, 20, 747, 227, 228, - /* 400 */ 728, 19, 638, 62, 19, 263, 31, 640, 265, 31, - /* 410 */ 639, 60, 82, 28, 60, 717, 266, 95, 94, 14, - /* 420 */ 13, 67, 730, 627, 185, 101, 100, 179, 16, 15, - /* 430 */ 979, 656, 654, 657, 655, 114, 113, 130, 128, 186, - /* 440 */ 187, 193, 194, 192, 177, 191, 181, 1026, 915, 978, - /* 450 */ 214, 975, 974, 215, 287, 131, 39, 936, 944, 946, - /* 460 */ 133, 137, 929, 244, 129, 150, 961, 960, 911, 909, - /* 470 */ 149, 679, 246, 151, 204, 152, 653, 250, 258, 827, - /* 480 */ 140, 66, 141, 268, 37, 63, 175, 926, 34, 277, - /* 490 */ 248, 823, 253, 142, 1031, 58, 92, 1030, 1028, 256, - /* 500 */ 156, 143, 281, 1025, 98, 1024, 1022, 254, 157, 845, - /* 510 */ 35, 32, 38, 252, 176, 812, 108, 810, 110, 111, - /* 520 */ 808, 807, 229, 167, 805, 804, 803, 802, 801, 800, - /* 530 */ 170, 172, 797, 795, 793, 791, 789, 174, 247, 242, - /* 540 */ 71, 74, 249, 962, 40, 297, 103, 289, 290, 291, - /* 550 */ 292, 293, 294, 295, 199, 221, 307, 766, 231, 232, - /* 560 */ 267, 765, 234, 235, 764, 200, 238, 87, 88, 752, - /* 570 */ 195, 243, 75, 8, 262, 806, 72, 659, 681, 135, - /* 580 */ 76, 121, 159, 846, 160, 161, 158, 162, 164, 122, - /* 590 */ 163, 799, 2, 123, 880, 124, 798, 790, 684, 144, - /* 600 */ 147, 145, 146, 4, 136, 148, 892, 206, 251, 26, - /* 610 */ 688, 138, 9, 10, 729, 27, 7, 11, 21, 731, - /* 620 */ 22, 85, 264, 591, 587, 83, 585, 584, 583, 580, - /* 630 */ 553, 275, 93, 89, 31, 630, 59, 97, 629, 99, - /* 640 */ 626, 575, 573, 565, 571, 567, 569, 563, 561, 594, - /* 650 */ 593, 592, 590, 589, 588, 586, 582, 581, 60, 551, - /* 660 */ 519, 517, 770, 769, 769, 769, 769, 769, 769, 769, - /* 670 */ 769, 769, 769, 769, 126, 127, + /* 0 */ 133, 552, 202, 312, 206, 140, 941, 17, 85, 553, + /* 10 */ 772, 314, 179, 47, 48, 140, 51, 52, 30, 181, + /* 20 */ 214, 41, 181, 50, 262, 55, 53, 57, 54, 1020, + /* 30 */ 920, 209, 1021, 46, 45, 185, 181, 44, 43, 42, + /* 40 */ 47, 48, 908, 51, 52, 208, 1021, 214, 41, 552, + /* 50 */ 50, 262, 55, 53, 57, 54, 932, 553, 1017, 203, + /* 60 */ 46, 45, 917, 247, 44, 43, 42, 48, 938, 51, + /* 70 */ 52, 242, 972, 214, 41, 552, 50, 262, 55, 53, + /* 80 */ 57, 54, 973, 553, 257, 278, 46, 45, 298, 225, + /* 90 */ 44, 43, 42, 506, 507, 508, 509, 510, 511, 512, + /* 100 */ 513, 514, 515, 516, 517, 518, 313, 631, 1016, 231, + /* 110 */ 70, 552, 30, 47, 48, 1015, 51, 52, 819, 553, + /* 120 */ 214, 41, 166, 50, 262, 55, 53, 57, 54, 44, + /* 130 */ 43, 42, 717, 46, 45, 288, 287, 44, 43, 42, + /* 140 */ 47, 49, 198, 51, 52, 140, 140, 214, 41, 234, + /* 150 */ 50, 262, 55, 53, 57, 54, 916, 238, 237, 227, + /* 160 */ 46, 45, 285, 284, 44, 43, 42, 23, 276, 307, + /* 170 */ 306, 275, 274, 273, 305, 272, 304, 303, 302, 271, + /* 180 */ 301, 300, 880, 30, 868, 869, 870, 871, 872, 873, + /* 190 */ 874, 875, 876, 877, 878, 879, 881, 882, 51, 52, + /* 200 */ 18, 30, 214, 41, 906, 50, 262, 55, 53, 57, + /* 210 */ 54, 259, 79, 78, 25, 46, 45, 190, 199, 44, + /* 220 */ 43, 42, 82, 191, 217, 28, 30, 917, 268, 118, + /* 230 */ 117, 189, 12, 213, 730, 932, 84, 721, 81, 724, + /* 240 */ 74, 727, 218, 213, 730, 917, 80, 721, 36, 724, + /* 250 */ 204, 727, 30, 903, 904, 29, 907, 46, 45, 71, + /* 260 */ 74, 44, 43, 42, 223, 210, 211, 281, 36, 261, + /* 270 */ 917, 23, 914, 307, 306, 210, 211, 723, 305, 726, + /* 280 */ 304, 303, 302, 278, 301, 300, 311, 310, 126, 677, + /* 290 */ 241, 888, 68, 282, 886, 887, 917, 245, 197, 889, + /* 300 */ 219, 891, 892, 890, 670, 893, 894, 55, 53, 57, + /* 310 */ 54, 1, 154, 263, 220, 46, 45, 30, 221, 44, + /* 320 */ 43, 42, 105, 103, 108, 308, 920, 298, 69, 97, + /* 330 */ 107, 113, 116, 106, 224, 655, 56, 280, 652, 110, + /* 340 */ 653, 226, 654, 30, 920, 667, 56, 5, 156, 729, + /* 350 */ 183, 920, 24, 33, 155, 92, 87, 91, 286, 729, + /* 360 */ 905, 917, 174, 170, 719, 728, 228, 229, 172, 169, + /* 370 */ 121, 120, 119, 828, 820, 728, 918, 166, 166, 3, + /* 380 */ 167, 243, 674, 212, 290, 31, 683, 917, 698, 699, + /* 390 */ 135, 689, 690, 750, 731, 60, 20, 19, 19, 722, + /* 400 */ 720, 725, 61, 64, 641, 184, 265, 643, 31, 733, + /* 410 */ 31, 60, 267, 642, 115, 114, 83, 60, 96, 95, + /* 420 */ 186, 14, 13, 65, 62, 180, 187, 6, 102, 101, + /* 430 */ 67, 188, 630, 16, 15, 659, 657, 660, 658, 131, + /* 440 */ 129, 194, 195, 193, 656, 178, 192, 182, 1031, 919, + /* 450 */ 983, 239, 982, 215, 979, 978, 216, 289, 39, 132, + /* 460 */ 940, 948, 950, 130, 134, 933, 138, 246, 965, 964, + /* 470 */ 151, 915, 150, 682, 248, 913, 205, 299, 104, 884, + /* 480 */ 160, 260, 152, 153, 145, 143, 141, 831, 270, 66, + /* 490 */ 250, 930, 63, 255, 37, 176, 34, 279, 58, 142, + /* 500 */ 827, 1036, 93, 1035, 1033, 157, 283, 1030, 99, 1029, + /* 510 */ 1027, 158, 849, 35, 258, 32, 38, 256, 177, 816, + /* 520 */ 109, 814, 111, 112, 254, 812, 811, 230, 168, 252, + /* 530 */ 809, 808, 807, 806, 805, 804, 171, 173, 801, 799, + /* 540 */ 797, 795, 793, 175, 249, 244, 72, 75, 40, 251, + /* 550 */ 966, 291, 292, 293, 294, 295, 296, 297, 309, 200, + /* 560 */ 222, 770, 269, 232, 233, 769, 235, 201, 196, 88, + /* 570 */ 89, 236, 768, 756, 755, 240, 245, 8, 810, 662, + /* 580 */ 122, 161, 123, 165, 163, 803, 850, 159, 162, 164, + /* 590 */ 124, 802, 73, 125, 794, 4, 2, 264, 76, 684, + /* 600 */ 136, 137, 687, 77, 144, 148, 146, 147, 149, 896, + /* 610 */ 207, 253, 26, 691, 139, 27, 9, 732, 10, 7, + /* 620 */ 734, 11, 21, 266, 22, 86, 594, 84, 590, 588, + /* 630 */ 587, 586, 583, 556, 277, 31, 59, 90, 633, 94, + /* 640 */ 632, 629, 578, 98, 100, 576, 568, 574, 570, 572, + /* 650 */ 566, 564, 597, 596, 595, 593, 592, 591, 589, 585, + /* 660 */ 584, 60, 554, 522, 520, 774, 773, 773, 773, 773, + /* 670 */ 773, 773, 773, 773, 773, 773, 773, 127, 128, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 190, 1, 189, 190, 209, 190, 190, 193, 194, 9, - /* 10 */ 187, 188, 251, 13, 14, 190, 16, 17, 190, 251, - /* 20 */ 20, 21, 251, 23, 24, 25, 26, 27, 28, 261, - /* 30 */ 235, 260, 261, 33, 34, 251, 251, 37, 38, 39, - /* 40 */ 13, 14, 232, 16, 17, 260, 261, 20, 21, 1, - /* 50 */ 23, 24, 25, 26, 27, 28, 233, 9, 251, 231, - /* 60 */ 33, 34, 234, 209, 37, 38, 39, 14, 252, 16, - /* 70 */ 17, 248, 257, 20, 21, 1, 23, 24, 25, 26, - /* 80 */ 27, 28, 257, 9, 259, 209, 33, 34, 79, 235, + /* 0 */ 191, 1, 190, 191, 210, 191, 191, 252, 197, 9, + /* 10 */ 188, 189, 252, 13, 14, 191, 16, 17, 191, 252, + /* 20 */ 20, 21, 252, 23, 24, 25, 26, 27, 28, 262, + /* 30 */ 236, 261, 262, 33, 34, 252, 252, 37, 38, 39, + /* 40 */ 13, 14, 231, 16, 17, 261, 262, 20, 21, 1, + /* 50 */ 23, 24, 25, 26, 27, 28, 234, 9, 252, 232, + /* 60 */ 33, 34, 235, 254, 37, 38, 39, 14, 253, 16, + /* 70 */ 17, 249, 258, 20, 21, 1, 23, 24, 25, 26, + /* 80 */ 27, 28, 258, 9, 260, 79, 33, 34, 81, 67, /* 90 */ 37, 38, 39, 45, 46, 47, 48, 49, 50, 51, - /* 100 */ 52, 53, 54, 55, 56, 57, 58, 5, 196, 61, - /* 110 */ 110, 235, 251, 13, 14, 190, 16, 17, 81, 190, - /* 120 */ 20, 21, 1, 23, 24, 25, 26, 27, 28, 109, - /* 130 */ 9, 209, 105, 33, 34, 33, 34, 37, 38, 39, - /* 140 */ 13, 14, 230, 16, 17, 67, 251, 20, 21, 129, - /* 150 */ 23, 24, 25, 26, 27, 28, 231, 235, 0, 234, - /* 160 */ 33, 34, 67, 234, 37, 38, 39, 88, 89, 90, + /* 100 */ 52, 53, 54, 55, 56, 57, 58, 5, 252, 61, + /* 110 */ 110, 1, 191, 13, 14, 252, 16, 17, 196, 9, + /* 120 */ 20, 21, 200, 23, 24, 25, 26, 27, 28, 37, + /* 130 */ 38, 39, 105, 33, 34, 33, 34, 37, 38, 39, + /* 140 */ 13, 14, 252, 16, 17, 191, 191, 20, 21, 135, + /* 150 */ 23, 24, 25, 26, 27, 28, 235, 143, 144, 137, + /* 160 */ 33, 34, 140, 141, 37, 38, 39, 88, 89, 90, /* 170 */ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - /* 180 */ 101, 102, 208, 190, 210, 211, 212, 213, 214, 215, - /* 190 */ 216, 217, 218, 219, 220, 221, 222, 223, 16, 17, - /* 200 */ 195, 190, 20, 21, 199, 23, 24, 25, 26, 27, - /* 210 */ 28, 251, 44, 196, 136, 33, 34, 139, 140, 37, - /* 220 */ 38, 39, 1, 2, 233, 104, 5, 196, 7, 61, - /* 230 */ 9, 136, 1, 2, 139, 67, 5, 79, 7, 248, - /* 240 */ 9, 73, 74, 75, 227, 228, 229, 230, 255, 135, - /* 250 */ 257, 37, 38, 39, 33, 34, 142, 143, 37, 228, - /* 260 */ 88, 251, 90, 91, 33, 34, 190, 95, 257, 97, - /* 270 */ 98, 99, 104, 101, 102, 208, 76, 190, 211, 212, - /* 280 */ 112, 81, 5, 216, 7, 218, 219, 220, 37, 222, - /* 290 */ 223, 25, 26, 27, 28, 190, 64, 65, 66, 33, - /* 300 */ 34, 225, 134, 37, 38, 39, 62, 63, 190, 141, - /* 310 */ 109, 104, 68, 69, 70, 71, 72, 116, 231, 112, - /* 320 */ 105, 234, 78, 62, 63, 104, 15, 236, 113, 68, - /* 330 */ 69, 70, 71, 72, 190, 104, 62, 63, 117, 190, - /* 340 */ 249, 190, 68, 69, 70, 71, 72, 104, 117, 231, - /* 350 */ 60, 108, 234, 110, 133, 195, 33, 34, 253, 199, - /* 360 */ 37, 38, 39, 251, 133, 195, 115, 2, 251, 199, - /* 370 */ 5, 5, 7, 7, 9, 231, 197, 198, 234, 1, - /* 380 */ 231, 109, 231, 234, 251, 234, 105, 124, 125, 105, - /* 390 */ 109, 105, 105, 109, 104, 109, 109, 105, 33, 34, - /* 400 */ 105, 109, 105, 131, 109, 105, 109, 105, 105, 109, - /* 410 */ 105, 109, 109, 104, 109, 37, 107, 137, 138, 137, - /* 420 */ 138, 104, 111, 106, 251, 137, 138, 251, 137, 138, - /* 430 */ 226, 5, 5, 7, 7, 76, 77, 62, 63, 251, - /* 440 */ 251, 251, 251, 251, 251, 251, 251, 235, 235, 226, - /* 450 */ 226, 226, 226, 226, 226, 190, 250, 190, 190, 190, - /* 460 */ 190, 190, 233, 233, 60, 190, 258, 258, 233, 190, - /* 470 */ 237, 117, 254, 190, 254, 190, 111, 119, 122, 190, - /* 480 */ 246, 128, 245, 190, 190, 130, 190, 247, 190, 190, - /* 490 */ 254, 190, 254, 244, 190, 127, 190, 190, 190, 126, - /* 500 */ 190, 243, 190, 190, 190, 190, 190, 121, 190, 190, - /* 510 */ 190, 190, 190, 120, 190, 190, 190, 190, 190, 190, - /* 520 */ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, - /* 530 */ 190, 190, 190, 190, 190, 190, 190, 190, 118, 191, - /* 540 */ 191, 191, 191, 191, 132, 103, 87, 86, 50, 83, - /* 550 */ 85, 54, 84, 82, 191, 191, 79, 5, 144, 5, - /* 560 */ 191, 5, 144, 5, 5, 191, 135, 196, 196, 89, - /* 570 */ 191, 113, 109, 104, 107, 191, 114, 105, 105, 104, - /* 580 */ 104, 192, 205, 207, 201, 204, 206, 202, 200, 192, - /* 590 */ 203, 191, 197, 192, 224, 192, 191, 191, 105, 242, - /* 600 */ 239, 241, 240, 193, 109, 238, 224, 1, 104, 109, - /* 610 */ 105, 104, 123, 123, 105, 109, 104, 104, 104, 111, - /* 620 */ 104, 76, 107, 9, 5, 108, 5, 5, 5, 5, - /* 630 */ 80, 15, 138, 76, 109, 5, 16, 138, 5, 138, - /* 640 */ 105, 5, 5, 5, 5, 5, 5, 5, 5, 5, - /* 650 */ 5, 5, 5, 5, 5, 5, 5, 5, 109, 80, - /* 660 */ 60, 59, 0, 262, 262, 262, 262, 262, 262, 262, - /* 670 */ 262, 262, 262, 262, 21, 21, 262, 262, 262, 262, - /* 680 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 690 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 700 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 710 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 720 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 730 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 740 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 750 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 760 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 770 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 780 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 790 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 800 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 810 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 820 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 830 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 840 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 850 */ 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, - /* 860 */ 262, 262, + /* 180 */ 101, 102, 209, 191, 211, 212, 213, 214, 215, 216, + /* 190 */ 217, 218, 219, 220, 221, 222, 223, 224, 16, 17, + /* 200 */ 44, 191, 20, 21, 0, 23, 24, 25, 26, 27, + /* 210 */ 28, 256, 258, 258, 104, 33, 34, 61, 252, 37, + /* 220 */ 38, 39, 197, 67, 232, 104, 191, 235, 107, 73, + /* 230 */ 74, 75, 104, 1, 2, 234, 108, 5, 110, 7, + /* 240 */ 104, 9, 232, 1, 2, 235, 237, 5, 112, 7, + /* 250 */ 249, 9, 191, 228, 229, 230, 231, 33, 34, 250, + /* 260 */ 104, 37, 38, 39, 67, 33, 34, 232, 112, 37, + /* 270 */ 235, 88, 191, 90, 91, 33, 34, 5, 95, 7, + /* 280 */ 97, 98, 99, 79, 101, 102, 64, 65, 66, 105, + /* 290 */ 134, 209, 136, 232, 212, 213, 235, 113, 142, 217, + /* 300 */ 210, 219, 220, 221, 37, 223, 224, 25, 26, 27, + /* 310 */ 28, 198, 199, 15, 233, 33, 34, 191, 210, 37, + /* 320 */ 38, 39, 76, 62, 63, 210, 236, 81, 197, 68, + /* 330 */ 69, 70, 71, 72, 137, 2, 104, 140, 5, 78, + /* 340 */ 7, 191, 9, 191, 236, 109, 104, 62, 63, 117, + /* 350 */ 252, 236, 116, 68, 69, 70, 71, 72, 232, 117, + /* 360 */ 229, 235, 62, 63, 1, 133, 33, 34, 68, 69, + /* 370 */ 70, 71, 72, 196, 196, 133, 226, 200, 200, 194, + /* 380 */ 195, 105, 115, 60, 232, 109, 105, 235, 124, 125, + /* 390 */ 109, 105, 105, 105, 105, 109, 109, 109, 109, 5, + /* 400 */ 37, 7, 109, 109, 105, 252, 105, 105, 109, 111, + /* 410 */ 109, 109, 105, 105, 76, 77, 109, 109, 138, 139, + /* 420 */ 252, 138, 139, 129, 131, 252, 252, 104, 138, 139, + /* 430 */ 104, 252, 106, 138, 139, 5, 5, 7, 7, 62, + /* 440 */ 63, 252, 252, 252, 111, 252, 252, 252, 236, 236, + /* 450 */ 227, 191, 227, 227, 227, 227, 227, 227, 251, 191, + /* 460 */ 191, 191, 191, 60, 191, 234, 191, 234, 259, 259, + /* 470 */ 191, 234, 238, 117, 255, 191, 255, 103, 87, 225, + /* 480 */ 206, 122, 191, 191, 243, 245, 247, 191, 191, 128, + /* 490 */ 255, 248, 130, 255, 191, 191, 191, 191, 127, 246, + /* 500 */ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, + /* 510 */ 191, 191, 191, 191, 126, 191, 191, 121, 191, 191, + /* 520 */ 191, 191, 191, 191, 120, 191, 191, 191, 191, 119, + /* 530 */ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, + /* 540 */ 191, 191, 191, 191, 118, 192, 192, 192, 132, 192, + /* 550 */ 192, 86, 50, 83, 85, 54, 84, 82, 79, 192, + /* 560 */ 192, 5, 192, 145, 5, 5, 145, 192, 192, 197, + /* 570 */ 197, 5, 5, 90, 89, 135, 113, 104, 192, 105, + /* 580 */ 193, 202, 193, 201, 203, 192, 208, 207, 205, 204, + /* 590 */ 193, 192, 114, 193, 192, 194, 198, 107, 109, 105, + /* 600 */ 104, 109, 105, 104, 244, 240, 242, 241, 239, 225, + /* 610 */ 1, 104, 109, 105, 104, 109, 123, 105, 123, 104, + /* 620 */ 111, 104, 104, 107, 104, 76, 9, 108, 5, 5, + /* 630 */ 5, 5, 5, 80, 15, 109, 16, 76, 5, 139, + /* 640 */ 5, 105, 5, 139, 139, 5, 5, 5, 5, 5, + /* 650 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + /* 660 */ 5, 109, 80, 60, 59, 0, 263, 263, 263, 263, + /* 670 */ 263, 263, 263, 263, 263, 263, 263, 21, 21, 263, + /* 680 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 690 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 700 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 710 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 720 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 730 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 740 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 750 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 760 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 770 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 780 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 790 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 800 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 810 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 820 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 830 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 840 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 850 */ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + /* 860 */ 263, 263, 263, 263, 263, 263, }; -#define YY_SHIFT_COUNT (312) +#define YY_SHIFT_COUNT (314) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (662) +#define YY_SHIFT_MAX (665) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 168, 79, 79, 172, 172, 9, 221, 231, 74, 74, - /* 10 */ 74, 74, 74, 74, 74, 74, 74, 0, 48, 231, - /* 20 */ 365, 365, 365, 365, 121, 207, 74, 74, 74, 158, - /* 30 */ 74, 74, 200, 9, 37, 37, 676, 676, 676, 231, - /* 40 */ 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, - /* 50 */ 231, 231, 231, 231, 231, 231, 231, 231, 231, 365, - /* 60 */ 365, 102, 102, 102, 102, 102, 102, 102, 74, 74, - /* 70 */ 251, 74, 207, 207, 74, 74, 74, 263, 263, 201, - /* 80 */ 207, 74, 74, 74, 74, 74, 74, 74, 74, 74, + /* 0 */ 156, 79, 79, 183, 183, 6, 232, 242, 74, 74, + /* 10 */ 74, 74, 74, 74, 74, 74, 74, 0, 48, 242, + /* 20 */ 333, 333, 333, 333, 110, 136, 74, 74, 74, 204, + /* 30 */ 74, 74, 246, 6, 7, 7, 679, 679, 679, 242, + /* 40 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + /* 50 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 333, + /* 60 */ 333, 102, 102, 102, 102, 102, 102, 102, 74, 74, + /* 70 */ 74, 267, 74, 136, 136, 74, 74, 74, 264, 264, + /* 80 */ 236, 136, 74, 74, 74, 74, 74, 74, 74, 74, /* 90 */ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, /* 100 */ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, /* 110 */ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, /* 120 */ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - /* 130 */ 74, 404, 404, 404, 354, 354, 354, 404, 354, 404, - /* 140 */ 353, 355, 368, 356, 373, 386, 393, 358, 420, 412, - /* 150 */ 404, 404, 404, 442, 9, 9, 404, 404, 459, 461, - /* 160 */ 498, 466, 465, 497, 468, 471, 442, 404, 477, 477, - /* 170 */ 404, 477, 404, 477, 404, 676, 676, 27, 100, 127, - /* 180 */ 100, 100, 53, 182, 266, 266, 266, 266, 244, 261, - /* 190 */ 274, 323, 323, 323, 323, 78, 114, 214, 214, 243, - /* 200 */ 95, 232, 281, 215, 284, 286, 287, 292, 295, 277, - /* 210 */ 366, 378, 290, 311, 272, 20, 297, 300, 302, 303, - /* 220 */ 305, 309, 280, 282, 288, 317, 291, 426, 427, 359, - /* 230 */ 375, 552, 414, 554, 556, 418, 558, 559, 480, 431, - /* 240 */ 458, 467, 469, 462, 472, 463, 473, 475, 493, 495, - /* 250 */ 476, 606, 504, 505, 507, 500, 489, 506, 490, 509, - /* 260 */ 512, 508, 513, 467, 514, 515, 516, 517, 545, 614, - /* 270 */ 619, 621, 622, 623, 624, 550, 616, 557, 494, 525, - /* 280 */ 525, 620, 499, 501, 525, 630, 633, 535, 525, 636, - /* 290 */ 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, - /* 300 */ 647, 648, 649, 650, 651, 652, 549, 579, 653, 654, - /* 310 */ 600, 602, 662, + /* 130 */ 74, 74, 403, 403, 403, 356, 356, 356, 403, 356, + /* 140 */ 403, 361, 362, 371, 359, 388, 396, 404, 410, 426, + /* 150 */ 416, 403, 403, 403, 374, 6, 6, 403, 403, 391, + /* 160 */ 465, 502, 470, 469, 501, 472, 475, 374, 403, 479, + /* 170 */ 479, 403, 479, 403, 479, 403, 679, 679, 27, 100, + /* 180 */ 127, 100, 100, 53, 182, 282, 282, 282, 282, 261, + /* 190 */ 285, 300, 224, 224, 224, 224, 22, 14, 92, 92, + /* 200 */ 128, 197, 222, 276, 184, 281, 286, 287, 288, 289, + /* 210 */ 272, 394, 363, 323, 298, 293, 294, 299, 301, 302, + /* 220 */ 307, 308, 121, 280, 283, 290, 326, 295, 430, 431, + /* 230 */ 338, 377, 556, 418, 559, 560, 421, 566, 567, 483, + /* 240 */ 485, 440, 463, 490, 473, 478, 474, 489, 494, 496, + /* 250 */ 497, 492, 499, 609, 507, 508, 510, 503, 493, 506, + /* 260 */ 495, 512, 515, 509, 517, 490, 518, 516, 520, 519, + /* 270 */ 549, 617, 623, 624, 625, 626, 627, 553, 619, 561, + /* 280 */ 500, 526, 526, 620, 504, 505, 526, 633, 635, 536, + /* 290 */ 526, 637, 640, 641, 642, 643, 644, 645, 646, 647, + /* 300 */ 648, 649, 650, 651, 652, 653, 654, 655, 552, 582, + /* 310 */ 656, 657, 603, 605, 665, }; -#define YY_REDUCE_COUNT (176) -#define YY_REDUCE_MIN (-239) -#define YY_REDUCE_MAX (410) +#define YY_REDUCE_COUNT (177) +#define YY_REDUCE_MIN (-245) +#define YY_REDUCE_MAX (402) static const short yy_reduce_ofst[] = { - /* 0 */ -177, -26, -26, 67, 67, 17, -229, -215, -172, -175, - /* 10 */ -7, -75, 87, 118, 144, 149, 151, -184, -187, -232, - /* 20 */ -205, -146, -124, -78, 105, -9, -185, 11, -190, -88, - /* 30 */ 76, -71, 5, 31, 160, 170, 91, 179, -186, -239, - /* 40 */ -216, -193, -139, -105, -40, 10, 112, 117, 133, 173, - /* 50 */ 176, 188, 189, 190, 191, 192, 193, 194, 195, 212, - /* 60 */ 213, 204, 223, 224, 225, 226, 227, 228, 265, 267, - /* 70 */ 206, 268, 229, 230, 269, 270, 271, 208, 209, 233, - /* 80 */ 235, 275, 279, 283, 285, 289, 293, 294, 296, 298, - /* 90 */ 299, 301, 304, 306, 307, 308, 310, 312, 313, 314, - /* 100 */ 315, 316, 318, 319, 320, 321, 322, 324, 325, 326, - /* 110 */ 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, - /* 120 */ 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - /* 130 */ 347, 348, 349, 350, 218, 220, 236, 351, 238, 352, - /* 140 */ 240, 234, 237, 249, 258, 357, 360, 362, 361, 367, - /* 150 */ 363, 364, 369, 370, 371, 372, 374, 379, 376, 380, - /* 160 */ 377, 383, 381, 385, 387, 388, 382, 384, 389, 397, - /* 170 */ 400, 401, 405, 403, 406, 395, 410, + /* 0 */ -178, -27, -27, 82, 82, 25, -230, -216, -173, -176, + /* 10 */ -45, -8, 10, 35, 61, 126, 152, -185, -188, -233, + /* 20 */ -206, 90, 108, 115, -191, 1, -186, -46, 81, -189, + /* 30 */ 150, -79, -78, 131, 177, 178, 9, 113, 185, -245, + /* 40 */ -240, -217, -194, -144, -137, -110, -34, 98, 153, 168, + /* 50 */ 173, 174, 179, 189, 190, 191, 193, 194, 195, 212, + /* 60 */ 213, 223, 225, 226, 227, 228, 229, 230, 260, 268, + /* 70 */ 269, 207, 270, 231, 233, 271, 273, 275, 209, 210, + /* 80 */ 234, 237, 279, 284, 291, 292, 296, 297, 303, 304, + /* 90 */ 305, 306, 309, 310, 311, 312, 313, 314, 315, 316, + /* 100 */ 317, 318, 319, 320, 321, 322, 324, 325, 327, 328, + /* 110 */ 329, 330, 331, 332, 334, 335, 336, 337, 339, 340, + /* 120 */ 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, + /* 130 */ 351, 352, 353, 354, 355, 219, 221, 235, 357, 238, + /* 140 */ 358, 243, 239, 253, 240, 360, 241, 364, 366, 365, + /* 150 */ 369, 367, 368, 370, 254, 372, 373, 375, 376, 378, + /* 160 */ 380, 274, 379, 383, 381, 385, 382, 384, 386, 387, + /* 170 */ 389, 393, 397, 399, 400, 402, 398, 401, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 767, 879, 825, 891, 813, 822, 1019, 1019, 767, 767, - /* 10 */ 767, 767, 767, 767, 767, 767, 767, 938, 786, 1019, - /* 20 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 822, - /* 30 */ 767, 767, 828, 822, 828, 828, 933, 863, 881, 767, - /* 40 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 50 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 60 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 70 */ 940, 943, 767, 767, 945, 767, 767, 965, 965, 931, - /* 80 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 90 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 100 */ 767, 767, 767, 767, 767, 767, 767, 767, 811, 767, - /* 110 */ 809, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 120 */ 767, 767, 767, 767, 767, 796, 767, 767, 767, 767, - /* 130 */ 767, 788, 788, 788, 767, 767, 767, 788, 767, 788, - /* 140 */ 972, 976, 970, 958, 966, 957, 953, 951, 950, 980, - /* 150 */ 788, 788, 788, 826, 822, 822, 788, 788, 844, 842, - /* 160 */ 840, 832, 838, 834, 836, 830, 814, 788, 820, 820, - /* 170 */ 788, 820, 788, 820, 788, 863, 881, 767, 981, 767, - /* 180 */ 1018, 971, 1008, 1007, 1014, 1006, 1005, 1004, 767, 767, - /* 190 */ 767, 1000, 1001, 1003, 1002, 767, 767, 1010, 1009, 767, - /* 200 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 210 */ 767, 767, 983, 767, 977, 973, 767, 767, 767, 767, - /* 220 */ 767, 767, 767, 767, 767, 893, 767, 767, 767, 767, - /* 230 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 240 */ 930, 767, 767, 767, 767, 941, 767, 767, 767, 767, - /* 250 */ 767, 767, 767, 767, 767, 967, 767, 959, 767, 767, - /* 260 */ 767, 767, 767, 905, 767, 767, 767, 767, 767, 767, - /* 270 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 1029, - /* 280 */ 1027, 767, 767, 767, 1023, 767, 767, 767, 1021, 767, - /* 290 */ 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, - /* 300 */ 767, 767, 767, 767, 767, 767, 847, 767, 794, 792, - /* 310 */ 767, 784, 767, + /* 0 */ 771, 883, 829, 895, 817, 826, 1023, 1023, 771, 771, + /* 10 */ 771, 771, 771, 771, 771, 771, 771, 942, 790, 1023, + /* 20 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 826, + /* 30 */ 771, 771, 832, 826, 832, 832, 937, 867, 885, 771, + /* 40 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 50 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 60 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 70 */ 771, 944, 947, 771, 771, 949, 771, 771, 969, 969, + /* 80 */ 935, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 90 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 100 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 815, + /* 110 */ 771, 813, 771, 771, 771, 771, 771, 771, 771, 771, + /* 120 */ 771, 771, 771, 771, 771, 771, 800, 771, 771, 771, + /* 130 */ 771, 771, 792, 792, 792, 771, 771, 771, 792, 771, + /* 140 */ 792, 976, 980, 974, 962, 970, 961, 957, 955, 954, + /* 150 */ 984, 792, 792, 792, 830, 826, 826, 792, 792, 848, + /* 160 */ 846, 844, 836, 842, 838, 840, 834, 818, 792, 824, + /* 170 */ 824, 792, 824, 792, 824, 792, 867, 885, 771, 985, + /* 180 */ 771, 1022, 975, 1012, 1011, 1018, 1010, 1009, 1008, 771, + /* 190 */ 771, 771, 1004, 1005, 1007, 1006, 771, 771, 1014, 1013, + /* 200 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 210 */ 771, 771, 771, 987, 771, 981, 977, 771, 771, 771, + /* 220 */ 771, 771, 771, 771, 771, 771, 897, 771, 771, 771, + /* 230 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 240 */ 771, 771, 934, 771, 771, 771, 771, 945, 771, 771, + /* 250 */ 771, 771, 771, 771, 771, 771, 771, 971, 771, 963, + /* 260 */ 771, 771, 771, 771, 771, 909, 771, 771, 771, 771, + /* 270 */ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 280 */ 771, 1034, 1032, 771, 771, 771, 1028, 771, 771, 771, + /* 290 */ 1026, 771, 771, 771, 771, 771, 771, 771, 771, 771, + /* 300 */ 771, 771, 771, 771, 771, 771, 771, 771, 851, 771, + /* 310 */ 798, 796, 771, 788, 771, }; /********** End of lemon-generated parsing tables *****************************/ @@ -612,6 +612,7 @@ static const YYCODETYPE yyFallback[] = { 1, /* NOW => ID */ 0, /* RESET => nothing */ 0, /* QUERY => nothing */ + 0, /* SYNCDB => nothing */ 0, /* ADD => nothing */ 0, /* COLUMN => nothing */ 0, /* TAG => nothing */ @@ -884,132 +885,133 @@ static const char *const yyTokenName[] = { /* 133 */ "NOW", /* 134 */ "RESET", /* 135 */ "QUERY", - /* 136 */ "ADD", - /* 137 */ "COLUMN", - /* 138 */ "TAG", - /* 139 */ "CHANGE", - /* 140 */ "SET", - /* 141 */ "KILL", - /* 142 */ "CONNECTION", - /* 143 */ "STREAM", - /* 144 */ "COLON", - /* 145 */ "ABORT", - /* 146 */ "AFTER", - /* 147 */ "ATTACH", - /* 148 */ "BEFORE", - /* 149 */ "BEGIN", - /* 150 */ "CASCADE", - /* 151 */ "CLUSTER", - /* 152 */ "CONFLICT", - /* 153 */ "COPY", - /* 154 */ "DEFERRED", - /* 155 */ "DELIMITERS", - /* 156 */ "DETACH", - /* 157 */ "EACH", - /* 158 */ "END", - /* 159 */ "EXPLAIN", - /* 160 */ "FAIL", - /* 161 */ "FOR", - /* 162 */ "IGNORE", - /* 163 */ "IMMEDIATE", - /* 164 */ "INITIALLY", - /* 165 */ "INSTEAD", - /* 166 */ "MATCH", - /* 167 */ "KEY", - /* 168 */ "OF", - /* 169 */ "RAISE", - /* 170 */ "REPLACE", - /* 171 */ "RESTRICT", - /* 172 */ "ROW", - /* 173 */ "STATEMENT", - /* 174 */ "TRIGGER", - /* 175 */ "VIEW", - /* 176 */ "SEMI", - /* 177 */ "NONE", - /* 178 */ "PREV", - /* 179 */ "LINEAR", - /* 180 */ "IMPORT", - /* 181 */ "TBNAME", - /* 182 */ "JOIN", - /* 183 */ "INSERT", - /* 184 */ "INTO", - /* 185 */ "VALUES", - /* 186 */ "error", - /* 187 */ "program", - /* 188 */ "cmd", - /* 189 */ "dbPrefix", - /* 190 */ "ids", - /* 191 */ "cpxName", - /* 192 */ "ifexists", - /* 193 */ "alter_db_optr", - /* 194 */ "alter_topic_optr", - /* 195 */ "acct_optr", - /* 196 */ "ifnotexists", - /* 197 */ "db_optr", - /* 198 */ "topic_optr", - /* 199 */ "pps", - /* 200 */ "tseries", - /* 201 */ "dbs", - /* 202 */ "streams", - /* 203 */ "storage", - /* 204 */ "qtime", - /* 205 */ "users", - /* 206 */ "conns", - /* 207 */ "state", - /* 208 */ "keep", - /* 209 */ "tagitemlist", - /* 210 */ "cache", - /* 211 */ "replica", - /* 212 */ "quorum", - /* 213 */ "days", - /* 214 */ "minrows", - /* 215 */ "maxrows", - /* 216 */ "blocks", - /* 217 */ "ctime", - /* 218 */ "wal", - /* 219 */ "fsync", - /* 220 */ "comp", - /* 221 */ "prec", - /* 222 */ "update", - /* 223 */ "cachelast", - /* 224 */ "partitions", - /* 225 */ "typename", - /* 226 */ "signed", - /* 227 */ "create_table_args", - /* 228 */ "create_stable_args", - /* 229 */ "create_table_list", - /* 230 */ "create_from_stable", - /* 231 */ "columnlist", - /* 232 */ "tagNamelist", - /* 233 */ "select", - /* 234 */ "column", - /* 235 */ "tagitem", - /* 236 */ "selcollist", - /* 237 */ "from", - /* 238 */ "where_opt", - /* 239 */ "interval_opt", - /* 240 */ "session_option", - /* 241 */ "fill_opt", - /* 242 */ "sliding_opt", - /* 243 */ "groupby_opt", - /* 244 */ "orderby_opt", - /* 245 */ "having_opt", - /* 246 */ "slimit_opt", - /* 247 */ "limit_opt", - /* 248 */ "union", - /* 249 */ "sclp", - /* 250 */ "distinct", - /* 251 */ "expr", - /* 252 */ "as", - /* 253 */ "tablelist", - /* 254 */ "tmvar", - /* 255 */ "sortlist", - /* 256 */ "sortitem", - /* 257 */ "item", - /* 258 */ "sortorder", - /* 259 */ "grouplist", - /* 260 */ "exprlist", - /* 261 */ "expritem", + /* 136 */ "SYNCDB", + /* 137 */ "ADD", + /* 138 */ "COLUMN", + /* 139 */ "TAG", + /* 140 */ "CHANGE", + /* 141 */ "SET", + /* 142 */ "KILL", + /* 143 */ "CONNECTION", + /* 144 */ "STREAM", + /* 145 */ "COLON", + /* 146 */ "ABORT", + /* 147 */ "AFTER", + /* 148 */ "ATTACH", + /* 149 */ "BEFORE", + /* 150 */ "BEGIN", + /* 151 */ "CASCADE", + /* 152 */ "CLUSTER", + /* 153 */ "CONFLICT", + /* 154 */ "COPY", + /* 155 */ "DEFERRED", + /* 156 */ "DELIMITERS", + /* 157 */ "DETACH", + /* 158 */ "EACH", + /* 159 */ "END", + /* 160 */ "EXPLAIN", + /* 161 */ "FAIL", + /* 162 */ "FOR", + /* 163 */ "IGNORE", + /* 164 */ "IMMEDIATE", + /* 165 */ "INITIALLY", + /* 166 */ "INSTEAD", + /* 167 */ "MATCH", + /* 168 */ "KEY", + /* 169 */ "OF", + /* 170 */ "RAISE", + /* 171 */ "REPLACE", + /* 172 */ "RESTRICT", + /* 173 */ "ROW", + /* 174 */ "STATEMENT", + /* 175 */ "TRIGGER", + /* 176 */ "VIEW", + /* 177 */ "SEMI", + /* 178 */ "NONE", + /* 179 */ "PREV", + /* 180 */ "LINEAR", + /* 181 */ "IMPORT", + /* 182 */ "TBNAME", + /* 183 */ "JOIN", + /* 184 */ "INSERT", + /* 185 */ "INTO", + /* 186 */ "VALUES", + /* 187 */ "error", + /* 188 */ "program", + /* 189 */ "cmd", + /* 190 */ "dbPrefix", + /* 191 */ "ids", + /* 192 */ "cpxName", + /* 193 */ "ifexists", + /* 194 */ "alter_db_optr", + /* 195 */ "alter_topic_optr", + /* 196 */ "acct_optr", + /* 197 */ "ifnotexists", + /* 198 */ "db_optr", + /* 199 */ "topic_optr", + /* 200 */ "pps", + /* 201 */ "tseries", + /* 202 */ "dbs", + /* 203 */ "streams", + /* 204 */ "storage", + /* 205 */ "qtime", + /* 206 */ "users", + /* 207 */ "conns", + /* 208 */ "state", + /* 209 */ "keep", + /* 210 */ "tagitemlist", + /* 211 */ "cache", + /* 212 */ "replica", + /* 213 */ "quorum", + /* 214 */ "days", + /* 215 */ "minrows", + /* 216 */ "maxrows", + /* 217 */ "blocks", + /* 218 */ "ctime", + /* 219 */ "wal", + /* 220 */ "fsync", + /* 221 */ "comp", + /* 222 */ "prec", + /* 223 */ "update", + /* 224 */ "cachelast", + /* 225 */ "partitions", + /* 226 */ "typename", + /* 227 */ "signed", + /* 228 */ "create_table_args", + /* 229 */ "create_stable_args", + /* 230 */ "create_table_list", + /* 231 */ "create_from_stable", + /* 232 */ "columnlist", + /* 233 */ "tagNamelist", + /* 234 */ "select", + /* 235 */ "column", + /* 236 */ "tagitem", + /* 237 */ "selcollist", + /* 238 */ "from", + /* 239 */ "where_opt", + /* 240 */ "interval_opt", + /* 241 */ "session_option", + /* 242 */ "fill_opt", + /* 243 */ "sliding_opt", + /* 244 */ "groupby_opt", + /* 245 */ "orderby_opt", + /* 246 */ "having_opt", + /* 247 */ "slimit_opt", + /* 248 */ "limit_opt", + /* 249 */ "union", + /* 250 */ "sclp", + /* 251 */ "distinct", + /* 252 */ "expr", + /* 253 */ "as", + /* 254 */ "tablelist", + /* 255 */ "tmvar", + /* 256 */ "sortlist", + /* 257 */ "sortitem", + /* 258 */ "item", + /* 259 */ "sortorder", + /* 260 */ "grouplist", + /* 261 */ "exprlist", + /* 262 */ "expritem", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -1268,20 +1270,21 @@ static const char *const yyRuleName[] = { /* 248 */ "expritem ::= expr", /* 249 */ "expritem ::=", /* 250 */ "cmd ::= RESET QUERY CACHE", - /* 251 */ "cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist", - /* 252 */ "cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids", - /* 253 */ "cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist", - /* 254 */ "cmd ::= ALTER TABLE ids cpxName DROP TAG ids", - /* 255 */ "cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids", - /* 256 */ "cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem", - /* 257 */ "cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist", - /* 258 */ "cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids", - /* 259 */ "cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist", - /* 260 */ "cmd ::= ALTER STABLE ids cpxName DROP TAG ids", - /* 261 */ "cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids", - /* 262 */ "cmd ::= KILL CONNECTION INTEGER", - /* 263 */ "cmd ::= KILL STREAM INTEGER COLON INTEGER", - /* 264 */ "cmd ::= KILL QUERY INTEGER COLON INTEGER", + /* 251 */ "cmd ::= SYNCDB ids REPLICA", + /* 252 */ "cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist", + /* 253 */ "cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids", + /* 254 */ "cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist", + /* 255 */ "cmd ::= ALTER TABLE ids cpxName DROP TAG ids", + /* 256 */ "cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids", + /* 257 */ "cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem", + /* 258 */ "cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist", + /* 259 */ "cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids", + /* 260 */ "cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist", + /* 261 */ "cmd ::= ALTER STABLE ids cpxName DROP TAG ids", + /* 262 */ "cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids", + /* 263 */ "cmd ::= KILL CONNECTION INTEGER", + /* 264 */ "cmd ::= KILL STREAM INTEGER COLON INTEGER", + /* 265 */ "cmd ::= KILL QUERY INTEGER COLON INTEGER", }; #endif /* NDEBUG */ @@ -1402,52 +1405,52 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 208: /* keep */ - case 209: /* tagitemlist */ - case 231: /* columnlist */ - case 232: /* tagNamelist */ - case 241: /* fill_opt */ - case 243: /* groupby_opt */ - case 244: /* orderby_opt */ - case 255: /* sortlist */ - case 259: /* grouplist */ + case 209: /* keep */ + case 210: /* tagitemlist */ + case 232: /* columnlist */ + case 233: /* tagNamelist */ + case 242: /* fill_opt */ + case 244: /* groupby_opt */ + case 245: /* orderby_opt */ + case 256: /* sortlist */ + case 260: /* grouplist */ { -taosArrayDestroy((yypminor->yy429)); +taosArrayDestroy((yypminor->yy159)); } break; - case 229: /* create_table_list */ + case 230: /* create_table_list */ { -destroyCreateTableSql((yypminor->yy194)); +destroyCreateTableSql((yypminor->yy14)); } break; - case 233: /* select */ + case 234: /* select */ { -destroyQuerySqlNode((yypminor->yy254)); +destroyQuerySqlNode((yypminor->yy272)); } break; - case 236: /* selcollist */ - case 249: /* sclp */ - case 260: /* exprlist */ + case 237: /* selcollist */ + case 250: /* sclp */ + case 261: /* exprlist */ { -tSqlExprListDestroy((yypminor->yy429)); +tSqlExprListDestroy((yypminor->yy159)); } break; - case 238: /* where_opt */ - case 245: /* having_opt */ - case 251: /* expr */ - case 261: /* expritem */ + case 239: /* where_opt */ + case 246: /* having_opt */ + case 252: /* expr */ + case 262: /* expritem */ { -tSqlExprDestroy((yypminor->yy170)); +tSqlExprDestroy((yypminor->yy118)); } break; - case 248: /* union */ + case 249: /* union */ { -destroyAllSelectClause((yypminor->yy141)); +destroyAllSelectClause((yypminor->yy391)); } break; - case 256: /* sortitem */ + case 257: /* sortitem */ { -tVariantDestroy(&(yypminor->yy218)); +tVariantDestroy(&(yypminor->yy488)); } break; /********* End destructor definitions *****************************************/ @@ -1741,271 +1744,272 @@ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } yyRuleInfo[] = { - { 187, -1 }, /* (0) program ::= cmd */ - { 188, -2 }, /* (1) cmd ::= SHOW DATABASES */ - { 188, -2 }, /* (2) cmd ::= SHOW TOPICS */ - { 188, -2 }, /* (3) cmd ::= SHOW MNODES */ - { 188, -2 }, /* (4) cmd ::= SHOW DNODES */ - { 188, -2 }, /* (5) cmd ::= SHOW ACCOUNTS */ - { 188, -2 }, /* (6) cmd ::= SHOW USERS */ - { 188, -2 }, /* (7) cmd ::= SHOW MODULES */ - { 188, -2 }, /* (8) cmd ::= SHOW QUERIES */ - { 188, -2 }, /* (9) cmd ::= SHOW CONNECTIONS */ - { 188, -2 }, /* (10) cmd ::= SHOW STREAMS */ - { 188, -2 }, /* (11) cmd ::= SHOW VARIABLES */ - { 188, -2 }, /* (12) cmd ::= SHOW SCORES */ - { 188, -2 }, /* (13) cmd ::= SHOW GRANTS */ - { 188, -2 }, /* (14) cmd ::= SHOW VNODES */ - { 188, -3 }, /* (15) cmd ::= SHOW VNODES IPTOKEN */ - { 189, 0 }, /* (16) dbPrefix ::= */ - { 189, -2 }, /* (17) dbPrefix ::= ids DOT */ - { 191, 0 }, /* (18) cpxName ::= */ - { 191, -2 }, /* (19) cpxName ::= DOT ids */ - { 188, -5 }, /* (20) cmd ::= SHOW CREATE TABLE ids cpxName */ - { 188, -4 }, /* (21) cmd ::= SHOW CREATE DATABASE ids */ - { 188, -3 }, /* (22) cmd ::= SHOW dbPrefix TABLES */ - { 188, -5 }, /* (23) cmd ::= SHOW dbPrefix TABLES LIKE ids */ - { 188, -3 }, /* (24) cmd ::= SHOW dbPrefix STABLES */ - { 188, -5 }, /* (25) cmd ::= SHOW dbPrefix STABLES LIKE ids */ - { 188, -3 }, /* (26) cmd ::= SHOW dbPrefix VGROUPS */ - { 188, -4 }, /* (27) cmd ::= SHOW dbPrefix VGROUPS ids */ - { 188, -5 }, /* (28) cmd ::= DROP TABLE ifexists ids cpxName */ - { 188, -5 }, /* (29) cmd ::= DROP STABLE ifexists ids cpxName */ - { 188, -4 }, /* (30) cmd ::= DROP DATABASE ifexists ids */ - { 188, -4 }, /* (31) cmd ::= DROP TOPIC ifexists ids */ - { 188, -3 }, /* (32) cmd ::= DROP DNODE ids */ - { 188, -3 }, /* (33) cmd ::= DROP USER ids */ - { 188, -3 }, /* (34) cmd ::= DROP ACCOUNT ids */ - { 188, -2 }, /* (35) cmd ::= USE ids */ - { 188, -3 }, /* (36) cmd ::= DESCRIBE ids cpxName */ - { 188, -5 }, /* (37) cmd ::= ALTER USER ids PASS ids */ - { 188, -5 }, /* (38) cmd ::= ALTER USER ids PRIVILEGE ids */ - { 188, -4 }, /* (39) cmd ::= ALTER DNODE ids ids */ - { 188, -5 }, /* (40) cmd ::= ALTER DNODE ids ids ids */ - { 188, -3 }, /* (41) cmd ::= ALTER LOCAL ids */ - { 188, -4 }, /* (42) cmd ::= ALTER LOCAL ids ids */ - { 188, -4 }, /* (43) cmd ::= ALTER DATABASE ids alter_db_optr */ - { 188, -4 }, /* (44) cmd ::= ALTER TOPIC ids alter_topic_optr */ - { 188, -4 }, /* (45) cmd ::= ALTER ACCOUNT ids acct_optr */ - { 188, -6 }, /* (46) cmd ::= ALTER ACCOUNT ids PASS ids acct_optr */ - { 190, -1 }, /* (47) ids ::= ID */ - { 190, -1 }, /* (48) ids ::= STRING */ - { 192, -2 }, /* (49) ifexists ::= IF EXISTS */ - { 192, 0 }, /* (50) ifexists ::= */ - { 196, -3 }, /* (51) ifnotexists ::= IF NOT EXISTS */ - { 196, 0 }, /* (52) ifnotexists ::= */ - { 188, -3 }, /* (53) cmd ::= CREATE DNODE ids */ - { 188, -6 }, /* (54) cmd ::= CREATE ACCOUNT ids PASS ids acct_optr */ - { 188, -5 }, /* (55) cmd ::= CREATE DATABASE ifnotexists ids db_optr */ - { 188, -5 }, /* (56) cmd ::= CREATE TOPIC ifnotexists ids topic_optr */ - { 188, -5 }, /* (57) cmd ::= CREATE USER ids PASS ids */ - { 199, 0 }, /* (58) pps ::= */ - { 199, -2 }, /* (59) pps ::= PPS INTEGER */ - { 200, 0 }, /* (60) tseries ::= */ - { 200, -2 }, /* (61) tseries ::= TSERIES INTEGER */ - { 201, 0 }, /* (62) dbs ::= */ - { 201, -2 }, /* (63) dbs ::= DBS INTEGER */ - { 202, 0 }, /* (64) streams ::= */ - { 202, -2 }, /* (65) streams ::= STREAMS INTEGER */ - { 203, 0 }, /* (66) storage ::= */ - { 203, -2 }, /* (67) storage ::= STORAGE INTEGER */ - { 204, 0 }, /* (68) qtime ::= */ - { 204, -2 }, /* (69) qtime ::= QTIME INTEGER */ - { 205, 0 }, /* (70) users ::= */ - { 205, -2 }, /* (71) users ::= USERS INTEGER */ - { 206, 0 }, /* (72) conns ::= */ - { 206, -2 }, /* (73) conns ::= CONNS INTEGER */ - { 207, 0 }, /* (74) state ::= */ - { 207, -2 }, /* (75) state ::= STATE ids */ - { 195, -9 }, /* (76) acct_optr ::= pps tseries storage streams qtime dbs users conns state */ - { 208, -2 }, /* (77) keep ::= KEEP tagitemlist */ - { 210, -2 }, /* (78) cache ::= CACHE INTEGER */ - { 211, -2 }, /* (79) replica ::= REPLICA INTEGER */ - { 212, -2 }, /* (80) quorum ::= QUORUM INTEGER */ - { 213, -2 }, /* (81) days ::= DAYS INTEGER */ - { 214, -2 }, /* (82) minrows ::= MINROWS INTEGER */ - { 215, -2 }, /* (83) maxrows ::= MAXROWS INTEGER */ - { 216, -2 }, /* (84) blocks ::= BLOCKS INTEGER */ - { 217, -2 }, /* (85) ctime ::= CTIME INTEGER */ - { 218, -2 }, /* (86) wal ::= WAL INTEGER */ - { 219, -2 }, /* (87) fsync ::= FSYNC INTEGER */ - { 220, -2 }, /* (88) comp ::= COMP INTEGER */ - { 221, -2 }, /* (89) prec ::= PRECISION STRING */ - { 222, -2 }, /* (90) update ::= UPDATE INTEGER */ - { 223, -2 }, /* (91) cachelast ::= CACHELAST INTEGER */ - { 224, -2 }, /* (92) partitions ::= PARTITIONS INTEGER */ - { 197, 0 }, /* (93) db_optr ::= */ - { 197, -2 }, /* (94) db_optr ::= db_optr cache */ - { 197, -2 }, /* (95) db_optr ::= db_optr replica */ - { 197, -2 }, /* (96) db_optr ::= db_optr quorum */ - { 197, -2 }, /* (97) db_optr ::= db_optr days */ - { 197, -2 }, /* (98) db_optr ::= db_optr minrows */ - { 197, -2 }, /* (99) db_optr ::= db_optr maxrows */ - { 197, -2 }, /* (100) db_optr ::= db_optr blocks */ - { 197, -2 }, /* (101) db_optr ::= db_optr ctime */ - { 197, -2 }, /* (102) db_optr ::= db_optr wal */ - { 197, -2 }, /* (103) db_optr ::= db_optr fsync */ - { 197, -2 }, /* (104) db_optr ::= db_optr comp */ - { 197, -2 }, /* (105) db_optr ::= db_optr prec */ - { 197, -2 }, /* (106) db_optr ::= db_optr keep */ - { 197, -2 }, /* (107) db_optr ::= db_optr update */ - { 197, -2 }, /* (108) db_optr ::= db_optr cachelast */ - { 198, -1 }, /* (109) topic_optr ::= db_optr */ - { 198, -2 }, /* (110) topic_optr ::= topic_optr partitions */ - { 193, 0 }, /* (111) alter_db_optr ::= */ - { 193, -2 }, /* (112) alter_db_optr ::= alter_db_optr replica */ - { 193, -2 }, /* (113) alter_db_optr ::= alter_db_optr quorum */ - { 193, -2 }, /* (114) alter_db_optr ::= alter_db_optr keep */ - { 193, -2 }, /* (115) alter_db_optr ::= alter_db_optr blocks */ - { 193, -2 }, /* (116) alter_db_optr ::= alter_db_optr comp */ - { 193, -2 }, /* (117) alter_db_optr ::= alter_db_optr wal */ - { 193, -2 }, /* (118) alter_db_optr ::= alter_db_optr fsync */ - { 193, -2 }, /* (119) alter_db_optr ::= alter_db_optr update */ - { 193, -2 }, /* (120) alter_db_optr ::= alter_db_optr cachelast */ - { 194, -1 }, /* (121) alter_topic_optr ::= alter_db_optr */ - { 194, -2 }, /* (122) alter_topic_optr ::= alter_topic_optr partitions */ - { 225, -1 }, /* (123) typename ::= ids */ - { 225, -4 }, /* (124) typename ::= ids LP signed RP */ - { 225, -2 }, /* (125) typename ::= ids UNSIGNED */ - { 226, -1 }, /* (126) signed ::= INTEGER */ - { 226, -2 }, /* (127) signed ::= PLUS INTEGER */ - { 226, -2 }, /* (128) signed ::= MINUS INTEGER */ - { 188, -3 }, /* (129) cmd ::= CREATE TABLE create_table_args */ - { 188, -3 }, /* (130) cmd ::= CREATE TABLE create_stable_args */ - { 188, -3 }, /* (131) cmd ::= CREATE STABLE create_stable_args */ - { 188, -3 }, /* (132) cmd ::= CREATE TABLE create_table_list */ - { 229, -1 }, /* (133) create_table_list ::= create_from_stable */ - { 229, -2 }, /* (134) create_table_list ::= create_table_list create_from_stable */ - { 227, -6 }, /* (135) create_table_args ::= ifnotexists ids cpxName LP columnlist RP */ - { 228, -10 }, /* (136) create_stable_args ::= ifnotexists ids cpxName LP columnlist RP TAGS LP columnlist RP */ - { 230, -10 }, /* (137) create_from_stable ::= ifnotexists ids cpxName USING ids cpxName TAGS LP tagitemlist RP */ - { 230, -13 }, /* (138) create_from_stable ::= ifnotexists ids cpxName USING ids cpxName LP tagNamelist RP TAGS LP tagitemlist RP */ - { 232, -3 }, /* (139) tagNamelist ::= tagNamelist COMMA ids */ - { 232, -1 }, /* (140) tagNamelist ::= ids */ - { 227, -5 }, /* (141) create_table_args ::= ifnotexists ids cpxName AS select */ - { 231, -3 }, /* (142) columnlist ::= columnlist COMMA column */ - { 231, -1 }, /* (143) columnlist ::= column */ - { 234, -2 }, /* (144) column ::= ids typename */ - { 209, -3 }, /* (145) tagitemlist ::= tagitemlist COMMA tagitem */ - { 209, -1 }, /* (146) tagitemlist ::= tagitem */ - { 235, -1 }, /* (147) tagitem ::= INTEGER */ - { 235, -1 }, /* (148) tagitem ::= FLOAT */ - { 235, -1 }, /* (149) tagitem ::= STRING */ - { 235, -1 }, /* (150) tagitem ::= BOOL */ - { 235, -1 }, /* (151) tagitem ::= NULL */ - { 235, -2 }, /* (152) tagitem ::= MINUS INTEGER */ - { 235, -2 }, /* (153) tagitem ::= MINUS FLOAT */ - { 235, -2 }, /* (154) tagitem ::= PLUS INTEGER */ - { 235, -2 }, /* (155) tagitem ::= PLUS FLOAT */ - { 233, -13 }, /* (156) select ::= SELECT selcollist from where_opt interval_opt session_option fill_opt sliding_opt groupby_opt orderby_opt having_opt slimit_opt limit_opt */ - { 233, -3 }, /* (157) select ::= LP select RP */ - { 248, -1 }, /* (158) union ::= select */ - { 248, -4 }, /* (159) union ::= union UNION ALL select */ - { 188, -1 }, /* (160) cmd ::= union */ - { 233, -2 }, /* (161) select ::= SELECT selcollist */ - { 249, -2 }, /* (162) sclp ::= selcollist COMMA */ - { 249, 0 }, /* (163) sclp ::= */ - { 236, -4 }, /* (164) selcollist ::= sclp distinct expr as */ - { 236, -2 }, /* (165) selcollist ::= sclp STAR */ - { 252, -2 }, /* (166) as ::= AS ids */ - { 252, -1 }, /* (167) as ::= ids */ - { 252, 0 }, /* (168) as ::= */ - { 250, -1 }, /* (169) distinct ::= DISTINCT */ - { 250, 0 }, /* (170) distinct ::= */ - { 237, -2 }, /* (171) from ::= FROM tablelist */ - { 237, -4 }, /* (172) from ::= FROM LP union RP */ - { 253, -2 }, /* (173) tablelist ::= ids cpxName */ - { 253, -3 }, /* (174) tablelist ::= ids cpxName ids */ - { 253, -4 }, /* (175) tablelist ::= tablelist COMMA ids cpxName */ - { 253, -5 }, /* (176) tablelist ::= tablelist COMMA ids cpxName ids */ - { 254, -1 }, /* (177) tmvar ::= VARIABLE */ - { 239, -4 }, /* (178) interval_opt ::= INTERVAL LP tmvar RP */ - { 239, -6 }, /* (179) interval_opt ::= INTERVAL LP tmvar COMMA tmvar RP */ - { 239, 0 }, /* (180) interval_opt ::= */ - { 240, 0 }, /* (181) session_option ::= */ - { 240, -7 }, /* (182) session_option ::= SESSION LP ids cpxName COMMA tmvar RP */ - { 241, 0 }, /* (183) fill_opt ::= */ - { 241, -6 }, /* (184) fill_opt ::= FILL LP ID COMMA tagitemlist RP */ - { 241, -4 }, /* (185) fill_opt ::= FILL LP ID RP */ - { 242, -4 }, /* (186) sliding_opt ::= SLIDING LP tmvar RP */ - { 242, 0 }, /* (187) sliding_opt ::= */ - { 244, 0 }, /* (188) orderby_opt ::= */ - { 244, -3 }, /* (189) orderby_opt ::= ORDER BY sortlist */ - { 255, -4 }, /* (190) sortlist ::= sortlist COMMA item sortorder */ - { 255, -2 }, /* (191) sortlist ::= item sortorder */ - { 257, -2 }, /* (192) item ::= ids cpxName */ - { 258, -1 }, /* (193) sortorder ::= ASC */ - { 258, -1 }, /* (194) sortorder ::= DESC */ - { 258, 0 }, /* (195) sortorder ::= */ - { 243, 0 }, /* (196) groupby_opt ::= */ - { 243, -3 }, /* (197) groupby_opt ::= GROUP BY grouplist */ - { 259, -3 }, /* (198) grouplist ::= grouplist COMMA item */ - { 259, -1 }, /* (199) grouplist ::= item */ - { 245, 0 }, /* (200) having_opt ::= */ - { 245, -2 }, /* (201) having_opt ::= HAVING expr */ - { 247, 0 }, /* (202) limit_opt ::= */ - { 247, -2 }, /* (203) limit_opt ::= LIMIT signed */ - { 247, -4 }, /* (204) limit_opt ::= LIMIT signed OFFSET signed */ - { 247, -4 }, /* (205) limit_opt ::= LIMIT signed COMMA signed */ - { 246, 0 }, /* (206) slimit_opt ::= */ - { 246, -2 }, /* (207) slimit_opt ::= SLIMIT signed */ - { 246, -4 }, /* (208) slimit_opt ::= SLIMIT signed SOFFSET signed */ - { 246, -4 }, /* (209) slimit_opt ::= SLIMIT signed COMMA signed */ - { 238, 0 }, /* (210) where_opt ::= */ - { 238, -2 }, /* (211) where_opt ::= WHERE expr */ - { 251, -3 }, /* (212) expr ::= LP expr RP */ - { 251, -1 }, /* (213) expr ::= ID */ - { 251, -3 }, /* (214) expr ::= ID DOT ID */ - { 251, -3 }, /* (215) expr ::= ID DOT STAR */ - { 251, -1 }, /* (216) expr ::= INTEGER */ - { 251, -2 }, /* (217) expr ::= MINUS INTEGER */ - { 251, -2 }, /* (218) expr ::= PLUS INTEGER */ - { 251, -1 }, /* (219) expr ::= FLOAT */ - { 251, -2 }, /* (220) expr ::= MINUS FLOAT */ - { 251, -2 }, /* (221) expr ::= PLUS FLOAT */ - { 251, -1 }, /* (222) expr ::= STRING */ - { 251, -1 }, /* (223) expr ::= NOW */ - { 251, -1 }, /* (224) expr ::= VARIABLE */ - { 251, -1 }, /* (225) expr ::= BOOL */ - { 251, -4 }, /* (226) expr ::= ID LP exprlist RP */ - { 251, -4 }, /* (227) expr ::= ID LP STAR RP */ - { 251, -3 }, /* (228) expr ::= expr IS NULL */ - { 251, -4 }, /* (229) expr ::= expr IS NOT NULL */ - { 251, -3 }, /* (230) expr ::= expr LT expr */ - { 251, -3 }, /* (231) expr ::= expr GT expr */ - { 251, -3 }, /* (232) expr ::= expr LE expr */ - { 251, -3 }, /* (233) expr ::= expr GE expr */ - { 251, -3 }, /* (234) expr ::= expr NE expr */ - { 251, -3 }, /* (235) expr ::= expr EQ expr */ - { 251, -5 }, /* (236) expr ::= expr BETWEEN expr AND expr */ - { 251, -3 }, /* (237) expr ::= expr AND expr */ - { 251, -3 }, /* (238) expr ::= expr OR expr */ - { 251, -3 }, /* (239) expr ::= expr PLUS expr */ - { 251, -3 }, /* (240) expr ::= expr MINUS expr */ - { 251, -3 }, /* (241) expr ::= expr STAR expr */ - { 251, -3 }, /* (242) expr ::= expr SLASH expr */ - { 251, -3 }, /* (243) expr ::= expr REM expr */ - { 251, -3 }, /* (244) expr ::= expr LIKE expr */ - { 251, -5 }, /* (245) expr ::= expr IN LP exprlist RP */ - { 260, -3 }, /* (246) exprlist ::= exprlist COMMA expritem */ - { 260, -1 }, /* (247) exprlist ::= expritem */ - { 261, -1 }, /* (248) expritem ::= expr */ - { 261, 0 }, /* (249) expritem ::= */ - { 188, -3 }, /* (250) cmd ::= RESET QUERY CACHE */ - { 188, -7 }, /* (251) cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist */ - { 188, -7 }, /* (252) cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids */ - { 188, -7 }, /* (253) cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist */ - { 188, -7 }, /* (254) cmd ::= ALTER TABLE ids cpxName DROP TAG ids */ - { 188, -8 }, /* (255) cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids */ - { 188, -9 }, /* (256) cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem */ - { 188, -7 }, /* (257) cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist */ - { 188, -7 }, /* (258) cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids */ - { 188, -7 }, /* (259) cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist */ - { 188, -7 }, /* (260) cmd ::= ALTER STABLE ids cpxName DROP TAG ids */ - { 188, -8 }, /* (261) cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids */ - { 188, -3 }, /* (262) cmd ::= KILL CONNECTION INTEGER */ - { 188, -5 }, /* (263) cmd ::= KILL STREAM INTEGER COLON INTEGER */ - { 188, -5 }, /* (264) cmd ::= KILL QUERY INTEGER COLON INTEGER */ + { 188, -1 }, /* (0) program ::= cmd */ + { 189, -2 }, /* (1) cmd ::= SHOW DATABASES */ + { 189, -2 }, /* (2) cmd ::= SHOW TOPICS */ + { 189, -2 }, /* (3) cmd ::= SHOW MNODES */ + { 189, -2 }, /* (4) cmd ::= SHOW DNODES */ + { 189, -2 }, /* (5) cmd ::= SHOW ACCOUNTS */ + { 189, -2 }, /* (6) cmd ::= SHOW USERS */ + { 189, -2 }, /* (7) cmd ::= SHOW MODULES */ + { 189, -2 }, /* (8) cmd ::= SHOW QUERIES */ + { 189, -2 }, /* (9) cmd ::= SHOW CONNECTIONS */ + { 189, -2 }, /* (10) cmd ::= SHOW STREAMS */ + { 189, -2 }, /* (11) cmd ::= SHOW VARIABLES */ + { 189, -2 }, /* (12) cmd ::= SHOW SCORES */ + { 189, -2 }, /* (13) cmd ::= SHOW GRANTS */ + { 189, -2 }, /* (14) cmd ::= SHOW VNODES */ + { 189, -3 }, /* (15) cmd ::= SHOW VNODES IPTOKEN */ + { 190, 0 }, /* (16) dbPrefix ::= */ + { 190, -2 }, /* (17) dbPrefix ::= ids DOT */ + { 192, 0 }, /* (18) cpxName ::= */ + { 192, -2 }, /* (19) cpxName ::= DOT ids */ + { 189, -5 }, /* (20) cmd ::= SHOW CREATE TABLE ids cpxName */ + { 189, -4 }, /* (21) cmd ::= SHOW CREATE DATABASE ids */ + { 189, -3 }, /* (22) cmd ::= SHOW dbPrefix TABLES */ + { 189, -5 }, /* (23) cmd ::= SHOW dbPrefix TABLES LIKE ids */ + { 189, -3 }, /* (24) cmd ::= SHOW dbPrefix STABLES */ + { 189, -5 }, /* (25) cmd ::= SHOW dbPrefix STABLES LIKE ids */ + { 189, -3 }, /* (26) cmd ::= SHOW dbPrefix VGROUPS */ + { 189, -4 }, /* (27) cmd ::= SHOW dbPrefix VGROUPS ids */ + { 189, -5 }, /* (28) cmd ::= DROP TABLE ifexists ids cpxName */ + { 189, -5 }, /* (29) cmd ::= DROP STABLE ifexists ids cpxName */ + { 189, -4 }, /* (30) cmd ::= DROP DATABASE ifexists ids */ + { 189, -4 }, /* (31) cmd ::= DROP TOPIC ifexists ids */ + { 189, -3 }, /* (32) cmd ::= DROP DNODE ids */ + { 189, -3 }, /* (33) cmd ::= DROP USER ids */ + { 189, -3 }, /* (34) cmd ::= DROP ACCOUNT ids */ + { 189, -2 }, /* (35) cmd ::= USE ids */ + { 189, -3 }, /* (36) cmd ::= DESCRIBE ids cpxName */ + { 189, -5 }, /* (37) cmd ::= ALTER USER ids PASS ids */ + { 189, -5 }, /* (38) cmd ::= ALTER USER ids PRIVILEGE ids */ + { 189, -4 }, /* (39) cmd ::= ALTER DNODE ids ids */ + { 189, -5 }, /* (40) cmd ::= ALTER DNODE ids ids ids */ + { 189, -3 }, /* (41) cmd ::= ALTER LOCAL ids */ + { 189, -4 }, /* (42) cmd ::= ALTER LOCAL ids ids */ + { 189, -4 }, /* (43) cmd ::= ALTER DATABASE ids alter_db_optr */ + { 189, -4 }, /* (44) cmd ::= ALTER TOPIC ids alter_topic_optr */ + { 189, -4 }, /* (45) cmd ::= ALTER ACCOUNT ids acct_optr */ + { 189, -6 }, /* (46) cmd ::= ALTER ACCOUNT ids PASS ids acct_optr */ + { 191, -1 }, /* (47) ids ::= ID */ + { 191, -1 }, /* (48) ids ::= STRING */ + { 193, -2 }, /* (49) ifexists ::= IF EXISTS */ + { 193, 0 }, /* (50) ifexists ::= */ + { 197, -3 }, /* (51) ifnotexists ::= IF NOT EXISTS */ + { 197, 0 }, /* (52) ifnotexists ::= */ + { 189, -3 }, /* (53) cmd ::= CREATE DNODE ids */ + { 189, -6 }, /* (54) cmd ::= CREATE ACCOUNT ids PASS ids acct_optr */ + { 189, -5 }, /* (55) cmd ::= CREATE DATABASE ifnotexists ids db_optr */ + { 189, -5 }, /* (56) cmd ::= CREATE TOPIC ifnotexists ids topic_optr */ + { 189, -5 }, /* (57) cmd ::= CREATE USER ids PASS ids */ + { 200, 0 }, /* (58) pps ::= */ + { 200, -2 }, /* (59) pps ::= PPS INTEGER */ + { 201, 0 }, /* (60) tseries ::= */ + { 201, -2 }, /* (61) tseries ::= TSERIES INTEGER */ + { 202, 0 }, /* (62) dbs ::= */ + { 202, -2 }, /* (63) dbs ::= DBS INTEGER */ + { 203, 0 }, /* (64) streams ::= */ + { 203, -2 }, /* (65) streams ::= STREAMS INTEGER */ + { 204, 0 }, /* (66) storage ::= */ + { 204, -2 }, /* (67) storage ::= STORAGE INTEGER */ + { 205, 0 }, /* (68) qtime ::= */ + { 205, -2 }, /* (69) qtime ::= QTIME INTEGER */ + { 206, 0 }, /* (70) users ::= */ + { 206, -2 }, /* (71) users ::= USERS INTEGER */ + { 207, 0 }, /* (72) conns ::= */ + { 207, -2 }, /* (73) conns ::= CONNS INTEGER */ + { 208, 0 }, /* (74) state ::= */ + { 208, -2 }, /* (75) state ::= STATE ids */ + { 196, -9 }, /* (76) acct_optr ::= pps tseries storage streams qtime dbs users conns state */ + { 209, -2 }, /* (77) keep ::= KEEP tagitemlist */ + { 211, -2 }, /* (78) cache ::= CACHE INTEGER */ + { 212, -2 }, /* (79) replica ::= REPLICA INTEGER */ + { 213, -2 }, /* (80) quorum ::= QUORUM INTEGER */ + { 214, -2 }, /* (81) days ::= DAYS INTEGER */ + { 215, -2 }, /* (82) minrows ::= MINROWS INTEGER */ + { 216, -2 }, /* (83) maxrows ::= MAXROWS INTEGER */ + { 217, -2 }, /* (84) blocks ::= BLOCKS INTEGER */ + { 218, -2 }, /* (85) ctime ::= CTIME INTEGER */ + { 219, -2 }, /* (86) wal ::= WAL INTEGER */ + { 220, -2 }, /* (87) fsync ::= FSYNC INTEGER */ + { 221, -2 }, /* (88) comp ::= COMP INTEGER */ + { 222, -2 }, /* (89) prec ::= PRECISION STRING */ + { 223, -2 }, /* (90) update ::= UPDATE INTEGER */ + { 224, -2 }, /* (91) cachelast ::= CACHELAST INTEGER */ + { 225, -2 }, /* (92) partitions ::= PARTITIONS INTEGER */ + { 198, 0 }, /* (93) db_optr ::= */ + { 198, -2 }, /* (94) db_optr ::= db_optr cache */ + { 198, -2 }, /* (95) db_optr ::= db_optr replica */ + { 198, -2 }, /* (96) db_optr ::= db_optr quorum */ + { 198, -2 }, /* (97) db_optr ::= db_optr days */ + { 198, -2 }, /* (98) db_optr ::= db_optr minrows */ + { 198, -2 }, /* (99) db_optr ::= db_optr maxrows */ + { 198, -2 }, /* (100) db_optr ::= db_optr blocks */ + { 198, -2 }, /* (101) db_optr ::= db_optr ctime */ + { 198, -2 }, /* (102) db_optr ::= db_optr wal */ + { 198, -2 }, /* (103) db_optr ::= db_optr fsync */ + { 198, -2 }, /* (104) db_optr ::= db_optr comp */ + { 198, -2 }, /* (105) db_optr ::= db_optr prec */ + { 198, -2 }, /* (106) db_optr ::= db_optr keep */ + { 198, -2 }, /* (107) db_optr ::= db_optr update */ + { 198, -2 }, /* (108) db_optr ::= db_optr cachelast */ + { 199, -1 }, /* (109) topic_optr ::= db_optr */ + { 199, -2 }, /* (110) topic_optr ::= topic_optr partitions */ + { 194, 0 }, /* (111) alter_db_optr ::= */ + { 194, -2 }, /* (112) alter_db_optr ::= alter_db_optr replica */ + { 194, -2 }, /* (113) alter_db_optr ::= alter_db_optr quorum */ + { 194, -2 }, /* (114) alter_db_optr ::= alter_db_optr keep */ + { 194, -2 }, /* (115) alter_db_optr ::= alter_db_optr blocks */ + { 194, -2 }, /* (116) alter_db_optr ::= alter_db_optr comp */ + { 194, -2 }, /* (117) alter_db_optr ::= alter_db_optr wal */ + { 194, -2 }, /* (118) alter_db_optr ::= alter_db_optr fsync */ + { 194, -2 }, /* (119) alter_db_optr ::= alter_db_optr update */ + { 194, -2 }, /* (120) alter_db_optr ::= alter_db_optr cachelast */ + { 195, -1 }, /* (121) alter_topic_optr ::= alter_db_optr */ + { 195, -2 }, /* (122) alter_topic_optr ::= alter_topic_optr partitions */ + { 226, -1 }, /* (123) typename ::= ids */ + { 226, -4 }, /* (124) typename ::= ids LP signed RP */ + { 226, -2 }, /* (125) typename ::= ids UNSIGNED */ + { 227, -1 }, /* (126) signed ::= INTEGER */ + { 227, -2 }, /* (127) signed ::= PLUS INTEGER */ + { 227, -2 }, /* (128) signed ::= MINUS INTEGER */ + { 189, -3 }, /* (129) cmd ::= CREATE TABLE create_table_args */ + { 189, -3 }, /* (130) cmd ::= CREATE TABLE create_stable_args */ + { 189, -3 }, /* (131) cmd ::= CREATE STABLE create_stable_args */ + { 189, -3 }, /* (132) cmd ::= CREATE TABLE create_table_list */ + { 230, -1 }, /* (133) create_table_list ::= create_from_stable */ + { 230, -2 }, /* (134) create_table_list ::= create_table_list create_from_stable */ + { 228, -6 }, /* (135) create_table_args ::= ifnotexists ids cpxName LP columnlist RP */ + { 229, -10 }, /* (136) create_stable_args ::= ifnotexists ids cpxName LP columnlist RP TAGS LP columnlist RP */ + { 231, -10 }, /* (137) create_from_stable ::= ifnotexists ids cpxName USING ids cpxName TAGS LP tagitemlist RP */ + { 231, -13 }, /* (138) create_from_stable ::= ifnotexists ids cpxName USING ids cpxName LP tagNamelist RP TAGS LP tagitemlist RP */ + { 233, -3 }, /* (139) tagNamelist ::= tagNamelist COMMA ids */ + { 233, -1 }, /* (140) tagNamelist ::= ids */ + { 228, -5 }, /* (141) create_table_args ::= ifnotexists ids cpxName AS select */ + { 232, -3 }, /* (142) columnlist ::= columnlist COMMA column */ + { 232, -1 }, /* (143) columnlist ::= column */ + { 235, -2 }, /* (144) column ::= ids typename */ + { 210, -3 }, /* (145) tagitemlist ::= tagitemlist COMMA tagitem */ + { 210, -1 }, /* (146) tagitemlist ::= tagitem */ + { 236, -1 }, /* (147) tagitem ::= INTEGER */ + { 236, -1 }, /* (148) tagitem ::= FLOAT */ + { 236, -1 }, /* (149) tagitem ::= STRING */ + { 236, -1 }, /* (150) tagitem ::= BOOL */ + { 236, -1 }, /* (151) tagitem ::= NULL */ + { 236, -2 }, /* (152) tagitem ::= MINUS INTEGER */ + { 236, -2 }, /* (153) tagitem ::= MINUS FLOAT */ + { 236, -2 }, /* (154) tagitem ::= PLUS INTEGER */ + { 236, -2 }, /* (155) tagitem ::= PLUS FLOAT */ + { 234, -13 }, /* (156) select ::= SELECT selcollist from where_opt interval_opt session_option fill_opt sliding_opt groupby_opt orderby_opt having_opt slimit_opt limit_opt */ + { 234, -3 }, /* (157) select ::= LP select RP */ + { 249, -1 }, /* (158) union ::= select */ + { 249, -4 }, /* (159) union ::= union UNION ALL select */ + { 189, -1 }, /* (160) cmd ::= union */ + { 234, -2 }, /* (161) select ::= SELECT selcollist */ + { 250, -2 }, /* (162) sclp ::= selcollist COMMA */ + { 250, 0 }, /* (163) sclp ::= */ + { 237, -4 }, /* (164) selcollist ::= sclp distinct expr as */ + { 237, -2 }, /* (165) selcollist ::= sclp STAR */ + { 253, -2 }, /* (166) as ::= AS ids */ + { 253, -1 }, /* (167) as ::= ids */ + { 253, 0 }, /* (168) as ::= */ + { 251, -1 }, /* (169) distinct ::= DISTINCT */ + { 251, 0 }, /* (170) distinct ::= */ + { 238, -2 }, /* (171) from ::= FROM tablelist */ + { 238, -4 }, /* (172) from ::= FROM LP union RP */ + { 254, -2 }, /* (173) tablelist ::= ids cpxName */ + { 254, -3 }, /* (174) tablelist ::= ids cpxName ids */ + { 254, -4 }, /* (175) tablelist ::= tablelist COMMA ids cpxName */ + { 254, -5 }, /* (176) tablelist ::= tablelist COMMA ids cpxName ids */ + { 255, -1 }, /* (177) tmvar ::= VARIABLE */ + { 240, -4 }, /* (178) interval_opt ::= INTERVAL LP tmvar RP */ + { 240, -6 }, /* (179) interval_opt ::= INTERVAL LP tmvar COMMA tmvar RP */ + { 240, 0 }, /* (180) interval_opt ::= */ + { 241, 0 }, /* (181) session_option ::= */ + { 241, -7 }, /* (182) session_option ::= SESSION LP ids cpxName COMMA tmvar RP */ + { 242, 0 }, /* (183) fill_opt ::= */ + { 242, -6 }, /* (184) fill_opt ::= FILL LP ID COMMA tagitemlist RP */ + { 242, -4 }, /* (185) fill_opt ::= FILL LP ID RP */ + { 243, -4 }, /* (186) sliding_opt ::= SLIDING LP tmvar RP */ + { 243, 0 }, /* (187) sliding_opt ::= */ + { 245, 0 }, /* (188) orderby_opt ::= */ + { 245, -3 }, /* (189) orderby_opt ::= ORDER BY sortlist */ + { 256, -4 }, /* (190) sortlist ::= sortlist COMMA item sortorder */ + { 256, -2 }, /* (191) sortlist ::= item sortorder */ + { 258, -2 }, /* (192) item ::= ids cpxName */ + { 259, -1 }, /* (193) sortorder ::= ASC */ + { 259, -1 }, /* (194) sortorder ::= DESC */ + { 259, 0 }, /* (195) sortorder ::= */ + { 244, 0 }, /* (196) groupby_opt ::= */ + { 244, -3 }, /* (197) groupby_opt ::= GROUP BY grouplist */ + { 260, -3 }, /* (198) grouplist ::= grouplist COMMA item */ + { 260, -1 }, /* (199) grouplist ::= item */ + { 246, 0 }, /* (200) having_opt ::= */ + { 246, -2 }, /* (201) having_opt ::= HAVING expr */ + { 248, 0 }, /* (202) limit_opt ::= */ + { 248, -2 }, /* (203) limit_opt ::= LIMIT signed */ + { 248, -4 }, /* (204) limit_opt ::= LIMIT signed OFFSET signed */ + { 248, -4 }, /* (205) limit_opt ::= LIMIT signed COMMA signed */ + { 247, 0 }, /* (206) slimit_opt ::= */ + { 247, -2 }, /* (207) slimit_opt ::= SLIMIT signed */ + { 247, -4 }, /* (208) slimit_opt ::= SLIMIT signed SOFFSET signed */ + { 247, -4 }, /* (209) slimit_opt ::= SLIMIT signed COMMA signed */ + { 239, 0 }, /* (210) where_opt ::= */ + { 239, -2 }, /* (211) where_opt ::= WHERE expr */ + { 252, -3 }, /* (212) expr ::= LP expr RP */ + { 252, -1 }, /* (213) expr ::= ID */ + { 252, -3 }, /* (214) expr ::= ID DOT ID */ + { 252, -3 }, /* (215) expr ::= ID DOT STAR */ + { 252, -1 }, /* (216) expr ::= INTEGER */ + { 252, -2 }, /* (217) expr ::= MINUS INTEGER */ + { 252, -2 }, /* (218) expr ::= PLUS INTEGER */ + { 252, -1 }, /* (219) expr ::= FLOAT */ + { 252, -2 }, /* (220) expr ::= MINUS FLOAT */ + { 252, -2 }, /* (221) expr ::= PLUS FLOAT */ + { 252, -1 }, /* (222) expr ::= STRING */ + { 252, -1 }, /* (223) expr ::= NOW */ + { 252, -1 }, /* (224) expr ::= VARIABLE */ + { 252, -1 }, /* (225) expr ::= BOOL */ + { 252, -4 }, /* (226) expr ::= ID LP exprlist RP */ + { 252, -4 }, /* (227) expr ::= ID LP STAR RP */ + { 252, -3 }, /* (228) expr ::= expr IS NULL */ + { 252, -4 }, /* (229) expr ::= expr IS NOT NULL */ + { 252, -3 }, /* (230) expr ::= expr LT expr */ + { 252, -3 }, /* (231) expr ::= expr GT expr */ + { 252, -3 }, /* (232) expr ::= expr LE expr */ + { 252, -3 }, /* (233) expr ::= expr GE expr */ + { 252, -3 }, /* (234) expr ::= expr NE expr */ + { 252, -3 }, /* (235) expr ::= expr EQ expr */ + { 252, -5 }, /* (236) expr ::= expr BETWEEN expr AND expr */ + { 252, -3 }, /* (237) expr ::= expr AND expr */ + { 252, -3 }, /* (238) expr ::= expr OR expr */ + { 252, -3 }, /* (239) expr ::= expr PLUS expr */ + { 252, -3 }, /* (240) expr ::= expr MINUS expr */ + { 252, -3 }, /* (241) expr ::= expr STAR expr */ + { 252, -3 }, /* (242) expr ::= expr SLASH expr */ + { 252, -3 }, /* (243) expr ::= expr REM expr */ + { 252, -3 }, /* (244) expr ::= expr LIKE expr */ + { 252, -5 }, /* (245) expr ::= expr IN LP exprlist RP */ + { 261, -3 }, /* (246) exprlist ::= exprlist COMMA expritem */ + { 261, -1 }, /* (247) exprlist ::= expritem */ + { 262, -1 }, /* (248) expritem ::= expr */ + { 262, 0 }, /* (249) expritem ::= */ + { 189, -3 }, /* (250) cmd ::= RESET QUERY CACHE */ + { 189, -3 }, /* (251) cmd ::= SYNCDB ids REPLICA */ + { 189, -7 }, /* (252) cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist */ + { 189, -7 }, /* (253) cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids */ + { 189, -7 }, /* (254) cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist */ + { 189, -7 }, /* (255) cmd ::= ALTER TABLE ids cpxName DROP TAG ids */ + { 189, -8 }, /* (256) cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids */ + { 189, -9 }, /* (257) cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem */ + { 189, -7 }, /* (258) cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist */ + { 189, -7 }, /* (259) cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids */ + { 189, -7 }, /* (260) cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist */ + { 189, -7 }, /* (261) cmd ::= ALTER STABLE ids cpxName DROP TAG ids */ + { 189, -8 }, /* (262) cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids */ + { 189, -3 }, /* (263) cmd ::= KILL CONNECTION INTEGER */ + { 189, -5 }, /* (264) cmd ::= KILL STREAM INTEGER COLON INTEGER */ + { 189, -5 }, /* (265) cmd ::= KILL QUERY INTEGER COLON INTEGER */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -2252,13 +2256,13 @@ static void yy_reduce( break; case 43: /* cmd ::= ALTER DATABASE ids alter_db_optr */ case 44: /* cmd ::= ALTER TOPIC ids alter_topic_optr */ yytestcase(yyruleno==44); -{ SStrToken t = {0}; setCreateDbInfo(pInfo, TSDB_SQL_ALTER_DB, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy94, &t);} +{ SStrToken t = {0}; setCreateDbInfo(pInfo, TSDB_SQL_ALTER_DB, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy322, &t);} break; case 45: /* cmd ::= ALTER ACCOUNT ids acct_optr */ -{ setCreateAcctSql(pInfo, TSDB_SQL_ALTER_ACCT, &yymsp[-1].minor.yy0, NULL, &yymsp[0].minor.yy419);} +{ setCreateAcctSql(pInfo, TSDB_SQL_ALTER_ACCT, &yymsp[-1].minor.yy0, NULL, &yymsp[0].minor.yy351);} break; case 46: /* cmd ::= ALTER ACCOUNT ids PASS ids acct_optr */ -{ setCreateAcctSql(pInfo, TSDB_SQL_ALTER_ACCT, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy419);} +{ setCreateAcctSql(pInfo, TSDB_SQL_ALTER_ACCT, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy351);} break; case 47: /* ids ::= ID */ case 48: /* ids ::= STRING */ yytestcase(yyruleno==48); @@ -2280,11 +2284,11 @@ static void yy_reduce( { setDCLSqlElems(pInfo, TSDB_SQL_CREATE_DNODE, 1, &yymsp[0].minor.yy0);} break; case 54: /* cmd ::= CREATE ACCOUNT ids PASS ids acct_optr */ -{ setCreateAcctSql(pInfo, TSDB_SQL_CREATE_ACCT, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy419);} +{ setCreateAcctSql(pInfo, TSDB_SQL_CREATE_ACCT, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy351);} break; case 55: /* cmd ::= CREATE DATABASE ifnotexists ids db_optr */ case 56: /* cmd ::= CREATE TOPIC ifnotexists ids topic_optr */ yytestcase(yyruleno==56); -{ setCreateDbInfo(pInfo, TSDB_SQL_CREATE_DB, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy94, &yymsp[-2].minor.yy0);} +{ setCreateDbInfo(pInfo, TSDB_SQL_CREATE_DB, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy322, &yymsp[-2].minor.yy0);} break; case 57: /* cmd ::= CREATE USER ids PASS ids */ { setCreateUserSql(pInfo, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);} @@ -2313,20 +2317,20 @@ static void yy_reduce( break; case 76: /* acct_optr ::= pps tseries storage streams qtime dbs users conns state */ { - yylhsminor.yy419.maxUsers = (yymsp[-2].minor.yy0.n>0)?atoi(yymsp[-2].minor.yy0.z):-1; - yylhsminor.yy419.maxDbs = (yymsp[-3].minor.yy0.n>0)?atoi(yymsp[-3].minor.yy0.z):-1; - yylhsminor.yy419.maxTimeSeries = (yymsp[-7].minor.yy0.n>0)?atoi(yymsp[-7].minor.yy0.z):-1; - yylhsminor.yy419.maxStreams = (yymsp[-5].minor.yy0.n>0)?atoi(yymsp[-5].minor.yy0.z):-1; - yylhsminor.yy419.maxPointsPerSecond = (yymsp[-8].minor.yy0.n>0)?atoi(yymsp[-8].minor.yy0.z):-1; - yylhsminor.yy419.maxStorage = (yymsp[-6].minor.yy0.n>0)?strtoll(yymsp[-6].minor.yy0.z, NULL, 10):-1; - yylhsminor.yy419.maxQueryTime = (yymsp[-4].minor.yy0.n>0)?strtoll(yymsp[-4].minor.yy0.z, NULL, 10):-1; - yylhsminor.yy419.maxConnections = (yymsp[-1].minor.yy0.n>0)?atoi(yymsp[-1].minor.yy0.z):-1; - yylhsminor.yy419.stat = yymsp[0].minor.yy0; + yylhsminor.yy351.maxUsers = (yymsp[-2].minor.yy0.n>0)?atoi(yymsp[-2].minor.yy0.z):-1; + yylhsminor.yy351.maxDbs = (yymsp[-3].minor.yy0.n>0)?atoi(yymsp[-3].minor.yy0.z):-1; + yylhsminor.yy351.maxTimeSeries = (yymsp[-7].minor.yy0.n>0)?atoi(yymsp[-7].minor.yy0.z):-1; + yylhsminor.yy351.maxStreams = (yymsp[-5].minor.yy0.n>0)?atoi(yymsp[-5].minor.yy0.z):-1; + yylhsminor.yy351.maxPointsPerSecond = (yymsp[-8].minor.yy0.n>0)?atoi(yymsp[-8].minor.yy0.z):-1; + yylhsminor.yy351.maxStorage = (yymsp[-6].minor.yy0.n>0)?strtoll(yymsp[-6].minor.yy0.z, NULL, 10):-1; + yylhsminor.yy351.maxQueryTime = (yymsp[-4].minor.yy0.n>0)?strtoll(yymsp[-4].minor.yy0.z, NULL, 10):-1; + yylhsminor.yy351.maxConnections = (yymsp[-1].minor.yy0.n>0)?atoi(yymsp[-1].minor.yy0.z):-1; + yylhsminor.yy351.stat = yymsp[0].minor.yy0; } - yymsp[-8].minor.yy419 = yylhsminor.yy419; + yymsp[-8].minor.yy351 = yylhsminor.yy351; break; case 77: /* keep ::= KEEP tagitemlist */ -{ yymsp[-1].minor.yy429 = yymsp[0].minor.yy429; } +{ yymsp[-1].minor.yy159 = yymsp[0].minor.yy159; } break; case 78: /* cache ::= CACHE INTEGER */ case 79: /* replica ::= REPLICA INTEGER */ yytestcase(yyruleno==79); @@ -2346,234 +2350,234 @@ static void yy_reduce( { yymsp[-1].minor.yy0 = yymsp[0].minor.yy0; } break; case 93: /* db_optr ::= */ -{setDefaultCreateDbOption(&yymsp[1].minor.yy94); yymsp[1].minor.yy94.dbType = TSDB_DB_TYPE_DEFAULT;} +{setDefaultCreateDbOption(&yymsp[1].minor.yy322); yymsp[1].minor.yy322.dbType = TSDB_DB_TYPE_DEFAULT;} break; case 94: /* db_optr ::= db_optr cache */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.cacheBlockSize = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.cacheBlockSize = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 95: /* db_optr ::= db_optr replica */ case 112: /* alter_db_optr ::= alter_db_optr replica */ yytestcase(yyruleno==112); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.replica = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.replica = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 96: /* db_optr ::= db_optr quorum */ case 113: /* alter_db_optr ::= alter_db_optr quorum */ yytestcase(yyruleno==113); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.quorum = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.quorum = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 97: /* db_optr ::= db_optr days */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.daysPerFile = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.daysPerFile = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 98: /* db_optr ::= db_optr minrows */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.minRowsPerBlock = strtod(yymsp[0].minor.yy0.z, NULL); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.minRowsPerBlock = strtod(yymsp[0].minor.yy0.z, NULL); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 99: /* db_optr ::= db_optr maxrows */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.maxRowsPerBlock = strtod(yymsp[0].minor.yy0.z, NULL); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.maxRowsPerBlock = strtod(yymsp[0].minor.yy0.z, NULL); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 100: /* db_optr ::= db_optr blocks */ case 115: /* alter_db_optr ::= alter_db_optr blocks */ yytestcase(yyruleno==115); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.numOfBlocks = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.numOfBlocks = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 101: /* db_optr ::= db_optr ctime */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.commitTime = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.commitTime = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 102: /* db_optr ::= db_optr wal */ case 117: /* alter_db_optr ::= alter_db_optr wal */ yytestcase(yyruleno==117); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.walLevel = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.walLevel = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 103: /* db_optr ::= db_optr fsync */ case 118: /* alter_db_optr ::= alter_db_optr fsync */ yytestcase(yyruleno==118); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.fsyncPeriod = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.fsyncPeriod = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 104: /* db_optr ::= db_optr comp */ case 116: /* alter_db_optr ::= alter_db_optr comp */ yytestcase(yyruleno==116); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.compressionLevel = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.compressionLevel = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 105: /* db_optr ::= db_optr prec */ -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.precision = yymsp[0].minor.yy0; } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.precision = yymsp[0].minor.yy0; } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 106: /* db_optr ::= db_optr keep */ case 114: /* alter_db_optr ::= alter_db_optr keep */ yytestcase(yyruleno==114); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.keep = yymsp[0].minor.yy429; } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.keep = yymsp[0].minor.yy159; } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 107: /* db_optr ::= db_optr update */ case 119: /* alter_db_optr ::= alter_db_optr update */ yytestcase(yyruleno==119); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.update = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.update = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 108: /* db_optr ::= db_optr cachelast */ case 120: /* alter_db_optr ::= alter_db_optr cachelast */ yytestcase(yyruleno==120); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.cachelast = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.cachelast = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 109: /* topic_optr ::= db_optr */ case 121: /* alter_topic_optr ::= alter_db_optr */ yytestcase(yyruleno==121); -{ yylhsminor.yy94 = yymsp[0].minor.yy94; yylhsminor.yy94.dbType = TSDB_DB_TYPE_TOPIC; } - yymsp[0].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[0].minor.yy322; yylhsminor.yy322.dbType = TSDB_DB_TYPE_TOPIC; } + yymsp[0].minor.yy322 = yylhsminor.yy322; break; case 110: /* topic_optr ::= topic_optr partitions */ case 122: /* alter_topic_optr ::= alter_topic_optr partitions */ yytestcase(yyruleno==122); -{ yylhsminor.yy94 = yymsp[-1].minor.yy94; yylhsminor.yy94.partitions = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[-1].minor.yy94 = yylhsminor.yy94; +{ yylhsminor.yy322 = yymsp[-1].minor.yy322; yylhsminor.yy322.partitions = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[-1].minor.yy322 = yylhsminor.yy322; break; case 111: /* alter_db_optr ::= */ -{ setDefaultCreateDbOption(&yymsp[1].minor.yy94); yymsp[1].minor.yy94.dbType = TSDB_DB_TYPE_DEFAULT;} +{ setDefaultCreateDbOption(&yymsp[1].minor.yy322); yymsp[1].minor.yy322.dbType = TSDB_DB_TYPE_DEFAULT;} break; case 123: /* typename ::= ids */ { yymsp[0].minor.yy0.type = 0; - tSetColumnType (&yylhsminor.yy451, &yymsp[0].minor.yy0); + tSetColumnType (&yylhsminor.yy407, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy451 = yylhsminor.yy451; + yymsp[0].minor.yy407 = yylhsminor.yy407; break; case 124: /* typename ::= ids LP signed RP */ { - if (yymsp[-1].minor.yy481 <= 0) { + if (yymsp[-1].minor.yy317 <= 0) { yymsp[-3].minor.yy0.type = 0; - tSetColumnType(&yylhsminor.yy451, &yymsp[-3].minor.yy0); + tSetColumnType(&yylhsminor.yy407, &yymsp[-3].minor.yy0); } else { - yymsp[-3].minor.yy0.type = -yymsp[-1].minor.yy481; // negative value of name length - tSetColumnType(&yylhsminor.yy451, &yymsp[-3].minor.yy0); + yymsp[-3].minor.yy0.type = -yymsp[-1].minor.yy317; // negative value of name length + tSetColumnType(&yylhsminor.yy407, &yymsp[-3].minor.yy0); } } - yymsp[-3].minor.yy451 = yylhsminor.yy451; + yymsp[-3].minor.yy407 = yylhsminor.yy407; break; case 125: /* typename ::= ids UNSIGNED */ { yymsp[-1].minor.yy0.type = 0; yymsp[-1].minor.yy0.n = ((yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n) - yymsp[-1].minor.yy0.z); - tSetColumnType (&yylhsminor.yy451, &yymsp[-1].minor.yy0); + tSetColumnType (&yylhsminor.yy407, &yymsp[-1].minor.yy0); } - yymsp[-1].minor.yy451 = yylhsminor.yy451; + yymsp[-1].minor.yy407 = yylhsminor.yy407; break; case 126: /* signed ::= INTEGER */ -{ yylhsminor.yy481 = strtol(yymsp[0].minor.yy0.z, NULL, 10); } - yymsp[0].minor.yy481 = yylhsminor.yy481; +{ yylhsminor.yy317 = strtol(yymsp[0].minor.yy0.z, NULL, 10); } + yymsp[0].minor.yy317 = yylhsminor.yy317; break; case 127: /* signed ::= PLUS INTEGER */ -{ yymsp[-1].minor.yy481 = strtol(yymsp[0].minor.yy0.z, NULL, 10); } +{ yymsp[-1].minor.yy317 = strtol(yymsp[0].minor.yy0.z, NULL, 10); } break; case 128: /* signed ::= MINUS INTEGER */ -{ yymsp[-1].minor.yy481 = -strtol(yymsp[0].minor.yy0.z, NULL, 10);} +{ yymsp[-1].minor.yy317 = -strtol(yymsp[0].minor.yy0.z, NULL, 10);} break; case 132: /* cmd ::= CREATE TABLE create_table_list */ -{ pInfo->type = TSDB_SQL_CREATE_TABLE; pInfo->pCreateTableInfo = yymsp[0].minor.yy194;} +{ pInfo->type = TSDB_SQL_CREATE_TABLE; pInfo->pCreateTableInfo = yymsp[0].minor.yy14;} break; case 133: /* create_table_list ::= create_from_stable */ { SCreateTableSql* pCreateTable = calloc(1, sizeof(SCreateTableSql)); pCreateTable->childTableInfo = taosArrayInit(4, sizeof(SCreatedTableInfo)); - taosArrayPush(pCreateTable->childTableInfo, &yymsp[0].minor.yy252); + taosArrayPush(pCreateTable->childTableInfo, &yymsp[0].minor.yy206); pCreateTable->type = TSQL_CREATE_TABLE_FROM_STABLE; - yylhsminor.yy194 = pCreateTable; + yylhsminor.yy14 = pCreateTable; } - yymsp[0].minor.yy194 = yylhsminor.yy194; + yymsp[0].minor.yy14 = yylhsminor.yy14; break; case 134: /* create_table_list ::= create_table_list create_from_stable */ { - taosArrayPush(yymsp[-1].minor.yy194->childTableInfo, &yymsp[0].minor.yy252); - yylhsminor.yy194 = yymsp[-1].minor.yy194; + taosArrayPush(yymsp[-1].minor.yy14->childTableInfo, &yymsp[0].minor.yy206); + yylhsminor.yy14 = yymsp[-1].minor.yy14; } - yymsp[-1].minor.yy194 = yylhsminor.yy194; + yymsp[-1].minor.yy14 = yylhsminor.yy14; break; case 135: /* create_table_args ::= ifnotexists ids cpxName LP columnlist RP */ { - yylhsminor.yy194 = tSetCreateTableInfo(yymsp[-1].minor.yy429, NULL, NULL, TSQL_CREATE_TABLE); - setSqlInfo(pInfo, yylhsminor.yy194, NULL, TSDB_SQL_CREATE_TABLE); + yylhsminor.yy14 = tSetCreateTableInfo(yymsp[-1].minor.yy159, NULL, NULL, TSQL_CREATE_TABLE); + setSqlInfo(pInfo, yylhsminor.yy14, NULL, TSDB_SQL_CREATE_TABLE); yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; setCreatedTableName(pInfo, &yymsp[-4].minor.yy0, &yymsp[-5].minor.yy0); } - yymsp[-5].minor.yy194 = yylhsminor.yy194; + yymsp[-5].minor.yy14 = yylhsminor.yy14; break; case 136: /* create_stable_args ::= ifnotexists ids cpxName LP columnlist RP TAGS LP columnlist RP */ { - yylhsminor.yy194 = tSetCreateTableInfo(yymsp[-5].minor.yy429, yymsp[-1].minor.yy429, NULL, TSQL_CREATE_STABLE); - setSqlInfo(pInfo, yylhsminor.yy194, NULL, TSDB_SQL_CREATE_TABLE); + yylhsminor.yy14 = tSetCreateTableInfo(yymsp[-5].minor.yy159, yymsp[-1].minor.yy159, NULL, TSQL_CREATE_STABLE); + setSqlInfo(pInfo, yylhsminor.yy14, NULL, TSDB_SQL_CREATE_TABLE); yymsp[-8].minor.yy0.n += yymsp[-7].minor.yy0.n; setCreatedTableName(pInfo, &yymsp[-8].minor.yy0, &yymsp[-9].minor.yy0); } - yymsp[-9].minor.yy194 = yylhsminor.yy194; + yymsp[-9].minor.yy14 = yylhsminor.yy14; break; case 137: /* create_from_stable ::= ifnotexists ids cpxName USING ids cpxName TAGS LP tagitemlist RP */ { yymsp[-5].minor.yy0.n += yymsp[-4].minor.yy0.n; yymsp[-8].minor.yy0.n += yymsp[-7].minor.yy0.n; - yylhsminor.yy252 = createNewChildTableInfo(&yymsp[-5].minor.yy0, NULL, yymsp[-1].minor.yy429, &yymsp[-8].minor.yy0, &yymsp[-9].minor.yy0); + yylhsminor.yy206 = createNewChildTableInfo(&yymsp[-5].minor.yy0, NULL, yymsp[-1].minor.yy159, &yymsp[-8].minor.yy0, &yymsp[-9].minor.yy0); } - yymsp[-9].minor.yy252 = yylhsminor.yy252; + yymsp[-9].minor.yy206 = yylhsminor.yy206; break; case 138: /* create_from_stable ::= ifnotexists ids cpxName USING ids cpxName LP tagNamelist RP TAGS LP tagitemlist RP */ { yymsp[-8].minor.yy0.n += yymsp[-7].minor.yy0.n; yymsp[-11].minor.yy0.n += yymsp[-10].minor.yy0.n; - yylhsminor.yy252 = createNewChildTableInfo(&yymsp[-8].minor.yy0, yymsp[-5].minor.yy429, yymsp[-1].minor.yy429, &yymsp[-11].minor.yy0, &yymsp[-12].minor.yy0); + yylhsminor.yy206 = createNewChildTableInfo(&yymsp[-8].minor.yy0, yymsp[-5].minor.yy159, yymsp[-1].minor.yy159, &yymsp[-11].minor.yy0, &yymsp[-12].minor.yy0); } - yymsp[-12].minor.yy252 = yylhsminor.yy252; + yymsp[-12].minor.yy206 = yylhsminor.yy206; break; case 139: /* tagNamelist ::= tagNamelist COMMA ids */ -{taosArrayPush(yymsp[-2].minor.yy429, &yymsp[0].minor.yy0); yylhsminor.yy429 = yymsp[-2].minor.yy429; } - yymsp[-2].minor.yy429 = yylhsminor.yy429; +{taosArrayPush(yymsp[-2].minor.yy159, &yymsp[0].minor.yy0); yylhsminor.yy159 = yymsp[-2].minor.yy159; } + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 140: /* tagNamelist ::= ids */ -{yylhsminor.yy429 = taosArrayInit(4, sizeof(SStrToken)); taosArrayPush(yylhsminor.yy429, &yymsp[0].minor.yy0);} - yymsp[0].minor.yy429 = yylhsminor.yy429; +{yylhsminor.yy159 = taosArrayInit(4, sizeof(SStrToken)); taosArrayPush(yylhsminor.yy159, &yymsp[0].minor.yy0);} + yymsp[0].minor.yy159 = yylhsminor.yy159; break; case 141: /* create_table_args ::= ifnotexists ids cpxName AS select */ { - yylhsminor.yy194 = tSetCreateTableInfo(NULL, NULL, yymsp[0].minor.yy254, TSQL_CREATE_STREAM); - setSqlInfo(pInfo, yylhsminor.yy194, NULL, TSDB_SQL_CREATE_TABLE); + yylhsminor.yy14 = tSetCreateTableInfo(NULL, NULL, yymsp[0].minor.yy272, TSQL_CREATE_STREAM); + setSqlInfo(pInfo, yylhsminor.yy14, NULL, TSDB_SQL_CREATE_TABLE); yymsp[-3].minor.yy0.n += yymsp[-2].minor.yy0.n; setCreatedTableName(pInfo, &yymsp[-3].minor.yy0, &yymsp[-4].minor.yy0); } - yymsp[-4].minor.yy194 = yylhsminor.yy194; + yymsp[-4].minor.yy14 = yylhsminor.yy14; break; case 142: /* columnlist ::= columnlist COMMA column */ -{taosArrayPush(yymsp[-2].minor.yy429, &yymsp[0].minor.yy451); yylhsminor.yy429 = yymsp[-2].minor.yy429; } - yymsp[-2].minor.yy429 = yylhsminor.yy429; +{taosArrayPush(yymsp[-2].minor.yy159, &yymsp[0].minor.yy407); yylhsminor.yy159 = yymsp[-2].minor.yy159; } + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 143: /* columnlist ::= column */ -{yylhsminor.yy429 = taosArrayInit(4, sizeof(TAOS_FIELD)); taosArrayPush(yylhsminor.yy429, &yymsp[0].minor.yy451);} - yymsp[0].minor.yy429 = yylhsminor.yy429; +{yylhsminor.yy159 = taosArrayInit(4, sizeof(TAOS_FIELD)); taosArrayPush(yylhsminor.yy159, &yymsp[0].minor.yy407);} + yymsp[0].minor.yy159 = yylhsminor.yy159; break; case 144: /* column ::= ids typename */ { - tSetColumnInfo(&yylhsminor.yy451, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy451); + tSetColumnInfo(&yylhsminor.yy407, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy407); } - yymsp[-1].minor.yy451 = yylhsminor.yy451; + yymsp[-1].minor.yy407 = yylhsminor.yy407; break; case 145: /* tagitemlist ::= tagitemlist COMMA tagitem */ -{ yylhsminor.yy429 = tVariantListAppend(yymsp[-2].minor.yy429, &yymsp[0].minor.yy218, -1); } - yymsp[-2].minor.yy429 = yylhsminor.yy429; +{ yylhsminor.yy159 = tVariantListAppend(yymsp[-2].minor.yy159, &yymsp[0].minor.yy488, -1); } + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 146: /* tagitemlist ::= tagitem */ -{ yylhsminor.yy429 = tVariantListAppend(NULL, &yymsp[0].minor.yy218, -1); } - yymsp[0].minor.yy429 = yylhsminor.yy429; +{ yylhsminor.yy159 = tVariantListAppend(NULL, &yymsp[0].minor.yy488, -1); } + yymsp[0].minor.yy159 = yylhsminor.yy159; break; case 147: /* tagitem ::= INTEGER */ case 148: /* tagitem ::= FLOAT */ yytestcase(yyruleno==148); case 149: /* tagitem ::= STRING */ yytestcase(yyruleno==149); case 150: /* tagitem ::= BOOL */ yytestcase(yyruleno==150); -{ toTSDBType(yymsp[0].minor.yy0.type); tVariantCreate(&yylhsminor.yy218, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy218 = yylhsminor.yy218; +{ toTSDBType(yymsp[0].minor.yy0.type); tVariantCreate(&yylhsminor.yy488, &yymsp[0].minor.yy0); } + yymsp[0].minor.yy488 = yylhsminor.yy488; break; case 151: /* tagitem ::= NULL */ -{ yymsp[0].minor.yy0.type = 0; tVariantCreate(&yylhsminor.yy218, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy218 = yylhsminor.yy218; +{ yymsp[0].minor.yy0.type = 0; tVariantCreate(&yylhsminor.yy488, &yymsp[0].minor.yy0); } + yymsp[0].minor.yy488 = yylhsminor.yy488; break; case 152: /* tagitem ::= MINUS INTEGER */ case 153: /* tagitem ::= MINUS FLOAT */ yytestcase(yyruleno==153); @@ -2583,56 +2587,56 @@ static void yy_reduce( yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; yymsp[-1].minor.yy0.type = yymsp[0].minor.yy0.type; toTSDBType(yymsp[-1].minor.yy0.type); - tVariantCreate(&yylhsminor.yy218, &yymsp[-1].minor.yy0); + tVariantCreate(&yylhsminor.yy488, &yymsp[-1].minor.yy0); } - yymsp[-1].minor.yy218 = yylhsminor.yy218; + yymsp[-1].minor.yy488 = yylhsminor.yy488; break; case 156: /* select ::= SELECT selcollist from where_opt interval_opt session_option fill_opt sliding_opt groupby_opt orderby_opt having_opt slimit_opt limit_opt */ { - yylhsminor.yy254 = tSetQuerySqlNode(&yymsp[-12].minor.yy0, yymsp[-11].minor.yy429, yymsp[-10].minor.yy70, yymsp[-9].minor.yy170, yymsp[-4].minor.yy429, yymsp[-3].minor.yy429, &yymsp[-8].minor.yy220, &yymsp[-7].minor.yy87, &yymsp[-5].minor.yy0, yymsp[-6].minor.yy429, &yymsp[0].minor.yy18, &yymsp[-1].minor.yy18); + yylhsminor.yy272 = tSetQuerySqlNode(&yymsp[-12].minor.yy0, yymsp[-11].minor.yy159, yymsp[-10].minor.yy514, yymsp[-9].minor.yy118, yymsp[-4].minor.yy159, yymsp[-3].minor.yy159, &yymsp[-8].minor.yy184, &yymsp[-7].minor.yy249, &yymsp[-5].minor.yy0, yymsp[-6].minor.yy159, &yymsp[0].minor.yy440, &yymsp[-1].minor.yy440); } - yymsp[-12].minor.yy254 = yylhsminor.yy254; + yymsp[-12].minor.yy272 = yylhsminor.yy272; break; case 157: /* select ::= LP select RP */ -{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} +{yymsp[-2].minor.yy272 = yymsp[-1].minor.yy272;} break; case 158: /* union ::= select */ -{ yylhsminor.yy141 = setSubclause(NULL, yymsp[0].minor.yy254); } - yymsp[0].minor.yy141 = yylhsminor.yy141; +{ yylhsminor.yy391 = setSubclause(NULL, yymsp[0].minor.yy272); } + yymsp[0].minor.yy391 = yylhsminor.yy391; break; case 159: /* union ::= union UNION ALL select */ -{ yylhsminor.yy141 = appendSelectClause(yymsp[-3].minor.yy141, yymsp[0].minor.yy254); } - yymsp[-3].minor.yy141 = yylhsminor.yy141; +{ yylhsminor.yy391 = appendSelectClause(yymsp[-3].minor.yy391, yymsp[0].minor.yy272); } + yymsp[-3].minor.yy391 = yylhsminor.yy391; break; case 160: /* cmd ::= union */ -{ setSqlInfo(pInfo, yymsp[0].minor.yy141, NULL, TSDB_SQL_SELECT); } +{ setSqlInfo(pInfo, yymsp[0].minor.yy391, NULL, TSDB_SQL_SELECT); } break; case 161: /* select ::= SELECT selcollist */ { - yylhsminor.yy254 = tSetQuerySqlNode(&yymsp[-1].minor.yy0, yymsp[0].minor.yy429, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + yylhsminor.yy272 = tSetQuerySqlNode(&yymsp[-1].minor.yy0, yymsp[0].minor.yy159, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } - yymsp[-1].minor.yy254 = yylhsminor.yy254; + yymsp[-1].minor.yy272 = yylhsminor.yy272; break; case 162: /* sclp ::= selcollist COMMA */ -{yylhsminor.yy429 = yymsp[-1].minor.yy429;} - yymsp[-1].minor.yy429 = yylhsminor.yy429; +{yylhsminor.yy159 = yymsp[-1].minor.yy159;} + yymsp[-1].minor.yy159 = yylhsminor.yy159; break; case 163: /* sclp ::= */ case 188: /* orderby_opt ::= */ yytestcase(yyruleno==188); -{yymsp[1].minor.yy429 = 0;} +{yymsp[1].minor.yy159 = 0;} break; case 164: /* selcollist ::= sclp distinct expr as */ { - yylhsminor.yy429 = tSqlExprListAppend(yymsp[-3].minor.yy429, yymsp[-1].minor.yy170, yymsp[-2].minor.yy0.n? &yymsp[-2].minor.yy0:0, yymsp[0].minor.yy0.n?&yymsp[0].minor.yy0:0); + yylhsminor.yy159 = tSqlExprListAppend(yymsp[-3].minor.yy159, yymsp[-1].minor.yy118, yymsp[-2].minor.yy0.n? &yymsp[-2].minor.yy0:0, yymsp[0].minor.yy0.n?&yymsp[0].minor.yy0:0); } - yymsp[-3].minor.yy429 = yylhsminor.yy429; + yymsp[-3].minor.yy159 = yylhsminor.yy159; break; case 165: /* selcollist ::= sclp STAR */ { tSqlExpr *pNode = tSqlExprCreateIdValue(NULL, TK_ALL); - yylhsminor.yy429 = tSqlExprListAppend(yymsp[-1].minor.yy429, pNode, 0, 0); + yylhsminor.yy159 = tSqlExprListAppend(yymsp[-1].minor.yy159, pNode, 0, 0); } - yymsp[-1].minor.yy429 = yylhsminor.yy429; + yymsp[-1].minor.yy159 = yylhsminor.yy159; break; case 166: /* as ::= AS ids */ { yymsp[-1].minor.yy0 = yymsp[0].minor.yy0; } @@ -2649,35 +2653,35 @@ static void yy_reduce( yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 171: /* from ::= FROM tablelist */ -{yymsp[-1].minor.yy70 = yymsp[0].minor.yy429;} +{yymsp[-1].minor.yy514 = yymsp[0].minor.yy159;} break; case 172: /* from ::= FROM LP union RP */ -{yymsp[-3].minor.yy70 = yymsp[-1].minor.yy141;} +{yymsp[-3].minor.yy514 = yymsp[-1].minor.yy391;} break; case 173: /* tablelist ::= ids cpxName */ { toTSDBType(yymsp[-1].minor.yy0.type); yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; - yylhsminor.yy429 = setTableNameList(NULL, &yymsp[-1].minor.yy0, NULL); + yylhsminor.yy159 = setTableNameList(NULL, &yymsp[-1].minor.yy0, NULL); } - yymsp[-1].minor.yy429 = yylhsminor.yy429; + yymsp[-1].minor.yy159 = yylhsminor.yy159; break; case 174: /* tablelist ::= ids cpxName ids */ { toTSDBType(yymsp[-2].minor.yy0.type); toTSDBType(yymsp[0].minor.yy0.type); yymsp[-2].minor.yy0.n += yymsp[-1].minor.yy0.n; - yylhsminor.yy429 = setTableNameList(NULL, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + yylhsminor.yy159 = setTableNameList(NULL, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } - yymsp[-2].minor.yy429 = yylhsminor.yy429; + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 175: /* tablelist ::= tablelist COMMA ids cpxName */ { toTSDBType(yymsp[-1].minor.yy0.type); yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; - yylhsminor.yy429 = setTableNameList(yymsp[-3].minor.yy429, &yymsp[-1].minor.yy0, NULL); + yylhsminor.yy159 = setTableNameList(yymsp[-3].minor.yy159, &yymsp[-1].minor.yy0, NULL); } - yymsp[-3].minor.yy429 = yylhsminor.yy429; + yymsp[-3].minor.yy159 = yylhsminor.yy159; break; case 176: /* tablelist ::= tablelist COMMA ids cpxName ids */ { @@ -2685,35 +2689,35 @@ static void yy_reduce( toTSDBType(yymsp[0].minor.yy0.type); yymsp[-2].minor.yy0.n += yymsp[-1].minor.yy0.n; - yylhsminor.yy429 = setTableNameList(yymsp[-4].minor.yy429, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + yylhsminor.yy159 = setTableNameList(yymsp[-4].minor.yy159, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } - yymsp[-4].minor.yy429 = yylhsminor.yy429; + yymsp[-4].minor.yy159 = yylhsminor.yy159; break; case 177: /* tmvar ::= VARIABLE */ {yylhsminor.yy0 = yymsp[0].minor.yy0;} yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 178: /* interval_opt ::= INTERVAL LP tmvar RP */ -{yymsp[-3].minor.yy220.interval = yymsp[-1].minor.yy0; yymsp[-3].minor.yy220.offset.n = 0;} +{yymsp[-3].minor.yy184.interval = yymsp[-1].minor.yy0; yymsp[-3].minor.yy184.offset.n = 0;} break; case 179: /* interval_opt ::= INTERVAL LP tmvar COMMA tmvar RP */ -{yymsp[-5].minor.yy220.interval = yymsp[-3].minor.yy0; yymsp[-5].minor.yy220.offset = yymsp[-1].minor.yy0;} +{yymsp[-5].minor.yy184.interval = yymsp[-3].minor.yy0; yymsp[-5].minor.yy184.offset = yymsp[-1].minor.yy0;} break; case 180: /* interval_opt ::= */ -{memset(&yymsp[1].minor.yy220, 0, sizeof(yymsp[1].minor.yy220));} +{memset(&yymsp[1].minor.yy184, 0, sizeof(yymsp[1].minor.yy184));} break; case 181: /* session_option ::= */ -{yymsp[1].minor.yy87.col.n = 0; yymsp[1].minor.yy87.gap.n = 0;} +{yymsp[1].minor.yy249.col.n = 0; yymsp[1].minor.yy249.gap.n = 0;} break; case 182: /* session_option ::= SESSION LP ids cpxName COMMA tmvar RP */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; - yymsp[-6].minor.yy87.col = yymsp[-4].minor.yy0; - yymsp[-6].minor.yy87.gap = yymsp[-1].minor.yy0; + yymsp[-6].minor.yy249.col = yymsp[-4].minor.yy0; + yymsp[-6].minor.yy249.gap = yymsp[-1].minor.yy0; } break; case 183: /* fill_opt ::= */ -{ yymsp[1].minor.yy429 = 0; } +{ yymsp[1].minor.yy159 = 0; } break; case 184: /* fill_opt ::= FILL LP ID COMMA tagitemlist RP */ { @@ -2721,14 +2725,14 @@ static void yy_reduce( toTSDBType(yymsp[-3].minor.yy0.type); tVariantCreate(&A, &yymsp[-3].minor.yy0); - tVariantListInsert(yymsp[-1].minor.yy429, &A, -1, 0); - yymsp[-5].minor.yy429 = yymsp[-1].minor.yy429; + tVariantListInsert(yymsp[-1].minor.yy159, &A, -1, 0); + yymsp[-5].minor.yy159 = yymsp[-1].minor.yy159; } break; case 185: /* fill_opt ::= FILL LP ID RP */ { toTSDBType(yymsp[-1].minor.yy0.type); - yymsp[-3].minor.yy429 = tVariantListAppendToken(NULL, &yymsp[-1].minor.yy0, -1); + yymsp[-3].minor.yy159 = tVariantListAppendToken(NULL, &yymsp[-1].minor.yy0, -1); } break; case 186: /* sliding_opt ::= SLIDING LP tmvar RP */ @@ -2738,238 +2742,241 @@ static void yy_reduce( {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = NULL; yymsp[1].minor.yy0.type = 0; } break; case 189: /* orderby_opt ::= ORDER BY sortlist */ -{yymsp[-2].minor.yy429 = yymsp[0].minor.yy429;} +{yymsp[-2].minor.yy159 = yymsp[0].minor.yy159;} break; case 190: /* sortlist ::= sortlist COMMA item sortorder */ { - yylhsminor.yy429 = tVariantListAppend(yymsp[-3].minor.yy429, &yymsp[-1].minor.yy218, yymsp[0].minor.yy116); + yylhsminor.yy159 = tVariantListAppend(yymsp[-3].minor.yy159, &yymsp[-1].minor.yy488, yymsp[0].minor.yy20); } - yymsp[-3].minor.yy429 = yylhsminor.yy429; + yymsp[-3].minor.yy159 = yylhsminor.yy159; break; case 191: /* sortlist ::= item sortorder */ { - yylhsminor.yy429 = tVariantListAppend(NULL, &yymsp[-1].minor.yy218, yymsp[0].minor.yy116); + yylhsminor.yy159 = tVariantListAppend(NULL, &yymsp[-1].minor.yy488, yymsp[0].minor.yy20); } - yymsp[-1].minor.yy429 = yylhsminor.yy429; + yymsp[-1].minor.yy159 = yylhsminor.yy159; break; case 192: /* item ::= ids cpxName */ { toTSDBType(yymsp[-1].minor.yy0.type); yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; - tVariantCreate(&yylhsminor.yy218, &yymsp[-1].minor.yy0); + tVariantCreate(&yylhsminor.yy488, &yymsp[-1].minor.yy0); } - yymsp[-1].minor.yy218 = yylhsminor.yy218; + yymsp[-1].minor.yy488 = yylhsminor.yy488; break; case 193: /* sortorder ::= ASC */ -{ yymsp[0].minor.yy116 = TSDB_ORDER_ASC; } +{ yymsp[0].minor.yy20 = TSDB_ORDER_ASC; } break; case 194: /* sortorder ::= DESC */ -{ yymsp[0].minor.yy116 = TSDB_ORDER_DESC;} +{ yymsp[0].minor.yy20 = TSDB_ORDER_DESC;} break; case 195: /* sortorder ::= */ -{ yymsp[1].minor.yy116 = TSDB_ORDER_ASC; } +{ yymsp[1].minor.yy20 = TSDB_ORDER_ASC; } break; case 196: /* groupby_opt ::= */ -{ yymsp[1].minor.yy429 = 0;} +{ yymsp[1].minor.yy159 = 0;} break; case 197: /* groupby_opt ::= GROUP BY grouplist */ -{ yymsp[-2].minor.yy429 = yymsp[0].minor.yy429;} +{ yymsp[-2].minor.yy159 = yymsp[0].minor.yy159;} break; case 198: /* grouplist ::= grouplist COMMA item */ { - yylhsminor.yy429 = tVariantListAppend(yymsp[-2].minor.yy429, &yymsp[0].minor.yy218, -1); + yylhsminor.yy159 = tVariantListAppend(yymsp[-2].minor.yy159, &yymsp[0].minor.yy488, -1); } - yymsp[-2].minor.yy429 = yylhsminor.yy429; + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 199: /* grouplist ::= item */ { - yylhsminor.yy429 = tVariantListAppend(NULL, &yymsp[0].minor.yy218, -1); + yylhsminor.yy159 = tVariantListAppend(NULL, &yymsp[0].minor.yy488, -1); } - yymsp[0].minor.yy429 = yylhsminor.yy429; + yymsp[0].minor.yy159 = yylhsminor.yy159; break; case 200: /* having_opt ::= */ case 210: /* where_opt ::= */ yytestcase(yyruleno==210); case 249: /* expritem ::= */ yytestcase(yyruleno==249); -{yymsp[1].minor.yy170 = 0;} +{yymsp[1].minor.yy118 = 0;} break; case 201: /* having_opt ::= HAVING expr */ case 211: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==211); -{yymsp[-1].minor.yy170 = yymsp[0].minor.yy170;} +{yymsp[-1].minor.yy118 = yymsp[0].minor.yy118;} break; case 202: /* limit_opt ::= */ case 206: /* slimit_opt ::= */ yytestcase(yyruleno==206); -{yymsp[1].minor.yy18.limit = -1; yymsp[1].minor.yy18.offset = 0;} +{yymsp[1].minor.yy440.limit = -1; yymsp[1].minor.yy440.offset = 0;} break; case 203: /* limit_opt ::= LIMIT signed */ case 207: /* slimit_opt ::= SLIMIT signed */ yytestcase(yyruleno==207); -{yymsp[-1].minor.yy18.limit = yymsp[0].minor.yy481; yymsp[-1].minor.yy18.offset = 0;} +{yymsp[-1].minor.yy440.limit = yymsp[0].minor.yy317; yymsp[-1].minor.yy440.offset = 0;} break; case 204: /* limit_opt ::= LIMIT signed OFFSET signed */ -{ yymsp[-3].minor.yy18.limit = yymsp[-2].minor.yy481; yymsp[-3].minor.yy18.offset = yymsp[0].minor.yy481;} +{ yymsp[-3].minor.yy440.limit = yymsp[-2].minor.yy317; yymsp[-3].minor.yy440.offset = yymsp[0].minor.yy317;} break; case 205: /* limit_opt ::= LIMIT signed COMMA signed */ -{ yymsp[-3].minor.yy18.limit = yymsp[0].minor.yy481; yymsp[-3].minor.yy18.offset = yymsp[-2].minor.yy481;} +{ yymsp[-3].minor.yy440.limit = yymsp[0].minor.yy317; yymsp[-3].minor.yy440.offset = yymsp[-2].minor.yy317;} break; case 208: /* slimit_opt ::= SLIMIT signed SOFFSET signed */ -{yymsp[-3].minor.yy18.limit = yymsp[-2].minor.yy481; yymsp[-3].minor.yy18.offset = yymsp[0].minor.yy481;} +{yymsp[-3].minor.yy440.limit = yymsp[-2].minor.yy317; yymsp[-3].minor.yy440.offset = yymsp[0].minor.yy317;} break; case 209: /* slimit_opt ::= SLIMIT signed COMMA signed */ -{yymsp[-3].minor.yy18.limit = yymsp[0].minor.yy481; yymsp[-3].minor.yy18.offset = yymsp[-2].minor.yy481;} +{yymsp[-3].minor.yy440.limit = yymsp[0].minor.yy317; yymsp[-3].minor.yy440.offset = yymsp[-2].minor.yy317;} break; case 212: /* expr ::= LP expr RP */ -{yylhsminor.yy170 = yymsp[-1].minor.yy170; yylhsminor.yy170->token.z = yymsp[-2].minor.yy0.z; yylhsminor.yy170->token.n = (yymsp[0].minor.yy0.z - yymsp[-2].minor.yy0.z + 1);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = yymsp[-1].minor.yy118; yylhsminor.yy118->token.z = yymsp[-2].minor.yy0.z; yylhsminor.yy118->token.n = (yymsp[0].minor.yy0.z - yymsp[-2].minor.yy0.z + 1);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 213: /* expr ::= ID */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_ID);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_ID);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 214: /* expr ::= ID DOT ID */ -{ yymsp[-2].minor.yy0.n += (1+yymsp[0].minor.yy0.n); yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[-2].minor.yy0, TK_ID);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{ yymsp[-2].minor.yy0.n += (1+yymsp[0].minor.yy0.n); yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[-2].minor.yy0, TK_ID);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 215: /* expr ::= ID DOT STAR */ -{ yymsp[-2].minor.yy0.n += (1+yymsp[0].minor.yy0.n); yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[-2].minor.yy0, TK_ALL);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{ yymsp[-2].minor.yy0.n += (1+yymsp[0].minor.yy0.n); yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[-2].minor.yy0, TK_ALL);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 216: /* expr ::= INTEGER */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_INTEGER);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_INTEGER);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 217: /* expr ::= MINUS INTEGER */ case 218: /* expr ::= PLUS INTEGER */ yytestcase(yyruleno==218); -{ yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; yymsp[-1].minor.yy0.type = TK_INTEGER; yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[-1].minor.yy0, TK_INTEGER);} - yymsp[-1].minor.yy170 = yylhsminor.yy170; +{ yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; yymsp[-1].minor.yy0.type = TK_INTEGER; yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[-1].minor.yy0, TK_INTEGER);} + yymsp[-1].minor.yy118 = yylhsminor.yy118; break; case 219: /* expr ::= FLOAT */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_FLOAT);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_FLOAT);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 220: /* expr ::= MINUS FLOAT */ case 221: /* expr ::= PLUS FLOAT */ yytestcase(yyruleno==221); -{ yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; yymsp[-1].minor.yy0.type = TK_FLOAT; yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[-1].minor.yy0, TK_FLOAT);} - yymsp[-1].minor.yy170 = yylhsminor.yy170; +{ yymsp[-1].minor.yy0.n += yymsp[0].minor.yy0.n; yymsp[-1].minor.yy0.type = TK_FLOAT; yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[-1].minor.yy0, TK_FLOAT);} + yymsp[-1].minor.yy118 = yylhsminor.yy118; break; case 222: /* expr ::= STRING */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_STRING);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_STRING);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 223: /* expr ::= NOW */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_NOW); } - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_NOW); } + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 224: /* expr ::= VARIABLE */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_VARIABLE);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_VARIABLE);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 225: /* expr ::= BOOL */ -{ yylhsminor.yy170 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_BOOL);} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateIdValue(&yymsp[0].minor.yy0, TK_BOOL);} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 226: /* expr ::= ID LP exprlist RP */ -{ yylhsminor.yy170 = tSqlExprCreateFunction(yymsp[-1].minor.yy429, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); } - yymsp[-3].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateFunction(yymsp[-1].minor.yy159, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); } + yymsp[-3].minor.yy118 = yylhsminor.yy118; break; case 227: /* expr ::= ID LP STAR RP */ -{ yylhsminor.yy170 = tSqlExprCreateFunction(NULL, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); } - yymsp[-3].minor.yy170 = yylhsminor.yy170; +{ yylhsminor.yy118 = tSqlExprCreateFunction(NULL, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); } + yymsp[-3].minor.yy118 = yylhsminor.yy118; break; case 228: /* expr ::= expr IS NULL */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, NULL, TK_ISNULL);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, NULL, TK_ISNULL);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 229: /* expr ::= expr IS NOT NULL */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-3].minor.yy170, NULL, TK_NOTNULL);} - yymsp[-3].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-3].minor.yy118, NULL, TK_NOTNULL);} + yymsp[-3].minor.yy118 = yylhsminor.yy118; break; case 230: /* expr ::= expr LT expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_LT);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_LT);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 231: /* expr ::= expr GT expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_GT);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_GT);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 232: /* expr ::= expr LE expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_LE);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_LE);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 233: /* expr ::= expr GE expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_GE);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_GE);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 234: /* expr ::= expr NE expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_NE);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_NE);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 235: /* expr ::= expr EQ expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_EQ);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_EQ);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 236: /* expr ::= expr BETWEEN expr AND expr */ -{ tSqlExpr* X2 = tSqlExprClone(yymsp[-4].minor.yy170); yylhsminor.yy170 = tSqlExprCreate(tSqlExprCreate(yymsp[-4].minor.yy170, yymsp[-2].minor.yy170, TK_GE), tSqlExprCreate(X2, yymsp[0].minor.yy170, TK_LE), TK_AND);} - yymsp[-4].minor.yy170 = yylhsminor.yy170; +{ tSqlExpr* X2 = tSqlExprClone(yymsp[-4].minor.yy118); yylhsminor.yy118 = tSqlExprCreate(tSqlExprCreate(yymsp[-4].minor.yy118, yymsp[-2].minor.yy118, TK_GE), tSqlExprCreate(X2, yymsp[0].minor.yy118, TK_LE), TK_AND);} + yymsp[-4].minor.yy118 = yylhsminor.yy118; break; case 237: /* expr ::= expr AND expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_AND);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_AND);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 238: /* expr ::= expr OR expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_OR); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_OR); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 239: /* expr ::= expr PLUS expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_PLUS); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_PLUS); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 240: /* expr ::= expr MINUS expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_MINUS); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_MINUS); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 241: /* expr ::= expr STAR expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_STAR); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_STAR); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 242: /* expr ::= expr SLASH expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_DIVIDE);} - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_DIVIDE);} + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 243: /* expr ::= expr REM expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_REM); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_REM); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 244: /* expr ::= expr LIKE expr */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-2].minor.yy170, yymsp[0].minor.yy170, TK_LIKE); } - yymsp[-2].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-2].minor.yy118, yymsp[0].minor.yy118, TK_LIKE); } + yymsp[-2].minor.yy118 = yylhsminor.yy118; break; case 245: /* expr ::= expr IN LP exprlist RP */ -{yylhsminor.yy170 = tSqlExprCreate(yymsp[-4].minor.yy170, (tSqlExpr*)yymsp[-1].minor.yy429, TK_IN); } - yymsp[-4].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = tSqlExprCreate(yymsp[-4].minor.yy118, (tSqlExpr*)yymsp[-1].minor.yy159, TK_IN); } + yymsp[-4].minor.yy118 = yylhsminor.yy118; break; case 246: /* exprlist ::= exprlist COMMA expritem */ -{yylhsminor.yy429 = tSqlExprListAppend(yymsp[-2].minor.yy429,yymsp[0].minor.yy170,0, 0);} - yymsp[-2].minor.yy429 = yylhsminor.yy429; +{yylhsminor.yy159 = tSqlExprListAppend(yymsp[-2].minor.yy159,yymsp[0].minor.yy118,0, 0);} + yymsp[-2].minor.yy159 = yylhsminor.yy159; break; case 247: /* exprlist ::= expritem */ -{yylhsminor.yy429 = tSqlExprListAppend(0,yymsp[0].minor.yy170,0, 0);} - yymsp[0].minor.yy429 = yylhsminor.yy429; +{yylhsminor.yy159 = tSqlExprListAppend(0,yymsp[0].minor.yy118,0, 0);} + yymsp[0].minor.yy159 = yylhsminor.yy159; break; case 248: /* expritem ::= expr */ -{yylhsminor.yy170 = yymsp[0].minor.yy170;} - yymsp[0].minor.yy170 = yylhsminor.yy170; +{yylhsminor.yy118 = yymsp[0].minor.yy118;} + yymsp[0].minor.yy118 = yylhsminor.yy118; break; case 250: /* cmd ::= RESET QUERY CACHE */ { setDCLSqlElems(pInfo, TSDB_SQL_RESET_CACHE, 0);} break; - case 251: /* cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist */ + case 251: /* cmd ::= SYNCDB ids REPLICA */ +{ setDCLSqlElems(pInfo, TSDB_SQL_SYNC_DB_REPLICA, 1, &yymsp[-1].minor.yy0);} + break; + case 252: /* cmd ::= ALTER TABLE ids cpxName ADD COLUMN columnlist */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; - SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy429, NULL, TSDB_ALTER_TABLE_ADD_COLUMN, -1); + SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy159, NULL, TSDB_ALTER_TABLE_ADD_COLUMN, -1); setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 252: /* cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids */ + case 253: /* cmd ::= ALTER TABLE ids cpxName DROP COLUMN ids */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; @@ -2980,14 +2987,14 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 253: /* cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist */ + case 254: /* cmd ::= ALTER TABLE ids cpxName ADD TAG columnlist */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; - SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy429, NULL, TSDB_ALTER_TABLE_ADD_TAG_COLUMN, -1); + SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy159, NULL, TSDB_ALTER_TABLE_ADD_TAG_COLUMN, -1); setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 254: /* cmd ::= ALTER TABLE ids cpxName DROP TAG ids */ + case 255: /* cmd ::= ALTER TABLE ids cpxName DROP TAG ids */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; @@ -2998,7 +3005,7 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 255: /* cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids */ + case 256: /* cmd ::= ALTER TABLE ids cpxName CHANGE TAG ids ids */ { yymsp[-5].minor.yy0.n += yymsp[-4].minor.yy0.n; @@ -3012,26 +3019,26 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 256: /* cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem */ + case 257: /* cmd ::= ALTER TABLE ids cpxName SET TAG ids EQ tagitem */ { yymsp[-6].minor.yy0.n += yymsp[-5].minor.yy0.n; toTSDBType(yymsp[-2].minor.yy0.type); SArray* A = tVariantListAppendToken(NULL, &yymsp[-2].minor.yy0, -1); - A = tVariantListAppend(A, &yymsp[0].minor.yy218, -1); + A = tVariantListAppend(A, &yymsp[0].minor.yy488, -1); SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-6].minor.yy0, NULL, A, TSDB_ALTER_TABLE_UPDATE_TAG_VAL, -1); setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 257: /* cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist */ + case 258: /* cmd ::= ALTER STABLE ids cpxName ADD COLUMN columnlist */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; - SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy429, NULL, TSDB_ALTER_TABLE_ADD_COLUMN, TSDB_SUPER_TABLE); + SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy159, NULL, TSDB_ALTER_TABLE_ADD_COLUMN, TSDB_SUPER_TABLE); setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 258: /* cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids */ + case 259: /* cmd ::= ALTER STABLE ids cpxName DROP COLUMN ids */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; @@ -3042,14 +3049,14 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 259: /* cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist */ + case 260: /* cmd ::= ALTER STABLE ids cpxName ADD TAG columnlist */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; - SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy429, NULL, TSDB_ALTER_TABLE_ADD_TAG_COLUMN, TSDB_SUPER_TABLE); + SAlterTableInfo* pAlterTable = tSetAlterTableInfo(&yymsp[-4].minor.yy0, yymsp[0].minor.yy159, NULL, TSDB_ALTER_TABLE_ADD_TAG_COLUMN, TSDB_SUPER_TABLE); setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 260: /* cmd ::= ALTER STABLE ids cpxName DROP TAG ids */ + case 261: /* cmd ::= ALTER STABLE ids cpxName DROP TAG ids */ { yymsp[-4].minor.yy0.n += yymsp[-3].minor.yy0.n; @@ -3060,7 +3067,7 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 261: /* cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids */ + case 262: /* cmd ::= ALTER STABLE ids cpxName CHANGE TAG ids ids */ { yymsp[-5].minor.yy0.n += yymsp[-4].minor.yy0.n; @@ -3074,13 +3081,13 @@ static void yy_reduce( setSqlInfo(pInfo, pAlterTable, NULL, TSDB_SQL_ALTER_TABLE); } break; - case 262: /* cmd ::= KILL CONNECTION INTEGER */ + case 263: /* cmd ::= KILL CONNECTION INTEGER */ {setKillSql(pInfo, TSDB_SQL_KILL_CONNECTION, &yymsp[0].minor.yy0);} break; - case 263: /* cmd ::= KILL STREAM INTEGER COLON INTEGER */ + case 264: /* cmd ::= KILL STREAM INTEGER COLON INTEGER */ {yymsp[-2].minor.yy0.n += (yymsp[-1].minor.yy0.n + yymsp[0].minor.yy0.n); setKillSql(pInfo, TSDB_SQL_KILL_STREAM, &yymsp[-2].minor.yy0);} break; - case 264: /* cmd ::= KILL QUERY INTEGER COLON INTEGER */ + case 265: /* cmd ::= KILL QUERY INTEGER COLON INTEGER */ {yymsp[-2].minor.yy0.n += (yymsp[-1].minor.yy0.n + yymsp[0].minor.yy0.n); setKillSql(pInfo, TSDB_SQL_KILL_QUERY, &yymsp[-2].minor.yy0);} break; default: diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c index cae227cbdb..133ae6d0ab 100644 --- a/src/rpc/src/rpcMain.c +++ b/src/rpc/src/rpcMain.c @@ -1017,6 +1017,13 @@ static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv, SRpcReqCont return pConn; } +static void doRpcReportBrokenLinkToServer(void *param, void *id) { + SRpcMsg *pRpcMsg = (SRpcMsg *)(param); + SRpcConn *pConn = (SRpcConn *)(pRpcMsg->handle); + SRpcInfo *pRpc = pConn->pRpc; + (*(pRpc->cfp))(pRpcMsg, NULL); + free(pRpcMsg); +} static void rpcReportBrokenLinkToServer(SRpcConn *pConn) { SRpcInfo *pRpc = pConn->pRpc; if (pConn->pReqMsg == NULL) return; @@ -1025,16 +1032,20 @@ static void rpcReportBrokenLinkToServer(SRpcConn *pConn) { rpcAddRef(pRpc); tDebug("%s, notify the server app, connection is gone", pConn->info); - SRpcMsg rpcMsg; - rpcMsg.pCont = pConn->pReqMsg; // pReqMsg is re-used to store the APP context from server - rpcMsg.contLen = pConn->reqMsgLen; // reqMsgLen is re-used to store the APP context length - rpcMsg.ahandle = pConn->ahandle; - rpcMsg.handle = pConn; - rpcMsg.msgType = pConn->inType; - rpcMsg.code = TSDB_CODE_RPC_NETWORK_UNAVAIL; + SRpcMsg *rpcMsg = malloc(sizeof(SRpcMsg)); + rpcMsg->pCont = pConn->pReqMsg; // pReqMsg is re-used to store the APP context from server + rpcMsg->contLen = pConn->reqMsgLen; // reqMsgLen is re-used to store the APP context length + rpcMsg->ahandle = pConn->ahandle; + rpcMsg->handle = pConn; + rpcMsg->msgType = pConn->inType; + rpcMsg->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; pConn->pReqMsg = NULL; pConn->reqMsgLen = 0; - if (pRpc->cfp) (*(pRpc->cfp))(&rpcMsg, NULL); + if (pRpc->cfp) { + taosTmrStart(doRpcReportBrokenLinkToServer, 0, rpcMsg, pRpc->tmrCtrl); + } else { + free(rpcMsg); + } } static void rpcProcessBrokenLink(SRpcConn *pConn) { @@ -1051,7 +1062,7 @@ static void rpcProcessBrokenLink(SRpcConn *pConn) { pConn->pReqMsg = NULL; taosTmrStart(rpcProcessConnError, 0, pContext, pRpc->tmrCtrl); } - + if (pConn->inType) rpcReportBrokenLinkToServer(pConn); rpcReleaseConn(pConn); diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 264bbf6b92..76d4379c5f 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -410,7 +410,7 @@ void syncConfirmForward(int64_t rid, uint64_t version, int32_t code, bool force) syncReleaseNode(pNode); } -#if 0 +#if 1 void syncRecover(int64_t rid) { SSyncPeer *pPeer; diff --git a/src/tfs/src/tdisk.c b/src/tfs/src/tdisk.c index 28c836e5d9..22601e48c3 100644 --- a/src/tfs/src/tdisk.c +++ b/src/tfs/src/tdisk.c @@ -27,7 +27,7 @@ SDisk *tfsNewDisk(int level, int id, const char *dir) { pDisk->level = level; pDisk->id = id; - strncpy(pDisk->dir, dir, TSDB_FILENAME_LEN); + tstrncpy(pDisk->dir, dir, TSDB_FILENAME_LEN); return pDisk; } diff --git a/src/tfs/src/tfs.c b/src/tfs/src/tfs.c index 63fc090f00..f78535b8ed 100644 --- a/src/tfs/src/tfs.c +++ b/src/tfs/src/tfs.c @@ -187,7 +187,7 @@ void tfsInitFile(TFILE *pf, int level, int id, const char *bname) { pf->level = level; pf->id = id; - strncpy(pf->rname, bname, TSDB_FILENAME_LEN); + tstrncpy(pf->rname, bname, TSDB_FILENAME_LEN); char tmpName[TMPNAME_LEN] = {0}; snprintf(tmpName, TMPNAME_LEN, "%s/%s", DISK_DIR(pDisk), bname); @@ -230,15 +230,15 @@ void *tfsDecodeFile(void *buf, TFILE *pf) { void tfsbasename(const TFILE *pf, char *dest) { char tname[TSDB_FILENAME_LEN] = "\0"; - strncpy(tname, pf->aname, TSDB_FILENAME_LEN); - strncpy(dest, basename(tname), TSDB_FILENAME_LEN); + tstrncpy(tname, pf->aname, TSDB_FILENAME_LEN); + tstrncpy(dest, basename(tname), TSDB_FILENAME_LEN); } void tfsdirname(const TFILE *pf, char *dest) { char tname[TSDB_FILENAME_LEN] = "\0"; - strncpy(tname, pf->aname, TSDB_FILENAME_LEN); - strncpy(dest, dirname(tname), TSDB_FILENAME_LEN); + tstrncpy(tname, pf->aname, TSDB_FILENAME_LEN); + tstrncpy(dest, dirname(tname), TSDB_FILENAME_LEN); } // DIR APIs ==================================== @@ -344,7 +344,7 @@ TDIR *tfsOpendir(const char *rname) { } tfsInitDiskIter(&(tdir->iter)); - strncpy(tdir->dirname, rname, TSDB_FILENAME_LEN); + tstrncpy(tdir->dirname, rname, TSDB_FILENAME_LEN); if (tfsOpendirImpl(tdir) < 0) { free(tdir); diff --git a/src/tsdb/inc/tsdbFile.h b/src/tsdb/inc/tsdbFile.h index f1e2422e45..792efcdb2e 100644 --- a/src/tsdb/inc/tsdbFile.h +++ b/src/tsdb/inc/tsdbFile.h @@ -334,7 +334,7 @@ static FORCE_INLINE int tsdbOpenDFileSet(SDFileSet* pSet, int flags) { static FORCE_INLINE void tsdbRemoveDFileSet(SDFileSet* pSet) { for (TSDB_FILE_T ftype = 0; ftype < TSDB_FILE_MAX; ftype++) { - tsdbRemoveDFile(TSDB_DFILE_IN_SET(pSet, ftype)); + (void)tsdbRemoveDFile(TSDB_DFILE_IN_SET(pSet, ftype)); } } diff --git a/src/tsdb/src/tsdbCommit.c b/src/tsdb/src/tsdbCommit.c index a1ed0796a6..dd0fd18019 100644 --- a/src/tsdb/src/tsdbCommit.c +++ b/src/tsdb/src/tsdbCommit.c @@ -17,7 +17,7 @@ #define TSDB_MAX_SUBBLOCKS 8 static FORCE_INLINE int TSDB_KEY_FID(TSKEY key, int32_t days, int8_t precision) { if (key < 0) { - return (int)(-((-key) / tsMsPerDay[precision] / days + 1)); + return (int)((key + 1) / tsMsPerDay[precision] / days + 1); } else { return (int)((key / tsMsPerDay[precision] / days)); } @@ -164,7 +164,7 @@ static int tsdbCommitMeta(STsdbRepo *pRepo) { tsdbError("vgId:%d failed to update META record, uid %" PRIu64 " since %s", REPO_ID(pRepo), pAct->uid, tstrerror(terrno)); tsdbCloseMFile(&mf); - tsdbApplyMFileChange(&mf, pOMFile); + (void)tsdbApplyMFileChange(&mf, pOMFile); // TODO: need to reload metaCache return -1; } @@ -304,7 +304,7 @@ static int tsdbCommitTSData(STsdbRepo *pRepo) { SDFileSet *pSet = NULL; int fid; - memset(&commith, 0, sizeof(SMemTable *)); + memset(&commith, 0, sizeof(commith)); if (pMem->numOfRows <= 0) { // No memory data, just apply retention on each file on disk @@ -399,9 +399,9 @@ static void tsdbEndCommit(STsdbRepo *pRepo, int eno) { if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_OVER, eno); SMemTable *pIMem = pRepo->imem; - tsdbLockRepo(pRepo); + (void)tsdbLockRepo(pRepo); pRepo->imem = NULL; - tsdbUnlockRepo(pRepo); + (void)tsdbUnlockRepo(pRepo); tsdbUnRefMemTable(pRepo, pIMem); tsem_post(&(pRepo->readyToCommit)); } @@ -452,6 +452,14 @@ static int tsdbCommitToFile(SCommitH *pCommith, SDFileSet *pSet, int fid) { return -1; } + if (tsdbUpdateDFileSetHeader(&(pCommith->wSet)) < 0) { + tsdbError("vgId:%d failed to update FSET %d header since %s", REPO_ID(pRepo), fid, tstrerror(terrno)); + tsdbCloseCommitFile(pCommith, true); + // revert the file change + tsdbApplyDFileSetChange(TSDB_COMMIT_WRITE_FSET(pCommith), pSet); + return -1; + } + // Close commit file tsdbCloseCommitFile(pCommith, false); @@ -1136,12 +1144,12 @@ static int tsdbMoveBlock(SCommitH *pCommith, int bidx) { } static int tsdbCommitAddBlock(SCommitH *pCommith, const SBlock *pSupBlock, const SBlock *pSubBlocks, int nSubBlocks) { - if (taosArrayPush(pCommith->aSupBlk, pSupBlock) < 0) { + if (taosArrayPush(pCommith->aSupBlk, pSupBlock) == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; } - if (pSubBlocks && taosArrayPushBatch(pCommith->aSubBlk, pSubBlocks, nSubBlocks) < 0) { + if (pSubBlocks && taosArrayPushBatch(pCommith->aSubBlk, pSubBlocks, nSubBlocks) == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; } @@ -1379,7 +1387,7 @@ static int tsdbSetAndOpenCommitFile(SCommitH *pCommith, SDFileSet *pSet, int fid tstrerror(terrno)); tsdbCloseDFileSet(pWSet); - tsdbRemoveDFile(pWHeadf); + (void)tsdbRemoveDFile(pWHeadf); if (pCommith->isRFileSet) { tsdbCloseAndUnsetFSet(&(pCommith->readh)); return -1; diff --git a/src/tsdb/src/tsdbFS.c b/src/tsdb/src/tsdbFS.c index cbff4fbeaa..a9e74cb229 100644 --- a/src/tsdb/src/tsdbFS.c +++ b/src/tsdb/src/tsdbFS.c @@ -380,7 +380,7 @@ static int tsdbSaveFSStatus(SFSStatus *pStatus, int vid) { if (taosWrite(fd, pBuf, fsheader.len) < fsheader.len) { terrno = TAOS_SYSTEM_ERROR(errno); close(fd); - remove(tfname); + (void)remove(tfname); taosTZfree(pBuf); return -1; } @@ -413,7 +413,7 @@ static void tsdbApplyFSTxnOnDisk(SFSStatus *pFrom, SFSStatus *pTo) { sizeTo = taosArrayGetSize(pTo->df); // Apply meta file change - tsdbApplyMFileChange(pFrom->pmf, pTo->pmf); + (void)tsdbApplyMFileChange(pFrom->pmf, pTo->pmf); // Apply SDFileSet change if (ifrom >= sizeFrom) { @@ -853,7 +853,7 @@ static int tsdbScanRootDir(STsdbRepo *pRepo) { continue; } - tfsremove(pf); + (void)tfsremove(pf); tsdbDebug("vgId:%d invalid file %s is removed", REPO_ID(pRepo), TFILE_NAME(pf)); } @@ -879,7 +879,7 @@ static int tsdbScanDataDir(STsdbRepo *pRepo) { tfsbasename(pf, bname); if (!tsdbIsTFileInFS(pfs, pf)) { - tfsremove(pf); + (void)tfsremove(pf); tsdbDebug("vgId:%d invalid file %s is removed", REPO_ID(pRepo), TFILE_NAME(pf)); } } @@ -939,7 +939,7 @@ static int tsdbRestoreMeta(STsdbRepo *pRepo) { if (strcmp(bname, tsdbTxnFname[TSDB_TXN_TEMP_FILE]) == 0) { // Skip current.t file tsdbInfo("vgId:%d file %s exists, remove it", REPO_ID(pRepo), TFILE_NAME(pf)); - tfsremove(pf); + (void)tfsremove(pf); continue; } @@ -1045,7 +1045,7 @@ static int tsdbRestoreDFileSet(STsdbRepo *pRepo) { int code = regexec(®ex, bname, 0, NULL, 0); if (code == 0) { - if (taosArrayPush(fArray, (void *)pf) < 0) { + if (taosArrayPush(fArray, (void *)pf) == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; tfsClosedir(tdir); taosArrayDestroy(fArray); @@ -1055,7 +1055,7 @@ static int tsdbRestoreDFileSet(STsdbRepo *pRepo) { } else if (code == REG_NOMATCH) { // Not match tsdbInfo("vgId:%d invalid file %s exists, remove it", REPO_ID(pRepo), TFILE_NAME(pf)); - tfsremove(pf); + (void)tfsremove(pf); continue; } else { // Has other error diff --git a/src/tsdb/src/tsdbFile.c b/src/tsdb/src/tsdbFile.c index 8124a0e3b5..304ba2f073 100644 --- a/src/tsdb/src/tsdbFile.c +++ b/src/tsdb/src/tsdbFile.c @@ -134,14 +134,14 @@ int tsdbCreateMFile(SMFile *pMFile, bool updateHeader) { return 0; } + pMFile->info.size += TSDB_FILE_HEAD_SIZE; + if (tsdbUpdateMFileHeader(pMFile) < 0) { tsdbCloseMFile(pMFile); tsdbRemoveMFile(pMFile); return -1; } - pMFile->info.size += TSDB_FILE_HEAD_SIZE; - return 0; } @@ -378,14 +378,14 @@ int tsdbCreateDFile(SDFile *pDFile, bool updateHeader) { return 0; } + pDFile->info.size += TSDB_FILE_HEAD_SIZE; + if (tsdbUpdateDFileHeader(pDFile) < 0) { tsdbCloseDFile(pDFile); tsdbRemoveDFile(pDFile); return -1; } - pDFile->info.size += TSDB_FILE_HEAD_SIZE; - return 0; } @@ -523,7 +523,7 @@ static int tsdbApplyDFileChange(SDFile *from, SDFile *to) { tsdbRollBackDFile(to); } } else { - tsdbRemoveDFile(from); + (void)tsdbRemoveDFile(from); } } } diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 648b6d3617..6c0137abf5 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -111,7 +111,7 @@ typedef struct STsdbQueryHandle { bool loadExternalRow; // load time window external data rows bool currentLoadExternalRows; // current load external rows int32_t loadType; // block load type - void* qinfo; // query info handle, for debug purpose + uint64_t qId; // query info handle, for debug purpose int32_t type; // query type: retrieve all data blocks, 2. retrieve only last row, 3. retrieve direct prev|next rows SDFileSet* pFileGroup; SFSIter fileIter; @@ -286,8 +286,8 @@ static SArray* createCheckInfoFromTableGroup(STsdbQueryHandle* pQueryHandle, STa } taosArrayPush(pTableCheckInfo, &info); - tsdbDebug("%p check table uid:%"PRId64", tid:%d from lastKey:%"PRId64" %p", pQueryHandle, info.tableId.uid, - info.tableId.tid, info.lastKey, pQueryHandle->qinfo); + tsdbDebug("%p check table uid:%"PRId64", tid:%d from lastKey:%"PRId64" %"PRIu64, pQueryHandle, info.tableId.uid, + info.tableId.tid, info.lastKey, pQueryHandle->qId); } } @@ -339,7 +339,7 @@ static SArray* createCheckInfoFromCheckInfo(STableCheckInfo* pCheckInfo, TSKEY s return pNew; } -static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pCond, void* qinfo, SMemRef* pMemRef) { +static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pCond, uint64_t qId, SMemRef* pMemRef) { STsdbQueryHandle* pQueryHandle = calloc(1, sizeof(STsdbQueryHandle)); if (pQueryHandle == NULL) { goto out_of_memory; @@ -353,7 +353,7 @@ static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pC pQueryHandle->cur.win = TSWINDOW_INITIALIZER; pQueryHandle->checkFiles = true; pQueryHandle->activeIndex = 0; // current active table index - pQueryHandle->qinfo = qinfo; + pQueryHandle->qId = qId; pQueryHandle->outputCapacity = ((STsdbRepo*)tsdb)->config.maxRowsPerFileBlock; pQueryHandle->allocSize = 0; pQueryHandle->locateStart = false; @@ -406,7 +406,7 @@ static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pC pQueryHandle->pDataCols = tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pQueryHandle->pTsdb->config.maxRowsPerFileBlock); if (pQueryHandle->pDataCols == NULL) { - tsdbError("%p failed to malloc buf for pDataCols, %p", pQueryHandle, pQueryHandle->qinfo); + tsdbError("%p failed to malloc buf for pDataCols, %"PRIu64, pQueryHandle, pQueryHandle->qId); terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto out_of_memory; } @@ -422,8 +422,8 @@ static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pC return NULL; } -TsdbQueryHandleT* tsdbQueryTables(STsdbRepo* tsdb, STsdbQueryCond* pCond, STableGroupInfo* groupList, void* qinfo, SMemRef* pRef) { - STsdbQueryHandle* pQueryHandle = tsdbQueryTablesImpl(tsdb, pCond, qinfo, pRef); +TsdbQueryHandleT* tsdbQueryTables(STsdbRepo* tsdb, STsdbQueryCond* pCond, STableGroupInfo* groupList, uint64_t qId, SMemRef* pRef) { + STsdbQueryHandle* pQueryHandle = tsdbQueryTablesImpl(tsdb, pCond, qId, pRef); STsdbMeta* pMeta = tsdbGetMeta(tsdb); assert(pMeta != NULL); @@ -440,7 +440,7 @@ TsdbQueryHandleT* tsdbQueryTables(STsdbRepo* tsdb, STsdbQueryCond* pCond, STable tsdbMayTakeMemSnapshot(pQueryHandle, psTable); - tsdbDebug("%p total numOfTable:%" PRIzu " in query, %p", pQueryHandle, taosArrayGetSize(pQueryHandle->pTableCheckInfo), pQueryHandle->qinfo); + tsdbDebug("%p total numOfTable:%" PRIzu " in query, %"PRIu64, pQueryHandle, taosArrayGetSize(pQueryHandle->pTableCheckInfo), pQueryHandle->qId); return (TsdbQueryHandleT) pQueryHandle; } @@ -512,7 +512,7 @@ void tsdbResetQueryHandleForNewTable(TsdbQueryHandleT queryHandle, STsdbQueryCon pQueryHandle->next = doFreeColumnInfoData(pQueryHandle->next); } -TsdbQueryHandleT tsdbQueryLastRow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList, void* qinfo, SMemRef* pMemRef) { +TsdbQueryHandleT tsdbQueryLastRow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList, uint64_t qId, SMemRef* pMemRef) { pCond->twindow = updateLastrowForEachGroup(groupList); // no qualified table @@ -520,7 +520,7 @@ TsdbQueryHandleT tsdbQueryLastRow(STsdbRepo *tsdb, STsdbQueryCond *pCond, STable return NULL; } - STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qinfo, pMemRef); + STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qId, pMemRef); int32_t code = checkForCachedLastRow(pQueryHandle, groupList); if (code != TSDB_CODE_SUCCESS) { // set the numOfTables to be 0 terrno = code; @@ -581,10 +581,10 @@ static STableGroupInfo* trimTableGroup(STimeWindow* window, STableGroupInfo* pGr return pNew; } -TsdbQueryHandleT tsdbQueryRowsInExternalWindow(STsdbRepo *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo, SMemRef* pRef) { +TsdbQueryHandleT tsdbQueryRowsInExternalWindow(STsdbRepo *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, uint64_t qId, SMemRef* pRef) { STableGroupInfo* pNew = trimTableGroup(&pCond->twindow, groupList); - STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, pNew, qinfo, pRef); + STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, pNew, qId, pRef); pQueryHandle->loadExternalRow = true; pQueryHandle->currentLoadExternalRows = true; @@ -651,9 +651,9 @@ static bool initTableMemIterator(STsdbQueryHandle* pHandle, STableCheckInfo* pCh SDataRow row = (SDataRow)SL_GET_NODE_DATA(node); TSKEY key = dataRowKey(row); // first timestamp in buffer tsdbDebug("%p uid:%" PRId64 ", tid:%d check data in mem from skey:%" PRId64 ", order:%d, ts range in buf:%" PRId64 - "-%" PRId64 ", lastKey:%" PRId64 ", numOfRows:%"PRId64", %p", + "-%" PRId64 ", lastKey:%" PRId64 ", numOfRows:%"PRId64", %"PRIu64, pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, key, order, pMem->keyFirst, pMem->keyLast, - pCheckInfo->lastKey, pMem->numOfRows, pHandle->qinfo); + pCheckInfo->lastKey, pMem->numOfRows, pHandle->qId); if (ASCENDING_TRAVERSE(order)) { assert(pCheckInfo->lastKey <= key); @@ -662,8 +662,8 @@ static bool initTableMemIterator(STsdbQueryHandle* pHandle, STableCheckInfo* pCh } } else { - tsdbDebug("%p uid:%"PRId64", tid:%d no data in mem, %p", pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, - pHandle->qinfo); + tsdbDebug("%p uid:%"PRId64", tid:%d no data in mem, %"PRIu64, pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, + pHandle->qId); } if (!imemEmpty) { @@ -673,9 +673,9 @@ static bool initTableMemIterator(STsdbQueryHandle* pHandle, STableCheckInfo* pCh SDataRow row = (SDataRow)SL_GET_NODE_DATA(node); TSKEY key = dataRowKey(row); // first timestamp in buffer tsdbDebug("%p uid:%" PRId64 ", tid:%d check data in imem from skey:%" PRId64 ", order:%d, ts range in buf:%" PRId64 - "-%" PRId64 ", lastKey:%" PRId64 ", numOfRows:%"PRId64", %p", + "-%" PRId64 ", lastKey:%" PRId64 ", numOfRows:%"PRId64", %"PRIu64, pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, key, order, pIMem->keyFirst, pIMem->keyLast, - pCheckInfo->lastKey, pIMem->numOfRows, pHandle->qinfo); + pCheckInfo->lastKey, pIMem->numOfRows, pHandle->qId); if (ASCENDING_TRAVERSE(order)) { assert(pCheckInfo->lastKey <= key); @@ -683,8 +683,8 @@ static bool initTableMemIterator(STsdbQueryHandle* pHandle, STableCheckInfo* pCh assert(pCheckInfo->lastKey >= key); } } else { - tsdbDebug("%p uid:%"PRId64", tid:%d no data in imem, %p", pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, - pHandle->qinfo); + tsdbDebug("%p uid:%"PRId64", tid:%d no data in imem, %"PRIu64, pHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, + pHandle->qId); } return true; @@ -811,8 +811,8 @@ static bool hasMoreDataInCache(STsdbQueryHandle* pHandle) { } pCheckInfo->lastKey = dataRowKey(row); // first timestamp in buffer - tsdbDebug("%p uid:%" PRId64", tid:%d check data in buffer from skey:%" PRId64 ", order:%d, %p", pHandle, - pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, pCheckInfo->lastKey, pHandle->order, pHandle->qinfo); + tsdbDebug("%p uid:%" PRId64", tid:%d check data in buffer from skey:%" PRId64 ", order:%d, %"PRIu64, pHandle, + pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, pCheckInfo->lastKey, pHandle->order, pHandle->qId); // all data in mem are checked already. if ((pCheckInfo->lastKey > pHandle->window.ekey && ASCENDING_TRAVERSE(pHandle->order)) || @@ -984,21 +984,21 @@ static int32_t doLoadFileDataBlock(STsdbQueryHandle* pQueryHandle, SBlock* pBloc STSchema *pSchema = tsdbGetTableSchema(pCheckInfo->pTableObj); int32_t code = tdInitDataCols(pQueryHandle->pDataCols, pSchema); if (code != TSDB_CODE_SUCCESS) { - tsdbError("%p failed to malloc buf for pDataCols, %p", pQueryHandle, pQueryHandle->qinfo); + tsdbError("%p failed to malloc buf for pDataCols, %"PRIu64, pQueryHandle, pQueryHandle->qId); terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _error; } code = tdInitDataCols(pQueryHandle->rhelper.pDCols[0], pSchema); if (code != TSDB_CODE_SUCCESS) { - tsdbError("%p failed to malloc buf for rhelper.pDataCols[0], %p", pQueryHandle, pQueryHandle->qinfo); + tsdbError("%p failed to malloc buf for rhelper.pDataCols[0], %"PRIu64, pQueryHandle, pQueryHandle->qId); terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _error; } code = tdInitDataCols(pQueryHandle->rhelper.pDCols[1], pSchema); if (code != TSDB_CODE_SUCCESS) { - tsdbError("%p failed to malloc buf for rhelper.pDataCols[1], %p", pQueryHandle, pQueryHandle->qinfo); + tsdbError("%p failed to malloc buf for rhelper.pDataCols[1], %"PRIu64, pQueryHandle, pQueryHandle->qId); terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _error; } @@ -1034,15 +1034,15 @@ static int32_t doLoadFileDataBlock(STsdbQueryHandle* pQueryHandle, SBlock* pBloc int64_t elapsedTime = (taosGetTimestampUs() - st); pQueryHandle->cost.blockLoadTime += elapsedTime; - tsdbDebug("%p load file block into buffer, index:%d, brange:%"PRId64"-%"PRId64", rows:%d, elapsed time:%"PRId64 " us, %p", - pQueryHandle, slotIndex, pBlock->keyFirst, pBlock->keyLast, pBlock->numOfRows, elapsedTime, pQueryHandle->qinfo); + tsdbDebug("%p load file block into buffer, index:%d, brange:%"PRId64"-%"PRId64", rows:%d, elapsed time:%"PRId64 " us, %"PRIu64, + pQueryHandle, slotIndex, pBlock->keyFirst, pBlock->keyLast, pBlock->numOfRows, elapsedTime, pQueryHandle->qId); return TSDB_CODE_SUCCESS; _error: pBlock->numOfRows = 0; - tsdbError("%p error occurs in loading file block, index:%d, brange:%"PRId64"-%"PRId64", rows:%d, %p", - pQueryHandle, slotIndex, pBlock->keyFirst, pBlock->keyLast, pBlock->numOfRows, pQueryHandle->qinfo); + tsdbError("%p error occurs in loading file block, index:%d, brange:%"PRId64"-%"PRId64", rows:%d, %"PRIu64, + pQueryHandle, slotIndex, pBlock->keyFirst, pBlock->keyLast, pBlock->numOfRows, pQueryHandle->qId); return terrno; } @@ -1064,7 +1064,7 @@ static int32_t handleDataMergeIfNeeded(STsdbQueryHandle* pQueryHandle, SBlock* p assert(cur->pos >= 0 && cur->pos <= binfo.rows); TSKEY key = (row != NULL)? dataRowKey(row):TSKEY_INITIAL_VAL; - tsdbDebug("%p key in mem:%"PRId64", %p", pQueryHandle, key, pQueryHandle->qinfo); + tsdbDebug("%p key in mem:%"PRId64", %"PRIu64, pQueryHandle, key, pQueryHandle->qId); if ((ASCENDING_TRAVERSE(pQueryHandle->order) && (key != TSKEY_INITIAL_VAL && key <= binfo.window.ekey)) || (!ASCENDING_TRAVERSE(pQueryHandle->order) && (key != TSKEY_INITIAL_VAL && key >= binfo.window.skey))) { @@ -1545,9 +1545,9 @@ static void copyAllRemainRowsFromFileBlock(STsdbQueryHandle* pQueryHandle, STabl updateInfoAfterMerge(pQueryHandle, pCheckInfo, numOfRows, pos); doCheckGeneratedBlockRange(pQueryHandle); - tsdbDebug("%p uid:%" PRIu64",tid:%d data block created, mixblock:%d, brange:%"PRIu64"-%"PRIu64" rows:%d, %p", + tsdbDebug("%p uid:%" PRIu64",tid:%d data block created, mixblock:%d, brange:%"PRIu64"-%"PRIu64" rows:%d, %"PRIu64, pQueryHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, cur->mixBlock, cur->win.skey, - cur->win.ekey, cur->rows, pQueryHandle->qinfo); + cur->win.ekey, cur->rows, pQueryHandle->qId); } int32_t getEndPosInDataBlock(STsdbQueryHandle* pQueryHandle, SDataBlockInfo* pBlockInfo) { @@ -1599,9 +1599,9 @@ static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* int32_t endPos = getEndPosInDataBlock(pQueryHandle, &blockInfo); tsdbDebug("%p uid:%" PRIu64",tid:%d start merge data block, file block range:%"PRIu64"-%"PRIu64" rows:%d, start:%d," - "end:%d, %p", + "end:%d, %"PRIu64, pQueryHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, blockInfo.window.skey, blockInfo.window.ekey, - blockInfo.rows, cur->pos, endPos, pQueryHandle->qinfo); + blockInfo.rows, cur->pos, endPos, pQueryHandle->qId); // compared with the data from in-memory buffer, to generate the correct timestamp array list int32_t numOfRows = 0; @@ -1741,9 +1741,9 @@ static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* updateInfoAfterMerge(pQueryHandle, pCheckInfo, numOfRows, pos); doCheckGeneratedBlockRange(pQueryHandle); - tsdbDebug("%p uid:%" PRIu64",tid:%d data block created, mixblock:%d, brange:%"PRIu64"-%"PRIu64" rows:%d, %p", + tsdbDebug("%p uid:%" PRIu64",tid:%d data block created, mixblock:%d, brange:%"PRIu64"-%"PRIu64" rows:%d, %"PRIu64, pQueryHandle, pCheckInfo->tableId.uid, pCheckInfo->tableId.tid, cur->mixBlock, cur->win.skey, - cur->win.ekey, cur->rows, pQueryHandle->qinfo); + cur->win.ekey, cur->rows, pQueryHandle->qId); } int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order) { @@ -1917,13 +1917,13 @@ static int32_t createDataBlocksInfo(STsdbQueryHandle* pQueryHandle, int32_t numO memcpy(pQueryHandle->pDataBlockInfo, sup.pDataBlockInfo[0], sizeof(STableBlockInfo) * numOfBlocks); cleanBlockOrderSupporter(&sup, numOfQualTables); - tsdbDebug("%p create data blocks info struct completed for 1 table, %d blocks not sorted %p ", pQueryHandle, cnt, - pQueryHandle->qinfo); + tsdbDebug("%p create data blocks info struct completed for 1 table, %d blocks not sorted %"PRIu64, pQueryHandle, cnt, + pQueryHandle->qId); return TSDB_CODE_SUCCESS; } - tsdbDebug("%p create data blocks info struct completed, %d blocks in %d tables %p", pQueryHandle, cnt, - numOfQualTables, pQueryHandle->qinfo); + tsdbDebug("%p create data blocks info struct completed, %d blocks in %d tables %"PRIu64, pQueryHandle, cnt, + numOfQualTables, pQueryHandle->qId); assert(cnt <= numOfBlocks && numOfQualTables <= numOfTables); // the pTableQueryInfo[j]->numOfBlocks may be 0 sup.numOfTables = numOfQualTables; @@ -1959,7 +1959,7 @@ static int32_t createDataBlocksInfo(STsdbQueryHandle* pQueryHandle, int32_t numO * } */ - tsdbDebug("%p %d data blocks sort completed, %p", pQueryHandle, cnt, pQueryHandle->qinfo); + tsdbDebug("%p %d data blocks sort completed, %"PRIu64, pQueryHandle, cnt, pQueryHandle->qId); cleanBlockOrderSupporter(&sup, numOfTables); free(pTree); @@ -2017,8 +2017,8 @@ static int32_t getFirstFileDataBlock(STsdbQueryHandle* pQueryHandle, bool* exist if ((ASCENDING_TRAVERSE(pQueryHandle->order) && win.skey > pQueryHandle->window.ekey) || (!ASCENDING_TRAVERSE(pQueryHandle->order) && win.ekey < pQueryHandle->window.ekey)) { tsdbUnLockFS(REPO_FS(pQueryHandle->pTsdb)); - tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, %p", pQueryHandle, - pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qinfo); + tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, %"PRIu64, pQueryHandle, + pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qId); pQueryHandle->pFileGroup = NULL; assert(pQueryHandle->numOfBlocks == 0); break; @@ -2041,8 +2041,8 @@ static int32_t getFirstFileDataBlock(STsdbQueryHandle* pQueryHandle, bool* exist break; } - tsdbDebug("%p %d blocks found in file for %d table(s), fid:%d, %p", pQueryHandle, numOfBlocks, numOfTables, - pQueryHandle->pFileGroup->fid, pQueryHandle->qinfo); + tsdbDebug("%p %d blocks found in file for %d table(s), fid:%d, %"PRIu64, pQueryHandle, numOfBlocks, numOfTables, + pQueryHandle->pFileGroup->fid, pQueryHandle->qId); assert(numOfBlocks >= 0); if (numOfBlocks == 0) { @@ -2133,8 +2133,8 @@ int32_t tsdbGetFileBlocksDistInfo(TsdbQueryHandleT* queryHandle, STableBlockDist if ((ASCENDING_TRAVERSE(pQueryHandle->order) && win.skey > pQueryHandle->window.ekey) || (!ASCENDING_TRAVERSE(pQueryHandle->order) && win.ekey < pQueryHandle->window.ekey)) { tsdbUnLockFS(REPO_FS(pQueryHandle->pTsdb)); - tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, %p", pQueryHandle, - pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qinfo); + tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, %"PRIu64, pQueryHandle, + pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qId); pQueryHandle->pFileGroup = NULL; break; } @@ -2157,8 +2157,8 @@ int32_t tsdbGetFileBlocksDistInfo(TsdbQueryHandleT* queryHandle, STableBlockDist break; } - tsdbDebug("%p %d blocks found in file for %d table(s), fid:%d, %p", pQueryHandle, numOfBlocks, numOfTables, - pQueryHandle->pFileGroup->fid, pQueryHandle->qinfo); + tsdbDebug("%p %d blocks found in file for %d table(s), fid:%d, %"PRIu64, pQueryHandle, numOfBlocks, numOfTables, + pQueryHandle->pFileGroup->fid, pQueryHandle->qId); if (numOfBlocks == 0) { continue; @@ -2205,8 +2205,8 @@ static int32_t getDataBlocksInFiles(STsdbQueryHandle* pQueryHandle, bool* exists if ((!cur->mixBlock) || cur->blockCompleted) { // all data blocks in current file has been checked already, try next file if exists } else { - tsdbDebug("%p continue in current data block, index:%d, pos:%d, %p", pQueryHandle, cur->slot, cur->pos, - pQueryHandle->qinfo); + tsdbDebug("%p continue in current data block, index:%d, pos:%d, %"PRIu64, pQueryHandle, cur->slot, cur->pos, + pQueryHandle->qId); int32_t code = handleDataMergeIfNeeded(pQueryHandle, pBlockInfo->compBlock, pCheckInfo); *exists = (pQueryHandle->realNumOfRows > 0); @@ -2334,8 +2334,8 @@ static int tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int } int64_t elapsedTime = taosGetTimestampUs() - st; - tsdbDebug("%p build data block from cache completed, elapsed time:%"PRId64" us, numOfRows:%d, numOfCols:%d, %p", pQueryHandle, - elapsedTime, numOfRows, numOfCols, pQueryHandle->qinfo); + tsdbDebug("%p build data block from cache completed, elapsed time:%"PRId64" us, numOfRows:%d, numOfCols:%d, %"PRIu64, pQueryHandle, + elapsedTime, numOfRows, numOfCols, pQueryHandle->qId); return numOfRows; } @@ -2593,7 +2593,7 @@ static int32_t doGetExternalRow(STsdbQueryHandle* pQueryHandle, int16_t type, SM memcpy(&cond.colList[i], &pColInfoData->info, sizeof(SColumnInfo)); } - pSecQueryHandle = tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qinfo, pMemRef); + pSecQueryHandle = tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qId, pMemRef); tfree(cond.colList); // current table, only one table @@ -3393,8 +3393,8 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) { pQueryHandle->next = doFreeColumnInfoData(pQueryHandle->next); SIOCostSummary* pCost = &pQueryHandle->cost; - tsdbDebug("%p :io-cost summary: statis-info:%"PRId64" us, datablock:%" PRId64" us, check data:%"PRId64" us, %p", - pQueryHandle, pCost->statisInfoLoadTime, pCost->blockLoadTime, pCost->checkForNextTime, pQueryHandle->qinfo); + tsdbDebug("%p :io-cost summary: statis-info:%"PRId64" us, datablock:%" PRId64" us, check data:%"PRId64" us, %"PRIu64, + pQueryHandle, pCost->statisInfoLoadTime, pCost->blockLoadTime, pCost->checkForNextTime, pQueryHandle->qId); tfree(pQueryHandle); } diff --git a/src/tsdb/src/tsdbReadImpl.c b/src/tsdb/src/tsdbReadImpl.c index 572706d45e..7212ae1636 100644 --- a/src/tsdb/src/tsdbReadImpl.c +++ b/src/tsdb/src/tsdbReadImpl.c @@ -139,7 +139,7 @@ int tsdbLoadBlockIdx(SReadH *pReadh) { ptr = tsdbDecodeSBlockIdx(ptr, &blkIdx); ASSERT(ptr != NULL); - if (taosArrayPush(pReadh->aBlkIdx, (void *)(&blkIdx)) < 0) { + if (taosArrayPush(pReadh->aBlkIdx, (void *)(&blkIdx)) == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; } diff --git a/src/util/inc/tchecksum.h b/src/util/inc/tchecksum.h index 495aaf33e8..12ca3a5443 100644 --- a/src/util/inc/tchecksum.h +++ b/src/util/inc/tchecksum.h @@ -47,7 +47,6 @@ static FORCE_INLINE int taosCalcChecksumAppend(TSCKSUM csi, uint8_t *stream, uin } static FORCE_INLINE int taosCheckChecksum(const uint8_t *stream, uint32_t ssize, TSCKSUM checksum) { - if (ssize < 0) return 0; return (checksum == (*crc32c)(0, stream, (size_t)ssize)); } diff --git a/src/util/src/terror.c b/src/util/src/terror.c index 221e618390..918ccc4935 100644 --- a/src/util/src/terror.c +++ b/src/util/src/terror.c @@ -199,6 +199,8 @@ TAOS_DEFINE_ERROR(TSDB_CODE_MND_INVALID_DB_OPTION_KEEP, "Invalid database opti TAOS_DEFINE_ERROR(TSDB_CODE_MND_INVALID_TOPIC, "Invalid topic name") TAOS_DEFINE_ERROR(TSDB_CODE_MND_INVALID_TOPIC_OPTION, "Invalid topic option") +TAOS_DEFINE_ERROR(TSDB_CODE_MND_INVALID_TOPIC_PARTITONS, "Invalid topic partitons num, valid range: [1, 1000]") +TAOS_DEFINE_ERROR(TSDB_CODE_MND_TOPIC_ALREADY_EXIST, "Topic already exists") // dnode TAOS_DEFINE_ERROR(TSDB_CODE_DND_MSG_NOT_PROCESSED, "Message not processed") diff --git a/src/vnode/inc/vnodeMain.h b/src/vnode/inc/vnodeMain.h index 73591bc10d..91a5d632cd 100644 --- a/src/vnode/inc/vnodeMain.h +++ b/src/vnode/inc/vnodeMain.h @@ -25,6 +25,7 @@ int32_t vnodeCreate(SCreateVnodeMsg *pVnodeCfg); int32_t vnodeDrop(int32_t vgId); int32_t vnodeOpen(int32_t vgId); int32_t vnodeAlter(void *pVnode, SCreateVnodeMsg *pVnodeCfg); +int32_t vnodeSync(int32_t vgId); int32_t vnodeClose(int32_t vgId); void vnodeCleanUp(SVnodeObj *pVnode); void vnodeDestroy(SVnodeObj *pVnode); @@ -33,4 +34,4 @@ void vnodeDestroy(SVnodeObj *pVnode); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/vnode/src/vnodeMain.c b/src/vnode/src/vnodeMain.c index ded39e67cc..441e951250 100644 --- a/src/vnode/src/vnodeMain.c +++ b/src/vnode/src/vnodeMain.c @@ -91,6 +91,23 @@ int32_t vnodeCreate(SCreateVnodeMsg *pVnodeCfg) { return code; } +int32_t vnodeSync(int32_t vgId) { + SVnodeObj *pVnode = vnodeAcquire(vgId); + if (pVnode == NULL) { + vDebug("vgId:%d, failed to sync, vnode not find", vgId); + return TSDB_CODE_VND_INVALID_VGROUP_ID; + } + + if (pVnode->role != TAOS_SYNC_ROLE_MASTER) { + vInfo("vgId:%d, vnode will sync, refCount:%d pVnode:%p", pVnode->vgId, pVnode->refCount, pVnode); + syncRecover(pVnode->sync); + } + + vnodeRelease(pVnode); + + return TSDB_CODE_SUCCESS; +} + int32_t vnodeDrop(int32_t vgId) { SVnodeObj *pVnode = vnodeAcquire(vgId); if (pVnode == NULL) { diff --git a/src/vnode/src/vnodeRead.c b/src/vnode/src/vnodeRead.c index ef68499b88..8233c45632 100644 --- a/src/vnode/src/vnodeRead.c +++ b/src/vnode/src/vnodeRead.c @@ -25,7 +25,7 @@ static int32_t (*vnodeProcessReadMsgFp[TSDB_MSG_TYPE_MAX])(SVnodeObj *pVnode, SV static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, SVReadMsg *pRead); static int32_t vnodeProcessFetchMsg(SVnodeObj *pVnode, SVReadMsg *pRead); -static int32_t vnodeNotifyCurrentQhandle(void* handle, void* qhandle, int32_t vgId); +static int32_t vnodeNotifyCurrentQhandle(void* handle, uint64_t qId, void* qhandle, int32_t vgId); int32_t vnodeInitRead(void) { vnodeProcessReadMsgFp[TSDB_MSG_TYPE_QUERY] = vnodeProcessQueryMsg; @@ -167,7 +167,7 @@ static int32_t vnodePutItemIntoReadQueue(SVnodeObj *pVnode, void **qhandle, void * @param ahandle sqlObj address at client side * @return */ -static int32_t vnodeDumpQueryResult(SRspRet *pRet, void *pVnode, void **handle, bool *freeHandle, void *ahandle) { +static int32_t vnodeDumpQueryResult(SRspRet *pRet, void *pVnode, uint64_t qId, void **handle, bool *freeHandle, void *ahandle) { bool continueExec = false; int32_t code = TSDB_CODE_SUCCESS; @@ -183,7 +183,7 @@ static int32_t vnodeDumpQueryResult(SRspRet *pRet, void *pVnode, void **handle, } } else { *freeHandle = true; - vTrace("QInfo:%p exec completed, free handle:%d", *handle, *freeHandle); + vTrace("QInfo:%"PRIu64"-%p exec completed, free handle:%d", qId, *handle, *freeHandle); } } else { SRetrieveTableRsp *pRsp = (SRetrieveTableRsp *)rpcMallocCont(sizeof(SRetrieveTableRsp)); @@ -220,27 +220,6 @@ static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { if (pRead->code == TSDB_CODE_RPC_NETWORK_UNAVAIL) { vError("error rpc msg in query, %s", tstrerror(pRead->code)); } -// assert(pRead->code != TSDB_CODE_RPC_NETWORK_UNAVAIL); -// if (pRead->code == TSDB_CODE_RPC_NETWORK_UNAVAIL) { -// SCancelQueryMsg *pMsg = (SCancelQueryMsg *)pRead->pCont; -//// pMsg->free = htons(killQueryMsg->free); -// pMsg->qhandle = htobe64(pMsg->qhandle); -// -// vWarn("QInfo:%p connection %p broken, kill query", (void *)pMsg->qhandle, pRead->rpcHandle); -//// assert(pRead->contLen > 0 && pMsg->free == 1); -// -// void **qhandle = qAcquireQInfo(pVnode->qMgmt, (uint64_t)pMsg->qhandle); -// if (qhandle == NULL || *qhandle == NULL) { -// vWarn("QInfo:%p invalid qhandle, no matched query handle, conn:%p", (void *)pMsg->qhandle, pRead->rpcHandle); -// } else { -// assert(*qhandle == (void *)pMsg->qhandle); -// -// qKillQuery(*qhandle); -// qReleaseQInfo(pVnode->qMgmt, (void **)&qhandle, true); -// } -// -// return TSDB_CODE_TSC_QUERY_CANCELLED; -// } int32_t code = TSDB_CODE_SUCCESS; void ** handle = NULL; @@ -274,7 +253,7 @@ static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { } if (handle != NULL && - vnodeNotifyCurrentQhandle(pRead->rpcHandle, *handle, pVnode->vgId) != TSDB_CODE_SUCCESS) { + vnodeNotifyCurrentQhandle(pRead->rpcHandle, qId, *handle, pVnode->vgId) != TSDB_CODE_SUCCESS) { vError("vgId:%d, QInfo:%"PRIu64 "-%p, query discarded since link is broken, %p", pVnode->vgId, qId, *handle, pRead->rpcHandle); pRsp->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; @@ -297,16 +276,17 @@ static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { } else { assert(pCont != NULL); void **qhandle = (void **)pRead->qhandle; + uint64_t qId = 0; vTrace("vgId:%d, QInfo:%p, dnode continues to exec query", pVnode->vgId, *qhandle); // In the retrieve blocking model, only 50% CPU will be used in query processing if (tsRetrieveBlockingModel) { - qTableQuery(*qhandle); // do execute query + qTableQuery(*qhandle, &qId); // do execute query qReleaseQInfo(pVnode->qMgmt, (void **)&qhandle, false); } else { bool freehandle = false; - bool buildRes = qTableQuery(*qhandle); // do execute query + bool buildRes = qTableQuery(*qhandle, &qId); // do execute query // build query rsp, the retrieve request has reached here already if (buildRes) { @@ -318,7 +298,7 @@ static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { pRead->rpcHandle); // set the real rsp error code - pRead->code = vnodeDumpQueryResult(&pRead->rspRet, pVnode, qhandle, &freehandle, pRead->rpcHandle); + pRead->code = vnodeDumpQueryResult(&pRead->rspRet, pVnode, qId, qhandle, &freehandle, pRead->rpcHandle); // NOTE: set return code to be TSDB_CODE_QRY_HAS_RSP to notify dnode to return msg to client code = TSDB_CODE_QRY_HAS_RSP; @@ -348,32 +328,32 @@ static int32_t vnodeProcessFetchMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { SRetrieveTableMsg *pRetrieve = pCont; pRetrieve->free = htons(pRetrieve->free); - pRetrieve->qhandle = htobe64(pRetrieve->qhandle); + pRetrieve->qId = htobe64(pRetrieve->qId); - vTrace("vgId:%d, QInfo:%" PRIu64 ", retrieve msg is disposed, free:%d, conn:%p", pVnode->vgId, pRetrieve->qhandle, + vTrace("vgId:%d, qId:%" PRIu64 ", retrieve msg is disposed, free:%d, conn:%p", pVnode->vgId, pRetrieve->qId, pRetrieve->free, pRead->rpcHandle); memset(pRet, 0, sizeof(SRspRet)); terrno = TSDB_CODE_SUCCESS; int32_t code = TSDB_CODE_SUCCESS; - void ** handle = qAcquireQInfo(pVnode->qMgmt, pRetrieve->qhandle); + void ** handle = qAcquireQInfo(pVnode->qMgmt, pRetrieve->qId); if (handle == NULL) { code = terrno; terrno = TSDB_CODE_SUCCESS; - } else if (!checkQIdEqual(*handle, pRetrieve->qhandle)) { + } else if (!checkQIdEqual(*handle, pRetrieve->qId)) { code = TSDB_CODE_QRY_INVALID_QHANDLE; } if (code != TSDB_CODE_SUCCESS) { - vError("vgId:%d, invalid handle in retrieving result, code:%s, QInfo:%" PRIu64, pVnode->vgId, tstrerror(code), pRetrieve->qhandle); + vError("vgId:%d, invalid qId in retrieving result, code:%s, QInfo:%" PRIu64, pVnode->vgId, tstrerror(code), pRetrieve->qId); vnodeBuildNoResultQueryRsp(pRet); return code; } // kill current query and free corresponding resources. if (pRetrieve->free == 1) { - vWarn("vgId:%d, QInfo:%"PRIu64 "-%p, retrieve msg received to kill query and free qhandle", pVnode->vgId, pRetrieve->qhandle, *handle); + vWarn("vgId:%d, QInfo:%"PRIu64 "-%p, retrieve msg received to kill query and free qhandle", pVnode->vgId, pRetrieve->qId, *handle); qKillQuery(*handle); qReleaseQInfo(pVnode->qMgmt, (void **)&handle, true); @@ -383,7 +363,7 @@ static int32_t vnodeProcessFetchMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { } // register the qhandle to connect to quit query immediate if connection is broken - if (vnodeNotifyCurrentQhandle(pRead->rpcHandle, *handle, pVnode->vgId) != TSDB_CODE_SUCCESS) { + if (vnodeNotifyCurrentQhandle(pRead->rpcHandle, pRetrieve->qId, *handle, pVnode->vgId) != TSDB_CODE_SUCCESS) { vError("vgId:%d, QInfo:%"PRIu64 "-%p, retrieve discarded since link is broken, %p", pVnode->vgId, pRetrieve->qhandle, *handle, pRead->rpcHandle); code = TSDB_CODE_RPC_NETWORK_UNAVAIL; qKillQuery(*handle); @@ -413,7 +393,7 @@ static int32_t vnodeProcessFetchMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { } // ahandle is the sqlObj pointer - code = vnodeDumpQueryResult(pRet, pVnode, handle, &freeHandle, pRead->rpcHandle); + code = vnodeDumpQueryResult(pRet, pVnode, pRetrieve->qId, handle, &freeHandle, pRead->rpcHandle); } // If qhandle is not added into vread queue, the query should be completed already or paused with error. @@ -427,13 +407,13 @@ static int32_t vnodeProcessFetchMsg(SVnodeObj *pVnode, SVReadMsg *pRead) { // notify connection(handle) that current qhandle is created, if current connection from // client is broken, the query needs to be killed immediately. -int32_t vnodeNotifyCurrentQhandle(void *handle, void *qhandle, int32_t vgId) { +int32_t vnodeNotifyCurrentQhandle(void *handle, uint64_t qId, void *qhandle, int32_t vgId) { SRetrieveTableMsg *pMsg = rpcMallocCont(sizeof(SRetrieveTableMsg)); pMsg->qhandle = htobe64((uint64_t)qhandle); pMsg->header.vgId = htonl(vgId); pMsg->header.contLen = htonl(sizeof(SRetrieveTableMsg)); - vTrace("QInfo:%p register qhandle to connect:%p", qhandle, handle); + vTrace("QInfo:%"PRIu64"-%p register qhandle to connect:%p", qId, qhandle, handle); return rpcReportProgress(handle, (char *)pMsg, sizeof(SRetrieveTableMsg)); } diff --git a/tests/Jenkinsfile b/tests/Jenkinsfile index 7cdcfb2e24..178a0446c3 100644 --- a/tests/Jenkinsfile +++ b/tests/Jenkinsfile @@ -1,9 +1,8 @@ def pre_test(){ - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - sudo rmtaos - ''' - } + + sh ''' + sudo rmtaos||echo 'no taosd installed' + ''' sh ''' cd ${WKC} git reset --hard @@ -56,14 +55,8 @@ pipeline { cd ${WKC}/tests ./test-all.sh b1 date''' - sh ''' - cd ${WKC}/tests - ./test-all.sh full jdbc - date''' - sh ''' - cd ${WKC}/tests - ./test-all.sh full unit - date''' + + } } @@ -83,9 +76,20 @@ pipeline { catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { sh ''' cd ${WKC}/tests/pytest + rm -rf /var/lib/taos/* + rm -rf /var/log/taos/* ./handle_crash_gen_val_log.sh ''' } + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + rm -rf /var/lib/taos/* + rm -rf /var/log/taos/* + ./handle_taosd_val_log.sh + ''' + } + sh''' systemctl start taosd sleep 10 @@ -136,6 +140,10 @@ pipeline { ./test-all.sh b2 date ''' + sh ''' + cd ${WKC}/tests + ./test-all.sh full unit + date''' } } @@ -154,6 +162,10 @@ pipeline { ''' } sh ''' + cd ${WKC}/tests + ./test-all.sh full jdbc + date''' + sh ''' cd ${WKC}/tests/pytest ./valgrind-test.sh 2>&1 > mem-error-out.log ./handle_val_log.sh @@ -162,6 +174,11 @@ pipeline { cd ${WKC}/tests ./test-all.sh b3 date''' + sh ''' + date + cd ${WKC}/tests + ./test-all.sh full example + date''' } } diff --git a/tests/examples/JDBC/JDBCDemo/pom.xml b/tests/examples/JDBC/JDBCDemo/pom.xml index 167e7e37ae..66e866a2d3 100644 --- a/tests/examples/JDBC/JDBCDemo/pom.xml +++ b/tests/examples/JDBC/JDBCDemo/pom.xml @@ -13,7 +13,7 @@ com.taosdata.jdbc taos-jdbcdriver - 2.0.20 + 2.0.22 diff --git a/tests/examples/JDBC/taosdemo/src/main/resources/insert.json b/tests/examples/JDBC/taosdemo/src/main/resources/insert.json index a7bd87e6d3..35c7773175 100644 --- a/tests/examples/JDBC/taosdemo/src/main/resources/insert.json +++ b/tests/examples/JDBC/taosdemo/src/main/resources/insert.json @@ -38,7 +38,7 @@ "insert_rows": 100, "multi_thread_write_one_tbl": "no", "number_of_tbl_in_one_sql": 0, - "rows_per_tbl": 3, + "interlace_rows": 3, "max_sql_len": 1024, "disorder_ratio": 0, "disorder_range": 1000, diff --git a/tests/examples/c/asyncdemo.c b/tests/examples/c/asyncdemo.c index 16a14e9654..d711ce22c1 100644 --- a/tests/examples/c/asyncdemo.c +++ b/tests/examples/c/asyncdemo.c @@ -163,6 +163,16 @@ int main(int argc, char *argv[]) getchar(); + while(1) { + if (tablesProcessed < numOfTables) { + printf("wait for process finished\n"); + sleep(1); + continue; + } + + break; + } + taos_close(taos); free(tableList); diff --git a/tests/pytest/cluster/clusterEnvSetup/Dockerfile b/tests/pytest/cluster/clusterEnvSetup/Dockerfile index c9c4d79be9..437dbc65e6 100644 --- a/tests/pytest/cluster/clusterEnvSetup/Dockerfile +++ b/tests/pytest/cluster/clusterEnvSetup/Dockerfile @@ -28,6 +28,8 @@ RUN ulimit -c unlimited COPY --from=builder /root/bin/taosd /usr/bin COPY --from=builder /root/bin/tarbitrator /usr/bin +COPY --from=builder /root/bin/taosdemo /usr/bin +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 diff --git a/tests/pytest/cluster/clusterEnvSetup/basic.py b/tests/pytest/cluster/clusterEnvSetup/basic.py index eb39051898..dc7e07fd5c 100644 --- a/tests/pytest/cluster/clusterEnvSetup/basic.py +++ b/tests/pytest/cluster/clusterEnvSetup/basic.py @@ -45,8 +45,8 @@ class BuildDockerCluser: os.system("docker exec -d $(docker ps|grep tdnode1|awk '{print $1}') tarbitrator") def run(self): - if self.numOfNodes < 2 or self.numOfNodes > 5: - print("the number of nodes must be between 2 and 5") + if self.numOfNodes < 2 or self.numOfNodes > 10: + print("the number of nodes must be between 2 and 10") exit(0) print("remove Flag value %s" % self.removeFlag) if self.removeFlag == False: @@ -96,7 +96,7 @@ parser.add_argument( '-v', '--version', action='store', - default='2.0.17.1', + default='2.0.18.1', type=str, help='the version of the cluster to be build, Default is 2.0.17.1') parser.add_argument( diff --git a/tests/pytest/cluster/clusterEnvSetup/buildClusterEnv.sh b/tests/pytest/cluster/clusterEnvSetup/buildClusterEnv.sh index f6199649cd..60c81cd82b 100755 --- a/tests/pytest/cluster/clusterEnvSetup/buildClusterEnv.sh +++ b/tests/pytest/cluster/clusterEnvSetup/buildClusterEnv.sh @@ -1,6 +1,7 @@ #!/bin/bash echo "Executing buildClusterEnv.sh" CURR_DIR=`pwd` +IN_TDINTERNAL="community" if [ $# != 6 ]; then echo "argument list need input : " @@ -32,7 +33,7 @@ do done function addTaoscfg { - for i in {1..5} + for((i=1;i<=$NUM_OF_NODES;i++)) do touch $DOCKER_DIR/node$i/cfg/taos.cfg echo 'firstEp tdnode1:6030' > $DOCKER_DIR/node$i/cfg/taos.cfg @@ -42,7 +43,7 @@ function addTaoscfg { } function createDIR { - for i in {1..5} + for((i=1;i<=$NUM_OF_NODES;i++)) do mkdir -p $DOCKER_DIR/node$i/data mkdir -p $DOCKER_DIR/node$i/log @@ -53,7 +54,7 @@ function createDIR { function cleanEnv { echo "Clean up docker environment" - for i in {1..5} + for((i=1;i<=$NUM_OF_NODES;i++)) do rm -rf $DOCKER_DIR/node$i/data/* rm -rf $DOCKER_DIR/node$i/log/* @@ -67,24 +68,48 @@ function prepareBuild { rm -rf $CURR_DIR/../../../../release/* fi - if [ ! -e $DOCKER_DIR/TDengine-server-$VERSION-Linux-x64.tar.gz ] || [ ! -e $DOCKER_DIR/TDengine-arbitrator-$VERSION-Linux-x64.tar.gz ]; then - cd $CURR_DIR/../../../../packaging - echo "generating TDeninger packages" - ./release.sh -v edge -n $VERSION >> /dev/null + cd $CURR_DIR/../../../../packaging - if [ ! -e $CURR_DIR/../../../../release/TDengine-server-$VERSION-Linux-x64.tar.gz ]; then - echo "no TDengine install package found" - exit 1 + if [[ "$CURR_DIR" == *"$IN_TDINTERNAL"* ]]; then + if [ ! -e $DOCKER_DIR/TDengine-enterprise-server-$VERSION-Linux-x64.tar.gz ] || [ ! -e $DOCKER_DIR/TDengine-enterprise-arbitrator-$VERSION-Linux-x64.tar.gz ]; then + + echo "generating TDeninge enterprise packages" + ./release.sh -v cluster -n $VERSION >> /dev/null 2>&1 + + if [ ! -e $CURR_DIR/../../../../release/TDengine-enterprise-server-$VERSION-Linux-x64.tar.gz ]; then + echo "no TDengine install package found" + exit 1 + fi + + if [ ! -e $CURR_DIR/../../../../release/TDengine-enterprise-arbitrator-$VERSION-Linux-x64.tar.gz ]; then + echo "no arbitrator install package found" + exit 1 + fi + + cd $CURR_DIR/../../../../release + mv TDengine-enterprise-server-$VERSION-Linux-x64.tar.gz $DOCKER_DIR + mv TDengine-enterprise-arbitrator-$VERSION-Linux-x64.tar.gz $DOCKER_DIR fi + else + if [ ! -e $DOCKER_DIR/TDengine-server-$VERSION-Linux-x64.tar.gz ] || [ ! -e $DOCKER_DIR/TDengine-arbitrator-$VERSION-Linux-x64.tar.gz ]; then - if [ ! -e $CURR_DIR/../../../../release/TDengine-arbitrator-$VERSION-Linux-x64.tar.gz ]; then - echo "no arbitrator install package found" - exit 1 - fi + echo "generating TDeninge community packages" + ./release.sh -v edge -n $VERSION >> /dev/null 2>&1 + + if [ ! -e $CURR_DIR/../../../../release/TDengine-server-$VERSION-Linux-x64.tar.gz ]; then + echo "no TDengine install package found" + exit 1 + fi - cd $CURR_DIR/../../../../release - mv TDengine-server-$VERSION-Linux-x64.tar.gz $DOCKER_DIR - mv TDengine-arbitrator-$VERSION-Linux-x64.tar.gz $DOCKER_DIR + if [ ! -e $CURR_DIR/../../../../release/TDengine-arbitrator-$VERSION-Linux-x64.tar.gz ]; then + echo "no arbitrator install package found" + exit 1 + fi + + cd $CURR_DIR/../../../../release + mv TDengine-server-$VERSION-Linux-x64.tar.gz $DOCKER_DIR + mv TDengine-arbitrator-$VERSION-Linux-x64.tar.gz $DOCKER_DIR + fi fi rm -rf $DOCKER_DIR/*.yml @@ -99,23 +124,31 @@ function clusterUp { cd $DOCKER_DIR - if [ $NUM_OF_NODES -eq 2 ]; then - echo "create 2 dnodes" - PACKAGE=TDengine-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-server-$VERSION DIR2=TDengine-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose up -d + if [[ "$CURR_DIR" == *"$IN_TDINTERNAL"* ]]; then + docker_run="PACKAGE=TDengine-enterprise-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-enterprise-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-enterprise-server-$VERSION DIR2=TDengine-enterprise-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose -f docker-compose.yml " + else + docker_run="PACKAGE=TDengine-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-server-$VERSION DIR2=TDengine-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose -f docker-compose.yml " fi - if [ $NUM_OF_NODES -eq 3 ]; then - PACKAGE=TDengine-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-server-$VERSION DIR2=TDengine-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose -f docker-compose.yml -f node3.yml up -d + if [ $NUM_OF_NODES -ge 2 ];then + echo "create $NUM_OF_NODES dnodes" + for((i=3;i<=$NUM_OF_NODES;i++)) + do + if [ ! -f node$i.yml ];then + echo "node$i.yml not exist" + cp node3.yml node$i.yml + sed -i "s/td2.0-node3/td2.0-node$i/g" node$i.yml + sed -i "s/'tdnode3'/'tdnode$i'/g" node$i.yml + sed -i "s#/node3/#/node$i/#g" node$i.yml + sed -i "s#hostname: tdnode3#hostname: tdnode$i#g" node$i.yml + sed -i "s#ipv4_address: 172.27.0.9#ipv4_address: 172.27.0.`expr $i + 6`#g" node$i.yml + fi + docker_run=$docker_run" -f node$i.yml " + done + docker_run=$docker_run" up -d" fi - - if [ $NUM_OF_NODES -eq 4 ]; then - PACKAGE=TDengine-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-server-$VERSION DIR2=TDengine-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose -f docker-compose.yml -f node3.yml -f node4.yml up -d - fi - - if [ $NUM_OF_NODES -eq 5 ]; then - PACKAGE=TDengine-server-$VERSION-Linux-x64.tar.gz TARBITRATORPKG=TDengine-arbitrator-$VERSION-Linux-x64.tar.gz DIR=TDengine-server-$VERSION DIR2=TDengine-arbitrator-$VERSION VERSION=$VERSION DATADIR=$DOCKER_DIR docker-compose -f docker-compose.yml -f node3.yml -f node4.yml -f node5.yml up -d - fi - + echo $docker_run |sh + echo "docker compose finish" } diff --git a/tests/pytest/cluster/clusterEnvSetup/cleanClusterEnv.sh b/tests/pytest/cluster/clusterEnvSetup/cleanClusterEnv.sh index 006db3f4eb..675cae5fef 100755 --- a/tests/pytest/cluster/clusterEnvSetup/cleanClusterEnv.sh +++ b/tests/pytest/cluster/clusterEnvSetup/cleanClusterEnv.sh @@ -28,7 +28,7 @@ function removeDockerContainers { function cleanEnv { echo "Clean up docker environment" - for i in {1..5} + for i in {1..10} do rm -rf $DOCKER_DIR/node$i/data/* rm -rf $DOCKER_DIR/node$i/log/* diff --git a/tests/pytest/cluster/clusterEnvSetup/docker-compose.yml b/tests/pytest/cluster/clusterEnvSetup/docker-compose.yml index 80cd859cdf..d241062a2d 100644 --- a/tests/pytest/cluster/clusterEnvSetup/docker-compose.yml +++ b/tests/pytest/cluster/clusterEnvSetup/docker-compose.yml @@ -30,6 +30,11 @@ services: - "tdnode3:172.27.0.9" - "tdnode4:172.27.0.10" - "tdnode5:172.27.0.11" + - "tdnode6:172.27.0.12" + - "tdnode7:172.27.0.13" + - "tdnode8:172.27.0.14" + - "tdnode9:172.27.0.15" + - "tdnode10:172.27.0.16" volumes: # bind data directory - type: bind @@ -61,7 +66,9 @@ services: context: . args: - PACKAGE=${PACKAGE} + - TARBITRATORPKG=${TARBITRATORPKG} - EXTRACTDIR=${DIR} + - EXTRACTDIR2=${DIR2} - DATADIR=${DATADIR} image: 'tdengine:${VERSION}' container_name: 'tdnode2' diff --git a/tests/pytest/cluster/clusterEnvSetup/insert.json b/tests/pytest/cluster/clusterEnvSetup/insert.json index 56a64b7b85..4548ef74e6 100644 --- a/tests/pytest/cluster/clusterEnvSetup/insert.json +++ b/tests/pytest/cluster/clusterEnvSetup/insert.json @@ -39,7 +39,7 @@ "insert_rows": 100000, "multi_thread_write_one_tbl": "no", "number_of_tbl_in_one_sql": 1, - "rows_per_tbl": 100, + "interlace_rows": 100, "max_sql_len": 1024000, "disorder_ratio": 0, "disorder_range": 1000, diff --git a/tests/pytest/cluster/clusterEnvSetup/node3.yml b/tests/pytest/cluster/clusterEnvSetup/node3.yml index 93044d24af..18f1b37c1c 100644 --- a/tests/pytest/cluster/clusterEnvSetup/node3.yml +++ b/tests/pytest/cluster/clusterEnvSetup/node3.yml @@ -6,7 +6,9 @@ services: context: . args: - PACKAGE=${PACKAGE} + - TARBITRATORPKG=${TARBITRATORPKG} - EXTRACTDIR=${DIR} + - EXTRACTDIR2=${DIR2} - DATADIR=${DATADIR} image: 'tdengine:${VERSION}' container_name: 'tdnode3' @@ -24,10 +26,15 @@ services: sysctl -p && exec my-main-application" extra_hosts: - - "tdnode1:172.27.0.7" - "tdnode2:172.27.0.8" + - "tdnode3:172.27.0.9" - "tdnode4:172.27.0.10" - "tdnode5:172.27.0.11" + - "tdnode6:172.27.0.12" + - "tdnode7:172.27.0.13" + - "tdnode8:172.27.0.14" + - "tdnode9:172.27.0.15" + - "tdnode10:172.27.0.16" volumes: # bind data directory - type: bind diff --git a/tests/pytest/cluster/clusterEnvSetup/node4.yml b/tests/pytest/cluster/clusterEnvSetup/node4.yml index 1fc603b3b5..f542c22c45 100644 --- a/tests/pytest/cluster/clusterEnvSetup/node4.yml +++ b/tests/pytest/cluster/clusterEnvSetup/node4.yml @@ -6,7 +6,9 @@ services: context: . args: - PACKAGE=${PACKAGE} + - TARBITRATORPKG=${TARBITRATORPKG} - EXTRACTDIR=${DIR} + - EXTRACTDIR2=${DIR2} - DATADIR=${DATADIR} image: 'tdengine:${VERSION}' container_name: 'tdnode4' @@ -28,6 +30,11 @@ services: - "tdnode3:172.27.0.9" - "tdnode4:172.27.0.10" - "tdnode5:172.27.0.11" + - "tdnode6:172.27.0.12" + - "tdnode7:172.27.0.13" + - "tdnode8:172.27.0.14" + - "tdnode9:172.27.0.15" + - "tdnode10:172.27.0.16" volumes: # bind data directory - type: bind diff --git a/tests/pytest/cluster/clusterEnvSetup/node5.yml b/tests/pytest/cluster/clusterEnvSetup/node5.yml index 5e3aba3b76..dd5941ac76 100644 --- a/tests/pytest/cluster/clusterEnvSetup/node5.yml +++ b/tests/pytest/cluster/clusterEnvSetup/node5.yml @@ -6,7 +6,9 @@ services: context: . args: - PACKAGE=${PACKAGE} + - TARBITRATORPKG=${TARBITRATORPKG} - EXTRACTDIR=${DIR} + - EXTRACTDIR2=${DIR2} - DATADIR=${DATADIR} image: 'tdengine:${VERSION}' container_name: 'tdnode5' @@ -28,6 +30,11 @@ services: - "tdnode3:172.27.0.9" - "tdnode4:172.27.0.10" - "tdnode5:172.27.0.11" + - "tdnode6:172.27.0.12" + - "tdnode7:172.27.0.13" + - "tdnode8:172.27.0.14" + - "tdnode9:172.27.0.15" + - "tdnode10:172.27.0.16" volumes: # bind data directory - type: bind diff --git a/tests/pytest/fulltest.sh b/tests/pytest/fulltest.sh index 46a1abf12c..fc86570bd2 100755 --- a/tests/pytest/fulltest.sh +++ b/tests/pytest/fulltest.sh @@ -196,6 +196,9 @@ python3 ./test.py -f query/bug2119.py python3 ./test.py -f query/isNullTest.py python3 ./test.py -f query/queryWithTaosdKilled.py python3 ./test.py -f query/floatCompare.py +python3 ./test.py -f query/bug3375.py + + #stream python3 ./test.py -f stream/metric_1.py @@ -230,15 +233,6 @@ python3 client/twoClients.py python3 test.py -f query/queryInterval.py python3 test.py -f query/queryFillTest.py -# tools -python3 test.py -f tools/taosdemoTest.py -python3 test.py -f tools/taosdemoTestWithoutMetric.py -python3 test.py -f tools/taosdemoTestWithJson.py -python3 test.py -f tools/taosdemoTestLimitOffset.py -python3 test.py -f tools/taosdumpTest.py -python3 test.py -f tools/taosdemoTest2.py -python3 test.py -f tools/taosdemoTestSampleData.py - # subscribe python3 test.py -f subscribe/singlemeter.py #python3 test.py -f subscribe/stability.py @@ -248,6 +242,18 @@ python3 test.py -f subscribe/supertable.py #======================p3-end=============== #======================p4-start=============== +# tools +python3 test.py -f tools/taosdumpTest.py + +python3 test.py -f tools/taosdemoTest.py +python3 test.py -f tools/taosdemoTestWithoutMetric.py +python3 test.py -f tools/taosdemoTestWithJson.py +python3 test.py -f tools/taosdemoTestLimitOffset.py +python3 test.py -f tools/taosdemoTest2.py +python3 test.py -f tools/taosdemoTestSampleData.py +python3 test.py -f tools/taosdemoTestInterlace.py +python3 test.py -f tools/taosdemoTestQuery.py + python3 ./test.py -f update/merge_commit_data-0.py # wal python3 ./test.py -f wal/addOldWalTest.py diff --git a/tests/pytest/handle_taosd_val_log.sh b/tests/pytest/handle_taosd_val_log.sh new file mode 100755 index 0000000000..6b7f669efe --- /dev/null +++ b/tests/pytest/handle_taosd_val_log.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Color setting +RED='\033[0;31m' +GREEN='\033[1;32m' +GREEN_DARK='\033[0;32m' +GREEN_UNDERLINE='\033[4;32m' +NC='\033[0m' +IN_TDINTERNAL="community" +TDIR=`pwd` +if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]]; then + cd ../.. +else + cd ../../.. +fi +TOP_DIR=`pwd` +TAOSD_DIR=`find . -name "taosd"|grep -v community|grep debug|head -n1` +VALGRIND_OUT=taosd_valgrind.out +VALGRIND_ERR=taosd_valgrind.err +rm -rf /var/lib/taos/* +# nohup valgrind --tool=memcheck --leak-check=yes $TAOSD_DIR > $TDIR/$VALGRIND_OUT 2> $TDIR/$VALGRIND_ERR & +nohup valgrind --leak-check=yes $TAOSD_DIR > $TDIR/$VALGRIND_OUT 2> $TDIR/$VALGRIND_ERR & +sleep 20 +cd - +./crash_gen.sh -p -t 10 -s 200 +ps -ef |grep valgrind|grep -v grep|awk '{print $2}'|xargs kill -term +while true +do + monitoring=` ps -ef|grep valgrind |grep -v grep| wc -l` + if [ $monitoring -eq 0 ] + then + echo "Manipulator is not running " + break + else + sleep 1 + fi +done + +grep 'start to execute\|ERROR SUMMARY' $VALGRIND_ERR | grep -v 'grep' | uniq | tee taosd_mem_err.log + +for memError in `grep 'ERROR SUMMARY' taosd_mem_err.log | awk '{print $4}'` +do +memError=(${memError//,/}) +if [ -n "$memError" ]; then + if [ "$memError" -gt 12 ]; then + echo -e "${RED} ## Memory errors number valgrind reports is $memError.\ + More than our threshold! ## ${NC}" + fi +fi +done + +grep 'start to execute\|definitely lost:' $VALGRIND_ERR|grep -v 'grep'|uniq|tee taosd-definitely-lost-out.log +for defiMemError in `grep 'definitely lost:' taosd-definitely-lost-out.log | awk '{print $7}'` +do +defiMemError=(${defiMemError//,/}) +if [ -n "$defiMemError" ]; then + if [ "$defiMemError" -gt 0 -a "$defiMemError" -lt 1013 ]; then + cat $VALGRIND_ERR + echo -e "${RED} ## Memory errors number valgrind reports \ + Definitely lost is $defiMemError. More than our threshold! ## ${NC}" + exit 8 + elif [ "$defiMemError" -gt 1013 ];then #add for azure + cat $VALGRIND_ERR + echo -e "${RED} ## Memory errors number valgrind reports \ + Definitely lost is $defiMemError. More than our threshold! ## ${NC}" + exit 8 + fi +fi +done diff --git a/tests/pytest/insert/metadataUpdate.py b/tests/pytest/insert/metadataUpdate.py index 76b9a3ae8f..4c32b0e39a 100644 --- a/tests/pytest/insert/metadataUpdate.py +++ b/tests/pytest/insert/metadataUpdate.py @@ -25,6 +25,8 @@ class TDTestCase: tdSql.init(conn.cursor(), logSql) self.ts = 1538548685000 + self.tables = 10 + self.rows = 1000 def updateMetadata(self): self.host = "127.0.0.1" @@ -37,6 +39,29 @@ class TDTestCase: self.cursor.execute("alter table db.tb add column col2 int") print("alter table done") + def deleteTableAndRecreate(self): + self.host = "127.0.0.1" + self.user = "root" + self.password = "taosdata" + self.config = tdDnodes.getSimCfgPath() + + self.conn = taos.connect(host = self.host, user = self.user, password = self.password, config = self.config) + self.cursor = self.conn.cursor() + + self.cursor.execute("use test") + print("drop table stb") + self.cursor.execute("drop table stb") + + print("create table stb") + self.cursor.execute("create table if not exists stb (ts timestamp, col1 int) tags(areaid int, city nchar(20))") + print("insert data") + for i in range(self.tables): + city = "beijing" if i % 2 == 0 else "shanghai" + self.cursor.execute("create table tb%d using stb tags(%d, '%s')" % (i, i, city)) + for j in range(self.rows): + self.cursor.execute("insert into tb%d values(%d, %d)" % (i, self.ts + j, j * 100000)) + + def run(self): tdSql.prepare() @@ -59,6 +84,36 @@ class TDTestCase: tdSql.query("select * from tb") tdSql.checkRows(2) + # Add test case: https://jira.taosdata.com:18080/browse/TD-3474 + + print("==============step1") + tdSql.execute("create database test") + tdSql.execute("use test") + tdSql.execute("create table if not exists stb (ts timestamp, col1 int) tags(areaid int, city nchar(20))") + + for i in range(self.tables): + city = "beijing" if i % 2 == 0 else "shanghai" + tdSql.execute("create table tb%d using stb tags(%d, '%s')" % (i, i, city)) + for j in range(self.rows): + tdSql.execute("insert into tb%d values(%d, %d)" % (i, self.ts + j, j * 100000)) + + tdSql.query("select count(*) from stb") + tdSql.checkData(0, 0, 10000) + + tdSql.query("select count(*) from tb1") + tdSql.checkData(0, 0, 1000) + + p = Process(target=self.deleteTableAndRecreate, args=()) + p.start() + p.join() + p.terminate() + + tdSql.query("select count(*) from stb") + tdSql.checkData(0, 0, 10000) + + tdSql.query("select count(*) from tb1") + tdSql.checkData(0, 0, 1000) + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) diff --git a/tests/pytest/query/bug3375.py b/tests/pytest/query/bug3375.py new file mode 100644 index 0000000000..25c3467c05 --- /dev/null +++ b/tests/pytest/query/bug3375.py @@ -0,0 +1,61 @@ +################################################################### +# 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 sys +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import * + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def run(self): + tdSql.prepare() + tdSql.execute("drop database if exists db") + tdSql.execute("create database if not exists db keep 36500") + tdSql.execute("use db") + + tdLog.printNoPrefix("==========step1:create table && insert data") + tdSql.execute( + "create table stb1 (ts timestamp, c11 int) TAGS(t11 int, t12 int )" + ) + tdSql.execute( + "create table stb2 (ts timestamp, c21 int) TAGS(t21 int, t22 int )" + ) + tdSql.execute("create table t10 using stb1 tags(1, 10)") + tdSql.execute("create table t20 using stb2 tags(1, 12)") + tdSql.execute("insert into t10 values (1600000000000, 1)") + tdSql.execute("insert into t10 values (1610000000000, 2)") + tdSql.execute("insert into t20 values (1600000000000, 3)") + tdSql.execute("insert into t20 values (1610000000000, 4)") + + tdLog.printNoPrefix("==========step2:query crash test") + tdSql.query("select stb1.c11, stb1.t11, stb1.t12 from stb2,stb1 where stb2.t21 = stb1.t11 and stb1.ts = stb2.ts") + tdSql.checkRows(2) + tdSql.query("select stb2.c21, stb2.t21, stb2.t21 from stb1, stb2 where stb2.t21 = stb1.t11 and stb1.ts = stb2.ts") + tdSql.checkRows(2) + tdSql.query("select top(stb2.c21,2) from stb1, stb2 where stb2.t21 = stb1.t11 and stb1.ts = stb2.ts") + tdSql.checkRows(2) + tdSql.query("select last(stb2.c21) from stb1, stb2 where stb2.t21 = stb1.t11 and stb1.ts = stb2.ts") + tdSql.checkRows(1) + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) \ No newline at end of file diff --git a/tests/pytest/query/query1970YearsAf.py b/tests/pytest/query/query1970YearsAf.py new file mode 100644 index 0000000000..9794973325 --- /dev/null +++ b/tests/pytest/query/query1970YearsAf.py @@ -0,0 +1,230 @@ +################################################################### +# 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 taos +import sys +import os +import json +import subprocess +import datetime + + +from util.log import * +from util.sql import * +from util.cases import * + +class TDTestCase: + + def init(self, conn, logSql): + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor()) + + def getCfgDir(self, path): + binPath = os.path.dirname(os.path.realpath(__file__)) + binPath = binPath + "/../../../debug/" + tdLog.debug("binPath %s" % (binPath)) + binPath = os.path.realpath(binPath) + tdLog.debug("binPath real path %s" % (binPath)) + if path == "": + self.path = os.path.abspath(binPath + "../../") + else: + self.path = os.path.realpath(path) + + self.cfgDir = "%s/sim/psim/cfg" % (self.path) + return self.cfgDir + + def creatcfg(self): + dbinfo = { + "name": "db", + "drop": "yes", + "replica": 1, + "days": 10, + "cache": 16, + "blocks": 8, + "precision": "ms", + "keep": 36500, + "minRows": 100, + "maxRows": 4096, + "comp": 2, + "walLevel": 1, + "cachelast": 0, + "quorum": 1, + "fsync": 3000, + "update": 0 + } + + # 设置创建的超级表格式 + stable1 = { + "name": "stb2", + "child_table_exists": "no", + "childtable_count": 10, + "childtable_prefix": "t", + "auto_create_table": "no", + "data_source": "rand", + "insert_mode": "taosc", + "insert_rows": 5000, + "multi_thread_write_one_tbl": "no", + "number_of_tbl_in_one_sql": 0, + "rows_per_tbl": 1000, + "max_sql_len": 65480, + "disorder_ratio": 0, + "disorder_range": 1000, + "timestamp_step": 19000000, + "start_timestamp": "1969-01-01 00:00:00.000", + "sample_format": "csv", + "sample_file": "./sample.csv", + "tags_file": "", + "columns": [ + {"type": "INT"}, + {"type": "DOUBLE", "count": 10}, + {"type": "BINARY", "len": 16, "count": 3}, + {"type": "BINARY", "len": 32, "count": 6} + ], + "tags": [ + {"type": "TINYINT", "count": 2}, + {"type": "BINARY", "len": 16, "count": 5} + ] + } + + # 需要创建多个超级表时,只需创建不同的超级表格式并添加至super_tables + super_tables = [stable1] + database = { + "dbinfo": dbinfo, + "super_tables": super_tables + } + + cfgdir = self.getCfgDir("") + create_table = { + "filetype": "insert", + "cfgdir": cfgdir, + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "thread_count": 4, + "thread_count_create_tbl": 4, + "result_file": "/tmp/insert_res.txt", + "confirm_parameter_prompt": "no", + "insert_interval": 0, + "num_of_records_per_req": 100, + "databases": [database] + } + return create_table + + def inserttable(self): + create_table = self.creatcfg() + date = datetime.datetime.now().strftime("%Y%m%d%H%M") + file_create_table = f"/tmp/insert_{date}.json" + + with open(file_create_table, 'w') as f: + json.dump(create_table, f) + + create_table_cmd = f"taosdemo -f {file_create_table}" + _ = subprocess.check_output(create_table_cmd, shell=True).decode("utf-8") + + + def run(self): + s = 'reset query cache' + tdSql.execute(s) + s = 'create database if not exists db' + tdSql.execute(s) + s = 'use db' + tdSql.execute(s) + + tdLog.info("==========step1:create table stable and child table,then insert data automatically") + self.inserttable() + # tdSql.execute( + # '''create table if not exists supt + # (ts timestamp, c1 int, c2 float, c3 bigint, c4 double, c5 smallint, c6 tinyint) + # tags(location binary(64), type int, isused bool , family nchar(64))''' + # ) + # tdSql.execute("create table t1 using supt tags('beijing', 1, 1, '自行车')") + # tdSql.execute("create table t2 using supt tags('shanghai', 2, 0, '拖拉机')") + # tdSql.execute( + # f"insert into t1 values (-31564800000, 6, 5, 4, 3, 2, 1)" + # ) + + + + tdLog.info("==========step2:query join") + + # stable query + tdSql.query( + "select * from stb2 where stb2.ts < '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(16600) + + tdSql.query( + "select * from stb2 where stb2.ts >= '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(33400) + + tdSql.query( + "select * from stb2 where stb2.ts > '1969-12-01 00:00:00.000' and stb2.ts <'1970-01-31 00:00:00.000' " + ) + tdSql.checkRows(2780) + + # child-table query + tdSql.query( + "select * from t0 where t0.ts < '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(1660) + + tdSql.query( + "select * from t1 where t1.ts >= '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(3340) + + tdSql.query( + "select * from t9 where t9.ts > '1969-12-01 00:00:00.000' and t9.ts <'1970-01-31 00:00:00.000' " + ) + tdSql.checkRows(278) + + tdSql.query( + "select * from t0,t1 where t0.ts=t1.ts and t1.ts >= '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(3340) + + tdSql.query( + "select diff(col1) from t0 where t0.ts >= '1970-01-01 00:00:00.000' " + ) + tdSql.checkRows(3339) + + tdSql.query( + "select t0,col1 from stb2 where stb2.ts < '1970-01-01 00:00:00.000' order by ts" + ) + tdSql.checkRows(16600) + + # query with timestamp in 'where ...' + tdSql.query( + "select * from stb2 where stb2.ts > -28800000 " + ) + tdSql.checkRows(33400) + + tdSql.query( + "select * from stb2 where stb2.ts > -28800000 and stb2.ts < '1970-01-01 08:00:00.000' " + ) + tdSql.checkRows(20) + + tdSql.query( + "select * from stb2 where stb2.ts < -28800000 and stb2.ts > '1969-12-31 16:00:00.000' " + ) + + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) \ No newline at end of file diff --git a/tests/pytest/tools/insert-interlace.json b/tests/pytest/tools/insert-interlace.json index a2ff2c001c..d4767ad064 100644 --- a/tests/pytest/tools/insert-interlace.json +++ b/tests/pytest/tools/insert-interlace.json @@ -10,7 +10,7 @@ "result_file": "./insert_res.txt", "confirm_parameter_prompt": "no", "insert_interval": 5000, - "rows_per_tbl": 50, + "interlace_rows": 50, "num_of_records_per_req": 100, "max_sql_len": 1024000, "databases": [{ @@ -42,7 +42,7 @@ "insert_mode": "taosc", "insert_rows": 250, "multi_thread_write_one_tbl": "no", - "rows_per_tbl": 80, + "interlace_rows": 80, "max_sql_len": 1024000, "disorder_ratio": 0, "disorder_range": 1000, diff --git a/tests/pytest/tools/query.json b/tests/pytest/tools/query.json new file mode 100644 index 0000000000..d486423865 --- /dev/null +++ b/tests/pytest/tools/query.json @@ -0,0 +1,22 @@ +{ + "filetype": "query", + "cfgdir": "/etc/taos", + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "confirm_parameter_prompt": "no", + "databases": "test", + "query_times": 1, + "super_table_query": { + "stblname": "meters", + "query_interval": 10, + "threads": 8, + "sqls": [ + { + "sql": "select last_row(ts) from xxxx", + "result": "" + } + ] + } +} diff --git a/tests/pytest/tools/taosdemoTest.py b/tests/pytest/tools/taosdemoTest.py index 2ce9228c54..ff5921be60 100644 --- a/tests/pytest/tools/taosdemoTest.py +++ b/tests/pytest/tools/taosdemoTest.py @@ -51,7 +51,7 @@ class TDTestCase: else: tdLog.info("taosd found in %s" % buildPath) binPath = buildPath + "/build/bin/" - os.system("%staosdemo -y -M -t %d -n %d -x" % + os.system("%staosdemo -y -t %d -n %d" % (binPath, self.numberOfTables, self.numberOfRecords)) tdSql.execute("use test") diff --git a/tests/pytest/tools/taosdemoTest2.py b/tests/pytest/tools/taosdemoTest2.py index 75a79d0585..74b05faf8b 100644 --- a/tests/pytest/tools/taosdemoTest2.py +++ b/tests/pytest/tools/taosdemoTest2.py @@ -31,12 +31,20 @@ class TDTestCase: def insertDataAndAlterTable(self, threadID): if(threadID == 0): - os.system("taosdemo -M -y -t %d -n %d -x" % + os.system("taosdemo -y -t %d -n %d" % (self.numberOfTables, self.numberOfRecords)) if(threadID == 1): time.sleep(2) print("use test") - tdSql.execute("use test") + while True: + try: + tdSql.execute("use test") + break + except Exception as e: + tdLog.info("use database test failed") + time.sleep(1) + continue + # check if all the tables have heen created while True: tdSql.query("show tables") diff --git a/tests/pytest/tools/taosdemoTestInterlace.py b/tests/pytest/tools/taosdemoTestInterlace.py index 9ceb8c5cbb..4c551f327a 100644 --- a/tests/pytest/tools/taosdemoTestInterlace.py +++ b/tests/pytest/tools/taosdemoTestInterlace.py @@ -1,4 +1,4 @@ -################################################################### +################################################################## # Copyright (c) 2016 by TAOS Technologies, Inc. # All rights reserved. # @@ -17,6 +17,7 @@ from util.log import * from util.cases import * from util.sql import * from util.dnodes import * +import subprocess class TDTestCase: @@ -24,9 +25,6 @@ class TDTestCase: tdLog.debug("start to execute %s" % __file__) tdSql.init(conn.cursor(), logSql) - self.numberOfTables = 10000 - self.numberOfRecords = 100 - def getBuildPath(self): selfPath = os.path.dirname(os.path.realpath(__file__)) @@ -39,7 +37,7 @@ class TDTestCase: if ("taosd" in files): rootRealPath = os.path.dirname(os.path.realpath(root)) if ("packaging" not in rootRealPath): - buildPath = root[:len(root)-len("/build/bin")] + buildPath = root[:len(root) - len("/build/bin")] break return buildPath @@ -50,14 +48,23 @@ class TDTestCase: tdLog.exit("taosd not found!") else: tdLog.info("taosd found in %s" % buildPath) - binPath = buildPath+ "/build/bin/" - os.system("%staosdemo -f tools/insert-interlace.json" % binPath) + binPath = buildPath + "/build/bin/" + taosdemoCmd = "%staosdemo -f tools/insert-interlace.json -pp 2>&1 | grep sleep | wc -l" % binPath + sleepTimes = subprocess.check_output( + taosdemoCmd, shell=True).decode("utf-8") + print("sleep times: %d" % int(sleepTimes)) + + if (int(sleepTimes) != 16): + caller = inspect.getframeinfo(inspect.stack()[0][0]) + tdLog.exit( + "%s(%d) failed: expected sleep times 16, actual %d" % + (caller.filename, caller.lineno, int(sleepTimes))) tdSql.execute("use db") tdSql.query("select count(tbname) from db.stb") - tdSql.checkData(0, 0, 100) + tdSql.checkData(0, 0, 9) tdSql.query("select count(*) from db.stb") - tdSql.checkData(0, 0, 33000) + tdSql.checkData(0, 0, 2250) def stop(self): tdSql.close() diff --git a/tests/pytest/tools/taosdemoTestQuery.py b/tests/pytest/tools/taosdemoTestQuery.py new file mode 100644 index 0000000000..bb2bb85052 --- /dev/null +++ b/tests/pytest/tools/taosdemoTestQuery.py @@ -0,0 +1,78 @@ +################################################################### +# 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 sys +import os +import time +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import * +import subprocess + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + self.numberOfTables = 1000 + self.numberOfRecords = 100 + + def getBuildPath(self): + selfPath = os.path.dirname(os.path.realpath(__file__)) + + if ("community" in selfPath): + projPath = selfPath[:selfPath.find("community")] + else: + projPath = selfPath[:selfPath.find("tests")] + + for root, dirs, files in os.walk(projPath): + if ("taosd" in files): + rootRealPath = os.path.dirname(os.path.realpath(root)) + if ("packaging" not in rootRealPath): + buildPath = root[:len(root) - len("/build/bin")] + break + return buildPath + + def run(self): + tdSql.prepare() + buildPath = self.getBuildPath() + if (buildPath == ""): + tdLog.exit("taosd not found!") + else: + tdLog.info("taosd found in %s" % buildPath) + binPath = buildPath + "/build/bin/" + os.system("%staosdemo -y -t %d -n %d" % + (binPath, self.numberOfTables, self.numberOfRecords)) + print("Sleep 2 seconds..") + time.sleep(2) + os.system('%staosdemo -f tools/query.json ' % binPath) +# taosdemoCmd = '%staosdemo -f tools/query.json ' % binPath +# threads = subprocess.check_output( +# taosdemoCmd, shell=True).decode("utf-8") +# print("threads: %d" % int(threads)) + +# if (int(threads) != 8): +# caller = inspect.getframeinfo(inspect.stack()[0][0]) +# tdLog.exit( +# "%s(%d) failed: expected threads 8, actual %d" % +# (caller.filename, caller.lineno, int(threads))) +# + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/pytest/tools/taosdemoTestWithoutMetric.py b/tests/pytest/tools/taosdemoTestWithoutMetric.py index 647d6a37cb..9687600563 100644 --- a/tests/pytest/tools/taosdemoTestWithoutMetric.py +++ b/tests/pytest/tools/taosdemoTestWithoutMetric.py @@ -50,7 +50,7 @@ class TDTestCase: else: tdLog.info("taosd found in %s" % buildPath) binPath = buildPath + "/build/bin/" - os.system("%staosdemo -y -t %d -n %d -x" % + os.system("%staosdemo -N -y -t %d -n %d" % (binPath, self.numberOfTables, self.numberOfRecords)) tdSql.query("show databases") diff --git a/tests/script/general/db/topic1.sim b/tests/script/general/db/topic1.sim index cdfb8ea2ec..42613405af 100644 --- a/tests/script/general/db/topic1.sim +++ b/tests/script/general/db/topic1.sim @@ -167,7 +167,7 @@ sql_error show t1.stables; sql_error show t1.tables; sql_error create topic t1 partitions -1; -sql_error create topic t1 partitions 0; +#sql_error create topic t1 partitions 0; sql_error create topic t1 partitions 10001; print =============step3 create with db para @@ -718,7 +718,7 @@ sql_error alter database t1 partitions 1000 sql_error alter database t1 partitions 10000 sql_error alter topic t1 partitions -1 -sql_error alter topic t1 partitions 0 +#sql_error alter topic t1 partitions 0 sql_error alter database t1 partitions 10000 sql alter topic t1 partitions 1 @@ -842,4 +842,43 @@ if $rows != 10 then return -1 endi +sql drop topic t1 + +print ============== create same name topic +sql create database d2 +sql create topic t2 + +sql_error create topic d2 +sql_error create topic if not exists d2 +sql_error create topic t2 +sql create topic if not exists t2 +sql_error create topic t2 partitions 5; +sql_error create topic t2 partitions 6; +sql_error create topic t2 partitions 3; + +sql_error alter topic t3 partitions 1 +sql_error alter topic d2 partitions 1 +#sql_error alter topic t2 partitions 0 +sql_error alter topic t2 partitions 10000 + +sql_error drop topic d2 +sql_error drop topic d3 +sql drop database d2 +sql drop database t2 + +print ============== create partitons 0 +sql create topic t2 partitions 0 +sql show t2.stables; +if $rows != 0 then + return -1 +endi +sql show t2.tables; +if $rows != 0 then + return -1 +endi + +sql drop topic t2 +sql_error drop topic abc +sql drop topic if exists abc; + system sh/exec.sh -n dnode1 -s stop -x SIGINT diff --git a/tests/script/general/parser/join_multitables.sim b/tests/script/general/parser/join_multitables.sim new file mode 100644 index 0000000000..acb8be10e7 --- /dev/null +++ b/tests/script/general/parser/join_multitables.sim @@ -0,0 +1,2326 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/cfg.sh -n dnode1 -c walLevel -v 0 +system sh/cfg.sh -n dnode1 -c maxtablesPerVnode -v 2 +system sh/exec.sh -n dnode1 -s start + +sleep 100 +sql connect +print ======================== dnode1 start + +$db = testdb + +sql create database $db +sql use $db + +sql create stable st0 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st1 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st2 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st3 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st4 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st5 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st6 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st7 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st8 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable st9 (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable sta (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); +sql create stable stb (ts timestamp, f1 int, f2 double, f3 binary(10)) tags(id1 int, id2 smallint, id3 double, id4 bool, id5 binary(5)); + +sql create table tb0_1 using st0 tags(0,1,2.0,true,'3'); +sql create table tb0_2 using st0 tags(1,2,3.0,false,'4'); +sql create table tb0_3 using st0 tags(2,3,4.0,true,'5'); +sql create table tb0_4 using st0 tags(3,4,5.0,false,'6'); +sql create table tb0_5 using st0 tags(4,5,6.0,true,'7'); + +sql create table tb1_1 using st1 tags(0,1,2.0,true,'3'); +sql create table tb1_2 using st1 tags(1,2,3.0,false,'4'); +sql create table tb1_3 using st1 tags(2,3,4.0,true,'5'); +sql create table tb1_4 using st1 tags(3,4,5.0,false,'6'); +sql create table tb1_5 using st1 tags(4,5,6.0,true,'7'); + +sql create table tb2_1 using st2 tags(0,1,2.0,true,'3'); +sql create table tb2_2 using st2 tags(1,2,3.0,false,'4'); +sql create table tb2_3 using st2 tags(2,3,4.0,true,'5'); +sql create table tb2_4 using st2 tags(3,4,5.0,false,'6'); +sql create table tb2_5 using st2 tags(4,5,6.0,true,'7'); + +sql create table tb3_1 using st3 tags(0,1,2.0,true,'3'); +sql create table tb3_2 using st3 tags(1,2,3.0,false,'4'); +sql create table tb3_3 using st3 tags(2,3,4.0,true,'5'); +sql create table tb3_4 using st3 tags(3,4,5.0,false,'6'); +sql create table tb3_5 using st3 tags(4,5,6.0,true,'7'); + +sql create table tb4_1 using st4 tags(0,1,2.0,true,'3'); +sql create table tb4_2 using st4 tags(1,2,3.0,false,'4'); +sql create table tb4_3 using st4 tags(2,3,4.0,true,'5'); +sql create table tb4_4 using st4 tags(3,4,5.0,false,'6'); +sql create table tb4_5 using st4 tags(4,5,6.0,true,'7'); + +sql create table tb5_1 using st5 tags(0,1,2.0,true,'3'); +sql create table tb5_2 using st5 tags(1,2,3.0,false,'4'); +sql create table tb5_3 using st5 tags(2,3,4.0,true,'5'); +sql create table tb5_4 using st5 tags(3,4,5.0,false,'6'); +sql create table tb5_5 using st5 tags(4,5,6.0,true,'7'); + +sql create table tb6_1 using st6 tags(0,1,2.0,true,'3'); +sql create table tb6_2 using st6 tags(1,2,3.0,false,'4'); +sql create table tb6_3 using st6 tags(2,3,4.0,true,'5'); +sql create table tb6_4 using st6 tags(3,4,5.0,false,'6'); +sql create table tb6_5 using st6 tags(4,5,6.0,true,'7'); + +sql create table tb7_1 using st7 tags(0,1,2.0,true,'3'); +sql create table tb7_2 using st7 tags(1,2,3.0,false,'4'); +sql create table tb7_3 using st7 tags(2,3,4.0,true,'5'); +sql create table tb7_4 using st7 tags(3,4,5.0,false,'6'); +sql create table tb7_5 using st7 tags(4,5,6.0,true,'7'); + +sql create table tb8_1 using st8 tags(0,1,2.0,true,'3'); +sql create table tb8_2 using st8 tags(1,2,3.0,false,'4'); +sql create table tb8_3 using st8 tags(2,3,4.0,true,'5'); +sql create table tb8_4 using st8 tags(3,4,5.0,false,'6'); +sql create table tb8_5 using st8 tags(4,5,6.0,true,'7'); + +sql create table tb9_1 using st9 tags(0,1,2.0,true,'3'); +sql create table tb9_2 using st9 tags(1,2,3.0,false,'4'); +sql create table tb9_3 using st9 tags(2,3,4.0,true,'5'); +sql create table tb9_4 using st9 tags(3,4,5.0,false,'6'); +sql create table tb9_5 using st9 tags(4,5,6.0,true,'7'); + +sql create table tba_1 using sta tags(0,1,2.0,true,'3'); +sql create table tba_2 using sta tags(0,1,2.0,true,'3'); +sql create table tba_3 using sta tags(0,1,2.0,true,'3'); +sql create table tba_4 using sta tags(0,1,2.0,true,'3'); +sql create table tba_5 using sta tags(0,1,2.0,true,'3'); + +sql create table tbb_1 using stb tags(0,1,2.0,true,'3'); +sql create table tbb_2 using stb tags(0,1,2.0,true,'3'); +sql create table tbb_3 using stb tags(0,1,2.0,true,'3'); +sql create table tbb_4 using stb tags(0,1,2.0,true,'3'); +sql create table tbb_5 using stb tags(0,1,2.0,true,'3'); + +sql insert into tb0_1 values('2021-03-01 01:00:00.000', 9901,9901.0,'01'); +sql insert into tb0_1 values('2021-03-02 01:00:00.000', 9901,9901.0,'01'); +sql insert into tb0_1 values('2021-03-03 01:00:00.000', 9901,9901.0,'01'); +sql insert into tb0_1 values('2021-03-04 01:00:00.000', 9901,9901.0,'01'); +sql insert into tb0_1 values('2021-03-05 01:00:00.000', 9901,9901.0,'01'); +sql insert into tb0_2 values('2021-03-01 02:00:00.000', 9902,9902.0,'02'); +sql insert into tb0_2 values('2021-03-02 02:00:00.000', 9902,9902.0,'02'); +sql insert into tb0_2 values('2021-03-03 02:00:00.000', 9902,9902.0,'02'); +sql insert into tb0_2 values('2021-03-04 02:00:00.000', 9902,9902.0,'02'); +sql insert into tb0_2 values('2021-03-05 02:00:00.000', 9902,9902.0,'02'); +sql insert into tb0_3 values('2021-03-01 03:00:00.000', 9903,9903.0,'03'); +sql insert into tb0_3 values('2021-03-02 03:00:00.000', 9903,9903.0,'03'); +sql insert into tb0_3 values('2021-03-03 03:00:00.000', 9903,9903.0,'03'); +sql insert into tb0_3 values('2021-03-04 03:00:00.000', 9903,9903.0,'03'); +sql insert into tb0_3 values('2021-03-05 03:00:00.000', 9903,9903.0,'03'); +sql insert into tb0_4 values('2021-03-01 04:00:00.000', 9904,9904.0,'04'); +sql insert into tb0_4 values('2021-03-02 04:00:00.000', 9904,9904.0,'04'); +sql insert into tb0_4 values('2021-03-03 04:00:00.000', 9904,9904.0,'04'); +sql insert into tb0_4 values('2021-03-04 04:00:00.000', 9904,9904.0,'04'); +sql insert into tb0_4 values('2021-03-05 04:00:00.000', 9904,9904.0,'04'); +sql insert into tb0_5 values('2021-03-01 05:00:00.000', 9905,9905.0,'05'); +sql insert into tb0_5 values('2021-03-02 05:00:00.000', 9905,9905.0,'05'); +sql insert into tb0_5 values('2021-03-03 05:00:00.000', 9905,9905.0,'05'); +sql insert into tb0_5 values('2021-03-04 05:00:00.000', 9905,9905.0,'05'); +sql insert into tb0_5 values('2021-03-05 05:00:00.000', 9905,9905.0,'05'); + +sql insert into tb1_1 values('2021-03-01 01:00:00.000', 9911,9911.0,'11'); +sql insert into tb1_1 values('2021-03-02 01:00:00.000', 9911,9911.0,'11'); +sql insert into tb1_1 values('2021-03-03 01:00:00.000', 9911,9911.0,'11'); +sql insert into tb1_1 values('2021-03-04 01:00:00.000', 9911,9911.0,'11'); +sql insert into tb1_1 values('2021-03-05 01:00:00.000', 9911,9911.0,'11'); +sql insert into tb1_2 values('2021-03-01 02:00:00.000', 9912,9912.0,'12'); +sql insert into tb1_2 values('2021-03-02 02:00:00.000', 9912,9912.0,'12'); +sql insert into tb1_2 values('2021-03-03 02:00:00.000', 9912,9912.0,'12'); +sql insert into tb1_2 values('2021-03-04 02:00:00.000', 9912,9912.0,'12'); +sql insert into tb1_2 values('2021-03-05 02:00:00.000', 9912,9912.0,'12'); +sql insert into tb1_3 values('2021-03-01 03:00:00.000', 9913,9913.0,'13'); +sql insert into tb1_3 values('2021-03-02 03:00:00.000', 9913,9913.0,'13'); +sql insert into tb1_3 values('2021-03-03 03:00:00.000', 9913,9913.0,'13'); +sql insert into tb1_3 values('2021-03-04 03:00:00.000', 9913,9913.0,'13'); +sql insert into tb1_3 values('2021-03-05 03:00:00.000', 9913,9913.0,'13'); +sql insert into tb1_4 values('2021-03-01 04:00:00.000', 9914,9914.0,'14'); +sql insert into tb1_4 values('2021-03-02 04:00:00.000', 9914,9914.0,'14'); +sql insert into tb1_4 values('2021-03-03 04:00:00.000', 9914,9914.0,'14'); +sql insert into tb1_4 values('2021-03-04 04:00:00.000', 9914,9914.0,'14'); +sql insert into tb1_4 values('2021-03-05 04:00:00.000', 9914,9914.0,'14'); +sql insert into tb1_5 values('2021-03-01 05:00:00.000', 9915,9915.0,'15'); +sql insert into tb1_5 values('2021-03-02 05:00:00.000', 9915,9915.0,'15'); +sql insert into tb1_5 values('2021-03-03 05:00:00.000', 9915,9915.0,'15'); +sql insert into tb1_5 values('2021-03-04 05:00:00.000', 9915,9915.0,'15'); +sql insert into tb1_5 values('2021-03-05 05:00:00.000', 9915,9915.0,'15'); + +sql insert into tb2_1 values('2021-03-01 01:00:00.000', 9921,9921.0,'21'); +sql insert into tb2_1 values('2021-03-02 01:00:00.000', 9921,9921.0,'21'); +sql insert into tb2_1 values('2021-03-03 01:00:00.000', 9921,9921.0,'21'); +sql insert into tb2_1 values('2021-03-04 01:00:00.000', 9921,9921.0,'21'); +sql insert into tb2_1 values('2021-03-05 01:00:00.000', 9921,9921.0,'21'); +sql insert into tb2_2 values('2021-03-01 02:00:00.000', 9922,9922.0,'22'); +sql insert into tb2_2 values('2021-03-02 02:00:00.000', 9922,9922.0,'22'); +sql insert into tb2_2 values('2021-03-03 02:00:00.000', 9922,9922.0,'22'); +sql insert into tb2_2 values('2021-03-04 02:00:00.000', 9922,9922.0,'22'); +sql insert into tb2_2 values('2021-03-05 02:00:00.000', 9922,9922.0,'22'); +sql insert into tb2_3 values('2021-03-01 03:00:00.000', 9923,9923.0,'23'); +sql insert into tb2_3 values('2021-03-02 03:00:00.000', 9923,9923.0,'23'); +sql insert into tb2_3 values('2021-03-03 03:00:00.000', 9923,9923.0,'23'); +sql insert into tb2_3 values('2021-03-04 03:00:00.000', 9923,9923.0,'23'); +sql insert into tb2_3 values('2021-03-05 03:00:00.000', 9923,9923.0,'23'); +sql insert into tb2_4 values('2021-03-01 04:00:00.000', 9924,9924.0,'24'); +sql insert into tb2_4 values('2021-03-02 04:00:00.000', 9924,9924.0,'24'); +sql insert into tb2_4 values('2021-03-03 04:00:00.000', 9924,9924.0,'24'); +sql insert into tb2_4 values('2021-03-04 04:00:00.000', 9924,9924.0,'24'); +sql insert into tb2_4 values('2021-03-05 04:00:00.000', 9924,9924.0,'24'); +sql insert into tb2_5 values('2021-03-01 05:00:00.000', 9925,9925.0,'25'); +sql insert into tb2_5 values('2021-03-02 05:00:00.000', 9925,9925.0,'25'); +sql insert into tb2_5 values('2021-03-03 05:00:00.000', 9925,9925.0,'25'); +sql insert into tb2_5 values('2021-03-04 05:00:00.000', 9925,9925.0,'25'); +sql insert into tb2_5 values('2021-03-05 05:00:00.000', 9925,9925.0,'25'); + + +sql insert into tb3_1 values('2021-03-01 01:00:00.000', 9931,9931.0,'31'); +sql insert into tb3_1 values('2021-03-02 01:00:00.000', 9931,9931.0,'31'); +sql insert into tb3_1 values('2021-03-03 01:00:00.000', 9931,9931.0,'31'); +sql insert into tb3_1 values('2021-03-04 01:00:00.000', 9931,9931.0,'31'); +sql insert into tb3_1 values('2021-03-05 01:00:00.000', 9931,9931.0,'31'); +sql insert into tb3_2 values('2021-03-01 02:00:00.000', 9932,9932.0,'32'); +sql insert into tb3_2 values('2021-03-02 02:00:00.000', 9932,9932.0,'32'); +sql insert into tb3_2 values('2021-03-03 02:00:00.000', 9932,9932.0,'32'); +sql insert into tb3_2 values('2021-03-04 02:00:00.000', 9932,9932.0,'32'); +sql insert into tb3_2 values('2021-03-05 02:00:00.000', 9932,9932.0,'32'); +sql insert into tb3_3 values('2021-03-01 03:00:00.000', 9933,9933.0,'33'); +sql insert into tb3_3 values('2021-03-02 03:00:00.000', 9933,9933.0,'33'); +sql insert into tb3_3 values('2021-03-03 03:00:00.000', 9933,9933.0,'33'); +sql insert into tb3_3 values('2021-03-04 03:00:00.000', 9933,9933.0,'33'); +sql insert into tb3_3 values('2021-03-05 03:00:00.000', 9933,9933.0,'33'); +sql insert into tb3_4 values('2021-03-01 04:00:00.000', 9934,9934.0,'34'); +sql insert into tb3_4 values('2021-03-02 04:00:00.000', 9934,9934.0,'34'); +sql insert into tb3_4 values('2021-03-03 04:00:00.000', 9934,9934.0,'34'); +sql insert into tb3_4 values('2021-03-04 04:00:00.000', 9934,9934.0,'34'); +sql insert into tb3_4 values('2021-03-05 04:00:00.000', 9934,9934.0,'34'); +sql insert into tb3_5 values('2021-03-01 05:00:00.000', 9935,9935.0,'35'); +sql insert into tb3_5 values('2021-03-02 05:00:00.000', 9935,9935.0,'35'); +sql insert into tb3_5 values('2021-03-03 05:00:00.000', 9935,9935.0,'35'); +sql insert into tb3_5 values('2021-03-04 05:00:00.000', 9935,9935.0,'35'); +sql insert into tb3_5 values('2021-03-05 05:00:00.000', 9935,9935.0,'35'); + + +sql insert into tb4_1 values('2021-03-01 01:00:00.000', 9941,9941.0,'41'); +sql insert into tb4_1 values('2021-03-02 01:00:00.000', 9941,9941.0,'41'); +sql insert into tb4_1 values('2021-03-03 01:00:00.000', 9941,9941.0,'41'); +sql insert into tb4_1 values('2021-03-04 01:00:00.000', 9941,9941.0,'41'); +sql insert into tb4_1 values('2021-03-05 01:00:00.000', 9941,9941.0,'41'); +sql insert into tb4_2 values('2021-03-01 02:00:00.000', 9942,9942.0,'42'); +sql insert into tb4_2 values('2021-03-02 02:00:00.000', 9942,9942.0,'42'); +sql insert into tb4_2 values('2021-03-03 02:00:00.000', 9942,9942.0,'42'); +sql insert into tb4_2 values('2021-03-04 02:00:00.000', 9942,9942.0,'42'); +sql insert into tb4_2 values('2021-03-05 02:00:00.000', 9942,9942.0,'42'); +sql insert into tb4_3 values('2021-03-01 03:00:00.000', 9943,9943.0,'43'); +sql insert into tb4_3 values('2021-03-02 03:00:00.000', 9943,9943.0,'43'); +sql insert into tb4_3 values('2021-03-03 03:00:00.000', 9943,9943.0,'43'); +sql insert into tb4_3 values('2021-03-04 03:00:00.000', 9943,9943.0,'43'); +sql insert into tb4_3 values('2021-03-05 03:00:00.000', 9943,9943.0,'43'); +sql insert into tb4_4 values('2021-03-01 04:00:00.000', 9944,9944.0,'44'); +sql insert into tb4_4 values('2021-03-02 04:00:00.000', 9944,9944.0,'44'); +sql insert into tb4_4 values('2021-03-03 04:00:00.000', 9944,9944.0,'44'); +sql insert into tb4_4 values('2021-03-04 04:00:00.000', 9944,9944.0,'44'); +sql insert into tb4_4 values('2021-03-05 04:00:00.000', 9944,9944.0,'44'); +sql insert into tb4_5 values('2021-03-01 05:00:00.000', 9945,9945.0,'45'); +sql insert into tb4_5 values('2021-03-02 05:00:00.000', 9945,9945.0,'45'); +sql insert into tb4_5 values('2021-03-03 05:00:00.000', 9945,9945.0,'45'); +sql insert into tb4_5 values('2021-03-04 05:00:00.000', 9945,9945.0,'45'); +sql insert into tb4_5 values('2021-03-05 05:00:00.000', 9945,9945.0,'45'); + +sql insert into tb5_1 values('2021-03-01 01:00:00.000', 9951,9951.0,'51'); +sql insert into tb5_1 values('2021-03-02 01:00:00.000', 9951,9951.0,'51'); +sql insert into tb5_1 values('2021-03-03 01:00:00.000', 9951,9951.0,'51'); +sql insert into tb5_1 values('2021-03-04 01:00:00.000', 9951,9951.0,'51'); +sql insert into tb5_1 values('2021-03-05 01:00:00.000', 9951,9951.0,'51'); +sql insert into tb5_2 values('2021-03-01 02:00:00.000', 9952,9952.0,'52'); +sql insert into tb5_2 values('2021-03-02 02:00:00.000', 9952,9952.0,'52'); +sql insert into tb5_2 values('2021-03-03 02:00:00.000', 9952,9952.0,'52'); +sql insert into tb5_2 values('2021-03-04 02:00:00.000', 9952,9952.0,'52'); +sql insert into tb5_2 values('2021-03-05 02:00:00.000', 9952,9952.0,'52'); +sql insert into tb5_3 values('2021-03-01 03:00:00.000', 9953,9953.0,'53'); +sql insert into tb5_3 values('2021-03-02 03:00:00.000', 9953,9953.0,'53'); +sql insert into tb5_3 values('2021-03-03 03:00:00.000', 9953,9953.0,'53'); +sql insert into tb5_3 values('2021-03-04 03:00:00.000', 9953,9953.0,'53'); +sql insert into tb5_3 values('2021-03-05 03:00:00.000', 9953,9953.0,'53'); +sql insert into tb5_4 values('2021-03-01 04:00:00.000', 9954,9954.0,'54'); +sql insert into tb5_4 values('2021-03-02 04:00:00.000', 9954,9954.0,'54'); +sql insert into tb5_4 values('2021-03-03 04:00:00.000', 9954,9954.0,'54'); +sql insert into tb5_4 values('2021-03-04 04:00:00.000', 9954,9954.0,'54'); +sql insert into tb5_4 values('2021-03-05 04:00:00.000', 9954,9954.0,'54'); +sql insert into tb5_5 values('2021-03-01 05:00:00.000', 9955,9955.0,'55'); +sql insert into tb5_5 values('2021-03-02 05:00:00.000', 9955,9955.0,'55'); +sql insert into tb5_5 values('2021-03-03 05:00:00.000', 9955,9955.0,'55'); +sql insert into tb5_5 values('2021-03-04 05:00:00.000', 9955,9955.0,'55'); +sql insert into tb5_5 values('2021-03-05 05:00:00.000', 9955,9955.0,'55'); + +sql insert into tb6_1 values('2021-03-01 01:00:00.000', 9961,9961.0,'61'); +sql insert into tb6_1 values('2021-03-02 01:00:00.000', 9961,9961.0,'61'); +sql insert into tb6_1 values('2021-03-03 01:00:00.000', 9961,9961.0,'61'); +sql insert into tb6_1 values('2021-03-04 01:00:00.000', 9961,9961.0,'61'); +sql insert into tb6_1 values('2021-03-05 01:00:00.000', 9961,9961.0,'61'); +sql insert into tb6_2 values('2021-03-01 02:00:00.000', 9962,9962.0,'62'); +sql insert into tb6_2 values('2021-03-02 02:00:00.000', 9962,9962.0,'62'); +sql insert into tb6_2 values('2021-03-03 02:00:00.000', 9962,9962.0,'62'); +sql insert into tb6_2 values('2021-03-04 02:00:00.000', 9962,9962.0,'62'); +sql insert into tb6_2 values('2021-03-05 02:00:00.000', 9962,9962.0,'62'); +sql insert into tb6_3 values('2021-03-01 03:00:00.000', 9963,9963.0,'63'); +sql insert into tb6_3 values('2021-03-02 03:00:00.000', 9963,9963.0,'63'); +sql insert into tb6_3 values('2021-03-03 03:00:00.000', 9963,9963.0,'63'); +sql insert into tb6_3 values('2021-03-04 03:00:00.000', 9963,9963.0,'63'); +sql insert into tb6_3 values('2021-03-05 03:00:00.000', 9963,9963.0,'63'); +sql insert into tb6_4 values('2021-03-01 04:00:00.000', 9964,9964.0,'64'); +sql insert into tb6_4 values('2021-03-02 04:00:00.000', 9964,9964.0,'64'); +sql insert into tb6_4 values('2021-03-03 04:00:00.000', 9964,9964.0,'64'); +sql insert into tb6_4 values('2021-03-04 04:00:00.000', 9964,9964.0,'64'); +sql insert into tb6_4 values('2021-03-05 04:00:00.000', 9964,9964.0,'64'); +sql insert into tb6_5 values('2021-03-01 05:00:00.000', 9965,9965.0,'65'); +sql insert into tb6_5 values('2021-03-02 05:00:00.000', 9965,9965.0,'65'); +sql insert into tb6_5 values('2021-03-03 05:00:00.000', 9965,9965.0,'65'); +sql insert into tb6_5 values('2021-03-04 05:00:00.000', 9965,9965.0,'65'); +sql insert into tb6_5 values('2021-03-05 05:00:00.000', 9965,9965.0,'65'); + +sql insert into tb7_1 values('2021-03-01 01:00:00.000', 9971,9971.0,'71'); +sql insert into tb7_1 values('2021-03-02 01:00:00.000', 9971,9971.0,'71'); +sql insert into tb7_1 values('2021-03-03 01:00:00.000', 9971,9971.0,'71'); +sql insert into tb7_1 values('2021-03-04 01:00:00.000', 9971,9971.0,'71'); +sql insert into tb7_1 values('2021-03-05 01:00:00.000', 9971,9971.0,'71'); +sql insert into tb7_2 values('2021-03-01 02:00:00.000', 9972,9972.0,'72'); +sql insert into tb7_2 values('2021-03-02 02:00:00.000', 9972,9972.0,'72'); +sql insert into tb7_2 values('2021-03-03 02:00:00.000', 9972,9972.0,'72'); +sql insert into tb7_2 values('2021-03-04 02:00:00.000', 9972,9972.0,'72'); +sql insert into tb7_2 values('2021-03-05 02:00:00.000', 9972,9972.0,'72'); +sql insert into tb7_3 values('2021-03-01 03:00:00.000', 9973,9973.0,'73'); +sql insert into tb7_3 values('2021-03-02 03:00:00.000', 9973,9973.0,'73'); +sql insert into tb7_3 values('2021-03-03 03:00:00.000', 9973,9973.0,'73'); +sql insert into tb7_3 values('2021-03-04 03:00:00.000', 9973,9973.0,'73'); +sql insert into tb7_3 values('2021-03-05 03:00:00.000', 9973,9973.0,'73'); +sql insert into tb7_4 values('2021-03-01 04:00:00.000', 9974,9974.0,'74'); +sql insert into tb7_4 values('2021-03-02 04:00:00.000', 9974,9974.0,'74'); +sql insert into tb7_4 values('2021-03-03 04:00:00.000', 9974,9974.0,'74'); +sql insert into tb7_4 values('2021-03-04 04:00:00.000', 9974,9974.0,'74'); +sql insert into tb7_4 values('2021-03-05 04:00:00.000', 9974,9974.0,'74'); +sql insert into tb7_5 values('2021-03-01 05:00:00.000', 9975,9975.0,'75'); +sql insert into tb7_5 values('2021-03-02 05:00:00.000', 9975,9975.0,'75'); +sql insert into tb7_5 values('2021-03-03 05:00:00.000', 9975,9975.0,'75'); +sql insert into tb7_5 values('2021-03-04 05:00:00.000', 9975,9975.0,'75'); +sql insert into tb7_5 values('2021-03-05 05:00:00.000', 9975,9975.0,'75'); + +sql insert into tb8_1 values('2021-03-01 01:00:00.000', 9981,9981.0,'81'); +sql insert into tb8_1 values('2021-03-02 01:00:00.000', 9981,9981.0,'81'); +sql insert into tb8_1 values('2021-03-03 01:00:00.000', 9981,9981.0,'81'); +sql insert into tb8_1 values('2021-03-04 01:00:00.000', 9981,9981.0,'81'); +sql insert into tb8_1 values('2021-03-05 01:00:00.000', 9981,9981.0,'81'); +sql insert into tb8_2 values('2021-03-01 02:00:00.000', 9982,9982.0,'82'); +sql insert into tb8_2 values('2021-03-02 02:00:00.000', 9982,9982.0,'82'); +sql insert into tb8_2 values('2021-03-03 02:00:00.000', 9982,9982.0,'82'); +sql insert into tb8_2 values('2021-03-04 02:00:00.000', 9982,9982.0,'82'); +sql insert into tb8_2 values('2021-03-05 02:00:00.000', 9982,9982.0,'82'); +sql insert into tb8_3 values('2021-03-01 03:00:00.000', 9983,9983.0,'83'); +sql insert into tb8_3 values('2021-03-02 03:00:00.000', 9983,9983.0,'83'); +sql insert into tb8_3 values('2021-03-03 03:00:00.000', 9983,9983.0,'83'); +sql insert into tb8_3 values('2021-03-04 03:00:00.000', 9983,9983.0,'83'); +sql insert into tb8_3 values('2021-03-05 03:00:00.000', 9983,9983.0,'83'); +sql insert into tb8_4 values('2021-03-01 04:00:00.000', 9984,9984.0,'84'); +sql insert into tb8_4 values('2021-03-02 04:00:00.000', 9984,9984.0,'84'); +sql insert into tb8_4 values('2021-03-03 04:00:00.000', 9984,9984.0,'84'); +sql insert into tb8_4 values('2021-03-04 04:00:00.000', 9984,9984.0,'84'); +sql insert into tb8_4 values('2021-03-05 04:00:00.000', 9984,9984.0,'84'); +sql insert into tb8_5 values('2021-03-01 05:00:00.000', 9985,9985.0,'85'); +sql insert into tb8_5 values('2021-03-02 05:00:00.000', 9985,9985.0,'85'); +sql insert into tb8_5 values('2021-03-03 05:00:00.000', 9985,9985.0,'85'); +sql insert into tb8_5 values('2021-03-04 05:00:00.000', 9985,9985.0,'85'); +sql insert into tb8_5 values('2021-03-05 05:00:00.000', 9985,9985.0,'85'); + +sql insert into tb9_1 values('2021-03-01 01:00:00.000', 9991,9991.0,'91'); +sql insert into tb9_1 values('2021-03-02 01:00:00.000', 9991,9991.0,'91'); +sql insert into tb9_1 values('2021-03-03 01:00:00.000', 9991,9991.0,'91'); +sql insert into tb9_1 values('2021-03-04 01:00:00.000', 9991,9991.0,'91'); +sql insert into tb9_1 values('2021-03-05 01:00:00.000', 9991,9991.0,'91'); +sql insert into tb9_2 values('2021-03-01 02:00:00.000', 9992,9992.0,'92'); +sql insert into tb9_2 values('2021-03-02 02:00:00.000', 9992,9992.0,'92'); +sql insert into tb9_2 values('2021-03-03 02:00:00.000', 9992,9992.0,'92'); +sql insert into tb9_2 values('2021-03-04 02:00:00.000', 9992,9992.0,'92'); +sql insert into tb9_2 values('2021-03-05 02:00:00.000', 9992,9992.0,'92'); +sql insert into tb9_3 values('2021-03-01 03:00:00.000', 9993,9993.0,'93'); +sql insert into tb9_3 values('2021-03-02 03:00:00.000', 9993,9993.0,'93'); +sql insert into tb9_3 values('2021-03-03 03:00:00.000', 9993,9993.0,'93'); +sql insert into tb9_3 values('2021-03-04 03:00:00.000', 9993,9993.0,'93'); +sql insert into tb9_3 values('2021-03-05 03:00:00.000', 9993,9993.0,'93'); +sql insert into tb9_4 values('2021-03-01 04:00:00.000', 9994,9994.0,'94'); +sql insert into tb9_4 values('2021-03-02 04:00:00.000', 9994,9994.0,'94'); +sql insert into tb9_4 values('2021-03-03 04:00:00.000', 9994,9994.0,'94'); +sql insert into tb9_4 values('2021-03-04 04:00:00.000', 9994,9994.0,'94'); +sql insert into tb9_4 values('2021-03-05 04:00:00.000', 9994,9994.0,'94'); +sql insert into tb9_5 values('2021-03-01 05:00:00.000', 9995,9995.0,'95'); +sql insert into tb9_5 values('2021-03-02 05:00:00.000', 9995,9995.0,'95'); +sql insert into tb9_5 values('2021-03-03 05:00:00.000', 9995,9995.0,'95'); +sql insert into tb9_5 values('2021-03-04 05:00:00.000', 9995,9995.0,'95'); +sql insert into tb9_5 values('2021-03-05 05:00:00.000', 9995,9995.0,'95'); + +sql insert into tba_1 values('2021-03-01 01:00:00.000', 99101,99101.0,'a1'); +sql insert into tba_1 values('2021-03-02 01:00:00.000', 99101,99101.0,'a1'); +sql insert into tba_1 values('2021-03-03 01:00:00.000', 99101,99101.0,'a1'); +sql insert into tba_1 values('2021-03-04 01:00:00.000', 99101,99101.0,'a1'); +sql insert into tba_1 values('2021-03-05 01:00:00.000', 99101,99101.0,'a1'); +sql insert into tba_2 values('2021-03-01 02:00:00.000', 99102,99102.0,'a2'); +sql insert into tba_2 values('2021-03-02 02:00:00.000', 99102,99102.0,'a2'); +sql insert into tba_2 values('2021-03-03 02:00:00.000', 99102,99102.0,'a2'); +sql insert into tba_2 values('2021-03-04 02:00:00.000', 99102,99102.0,'a2'); +sql insert into tba_2 values('2021-03-05 02:00:00.000', 99102,99102.0,'a2'); +sql insert into tba_3 values('2021-03-01 03:00:00.000', 99103,99103.0,'a3'); +sql insert into tba_3 values('2021-03-02 03:00:00.000', 99103,99103.0,'a3'); +sql insert into tba_3 values('2021-03-03 03:00:00.000', 99103,99103.0,'a3'); +sql insert into tba_3 values('2021-03-04 03:00:00.000', 99103,99103.0,'a3'); +sql insert into tba_3 values('2021-03-05 03:00:00.000', 99103,99103.0,'a3'); +sql insert into tba_4 values('2021-03-01 04:00:00.000', 99104,99104.0,'a4'); +sql insert into tba_4 values('2021-03-02 04:00:00.000', 99104,99104.0,'a4'); +sql insert into tba_4 values('2021-03-03 04:00:00.000', 99104,99104.0,'a4'); +sql insert into tba_4 values('2021-03-04 04:00:00.000', 99104,99104.0,'a4'); +sql insert into tba_4 values('2021-03-05 04:00:00.000', 99104,99104.0,'a4'); +sql insert into tba_5 values('2021-03-01 05:00:00.000', 99105,99105.0,'a5'); +sql insert into tba_5 values('2021-03-02 05:00:00.000', 99105,99105.0,'a5'); +sql insert into tba_5 values('2021-03-03 05:00:00.000', 99105,99105.0,'a5'); +sql insert into tba_5 values('2021-03-04 05:00:00.000', 99105,99105.0,'a5'); +sql insert into tba_5 values('2021-03-05 05:00:00.000', 99105,99105.0,'a5'); + +sql insert into tbb_1 values('2021-03-01 01:00:00.000', 99111,99111.0,'b1'); +sql insert into tbb_1 values('2021-03-02 01:00:00.000', 99111,99111.0,'b1'); +sql insert into tbb_1 values('2021-03-03 01:00:00.000', 99111,99111.0,'b1'); +sql insert into tbb_1 values('2021-03-04 01:00:00.000', 99111,99111.0,'b1'); +sql insert into tbb_1 values('2021-03-05 01:00:00.000', 99111,99111.0,'b1'); +sql insert into tbb_2 values('2021-03-01 02:00:00.000', 99112,99112.0,'b2'); +sql insert into tbb_2 values('2021-03-02 02:00:00.000', 99112,99112.0,'b2'); +sql insert into tbb_2 values('2021-03-03 02:00:00.000', 99112,99112.0,'b2'); +sql insert into tbb_2 values('2021-03-04 02:00:00.000', 99112,99112.0,'b2'); +sql insert into tbb_2 values('2021-03-05 02:00:00.000', 99112,99112.0,'b2'); +sql insert into tbb_3 values('2021-03-01 03:00:00.000', 99113,99113.0,'b3'); +sql insert into tbb_3 values('2021-03-02 03:00:00.000', 99113,99113.0,'b3'); +sql insert into tbb_3 values('2021-03-03 03:00:00.000', 99113,99113.0,'b3'); +sql insert into tbb_3 values('2021-03-04 03:00:00.000', 99113,99113.0,'b3'); +sql insert into tbb_3 values('2021-03-05 03:00:00.000', 99113,99113.0,'b3'); +sql insert into tbb_4 values('2021-03-01 04:00:00.000', 99114,99114.0,'b4'); +sql insert into tbb_4 values('2021-03-02 04:00:00.000', 99114,99114.0,'b4'); +sql insert into tbb_4 values('2021-03-03 04:00:00.000', 99114,99114.0,'b4'); +sql insert into tbb_4 values('2021-03-04 04:00:00.000', 99114,99114.0,'b4'); +sql insert into tbb_4 values('2021-03-05 04:00:00.000', 99114,99114.0,'b4'); +sql insert into tbb_5 values('2021-03-01 05:00:00.000', 99115,99115.0,'b5'); +sql insert into tbb_5 values('2021-03-02 05:00:00.000', 99115,99115.0,'b5'); +sql insert into tbb_5 values('2021-03-03 05:00:00.000', 99115,99115.0,'b5'); +sql insert into tbb_5 values('2021-03-04 05:00:00.000', 99115,99115.0,'b5'); +sql insert into tbb_5 values('2021-03-05 05:00:00.000', 99115,99115.0,'b5'); + + +sql select * from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi +if $data19 != @21-03-02 01:00:00.000@ then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi +if $data29 != @21-03-03 01:00:00.000@ then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi +if $data39 != @21-03-04 01:00:00.000@ then + return -1 +endi + + + + +sql select * from st0, st1 where st0.ts=st1.ts and st0.id2=st1.id2; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi +if $data19 != @21-03-02 01:00:00.000@ then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi +if $data29 != @21-03-03 01:00:00.000@ then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi +if $data39 != @21-03-04 01:00:00.000@ then + return -1 +endi + + + + +sql select * from st0, st1 where st0.id3=st1.id3 and st1.ts=st0.ts; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi +if $data19 != @21-03-02 01:00:00.000@ then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi +if $data29 != @21-03-03 01:00:00.000@ then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi +if $data39 != @21-03-04 01:00:00.000@ then + return -1 +endi + + + + + +sql select * from st0, st1 where st1.id5=st0.id5 and st0.ts=st1.ts; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi +if $data19 != @21-03-02 01:00:00.000@ then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi +if $data29 != @21-03-03 01:00:00.000@ then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi +if $data39 != @21-03-04 01:00:00.000@ then + return -1 +endi + + + + +sql select st0.* from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi + + + + +sql select st0.* from st0, st1 where st0.ts=st1.ts and st1.id2=st0.id2; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi + + + + + +sql select st0.* from st0, st1 where st0.id3=st1.id3 and st1.ts=st0.ts; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9901 then + return -1 +endi +if $data22 != 9901.000000000 then + return -1 +endi +if $data23 != 01 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9901 then + return -1 +endi +if $data32 != 9901.000000000 then + return -1 +endi +if $data33 != 01 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi + + + + +sql select st1.* from st0, st1 where st1.id5=st0.id5 and st0.ts=st1.ts; + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9911 then + return -1 +endi +if $data02 != 9911.000000000 then + return -1 +endi +if $data03 != 11 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + print $data07 + return -1 +endi +if $data08 != 3 then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9911 then + return -1 +endi +if $data12 != 9911.000000000 then + return -1 +endi +if $data13 != 11 then + return -1 +endi +if $data14 != 0 then + return -1 +endi +if $data15 != 1 then + return -1 +endi +if $data16 != 2.000000000 then + return -1 +endi +if $data17 != 1 then + return -1 +endi +if $data18 != 3 then + return -1 +endi + + + +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != 9911 then + return -1 +endi +if $data22 != 9911.000000000 then + return -1 +endi +if $data23 != 11 then + return -1 +endi +if $data24 != 0 then + return -1 +endi +if $data25 != 1 then + return -1 +endi +if $data26 != 2.000000000 then + return -1 +endi +if $data27 != 1 then + return -1 +endi +if $data28 != 3 then + return -1 +endi + + +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != 9911 then + return -1 +endi +if $data32 != 9911.000000000 then + return -1 +endi +if $data33 != 11 then + return -1 +endi +if $data34 != 0 then + return -1 +endi +if $data35 != 1 then + return -1 +endi +if $data36 != 2.000000000 then + return -1 +endi +if $data37 != 1 then + return -1 +endi +if $data38 != 3 then + return -1 +endi + + +sql select st0.f1,st1.f1 from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1; + +if $rows != 25 then + return -1 +endi + +if $data00 != 9901 then + return -1 +endi +if $data01 != 9911 then + return -1 +endi +if $data10 != 9901 then + return -1 +endi +if $data11 != 9911 then + return -1 +endi +if $data20 != 9901 then + return -1 +endi +if $data21 != 9911 then + return -1 +endi +if $data30 != 9901 then + return -1 +endi +if $data31 != 9911 then + return -1 +endi + + + + +sql select st0.ts,st1.ts from st0, st1 where st0.ts=st1.ts and st1.id2=st0.id2; + + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data20 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data21 != @21-03-03 01:00:00.000@ then + return -1 +endi +if $data30 != @21-03-04 01:00:00.000@ then + return -1 +endi +if $data31 != @21-03-04 01:00:00.000@ then + return -1 +endi + + + +sql select st1.ts,st0.ts,st0.id3,st1.id3,st0.f3,st1.f3 from st0, st1 where st0.id3=st1.id3 and st1.ts=st0.ts; + + +if $rows != 25 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data02 != 2.000000000 then + return -1 +endi +if $data03 != 2.000000000 then + return -1 +endi +if $data04 != 01 then + return -1 +endi +if $data05 != 11 then + return -1 +endi + +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data02 != 2.000000000 then + return -1 +endi +if $data03 != 2.000000000 then + return -1 +endi +if $data04 != 01 then + return -1 +endi +if $data05 != 11 then + return -1 +endi + + + +sql select st0.ts,st0.f2,st1.f3,st1.f2,st0.f3 from st0, st1 where st1.id5=st0.id5 and st0.ts=st1.ts; +if $rows != 25 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901.000000000 then + return -1 +endi +if $data02 != 11 then + return -1 +endi +if $data03 != 9911.000000000 then + return -1 +endi +if $data04 != 01 then + return -1 +endi +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901.000000000 then + return -1 +endi +if $data12 != 11 then + return -1 +endi +if $data13 != 9911.000000000 then + return -1 +endi +if $data14 != 01 then + return -1 +endi + + + + +sql select last(*) from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 interval(10a); +if $rows != 25 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data02 != 9901 then + return -1 +endi +if $data03 != 9901.000000000 then + return -1 +endi +if $data04 != 01 then + return -1 +endi +if $data05 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data06 != 9911 then + return -1 +endi +if $data07 != 9911.000000000 then + return -1 +endi +if $data08 != 11 then + return -1 +endi +if $data10 != @21-03-01 02:00:00.000@ then + return -1 +endi +if $data11 != @21-03-01 02:00:00.000@ then + return -1 +endi +if $data12 != 9902 then + return -1 +endi +if $data13 != 9902.000000000 then + return -1 +endi +if $data14 != 02 then + return -1 +endi +if $data15 != @21-03-01 02:00:00.000@ then + return -1 +endi +if $data16 != 9912 then + return -1 +endi +if $data17 != 9912.000000000 then + return -1 +endi +if $data18 != 12 then + return -1 +endi + + + +sql select last(*) from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 interval(1d) sliding(1d); +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 00:00:00.000@ then + return -1 +endi +if $data01 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data02 != 9905 then + return -1 +endi +if $data03 != 9905.000000000 then + return -1 +endi +if $data04 != 05 then + return -1 +endi +if $data05 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data06 != 9915 then + return -1 +endi +if $data07 != 9915.000000000 then + return -1 +endi +if $data08 != 15 then + return -1 +endi +if $data10 != @21-03-02 00:00:00.000@ then + return -1 +endi +if $data11 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data12 != 9905 then + return -1 +endi +if $data13 != 9905.000000000 then + return -1 +endi +if $data14 != 05 then + return -1 +endi +if $data15 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data16 != 9915 then + return -1 +endi +if $data17 != 9915.000000000 then + return -1 +endi +if $data18 != 15 then + return -1 +endi + + + +sql select st0.*,st1.* from st0, st1 where st1.id1=st0.id1 and st0.ts=st1.ts and st1.ts=st0.ts and st0.id1=st1.id1; +if $rows != 25 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + + + + + +sql select st0.ts,* from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 order by st0.ts; + +if $rows != 25 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data02 != 9901 then + return -1 +endi +if $data03 != 9901.000000000 then + return -1 +endi +if $data04 != 01 then + return -1 +endi +if $data05 != 0 then + return -1 +endi +if $data06 != 1 then + return -1 +endi +if $data07 != 2.000000000 then + return -1 +endi +if $data08 != 1 then + return -1 +endi +if $data09 != 3 then + return -1 +endi + + + + + +sql select st0.*,st1.* from st0, st1 where st1.id1=st0.id1 and st0.ts=st1.ts and st1.ts=st0.ts and st0.id1=st1.id1 order by st0.ts limit 5 offset 5 +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + print $data00 + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + + + +sql select top(st1.f1, 5) from st0, st1 where st1.id1=st0.id1 and st0.ts=st1.ts and st1.ts=st0.ts and st0.id1=st1.id1; +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data01 != 9915 then + return -1 +endi +if $data10 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data11 != 9915 then + return -1 +endi +if $data20 != @21-03-03 05:00:00.000@ then + return -1 +endi +if $data21 != 9915 then + return -1 +endi +if $data30 != @21-03-04 05:00:00.000@ then + return -1 +endi +if $data31 != 9915 then + return -1 +endi +if $data40 != @21-03-05 05:00:00.000@ then + return -1 +endi +if $data41 != 9915 then + return -1 +endi + + + + + +sql select top(st0.f1,5) from st0, st1 where st1.id1=st0.id1 and st0.ts=st1.ts and st1.ts=st0.ts and st0.id1=st1.id1; +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data01 != 9905 then + return -1 +endi +if $data10 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data11 != 9905 then + return -1 +endi +if $data20 != @21-03-03 05:00:00.000@ then + return -1 +endi +if $data21 != 9905 then + return -1 +endi +if $data30 != @21-03-04 05:00:00.000@ then + return -1 +endi +if $data31 != 9905 then + return -1 +endi +if $data40 != @21-03-05 05:00:00.000@ then + return -1 +endi +if $data41 != 9905 then + return -1 +endi + + +#sql select st0.*,st1.*,st2.*,st3.* from st3,st2,st1,st0 where st0.id1=st3.id1 and st3.ts=st2.ts and st2.id1=st1.id1 and st1.ts=st0.ts; +#sql select st0.*,st1.*,st2.*,st3.* from st3,st2,st1,st0 where st0.id1=st3.id1 and st3.ts=st2.ts and st2.id1=st1.id1 and st1.ts=st0.ts and st0.id1=st2.id1 and st1.ts=st2.ts; +#if $rows != 25 then +# print $rows +# return -1 +#endi +#if $data00 != @21-03-01 01:00:00.000@ then +# return -1 +#endi +#if $data01 != 9901 then +# return -1 +#endi +#if $data02 != 9901.000000000 then +# return -1 +#endi +#if $data03 != 01 then +# return -1 +#endi +#if $data04 != 0 then +# return -1 +#endi +#if $data05 != 1 then +# return -1 +#endi +#if $data06 != 2.000000000 then +# return -1 +#endi +#if $data07 != 1 then +# return -1 +#endi +#if $data08 != 3 then +# return -1 +#endi +#if $data09 != @21-03-01 01:00:00.000@ then +# return -1 +#endi + + + +#sql select st0.*,st1.*,st2.*,st3.* from st3,st2,st1,st0 where st0.id1=st1.id1 and st1.ts=st0.ts and st2.id1=st3.id1 and st3.ts=st2.ts; +#sql select st0.*,st1.*,st2.*,st3.* from st3,st2,st1,st0 where st0.id1=st1.id1 and st1.ts=st0.ts and st2.id1=st3.id1 and st3.ts=st2.ts and st0.id1=st2.id1 and st0.ts=st2.ts; +#if $rows != 25 then +# return -1 +#endi +#if $data00 != @21-03-01 01:00:00.000@ then +# return -1 +#endi +#if $data01 != 9901 then +# return -1 +#endi +#if $data02 != 9901.000000000 then +# return -1 +#endi +#if $data03 != 01 then +# return -1 +#endi +#if $data04 != 0 then +# return -1 +#endi +#if $data05 != 1 then +# return -1 +#endi +#if $data06 != 2.000000000 then +# return -1 +#endi +#if $data07 != 1 then +# return -1 +#endi +#if $data08 != 3 then +# return -1 +#endi +#if $data09 != @21-03-01 01:00:00.000@ then +# return -1 +#endi + + + +sql select st0.*,st1.*,st2.*,st3.*,st4.*,st5.*,st6.*,st7.*,st8.*,st9.* from st0,st1,st2,st3,st4,st5,st6,st7,st8,st9 where st0.ts=st2.ts and st0.ts=st4.ts and st0.ts=st6.ts and st0.ts=st8.ts and st1.ts=st3.ts and st3.ts=st5.ts and st5.ts=st7.ts and st7.ts=st9.ts and st0.ts=st1.ts and st0.id1=st2.id1 and st0.id1=st4.id1 and st0.id1=st6.id1 and st0.id1=st8.id1 and st1.id1=st3.id1 and st3.id1=st5.id1 and st5.id1=st7.id1 and st7.id1=st9.id1 and st0.id1=st1.id1; +if $rows != 25 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != 0 then + return -1 +endi +if $data05 != 1 then + return -1 +endi +if $data06 != 2.000000000 then + return -1 +endi +if $data07 != 1 then + return -1 +endi +if $data08 != 3 then + return -1 +endi +if $data09 != @21-03-01 01:00:00.000@ then + return -1 +endi + + + +sql select tb0_1.*, tb1_1.* from tb0_1, tb1_1 where tb0_1.ts=tb1_1.ts; +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data05 != 9911 then + return -1 +endi +if $data06 != 9911.000000000 then + return -1 +endi +if $data07 != 11 then + return -1 +endi +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data15 != 9911 then + return -1 +endi +if $data16 != 9911.000000000 then + return -1 +endi +if $data17 != 11 then + return -1 +endi + + + +sql select tb0_1.*, tb1_1.* from tb0_1, tb1_1 where tb0_1.ts=tb1_1.ts and tb0_1.id1=tb1_1.id1; +if $rows != 5 then + return -1 +endi +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data05 != 9911 then + return -1 +endi +if $data06 != 9911.000000000 then + return -1 +endi +if $data07 != 11 then + return -1 +endi +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data15 != 9911 then + return -1 +endi +if $data16 != 9911.000000000 then + return -1 +endi +if $data17 != 11 then + return -1 +endi + + +sql select tb0_1.*, tb1_2.*,tb2_3.*,tb3_4.*,tb4_5.* from tb0_1, tb1_2, tb2_3, tb3_4, tb4_5 where tb0_1.ts=tb1_2.ts and tb0_1.ts=tb2_3.ts and tb0_1.ts=tb3_4.ts and tb0_1.ts=tb4_5.ts; +if $rows != 0 then + return -1 +endi + + + +sql select tb0_1.*, tb1_1.*,tb2_1.*,tb3_1.*,tb4_1.* from tb0_1, tb1_1, tb2_1, tb3_1, tb4_1 where tb0_1.ts=tb1_1.ts and tb0_1.ts=tb2_1.ts and tb0_1.ts=tb3_1.ts and tb0_1.ts=tb4_1.ts; + +if $rows != 5 then + return -1 +endi + +if $data00 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data01 != 9901 then + return -1 +endi +if $data02 != 9901.000000000 then + return -1 +endi +if $data03 != 01 then + return -1 +endi +if $data04 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data05 != 9911 then + return -1 +endi +if $data06 != 9911.000000000 then + return -1 +endi +if $data07 != 11 then + return -1 +endi +if $data08 != @21-03-01 01:00:00.000@ then + return -1 +endi +if $data09 != 9921 then + return -1 +endi +if $data10 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data11 != 9901 then + return -1 +endi +if $data12 != 9901.000000000 then + return -1 +endi +if $data13 != 01 then + return -1 +endi +if $data14 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data15 != 9911 then + return -1 +endi +if $data16 != 9911.000000000 then + return -1 +endi +if $data17 != 11 then + return -1 +endi +if $data18 != @21-03-02 01:00:00.000@ then + return -1 +endi +if $data19 != 9921 then + return -1 +endi + + + +sql select tb0_5.*, tb1_5.*,tb2_5.*,tb3_5.*,tb4_5.*,tb5_5.*, tb6_5.*,tb7_5.*,tb8_5.*,tb9_5.* from tb0_5, tb1_5, tb2_5, tb3_5, tb4_5,tb5_5, tb6_5, tb7_5, tb8_5, tb9_5 where tb9_5.ts=tb8_5.ts and tb8_5.ts=tb7_5.ts and tb7_5.ts=tb6_5.ts and tb6_5.ts=tb5_5.ts and tb5_5.ts=tb4_5.ts and tb4_5.ts=tb3_5.ts and tb3_5.ts=tb2_5.ts and tb2_5.ts=tb1_5.ts and tb1_5.ts=tb0_5.ts; + +if $rows != 5 then + return -1 +endi + +if $data00 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data01 != 9905 then + return -1 +endi +if $data02 != 9905.000000000 then + return -1 +endi +if $data03 != 05 then + return -1 +endi +if $data04 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data05 != 9915 then + return -1 +endi +if $data06 != 9915.000000000 then + return -1 +endi +if $data07 != 15 then + return -1 +endi +if $data08 != @21-03-01 05:00:00.000@ then + return -1 +endi +if $data09 != 9925 then + return -1 +endi +if $data10 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data11 != 9905 then + return -1 +endi +if $data12 != 9905.000000000 then + return -1 +endi +if $data13 != 05 then + return -1 +endi +if $data14 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data15 != 9915 then + return -1 +endi +if $data16 != 9915.000000000 then + return -1 +endi +if $data17 != 15 then + return -1 +endi +if $data18 != @21-03-02 05:00:00.000@ then + return -1 +endi +if $data19 != 9925 then + return -1 +endi + + +sql_error select tb0_1.*, tb1_1.* from tb0_1, tb1_1 where tb0_1.f1=tb1_1.f1; +sql_error select tb0_1.*, tb1_1.* from tb0_1, tb1_1 where tb0_1.ts=tb1_1.ts and tb0_1.id1=tb1_1.id2; +sql_error select tb0_5.*, tb1_5.*,tb2_5.*,tb3_5.*,tb4_5.*,tb5_5.*, tb6_5.*,tb7_5.*,tb8_5.*,tb9_5.*,tba_5.* from tb0_5, tb1_5, tb2_5, tb3_5, tb4_5,tb5_5, tb6_5, tb7_5, tb8_5, tb9_5, tba_5 where tb9_5.ts=tb8_5.ts and tb8_5.ts=tb7_5.ts and tb7_5.ts=tb6_5.ts and tb6_5.ts=tb5_5.ts and tb5_5.ts=tb4_5.ts and tb4_5.ts=tb3_5.ts and tb3_5.ts=tb2_5.ts and tb2_5.ts=tb1_5.ts and tb1_5.ts=tb0_5.ts and tb0_5.ts=tba_5.ts; + +sql_error select * from st0, st1 where st0.ts=st1.ts; +sql_error select * from st0, st1 where st0.id1=st1.id1; +sql_error select * from st0, st1 where st0.f1=st1.f1 and st0.id1=st1.id1; +sql_error select * from st0, st1, st2, st3 where st0.id1=st1.id1 and st2.id1=st3.id1 and st0.ts=st1.ts and st1.ts=st2.ts and st2.ts=st3.ts; +sql_error select * from st0, st1, st2 where st0.id1=st1.id1; +sql_error select * from st0, st1 where st0.id1=st1.id1 and st0.id2=st1.id3; +sql_error select * from st0, st1 where st0.id1=st1.id1 or st0.ts=st1.ts; +sql_error select * from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 or st0.id2=st1.id2; +sql_error select * from st0, st1, st2 where st0.ts=st1.ts and st0.id1=st1.id1; +sql_error select * from st0, st1 where st0.id1=st1.ts and st0.ts=st1.id1; +sql_error select * from st0, st1 where st0.id1=st1.id2 and st0.ts=st1.ts; +sql_error select * from st0, st1 where st1.id4=st0.id4 and st1.ts=st0.ts; +sql_error select * from st0, st1 where st0.id1=st1.id2 and st1.ts=st0.ts; +sql_error select * from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 interval 10a; +sql_error select last(*) from st0, st1 where st0.ts=st1.ts and st0.id1=st1.id1 group by f1; +sql_error select st0.*,st1.*,st2.*,st3.*,st4.*,st5.*,st6.*,st7.*,st8.*,st9.* from st0,st1,st2,st3,st4,st5,st6,st7,st8,st9 where st0.ts=st2.ts and st0.ts=st4.ts and st0.ts=st6.ts and st0.ts=st8.ts and st1.ts=st3.ts and st3.ts=st5.ts and st5.ts=st7.ts and st7.ts=st9.ts and st0.id1=st2.id1 and st0.id1=st4.id1 and st0.id1=st6.id1 and st0.id1=st8.id1 and st1.id1=st3.id1 and st3.id1=st5.id1 and st5.id1=st7.id1 and st7.id1=st9.id1; +sql_error select st0.*,st1.*,st2.*,st3.*,st4.*,st5.*,st6.*,st7.*,st8.*,st9.* from st0,st1,st2,st3,st4,st5,st6,st7,st8,st9,sta where st0.ts=st2.ts and st0.ts=st4.ts and st0.ts=st6.ts and st0.ts=st8.ts and st1.ts=st3.ts and st3.ts=st5.ts and st5.ts=st7.ts and st7.ts=st9.ts and st0.ts=st1.ts and st0.id1=st2.id1 and st0.id1=st4.id1 and st0.id1=st6.id1 and st0.id1=st8.id1 and st1.id1=st3.id1 and st3.id1=st5.id1 and st5.id1=st7.id1 and st7.id1=st9.id1 and st0.id1=st1.id1 and st0.id1=sta.id1 and st0.ts=sta.ts; + + + + + + + +system sh/exec.sh -n dnode1 -s stop -x SIGINT diff --git a/tests/test-all.sh b/tests/test-all.sh index dcc2b61f43..1f9c76daf4 100755 --- a/tests/test-all.sh +++ b/tests/test-all.sh @@ -29,7 +29,25 @@ function dohavecore(){ proc=`echo $corefile|cut -d "_" -f3` if [ -n "$corefile" ];then echo 'taosd or taos has generated core' - tar -zcPf $corepath'taos_'`date "+%Y_%m_%d_%H_%M_%S"`.tar.gz /usr/local/taos/ + if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]] && [[ $1 == 1 ]]; then + cd ../../../ + tar -zcPf $corepath'taos_'`date "+%Y_%m_%d_%H_%M_%S"`.tar.gz debug/build/bin/taosd debug/build/bin/tsim debug/build/lib/libtaos*so* + if [[ $2 == 1 ]];then + cp -r sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S"` + rm -rf sim/case.log + else + cd community + cp -r sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S" ` + rm -rf sim/case.log + fi + else + cd ../../ + if [[ $1 == 1 ]];then + tar -zcPf $corepath'taos_'`date "+%Y_%m_%d_%H_%M_%S"`.tar.gz debug/build/bin/taosd debug/build/bin/tsim debug/build/lib/libtaos*so* + cp -r sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S" ` + rm -rf sim/case.log + fi + fi if [[ $1 == 1 ]];then echo '\n'|gdb /usr/local/taos/bin/$proc $core_file -ex "bt 10" -ex quit exit 8 @@ -79,32 +97,39 @@ function runSimCaseOneByOnefq { date +%F\ %T | tee -a out.log if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]]; then echo -n $case - ./test.sh -f $case > /dev/null 2>&1 && \ + ./test.sh -f $case > ../../../sim/case.log 2>&1 && \ ( grep -q 'script.*'$case'.*failed.*, err.*lineNum' ../../../sim/tsim/log/taoslog0.0 && echo -e "${RED} failed${NC}" | tee -a out.log || echo -e "${GREEN} success${NC}" | tee -a out.log )|| \ ( grep -q 'script.*success.*m$' ../../../sim/tsim/log/taoslog0.0 && echo -e "${GREEN} success${NC}" | tee -a out.log ) || \ - echo -e "${RED} failed${NC}" | tee -a out.log + ( echo -e "${RED} failed${NC}" | tee -a out.log && echo '=====================log=====================' && cat ../../../sim/case.log ) else echo -n $case - ./test.sh -f $case > /dev/null 2>&1 && \ + ./test.sh -f $case > ../../sim/case.log 2>&1 && \ ( grep -q 'script.*'$case'.*failed.*, err.*lineNum' ../../sim/tsim/log/taoslog0.0 && echo -e "${RED} failed${NC}" | tee -a out.log || echo -e "${GREEN} success${NC}" | tee -a out.log )|| \ ( grep -q 'script.*success.*m$' ../../sim/tsim/log/taoslog0.0 && echo -e "${GREEN} success${NC}" | tee -a out.log ) || \ - echo -e "${RED} failed${NC}" | tee -a out.log + ( echo -e "${RED} failed${NC}" | tee -a out.log && echo '=====================log=====================' && cat ../../sim/case.log ) fi out_log=`tail -1 out.log ` if [[ $out_log =~ 'failed' ]];then if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]]; then cp -r ../../../sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S"` + rm -rf ../../../sim/case.log else cp -r ../../sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S" ` + rm -rf ../../sim/case.log + fi + dohavecore $2 1 + if [[ $2 == 1 ]];then + exit 8 fi - exit 8 fi end_time=`date +%s` echo execution time of $case was `expr $end_time - $start_time`s. | tee -a out.log - dohavecore $2 + dohavecore $2 1 fi done + rm -rf ../../../sim/case.log + rm -rf ../../sim/case.log } function runPyCaseOneByOne { @@ -158,31 +183,39 @@ function runPyCaseOneByOnefq() { start_time=`date +%s` date +%F\ %T | tee -a pytest-out.log echo -n $case - $line > /dev/null 2>&1 && \ + $line > ../../sim/case.log 2>&1 && \ echo -e "${GREEN} success${NC}" | tee -a pytest-out.log || \ - echo -e "${RED} failed${NC}" | tee -a pytest-out.log + echo -e "${RED} failed${NC}" | tee -a pytest-out.log end_time=`date +%s` out_log=`tail -1 pytest-out.log ` if [[ $out_log =~ 'failed' ]];then cp -r ../../sim ~/sim_`date "+%Y_%m_%d_%H:%M:%S" ` - exit 8 + echo '=====================log===================== ' + cat ../../sim/case.log + rm -rf ../../sim/case.log + dohavecore $2 2 + if [[ $2 == 1 ]];then + exit 8 + fi fi echo execution time of $case was `expr $end_time - $start_time`s. | tee -a pytest-out.log else $line > /dev/null 2>&1 fi - dohavecore $2 + dohavecore $2 2 fi done + rm -rf ../../sim/case.log } totalFailed=0 totalPyFailed=0 totalJDBCFailed=0 totalUnitFailed=0 +totalExampleFailed=0 corepath=`grep -oP '.*(?=core_)' /proc/sys/kernel/core_pattern||grep -oP '.*(?=core-)' /proc/sys/kernel/core_pattern` -if [ "$2" != "jdbc" ] && [ "$2" != "python" ] && [ "$2" != "unit" ]; then +if [ "$2" != "jdbc" ] && [ "$2" != "python" ] && [ "$2" != "unit" ] && [ "$2" != "example" ]; then echo "### run TSIM test case ###" cd $tests_dir/script @@ -197,15 +230,15 @@ if [ "$2" != "jdbc" ] && [ "$2" != "python" ] && [ "$2" != "unit" ]; then echo "### run TSIM b1 test ###" runSimCaseOneByOnefq b1 0 runSimCaseOneByOnefq b4 0 - runSimCaseOneByOnefq b5 0 - runSimCaseOneByOnefq b6 0 runSimCaseOneByOnefq b7 0 elif [ "$1" == "b2" ]; then echo "### run TSIM b2 test ###" runSimCaseOneByOnefq b2 0 + runSimCaseOneByOnefq b5 0 elif [ "$1" == "b3" ]; then echo "### run TSIM b3 test ###" runSimCaseOneByOnefq b3 0 + runSimCaseOneByOnefq b6 0 elif [ "$1" == "b1fq" ]; then echo "### run TSIM b1 test ###" runSimCaseOneByOnefq b1 1 @@ -251,7 +284,7 @@ if [ "$2" != "jdbc" ] && [ "$2" != "python" ] && [ "$2" != "unit" ]; then fi fi -if [ "$2" != "sim" ] && [ "$2" != "jdbc" ] && [ "$2" != "unit" ]; then +if [ "$2" != "sim" ] && [ "$2" != "jdbc" ] && [ "$2" != "unit" ] && [ "$2" != "example" ]; then echo "### run Python test case ###" cd $tests_dir @@ -320,7 +353,7 @@ if [ "$2" != "sim" ] && [ "$2" != "jdbc" ] && [ "$2" != "unit" ]; then fi -if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "unit" ] && [ "$1" == "full" ]; then +if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "unit" ] && [ "$2" != "example" ] && [ "$1" == "full" ]; then echo "### run JDBC test cases ###" cd $tests_dir @@ -364,7 +397,7 @@ if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "unit" ] && [ "$1" == dohavecore 1 fi -if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "jdbc" ] && [ "$1" == "full" ]; then +if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "jdbc" ] && [ "$2" != "example" ] && [ "$1" == "full" ]; then echo "### run Unit tests ###" stopTaosd @@ -400,5 +433,80 @@ if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "jdbc" ] && [ "$1" == dohavecore 1 fi +if [ "$2" != "sim" ] && [ "$2" != "python" ] && [ "$2" != "jdbc" ] && [ "$2" != "unit" ] && [ "$1" == "full" ]; then + echo "### run Example tests ###" -exit $(($totalFailed + $totalPyFailed + $totalJDBCFailed + $totalUnitFailed)) + stopTaosd + cd $tests_dir + + if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]]; then + cd ../../ + else + cd ../ + fi + + pwd + cd debug/build/bin + rm -rf /var/lib/taos/* + nohup ./taosd -c /etc/taos/ > /dev/null 2>&1 & + echo "sleeping for 30 seconds" + #sleep 30 + + cd $tests_dir + echo "current dir: " + pwd + cd examples/c + echo "building applications" + make > /dev/null + totalExamplePass=0 + + echo "Running tests" + ./apitest > /dev/null 2>&1 + if [ $? != "0" ]; then + echo "prepare failed" + totalExampleFailed=`expr $totalExampleFailed + 1` + else + echo "prepare pass" + totalExamplePass=`expr $totalExamplePass + 1` + fi + + ./prepare 127.0.0.1 > /dev/null 2>&1 + if [ $? != "0" ]; then + echo "prepare failed" + totalExampleFailed=`expr $totalExampleFailed + 1` + else + echo "prepare pass" + totalExamplePass=`expr $totalExamplePass + 1` + fi + + ./subscribe -test > /dev/null 2>&1 + if [ $? != "0" ]; then + echo "prepare failed" + totalExampleFailed=`expr $totalExampleFailed + 1` + else + echo "prepare pass" + totalExamplePass=`expr $totalExamplePass + 1` + fi + + yes |./asyncdemo 127.0.0.1 test 1000 10 > /dev/null 2>&1 + if [ $? != "0" ]; then + echo "prepare failed" + totalExampleFailed=`expr $totalExampleFailed + 1` + else + echo "prepare pass" + totalExamplePass=`expr $totalExamplePass + 1` + fi + + if [ "$totalExamplePass" -gt "0" ]; then + echo -e "\n${GREEN} ### Total $totalExamplePass examples succeed! ### ${NC}" + fi + + if [ "$totalExampleFailed" -ne "0" ]; then + echo -e "\n${RED} ### Total $totalExampleFailed examples failed! ### ${NC}" + fi + + dohavecore 1 +fi + + +exit $(($totalFailed + $totalPyFailed + $totalJDBCFailed + $totalUnitFailed + $totalExampleFailed))