[TD-3762]<feature>: support us and ms percision for timestamp in JDBC (#5818)
* [TD-3762]<feature>: support us and ms percision for timestamp in JDBC * change * change * change * change
This commit is contained in:
parent
9f5301a318
commit
bcebfbe844
|
@ -4,13 +4,23 @@ import java.sql.*;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
public abstract class AbstractConnection extends WrapperImpl implements Connection {
|
public abstract class AbstractConnection extends WrapperImpl implements Connection {
|
||||||
|
|
||||||
protected volatile boolean isClosed;
|
protected volatile boolean isClosed;
|
||||||
protected volatile String catalog;
|
protected volatile String catalog;
|
||||||
protected volatile Properties clientInfoProps = new Properties();
|
protected final Properties clientInfoProps = new Properties();
|
||||||
|
|
||||||
|
protected AbstractConnection(Properties properties) {
|
||||||
|
Set<String> propNames = properties.stringPropertyNames();
|
||||||
|
for (String propName : propNames) {
|
||||||
|
clientInfoProps.setProperty(propName, properties.getProperty(propName));
|
||||||
|
}
|
||||||
|
String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, "STRING");
|
||||||
|
clientInfoProps.setProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, timestampFormat);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract Statement createStatement() throws SQLException;
|
public abstract Statement createStatement() throws SQLException;
|
||||||
|
@ -35,7 +45,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAutoCommit(boolean autoCommit) throws SQLException {
|
public void setAutoCommit(boolean autoCommit) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
|
@ -441,9 +450,8 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
|
||||||
if (isClosed)
|
if (isClosed)
|
||||||
throw (SQLClientInfoException) TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
|
throw (SQLClientInfoException) TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
|
||||||
|
|
||||||
if (clientInfoProps == null)
|
if (clientInfoProps != null)
|
||||||
clientInfoProps = new Properties();
|
clientInfoProps.setProperty(name, value);
|
||||||
clientInfoProps.setProperty(name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class TSDBConnection extends AbstractConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TSDBConnection(Properties info, TSDBDatabaseMetaData meta) throws SQLException {
|
public TSDBConnection(Properties info, TSDBDatabaseMetaData meta) throws SQLException {
|
||||||
|
super(info);
|
||||||
this.databaseMetaData = meta;
|
this.databaseMetaData = meta;
|
||||||
connect(info.getProperty(TSDBDriver.PROPERTY_KEY_HOST),
|
connect(info.getProperty(TSDBDriver.PROPERTY_KEY_HOST),
|
||||||
Integer.parseInt(info.getProperty(TSDBDriver.PROPERTY_KEY_PORT, "0")),
|
Integer.parseInt(info.getProperty(TSDBDriver.PROPERTY_KEY_PORT, "0")),
|
||||||
|
|
|
@ -95,6 +95,11 @@ public class TSDBDriver extends AbstractDriver {
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_KEY_BATCH_LOAD = "batchfetch";
|
public static final String PROPERTY_KEY_BATCH_LOAD = "batchfetch";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* timestamp format for JDBC-RESTful,should one of the options: string or timestamp or utc
|
||||||
|
*/
|
||||||
|
public static final String PROPERTY_KEY_TIMESTAMP_FORMAT = "timestampFormat";
|
||||||
|
|
||||||
private TSDBDatabaseMetaData dbMetaData = null;
|
private TSDBDatabaseMetaData dbMetaData = null;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -203,7 +203,11 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
|
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getLong(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
|
Object value = this.rowData.get(columnIndex - 1);
|
||||||
|
if (value instanceof Timestamp)
|
||||||
|
res = ((Timestamp) value).getTime();
|
||||||
|
else
|
||||||
|
res = this.rowData.getLong(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +277,6 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
checkAvailability(columnIndex, this.columnMetaDataList.size());
|
checkAvailability(columnIndex, this.columnMetaDataList.size());
|
||||||
|
|
||||||
Timestamp res = null;
|
Timestamp res = null;
|
||||||
|
|
||||||
if (this.getBatchFetch())
|
if (this.getBatchFetch())
|
||||||
return this.blockData.getTimestamp(columnIndex - 1);
|
return this.blockData.getTimestamp(columnIndex - 1);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ package com.taosdata.jdbc;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@ -299,7 +300,19 @@ public class TSDBResultSetRowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimestamp(int col, long ts) {
|
public void setTimestamp(int col, long ts) {
|
||||||
data.set(col, new Timestamp(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 Timestamp getTimestamp(int col) {
|
public Timestamp getTimestamp(int col) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ public class RestfulConnection extends AbstractConnection {
|
||||||
private final DatabaseMetaData metadata;
|
private final DatabaseMetaData metadata;
|
||||||
|
|
||||||
public RestfulConnection(String host, String port, Properties props, String database, String url) {
|
public RestfulConnection(String host, String port, Properties props, String database, String url) {
|
||||||
|
super(props);
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = Integer.parseInt(port);
|
this.port = Integer.parseInt(port);
|
||||||
this.database = database;
|
this.database = database;
|
||||||
|
|
|
@ -5,13 +5,14 @@ import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
import com.google.common.primitives.Shorts;
|
import com.google.common.primitives.Shorts;
|
||||||
import com.taosdata.jdbc.AbstractResultSet;
|
import com.taosdata.jdbc.*;
|
||||||
import com.taosdata.jdbc.TSDBConstants;
|
import com.taosdata.jdbc.utils.UtcTimestampUtil;
|
||||||
import com.taosdata.jdbc.TSDBError;
|
|
||||||
import com.taosdata.jdbc.TSDBErrorNumbers;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
private volatile boolean isClosed;
|
private volatile boolean isClosed;
|
||||||
private int pos = -1;
|
private int pos = -1;
|
||||||
|
|
||||||
|
|
||||||
private final String database;
|
private final String database;
|
||||||
private final Statement statement;
|
private final Statement statement;
|
||||||
// data
|
// data
|
||||||
|
@ -65,7 +67,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object parseColumnData(JSONArray row, int colIndex, int taosType) {
|
private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException {
|
||||||
switch (taosType) {
|
switch (taosType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
return row.getBoolean(colIndex);
|
return row.getBoolean(colIndex);
|
||||||
|
@ -81,8 +83,44 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return row.getFloat(colIndex);
|
return row.getFloat(colIndex);
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
return row.getDouble(colIndex);
|
return row.getDouble(colIndex);
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
|
||||||
return new Timestamp(row.getDate(colIndex).getTime());
|
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:
|
||||||
|
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_BINARY:
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
return row.getString(colIndex) == null ? null : row.getString(colIndex).getBytes();
|
return row.getString(colIndex) == null ? null : row.getString(colIndex).getBytes();
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
|
@ -215,6 +253,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
Object value = resultSet.get(pos).get(columnIndex - 1);
|
Object value = resultSet.get(pos).get(columnIndex - 1);
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (value instanceof Timestamp) {
|
||||||
|
return ((Timestamp) value).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
long valueAsLong = 0;
|
long valueAsLong = 0;
|
||||||
try {
|
try {
|
||||||
|
@ -307,6 +348,13 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return null;
|
return null;
|
||||||
if (value instanceof Timestamp)
|
if (value instanceof Timestamp)
|
||||||
return (Timestamp) value;
|
return (Timestamp) value;
|
||||||
|
// if (value instanceof Long) {
|
||||||
|
// if (1_0000_0000_0000_0L > (long) value)
|
||||||
|
// return Timestamp.from(Instant.ofEpochMilli((long) value));
|
||||||
|
// long epochSec = (long) value / 1000_000L;
|
||||||
|
// long nanoAdjustment = (long) ((long) value % 1000_000L * 1000);
|
||||||
|
// return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
|
||||||
|
// }
|
||||||
return Timestamp.valueOf(value.toString());
|
return Timestamp.valueOf(value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.taosdata.jdbc.AbstractStatement;
|
import com.taosdata.jdbc.AbstractStatement;
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
import com.taosdata.jdbc.TSDBError;
|
import com.taosdata.jdbc.TSDBError;
|
||||||
import com.taosdata.jdbc.TSDBErrorNumbers;
|
import com.taosdata.jdbc.TSDBErrorNumbers;
|
||||||
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
||||||
|
@ -34,14 +35,11 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
if (!SqlSyntaxValidator.isValidForExecuteQuery(sql))
|
if (!SqlSyntaxValidator.isValidForExecuteQuery(sql))
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "not a valid sql for executeQuery: " + sql);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "not a valid sql for executeQuery: " + sql);
|
||||||
|
|
||||||
final String url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql";
|
|
||||||
if (SqlSyntaxValidator.isDatabaseUnspecifiedQuery(sql)) {
|
if (SqlSyntaxValidator.isDatabaseUnspecifiedQuery(sql)) {
|
||||||
return executeOneQuery(url, sql);
|
return executeOneQuery(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.database != null && !this.database.trim().replaceAll("\\s","").isEmpty())
|
return executeOneQuery(sql);
|
||||||
// HttpClientPoolUtil.execute(url, "use " + this.database);
|
|
||||||
return executeOneQuery(url, sql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,8 +54,6 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
return executeOneUpdate(url, sql);
|
return executeOneUpdate(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.database != null && !this.database.trim().replaceAll("\\s", "").isEmpty())
|
|
||||||
// HttpClientPoolUtil.execute(url, "use " + this.database);
|
|
||||||
return executeOneUpdate(url, sql);
|
return executeOneUpdate(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,14 +74,21 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
|
|
||||||
//如果执行了use操作应该将当前Statement的catalog设置为新的database
|
//如果执行了use操作应该将当前Statement的catalog设置为新的database
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
final String url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql";
|
String url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql";
|
||||||
|
if (conn.getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT).equals("TIMESTAMP")) {
|
||||||
|
url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlt";
|
||||||
|
}
|
||||||
|
if (conn.getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT).equals("UTC")) {
|
||||||
|
url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlutc";
|
||||||
|
}
|
||||||
|
|
||||||
if (SqlSyntaxValidator.isUseSql(sql)) {
|
if (SqlSyntaxValidator.isUseSql(sql)) {
|
||||||
HttpClientPoolUtil.execute(url, sql);
|
HttpClientPoolUtil.execute(url, sql);
|
||||||
this.database = sql.trim().replace("use", "").trim();
|
this.database = sql.trim().replace("use", "").trim();
|
||||||
this.conn.setCatalog(this.database);
|
this.conn.setCatalog(this.database);
|
||||||
result = false;
|
result = false;
|
||||||
} else if (SqlSyntaxValidator.isDatabaseUnspecifiedQuery(sql)) {
|
} else if (SqlSyntaxValidator.isDatabaseUnspecifiedQuery(sql)) {
|
||||||
executeOneQuery(url, sql);
|
executeOneQuery(sql);
|
||||||
} else if (SqlSyntaxValidator.isDatabaseUnspecifiedUpdate(sql)) {
|
} else if (SqlSyntaxValidator.isDatabaseUnspecifiedUpdate(sql)) {
|
||||||
executeOneUpdate(url, sql);
|
executeOneUpdate(url, sql);
|
||||||
result = false;
|
result = false;
|
||||||
|
@ -101,11 +104,18 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultSet executeOneQuery(String url, String sql) throws SQLException {
|
private ResultSet executeOneQuery(String sql) throws SQLException {
|
||||||
if (!SqlSyntaxValidator.isValidForExecuteQuery(sql))
|
if (!SqlSyntaxValidator.isValidForExecuteQuery(sql))
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "not a valid sql for executeQuery: " + sql);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "not a valid sql for executeQuery: " + sql);
|
||||||
|
|
||||||
// row data
|
// row data
|
||||||
|
String url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql";
|
||||||
|
String timestampFormat = conn.getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT);
|
||||||
|
if ("TIMESTAMP".equalsIgnoreCase(timestampFormat))
|
||||||
|
url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlt";
|
||||||
|
if ("UTC".equalsIgnoreCase(timestampFormat))
|
||||||
|
url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlutc";
|
||||||
|
|
||||||
String result = HttpClientPoolUtil.execute(url, sql);
|
String result = HttpClientPoolUtil.execute(url, sql);
|
||||||
JSONObject resultJson = JSON.parseObject(result);
|
JSONObject resultJson = JSON.parseObject(result);
|
||||||
if (resultJson.getString("status").equals("error")) {
|
if (resultJson.getString("status").equals("error")) {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.taosdata.jdbc.utils;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
|
|
||||||
|
public class UtcTimestampUtil {
|
||||||
|
public static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
|
||||||
|
.appendPattern("yyyy-MM-ddTHH:mm:ss.SSS+")
|
||||||
|
// .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
|
||||||
|
.toFormatter();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class TwoTypeTimestampPercisionInJniTest {
|
||||||
|
|
||||||
|
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();
|
||||||
|
private static final long timestamp2 = timestamp1 * 1000 + 123;
|
||||||
|
|
||||||
|
private static Connection conn;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase1() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
long ts = rs.getTimestamp(1).getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase2() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + us_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
Timestamp timestamp = rs.getTimestamp(1);
|
||||||
|
System.out.println(timestamp);
|
||||||
|
long ts = timestamp.getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
int nanos = timestamp.getNanos();
|
||||||
|
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
||||||
|
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws SQLException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
|
||||||
|
String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
stmt.execute("drop database if exists " + ms_timestamp_db);
|
||||||
|
stmt.execute("create database if not exists " + ms_timestamp_db + " precision 'ms'");
|
||||||
|
stmt.execute("create table " + ms_timestamp_db + ".weather(ts timestamp, f1 int)");
|
||||||
|
stmt.executeUpdate("insert into " + ms_timestamp_db + ".weather(ts,f1) values(" + timestamp1 + ", 127)");
|
||||||
|
|
||||||
|
stmt.execute("drop database if exists " + us_timestamp_db);
|
||||||
|
stmt.execute("create database if not exists " + us_timestamp_db + " precision 'us'");
|
||||||
|
stmt.execute("create table " + us_timestamp_db + ".weather(ts timestamp, f1 int)");
|
||||||
|
stmt.executeUpdate("insert into " + us_timestamp_db + ".weather(ts,f1) values(" + timestamp2 + ", 127)");
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
try {
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class TwoTypeTimestampPercisionInRestfulTest {
|
||||||
|
|
||||||
|
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();
|
||||||
|
private static final long timestamp2 = timestamp1 * 1000 + 123;
|
||||||
|
|
||||||
|
private static Connection conn1;
|
||||||
|
private static Connection conn2;
|
||||||
|
private static Connection conn3;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase1() {
|
||||||
|
try (Statement stmt = conn1.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
long ts = rs.getTimestamp(1).getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase2() {
|
||||||
|
try (Statement stmt = conn1.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + us_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
Timestamp timestamp = rs.getTimestamp(1);
|
||||||
|
long ts = timestamp.getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
int nanos = timestamp.getNanos();
|
||||||
|
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
||||||
|
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase3() {
|
||||||
|
try (Statement stmt = conn2.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
Timestamp rsTimestamp = rs.getTimestamp(1);
|
||||||
|
long ts = rsTimestamp.getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase4() {
|
||||||
|
try (Statement stmt = conn2.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + us_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
Timestamp timestamp = rs.getTimestamp(1);
|
||||||
|
long ts = timestamp.getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
int nanos = timestamp.getNanos();
|
||||||
|
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
||||||
|
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase5() {
|
||||||
|
try (Statement stmt = conn3.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
long ts = rs.getTimestamp(1).getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase6() {
|
||||||
|
try (Statement stmt = conn3.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + us_timestamp_db + ".weather");
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
Timestamp timestamp = rs.getTimestamp(1);
|
||||||
|
long ts = timestamp.getTime();
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
int nanos = timestamp.getNanos();
|
||||||
|
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
||||||
|
|
||||||
|
ts = rs.getLong(1);
|
||||||
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws SQLException {
|
||||||
|
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");
|
||||||
|
// properties.setProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, "TIMESTAMP");
|
||||||
|
|
||||||
|
String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
|
||||||
|
conn1 = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata×tampFormat=timestamp";
|
||||||
|
conn2 = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata×tampFormat=utc";
|
||||||
|
conn3 = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
Statement stmt = conn1.createStatement();
|
||||||
|
stmt.execute("drop database if exists " + ms_timestamp_db);
|
||||||
|
stmt.execute("create database if not exists " + ms_timestamp_db + " precision 'ms'");
|
||||||
|
stmt.execute("create table " + ms_timestamp_db + ".weather(ts timestamp, f1 int)");
|
||||||
|
stmt.executeUpdate("insert into " + ms_timestamp_db + ".weather(ts,f1) values(" + timestamp1 + ", 127)");
|
||||||
|
|
||||||
|
stmt.execute("drop database if exists " + us_timestamp_db);
|
||||||
|
stmt.execute("create database if not exists " + us_timestamp_db + " precision 'us'");
|
||||||
|
stmt.execute("create table " + us_timestamp_db + ".weather(ts timestamp, f1 int)");
|
||||||
|
stmt.executeUpdate("insert into " + us_timestamp_db + ".weather(ts,f1) values(" + timestamp2 + ", 127)");
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
try {
|
||||||
|
if (conn1 != null)
|
||||||
|
conn1.close();
|
||||||
|
if (conn2 != null)
|
||||||
|
conn2.close();
|
||||||
|
if (conn3 != null)
|
||||||
|
conn3.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue