diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml
index 8ec65a243e21ff6d6da535690144ba06567ce3c9..a3a36d54cfe3d0c25dd69675be5b3464f4236975 100644
--- a/src/connector/jdbc/pom.xml
+++ b/src/connector/jdbc/pom.xml
@@ -122,7 +122,6 @@
**/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 2970f6c2d37d73476ee0d8831a68128569766fb4..686ef3626249d0c6c8e89ca848e054238fe65562 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 9dc559339a4ef88b8423ffcd621c7498437dac5c..8b6c074d1b859f179aac04a83cafb24cfae7c190 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 90967b3620fdaccf69f253c8f8927c067b6221fd..411a61eb86e317f5e38e37d2506ec1bdbe01c0a1 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 c978bb3a2e4a1b9dbd264268f057f2b6c735250a..9f0ba5afabde71bf6359cbfb66757e150899deaf 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/TSDBPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java
index c3d5abf35c7304f86f9cc4dc4449d8c88d144e3d..1a007156e9441dbea0806aa7c66e8dbfd84e4e7b 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 b0b3ae4180ea5df185f6f54e5c0c99fd49493d21..e00ec1e758f720c6dc59fd1a0d41f258ca66d4cc 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;
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 0000000000000000000000000000000000000000..79350076c7f4b31743ab9fb61226e506186f0f17
--- /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/RestfulPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java
index f58e3f8cd2406e6372900c2f7b2547a450fb7fe9..16272f4289ea9031afc91fa76260a8d5719f9a77 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 530b433d42bf4b387db0e9973ddcf48e3844f2f3..13850f0b804fef1306789fe0dba0246a0bd8038a 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 7ead8bd1bbaeeb8fe1f24c951656888f6bba6b6f..a185abb709605cdbc9afecd26d33a1cac85ce37d 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/enums/TimestampFormat.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..edc429857e4b47031b60f6a49a62f21e183d80ed
--- /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 b1c6dae6b3543337ae253c4cf94c2aaa5a31f9f5..ff27bdbdad2d5f56a4652ae822b9ba10c80c51b0 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,13 +16,12 @@ 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 {
private static final String DEFAULT_CONTENT_TYPE = "application/json";
- private static final String DEFAULT_TOKEN = "cm9vdDp0YW9zZGF0YQ==";
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;
@@ -80,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();
@@ -165,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 8ab610fec6541e96d8b4b997c6883dddc01f1549..4c92d27a28625e407d94e34da60aa7a57760baac 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/TSDBPreparedStatementTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java
index 3f8bef4a7ea00915925b2924b08ad8c453420416..40ff5c23ef9866d0a7d8fd5c594f2b933ed80b2a 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/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 2704d4cfa558ebdb6885c320d7ba775b36b99f09..212a751ec302ae02552d084248d34b35a7b21c59 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();
+ JSONObject value = new JSONObject();
+ value.put("name", "John Smith");
+ value.put("age", 20);
+
+ // when
+ int ret = 0;
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);
+ ret = pstmt.executeUpdate();
} 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());
+ // 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 f9b111bb12f189a7a42c7944237aa01ebb008d25..54e4273ea3e54c8db18ca11c10f960468ab91c75 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 5c83b5a9da527a55387a8ad399e78462b6fab63c..7e9f04cd6360431a3fe6c29a2f0eb61fbdc9e7c4 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 0000000000000000000000000000000000000000..4f2c87966ad6bb8390bab47b795e7d952725baf5
--- /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 0000000000000000000000000000000000000000..4271f918b9b096000cc59b730d7b70f032a0ab29
--- /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 782125144c4fbe8dcc4bdfd4769e95e5119ea32f..076125a752e5c4e81e24cbfa3299fa349939094b 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 f2ac94adc1b6e7d94e52650dcfbb5664c8f39760..ea6e36ec1d005e48f36ee1283935664aca6fcc47 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 c6fba81eb24b9b8c08fd553ca57b1e1d68bb81e0..61d767b5cf2bcd2e478de74e5f4bb8d66ad21678 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 0000000000000000000000000000000000000000..ed78c2561ec437e3b7c6a0ab8d3e91699c2572af
--- /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