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/tscSQLParser.c b/src/client/src/tscSQLParser.c
index d64fedab0c..79d9b6e8e3 100644
--- a/src/client/src/tscSQLParser.c
+++ b/src/client/src/tscSQLParser.c
@@ -772,6 +772,10 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
pCmd->active = pCmd->pQueryInfo;
pCmd->command = pCmd->pQueryInfo->command;
+ if (pTableMetaInfo->pTableMeta != NULL) {
+ pSql->res.precision = tscGetTableInfo(pTableMetaInfo->pTableMeta).precision;
+ }
+
return TSDB_CODE_SUCCESS; // do not build query message here
}
diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml
index 8ec65a243e..a3a36d54cf 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 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/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/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 b1c6dae6b3..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,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 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/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