diff --git a/packaging/check_package.sh b/packaging/check_package.sh
new file mode 100755
index 0000000000..e4d783d2f9
--- /dev/null
+++ b/packaging/check_package.sh
@@ -0,0 +1,245 @@
+#!/bin/bash
+#
+# This file is used to install database on linux systems. The operating system
+# is required to use systemd to manage services at boot
+
+set -e
+#set -x
+
+verMode=edge
+pagMode=full
+
+iplist=""
+serverFqdn=""
+
+# -----------------------Variables definition---------------------
+script_dir="../release"
+# Dynamic directory
+data_dir="/var/lib/taos"
+log_dir="/var/log/taos"
+
+data_link_dir="/usr/local/taos/data"
+log_link_dir="/usr/local/taos/log"
+
+cfg_install_dir="/etc/taos"
+
+bin_link_dir="/usr/bin"
+lib_link_dir="/usr/lib"
+lib64_link_dir="/usr/lib64"
+inc_link_dir="/usr/include"
+
+#install main path
+install_main_dir="/usr/local/taos"
+
+# old bin dir
+sbin_dir="/usr/local/taos/bin"
+
+temp_version=""
+fin_result=""
+
+service_config_dir="/etc/systemd/system"
+nginx_port=6060
+nginx_dir="/usr/local/nginxd"
+
+# Color setting
+RED='\033[0;31m'
+GREEN='\033[1;32m'
+GREEN_DARK='\033[0;32m'
+GREEN_UNDERLINE='\033[4;32m'
+NC='\033[0m'
+
+csudo=""
+if command -v sudo > /dev/null; then
+ csudo="sudo"
+fi
+
+# ============================= get input parameters =================================================
+
+# install.sh -v [server | client] -e [yes | no] -i [systemd | service | ...]
+
+# set parameters by default value
+interactiveFqdn=yes # [yes | no]
+verType=server # [server | client]
+initType=systemd # [systemd | service | ...]
+
+while getopts "hv:d:" arg
+do
+ case $arg in
+ d)
+ #echo "interactiveFqdn=$OPTARG"
+ script_dir=$( echo $OPTARG )
+ ;;
+ h)
+ echo "Usage: `basename $0` -d scripy_path"
+ exit 0
+ ;;
+ ?) #unknow option
+ echo "unkonw argument"
+ exit 1
+ ;;
+ esac
+done
+
+#echo "verType=${verType} interactiveFqdn=${interactiveFqdn}"
+
+function kill_process() {
+ pid=$(ps -ef | grep "$1" | grep -v "grep" | awk '{print $2}')
+ if [ -n "$pid" ]; then
+ ${csudo} kill -9 $pid || :
+ fi
+}
+
+function check_file() {
+ #check file whether exists
+ if [ ! -e $1/$2 ];then
+ echo -e "$1/$2 \033[31mnot exists\033[0m!quit"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+}
+
+function get_package_name() {
+ var=$1
+ if [[ $1 =~ 'aarch' ]];then
+ echo ${var::-21}
+ else
+ echo ${var::-17}
+ fi
+}
+function check_link() {
+ #check Link whether exists or broken
+ if [ -L $1 ] ; then
+ if [ ! -e $1 ] ; then
+ echo -e "$1 \033[31Broken link\033[0m"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+ else
+ echo -e "$1 \033[31mnot exists\033[0m!quit"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+}
+
+function check_main_path() {
+ #check install main dir and all sub dir
+ main_dir=("" "cfg" "bin" "connector" "driver" "examples" "include" "init.d")
+ for i in ${main_dir[@]};do
+ check_file ${install_main_dir} $i
+ done
+ if [ "$verMode" == "cluster" ]; then
+ nginx_main_dir=("admin" "conf" "html" "sbin" "logs")
+ for i in ${nginx_main_dir[@]};do
+ check_file ${nginx_dir} $i
+ done
+ fi
+ echo -e "Check main path:\033[32mOK\033[0m!"
+}
+
+function check_bin_path() {
+ # check install bin dir and all sub dir
+ bin_dir=("taos" "taosd" "taosdemo" "taosdump" "remove.sh" "tarbitrator" "set_core.sh")
+ for i in ${bin_dir[@]};do
+ check_file ${sbin_dir} $i
+ done
+ lbin_dir=("taos" "taosd" "taosdemo" "taosdump" "rmtaos" "tarbitrator" "set_core")
+ for i in ${lbin_dir[@]};do
+ check_link ${bin_link_dir}/$i
+ done
+ if [ "$verMode" == "cluster" ]; then
+ check_file ${nginx_dir}/sbin nginx
+ fi
+ echo -e "Check bin path:\033[32mOK\033[0m!"
+}
+
+
+function check_lib_path() {
+ # check all links
+ check_link ${lib_link_dir}/libtaos.so
+ check_link ${lib_link_dir}/libtaos.so.1
+
+ if [[ -d ${lib64_link_dir} ]]; then
+ check_link ${lib64_link_dir}/libtaos.so
+ check_link ${lib64_link_dir}/libtaos.so.1
+ fi
+ echo -e "Check lib path:\033[32mOK\033[0m!"
+}
+
+
+function check_header_path() {
+ # check all header
+ header_dir=("taos.h" "taoserror.h")
+ for i in ${header_dir[@]};do
+ check_link ${inc_link_dir}/$i
+ done
+ echo -e "Check bin path:\033[32mOK\033[0m!"
+}
+
+
+function check_config_dir() {
+ # check all config
+ check_file ${cfg_install_dir} taos.cfg
+ check_file ${install_main_dir}/cfg taos.cfg.org
+ echo -e "Check conf path:\033[32mOK\033[0m!"
+}
+
+function check_log_path() {
+ # check log path
+ check_file ${log_dir}
+ echo -e "Check log path:\033[32mOK\033[0m!"
+}
+
+function check_data_path() {
+ # check data path
+ check_file ${data_dir}
+ echo -e "Check data path:\033[32mOK\033[0m!"
+}
+
+function install_TDengine() {
+ cd ${script_dir}
+ tar zxf $1
+ temp_version=$(get_package_name $1)
+ cd $(get_package_name $1)
+ echo -e "\033[32muninstall TDengine && install TDengine...\033[0m"
+ rmtaos >/dev/null 2>&1 || echo 'taosd not installed' && echo -e '\n\n' |./install.sh >/dev/null 2>&1
+ echo -e "\033[32mTDengine has been installed!\033[0m"
+ echo -e "\033[32mTDengine is starting...\033[0m"
+ kill_process taos && systemctl start taosd && sleep 10
+}
+
+function test_TDengine() {
+ check_main_path
+ check_bin_path
+ check_lib_path
+ check_header_path
+ check_config_dir
+ check_log_path
+ check_data_path
+ result=`taos -s 'create database test ;create table test.tt(ts timestamp ,i int);insert into test.tt values(now,11);select * from test.tt' 2>&1 ||:`
+ if [[ $result =~ "Unable to establish" ]];then
+ echo -e "\033[31mTDengine connect failed\033[0m"
+ fin_result=$fin_result"\033[31m$temp_version\033[0m test failed!\n"
+ echo -e $fin_result
+ exit 8
+ fi
+ echo -e "Check TDengine connect:\033[32mOK\033[0m!"
+ fin_result=$fin_result"\033[32m$temp_version\033[0m test OK!\n"
+}
+# ## ==============================Main program starts from here============================
+TD_package_name=`ls ${script_dir}/*server*gz |awk -F '/' '{print $NF}' `
+temp=`pwd`
+for i in $TD_package_name;do
+ if [[ $i =~ 'enterprise' ]];then
+ verMode="cluster"
+ else
+ verMode=""
+ fi
+ cd $temp
+ install_TDengine $i
+ test_TDengine
+done
+echo "============================================================"
+echo -e $fin_result
\ No newline at end of file
diff --git a/src/balance/src/bnMain.c b/src/balance/src/bnMain.c
index 67741b1473..f022fff6d8 100644
--- a/src/balance/src/bnMain.c
+++ b/src/balance/src/bnMain.c
@@ -367,6 +367,7 @@ static bool bnMonitorBalance() {
for (int32_t dest = 0; dest < src; dest++) {
SDnodeObj *pDestDnode = tsBnDnodes.list[dest];
if (bnCheckDnodeInVgroup(pDestDnode, pVgroup)) continue;
+ if (taosGetTimestampMs() - pDestDnode->createdTime < 2000) continue;
float destScore = bnTryCalcDnodeScore(pDestDnode, 1);
if (srcScore + 0.0001 < destScore) continue;
diff --git a/src/client/inc/tscUtil.h b/src/client/inc/tscUtil.h
index a9ac788bc3..35f3b42811 100644
--- a/src/client/inc/tscUtil.h
+++ b/src/client/inc/tscUtil.h
@@ -123,6 +123,8 @@ int32_t tscGetDataBlockFromList(SHashObj* pHashList, int64_t id, int32_t size, i
*/
bool tscIsPointInterpQuery(SQueryInfo* pQueryInfo);
bool tscIsTWAQuery(SQueryInfo* pQueryInfo);
+bool tscIsIrateQuery(SQueryInfo* pQueryInfo);
+
bool tscIsSessionWindowQuery(SQueryInfo* pQueryInfo);
bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo);
bool tsIsArithmeticQueryOnAggResult(SQueryInfo* pQueryInfo);
diff --git a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
index d16b672f38..7181c658dd 100644
--- a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
+++ b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h
@@ -51,10 +51,10 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
- * Method: getResultTimePrecision
- * Signature: (J)J
+ * Method: getResultTimePrecisionImp
+ * Signature: (JJ)I
*/
-JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision
+JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecisionImp
(JNIEnv *, jobject, jlong, jlong);
/*
diff --git a/src/client/src/TSDBJNIConnector.c b/src/client/src/TSDBJNIConnector.c
index 324c436dce..379cf86301 100644
--- a/src/client/src/TSDBJNIConnector.c
+++ b/src/client/src/TSDBJNIConnector.c
@@ -113,7 +113,7 @@ static void jniGetGlobalMethod(JNIEnv *env) {
g_rowdataSetFloatFp = (*env)->GetMethodID(env, g_rowdataClass, "setFloat", "(IF)V");
g_rowdataSetDoubleFp = (*env)->GetMethodID(env, g_rowdataClass, "setDouble", "(ID)V");
g_rowdataSetStringFp = (*env)->GetMethodID(env, g_rowdataClass, "setString", "(ILjava/lang/String;)V");
- g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJ)V");
+ g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJI)V");
g_rowdataSetByteArrayFp = (*env)->GetMethodID(env, g_rowdataClass, "setByteArray", "(I[B)V");
(*env)->DeleteLocalRef(env, rowdataClass);
@@ -519,9 +519,11 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEn
jniFromNCharToByteArray(env, (char *)row[i], length[i]));
break;
}
- case TSDB_DATA_TYPE_TIMESTAMP:
- (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]));
+ case TSDB_DATA_TYPE_TIMESTAMP: {
+ int precision = taos_result_precision(result);
+ (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]), precision);
break;
+ }
default:
break;
}
@@ -672,7 +674,15 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(J
return (*env)->NewStringUTF(env, (const char *)tsCharset);
}
-JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision(JNIEnv *env, jobject jobj, jlong con,
+/**
+ * Get Result Time Precision
+ * @param env vm
+ * @param jobj the TSDBJNIConnector java object
+ * @param con the c connection pointer
+ * @param res the TAOS_RES object, i.e. the SSqlObject
+ * @return precision 0:ms 1:us 2:ns
+ */
+JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultTimePrecisionImp(JNIEnv *env, jobject jobj, jlong con,
jlong res) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
diff --git a/src/client/src/tscPrepare.c b/src/client/src/tscPrepare.c
index 89d915a813..bac8920d8f 100644
--- a/src/client/src/tscPrepare.c
+++ b/src/client/src/tscPrepare.c
@@ -906,7 +906,7 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
int code = doBindParam(pBlock, data, param, &bind[param->idx], 1);
if (code != TSDB_CODE_SUCCESS) {
- tscDebug("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
+ tscDebug("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
return invalidOperationMsg(tscGetErrorMsgPayload(&stmt->pSql->cmd), "bind column type mismatch or invalid");
}
}
@@ -1256,7 +1256,7 @@ int stmtParseInsertTbTags(SSqlObj* pSql, STscStmt* pStmt) {
return TSDB_CODE_SUCCESS;
}
- if (sToken.n <= 0 || sToken.type != TK_USING) {
+ if (sToken.n <= 0 || sToken.type != TK_USING) {
tscError("keywords USING is expected, sql:%s", pCmd->insertParam.sql);
return tscSQLSyntaxErrMsg(pCmd->payload, "keywords USING is expected", sToken.z ? sToken.z : pCmd->insertParam.sql);
}
@@ -1403,7 +1403,7 @@ int stmtGenInsertStatement(SSqlObj* pSql, STscStmt* pStmt, const char* name, TAO
} else {
tfree(pSql->sqlstr);
}
-
+
pSql->sqlstr = str;
return TSDB_CODE_SUCCESS;
@@ -1415,7 +1415,7 @@ int stmtGenInsertStatement(SSqlObj* pSql, STscStmt* pStmt, const char* name, TAO
TAOS_STMT* taos_stmt_init(TAOS* taos) {
STscObj* pObj = (STscObj*)taos;
STscStmt* pStmt = NULL;
-
+
if (pObj == NULL || pObj->signature != pObj) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
tscError("connection disconnected");
@@ -1469,7 +1469,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
tscError("sql is NULL");
STMT_RET(invalidOperationMsg(tscGetErrorMsgPayload(&pStmt->pSql->cmd), "sql is NULL"));
}
-
+
if (pStmt->last != STMT_INIT) {
tscError("prepare status error, last:%d", pStmt->last);
STMT_RET(invalidOperationMsg(tscGetErrorMsgPayload(&pStmt->pSql->cmd), "prepare status error"));
diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c
index 82a3a1f55b..9532d1e202 100644
--- a/src/client/src/tscSQLParser.c
+++ b/src/client/src/tscSQLParser.c
@@ -147,57 +147,57 @@ int16_t getNewResColId(SSqlCmd* pCmd) {
return pCmd->resColumnId--;
}
-// serialize expr in exprlist to binary
+// serialize expr in exprlist to binary
// formate "type | size | value"
bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType) {
bool ret = false;
if (!pList || pList->size <= 0 || colType < 0) {
return ret;
- }
-
- tSqlExprItem* item = (tSqlExprItem *)taosArrayGet(pList, 0);
- int32_t firstTokenType = item->pNode->token.type;
+ }
+
+ tSqlExprItem* item = (tSqlExprItem *)taosArrayGet(pList, 0);
+ int32_t firstTokenType = item->pNode->token.type;
int32_t type = firstTokenType;
- //nchar to binary and
- toTSDBType(type);
+ //nchar to binary and
+ toTSDBType(type);
if (type != colType && (type != TSDB_DATA_TYPE_BINARY || colType != TSDB_DATA_TYPE_NCHAR)) {
- return false;
- }
- type = colType;
-
+ return false;
+ }
+ type = colType;
+
SBufferWriter bw = tbufInitWriter( NULL, false );
tbufEnsureCapacity(&bw, 512);
int32_t size = (int32_t)(pList->size);
- tbufWriteUint32(&bw, type);
+ tbufWriteUint32(&bw, type);
tbufWriteInt32(&bw, size);
-
+
for (int32_t i = 0; i < size; i++) {
tSqlExpr* pSub = ((tSqlExprItem*)(taosArrayGet(pList, i)))->pNode;
// check all the token type in expr list same or not
if (firstTokenType != pSub->token.type) {
break;
- }
+ }
- toTSDBType(pSub->token.type);
+ toTSDBType(pSub->token.type);
- tVariant var;
- tVariantCreate(&var, &pSub->token);
- if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT
+ tVariant var;
+ tVariantCreate(&var, &pSub->token);
+ if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT
|| type == TSDB_DATA_TYPE_BIGINT || type == TSDB_DATA_TYPE_INT) {
- tbufWriteInt64(&bw, var.i64);
+ tbufWriteInt64(&bw, var.i64);
} else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) {
tbufWriteDouble(&bw, var.dKey);
} else if (type == TSDB_DATA_TYPE_BINARY){
tbufWriteBinary(&bw, var.pz, var.nLen);
} else if (type == TSDB_DATA_TYPE_NCHAR) {
- char *buf = (char *)calloc(1, (var.nLen + 1)*TSDB_NCHAR_SIZE);
+ char *buf = (char *)calloc(1, (var.nLen + 1)*TSDB_NCHAR_SIZE);
if (tVariantDump(&var, buf, type, false) != TSDB_CODE_SUCCESS) {
free(buf);
tVariantDestroy(&var);
- break;
+ break;
}
tbufWriteBinary(&bw, buf, twcslen((wchar_t *)buf) * TSDB_NCHAR_SIZE);
free(buf);
@@ -209,21 +209,21 @@ bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType)
if (ret == true) {
if ((*dst = calloc(1, sizeof(tVariant))) != NULL) {
- tVariantCreateFromBinary(*dst, tbufGetData(&bw, false), tbufTell(&bw), TSDB_DATA_TYPE_BINARY);
+ tVariantCreateFromBinary(*dst, tbufGetData(&bw, false), tbufTell(&bw), TSDB_DATA_TYPE_BINARY);
} else {
ret = false;
}
}
- tbufCloseWriter(&bw);
+ tbufCloseWriter(&bw);
return ret;
}
static int32_t validateParamOfRelationIn(tVariant *pVar, int32_t colType) {
if (pVar->nType != TSDB_DATA_TYPE_BINARY) {
- return -1;
+ return -1;
}
- SBufferReader br = tbufInitReader(pVar->pz, pVar->nLen, false);
- return colType == TSDB_DATA_TYPE_NCHAR ? 0 : (tbufReadUint32(&br) == colType ? 0: -1);
+ SBufferReader br = tbufInitReader(pVar->pz, pVar->nLen, false);
+ return colType == TSDB_DATA_TYPE_NCHAR ? 0 : (tbufReadUint32(&br) == colType ? 0: -1);
}
static uint8_t convertOptr(SStrToken *pToken) {
@@ -423,18 +423,6 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if(code != TSDB_CODE_SUCCESS) {
return code;
}
-
- if (pInfo->pMiscInfo->tableType == TSDB_SUPER_TABLE) {
-//// code = tscGetTableMeta(pSql, pTableMetaInfo);
-//// if (code != TSDB_CODE_SUCCESS) {
-//// return code;
-//// }
-//
-// if (!UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
-// return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg4);
-// }
- }
-
} else if (pInfo->type == TSDB_SQL_DROP_DNODE) {
if (pzName->type == TK_STRING) {
pzName->n = strdequote(pzName->z);
@@ -507,7 +495,7 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
break;
}
-
+
case TSDB_SQL_CREATE_DNODE: {
const char* msg = "invalid host name (ip address)";
@@ -772,6 +760,11 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
pCmd->active = pCmd->pQueryInfo;
pCmd->command = pCmd->pQueryInfo->command;
+ STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pCmd->active, 0);
+ if (pTableMetaInfo1->pTableMeta != NULL) {
+ pSql->res.precision = tscGetTableInfo(pTableMetaInfo1->pTableMeta).precision;
+ }
+
return TSDB_CODE_SUCCESS; // do not build query message here
}
@@ -803,12 +796,12 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
}
break;
}
- case TSDB_SQL_COMPACT_VNODE:{
+ case TSDB_SQL_COMPACT_VNODE:{
const char* msg = "invalid compact";
if (setCompactVnodeInfo(pSql, pInfo) != TSDB_CODE_SUCCESS) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
- }
- break;
+ }
+ break;
}
default:
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "not support sql expression");
@@ -956,20 +949,22 @@ int32_t validateIntervalNode(SSqlObj* pSql, SQueryInfo* pQueryInfo, SSqlNode* pS
static int32_t validateStateWindowNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSqlNode, bool isStable) {
const char* msg1 = "invalid column name";
+ const char* msg2 = "invalid column type";
const char* msg3 = "not support state_window with group by ";
const char* msg4 = "function not support for super table query";
+ const char* msg5 = "not support state_window on tag column";
SStrToken *col = &(pSqlNode->windowstateVal.col) ;
if (col->z == NULL || col->n <= 0) {
- return TSDB_CODE_SUCCESS;
- }
+ return TSDB_CODE_SUCCESS;
+ }
if (pQueryInfo->colList == NULL) {
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
}
if (pQueryInfo->groupbyExpr.numOfGroupCols > 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- }
+ }
pQueryInfo->groupbyExpr.numOfGroupCols = 1;
//TODO(dengyihao): check tag column
@@ -980,23 +975,27 @@ static int32_t validateStateWindowNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SS
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (getColumnIndexByName(pCmd, col, pQueryInfo, &index) != TSDB_CODE_SUCCESS) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
- }
+ }
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
int32_t numOfCols = tscGetNumOfColumns(pTableMeta);
- if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX || index.columnIndex >= numOfCols) {
+ if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
+ } else if (index.columnIndex >= numOfCols) {
+ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg5);
}
SGroupbyExpr* pGroupExpr = &pQueryInfo->groupbyExpr;
if (pGroupExpr->columnInfo == NULL) {
pGroupExpr->columnInfo = taosArrayInit(4, sizeof(SColIndex));
}
-
+
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, index.columnIndex);
- if (pSchema->type == TSDB_DATA_TYPE_TIMESTAMP || pSchema->type == TSDB_DATA_TYPE_FLOAT || pSchema->type == TSDB_DATA_TYPE_DOUBLE) {
- return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
+ if (pSchema->type == TSDB_DATA_TYPE_TIMESTAMP || pSchema->type == TSDB_DATA_TYPE_FLOAT
+ || pSchema->type == TSDB_DATA_TYPE_DOUBLE || pSchema->type == TSDB_DATA_TYPE_NCHAR
+ || pSchema->type == TSDB_DATA_TYPE_BINARY) {
+ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
}
tscColumnListInsert(pQueryInfo->colList, index.columnIndex, pTableMeta->id.uid, pSchema);
@@ -1045,7 +1044,7 @@ int32_t validateSessionNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode * pS
}
if (index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- }
+ }
pQueryInfo->sessionWindow.primaryColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
@@ -2022,8 +2021,10 @@ int32_t addProjectionExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, t
if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
SSchema colSchema = *tGetTbnameColumnSchema();
- getColumnName(pItem, colSchema.name, colSchema.name, sizeof(colSchema.name) - 1);
+ char name[TSDB_COL_NAME_LEN] = {0};
+ getColumnName(pItem, name, colSchema.name, sizeof(colSchema.name) - 1);
+ tstrncpy(colSchema.name, name, TSDB_COL_NAME_LEN);
/*SExprInfo* pExpr = */tscAddFuncInSelectClause(pQueryInfo, startPos, TSDB_FUNC_TAGPRJ, &index, &colSchema, TSDB_COL_TAG, getNewResColId(pCmd));
} else {
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
@@ -2337,7 +2338,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
tickPerSec /= 1000000;
} else if (info.precision == TSDB_TIME_PRECISION_MICRO) {
tickPerSec /= 1000;
- }
+ }
if (tickPerSec <= 0 || tickPerSec < TSDB_TICK_PER_SECOND(info.precision)) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg10);
@@ -2974,7 +2975,7 @@ int32_t setKillInfo(SSqlObj* pSql, struct SSqlInfo* pInfo, int32_t killType) {
static int32_t setCompactVnodeInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
SSqlCmd* pCmd = &pSql->cmd;
pCmd->command = pInfo->type;
-
+
return TSDB_CODE_SUCCESS;
}
bool validateIpAddress(const char* ip, size_t size) {
@@ -3062,8 +3063,8 @@ void tscRestoreFuncForSTableQuery(SQueryInfo* pQueryInfo) {
}
bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo) {
- const char* msg1 = "TWA/Diff not allowed to apply to super table directly";
- const char* msg2 = "TWA/Diff only support group by tbname for super table query";
+ const char* msg1 = "TWA/Diff/Derivative/Irate not allowed to apply to super table directly";
+ const char* msg2 = "TWA/Diff/Derivative/Irate only support group by tbname for super table query";
const char* msg3 = "function not support for super table query";
// filter sql function not supported by metric query yet.
@@ -3076,7 +3077,7 @@ bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo)
}
}
- if (tscIsTWAQuery(pQueryInfo) || tscIsDiffDerivQuery(pQueryInfo)) {
+ if (tscIsTWAQuery(pQueryInfo) || tscIsDiffDerivQuery(pQueryInfo) || tscIsIrateQuery(pQueryInfo)) {
if (pQueryInfo->groupbyExpr.numOfGroupCols == 0) {
invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
return true;
@@ -3094,7 +3095,7 @@ bool hasUnsupportFunctionsForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo)
}
} else if (tscIsSessionWindowQuery(pQueryInfo)) {
invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
- return true;
+ return true;
}
return false;
@@ -3336,24 +3337,24 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo,
// TK_GT,TK_GE,TK_EQ,TK_NE are based on the pColumn->lowerBndd
} else if (pExpr->tokenId == TK_IN) {
- tVariant *pVal;
+ tVariant *pVal;
if (pRight->tokenId != TK_SET || !serializeExprListToVariant(pRight->pParam, &pVal, colType) || colType == TSDB_DATA_TYPE_TIMESTAMP) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
- }
+ }
if (validateParamOfRelationIn(pVal, colType) != TSDB_CODE_SUCCESS) {
- tVariantDestroy(pVal);
+ tVariantDestroy(pVal);
free(pVal);
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
}
pColumnFilter->pz = (int64_t)calloc(1, pVal->nLen + 1);
pColumnFilter->len = pVal->nLen;
pColumnFilter->filterstr = 1;
- memcpy((char *)(pColumnFilter->pz), (char *)(pVal->pz), pVal->nLen);
+ memcpy((char *)(pColumnFilter->pz), (char *)(pVal->pz), pVal->nLen);
//retVal = tVariantDump(pVal, (char *)(pColumnFilter->pz), TSDB_DATA_TYPE_BINARY, false);
- tVariantDestroy(pVal);
+ tVariantDestroy(pVal);
free(pVal);
-
+
} else if (colType == TSDB_DATA_TYPE_BINARY) {
pColumnFilter->pz = (int64_t)calloc(1, bufLen * TSDB_NCHAR_SIZE);
pColumnFilter->len = pRight->value.nLen;
@@ -4880,7 +4881,7 @@ int32_t getTimeRange(STimeWindow* win, tSqlExpr* pRight, int32_t optr, int16_t t
if (pRight->flags & (1 << EXPR_FLAG_NS_TIMESTAMP)) {
pRight->value.i64 = convertTimePrecision(pRight->value.i64, TSDB_TIME_PRECISION_NANO, timePrecision);
}
-
+
tVariantDump(&pRight->value, (char*)&val, TSDB_DATA_TYPE_BIGINT, true);
}
@@ -5538,7 +5539,7 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if (pItem->type != TSDB_DATA_TYPE_BINARY && pItem->type != TSDB_DATA_TYPE_NCHAR) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg21);
}
-
+
SColumnIndex columnIndex = COLUMN_INDEX_INITIALIZER;
SStrToken name = {.type = TK_STRING, .z = pItem->name, .n = (uint32_t)strlen(pItem->name)};
if (getColumnIndexByName(pCmd, &name, pQueryInfo, &columnIndex) != TSDB_CODE_SUCCESS) {
@@ -5559,11 +5560,11 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
(pItem->type == TSDB_DATA_TYPE_NCHAR && (pItem->bytes <= 0 || pItem->bytes > TSDB_MAX_NCHAR_LEN))) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg24);
}
-
+
if (pItem->bytes <= pColSchema->bytes) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg22);
}
-
+
TAOS_FIELD f = tscCreateField(pColSchema->type, name.z, pItem->bytes);
tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
}else if (pAlterSQL->type == TSDB_ALTER_TABLE_MODIFY_TAG_COLUMN) {
@@ -5575,7 +5576,7 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
if (pItem->type != TSDB_DATA_TYPE_BINARY && pItem->type != TSDB_DATA_TYPE_NCHAR) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg21);
}
-
+
SColumnIndex columnIndex = COLUMN_INDEX_INITIALIZER;
SStrToken name = {.type = TK_STRING, .z = pItem->name, .n = (uint32_t)strlen(pItem->name)};
if (getColumnIndexByName(pCmd, &name, pQueryInfo, &columnIndex) != TSDB_CODE_SUCCESS) {
@@ -5600,11 +5601,11 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
(pItem->type == TSDB_DATA_TYPE_NCHAR && (pItem->bytes <= 0 || pItem->bytes > TSDB_MAX_NCHAR_LEN))) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg24);
}
-
+
if (pItem->bytes <= pColSchema->bytes) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg22);
}
-
+
TAOS_FIELD f = tscCreateField(pColSchema->type, name.z, pItem->bytes);
tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
}
@@ -5970,7 +5971,7 @@ static int32_t setKeepOption(SSqlCmd* pCmd, SCreateDbMsg* pMsg, SCreateDbInfo* p
tVariantListItem* p0 = taosArrayGet(pKeep, 0);
tVariantListItem* p1 = (s > 1) ? taosArrayGet(pKeep, 1) : p0;
tVariantListItem* p2 = (s > 2) ? taosArrayGet(pKeep, 2) : p1;
-
+
if ((int32_t)p0->pVar.i64 <= 0 || (int32_t)p1->pVar.i64 <= 0 || (int32_t)p2->pVar.i64 <= 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
}
@@ -7064,7 +7065,7 @@ int32_t doCheckForStream(SSqlObj* pSql, SSqlInfo* pInfo) {
} else {
if (pQueryInfo->interval.interval == 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg7);
- }
+ }
}
// set the created table[stream] name
@@ -7787,7 +7788,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
}
}
- // todo derivate funtion requires ts column exists in subquery
+ // todo derivative function requires ts column exists in subquery
STableMeta* pTableMeta = tscGetMetaInfo(pQueryInfo, 0)->pTableMeta;
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, 0);
@@ -7880,7 +7881,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
- // parse the window_state
+ // parse the window_state
if (validateStateWindowNode(pCmd, pQueryInfo, pSqlNode, isSTable) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
@@ -8095,7 +8096,7 @@ int32_t exprTreeFromSqlExpr(SSqlCmd* pCmd, tExprNode **pExpr, const tSqlExpr* pS
SColIndex* idx = taosArrayGet(pCols, 0);
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, idx->colIndex);
if (pSchema != NULL) {
- colType = pSchema->type;
+ colType = pSchema->type;
}
}
diff --git a/src/client/src/tscSub.c b/src/client/src/tscSub.c
index 7a0b3451c3..ef46b4068e 100644
--- a/src/client/src/tscSub.c
+++ b/src/client/src/tscSub.c
@@ -283,6 +283,7 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
SArray* tables = getTableList(pSql);
if (tables == NULL) {
+ pSub->lastSyncTime = 0; //force to get table list next time
return 0;
}
size_t numOfTables = taosArrayGetSize(tables);
@@ -489,7 +490,15 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
SSub *pSub = (SSub *)tsub;
if (pSub == NULL) return NULL;
- if (pSub->pSql->cmd.command == TSDB_SQL_RETRIEVE_EMPTY_RESULT) {
+ if (pSub->pTimer == NULL) {
+ int64_t duration = taosGetTimestampMs() - pSub->lastConsumeTime;
+ if (duration < (int64_t)(pSub->interval)) {
+ tscDebug("subscription consume too frequently, blocking...");
+ taosMsleep(pSub->interval - (int32_t)duration);
+ }
+ }
+
+ if (pSub->pSql->cmd.command == TSDB_SQL_RETRIEVE_EMPTY_RESULT) { //may reach here when retireve stable vgroup failed
SSqlObj* pSql = recreateSqlObj(pSub);
if (pSql == NULL) {
return NULL;
@@ -503,6 +512,11 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
pSub->pSql = pSql;
pSql->pSubscription = pSub;
+
+ // no table list now, force to update it
+ tscDebug("begin table synchronization");
+ if (!tscUpdateSubscription(pSub->taos, pSub)) return NULL;
+ tscDebug("table synchronization completed");
}
tscSaveSubscriptionProgress(pSub);
@@ -527,14 +541,6 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
tscDebug("subscribe:%s set next round subscribe skey:%"PRId64, pSub->topic, pQueryInfo->window.skey);
}
- if (pSub->pTimer == NULL) {
- int64_t duration = taosGetTimestampMs() - pSub->lastConsumeTime;
- if (duration < (int64_t)(pSub->interval)) {
- tscDebug("subscription consume too frequently, blocking...");
- taosMsleep(pSub->interval - (int32_t)duration);
- }
- }
-
size_t size = taosArrayGetSize(pSub->progress) * sizeof(STableIdInfo);
size += sizeof(SQueryTableMsg) + 4096;
int code = tscAllocPayload(&pSql->cmd, (int)size);
diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c
index e7f0606db2..22a603b71e 100644
--- a/src/client/src/tscSubquery.c
+++ b/src/client/src/tscSubquery.c
@@ -109,7 +109,7 @@ bool subAndCheckDone(SSqlObj *pSql, SSqlObj *pParentSql, int idx) {
// pthread_mutex_unlock(&subState->mutex);
// return false;
// }
-
+
tscDebug("0x%"PRIx64" subquery:0x%"PRIx64", index:%d state set to 1", pParentSql->self, pSql->self, idx);
subState->states[idx] = 1;
@@ -622,7 +622,7 @@ static int32_t tscLaunchRealSubqueries(SSqlObj* pSql) {
int16_t colId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid);
// set the tag column id for executor to extract correct tag value
-#ifndef _TD_NINGSI_60
+#ifndef _TD_NINGSI_60
pExpr->base.param[0] = (tVariant) {.i64 = colId, .nType = TSDB_DATA_TYPE_BIGINT, .nLen = sizeof(int64_t)};
#else
pExpr->base.param[0].i64 = colId;
@@ -1843,7 +1843,7 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
// refactor as one method
SQueryInfo *pNewQueryInfo = tscGetQueryInfo(&pNew->cmd);
assert(pNewQueryInfo != NULL);
-
+
pSupporter->colList = pNewQueryInfo->colList;
pNewQueryInfo->colList = NULL;
@@ -3158,7 +3158,7 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
pRes->code = TSDB_CODE_TSC_APP_ERROR;
return pRes->code;
}
-
+
for(int32_t i = 0; i < pSql->subState.numOfSub; ++i) {
SSqlObj* pSub = pSql->pSubs[i];
SInsertSupporter* pSup = calloc(1, sizeof(SInsertSupporter));
diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c
index 9011bae47b..9d2c500a92 100644
--- a/src/client/src/tscUtil.c
+++ b/src/client/src/tscUtil.c
@@ -460,6 +460,22 @@ bool tscIsTWAQuery(SQueryInfo* pQueryInfo) {
return false;
}
+bool tscIsIrateQuery(SQueryInfo* pQueryInfo) {
+ size_t numOfExprs = tscNumOfExprs(pQueryInfo);
+ for (int32_t i = 0; i < numOfExprs; ++i) {
+ SExprInfo* pExpr = tscExprGet(pQueryInfo, i);
+ if (pExpr == NULL) {
+ continue;
+ }
+
+ if (pExpr->base.functionId == TSDB_FUNC_IRATE) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool tscIsSessionWindowQuery(SQueryInfo* pQueryInfo) {
return pQueryInfo->sessionWindow.gap > 0;
}
@@ -3477,6 +3493,7 @@ static void tscSubqueryRetrieveCallback(void* param, TAOS_RES* tres, int code) {
if (pSql->res.code == TSDB_CODE_SUCCESS) {
(*pSql->fp)(pParentSql->param, pParentSql, pParentSql->res.numOfRows);
} else {
+ pParentSql->res.code = pSql->res.code;
tscAsyncResultOnError(pParentSql);
}
}
diff --git a/src/connector/jdbc/CMakeLists.txt b/src/connector/jdbc/CMakeLists.txt
index f6829bd0ea..1db8361faf 100644
--- a/src/connector/jdbc/CMakeLists.txt
+++ b/src/connector/jdbc/CMakeLists.txt
@@ -12,4 +12,4 @@ IF (TD_MVN_INSTALLED)
COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
COMMENT "build jdbc driver")
ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME})
-ENDIF ()
+ENDIF ()
\ No newline at end of file
diff --git a/src/connector/jdbc/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