From 402748d9f5823f06751d4cb9363270b9a1ce4cd9 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Fri, 14 May 2021 11:45:47 +0800 Subject: [PATCH] [TD-3776]set time precision after parsing and JNI time precision minor change --- .../jni/com_taosdata_jdbc_TSDBJNIConnector.h | 6 +- src/client/src/TSDBJNIConnector.c | 18 +++-- src/client/src/tscSQLParser.c | 4 ++ .../com/taosdata/jdbc/TSDBJNIConnector.java | 10 +++ .../taosdata/jdbc/TSDBResultSetRowData.java | 42 +++++++---- .../taosdata/jdbc/TSDBJNIConnectorTest.java | 71 +++++++++++++++++-- 6 files changed, 123 insertions(+), 28 deletions(-) diff --git a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h index d16b672f38..7181c658dd 100644 --- a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h +++ b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h @@ -51,10 +51,10 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset /* * Class: com_taosdata_jdbc_TSDBJNIConnector - * Method: getResultTimePrecision - * Signature: (J)J + * Method: getResultTimePrecisionImp + * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecisionImp (JNIEnv *, jobject, jlong, jlong); /* diff --git a/src/client/src/TSDBJNIConnector.c b/src/client/src/TSDBJNIConnector.c index 324c436dce..379cf86301 100644 --- a/src/client/src/TSDBJNIConnector.c +++ b/src/client/src/TSDBJNIConnector.c @@ -113,7 +113,7 @@ static void jniGetGlobalMethod(JNIEnv *env) { g_rowdataSetFloatFp = (*env)->GetMethodID(env, g_rowdataClass, "setFloat", "(IF)V"); g_rowdataSetDoubleFp = (*env)->GetMethodID(env, g_rowdataClass, "setDouble", "(ID)V"); g_rowdataSetStringFp = (*env)->GetMethodID(env, g_rowdataClass, "setString", "(ILjava/lang/String;)V"); - g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJ)V"); + g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJI)V"); g_rowdataSetByteArrayFp = (*env)->GetMethodID(env, g_rowdataClass, "setByteArray", "(I[B)V"); (*env)->DeleteLocalRef(env, rowdataClass); @@ -519,9 +519,11 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEn jniFromNCharToByteArray(env, (char *)row[i], length[i])); break; } - case TSDB_DATA_TYPE_TIMESTAMP: - (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i])); + case TSDB_DATA_TYPE_TIMESTAMP: { + int precision = taos_result_precision(result); + (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]), precision); break; + } default: break; } @@ -672,7 +674,15 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(J return (*env)->NewStringUTF(env, (const char *)tsCharset); } -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision(JNIEnv *env, jobject jobj, jlong con, +/** + * Get Result Time Precision + * @param env vm + * @param jobj the TSDBJNIConnector java object + * @param con the c connection pointer + * @param res the TAOS_RES object, i.e. the SSqlObject + * @return precision 0:ms 1:us 2:ns + */ +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultTimePrecisionImp(JNIEnv *env, jobject jobj, jlong con, jlong res) { TAOS *tscon = (TAOS *)con; if (tscon == NULL) { diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 82a3a1f55b..d0bd767a46 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -772,6 +772,10 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) { pCmd->active = pCmd->pQueryInfo; pCmd->command = pCmd->pQueryInfo->command; + if (pTableMetaInfo->pTableMeta != NULL) { + pSql->res.precision = tscGetTableInfo(pTableMetaInfo->pTableMeta).precision; + } + return TSDB_CODE_SUCCESS; // do not build query message here } diff --git a/src/connector/jdbc/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/TSDBResultSetRowData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java index 01104440ab..b0b3ae4180 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 @@ -414,26 +414,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/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 +} -- GitLab