diff --git a/cmake/install.inc b/cmake/install.inc
index 63764348d3..b37cf751fb 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.30.jar DESTINATION connector/jdbc)
+ INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.31.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 49cfa12119..4c37ce598c 100644
--- a/documentation20/cn/00.index/docs.md
+++ b/documentation20/cn/00.index/docs.md
@@ -81,7 +81,7 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台,专
## [与其他工具的连接](/connections)
* [Grafana](/connections#grafana):获取并可视化保存在TDengine的数据
-* [Matlab](/connections#matlab):通过配置Matlab的JDBC数据源访问保存在TDengine的数据
+* [MATLAB](/connections#matlab):通过配置MATLAB的JDBC数据源访问保存在TDengine的数据
* [R](/connections#r):通过配置R的JDBC数据源访问保存在TDengine的数据
* [IDEA Database](https://www.taosdata.com/blog/2020/08/27/1767.html):通过IDEA 数据库管理工具可视化使用 TDengine
diff --git a/documentation20/cn/01.evaluation/docs.md b/documentation20/cn/01.evaluation/docs.md
index 0ae2106ff2..7f70ccec56 100644
--- a/documentation20/cn/01.evaluation/docs.md
+++ b/documentation20/cn/01.evaluation/docs.md
@@ -9,8 +9,8 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的
* __10倍以上的性能提升__:定义了创新的数据存储结构,单核每秒能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快十倍以上。
* __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10。
* __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融为一体,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。
-* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。即席查询可通过Shell, Python, R, Matlab随时进行。
-* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, HiveMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。
+* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。即席查询可通过Shell, Python, R, MATLAB随时进行。
+* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, HiveMQ, Prometheus, MATLAB, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。
* __零运维成本、零学习成本__:安装集群简单快捷,无需分库分表,实时备份。类似标准SQL,支持RESTful, 支持Python/Java/C/C++/C#/Go/Node.js, 与MySQL相似,零学习成本。
采用TDengine,可将典型的物联网、车联网、工业互联网大数据平台的总拥有成本大幅降低。但需要指出的是,因充分利用了物联网时序数据的特点,它无法用来处理网络爬虫、微博、微信、电商、ERP、CRM等通用型数据。
diff --git a/documentation20/cn/08.connector/docs.md b/documentation20/cn/08.connector/docs.md
index 991c3ce6ce..c74d1ebc3e 100644
--- a/documentation20/cn/08.connector/docs.md
+++ b/documentation20/cn/08.connector/docs.md
@@ -56,7 +56,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
*taos.tar.gz*:应用驱动安装包
*driver*:TDengine应用驱动driver
*connector*: 各种编程语言连接器(go/grafanaplugin/nodejs/python/JDBC)
- *examples*: 各种编程语言的示例程序(c/C#/go/JDBC/matlab/python/R)
+ *examples*: 各种编程语言的示例程序(c/C#/go/JDBC/MATLAB/python/R)
运行install_client.sh进行安装
diff --git a/documentation20/cn/09.connections/docs.md b/documentation20/cn/09.connections/docs.md
index 6a2ead3766..d1dba5a736 100644
--- a/documentation20/cn/09.connections/docs.md
+++ b/documentation20/cn/09.connections/docs.md
@@ -75,17 +75,17 @@ sudo cp -rf /usr/local/taos/connector/grafanaplugin /var/lib/grafana/plugins/tde

-## Matlab
+## MATLAB
-MatLab可以通过安装包内提供的JDBC Driver直接连接到TDengine获取数据到本地工作空间。
+MATLAB可以通过安装包内提供的JDBC Driver直接连接到TDengine获取数据到本地工作空间。
-### MatLab的JDBC接口适配
+### MATLAB的JDBC接口适配
-MatLab的适配有下面几个步骤,下面以Windows10上适配MatLab2017a为例:
+MATLAB的适配有下面几个步骤,下面以Windows10上适配MATLAB2017a为例:
- 将TDengine安装包内的驱动程序JDBCDriver-1.0.0-dist.jar拷贝到${matlab_root}\MATLAB\R2017a\java\jar\toolbox
- 将TDengine安装包内的taos.lib文件拷贝至${matlab_ root _dir}\MATLAB\R2017a\lib\win64
-- 将新添加的驱动jar包加入MatLab的classpath。在${matlab_ root _dir}\MATLAB\R2017a\toolbox\local\classpath.txt文件中添加下面一行
+- 将新添加的驱动jar包加入MATLAB的classpath。在${matlab_ root _dir}\MATLAB\R2017a\toolbox\local\classpath.txt文件中添加下面一行
```
$matlabroot/java/jar/toolbox/JDBCDriver-1.0.0-dist.jar
@@ -96,9 +96,9 @@ $matlabroot/java/jar/toolbox/JDBCDriver-1.0.0-dist.jar
C:\Windows\System32
```
-### 在MatLab中连接TDengine获取数据
+### 在MATLAB中连接TDengine获取数据
-在成功进行了上述配置后,打开MatLab。
+在成功进行了上述配置后,打开MATLAB。
- 创建一个连接:
diff --git a/documentation20/cn/11.administrator/docs.md b/documentation20/cn/11.administrator/docs.md
index 9e1f627709..ae13a36f76 100644
--- a/documentation20/cn/11.administrator/docs.md
+++ b/documentation20/cn/11.administrator/docs.md
@@ -116,20 +116,22 @@ taosd -C
**注意:**对于端口,TDengine会使用从serverPort起13个连续的TCP和UDP端口号,请务必在防火墙打开。因此如果是缺省配置,需要打开从6030到6042共13个端口,而且必须TCP和UDP都打开。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port))
-不同应用场景的数据往往具有不同的数据特征,比如保留天数、副本数、采集频次、记录大小、采集点的数量、压缩等都可完全不同。为获得在存储上的最高效率,TDengine提供如下存储相关的系统配置参数:
+不同应用场景的数据往往具有不同的数据特征,比如保留天数、副本数、采集频次、记录大小、采集点的数量、压缩等都可完全不同。为获得在存储上的最高效率,TDengine提供如下存储相关的系统配置参数(既可以作为 create database 指令的参数,也可以写在 taos.cfg 配置文件中用来设定创建新数据库时所采用的默认值):
-- days:一个数据文件存储数据的时间跨度,单位为天,默认值:10。
-- keep:数据库中数据保留的天数,单位为天,默认值:3650。(可通过 alter database 修改)
-- minRows:文件块中记录的最小条数,单位为条,默认值:100。
-- maxRows:文件块中记录的最大条数,单位为条,默认值:4096。
-- comp:文件压缩标志位,0:关闭;1:一阶段压缩;2:两阶段压缩。默认值:2。(可通过 alter database 修改)
-- walLevel:WAL级别。1:写wal,但不执行fsync;2:写wal, 而且执行fsync。默认值:1。
-- fsync:当wal设置为2时,执行fsync的周期。设置为0,表示每次写入,立即执行fsync。单位为毫秒,默认值:3000。
-- cache:内存块的大小,单位为兆字节(MB),默认值:16。
+- days:一个数据文件存储数据的时间跨度。单位为天,默认值:10。
+- keep:数据库中数据保留的天数。单位为天,默认值:3650。(可通过 alter database 修改)
+- minRows:文件块中记录的最小条数。单位为条,默认值:100。
+- maxRows:文件块中记录的最大条数。单位为条,默认值:4096。
+- comp:文件压缩标志位。0:关闭;1:一阶段压缩;2:两阶段压缩。默认值:2。(可通过 alter database 修改)
+- wal:WAL级别。1:写wal,但不执行fsync;2:写wal, 而且执行fsync。默认值:1。(在 taos.cfg 中参数名需要写作 walLevel)(可通过 alter database 修改)
+- fsync:当wal设置为2时,执行fsync的周期。设置为0,表示每次写入,立即执行fsync。单位为毫秒,默认值:3000。(可通过 alter database 修改)
+- cache:内存块的大小。单位为兆字节(MB),默认值:16。
- blocks:每个VNODE(TSDB)中有多少cache大小的内存块。因此一个VNODE的用的内存大小粗略为(cache * blocks)。单位为块,默认值:4。(可通过 alter database 修改)
-- replica:副本个数,取值范围:1-3。单位为个,默认值:1。(可通过 alter database 修改)
-- precision:时间戳精度标识,ms表示毫秒,us表示微秒。默认值:ms。
-- cacheLast:是否在内存中缓存子表的最近数据,0:关闭;1:缓存子表最近一行数据;2:缓存子表每一列的最近的非NULL值,3:同时打开缓存最近行和列功能,默认值:0。(可通过 alter database 修改)(从 2.0.11 版本开始支持此参数)
+- replica:副本个数。取值范围:1-3,单位为个,默认值:1。(可通过 alter database 修改)
+- quorum:多副本环境下指令执行的确认数要求。取值范围:1、2,单位为个,默认值:1。(可通过 alter database 修改)
+- precision:时间戳精度标识。ms表示毫秒,us表示微秒,默认值:ms。(2.1.2.0 版本之前、2.0.20.7 版本之前在 taos.cfg 文件中不支持此参数。)
+- cacheLast:是否在内存中缓存子表的最近数据。0:关闭;1:缓存子表最近一行数据;2:缓存子表每一列的最近的非NULL值;3:同时打开缓存最近行和列功能。默认值:0。(可通过 alter database 修改)(从 2.1.2.0 版本开始此参数支持 0~3 的取值范围,在此之前取值只能是 [0, 1];而 2.0.11.0 之前的版本在 SQL 指令中不支持此参数。)(2.1.2.0 版本之前、2.0.20.7 版本之前在 taos.cfg 文件中不支持此参数。)
+- update:是否允许更新。0:不允许;1:允许。默认值:0。(可通过 alter database 修改)
对于一个应用场景,可能有多种数据特征的数据并存,最佳的设计是将具有相同数据特征的表放在一个库里,这样一个应用有多个库,而每个库可以配置不同的存储参数,从而保证系统有最优的性能。TDengine允许应用在创建库时指定上述存储参数,如果指定,该参数就将覆盖对应的系统配置参数。举例,有下述SQL:
@@ -142,7 +144,6 @@ taosd -C
TDengine集群中加入一个新的dnode时,涉及集群相关的一些参数必须与已有集群的配置相同,否则不能成功加入到集群中。会进行校验的参数如下:
- numOfMnodes:系统中管理节点个数。默认值:3。
-- balance:是否启动负载均衡。0:否,1:是。默认值:1。
- mnodeEqualVnodeNum: 一个mnode等同于vnode消耗的个数。默认值:4。
- offlineThreshold: dnode离线阈值,超过该时间将导致该dnode从集群中删除。单位为秒,默认值:86400*10(即10天)。
- statusInterval: dnode向mnode报告状态时长。单位为秒,默认值:1。
@@ -150,6 +151,10 @@ TDengine集群中加入一个新的dnode时,涉及集群相关的一些参数
- maxVgroupsPerDb: 每个数据库中能够使用的最大vgroup个数。
- arbitrator: 系统中裁决器的end point,缺省为空。
- timezone、locale、charset 的配置见客户端配置。(2.0.20.0 及以上的版本里,集群中加入新节点已不要求 locale 和 charset 参数取值一致)
+- balance:是否启用负载均衡。0:否,1:是。默认值:1。
+- flowctrl:是否启用非阻塞流控。0:否,1:是。默认值:1。
+- slaveQuery:是否启用 slave vnode 参与查询。0:否,1:是。默认值:1。
+- adjustMaster:是否启用 vnode master 负载均衡。0:否,1:是。默认值:1。
为方便调试,可通过SQL语句临时调整每个dnode的日志配置,系统重启后会失效:
diff --git a/documentation20/cn/12.taos-sql/docs.md b/documentation20/cn/12.taos-sql/docs.md
index 7508bbf86f..abbe7d8a0a 100644
--- a/documentation20/cn/12.taos-sql/docs.md
+++ b/documentation20/cn/12.taos-sql/docs.md
@@ -126,9 +126,25 @@ TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传
```mysql
ALTER DATABASE db_name CACHELAST 0;
```
- CACHELAST 参数控制是否在内存中缓存数据子表的 last_row。缺省值为 0,取值范围 [0, 1]。其中 0 表示不启用、1 表示启用。(从 2.0.11.0 版本开始支持。从 2.1.1.0 版本开始,修改此参数后无需重启服务器即可生效。)
+ CACHELAST 参数控制是否在内存中缓存子表的最近数据。缺省值为 0,取值范围 [0, 1, 2, 3]。其中 0 表示不缓存,1 表示缓存子表最近一行数据,2 表示缓存子表每一列的最近的非 NULL 值,3 表示同时打开缓存最近行和列功能。(从 2.0.11.0 版本开始支持参数值 [0, 1],从 2.1.2.0 版本开始支持参数值 [0, 1, 2, 3]。)
+ 说明:缓存最近行,将显著改善 LAST_ROW 函数的性能表现;缓存每列的最近非 NULL 值,将显著改善无特殊影响(WHERE、ORDER BY、GROUP BY、INTERVAL)下的 LAST 函数的性能表现。
- **Tips**: 以上所有参数修改后都可以用show databases来确认是否修改成功。
+ ```mysql
+ ALTER DATABASE db_name WAL 1;
+ ```
+ WAL 参数控制 WAL 日志的落盘方式。缺省值为 1,取值范围为 [1, 2]。1 表示写 WAL,但不执行 fsync;2 表示写 WAL,而且执行 fsync。
+
+ ```mysql
+ ALTER DATABASE db_name FSYNC 3000;
+ ```
+ FSYNC 参数控制执行 fsync 操作的周期。缺省值为 3000,单位是毫秒,取值范围为 [0, 180000]。如果设置为 0,表示每次写入,立即执行 fsync。该设置项主要用于调节 WAL 参数设为 2 时的系统行为。
+
+ ```mysql
+ ALTER DATABASE db_name UPDATE 0;
+ ```
+ UPDATE 参数控制是否允许更新数据。缺省值为 0,取值范围为 [0, 1]。0 表示会直接丢弃后写入的相同时间戳的数据;1 表示会使用后写入的数据覆盖已有的相同时间戳的数据。
+
+ **Tips**: 以上所有参数修改后都可以用show databases来确认是否修改成功。另外,从 2.1.1.0 版本开始,修改这些参数后无需重启服务器即可生效。
- **显示系统所有数据库**
diff --git a/documentation20/en/00.index/docs.md b/documentation20/en/00.index/docs.md
index 13f8a8565e..a10c22ee62 100644
--- a/documentation20/en/00.index/docs.md
+++ b/documentation20/en/00.index/docs.md
@@ -82,7 +82,7 @@ TDengine is a highly efficient platform to store, query, and analyze time-series
## [Connections with Other Tools](/connections)
- [Grafana](/connections#grafana): query the data saved in TDengine and provide visualization
-- [Matlab](/connections#matlab): access data stored in TDengine server via JDBC configured within Matlab
+- [MATLAB](/connections#matlab): access data stored in TDengine server via JDBC configured within MATLAB
- [R](/connections#r): access data stored in TDengine server via JDBC configured within R
- [IDEA Database](https://www.taosdata.com/blog/2020/08/27/1767.html): use TDengine visually through IDEA Database Management Tool
diff --git a/documentation20/en/01.evaluation/docs.md b/documentation20/en/01.evaluation/docs.md
index 89fb6443cb..50948efbd8 100644
--- a/documentation20/en/01.evaluation/docs.md
+++ b/documentation20/en/01.evaluation/docs.md
@@ -9,8 +9,8 @@ One of the modules of TDengine is the time-series database. However, in addition
- **Performance improvement over 10 times**: An innovative data storage structure is defined, with each single core can process at least 20,000 requests per second, insert millions of data points, and read more than 10 million data points, which is more than 10 times faster than other existing general database.
- **Reduce the cost of hardware or cloud services to 1/5**: Due to its ultra-performance, TDengine’s computing resources consumption is less than 1/5 of other common Big Data solutions; through columnar storage and advanced compression algorithms, the storage consumption is less than 1/10 of other general databases.
- **Full-stack time-series data processing engine**: Integrate database, message queue, cache, stream computing, and other functions, and the applications do not need to integrate with software such as Kafka/Redis/HBase/Spark/HDFS, thus greatly reducing the complexity cost of application development and maintenance.
-- **Powerful analysis functions**: Data from ten years ago or one second ago, can all be queried based on a specified time range. Data can be aggregated on a timeline or multiple devices. Ad-hoc queries can be made at any time through Shell, Python, R, and Matlab.
-- **Seamless connection with third-party tools**: Integration with Telegraf, Grafana, EMQ, HiveMQ, Prometheus, Matlab, R, etc. without even one single line of code. OPC, Hadoop, Spark, etc. will be supported in the future, and more BI tools will be seamlessly connected to.
+- **Powerful analysis functions**: Data from ten years ago or one second ago, can all be queried based on a specified time range. Data can be aggregated on a timeline or multiple devices. Ad-hoc queries can be made at any time through Shell, Python, R, and MATLAB.
+- **Seamless connection with third-party tools**: Integration with Telegraf, Grafana, EMQ, HiveMQ, Prometheus, MATLAB, R, etc. without even one single line of code. OPC, Hadoop, Spark, etc. will be supported in the future, and more BI tools will be seamlessly connected to.
- **Zero operation cost & zero learning cost**: Installing clusters is simple and quick, with real-time backup built-in, and no need to split libraries or tables. Similar to standard SQL, TDengine can support RESTful, Python/Java/C/C + +/C#/Go/Node.js, and similar to MySQL with zero learning cost.
With TDengine, the total cost of ownership of typical IoT, Internet of Vehicles, and Industrial Internet Big Data platforms can be greatly reduced. However, it should be pointed out that due to making full use of the characteristics of IoT time-series data, TDengine cannot be used to process general data from web crawlers, microblogs, WeChat, e-commerce, ERP, CRM, and other sources.
diff --git a/documentation20/en/08.connector/docs.md b/documentation20/en/08.connector/docs.md
index 9913a2958f..36dc06a36e 100644
--- a/documentation20/en/08.connector/docs.md
+++ b/documentation20/en/08.connector/docs.md
@@ -58,7 +58,7 @@ After extracting the package, you will see the following files (directories) in
*connector*: Connectors for various programming languages (go/grafanaplugin/nodejs/python/JDBC)
-*Examples*: Sample programs for various programming languages (C/C #/go/JDBC/matlab/python/R)
+*Examples*: Sample programs for various programming languages (C/C #/go/JDBC/MATLAB/python/R)
Run install_client.sh to install.
diff --git a/documentation20/en/09.connections/docs.md b/documentation20/en/09.connections/docs.md
index 93633ea369..e759da3167 100644
--- a/documentation20/en/09.connections/docs.md
+++ b/documentation20/en/09.connections/docs.md
@@ -74,17 +74,17 @@ You can see as follows after Dashboard imported.

-## Matlab
+## MATLAB
-MatLab can access data to the local workspace by connecting directly to the TDengine via the JDBC Driver provided in the installation package.
+MATLAB can access data to the local workspace by connecting directly to the TDengine via the JDBC Driver provided in the installation package.
-### JDBC Interface Adaptation of MatLab
+### JDBC Interface Adaptation of MATLAB
-Several steps are required to adapt Matlab to TDengine. Taking adapting Matlab2017a on Windows10 as an example:
+Several steps are required to adapt MATLAB to TDengine. Taking adapting MATLAB2017a on Windows10 as an example:
- Copy the file JDBCDriver-1.0.0-dist.ja*r* in TDengine package to the directory ${matlab_root}\MATLAB\R2017a\java\jar\toolbox
- Copy the file taos.lib in TDengine package to ${matlab root dir}\MATLAB\R2017a\lib\win64
-- Add the .jar package just copied to the Matlab classpath. Append the line below as the end of the file of ${matlab root dir}\MATLAB\R2017a\toolbox\local\classpath.txt
+- Add the .jar package just copied to the MATLAB classpath. Append the line below as the end of the file of ${matlab root dir}\MATLAB\R2017a\toolbox\local\classpath.txt
- ```
$matlabroot/java/jar/toolbox/JDBCDriver-1.0.0-dist.jar
```
@@ -94,9 +94,9 @@ Several steps are required to adapt Matlab to TDengine. Taking adapting Matlab20
C:\Windows\System32
```
-- ### Connect to TDengine in MatLab to get data
+- ### Connect to TDengine in MATLAB to get data
-After the above configured successfully, open MatLab.
+After the above configured successfully, open MATLAB.
- Create a connection:
diff --git a/packaging/check_package.sh b/packaging/check_package.sh
new file mode 100755
index 0000000000..e4d783d2f9
--- /dev/null
+++ b/packaging/check_package.sh
@@ -0,0 +1,245 @@
+#!/bin/bash
+#
+# This file is used to install database on linux systems. The operating system
+# is required to use systemd to manage services at boot
+
+set -e
+#set -x
+
+verMode=edge
+pagMode=full
+
+iplist=""
+serverFqdn=""
+
+# -----------------------Variables definition---------------------
+script_dir="../release"
+# Dynamic directory
+data_dir="/var/lib/taos"
+log_dir="/var/log/taos"
+
+data_link_dir="/usr/local/taos/data"
+log_link_dir="/usr/local/taos/log"
+
+cfg_install_dir="/etc/taos"
+
+bin_link_dir="/usr/bin"
+lib_link_dir="/usr/lib"
+lib64_link_dir="/usr/lib64"
+inc_link_dir="/usr/include"
+
+#install main path
+install_main_dir="/usr/local/taos"
+
+# old bin dir
+sbin_dir="/usr/local/taos/bin"
+
+temp_version=""
+fin_result=""
+
+service_config_dir="/etc/systemd/system"
+nginx_port=6060
+nginx_dir="/usr/local/nginxd"
+
+# Color setting
+RED='\033[0;31m'
+GREEN='\033[1;32m'
+GREEN_DARK='\033[0;32m'
+GREEN_UNDERLINE='\033[4;32m'
+NC='\033[0m'
+
+csudo=""
+if command -v sudo > /dev/null; then
+ csudo="sudo"
+fi
+
+# ============================= get input parameters =================================================
+
+# install.sh -v [server | client] -e [yes | no] -i [systemd | service | ...]
+
+# set parameters by default value
+interactiveFqdn=yes # [yes | no]
+verType=server # [server | client]
+initType=systemd # [systemd | service | ...]
+
+while getopts "hv:d:" arg
+do
+ case $arg in
+ d)
+ #echo "interactiveFqdn=$OPTARG"
+ script_dir=$( echo $OPTARG )
+ ;;
+ h)
+ echo "Usage: `basename $0` -d scripy_path"
+ exit 0
+ ;;
+ ?) #unknow option
+ echo "unkonw argument"
+ exit 1
+ ;;
+ esac
+done
+
+#echo "verType=${verType} interactiveFqdn=${interactiveFqdn}"
+
+function kill_process() {
+ pid=$(ps -ef | grep "$1" | grep -v "grep" | awk '{print $2}')
+ if [ -n "$pid" ]; then
+ ${csudo} kill -9 $pid || :
+ fi
+}
+
+function check_file() {
+ #check file whether exists
+ if [ ! -e $1/$2 ];then
+ echo -e "$1/$2 \033[31mnot exists\033[0m!quit"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+}
+
+function get_package_name() {
+ var=$1
+ if [[ $1 =~ 'aarch' ]];then
+ echo ${var::-21}
+ else
+ echo ${var::-17}
+ fi
+}
+function check_link() {
+ #check Link whether exists or broken
+ if [ -L $1 ] ; then
+ if [ ! -e $1 ] ; then
+ echo -e "$1 \033[31Broken link\033[0m"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+ else
+ echo -e "$1 \033[31mnot exists\033[0m!quit"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+}
+
+function check_main_path() {
+ #check install main dir and all sub dir
+ main_dir=("" "cfg" "bin" "connector" "driver" "examples" "include" "init.d")
+ for i in ${main_dir[@]};do
+ check_file ${install_main_dir} $i
+ done
+ if [ "$verMode" == "cluster" ]; then
+ nginx_main_dir=("admin" "conf" "html" "sbin" "logs")
+ for i in ${nginx_main_dir[@]};do
+ check_file ${nginx_dir} $i
+ done
+ fi
+ echo -e "Check main path:\033[32mOK\033[0m!"
+}
+
+function check_bin_path() {
+ # check install bin dir and all sub dir
+ bin_dir=("taos" "taosd" "taosdemo" "taosdump" "remove.sh" "tarbitrator" "set_core.sh")
+ for i in ${bin_dir[@]};do
+ check_file ${sbin_dir} $i
+ done
+ lbin_dir=("taos" "taosd" "taosdemo" "taosdump" "rmtaos" "tarbitrator" "set_core")
+ for i in ${lbin_dir[@]};do
+ check_link ${bin_link_dir}/$i
+ done
+ if [ "$verMode" == "cluster" ]; then
+ check_file ${nginx_dir}/sbin nginx
+ fi
+ echo -e "Check bin path:\033[32mOK\033[0m!"
+}
+
+
+function check_lib_path() {
+ # check all links
+ check_link ${lib_link_dir}/libtaos.so
+ check_link ${lib_link_dir}/libtaos.so.1
+
+ if [[ -d ${lib64_link_dir} ]]; then
+ check_link ${lib64_link_dir}/libtaos.so
+ check_link ${lib64_link_dir}/libtaos.so.1
+ fi
+ echo -e "Check lib path:\033[32mOK\033[0m!"
+}
+
+
+function check_header_path() {
+ # check all header
+ header_dir=("taos.h" "taoserror.h")
+ for i in ${header_dir[@]};do
+ check_link ${inc_link_dir}/$i
+ done
+ echo -e "Check bin path:\033[32mOK\033[0m!"
+}
+
+
+function check_config_dir() {
+ # check all config
+ check_file ${cfg_install_dir} taos.cfg
+ check_file ${install_main_dir}/cfg taos.cfg.org
+ echo -e "Check conf path:\033[32mOK\033[0m!"
+}
+
+function check_log_path() {
+ # check log path
+ check_file ${log_dir}
+ echo -e "Check log path:\033[32mOK\033[0m!"
+}
+
+function check_data_path() {
+ # check data path
+ check_file ${data_dir}
+ echo -e "Check data path:\033[32mOK\033[0m!"
+}
+
+function install_TDengine() {
+ cd ${script_dir}
+ tar zxf $1
+ temp_version=$(get_package_name $1)
+ cd $(get_package_name $1)
+ echo -e "\033[32muninstall TDengine && install TDengine...\033[0m"
+ rmtaos >/dev/null 2>&1 || echo 'taosd not installed' && echo -e '\n\n' |./install.sh >/dev/null 2>&1
+ echo -e "\033[32mTDengine has been installed!\033[0m"
+ echo -e "\033[32mTDengine is starting...\033[0m"
+ kill_process taos && systemctl start taosd && sleep 10
+}
+
+function test_TDengine() {
+ check_main_path
+ check_bin_path
+ check_lib_path
+ check_header_path
+ check_config_dir
+ check_log_path
+ check_data_path
+ result=`taos -s 'create database test ;create table test.tt(ts timestamp ,i int);insert into test.tt values(now,11);select * from test.tt' 2>&1 ||:`
+ if [[ $result =~ "Unable to establish" ]];then
+ echo -e "\033[31mTDengine connect failed\033[0m"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+ echo -e "Check TDengine connect:\033[32mOK\033[0m!"
+ fin_result=$fin_result"\033[32m$temp_version\033[0m test OK!\n"
+}
+# ## ==============================Main program starts from here============================
+TD_package_name=`ls ${script_dir}/*server*gz |awk -F '/' '{print $NF}' `
+temp=`pwd`
+for i in $TD_package_name;do
+ if [[ $i =~ 'enterprise' ]];then
+ verMode="cluster"
+ else
+ verMode=""
+ fi
+ cd $temp
+ install_TDengine $i
+ test_TDengine
+done
+echo "============================================================"
+echo -e $fin_result
\ No newline at end of file
diff --git a/src/balance/src/bnMain.c b/src/balance/src/bnMain.c
index 67741b1473..f022fff6d8 100644
--- a/src/balance/src/bnMain.c
+++ b/src/balance/src/bnMain.c
@@ -367,6 +367,7 @@ static bool bnMonitorBalance() {
for (int32_t dest = 0; dest < src; dest++) {
SDnodeObj *pDestDnode = tsBnDnodes.list[dest];
if (bnCheckDnodeInVgroup(pDestDnode, pVgroup)) continue;
+ if (taosGetTimestampMs() - pDestDnode->createdTime < 2000) continue;
float destScore = bnTryCalcDnodeScore(pDestDnode, 1);
if (srcScore + 0.0001 < destScore) continue;
diff --git a/src/client/inc/tscUtil.h b/src/client/inc/tscUtil.h
index 2c4d711520..35f3b42811 100644
--- a/src/client/inc/tscUtil.h
+++ b/src/client/inc/tscUtil.h
@@ -123,7 +123,8 @@ int32_t tscGetDataBlockFromList(SHashObj* pHashList, int64_t id, int32_t size, i
*/
bool tscIsPointInterpQuery(SQueryInfo* pQueryInfo);
bool tscIsTWAQuery(SQueryInfo* pQueryInfo);
-bool tscIsDiffQuery(SQueryInfo* pQueryInfo);
+bool tscIsIrateQuery(SQueryInfo* pQueryInfo);
+
bool tscIsSessionWindowQuery(SQueryInfo* pQueryInfo);
bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo);
bool tsIsArithmeticQueryOnAggResult(SQueryInfo* pQueryInfo);
diff --git a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
index d16b672f38..7181c658dd 100644
--- a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
+++ b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
@@ -51,10 +51,10 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
- * Method: getResultTimePrecision
- * Signature: (J)J
+ * Method: getResultTimePrecisionImp
+ * Signature: (JJ)I
*/
-JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision
+JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecisionImp
(JNIEnv *, jobject, jlong, jlong);
/*
diff --git a/src/client/src/TSDBJNIConnector.c b/src/client/src/TSDBJNIConnector.c
index 324c436dce..379cf86301 100644
--- a/src/client/src/TSDBJNIConnector.c
+++ b/src/client/src/TSDBJNIConnector.c
@@ -113,7 +113,7 @@ static void jniGetGlobalMethod(JNIEnv *env) {
g_rowdataSetFloatFp = (*env)->GetMethodID(env, g_rowdataClass, "setFloat", "(IF)V");
g_rowdataSetDoubleFp = (*env)->GetMethodID(env, g_rowdataClass, "setDouble", "(ID)V");
g_rowdataSetStringFp = (*env)->GetMethodID(env, g_rowdataClass, "setString", "(ILjava/lang/String;)V");
- g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJ)V");
+ g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJI)V");
g_rowdataSetByteArrayFp = (*env)->GetMethodID(env, g_rowdataClass, "setByteArray", "(I[B)V");
(*env)->DeleteLocalRef(env, rowdataClass);
@@ -519,9 +519,11 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEn
jniFromNCharToByteArray(env, (char *)row[i], length[i]));
break;
}
- case TSDB_DATA_TYPE_TIMESTAMP:
- (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]));
+ case TSDB_DATA_TYPE_TIMESTAMP: {
+ int precision = taos_result_precision(result);
+ (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]), precision);
break;
+ }
default:
break;
}
@@ -672,7 +674,15 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(J
return (*env)->NewStringUTF(env, (const char *)tsCharset);
}
-JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision(JNIEnv *env, jobject jobj, jlong con,
+/**
+ * Get Result Time Precision
+ * @param env vm
+ * @param jobj the TSDBJNIConnector java object
+ * @param con the c connection pointer
+ * @param res the TAOS_RES object, i.e. the SSqlObject
+ * @return precision 0:ms 1:us 2:ns
+ */
+JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultTimePrecisionImp(JNIEnv *env, jobject jobj, jlong con,
jlong res) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
diff --git a/src/client/src/tscPrepare.c b/src/client/src/tscPrepare.c
index 89d915a813..bac8920d8f 100644
--- a/src/client/src/tscPrepare.c
+++ b/src/client/src/tscPrepare.c
@@ -906,7 +906,7 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
int code = doBindParam(pBlock, data, param, &bind[param->idx], 1);
if (code != TSDB_CODE_SUCCESS) {
- tscDebug("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
+ tscDebug("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
return invalidOperationMsg(tscGetErrorMsgPayload(&stmt->pSql->cmd), "bind column type mismatch or invalid");
}
}
@@ -1256,7 +1256,7 @@ int stmtParseInsertTbTags(SSqlObj* pSql, STscStmt* pStmt) {
return TSDB_CODE_SUCCESS;
}
- if (sToken.n <= 0 || sToken.type != TK_USING) {
+ if (sToken.n <= 0 || sToken.type != TK_USING) {
tscError("keywords USING is expected, sql:%s", pCmd->insertParam.sql);
return tscSQLSyntaxErrMsg(pCmd->payload, "keywords USING is expected", sToken.z ? sToken.z : pCmd->insertParam.sql);
}
@@ -1403,7 +1403,7 @@ int stmtGenInsertStatement(SSqlObj* pSql, STscStmt* pStmt, const char* name, TAO
} else {
tfree(pSql->sqlstr);
}
-
+
pSql->sqlstr = str;
return TSDB_CODE_SUCCESS;
@@ -1415,7 +1415,7 @@ int stmtGenInsertStatement(SSqlObj* pSql, STscStmt* pStmt, const char* name, TAO
TAOS_STMT* taos_stmt_init(TAOS* taos) {
STscObj* pObj = (STscObj*)taos;
STscStmt* pStmt = NULL;
-
+
if (pObj == NULL || pObj->signature != pObj) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
tscError("connection disconnected");
@@ -1469,7 +1469,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
tscError("sql is NULL");
STMT_RET(invalidOperationMsg(tscGetErrorMsgPayload(&pStmt->pSql->cmd), "sql is NULL"));
}
-
+
if (pStmt->last != STMT_INIT) {
tscError("prepare status error, last:%d", pStmt->last);
STMT_RET(invalidOperationMsg(tscGetErrorMsgPayload(&pStmt->pSql->cmd), "prepare status error"));
diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c
index a5c9088ec3..d78eb65f2e 100644
--- a/src/client/src/tscSQLParser.c
+++ b/src/client/src/tscSQLParser.c
@@ -148,16 +148,16 @@ int16_t getNewResColId(SSqlCmd* pCmd) {
return pCmd->resColumnId--;
}
-// serialize expr in exprlist to binary
+// serialize expr in exprlist to binary
// formate "type | size | value"
bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType, uint8_t precision) {
bool ret = false;
if (!pList || pList->size <= 0 || colType < 0) {
return ret;
- }
-
- tSqlExprItem* item = (tSqlExprItem *)taosArrayGet(pList, 0);
- int32_t firstTokenType = item->pNode->token.type;
+ }
+
+ tSqlExprItem* item = (tSqlExprItem *)taosArrayGet(pList, 0);
+ int32_t firstTokenType = item->pNode->token.type;
int32_t type = firstTokenType;
//nchar to binary and other xxint to bigint
@@ -170,12 +170,13 @@ bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType,
type = colType;
SBufferWriter bw = tbufInitWriter( NULL, false);
+
tbufEnsureCapacity(&bw, 512);
int32_t size = (int32_t)(pList->size);
- tbufWriteUint32(&bw, type);
+ tbufWriteUint32(&bw, type);
tbufWriteInt32(&bw, size);
-
+
for (int32_t i = 0; i < size; i++) {
tSqlExpr* pSub = ((tSqlExprItem*)(taosArrayGet(pList, i)))->pNode;
@@ -203,11 +204,11 @@ bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType,
} else if (type == TSDB_DATA_TYPE_BINARY){
tbufWriteBinary(&bw, var.pz, var.nLen);
} else if (type == TSDB_DATA_TYPE_NCHAR) {
- char *buf = (char *)calloc(1, (var.nLen + 1)*TSDB_NCHAR_SIZE);
+ char *buf = (char *)calloc(1, (var.nLen + 1)*TSDB_NCHAR_SIZE);
if (tVariantDump(&var, buf, type, false) != TSDB_CODE_SUCCESS) {
free(buf);
tVariantDestroy(&var);
- break;
+ break;
}
tbufWriteBinary(&bw, buf, twcslen((wchar_t *)buf) * TSDB_NCHAR_SIZE);
free(buf);
@@ -229,21 +230,21 @@ bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType,
if (ret == true) {
if ((*dst = calloc(1, sizeof(tVariant))) != NULL) {
- tVariantCreateFromBinary(*dst, tbufGetData(&bw, false), tbufTell(&bw), TSDB_DATA_TYPE_BINARY);
+ tVariantCreateFromBinary(*dst, tbufGetData(&bw, false), tbufTell(&bw), TSDB_DATA_TYPE_BINARY);
} else {
ret = false;
}
}
- tbufCloseWriter(&bw);
+ tbufCloseWriter(&bw);
return ret;
}
static int32_t validateParamOfRelationIn(tVariant *pVar, int32_t colType) {
if (pVar->nType != TSDB_DATA_TYPE_BINARY) {
- return -1;
+ return -1;
}
- SBufferReader br = tbufInitReader(pVar->pz, pVar->nLen, false);
- return colType == TSDB_DATA_TYPE_NCHAR ? 0 : (tbufReadUint32(&br) == colType ? 0: -1);
+ SBufferReader br = tbufInitReader(pVar->pz, pVar->nLen, false);
+ return colType == TSDB_DATA_TYPE_NCHAR ? 0 : (tbufReadUint32(&br) == colType ? 0: -1);
}
static uint8_t convertOptr(SStrToken *pToken) {
@@ -447,18 +448,6 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if(code != TSDB_CODE_SUCCESS) {
return code;
}
-
- if (pInfo->pMiscInfo->tableType == TSDB_SUPER_TABLE) {
-//// code = tscGetTableMeta(pSql, pTableMetaInfo);
-//// if (code != TSDB_CODE_SUCCESS) {
-//// return code;
-//// }
-//
-// if (!UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
-// return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg4);
-// }
- }
-
} else if (pInfo->type == TSDB_SQL_DROP_DNODE) {
if (pzName->type == TK_STRING) {
pzName->n = strdequote(pzName->z);
@@ -531,7 +520,7 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
break;
}
-
+
case TSDB_SQL_CREATE_DNODE: {
const char* msg = "invalid host name (ip address)";
@@ -796,6 +785,11 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
pCmd->active = pCmd->pQueryInfo;
pCmd->command = pCmd->pQueryInfo->command;
+ STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pCmd->active, 0);
+ if (pTableMetaInfo1->pTableMeta != NULL) {
+ pSql->res.precision = tscGetTableInfo(pTableMetaInfo1->pTableMeta).precision;
+ }
+
return TSDB_CODE_SUCCESS; // do not build query message here
}
@@ -827,12 +821,12 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
}
break;
}
- case TSDB_SQL_COMPACT_VNODE:{
+ case TSDB_SQL_COMPACT_VNODE:{
const char* msg = "invalid compact";
if (setCompactVnodeInfo(pSql, pInfo) != TSDB_CODE_SUCCESS) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
- }
- break;
+ }
+ break;
}
default:
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "not support sql expression");
@@ -980,20 +974,22 @@ int32_t validateIntervalNode(SSqlObj* pSql, SQueryInfo* pQueryInfo, SSqlNode* pS
static int32_t validateStateWindowNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSqlNode, bool isStable) {
const char* msg1 = "invalid column name";
+ const char* msg2 = "invalid column type";
const char* msg3 = "not support state_window with group by ";
const char* msg4 = "function not support for super table query";
+ const char* msg5 = "not support state_window on tag column";
SStrToken *col = &(pSqlNode->windowstateVal.col) ;
if (col->z == NULL || col->n <= 0) {
- return TSDB_CODE_SUCCESS;
- }
+ return TSDB_CODE_SUCCESS;
+ }
if (pQueryInfo->colList == NULL) {
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
}
if (pQueryInfo->groupbyExpr.numOfGroupCols > 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- }
+ }
pQueryInfo->groupbyExpr.numOfGroupCols = 1;
//TODO(dengyihao): check tag column
@@ -1004,23 +1000,27 @@ static int32_t validateStateWindowNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SS
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (getColumnIndexByName(pCmd, col, pQueryInfo, &index) != TSDB_CODE_SUCCESS) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
- }
+ }
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
int32_t numOfCols = tscGetNumOfColumns(pTableMeta);
- if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX || index.columnIndex >= numOfCols) {
+ if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
+ } else if (index.columnIndex >= numOfCols) {
+ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg5);
}
SGroupbyExpr* pGroupExpr = &pQueryInfo->groupbyExpr;
if (pGroupExpr->columnInfo == NULL) {
pGroupExpr->columnInfo = taosArrayInit(4, sizeof(SColIndex));
}
-
+
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, index.columnIndex);
- if (pSchema->type == TSDB_DATA_TYPE_TIMESTAMP || pSchema->type == TSDB_DATA_TYPE_FLOAT || pSchema->type == TSDB_DATA_TYPE_DOUBLE) {
- return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
+ if (pSchema->type == TSDB_DATA_TYPE_TIMESTAMP || pSchema->type == TSDB_DATA_TYPE_FLOAT
+ || pSchema->type == TSDB_DATA_TYPE_DOUBLE || pSchema->type == TSDB_DATA_TYPE_NCHAR
+ || pSchema->type == TSDB_DATA_TYPE_BINARY) {
+ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
}
tscColumnListInsert(pQueryInfo->colList, index.columnIndex, pTableMeta->id.uid, pSchema);
@@ -1069,7 +1069,7 @@ int32_t validateSessionNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode * pS
}
if (index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- }
+ }
pQueryInfo->sessionWindow.primaryColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
@@ -1819,7 +1819,6 @@ int32_t validateSelectNodeList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SArray* pS
assert(pSelNodeList != NULL && pCmd != NULL);
const char* msg1 = "too many items in selection clause";
-
const char* msg2 = "functions or others can not be mixed up";
const char* msg3 = "not support query expression";
const char* msg4 = "only support distinct one tag";
@@ -2047,8 +2046,10 @@ int32_t addProjectionExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, t
if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
SSchema colSchema = *tGetTbnameColumnSchema();
- getColumnName(pItem, colSchema.name, colSchema.name, sizeof(colSchema.name) - 1);
+ char name[TSDB_COL_NAME_LEN] = {0};
+ getColumnName(pItem, name, colSchema.name, sizeof(colSchema.name) - 1);
+ tstrncpy(colSchema.name, name, TSDB_COL_NAME_LEN);
/*SExprInfo* pExpr = */tscAddFuncInSelectClause(pQueryInfo, startPos, TSDB_FUNC_TAGPRJ, &index, &colSchema, TSDB_COL_TAG, getNewResColId(pCmd));
} else {
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
@@ -2362,7 +2363,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
tickPerSec /= 1000000;
} else if (info.precision == TSDB_TIME_PRECISION_MICRO) {
tickPerSec /= 1000;
- }
+ }
if (tickPerSec <= 0 || tickPerSec < TSDB_TICK_PER_SECOND(info.precision)) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg10);
@@ -2748,6 +2749,8 @@ void getColumnName(tSqlExprItem* pItem, char* resultFieldName, char* rawName, in
strncpy(rawName, pItem->pNode->token.z, len);
if (pItem->aliasName != NULL) {
+ int32_t aliasNameLen = (int32_t) strlen(pItem->aliasName);
+ len = (aliasNameLen < nameLength)? aliasNameLen:nameLength;
strncpy(resultFieldName, pItem->aliasName, len);
} else {
strncpy(resultFieldName, rawName, len);
@@ -2997,7 +3000,7 @@ int32_t setKillInfo(SSqlObj* pSql, struct SSqlInfo* pInfo, int32_t killType) {
static int32_t setCompactVnodeInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
SSqlCmd* pCmd = &pSql->cmd;
pCmd->command = pInfo->type;
-
+
return TSDB_CODE_SUCCESS;
}
bool validateIpAddress(const char* ip, size_t size) {
@@ -3085,8 +3088,8 @@ void tscRestoreFuncForSTableQuery(SQueryInfo* pQueryInfo) {
}
bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo) {
- const char* msg1 = "TWA/Diff not allowed to apply to super table directly";
- const char* msg2 = "TWA/Diff only support group by tbname for super table query";
+ const char* msg1 = "TWA/Diff/Derivative/Irate not allowed to apply to super table directly";
+ const char* msg2 = "TWA/Diff/Derivative/Irate only support group by tbname for super table query";
const char* msg3 = "function not support for super table query";
// filter sql function not supported by metric query yet.
@@ -3099,7 +3102,7 @@ bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo)
}
}
- if (tscIsTWAQuery(pQueryInfo) || tscIsDiffQuery(pQueryInfo)) {
+ if (tscIsTWAQuery(pQueryInfo) || tscIsDiffDerivQuery(pQueryInfo) || tscIsIrateQuery(pQueryInfo)) {
if (pQueryInfo->groupbyExpr.numOfGroupCols == 0) {
invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
return true;
@@ -3117,7 +3120,7 @@ bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo)
}
} else if (tscIsSessionWindowQuery(pQueryInfo)) {
invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- return true;
+ return true;
}
return false;
@@ -3360,12 +3363,11 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo,
// TK_GT,TK_GE,TK_EQ,TK_NE are based on the pColumn->lowerBndd
} else if (pExpr->tokenId == TK_IN) {
tVariant *pVal;
-
if (pRight->tokenId != TK_SET || !serializeExprListToVariant(pRight->pParam, &pVal, colType, timePrecision)) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
- }
+ }
if (validateParamOfRelationIn(pVal, colType) != TSDB_CODE_SUCCESS) {
- tVariantDestroy(pVal);
+ tVariantDestroy(pVal);
free(pVal);
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
}
@@ -3374,9 +3376,9 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo,
pColumnFilter->filterstr = 1;
memcpy((char *)(pColumnFilter->pz), (char *)(pVal->pz), pVal->nLen);
- tVariantDestroy(pVal);
+ tVariantDestroy(pVal);
free(pVal);
-
+
} else if (colType == TSDB_DATA_TYPE_BINARY) {
pColumnFilter->pz = (int64_t)calloc(1, bufLen * TSDB_NCHAR_SIZE);
pColumnFilter->len = pRight->value.nLen;
@@ -4907,7 +4909,7 @@ int32_t getTimeRange(STimeWindow* win, tSqlExpr* pRight, int32_t optr, int16_t t
if (pRight->flags & (1 << EXPR_FLAG_NS_TIMESTAMP)) {
pRight->value.i64 = convertTimePrecision(pRight->value.i64, TSDB_TIME_PRECISION_NANO, timePrecision);
}
-
+
tVariantDump(&pRight->value, (char*)&val, TSDB_DATA_TYPE_BIGINT, true);
}
@@ -5565,7 +5567,7 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if (pItem->type != TSDB_DATA_TYPE_BINARY && pItem->type != TSDB_DATA_TYPE_NCHAR) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg21);
}
-
+
SColumnIndex columnIndex = COLUMN_INDEX_INITIALIZER;
SStrToken name = {.type = TK_STRING, .z = pItem->name, .n = (uint32_t)strlen(pItem->name)};
if (getColumnIndexByName(pCmd, &name, pQueryInfo, &columnIndex) != TSDB_CODE_SUCCESS) {
@@ -5586,11 +5588,11 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
(pItem->type == TSDB_DATA_TYPE_NCHAR && (pItem->bytes <= 0 || pItem->bytes > TSDB_MAX_NCHAR_LEN))) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg24);
}
-
+
if (pItem->bytes <= pColSchema->bytes) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg22);
}
-
+
TAOS_FIELD f = tscCreateField(pColSchema->type, name.z, pItem->bytes);
tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
}else if (pAlterSQL->type == TSDB_ALTER_TABLE_MODIFY_TAG_COLUMN) {
@@ -5602,7 +5604,7 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if (pItem->type != TSDB_DATA_TYPE_BINARY && pItem->type != TSDB_DATA_TYPE_NCHAR) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg21);
}
-
+
SColumnIndex columnIndex = COLUMN_INDEX_INITIALIZER;
SStrToken name = {.type = TK_STRING, .z = pItem->name, .n = (uint32_t)strlen(pItem->name)};
if (getColumnIndexByName(pCmd, &name, pQueryInfo, &columnIndex) != TSDB_CODE_SUCCESS) {
@@ -5627,11 +5629,11 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
(pItem->type == TSDB_DATA_TYPE_NCHAR && (pItem->bytes <= 0 || pItem->bytes > TSDB_MAX_NCHAR_LEN))) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg24);
}
-
+
if (pItem->bytes <= pColSchema->bytes) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg22);
}
-
+
TAOS_FIELD f = tscCreateField(pColSchema->type, name.z, pItem->bytes);
tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
}
@@ -5997,7 +5999,7 @@ static int32_t setKeepOption(SSqlCmd* pCmd, SCreateDbMsg* pMsg, SCreateDbInfo* p
tVariantListItem* p0 = taosArrayGet(pKeep, 0);
tVariantListItem* p1 = (s > 1) ? taosArrayGet(pKeep, 1) : p0;
tVariantListItem* p2 = (s > 2) ? taosArrayGet(pKeep, 2) : p1;
-
+
if ((int32_t)p0->pVar.i64 <= 0 || (int32_t)p1->pVar.i64 <= 0 || (int32_t)p2->pVar.i64 <= 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
}
@@ -7111,7 +7113,7 @@ int32_t doCheckForStream(SSqlObj* pSql, SSqlInfo* pInfo) {
} else {
if (pQueryInfo->interval.interval == 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg7);
- }
+ }
}
// set the created table[stream] name
@@ -7784,6 +7786,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
const char* msg4 = "interval query not supported, since the result of sub query not include valid timestamp column";
const char* msg5 = "only tag query not compatible with normal column filter";
const char* msg6 = "not support stddev/percentile in outer query yet";
+ const char* msg7 = "drivative requires timestamp column exists in subquery";
int32_t code = TSDB_CODE_SUCCESS;
@@ -7833,11 +7836,27 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
}
}
+ // todo derivative function requires ts column exists in subquery
+ STableMeta* pTableMeta = tscGetMetaInfo(pQueryInfo, 0)->pTableMeta;
+ SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, 0);
+
+ if (tscNumOfExprs(pQueryInfo) > 1) {
+ SExprInfo* pExpr = tscExprGet(pQueryInfo, 1);
+ if (pExpr->base.functionId == TSDB_FUNC_DERIVATIVE && pSchema->type != TSDB_DATA_TYPE_TIMESTAMP) {
+ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg7);
+ }
+ }
+
// validate the query filter condition info
if (pSqlNode->pWhere != NULL) {
if (validateWhereNode(pQueryInfo, &pSqlNode->pWhere, pSql) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
+
+ if (pTableMeta->tableInfo.precision == TSDB_TIME_PRECISION_MILLI) {
+ pQueryInfo->window.skey = pQueryInfo->window.skey / 1000;
+ pQueryInfo->window.ekey = pQueryInfo->window.ekey / 1000;
+ }
}
// validate the interval info
@@ -7858,7 +7877,6 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
}
// set order by info
- STableMeta* pTableMeta = tscGetMetaInfo(pQueryInfo, 0)->pTableMeta;
if (validateOrderbyNode(pCmd, pQueryInfo, pSqlNode, tscGetTableSchema(pTableMeta)) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
@@ -7911,7 +7929,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
- // parse the window_state
+ // parse the window_state
if (validateStateWindowNode(pCmd, pQueryInfo, pSqlNode, isSTable) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
@@ -8009,7 +8027,6 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
pQueryInfo->arithmeticOnAgg = tsIsArithmeticQueryOnAggResult(pQueryInfo);
pQueryInfo->orderProjectQuery = tscOrderedProjectionQueryOnSTable(pQueryInfo, 0);
-// pQueryInfo->diffQuery = tscIsDiffQuery(pQueryInfo);
SExprInfo** p = NULL;
int32_t numOfExpr = 0;
@@ -8137,7 +8154,7 @@ int32_t exprTreeFromSqlExpr(SSqlCmd* pCmd, tExprNode **pExpr, const tSqlExpr* pS
SColIndex* idx = taosArrayGet(pCols, 0);
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, idx->colIndex);
if (pSchema != NULL) {
- colType = pSchema->type;
+ colType = pSchema->type;
}
}
tVariant *pVal;
diff --git a/src/client/src/tscSub.c b/src/client/src/tscSub.c
index 7a0b3451c3..ef46b4068e 100644
--- a/src/client/src/tscSub.c
+++ b/src/client/src/tscSub.c
@@ -283,6 +283,7 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
SArray* tables = getTableList(pSql);
if (tables == NULL) {
+ pSub->lastSyncTime = 0; //force to get table list next time
return 0;
}
size_t numOfTables = taosArrayGetSize(tables);
@@ -489,7 +490,15 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
SSub *pSub = (SSub *)tsub;
if (pSub == NULL) return NULL;
- if (pSub->pSql->cmd.command == TSDB_SQL_RETRIEVE_EMPTY_RESULT) {
+ if (pSub->pTimer == NULL) {
+ int64_t duration = taosGetTimestampMs() - pSub->lastConsumeTime;
+ if (duration < (int64_t)(pSub->interval)) {
+ tscDebug("subscription consume too frequently, blocking...");
+ taosMsleep(pSub->interval - (int32_t)duration);
+ }
+ }
+
+ if (pSub->pSql->cmd.command == TSDB_SQL_RETRIEVE_EMPTY_RESULT) { //may reach here when retireve stable vgroup failed
SSqlObj* pSql = recreateSqlObj(pSub);
if (pSql == NULL) {
return NULL;
@@ -503,6 +512,11 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
pSub->pSql = pSql;
pSql->pSubscription = pSub;
+
+ // no table list now, force to update it
+ tscDebug("begin table synchronization");
+ if (!tscUpdateSubscription(pSub->taos, pSub)) return NULL;
+ tscDebug("table synchronization completed");
}
tscSaveSubscriptionProgress(pSub);
@@ -527,14 +541,6 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
tscDebug("subscribe:%s set next round subscribe skey:%"PRId64, pSub->topic, pQueryInfo->window.skey);
}
- if (pSub->pTimer == NULL) {
- int64_t duration = taosGetTimestampMs() - pSub->lastConsumeTime;
- if (duration < (int64_t)(pSub->interval)) {
- tscDebug("subscription consume too frequently, blocking...");
- taosMsleep(pSub->interval - (int32_t)duration);
- }
- }
-
size_t size = taosArrayGetSize(pSub->progress) * sizeof(STableIdInfo);
size += sizeof(SQueryTableMsg) + 4096;
int code = tscAllocPayload(&pSql->cmd, (int)size);
diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c
index e7f0606db2..22a603b71e 100644
--- a/src/client/src/tscSubquery.c
+++ b/src/client/src/tscSubquery.c
@@ -109,7 +109,7 @@ bool subAndCheckDone(SSqlObj *pSql, SSqlObj *pParentSql, int idx) {
// pthread_mutex_unlock(&subState->mutex);
// return false;
// }
-
+
tscDebug("0x%"PRIx64" subquery:0x%"PRIx64", index:%d state set to 1", pParentSql->self, pSql->self, idx);
subState->states[idx] = 1;
@@ -622,7 +622,7 @@ static int32_t tscLaunchRealSubqueries(SSqlObj* pSql) {
int16_t colId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid);
// set the tag column id for executor to extract correct tag value
-#ifndef _TD_NINGSI_60
+#ifndef _TD_NINGSI_60
pExpr->base.param[0] = (tVariant) {.i64 = colId, .nType = TSDB_DATA_TYPE_BIGINT, .nLen = sizeof(int64_t)};
#else
pExpr->base.param[0].i64 = colId;
@@ -1843,7 +1843,7 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
// refactor as one method
SQueryInfo *pNewQueryInfo = tscGetQueryInfo(&pNew->cmd);
assert(pNewQueryInfo != NULL);
-
+
pSupporter->colList = pNewQueryInfo->colList;
pNewQueryInfo->colList = NULL;
@@ -3158,7 +3158,7 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
pRes->code = TSDB_CODE_TSC_APP_ERROR;
return pRes->code;
}
-
+
for(int32_t i = 0; i < pSql->subState.numOfSub; ++i) {
SSqlObj* pSub = pSql->pSubs[i];
SInsertSupporter* pSup = calloc(1, sizeof(SInsertSupporter));
diff --git a/src/client/src/tscSystem.c b/src/client/src/tscSystem.c
index bd79f81846..ac6fc62adb 100644
--- a/src/client/src/tscSystem.c
+++ b/src/client/src/tscSystem.c
@@ -288,16 +288,24 @@ static int taos_options_imp(TSDB_OPTION option, const char *pStr) {
if (strlen(tsLocale) == 0) { // locale does not set yet
char* defaultLocale = setlocale(LC_CTYPE, "");
+
+ // The locale of the current OS does not be set correctly, so the default locale cannot be acquired.
+ // The launch of current system will abort soon.
+ if (defaultLocale == NULL) {
+ tscError("failed to get default locale, please set the correct locale in current OS");
+ return -1;
+ }
+
tstrncpy(tsLocale, defaultLocale, TSDB_LOCALE_LEN);
}
// set the user specified locale
char *locale = setlocale(LC_CTYPE, pStr);
- if (locale != NULL) {
+ if (locale != NULL) { // failed to set the user specified locale
tscInfo("locale set, prev locale:%s, new locale:%s", tsLocale, locale);
cfg->cfgStatus = TAOS_CFG_CSTATUS_OPTION;
- } else { // set the user-specified localed failed, use default LC_CTYPE as current locale
+ } else { // set the user specified locale failed, use default LC_CTYPE as current locale
locale = setlocale(LC_CTYPE, tsLocale);
tscInfo("failed to set locale:%s, current locale:%s", pStr, tsLocale);
}
diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c
index e3dba3fcbc..9d2c500a92 100644
--- a/src/client/src/tscUtil.c
+++ b/src/client/src/tscUtil.c
@@ -460,17 +460,15 @@ bool tscIsTWAQuery(SQueryInfo* pQueryInfo) {
return false;
}
-bool tscIsDiffQuery(SQueryInfo* pQueryInfo) {
- size_t num = tscNumOfExprs(pQueryInfo);
- for(int32_t i = 0; i < num; ++i) {
+bool tscIsIrateQuery(SQueryInfo* pQueryInfo) {
+ size_t numOfExprs = tscNumOfExprs(pQueryInfo);
+ for (int32_t i = 0; i < numOfExprs; ++i) {
SExprInfo* pExpr = tscExprGet(pQueryInfo, i);
-
- int32_t f = pExpr->base.functionId;
- if (pExpr == NULL || f == TSDB_FUNC_TS_DUMMY) {
+ if (pExpr == NULL) {
continue;
}
- if (f == TSDB_FUNC_DIFF || f == TSDB_FUNC_DERIVATIVE) {
+ if (pExpr->base.functionId == TSDB_FUNC_IRATE) {
return true;
}
}
@@ -516,7 +514,7 @@ bool isSimpleAggregateRv(SQueryInfo* pQueryInfo) {
return false;
}
- if (tscIsDiffQuery(pQueryInfo)) {
+ if (tscIsDiffDerivQuery(pQueryInfo)) {
return false;
}
@@ -3495,6 +3493,7 @@ static void tscSubqueryRetrieveCallback(void* param, TAOS_RES* tres, int code) {
if (pSql->res.code == TSDB_CODE_SUCCESS) {
(*pSql->fp)(pParentSql->param, pParentSql, pParentSql->res.numOfRows);
} else {
+ pParentSql->res.code = pSql->res.code;
tscAsyncResultOnError(pParentSql);
}
}
@@ -4260,7 +4259,7 @@ int32_t tscCreateQueryFromQueryInfo(SQueryInfo* pQueryInfo, SQueryAttr* pQueryAt
pQueryAttr->hasTagResults = hasTagValOutput(pQueryInfo);
pQueryAttr->stabledev = isStabledev(pQueryInfo);
pQueryAttr->tsCompQuery = isTsCompQuery(pQueryInfo);
- pQueryAttr->diffQuery = tscIsDiffQuery(pQueryInfo);
+ pQueryAttr->diffQuery = tscIsDiffDerivQuery(pQueryInfo);
pQueryAttr->simpleAgg = isSimpleAggregateRv(pQueryInfo);
pQueryAttr->needReverseScan = tscNeedReverseScan(pQueryInfo);
pQueryAttr->stableQuery = QUERY_IS_STABLE_QUERY(pQueryInfo->type);
diff --git a/src/client/tests/CMakeLists.txt b/src/client/tests/CMakeLists.txt
index f07af85e25..1a6c45aade 100644
--- a/src/client/tests/CMakeLists.txt
+++ b/src/client/tests/CMakeLists.txt
@@ -7,7 +7,12 @@ FIND_LIBRARY(LIB_GTEST_STATIC_DIR libgtest.a /usr/lib/ /usr/local/lib)
IF (HEADER_GTEST_INCLUDE_DIR AND LIB_GTEST_STATIC_DIR)
MESSAGE(STATUS "gTest library found, build unit test")
- INCLUDE_DIRECTORIES(${HEADER_GTEST_INCLUDE_DIR})
+ # GoogleTest requires at least C++11
+ SET(CMAKE_CXX_STANDARD 11)
+
+ INCLUDE_DIRECTORIES(/usr/include /usr/local/include)
+ LINK_DIRECTORIES(/usr/lib /usr/local/lib)
+
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_LIST)
ADD_EXECUTABLE(cliTest ${SOURCE_LIST})
diff --git a/src/connector/jdbc/CMakeLists.txt b/src/connector/jdbc/CMakeLists.txt
index a04902a422..1db8361faf 100644
--- a/src/connector/jdbc/CMakeLists.txt
+++ b/src/connector/jdbc/CMakeLists.txt
@@ -8,9 +8,8 @@ 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.30.jar ${LIBRARY_OUTPUT_PATH}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.31.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})
-ENDIF ()
-
+ENDIF ()
\ No newline at end of file
diff --git a/src/connector/jdbc/deploy-pom.xml b/src/connector/jdbc/deploy-pom.xml
index 657645d46c..8f77582d30 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.30
+ 2.0.31
jar
JDBCDriver
diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml
index 96e17bcd9b..a3a36d54cf 100644
--- 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.30
+ 2.0.31
jar
JDBCDriver
https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc
@@ -122,7 +122,7 @@
**/FailOverTest.java
**/InvalidResultSetPointerTest.java
**/RestfulConnectionTest.java
- **/TD4144Test.java
+ **/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java
true
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 2970f6c2d3..686ef36262 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
@@ -1,5 +1,7 @@
package com.taosdata.jdbc;
+import com.taosdata.jdbc.rs.enums.TimestampFormat;
+
import java.sql.*;
import java.util.Enumeration;
import java.util.Map;
@@ -18,7 +20,7 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
for (String propName : propNames) {
clientInfoProps.setProperty(propName, properties.getProperty(propName));
}
- String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, "STRING");
+ String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, String.valueOf(TimestampFormat.STRING));
clientInfoProps.setProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, timestampFormat);
}
@@ -516,7 +518,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
public void abort(Executor executor) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
-
// do nothing
}
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 9dc559339a..8b6c074d1b 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,8 +9,6 @@ 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/TSDBError.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java
index 90967b3620..411a61eb86 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java
@@ -32,6 +32,7 @@ public class TSDBError {
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_SQL, "invalid sql");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE, "numeric value out of range");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE, "unknown taos type in tdengine");
+ TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TIMESTAMP_PERCISION, "unknown timestamp precision");
/**************************************************/
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown error");
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java
index c978bb3a2e..9f0ba5afab 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java
@@ -25,6 +25,7 @@ public class TSDBErrorNumbers {
public static final int ERROR_INVALID_SQL = 0x2313; // invalid sql
public static final int ERROR_NUMERIC_VALUE_OUT_OF_RANGE = 0x2314; // numeric value out of range
public static final int ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE = 0x2315; //unknown taos type in tdengine
+ public static final int ERROR_UNKNOWN_TIMESTAMP_PERCISION = 0x2316; // unknown timestamp precision
public static final int ERROR_UNKNOWN = 0x2350; //unknown error
@@ -62,6 +63,7 @@ public class TSDBErrorNumbers {
errorNumbers.add(ERROR_INVALID_SQL);
errorNumbers.add(ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
errorNumbers.add(ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
+ errorNumbers.add(ERROR_UNKNOWN_TIMESTAMP_PERCISION);
/*****************************************************/
errorNumbers.add(ERROR_SUBSCRIBE_FAILED);
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java
index 92792d9751..bc4d58785a 100755
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java
@@ -216,6 +216,16 @@ public class TSDBJNIConnector {
private native int fetchBlockImp(long connection, long resultSet, TSDBResultSetBlockData blockData);
+ /**
+ * Get Result Time Precision.
+ * @return 0: ms, 1: us, 2: ns
+ */
+ public int getResultTimePrecision(long sqlObj) {
+ return this.getResultTimePrecisionImp(this.taos, sqlObj);
+ }
+
+ private native int getResultTimePrecisionImp(long connection, long result);
+
/**
* Execute close operation from C to release connection pointer by JNI
*
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 c3d5abf35c..1a007156e9 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
@@ -38,7 +38,6 @@ import java.util.regex.Pattern;
public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement {
private String rawSql;
private Object[] parameters;
- private boolean isPrepared;
private ArrayList colData;
private ArrayList tableTags;
@@ -47,8 +46,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
private String tableName;
private long nativeStmtHandle = 0;
- private volatile TSDBParameterMetaData parameterMetaData;
-
TSDBPreparedStatement(TSDBConnection connection, String sql) {
super(connection);
init(sql);
@@ -61,7 +58,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
}
}
parameters = new Object[parameterCnt];
- this.isPrepared = true;
}
if (parameterCnt > 1) {
@@ -76,11 +72,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
preprocessSql();
}
- @Override
- public int[] executeBatch() throws SQLException {
- return super.executeBatch();
- }
-
/*
* Some of the SQLs sent by other popular frameworks or tools like Spark, contains syntax that cannot be parsed by
* the TDengine client. Thus, some simple parsers/filters are intentionally added in this JDBC implementation in
@@ -137,29 +128,15 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
/***** for inner queries *****/
}
- /**
- * Populate parameters into prepared sql statements
- *
- * @return a string of the native sql statement for TSDB
- */
- private String getNativeSql(String rawSql) throws SQLException {
- return Utils.getNativeSql(rawSql, this.parameters);
- }
-
@Override
public ResultSet executeQuery() throws SQLException {
- if (!isPrepared)
- return executeQuery(this.rawSql);
-
- final String sql = getNativeSql(this.rawSql);
+ final String sql = Utils.getNativeSql(this.rawSql, this.parameters);
return executeQuery(sql);
}
@Override
public int executeUpdate() throws SQLException {
- if (!isPrepared)
- return executeUpdate(this.rawSql);
- String sql = getNativeSql(this.rawSql);
+ String sql = Utils.getNativeSql(this.rawSql, this.parameters);
return executeUpdate(sql);
}
@@ -282,25 +259,14 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
@Override
public boolean execute() throws SQLException {
- if (!isPrepared)
- return execute(this.rawSql);
-
- final String sql = getNativeSql(this.rawSql);
+ final String sql = Utils.getNativeSql(this.rawSql, this.parameters);
return execute(sql);
}
@Override
public void addBatch() throws SQLException {
- if (this.batchedArgs == null) {
- batchedArgs = new ArrayList<>();
- }
-
- if (!isPrepared) {
- addBatch(this.rawSql);
- } else {
- String sql = this.getConnection().nativeSQL(this.rawSql);
- addBatch(sql);
- }
+ String sql = Utils.getNativeSql(this.rawSql, this.parameters);
+ addBatch(sql);
}
@Override
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 01104440ab..e00ec1e758 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
@@ -147,30 +147,14 @@ public class TSDBResultSetRowData {
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
return Integer.parseInt((String) obj);
- case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
- Byte value = (byte) obj;
- if (value < 0)
- throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
- return value;
- }
- case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: {
- short value = (short) obj;
- if (value < 0)
- throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
- return value;
- }
- case TSDBConstants.TSDB_DATA_TYPE_UINT: {
- int value = (int) obj;
- if (value < 0)
- throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
- return value;
- }
- case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
- long value = (long) obj;
- if (value < 0)
- throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
- return Long.valueOf(value).intValue();
- }
+ case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
+ return parseUnsignedTinyIntToInt(obj);
+ case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
+ return parseUnsignedSmallIntToInt(obj);
+ case TSDBConstants.TSDB_DATA_TYPE_UINT:
+ return parseUnsignedIntegerToInt(obj);
+ case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
+ return parseUnsignedBigIntToInt(obj);
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return ((Float) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
@@ -180,6 +164,35 @@ public class TSDBResultSetRowData {
}
}
+ private byte parseUnsignedTinyIntToInt(Object obj) throws SQLException {
+ byte value = (byte) obj;
+ if (value < 0)
+ throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
+ return value;
+ }
+
+ private short parseUnsignedSmallIntToInt(Object obj) throws SQLException {
+ short value = (short) obj;
+ if (value < 0)
+ throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
+ return value;
+ }
+
+ private int parseUnsignedIntegerToInt(Object obj) throws SQLException {
+ int value = (int) obj;
+ if (value < 0)
+ throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
+ return value;
+ }
+
+ private int parseUnsignedBigIntToInt(Object obj) throws SQLException {
+ long value = (long) obj;
+ if (value < 0)
+ throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
+ return Long.valueOf(value).intValue();
+ }
+
+
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
*/
@@ -216,7 +229,7 @@ public class TSDBResultSetRowData {
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
return Long.parseLong((String) obj);
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
- Byte value = (byte) obj;
+ byte value = (byte) obj;
if (value < 0)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
return value;
@@ -414,26 +427,40 @@ public class TSDBResultSetRowData {
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
*/
public void setTimestampValue(int colIndex, long value) {
- setTimestamp(colIndex - 1, value);
+ setTimestamp(colIndex - 1, value, 0);
}
/**
* !!! this method is invoked by JNI method and the index start from 0 in C implementations
+ * @param precision 0 : ms, 1 : us, 2 : ns
*/
- public void setTimestamp(int col, long ts) {
- //TODO: this implementation contains logical error
- // when precision is us the (long ts) is 16 digital number
- // when precision is ms, the (long ts) is 13 digital number
- // we need a JNI function like this:
- // public void setTimestamp(int col, long epochSecond, long nanoAdjustment)
- if (ts < 1_0000_0000_0000_0L) {
- data.set(col, new Timestamp(ts));
- } else {
- long epochSec = ts / 1000_000l;
- long nanoAdjustment = ts % 1000_000l * 1000l;
- Timestamp timestamp = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
- data.set(col, timestamp);
+ public void setTimestamp(int col, long ts, int precision) {
+ long milliseconds = 0;
+ int fracNanoseconds = 0;
+ switch (precision) {
+ case 0: {
+ milliseconds = ts;
+ fracNanoseconds = (int)(ts*1_000_000%1_000_000_000);
+ break;
+ }
+ case 1: {
+ milliseconds = ts/1_000;
+ fracNanoseconds = (int)(ts*1_000%1_000_000_000);
+ break;
+ }
+ case 2: {
+ milliseconds = ts/1_000_000;
+ fracNanoseconds = (int)(ts%1_000_000_000);
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("precision is not valid. precision: " + precision);
+ }
}
+
+ Timestamp tsObj = new Timestamp(milliseconds);
+ tsObj.setNanos(fracNanoseconds);
+ data.set(col, tsObj);
}
public Timestamp getTimestamp(int col, int nativeType) {
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java
new file mode 100644
index 0000000000..79350076c7
--- /dev/null
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java
@@ -0,0 +1,8 @@
+package com.taosdata.jdbc.enums;
+
+public enum TimestampPrecision {
+ MS,
+ US,
+ NS,
+ UNKNOWN
+}
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 b810f9aeb5..d6a02b7e3a 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
@@ -17,16 +17,18 @@ public class RestfulConnection extends AbstractConnection {
private final int port;
private final String url;
private volatile String database;
+ private final String token;
/******************************************************/
private boolean isClosed;
private final DatabaseMetaData metadata;
- public RestfulConnection(String host, String port, Properties props, String database, String url) {
+ public RestfulConnection(String host, String port, Properties props, String database, String url, String token) {
super(props);
this.host = host;
this.port = Integer.parseInt(port);
this.database = database;
this.url = url;
+ this.token = token;
this.metadata = new RestfulDatabaseMetaData(url, props.getProperty(TSDBDriver.PROPERTY_KEY_USER), this);
}
@@ -66,6 +68,7 @@ public class RestfulConnection extends AbstractConnection {
return this.metadata;
}
+ // getters
public String getHost() {
return host;
}
@@ -81,4 +84,8 @@ public class RestfulConnection extends AbstractConnection {
public String getUrl() {
return url;
}
+
+ public String getToken() {
+ return token;
+ }
}
\ No newline at end of file
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..9ab67c5502 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
@@ -38,15 +38,11 @@ public class RestfulDriver extends AbstractDriver {
String port = props.getProperty(TSDBDriver.PROPERTY_KEY_PORT, "6041");
String database = props.containsKey(TSDBDriver.PROPERTY_KEY_DBNAME) ? props.getProperty(TSDBDriver.PROPERTY_KEY_DBNAME) : null;
- String loginUrl = "http://" + props.getProperty(TSDBDriver.PROPERTY_KEY_HOST) + ":"
- + props.getProperty(TSDBDriver.PROPERTY_KEY_PORT) + "/rest/login/"
- + props.getProperty(TSDBDriver.PROPERTY_KEY_USER) + "/"
- + props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD) + "";
+ String loginUrl = "http://" + host + ":" + port + "/rest/login/" + props.getProperty(TSDBDriver.PROPERTY_KEY_USER) + "/" + props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD) + "";
try {
String user = URLEncoder.encode(props.getProperty(TSDBDriver.PROPERTY_KEY_USER), "UTF-8");
String password = URLEncoder.encode(props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD), "UTF-8");
- loginUrl = "http://" + props.getProperty(TSDBDriver.PROPERTY_KEY_HOST) + ":"
- + props.getProperty(TSDBDriver.PROPERTY_KEY_PORT) + "/rest/login/" + user + "/" + password + "";
+ loginUrl = "http://" + props.getProperty(TSDBDriver.PROPERTY_KEY_HOST) + ":" + props.getProperty(TSDBDriver.PROPERTY_KEY_PORT) + "/rest/login/" + user + "/" + password + "";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
@@ -55,12 +51,12 @@ public class RestfulDriver extends AbstractDriver {
JSONObject jsonResult = JSON.parseObject(result);
String status = jsonResult.getString("status");
String token = jsonResult.getString("desc");
- HttpClientPoolUtil.token = token;
+
if (!status.equals("succ")) {
throw new SQLException(jsonResult.getString("desc"));
}
- RestfulConnection conn = new RestfulConnection(host, port, props, database, url);
+ RestfulConnection conn = new RestfulConnection(host, port, props, database, url, token);
if (database != null && !database.trim().replaceAll("\\s", "").isEmpty()) {
Statement stmt = conn.createStatement();
stmt.execute("use " + database);
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 f58e3f8cd2..16272f4289 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
@@ -44,7 +44,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
if (!isPrepared)
return executeQuery(this.rawSql);
- final String sql = getNativeSql(this.rawSql);
+ final String sql = Utils.getNativeSql(this.rawSql, this.parameters);
return executeQuery(sql);
}
@@ -55,20 +55,10 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
if (!isPrepared)
return executeUpdate(this.rawSql);
- final String sql = getNativeSql(this.rawSql);
+ final String sql = Utils.getNativeSql(rawSql, this.parameters);
return executeUpdate(sql);
}
- /****
- * 将rawSql转换成一条可执行的sql语句,使用属性parameters中的变脸进行替换
- * 对于insert into ?.? (?,?,?) using ?.? (?,?,?) tags(?, ?, ?) values(?, ?, ?)
- * @param rawSql,可能是insert、select或其他,使用?做占位符
- * @return
- */
- private String getNativeSql(String rawSql) {
- return Utils.getNativeSql(rawSql, this.parameters);
- }
-
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
if (isClosed())
@@ -224,16 +214,13 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
if (!isPrepared)
return execute(this.rawSql);
- final String sql = getNativeSql(rawSql);
+ final String sql = Utils.getNativeSql(rawSql, this.parameters);
return execute(sql);
}
@Override
public void addBatch() throws SQLException {
- if (isClosed())
- throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
-
- final String sql = getNativeSql(this.rawSql);
+ final String sql = Utils.getNativeSql(rawSql, this.parameters);
addBatch(sql);
}
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 530b433d42..13850f0b80 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
@@ -6,6 +6,8 @@ import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.taosdata.jdbc.*;
+import com.taosdata.jdbc.enums.TimestampPrecision;
+import com.taosdata.jdbc.rs.enums.TimestampFormat;
import com.taosdata.jdbc.utils.Utils;
import java.math.BigDecimal;
@@ -46,6 +48,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
columnNames.clear();
columns.clear();
this.resultSet.clear();
+ this.metaData = new RestfulResultSetMetaData(this.database, null, this);
return;
}
// get head
@@ -131,7 +134,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
}
}
-
private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException {
switch (taosType) {
case TSDBConstants.TSDB_DATA_TYPE_NULL:
@@ -150,44 +152,8 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
return row.getFloat(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
return row.getDouble(colIndex);
- case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
- if (row.get(colIndex) == null)
- return null;
- String timestampFormat = this.statement.getConnection().getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT);
- if ("TIMESTAMP".equalsIgnoreCase(timestampFormat)) {
- Long value = row.getLong(colIndex);
- //TODO: this implementation has bug if the timestamp bigger than 9999_9999_9999_9
- if (value < 1_0000_0000_0000_0L)
- return new Timestamp(value);
- long epochSec = value / 1000_000l;
- long nanoAdjustment = value % 1000_000l * 1000l;
- return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
- }
- if ("UTC".equalsIgnoreCase(timestampFormat)) {
- String value = row.getString(colIndex);
- long epochSec = Timestamp.valueOf(value.substring(0, 19).replace("T", " ")).getTime() / 1000;
- int fractionalSec = Integer.parseInt(value.substring(20, value.length() - 5));
- long nanoAdjustment = 0;
- if (value.length() > 28) {
- // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00
- nanoAdjustment = fractionalSec * 1000l;
- } else {
- // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00
- nanoAdjustment = fractionalSec * 1000_000l;
- }
- ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5));
- Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant();
- return Timestamp.from(instant);
- }
- String value = row.getString(colIndex);
- if (value.length() <= 23) // ms timestamp: yyyy-MM-dd HH:mm:ss.SSS
- return row.getTimestamp(colIndex);
- // us timestamp: yyyy-MM-dd HH:mm:ss.SSSSSS
- long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000;
- long nanoAdjustment = Integer.parseInt(value.substring(20)) * 1000l;
- Timestamp timestamp = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
- return timestamp;
- }
+ case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
+ return parseTimestampColumnData(row, colIndex);
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
return row.getString(colIndex) == null ? null : row.getString(colIndex).getBytes();
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
@@ -197,7 +163,66 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
}
}
- public class Field {
+ private Timestamp parseTimestampColumnData(JSONArray row, int colIndex) throws SQLException {
+ if (row.get(colIndex) == null)
+ return null;
+ String tsFormatUpperCase = this.statement.getConnection().getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT).toUpperCase();
+ TimestampFormat timestampFormat = TimestampFormat.valueOf(tsFormatUpperCase);
+ switch (timestampFormat) {
+ case TIMESTAMP: {
+ Long value = row.getLong(colIndex);
+ //TODO: this implementation has bug if the timestamp bigger than 9999_9999_9999_9
+ if (value < 1_0000_0000_0000_0L)
+ return new Timestamp(value);
+ long epochSec = value / 1000_000l;
+ long nanoAdjustment = value % 1000_000l * 1000l;
+ return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+ }
+ case UTC: {
+ String value = row.getString(colIndex);
+ long epochSec = Timestamp.valueOf(value.substring(0, 19).replace("T", " ")).getTime() / 1000;
+ int fractionalSec = Integer.parseInt(value.substring(20, value.length() - 5));
+ long nanoAdjustment;
+ if (value.length() > 31) {
+ // ns timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSSSSS+0x00
+ nanoAdjustment = fractionalSec;
+ } else if (value.length() > 28) {
+ // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00
+ nanoAdjustment = fractionalSec * 1000L;
+ } else {
+ // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00
+ nanoAdjustment = fractionalSec * 1000_000L;
+ }
+ ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5));
+ Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant();
+ return Timestamp.from(instant);
+ }
+ case STRING:
+ default: {
+ String value = row.getString(colIndex);
+ TimestampPrecision precision = Utils.guessTimestampPrecision(value);
+ if (precision == TimestampPrecision.MS) {
+ // ms timestamp: yyyy-MM-dd HH:mm:ss.SSS
+ return row.getTimestamp(colIndex);
+ }
+ if (precision == TimestampPrecision.US) {
+ // us timestamp: yyyy-MM-dd HH:mm:ss.SSSSSS
+ long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000;
+ long nanoAdjustment = Integer.parseInt(value.substring(20)) * 1000L;
+ return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+ }
+ if (precision == TimestampPrecision.NS) {
+ // ms timestamp: yyyy-MM-dd HH:mm:ss.SSSSSSSSS
+ long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000;
+ long nanoAdjustment = Integer.parseInt(value.substring(20));
+ return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+ }
+ throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TIMESTAMP_PERCISION);
+ }
+ }
+ }
+
+ public static class Field {
String name;
int type;
int length;
@@ -211,6 +236,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
this.note = note;
this.taos_type = taos_type;
}
+
}
@Override
@@ -334,6 +360,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
wasNull = true;
return 0;
}
+
wasNull = false;
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java
index 7ead8bd1bb..a185abb709 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java
@@ -8,20 +8,22 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
public class RestfulResultSetMetaData extends WrapperImpl implements ResultSetMetaData {
private final String database;
- private ArrayList fields;
+ private List fields;
private final RestfulResultSet resultSet;
public RestfulResultSetMetaData(String database, ArrayList fields, RestfulResultSet resultSet) {
this.database = database;
- this.fields = fields;
+ this.fields = fields == null ? Collections.emptyList() : fields;
this.resultSet = resultSet;
}
- public ArrayList getFields() {
+ public List getFields() {
return fields;
}
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
index fbc3a50a27..e9d193f6b4 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
@@ -83,7 +83,7 @@ public class RestfulStatement extends AbstractStatement {
}
if (SqlSyntaxValidator.isUseSql(sql)) {
- HttpClientPoolUtil.execute(url, sql);
+ HttpClientPoolUtil.execute(url, sql, this.conn.getToken());
this.database = sql.trim().replace("use", "").trim();
this.conn.setCatalog(this.database);
result = false;
@@ -116,7 +116,7 @@ public class RestfulStatement extends AbstractStatement {
if ("UTC".equalsIgnoreCase(timestampFormat))
url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlutc";
- String result = HttpClientPoolUtil.execute(url, sql);
+ String result = HttpClientPoolUtil.execute(url, sql, this.conn.getToken());
JSONObject resultJson = JSON.parseObject(result);
if (resultJson.getString("status").equals("error")) {
throw TSDBError.createSQLException(resultJson.getInteger("code"), resultJson.getString("desc"));
@@ -130,7 +130,7 @@ public class RestfulStatement extends AbstractStatement {
if (!SqlSyntaxValidator.isValidForExecuteUpdate(sql))
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_UPDATE, "not a valid sql for executeUpdate: " + sql);
- String result = HttpClientPoolUtil.execute(url, sql);
+ String result = HttpClientPoolUtil.execute(url, sql, this.conn.getToken());
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject.getString("status").equals("error")) {
throw TSDBError.createSQLException(jsonObject.getInteger("code"), jsonObject.getString("desc"));
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java
new file mode 100644
index 0000000000..edc429857e
--- /dev/null
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java
@@ -0,0 +1,7 @@
+package com.taosdata.jdbc.rs.enums;
+
+public enum TimestampFormat {
+ STRING,
+ TIMESTAMP,
+ UTC
+}
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java
index 5e2440fd1d..ff27bdbdad 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java
@@ -16,43 +16,32 @@ import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
public class HttpClientPoolUtil {
- public static PoolingHttpClientConnectionManager cm = null;
- public static CloseableHttpClient httpClient = null;
- public static String token = "cm9vdDp0YW9zZGF0YQ==";
- /**
- * 默认content 类型
- */
- private static final String DEFAULT_CONTENT_TYPE = "application/json";
- /**
- * 默认请求超时时间30s
- */
- private static final int DEFAULT_TIME_OUT = 15000;
- private static final int count = 32;
- private static final int totalCount = 1000;
- private static final int Http_Default_Keep_Time = 15000;
- /**
- * 初始化连接池
- */
+ private static final String DEFAULT_CONTENT_TYPE = "application/json";
+ private static final int DEFAULT_TIME_OUT = 15000;
+ private static final int DEFAULT_MAX_PER_ROUTE = 32;
+ private static final int DEFAULT_MAX_TOTAL = 1000;
+ private static final int DEFAULT_HTTP_KEEP_TIME = 15000;
+
+ private static PoolingHttpClientConnectionManager connectionManager;
+ private static CloseableHttpClient httpClient;
+
private static synchronized void initPools() {
if (httpClient == null) {
- cm = new PoolingHttpClientConnectionManager();
- cm.setDefaultMaxPerRoute(count);
- cm.setMaxTotal(totalCount);
- httpClient = HttpClients.custom().setKeepAliveStrategy(defaultStrategy).setConnectionManager(cm).build();
+ connectionManager = new PoolingHttpClientConnectionManager();
+ connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
+ connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL);
+ httpClient = HttpClients.custom().setKeepAliveStrategy(DEFAULT_KEEP_ALIVE_STRATEGY).setConnectionManager(connectionManager).build();
}
}
- /**
- * Http connection keepAlive 设置
- */
- private static ConnectionKeepAliveStrategy defaultStrategy = (response, context) -> {
+ private static ConnectionKeepAliveStrategy DEFAULT_KEEP_ALIVE_STRATEGY = (response, context) -> {
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
- int keepTime = Http_Default_Keep_Time * 1000;
+ int keepTime = DEFAULT_HTTP_KEEP_TIME * 1000;
while (it.hasNext()) {
HeaderElement headerElement = it.nextElement();
String param = headerElement.getName();
@@ -76,7 +65,7 @@ public class HttpClientPoolUtil {
* @param data 请求数据
* @return responseBody
*/
- public static String execute(String uri, String data) {
+ public static String execute(String uri, String data, String token) {
long startTime = System.currentTimeMillis();
HttpEntity httpEntity = null;
HttpEntityEnclosingRequestBase method = null;
@@ -90,7 +79,7 @@ public class HttpClientPoolUtil {
method.setHeader("Connection", "keep-alive");
method.setHeader("Authorization", "Taosd " + token);
- method.setEntity(new StringEntity(data, Charset.forName("UTF-8")));
+ method.setEntity(new StringEntity(data, StandardCharsets.UTF_8));
HttpContext context = HttpClientContext.create();
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
httpEntity = httpResponse.getEntity();
@@ -175,28 +164,18 @@ public class HttpClientPoolUtil {
httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
responseBody = EntityUtils.toString(httpEntity, "UTF-8");
-// logger.info("请求URL: " + uri + "+ 返回状态码:" + httpResponse.getStatusLine().getStatusCode());
}
} catch (Exception e) {
if (method != null) {
method.abort();
}
e.printStackTrace();
-// logger.error("execute get request exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):"
-// + (System.currentTimeMillis() - startTime));
- System.out.println("log:调用 HttpClientPoolUtil execute get request exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):"
- + (System.currentTimeMillis() - startTime));
} finally {
if (httpEntity != null) {
try {
EntityUtils.consumeQuietly(httpEntity);
} catch (Exception e) {
-// e.printStackTrace();
-// logger.error("close response exception, url:" + uri + ", exception:" + e.toString()
-// + ",cost time(ms):" + (System.currentTimeMillis() - startTime));
- new Exception("close response exception, url:" + uri + ", exception:" + e.toString()
- + ",cost time(ms):" + (System.currentTimeMillis() - startTime))
- .printStackTrace();
+ new Exception("close response exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):" + (System.currentTimeMillis() - startTime)).printStackTrace();
}
}
}
diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java
index 8ab610fec6..4c92d27a28 100644
--- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java
+++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java
@@ -3,14 +3,13 @@ package com.taosdata.jdbc.utils;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
+import com.taosdata.jdbc.enums.TimestampPrecision;
import java.nio.charset.Charset;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
-import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
@@ -25,39 +24,52 @@ public class Utils {
private static Pattern ptn = Pattern.compile(".*?'");
- private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
- .appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter();
- private static final DateTimeFormatter formatter2 = new DateTimeFormatterBuilder()
- .appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").toFormatter();
+ private static final DateTimeFormatter milliSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter();
+ private static final DateTimeFormatter microSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").toFormatter();
+ private static final DateTimeFormatter nanoSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS").toFormatter();
public static Time parseTime(String timestampStr) throws DateTimeParseException {
- LocalTime time;
- try {
- time = LocalTime.parse(timestampStr, formatter);
- } catch (DateTimeParseException e) {
- time = LocalTime.parse(timestampStr, formatter2);
- }
- return Time.valueOf(time);
+ LocalDateTime dateTime = parseLocalDateTime(timestampStr);
+ return dateTime != null ? Time.valueOf(dateTime.toLocalTime()) : null;
}
- public static Date parseDate(String timestampStr) throws DateTimeParseException {
- LocalDate date;
- try {
- date = LocalDate.parse(timestampStr, formatter);
- } catch (DateTimeParseException e) {
- date = LocalDate.parse(timestampStr, formatter2);
- }
- return Date.valueOf(date);
+ public static Date parseDate(String timestampStr) {
+ LocalDateTime dateTime = parseLocalDateTime(timestampStr);
+ return dateTime != null ? Date.valueOf(String.valueOf(dateTime)) : null;
}
public static Timestamp parseTimestamp(String timeStampStr) {
- LocalDateTime dateTime;
+ LocalDateTime dateTime = parseLocalDateTime(timeStampStr);
+ return dateTime != null ? Timestamp.valueOf(dateTime) : null;
+ }
+
+ private static LocalDateTime parseLocalDateTime(String timeStampStr) {
try {
- dateTime = LocalDateTime.parse(timeStampStr, formatter);
+ return parseMilliSecTimestamp(timeStampStr);
} catch (DateTimeParseException e) {
- dateTime = LocalDateTime.parse(timeStampStr, formatter2);
+ try {
+ return parseMicroSecTimestamp(timeStampStr);
+ } catch (DateTimeParseException ee) {
+ try {
+ return parseNanoSecTimestamp(timeStampStr);
+ } catch (DateTimeParseException eee) {
+ eee.printStackTrace();
+ }
+ }
}
- return Timestamp.valueOf(dateTime);
+ return null;
+ }
+
+ private static LocalDateTime parseMilliSecTimestamp(String timeStampStr) throws DateTimeParseException {
+ return LocalDateTime.parse(timeStampStr, milliSecFormatter);
+ }
+
+ private static LocalDateTime parseMicroSecTimestamp(String timeStampStr) throws DateTimeParseException {
+ return LocalDateTime.parse(timeStampStr, microSecFormatter);
+ }
+
+ private static LocalDateTime parseNanoSecTimestamp(String timeStampStr) throws DateTimeParseException {
+ return LocalDateTime.parse(timeStampStr, nanoSecFormatter);
}
public static String escapeSingleQuota(String origin) {
@@ -93,6 +105,8 @@ public class Utils {
}
public static String getNativeSql(String rawSql, Object[] parameters) {
+ if (parameters == null || !rawSql.contains("?"))
+ return rawSql;
// toLowerCase
String preparedSql = rawSql.trim().toLowerCase();
String[] clause = new String[]{"values\\s*\\(.*?\\)", "tags\\s*\\(.*?\\)", "where\\s*.*"};
@@ -167,13 +181,47 @@ public class Utils {
}).collect(Collectors.joining());
}
-
public static String formatTimestamp(Timestamp timestamp) {
int nanos = timestamp.getNanos();
if (nanos % 1000000l != 0)
- return timestamp.toLocalDateTime().format(formatter2);
- return timestamp.toLocalDateTime().format(formatter);
+ return timestamp.toLocalDateTime().format(microSecFormatter);
+ return timestamp.toLocalDateTime().format(milliSecFormatter);
}
+ public static TimestampPrecision guessTimestampPrecision(String value) {
+ if (isMilliSecFormat(value))
+ return TimestampPrecision.MS;
+ if (isMicroSecFormat(value))
+ return TimestampPrecision.US;
+ if (isNanoSecFormat(value))
+ return TimestampPrecision.NS;
+ return TimestampPrecision.UNKNOWN;
+ }
+ private static boolean isMilliSecFormat(String timestampStr) {
+ try {
+ milliSecFormatter.parse(timestampStr);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isMicroSecFormat(String timestampStr) {
+ try {
+ microSecFormatter.parse(timestampStr);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isNanoSecFormat(String timestampStr) {
+ try {
+ nanoSecFormatter.parse(timestampStr);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBJNIConnectorTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBJNIConnectorTest.java
index 66078ef503..b5f8114bff 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBJNIConnectorTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBJNIConnectorTest.java
@@ -1,12 +1,17 @@
package com.taosdata.jdbc;
import org.junit.Test;
+import static org.junit.Assert.*;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.List;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+
public class TSDBJNIConnectorTest {
private static TSDBResultSetRowData rowData;
@@ -14,17 +19,68 @@ public class TSDBJNIConnectorTest {
@Test
public void test() {
try {
+
+ try {
+ //change sleepSeconds when debugging with attach to process to find PID
+ int sleepSeconds = -1;
+ if (sleepSeconds>0) {
+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
+ String jvmName = runtimeBean.getName();
+ long pid = Long.valueOf(jvmName.split("@")[0]);
+ System.out.println("JVM PID = " + pid);
+
+ Thread.sleep(sleepSeconds*1000);
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+
// init
- TSDBJNIConnector.init("/etc/taos/taos.cfg", null, null, null);
+ TSDBJNIConnector.init("/etc/taos", null, null, null);
+
// connect
TSDBJNIConnector connector = new TSDBJNIConnector();
- connector.connect("127.0.0.1", 6030, "unsign_jni", "root", "taosdata");
+ connector.connect("127.0.0.1", 6030, null, "root", "taosdata");
+
+ // setup
+ String setupSqlStrs[] = {"create database if not exists d precision \"us\"",
+ "create table if not exists d.t(ts timestamp, f int)",
+ "create database if not exists d2",
+ "create table if not exists d2.t2(ts timestamp, f int)",
+ "insert into d.t values(now+100s, 100)",
+ "insert into d2.t2 values(now+200s, 200)"
+ };
+ for (String setupSqlStr : setupSqlStrs) {
+ long setupSql = connector.executeQuery(setupSqlStr);
+
+ assertEquals(0, connector.getResultTimePrecision(setupSql));
+ if (connector.isUpdateQuery(setupSql)) {
+ connector.freeResultSet(setupSql);
+ }
+ }
+
+ {
+ long sqlObj1 = connector.executeQuery("select * from d2.t2");
+ assertEquals(0, connector.getResultTimePrecision(sqlObj1));
+ List columnMetaDataList = new ArrayList<>();
+ int code = connector.getSchemaMetaData(sqlObj1, columnMetaDataList);
+ rowData = new TSDBResultSetRowData(columnMetaDataList.size());
+ assertTrue(next(connector, sqlObj1));
+ assertEquals(0, connector.getResultTimePrecision(sqlObj1));
+ connector.freeResultSet(sqlObj1);
+ }
+
// executeQuery
- long pSql = connector.executeQuery("select * from unsign_jni.us_table");
+ long pSql = connector.executeQuery("select * from d.t");
+
if (connector.isUpdateQuery(pSql)) {
connector.freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
+
+ assertEquals(1, connector.getResultTimePrecision(pSql));
+
// get schema
List columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
@@ -37,6 +93,8 @@ public class TSDBJNIConnectorTest {
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
}
+
+ assertEquals(1, connector.getResultTimePrecision(pSql));
int columnSize = columnMetaDataList.size();
// print metadata
for (int i = 0; i < columnSize; i++) {
@@ -45,9 +103,8 @@ public class TSDBJNIConnectorTest {
rowData = new TSDBResultSetRowData(columnSize);
// iterate resultSet
for (int i = 0; next(connector, pSql); i++) {
-// System.out.println("col[" + i + "] size: " + rowData.getColSize());
-// rowData.getData().stream().forEach(col -> System.out.print(col + "\t"));
-// System.out.println();
+ assertEquals(1, connector.getResultTimePrecision(pSql));
+ System.out.println();
}
// close resultSet
code = connector.freeResultSet(pSql);
@@ -86,4 +143,4 @@ public class TSDBJNIConnectorTest {
}
}
-}
\ 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 3f8bef4a7e..40ff5c23ef 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,7 +5,6 @@ import org.junit.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.*;
-import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Random;
@@ -15,6 +14,7 @@ public class TSDBPreparedStatementTest {
private static Connection conn;
private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String sql_select = "select * from t1 where ts >= ? and ts < ? and f1 >= ?";
+ private static final String dbname = "test_pstmt_jni";
private PreparedStatement pstmt_insert;
private PreparedStatement pstmt_select;
@@ -299,53 +299,53 @@ public class TSDBPreparedStatementTest {
}
@Test
- public void executeTest() throws SQLException {
- Statement stmt = conn.createStatement();
+ public void executeTest() throws SQLException {
+ Statement stmt = conn.createStatement();
- int numOfRows = 1000;
+ int numOfRows = 1000;
- for (int loop = 0; loop < 10; loop++){
+ for (int loop = 0; loop < 10; loop++) {
stmt.execute("drop table if exists weather_test");
- stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))");
+ stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))");
TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? values(?, ?, ?, ?, ?, ?, ?, ?)");
Random r = new Random();
s.setTableName("weather_test");
-
+
ArrayList ts = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
+ for (int i = 0; i < numOfRows; i++) {
ts.add(System.currentTimeMillis() + i);
- }
+ }
s.setTimestamp(0, ts);
int random = 10 + r.nextInt(5);
- ArrayList s2 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ ArrayList s2 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s2.add(null);
- }else{
+ } else {
s2.add("分支" + i % 4);
}
- }
- s.setNString(1, s2, 4);
+ }
+ s.setNString(1, s2, 4);
random = 10 + r.nextInt(5);
- ArrayList s3 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ ArrayList s3 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s3.add(null);
- }else{
+ } else {
s3.add(r.nextFloat());
}
- }
+ }
s.setFloat(2, s3);
random = 10 + r.nextInt(5);
ArrayList s4 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s4.add(null);
- }else{
+ } else {
s4.add(r.nextDouble());
}
}
@@ -353,47 +353,47 @@ public class TSDBPreparedStatementTest {
random = 10 + r.nextInt(5);
ArrayList ts2 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
ts2.add(null);
- }else{
+ } else {
ts2.add(System.currentTimeMillis() + i);
}
}
s.setTimestamp(4, ts2);
random = 10 + r.nextInt(5);
- ArrayList vals = new ArrayList<>();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ ArrayList vals = new ArrayList<>();
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
vals.add(null);
- }else{
+ } else {
vals.add(r.nextInt());
- }
+ }
}
s.setInt(5, vals);
random = 10 + r.nextInt(5);
ArrayList sb = new ArrayList<>();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
sb.add(null);
- }else{
+ } else {
sb.add(i % 2 == 0 ? true : false);
}
}
- s.setBoolean(6, sb);
+ s.setBoolean(6, sb);
random = 10 + r.nextInt(5);
ArrayList s5 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s5.add(null);
- }else{
+ } else {
s5.add("test" + i % 10);
}
}
- s.setString(7, s5, 10);
+ s.setString(7, s5, 10);
s.columnDataAddBatch();
s.columnDataExecuteBatch();
@@ -403,54 +403,54 @@ public class TSDBPreparedStatementTest {
PreparedStatement statement = conn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
int rows = 0;
- while(rs.next()) {
+ while (rs.next()) {
rows++;
}
- Assert.assertEquals(numOfRows, rows);
+ Assert.assertEquals(numOfRows, rows);
}
}
@Test
- public void bindDataSelectColumnTest() throws SQLException {
- Statement stmt = conn.createStatement();
+ public void bindDataSelectColumnTest() throws SQLException {
+ Statement stmt = conn.createStatement();
- int numOfRows = 1000;
+ int numOfRows = 1000;
- for (int loop = 0; loop < 10; loop++){
+ for (int loop = 0; loop < 10; loop++) {
stmt.execute("drop table if exists weather_test");
- stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))");
+ stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))");
TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? (ts, f1, f7) values(?, ?, ?)");
Random r = new Random();
s.setTableName("weather_test");
-
+
ArrayList ts = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
+ for (int i = 0; i < numOfRows; i++) {
ts.add(System.currentTimeMillis() + i);
- }
+ }
s.setTimestamp(0, ts);
int random = 10 + r.nextInt(5);
- ArrayList s2 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ ArrayList s2 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s2.add(null);
- }else{
+ } else {
s2.add("分支" + i % 4);
}
- }
- s.setNString(1, s2, 4);
+ }
+ s.setNString(1, s2, 4);
random = 10 + r.nextInt(5);
ArrayList s3 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- if(i % random == 0) {
+ for (int i = 0; i < numOfRows; i++) {
+ if (i % random == 0) {
s3.add(null);
- }else{
+ } else {
s3.add("test" + i % 10);
}
}
- s.setString(2, s3, 10);
+ s.setString(2, s3, 10);
s.columnDataAddBatch();
s.columnDataExecuteBatch();
@@ -460,30 +460,30 @@ public class TSDBPreparedStatementTest {
PreparedStatement statement = conn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
int rows = 0;
- while(rs.next()) {
+ while (rs.next()) {
rows++;
}
- Assert.assertEquals(numOfRows, rows);
+ Assert.assertEquals(numOfRows, rows);
}
}
@Test
- public void bindDataWithSingleTagTest() throws SQLException {
- Statement stmt = conn.createStatement();
+ public void bindDataWithSingleTagTest() throws SQLException {
+ Statement stmt = conn.createStatement();
- String types[] = new String[] {"tinyint", "smallint", "int", "bigint", "bool", "float", "double", "binary(10)", "nchar(10)"};
+ String types[] = new String[]{"tinyint", "smallint", "int", "bigint", "bool", "float", "double", "binary(10)", "nchar(10)"};
for (String type : types) {
stmt.execute("drop table if exists weather_test");
stmt.execute("create table weather_test(ts timestamp, f1 nchar(10), f2 binary(10)) tags (t " + type + ")");
int numOfRows = 1;
-
+
TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?) values(?, ?, ?)");
Random r = new Random();
s.setTableName("w1");
-
- switch(type) {
+
+ switch (type) {
case "tinyint":
case "smallint":
case "int":
@@ -508,37 +508,37 @@ public class TSDBPreparedStatementTest {
default:
break;
}
-
-
+
+
ArrayList ts = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
+ for (int i = 0; i < numOfRows; i++) {
ts.add(System.currentTimeMillis() + i);
- }
+ }
s.setTimestamp(0, ts);
-
+
int random = 10 + r.nextInt(5);
- ArrayList s2 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- s2.add("分支" + i % 4);
- }
+ ArrayList s2 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
+ s2.add("分支" + i % 4);
+ }
s.setNString(1, s2, 10);
-
+
random = 10 + r.nextInt(5);
- ArrayList s3 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
- s3.add("test" + i % 4);
- }
+ ArrayList s3 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
+ s3.add("test" + i % 4);
+ }
s.setString(2, s3, 10);
-
+
s.columnDataAddBatch();
s.columnDataExecuteBatch();
s.columnDataCloseBatch();
-
+
String sql = "select * from weather_test";
PreparedStatement statement = conn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
int rows = 0;
- while(rs.next()) {
+ while (rs.next()) {
rows++;
}
Assert.assertEquals(numOfRows, rows);
@@ -547,32 +547,32 @@ public class TSDBPreparedStatementTest {
@Test
- public void bindDataWithMultipleTagsTest() throws SQLException {
- Statement stmt = conn.createStatement();
-
+ public void bindDataWithMultipleTagsTest() throws SQLException {
+ Statement stmt = conn.createStatement();
+
stmt.execute("drop table if exists weather_test");
stmt.execute("create table weather_test(ts timestamp, f1 nchar(10), f2 binary(10)) tags (t1 int, t2 binary(10))");
int numOfRows = 1;
- TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?,?) (ts, f2) values(?, ?)");
- s.setTableName("w2");
+ TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?,?) (ts, f2) values(?, ?)");
+ s.setTableName("w2");
s.setTagInt(0, 1);
s.setTagString(1, "test");
-
-
+
+
ArrayList ts = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
+ for (int i = 0; i < numOfRows; i++) {
ts.add(System.currentTimeMillis() + i);
- }
+ }
s.setTimestamp(0, ts);
-
- ArrayList s2 = new ArrayList();
- for(int i = 0; i < numOfRows; i++) {
+
+ ArrayList s2 = new ArrayList();
+ for (int i = 0; i < numOfRows; i++) {
s2.add("test" + i % 4);
}
s.setString(1, s2, 10);
-
+
s.columnDataAddBatch();
s.columnDataExecuteBatch();
s.columnDataCloseBatch();
@@ -581,21 +581,20 @@ public class TSDBPreparedStatementTest {
PreparedStatement statement = conn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
int rows = 0;
- while(rs.next()) {
+ while (rs.next()) {
rows++;
}
Assert.assertEquals(numOfRows, rows);
-
}
-
- @Test
+
+ @Test(expected = SQLException.class)
public void createTwoSameDbTest() throws SQLException {
- Statement stmt = conn.createStatement();
-
+ // when
+ Statement stmt = conn.createStatement();
+ stmt.execute("create database dbtest");
stmt.execute("create database dbtest");
- Assert.assertThrows(SQLException.class, () -> stmt.execute("create database dbtest"));
}
-
+
@Test
public void setBoolean() throws SQLException {
// given
@@ -1097,9 +1096,9 @@ public class TSDBPreparedStatementTest {
try {
conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
try (Statement stmt = conn.createStatement()) {
- 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("drop database if exists " + dbname);
+ stmt.execute("create database if not exists " + dbname);
+ stmt.execute("use " + dbname);
}
} catch (SQLException e) {
e.printStackTrace();
@@ -1109,6 +1108,9 @@ public class TSDBPreparedStatementTest {
@AfterClass
public static void afterClass() {
try {
+ Statement statement = conn.createStatement();
+ statement.execute("drop database if exists " + dbname);
+ statement.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/BatchInsertTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/BatchInsertTest.java
index 472da34980..e2541e8109 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/BatchInsertTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/BatchInsertTest.java
@@ -28,9 +28,7 @@ public class BatchInsertTest {
@Before
public void before() {
try {
- Class.forName("com.taosdata.jdbc.TSDBDriver");
Properties properties = new Properties();
- properties.setProperty(TSDBDriver.PROPERTY_KEY_HOST, host);
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");
@@ -44,7 +42,7 @@ public class BatchInsertTest {
String createTableSql = "create table " + stbName + "(ts timestamp, f1 int, f2 int, f3 int) tags(areaid int, loc binary(20))";
statement.executeUpdate(createTableSql);
// create tables
- for(int i = 0; i < numOfTables; i++) {
+ for (int i = 0; i < numOfTables; i++) {
String loc = i % 2 == 0 ? "beijing" : "shanghai";
String createSubTalbesSql = "create table " + tablePrefix + i + " using " + stbName + " tags(" + i + ", '" + loc + "')";
statement.executeUpdate(createSubTalbesSql);
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java
new file mode 100644
index 0000000000..7f2d367dce
--- /dev/null
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java
@@ -0,0 +1,59 @@
+package com.taosdata.jdbc.cases;
+
+import com.taosdata.jdbc.TSDBDriver;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.*;
+import java.util.Properties;
+
+public class ConnectMultiTaosdByRestfulWithDifferentTokenTest {
+
+ private static String host1 = "192.168.17.156";
+ private static String user1 = "root";
+ private static String password1 = "tqueue";
+ private Connection conn1;
+ private static String host2 = "192.168.17.82";
+ private static String user2 = "root";
+ private static String password2 = "taosdata";
+ private Connection conn2;
+
+ @Test
+ public void test() {
+ //when
+ executeSelectStatus(conn1);
+ executeSelectStatus(conn2);
+ executeSelectStatus(conn1);
+ }
+
+ private void executeSelectStatus(Connection connection) {
+ try (Statement stmt = connection.createStatement()) {
+ ResultSet rs = stmt.executeQuery("select server_status()");
+ ResultSetMetaData meta = rs.getMetaData();
+ while (rs.next()) {
+ for (int i = 1; i <= meta.getColumnCount(); i++) {
+ System.out.println(meta.getColumnLabel(i) + ": " + rs.getString(i));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Before
+ public void before() {
+ Properties 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");
+
+ String url1 = "jdbc:TAOS-RS://" + host1 + ":6041/?user=" + user1 + "&password=" + password1;
+ String url2 = "jdbc:TAOS-RS://" + host2 + ":6041/?user=" + user2 + "&password=" + password2;
+ try {
+ conn1 = DriverManager.getConnection(url1, properties);
+ conn2 = DriverManager.getConnection(url2, properties);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java
similarity index 55%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java
index 2704d4cfa5..212a751ec3 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java
@@ -7,56 +7,64 @@ import org.junit.*;
import java.sql.*;
import java.util.Properties;
-public class TD4174Test {
- private Connection conn;
+public class DoubleQuoteInSqlTest {
private static final String host = "127.0.0.1";
+ private static final String dbname = "td4174";
+
+ private Connection conn;
@Test
public void test() {
+ // given
long ts = System.currentTimeMillis();
- try (PreparedStatement pstmt = conn.prepareStatement("insert into weather values(" + ts + ", ?)")) {
- JSONObject value = new JSONObject();
- value.put("name", "John Smith");
- value.put("age", 20);
- Assert.assertEquals("{\"name\":\"John Smith\",\"age\":20}",value.toJSONString());
- pstmt.setString(1, value.toJSONString());
-
- int ret = pstmt.executeUpdate();
- Assert.assertEquals(1, ret);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- public static void main(String[] args) {
JSONObject value = new JSONObject();
value.put("name", "John Smith");
value.put("age", 20);
- System.out.println(value.toJSONString());
+
+ // when
+ int ret = 0;
+ try (PreparedStatement pstmt = conn.prepareStatement("insert into weather values(" + ts + ", ?)")) {
+ pstmt.setString(1, value.toJSONString());
+ ret = pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals("{\"name\":\"John Smith\",\"age\":20}", value.toJSONString());
+ Assert.assertEquals(1, ret);
}
@Before
- public void before() throws SQLException {
+ public void before() {
String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
Properties 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");
- conn = DriverManager.getConnection(url, properties);
- try (Statement stmt = conn.createStatement()) {
- stmt.execute("drop database if exists td4174");
- stmt.execute("create database if not exists td4174");
- stmt.execute("use td4174");
+ try {
+ conn = DriverManager.getConnection(url, properties);
+ Statement stmt = conn.createStatement();
+ stmt.execute("drop database if exists " + dbname);
+ stmt.execute("create database if not exists " + dbname);
+ stmt.execute("use " + dbname);
stmt.execute("create table weather(ts timestamp, text binary(64))");
+ } catch (SQLException e) {
+ e.printStackTrace();
}
}
@After
- public void after() throws SQLException {
- if (conn != null)
+ public void after() {
+ try {
+ Statement stmt = conn.createStatement();
+ stmt.execute("drop database if exists " + dbname);
+ stmt.close();
conn.close();
-
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
}
}
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java
similarity index 98%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java
index f9b111bb12..54e4273ea3 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java
@@ -10,7 +10,7 @@ import org.junit.Test;
import java.sql.*;
import java.util.Properties;
-public class TwoTypeTimestampPercisionInJniTest {
+public class MicroSecondPrecisionJNITest {
private static final String host = "127.0.0.1";
private static final String ms_timestamp_db = "ms_precision_test";
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java
similarity index 99%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java
index 5c83b5a9da..7e9f04cd63 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java
@@ -10,10 +10,9 @@ import org.junit.Test;
import java.sql.*;
import java.util.Properties;
-public class TwoTypeTimestampPercisionInRestfulTest {
+public class MicroSecondPrecisionRestfulTest {
private static final String host = "127.0.0.1";
-
private static final String ms_timestamp_db = "ms_precision_test";
private static final String us_timestamp_db = "us_precision_test";
private static final long timestamp1 = System.currentTimeMillis();
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java
new file mode 100644
index 0000000000..4f2c87966a
--- /dev/null
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java
@@ -0,0 +1,182 @@
+package com.taosdata.jdbc.cases;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.*;
+import java.time.Instant;
+import java.util.Random;
+
+public class NanoSecondTimestampJNITest {
+
+ private static final String host = "127.0.0.1";
+ private static final String dbname = "nano_sec_test";
+ private static final Random random = new Random(System.currentTimeMillis());
+ private static Connection conn;
+
+ @Test
+ public void insertUsingLongValue() {
+ // given
+ long ms = System.currentTimeMillis();
+ long ns = ms * 1000_000 + random.nextInt(1000_000);
+
+ // when
+ int ret = 0;
+ try (Statement stmt = conn.createStatement()) {
+ ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void insertUsingStringValue() {
+ // given
+
+ // when
+ int ret = 0;
+ try (Statement stmt = conn.createStatement()) {
+ ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('2021-01-01 12:00:00.123456789', 12.3, 4)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void insertUsingTimestampValue() {
+ // given
+ long epochSec = System.currentTimeMillis() / 1000;
+ long nanoAdjustment = random.nextInt(1000_000_000);
+ Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+
+ // when
+ int ret = 0;
+ String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)";
+ try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+ pstmt.setTimestamp(1, ts);
+ pstmt.setFloat(2, 12.34f);
+ pstmt.setInt(3, 55);
+ ret = pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void selectUsingLongValue() throws SQLException {
+ // given
+ long ms = System.currentTimeMillis();
+ long ns = ms * 1000_000L + random.nextInt(1000_000);
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)");
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ long actual = rs.getLong(1);
+ Assert.assertEquals(ms, actual);
+ actual = rs.getLong("ts");
+ Assert.assertEquals(ms, actual);
+ }
+
+ @Test
+ public void selectUsingStringValue() throws SQLException {
+ // given
+ String timestampStr = "2021-01-01 12:00:00.123456789";
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('" + timestampStr + "', 12.3, 4)");
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ String actual = rs.getString(1);
+ Assert.assertEquals(timestampStr, actual);
+ actual = rs.getString("ts");
+ Assert.assertEquals(timestampStr, actual);
+ }
+
+ @Test
+ public void selectUsingTimestampValue() throws SQLException {
+ // given
+ long timeMillis = System.currentTimeMillis();
+ long epochSec = timeMillis / 1000;
+ long nanoAdjustment = (timeMillis % 1000) * 1000_000L + random.nextInt(1000_000);
+ Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+
+ // insert one row
+ String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)";
+ try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+ pstmt.setTimestamp(1, ts);
+ pstmt.setFloat(2, 12.34f);
+ pstmt.setInt(3, 55);
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Timestamp actual = rs.getTimestamp(1);
+ Assert.assertEquals(ts, actual);
+ actual = rs.getTimestamp("ts");
+ Assert.assertEquals(ts, actual);
+ Assert.assertEquals(timeMillis, actual.getTime());
+ Assert.assertEquals(nanoAdjustment, actual.getNanos());
+ }
+
+ @Before
+ public void before() {
+ try (Statement stmt = conn.createStatement()) {
+ stmt.execute("drop table if exists weather");
+ stmt.execute("create table weather(ts timestamp, temperature float, humidity int)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
+ try {
+ conn = DriverManager.getConnection(url);
+ Statement stmt = conn.createStatement();
+ stmt.execute("drop database if exists " + dbname);
+ stmt.execute("create database if not exists " + dbname + " precision 'ns'");
+ stmt.execute("use " + dbname);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java
new file mode 100644
index 0000000000..4271f918b9
--- /dev/null
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java
@@ -0,0 +1,182 @@
+package com.taosdata.jdbc.cases;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.*;
+import java.time.Instant;
+import java.util.Random;
+
+public class NanoSecondTimestampRestfulTest {
+
+ private static final String host = "127.0.0.1";
+ private static final String dbname = "nano_sec_test";
+ private static final Random random = new Random(System.currentTimeMillis());
+ private static Connection conn;
+
+ @Test
+ public void insertUsingLongValue() {
+ // given
+ long ms = System.currentTimeMillis();
+ long ns = ms * 1000_000 + random.nextInt(1000_000);
+
+ // when
+ int ret = 0;
+ try (Statement stmt = conn.createStatement()) {
+ ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void insertUsingStringValue() {
+ // given
+
+ // when
+ int ret = 0;
+ try (Statement stmt = conn.createStatement()) {
+ ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('2021-01-01 12:00:00.123456789', 12.3, 4)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void insertUsingTimestampValue() {
+ // given
+ long epochSec = System.currentTimeMillis() / 1000;
+ long nanoAdjustment = random.nextInt(1000_000_000);
+ Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+
+ // when
+ int ret = 0;
+ String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)";
+ try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+ pstmt.setTimestamp(1, ts);
+ pstmt.setFloat(2, 12.34f);
+ pstmt.setInt(3, 55);
+ ret = pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Assert.assertEquals(1, ret);
+ }
+
+ @Test
+ public void selectUsingLongValue() throws SQLException {
+ // given
+ long ms = System.currentTimeMillis();
+ long ns = ms * 1000_000L + random.nextInt(1000_000);
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)");
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ long actual = rs.getLong(1);
+ Assert.assertEquals(ms, actual);
+ actual = rs.getLong("ts");
+ Assert.assertEquals(ms, actual);
+ }
+
+ @Test
+ public void selectUsingStringValue() throws SQLException {
+ // given
+ String timestampStr = "2021-01-01 12:00:00.123456789";
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('" + timestampStr + "', 12.3, 4)");
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ String actual = rs.getString(1);
+ Assert.assertEquals(timestampStr, actual);
+ actual = rs.getString("ts");
+ Assert.assertEquals(timestampStr, actual);
+ }
+
+ @Test
+ public void selectUsingTimestampValue() throws SQLException {
+ // given
+ long timeMillis = System.currentTimeMillis();
+ long epochSec = timeMillis / 1000;
+ long nanoAdjustment = (timeMillis % 1000) * 1000_000L + random.nextInt(1000_000);
+ Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
+
+ // insert one row
+ String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)";
+ try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+ pstmt.setTimestamp(1, ts);
+ pstmt.setFloat(2, 12.34f);
+ pstmt.setInt(3, 55);
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // when
+ ResultSet rs = null;
+ try (Statement stmt = conn.createStatement()) {
+ rs = stmt.executeQuery("select * from weather");
+ rs.next();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ // then
+ Timestamp actual = rs.getTimestamp(1);
+ Assert.assertEquals(ts, actual);
+ actual = rs.getTimestamp("ts");
+ Assert.assertEquals(ts, actual);
+ Assert.assertEquals(timeMillis, actual.getTime());
+ Assert.assertEquals(nanoAdjustment, actual.getNanos());
+ }
+
+ @Before
+ public void before() {
+ try (Statement stmt = conn.createStatement()) {
+ stmt.execute("drop table if exists weather");
+ stmt.execute("create table weather(ts timestamp, temperature float, humidity int)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
+ try {
+ conn = DriverManager.getConnection(url);
+ Statement stmt = conn.createStatement();
+ stmt.execute("drop database if exists " + dbname);
+ stmt.execute("create database if not exists " + dbname + " precision 'ns'");
+ stmt.execute("use " + dbname);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java
similarity index 97%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java
index 782125144c..076125a752 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java
@@ -6,7 +6,7 @@ import org.junit.Test;
import java.sql.*;
-public class NullValueInResultSetForJdbcJniTest {
+public class NullValueInResultSetJNITest {
private static final String host = "127.0.0.1";
Connection conn;
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java
similarity index 97%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java
index f2ac94adc1..ea6e36ec1d 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java
@@ -6,7 +6,7 @@ import org.junit.Test;
import java.sql.*;
-public class NullValueInResultSetForJdbcRestfulTest {
+public class NullValueInResultSetRestfulTest {
private static final String host = "127.0.0.1";
Connection conn;
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java
similarity index 99%
rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java
rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java
index c6fba81eb2..61d767b5cf 100644
--- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java
@@ -7,7 +7,7 @@ import org.junit.*;
import java.sql.*;
import java.util.Properties;
-public class TD3841Test {
+public class NullValueInResultSetTest {
private static final String host = "127.0.0.1";
private static Properties properties;
private static Connection conn_restful;
diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java
new file mode 100644
index 0000000000..ed78c2561e
--- /dev/null
+++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java
@@ -0,0 +1,98 @@
+package com.taosdata.jdbc.cases;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.*;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class PreparedStatementBatchInsertJNITest {
+
+ private static final String host = "127.0.0.1";
+ private static final String dbname = "td4668";
+
+ private final Random random = new Random(System.currentTimeMillis());
+ private Connection conn;
+
+ @Test
+ public void test() {
+ // given
+ long ts = System.currentTimeMillis();
+ List