diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml index 8ec65a243e21ff6d6da535690144ba06567ce3c9..a3a36d54cfe3d0c25dd69675be5b3464f4236975 100644 --- a/src/connector/jdbc/pom.xml +++ b/src/connector/jdbc/pom.xml @@ -122,7 +122,6 @@ **/FailOverTest.java **/InvalidResultSetPointerTest.java **/RestfulConnectionTest.java - **/TD4144Test.java **/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java true diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java index 2970f6c2d37d73476ee0d8831a68128569766fb4..686ef3626249d0c6c8e89ca848e054238fe65562 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractConnection.java @@ -1,5 +1,7 @@ package com.taosdata.jdbc; +import com.taosdata.jdbc.rs.enums.TimestampFormat; + import java.sql.*; import java.util.Enumeration; import java.util.Map; @@ -18,7 +20,7 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti for (String propName : propNames) { clientInfoProps.setProperty(propName, properties.getProperty(propName)); } - String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, "STRING"); + String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, String.valueOf(TimestampFormat.STRING)); clientInfoProps.setProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, timestampFormat); } @@ -516,7 +518,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti public void abort(Executor executor) throws SQLException { if (isClosed()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED); - // do nothing } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java index 9dc559339a4ef88b8423ffcd621c7498437dac5c..8b6c074d1b859f179aac04a83cafb24cfae7c190 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/AbstractStatement.java @@ -9,8 +9,6 @@ public abstract class AbstractStatement extends WrapperImpl implements Statement protected List batchedArgs; private int fetchSize; - - @Override public abstract ResultSet executeQuery(String sql) throws SQLException; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java index 90967b3620fdaccf69f253c8f8927c067b6221fd..411a61eb86e317f5e38e37d2506ec1bdbe01c0a1 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBError.java @@ -32,6 +32,7 @@ public class TSDBError { TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_SQL, "invalid sql"); TSDBErrorMap.put(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE, "numeric value out of range"); TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE, "unknown taos type in tdengine"); + TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TIMESTAMP_PERCISION, "unknown timestamp precision"); /**************************************************/ TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown error"); diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java index c978bb3a2e4a1b9dbd264268f057f2b6c735250a..9f0ba5afabde71bf6359cbfb66757e150899deaf 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java @@ -25,6 +25,7 @@ public class TSDBErrorNumbers { public static final int ERROR_INVALID_SQL = 0x2313; // invalid sql public static final int ERROR_NUMERIC_VALUE_OUT_OF_RANGE = 0x2314; // numeric value out of range public static final int ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE = 0x2315; //unknown taos type in tdengine + public static final int ERROR_UNKNOWN_TIMESTAMP_PERCISION = 0x2316; // unknown timestamp precision public static final int ERROR_UNKNOWN = 0x2350; //unknown error @@ -62,6 +63,7 @@ public class TSDBErrorNumbers { errorNumbers.add(ERROR_INVALID_SQL); errorNumbers.add(ERROR_NUMERIC_VALUE_OUT_OF_RANGE); errorNumbers.add(ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE); + errorNumbers.add(ERROR_UNKNOWN_TIMESTAMP_PERCISION); /*****************************************************/ errorNumbers.add(ERROR_SUBSCRIBE_FAILED); diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java index c3d5abf35c7304f86f9cc4dc4449d8c88d144e3d..1a007156e9441dbea0806aa7c66e8dbfd84e4e7b 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java @@ -38,7 +38,6 @@ import java.util.regex.Pattern; public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement { private String rawSql; private Object[] parameters; - private boolean isPrepared; private ArrayList colData; private ArrayList tableTags; @@ -47,8 +46,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat private String tableName; private long nativeStmtHandle = 0; - private volatile TSDBParameterMetaData parameterMetaData; - TSDBPreparedStatement(TSDBConnection connection, String sql) { super(connection); init(sql); @@ -61,7 +58,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat } } parameters = new Object[parameterCnt]; - this.isPrepared = true; } if (parameterCnt > 1) { @@ -76,11 +72,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat preprocessSql(); } - @Override - public int[] executeBatch() throws SQLException { - return super.executeBatch(); - } - /* * Some of the SQLs sent by other popular frameworks or tools like Spark, contains syntax that cannot be parsed by * the TDengine client. Thus, some simple parsers/filters are intentionally added in this JDBC implementation in @@ -137,29 +128,15 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat /***** for inner queries *****/ } - /** - * Populate parameters into prepared sql statements - * - * @return a string of the native sql statement for TSDB - */ - private String getNativeSql(String rawSql) throws SQLException { - return Utils.getNativeSql(rawSql, this.parameters); - } - @Override public ResultSet executeQuery() throws SQLException { - if (!isPrepared) - return executeQuery(this.rawSql); - - final String sql = getNativeSql(this.rawSql); + final String sql = Utils.getNativeSql(this.rawSql, this.parameters); return executeQuery(sql); } @Override public int executeUpdate() throws SQLException { - if (!isPrepared) - return executeUpdate(this.rawSql); - String sql = getNativeSql(this.rawSql); + String sql = Utils.getNativeSql(this.rawSql, this.parameters); return executeUpdate(sql); } @@ -282,25 +259,14 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat @Override public boolean execute() throws SQLException { - if (!isPrepared) - return execute(this.rawSql); - - final String sql = getNativeSql(this.rawSql); + final String sql = Utils.getNativeSql(this.rawSql, this.parameters); return execute(sql); } @Override public void addBatch() throws SQLException { - if (this.batchedArgs == null) { - batchedArgs = new ArrayList<>(); - } - - if (!isPrepared) { - addBatch(this.rawSql); - } else { - String sql = this.getConnection().nativeSQL(this.rawSql); - addBatch(sql); - } + String sql = Utils.getNativeSql(this.rawSql, this.parameters); + addBatch(sql); } @Override diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java index b0b3ae4180ea5df185f6f54e5c0c99fd49493d21..e00ec1e758f720c6dc59fd1a0d41f258ca66d4cc 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java @@ -147,30 +147,14 @@ public class TSDBResultSetRowData { case TSDBConstants.TSDB_DATA_TYPE_NCHAR: case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Integer.parseInt((String) obj); - case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: { - Byte value = (byte) obj; - if (value < 0) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); - return value; - } - case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: { - short value = (short) obj; - if (value < 0) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); - return value; - } - case TSDBConstants.TSDB_DATA_TYPE_UINT: { - int value = (int) obj; - if (value < 0) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); - return value; - } - case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: { - long value = (long) obj; - if (value < 0) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); - return Long.valueOf(value).intValue(); - } + case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: + return parseUnsignedTinyIntToInt(obj); + case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: + return parseUnsignedSmallIntToInt(obj); + case TSDBConstants.TSDB_DATA_TYPE_UINT: + return parseUnsignedIntegerToInt(obj); + case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: + return parseUnsignedBigIntToInt(obj); case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj).intValue(); case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: @@ -180,6 +164,35 @@ public class TSDBResultSetRowData { } } + private byte parseUnsignedTinyIntToInt(Object obj) throws SQLException { + byte value = (byte) obj; + if (value < 0) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); + return value; + } + + private short parseUnsignedSmallIntToInt(Object obj) throws SQLException { + short value = (short) obj; + if (value < 0) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); + return value; + } + + private int parseUnsignedIntegerToInt(Object obj) throws SQLException { + int value = (int) obj; + if (value < 0) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); + return value; + } + + private int parseUnsignedBigIntToInt(Object obj) throws SQLException { + long value = (long) obj; + if (value < 0) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); + return Long.valueOf(value).intValue(); + } + + /** * $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api */ @@ -216,7 +229,7 @@ public class TSDBResultSetRowData { case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Long.parseLong((String) obj); case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: { - Byte value = (byte) obj; + byte value = (byte) obj; if (value < 0) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE); return value; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java new file mode 100644 index 0000000000000000000000000000000000000000..79350076c7f4b31743ab9fb61226e506186f0f17 --- /dev/null +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java @@ -0,0 +1,8 @@ +package com.taosdata.jdbc.enums; + +public enum TimestampPrecision { + MS, + US, + NS, + UNKNOWN +} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java index f58e3f8cd2406e6372900c2f7b2547a450fb7fe9..16272f4289ea9031afc91fa76260a8d5719f9a77 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulPreparedStatement.java @@ -44,7 +44,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar if (!isPrepared) return executeQuery(this.rawSql); - final String sql = getNativeSql(this.rawSql); + final String sql = Utils.getNativeSql(this.rawSql, this.parameters); return executeQuery(sql); } @@ -55,20 +55,10 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar if (!isPrepared) return executeUpdate(this.rawSql); - final String sql = getNativeSql(this.rawSql); + final String sql = Utils.getNativeSql(rawSql, this.parameters); return executeUpdate(sql); } - /**** - * 将rawSql转换成一条可执行的sql语句,使用属性parameters中的变脸进行替换 - * 对于insert into ?.? (?,?,?) using ?.? (?,?,?) tags(?, ?, ?) values(?, ?, ?) - * @param rawSql,可能是insert、select或其他,使用?做占位符 - * @return - */ - private String getNativeSql(String rawSql) { - return Utils.getNativeSql(rawSql, this.parameters); - } - @Override public void setNull(int parameterIndex, int sqlType) throws SQLException { if (isClosed()) @@ -224,16 +214,13 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); if (!isPrepared) return execute(this.rawSql); - final String sql = getNativeSql(rawSql); + final String sql = Utils.getNativeSql(rawSql, this.parameters); return execute(sql); } @Override public void addBatch() throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - - final String sql = getNativeSql(this.rawSql); + final String sql = Utils.getNativeSql(rawSql, this.parameters); addBatch(sql); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java index 530b433d42bf4b387db0e9973ddcf48e3844f2f3..13850f0b804fef1306789fe0dba0246a0bd8038a 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java @@ -6,6 +6,8 @@ import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import com.google.common.primitives.Shorts; import com.taosdata.jdbc.*; +import com.taosdata.jdbc.enums.TimestampPrecision; +import com.taosdata.jdbc.rs.enums.TimestampFormat; import com.taosdata.jdbc.utils.Utils; import java.math.BigDecimal; @@ -46,6 +48,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { columnNames.clear(); columns.clear(); this.resultSet.clear(); + this.metaData = new RestfulResultSetMetaData(this.database, null, this); return; } // get head @@ -131,7 +134,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { } } - private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException { switch (taosType) { case TSDBConstants.TSDB_DATA_TYPE_NULL: @@ -150,44 +152,8 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { return row.getFloat(colIndex); case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return row.getDouble(colIndex); - case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { - if (row.get(colIndex) == null) - return null; - String timestampFormat = this.statement.getConnection().getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT); - if ("TIMESTAMP".equalsIgnoreCase(timestampFormat)) { - Long value = row.getLong(colIndex); - //TODO: this implementation has bug if the timestamp bigger than 9999_9999_9999_9 - if (value < 1_0000_0000_0000_0L) - return new Timestamp(value); - long epochSec = value / 1000_000l; - long nanoAdjustment = value % 1000_000l * 1000l; - return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); - } - if ("UTC".equalsIgnoreCase(timestampFormat)) { - String value = row.getString(colIndex); - long epochSec = Timestamp.valueOf(value.substring(0, 19).replace("T", " ")).getTime() / 1000; - int fractionalSec = Integer.parseInt(value.substring(20, value.length() - 5)); - long nanoAdjustment = 0; - if (value.length() > 28) { - // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00 - nanoAdjustment = fractionalSec * 1000l; - } else { - // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00 - nanoAdjustment = fractionalSec * 1000_000l; - } - ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5)); - Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant(); - return Timestamp.from(instant); - } - String value = row.getString(colIndex); - if (value.length() <= 23) // ms timestamp: yyyy-MM-dd HH:mm:ss.SSS - return row.getTimestamp(colIndex); - // us timestamp: yyyy-MM-dd HH:mm:ss.SSSSSS - long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000; - long nanoAdjustment = Integer.parseInt(value.substring(20)) * 1000l; - Timestamp timestamp = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); - return timestamp; - } + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: + return parseTimestampColumnData(row, colIndex); case TSDBConstants.TSDB_DATA_TYPE_BINARY: return row.getString(colIndex) == null ? null : row.getString(colIndex).getBytes(); case TSDBConstants.TSDB_DATA_TYPE_NCHAR: @@ -197,7 +163,66 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { } } - public class Field { + private Timestamp parseTimestampColumnData(JSONArray row, int colIndex) throws SQLException { + if (row.get(colIndex) == null) + return null; + String tsFormatUpperCase = this.statement.getConnection().getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT).toUpperCase(); + TimestampFormat timestampFormat = TimestampFormat.valueOf(tsFormatUpperCase); + switch (timestampFormat) { + case TIMESTAMP: { + Long value = row.getLong(colIndex); + //TODO: this implementation has bug if the timestamp bigger than 9999_9999_9999_9 + if (value < 1_0000_0000_0000_0L) + return new Timestamp(value); + long epochSec = value / 1000_000l; + long nanoAdjustment = value % 1000_000l * 1000l; + return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + } + case UTC: { + String value = row.getString(colIndex); + long epochSec = Timestamp.valueOf(value.substring(0, 19).replace("T", " ")).getTime() / 1000; + int fractionalSec = Integer.parseInt(value.substring(20, value.length() - 5)); + long nanoAdjustment; + if (value.length() > 31) { + // ns timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSSSSS+0x00 + nanoAdjustment = fractionalSec; + } else if (value.length() > 28) { + // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00 + nanoAdjustment = fractionalSec * 1000L; + } else { + // ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00 + nanoAdjustment = fractionalSec * 1000_000L; + } + ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5)); + Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant(); + return Timestamp.from(instant); + } + case STRING: + default: { + String value = row.getString(colIndex); + TimestampPrecision precision = Utils.guessTimestampPrecision(value); + if (precision == TimestampPrecision.MS) { + // ms timestamp: yyyy-MM-dd HH:mm:ss.SSS + return row.getTimestamp(colIndex); + } + if (precision == TimestampPrecision.US) { + // us timestamp: yyyy-MM-dd HH:mm:ss.SSSSSS + long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000; + long nanoAdjustment = Integer.parseInt(value.substring(20)) * 1000L; + return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + } + if (precision == TimestampPrecision.NS) { + // ms timestamp: yyyy-MM-dd HH:mm:ss.SSSSSSSSS + long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000; + long nanoAdjustment = Integer.parseInt(value.substring(20)); + return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + } + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TIMESTAMP_PERCISION); + } + } + } + + public static class Field { String name; int type; int length; @@ -211,6 +236,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { this.note = note; this.taos_type = taos_type; } + } @Override @@ -334,6 +360,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { wasNull = true; return 0; } + wasNull = false; if (value instanceof Timestamp) { return ((Timestamp) value).getTime(); diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java index 7ead8bd1bbaeeb8fe1f24c951656888f6bba6b6f..a185abb709605cdbc9afecd26d33a1cac85ce37d 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSetMetaData.java @@ -8,20 +8,22 @@ import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class RestfulResultSetMetaData extends WrapperImpl implements ResultSetMetaData { private final String database; - private ArrayList fields; + private List fields; private final RestfulResultSet resultSet; public RestfulResultSetMetaData(String database, ArrayList fields, RestfulResultSet resultSet) { this.database = database; - this.fields = fields; + this.fields = fields == null ? Collections.emptyList() : fields; this.resultSet = resultSet; } - public ArrayList getFields() { + public List getFields() { return fields; } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..edc429857e4b47031b60f6a49a62f21e183d80ed --- /dev/null +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/enums/TimestampFormat.java @@ -0,0 +1,7 @@ +package com.taosdata.jdbc.rs.enums; + +public enum TimestampFormat { + STRING, + TIMESTAMP, + UTC +} diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java index b1c6dae6b3543337ae253c4cf94c2aaa5a31f9f5..ff27bdbdad2d5f56a4652ae822b9ba10c80c51b0 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/HttpClientPoolUtil.java @@ -16,13 +16,12 @@ import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; public class HttpClientPoolUtil { private static final String DEFAULT_CONTENT_TYPE = "application/json"; - private static final String DEFAULT_TOKEN = "cm9vdDp0YW9zZGF0YQ=="; private static final int DEFAULT_TIME_OUT = 15000; private static final int DEFAULT_MAX_PER_ROUTE = 32; private static final int DEFAULT_MAX_TOTAL = 1000; @@ -80,7 +79,7 @@ public class HttpClientPoolUtil { method.setHeader("Connection", "keep-alive"); method.setHeader("Authorization", "Taosd " + token); - method.setEntity(new StringEntity(data, Charset.forName("UTF-8"))); + method.setEntity(new StringEntity(data, StandardCharsets.UTF_8)); HttpContext context = HttpClientContext.create(); CloseableHttpResponse httpResponse = httpClient.execute(method, context); httpEntity = httpResponse.getEntity(); @@ -165,28 +164,18 @@ public class HttpClientPoolUtil { httpEntity = httpResponse.getEntity(); if (httpEntity != null) { responseBody = EntityUtils.toString(httpEntity, "UTF-8"); -// logger.info("请求URL: " + uri + "+ 返回状态码:" + httpResponse.getStatusLine().getStatusCode()); } } catch (Exception e) { if (method != null) { method.abort(); } e.printStackTrace(); -// logger.error("execute get request exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):" -// + (System.currentTimeMillis() - startTime)); - System.out.println("log:调用 HttpClientPoolUtil execute get request exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):" - + (System.currentTimeMillis() - startTime)); } finally { if (httpEntity != null) { try { EntityUtils.consumeQuietly(httpEntity); } catch (Exception e) { -// e.printStackTrace(); -// logger.error("close response exception, url:" + uri + ", exception:" + e.toString() -// + ",cost time(ms):" + (System.currentTimeMillis() - startTime)); - new Exception("close response exception, url:" + uri + ", exception:" + e.toString() - + ",cost time(ms):" + (System.currentTimeMillis() - startTime)) - .printStackTrace(); + new Exception("close response exception, url:" + uri + ", exception:" + e.toString() + ",cost time(ms):" + (System.currentTimeMillis() - startTime)).printStackTrace(); } } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java index 8ab610fec6541e96d8b4b997c6883dddc01f1549..4c92d27a28625e407d94e34da60aa7a57760baac 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/utils/Utils.java @@ -3,14 +3,13 @@ package com.taosdata.jdbc.utils; import com.google.common.collect.Range; import com.google.common.collect.RangeSet; import com.google.common.collect.TreeRangeSet; +import com.taosdata.jdbc.enums.TimestampPrecision; import java.nio.charset.Charset; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; -import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; @@ -25,39 +24,52 @@ public class Utils { private static Pattern ptn = Pattern.compile(".*?'"); - private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() - .appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter(); - private static final DateTimeFormatter formatter2 = new DateTimeFormatterBuilder() - .appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").toFormatter(); + private static final DateTimeFormatter milliSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter(); + private static final DateTimeFormatter microSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").toFormatter(); + private static final DateTimeFormatter nanoSecFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS").toFormatter(); public static Time parseTime(String timestampStr) throws DateTimeParseException { - LocalTime time; - try { - time = LocalTime.parse(timestampStr, formatter); - } catch (DateTimeParseException e) { - time = LocalTime.parse(timestampStr, formatter2); - } - return Time.valueOf(time); + LocalDateTime dateTime = parseLocalDateTime(timestampStr); + return dateTime != null ? Time.valueOf(dateTime.toLocalTime()) : null; } - public static Date parseDate(String timestampStr) throws DateTimeParseException { - LocalDate date; - try { - date = LocalDate.parse(timestampStr, formatter); - } catch (DateTimeParseException e) { - date = LocalDate.parse(timestampStr, formatter2); - } - return Date.valueOf(date); + public static Date parseDate(String timestampStr) { + LocalDateTime dateTime = parseLocalDateTime(timestampStr); + return dateTime != null ? Date.valueOf(String.valueOf(dateTime)) : null; } public static Timestamp parseTimestamp(String timeStampStr) { - LocalDateTime dateTime; + LocalDateTime dateTime = parseLocalDateTime(timeStampStr); + return dateTime != null ? Timestamp.valueOf(dateTime) : null; + } + + private static LocalDateTime parseLocalDateTime(String timeStampStr) { try { - dateTime = LocalDateTime.parse(timeStampStr, formatter); + return parseMilliSecTimestamp(timeStampStr); } catch (DateTimeParseException e) { - dateTime = LocalDateTime.parse(timeStampStr, formatter2); + try { + return parseMicroSecTimestamp(timeStampStr); + } catch (DateTimeParseException ee) { + try { + return parseNanoSecTimestamp(timeStampStr); + } catch (DateTimeParseException eee) { + eee.printStackTrace(); + } + } } - return Timestamp.valueOf(dateTime); + return null; + } + + private static LocalDateTime parseMilliSecTimestamp(String timeStampStr) throws DateTimeParseException { + return LocalDateTime.parse(timeStampStr, milliSecFormatter); + } + + private static LocalDateTime parseMicroSecTimestamp(String timeStampStr) throws DateTimeParseException { + return LocalDateTime.parse(timeStampStr, microSecFormatter); + } + + private static LocalDateTime parseNanoSecTimestamp(String timeStampStr) throws DateTimeParseException { + return LocalDateTime.parse(timeStampStr, nanoSecFormatter); } public static String escapeSingleQuota(String origin) { @@ -93,6 +105,8 @@ public class Utils { } public static String getNativeSql(String rawSql, Object[] parameters) { + if (parameters == null || !rawSql.contains("?")) + return rawSql; // toLowerCase String preparedSql = rawSql.trim().toLowerCase(); String[] clause = new String[]{"values\\s*\\(.*?\\)", "tags\\s*\\(.*?\\)", "where\\s*.*"}; @@ -167,13 +181,47 @@ public class Utils { }).collect(Collectors.joining()); } - public static String formatTimestamp(Timestamp timestamp) { int nanos = timestamp.getNanos(); if (nanos % 1000000l != 0) - return timestamp.toLocalDateTime().format(formatter2); - return timestamp.toLocalDateTime().format(formatter); + return timestamp.toLocalDateTime().format(microSecFormatter); + return timestamp.toLocalDateTime().format(milliSecFormatter); + } + + public static TimestampPrecision guessTimestampPrecision(String value) { + if (isMilliSecFormat(value)) + return TimestampPrecision.MS; + if (isMicroSecFormat(value)) + return TimestampPrecision.US; + if (isNanoSecFormat(value)) + return TimestampPrecision.NS; + return TimestampPrecision.UNKNOWN; + } + + private static boolean isMilliSecFormat(String timestampStr) { + try { + milliSecFormatter.parse(timestampStr); + } catch (DateTimeParseException e) { + return false; + } + return true; } + private static boolean isMicroSecFormat(String timestampStr) { + try { + microSecFormatter.parse(timestampStr); + } catch (DateTimeParseException e) { + return false; + } + return true; + } + private static boolean isNanoSecFormat(String timestampStr) { + try { + nanoSecFormatter.parse(timestampStr); + } catch (DateTimeParseException e) { + return false; + } + return true; + } } diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java index 3f8bef4a7ea00915925b2924b08ad8c453420416..40ff5c23ef9866d0a7d8fd5c594f2b933ed80b2a 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBPreparedStatementTest.java @@ -5,7 +5,6 @@ import org.junit.*; import java.io.IOException; import java.math.BigDecimal; import java.sql.*; -import java.time.LocalTime; import java.util.ArrayList; import java.util.Random; @@ -15,6 +14,7 @@ public class TSDBPreparedStatementTest { private static Connection conn; private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String sql_select = "select * from t1 where ts >= ? and ts < ? and f1 >= ?"; + private static final String dbname = "test_pstmt_jni"; private PreparedStatement pstmt_insert; private PreparedStatement pstmt_select; @@ -299,53 +299,53 @@ public class TSDBPreparedStatementTest { } @Test - public void executeTest() throws SQLException { - Statement stmt = conn.createStatement(); + public void executeTest() throws SQLException { + Statement stmt = conn.createStatement(); - int numOfRows = 1000; + int numOfRows = 1000; - for (int loop = 0; loop < 10; loop++){ + for (int loop = 0; loop < 10; loop++) { stmt.execute("drop table if exists weather_test"); - stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); + stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? values(?, ?, ?, ?, ?, ?, ?, ?)"); Random r = new Random(); s.setTableName("weather_test"); - + ArrayList ts = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { + for (int i = 0; i < numOfRows; i++) { ts.add(System.currentTimeMillis() + i); - } + } s.setTimestamp(0, ts); int random = 10 + r.nextInt(5); - ArrayList s2 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + ArrayList s2 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s2.add(null); - }else{ + } else { s2.add("分支" + i % 4); } - } - s.setNString(1, s2, 4); + } + s.setNString(1, s2, 4); random = 10 + r.nextInt(5); - ArrayList s3 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + ArrayList s3 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s3.add(null); - }else{ + } else { s3.add(r.nextFloat()); } - } + } s.setFloat(2, s3); random = 10 + r.nextInt(5); ArrayList s4 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s4.add(null); - }else{ + } else { s4.add(r.nextDouble()); } } @@ -353,47 +353,47 @@ public class TSDBPreparedStatementTest { random = 10 + r.nextInt(5); ArrayList ts2 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { ts2.add(null); - }else{ + } else { ts2.add(System.currentTimeMillis() + i); } } s.setTimestamp(4, ts2); random = 10 + r.nextInt(5); - ArrayList vals = new ArrayList<>(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + ArrayList vals = new ArrayList<>(); + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { vals.add(null); - }else{ + } else { vals.add(r.nextInt()); - } + } } s.setInt(5, vals); random = 10 + r.nextInt(5); ArrayList sb = new ArrayList<>(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { sb.add(null); - }else{ + } else { sb.add(i % 2 == 0 ? true : false); } } - s.setBoolean(6, sb); + s.setBoolean(6, sb); random = 10 + r.nextInt(5); ArrayList s5 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s5.add(null); - }else{ + } else { s5.add("test" + i % 10); } } - s.setString(7, s5, 10); + s.setString(7, s5, 10); s.columnDataAddBatch(); s.columnDataExecuteBatch(); @@ -403,54 +403,54 @@ public class TSDBPreparedStatementTest { PreparedStatement statement = conn.prepareStatement(sql); ResultSet rs = statement.executeQuery(); int rows = 0; - while(rs.next()) { + while (rs.next()) { rows++; } - Assert.assertEquals(numOfRows, rows); + Assert.assertEquals(numOfRows, rows); } } @Test - public void bindDataSelectColumnTest() throws SQLException { - Statement stmt = conn.createStatement(); + public void bindDataSelectColumnTest() throws SQLException { + Statement stmt = conn.createStatement(); - int numOfRows = 1000; + int numOfRows = 1000; - for (int loop = 0; loop < 10; loop++){ + for (int loop = 0; loop < 10; loop++) { stmt.execute("drop table if exists weather_test"); - stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); + stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? (ts, f1, f7) values(?, ?, ?)"); Random r = new Random(); s.setTableName("weather_test"); - + ArrayList ts = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { + for (int i = 0; i < numOfRows; i++) { ts.add(System.currentTimeMillis() + i); - } + } s.setTimestamp(0, ts); int random = 10 + r.nextInt(5); - ArrayList s2 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + ArrayList s2 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s2.add(null); - }else{ + } else { s2.add("分支" + i % 4); } - } - s.setNString(1, s2, 4); + } + s.setNString(1, s2, 4); random = 10 + r.nextInt(5); ArrayList s3 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - if(i % random == 0) { + for (int i = 0; i < numOfRows; i++) { + if (i % random == 0) { s3.add(null); - }else{ + } else { s3.add("test" + i % 10); } } - s.setString(2, s3, 10); + s.setString(2, s3, 10); s.columnDataAddBatch(); s.columnDataExecuteBatch(); @@ -460,30 +460,30 @@ public class TSDBPreparedStatementTest { PreparedStatement statement = conn.prepareStatement(sql); ResultSet rs = statement.executeQuery(); int rows = 0; - while(rs.next()) { + while (rs.next()) { rows++; } - Assert.assertEquals(numOfRows, rows); + Assert.assertEquals(numOfRows, rows); } } @Test - public void bindDataWithSingleTagTest() throws SQLException { - Statement stmt = conn.createStatement(); + public void bindDataWithSingleTagTest() throws SQLException { + Statement stmt = conn.createStatement(); - String types[] = new String[] {"tinyint", "smallint", "int", "bigint", "bool", "float", "double", "binary(10)", "nchar(10)"}; + String types[] = new String[]{"tinyint", "smallint", "int", "bigint", "bool", "float", "double", "binary(10)", "nchar(10)"}; for (String type : types) { stmt.execute("drop table if exists weather_test"); stmt.execute("create table weather_test(ts timestamp, f1 nchar(10), f2 binary(10)) tags (t " + type + ")"); int numOfRows = 1; - + TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?) values(?, ?, ?)"); Random r = new Random(); s.setTableName("w1"); - - switch(type) { + + switch (type) { case "tinyint": case "smallint": case "int": @@ -508,37 +508,37 @@ public class TSDBPreparedStatementTest { default: break; } - - + + ArrayList ts = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { + for (int i = 0; i < numOfRows; i++) { ts.add(System.currentTimeMillis() + i); - } + } s.setTimestamp(0, ts); - + int random = 10 + r.nextInt(5); - ArrayList s2 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - s2.add("分支" + i % 4); - } + ArrayList s2 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { + s2.add("分支" + i % 4); + } s.setNString(1, s2, 10); - + random = 10 + r.nextInt(5); - ArrayList s3 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { - s3.add("test" + i % 4); - } + ArrayList s3 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { + s3.add("test" + i % 4); + } s.setString(2, s3, 10); - + s.columnDataAddBatch(); s.columnDataExecuteBatch(); s.columnDataCloseBatch(); - + String sql = "select * from weather_test"; PreparedStatement statement = conn.prepareStatement(sql); ResultSet rs = statement.executeQuery(); int rows = 0; - while(rs.next()) { + while (rs.next()) { rows++; } Assert.assertEquals(numOfRows, rows); @@ -547,32 +547,32 @@ public class TSDBPreparedStatementTest { @Test - public void bindDataWithMultipleTagsTest() throws SQLException { - Statement stmt = conn.createStatement(); - + public void bindDataWithMultipleTagsTest() throws SQLException { + Statement stmt = conn.createStatement(); + stmt.execute("drop table if exists weather_test"); stmt.execute("create table weather_test(ts timestamp, f1 nchar(10), f2 binary(10)) tags (t1 int, t2 binary(10))"); int numOfRows = 1; - TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?,?) (ts, f2) values(?, ?)"); - s.setTableName("w2"); + TSDBPreparedStatement s = (TSDBPreparedStatement) conn.prepareStatement("insert into ? using weather_test tags(?,?) (ts, f2) values(?, ?)"); + s.setTableName("w2"); s.setTagInt(0, 1); s.setTagString(1, "test"); - - + + ArrayList ts = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { + for (int i = 0; i < numOfRows; i++) { ts.add(System.currentTimeMillis() + i); - } + } s.setTimestamp(0, ts); - - ArrayList s2 = new ArrayList(); - for(int i = 0; i < numOfRows; i++) { + + ArrayList s2 = new ArrayList(); + for (int i = 0; i < numOfRows; i++) { s2.add("test" + i % 4); } s.setString(1, s2, 10); - + s.columnDataAddBatch(); s.columnDataExecuteBatch(); s.columnDataCloseBatch(); @@ -581,21 +581,20 @@ public class TSDBPreparedStatementTest { PreparedStatement statement = conn.prepareStatement(sql); ResultSet rs = statement.executeQuery(); int rows = 0; - while(rs.next()) { + while (rs.next()) { rows++; } Assert.assertEquals(numOfRows, rows); - } - - @Test + + @Test(expected = SQLException.class) public void createTwoSameDbTest() throws SQLException { - Statement stmt = conn.createStatement(); - + // when + Statement stmt = conn.createStatement(); + stmt.execute("create database dbtest"); stmt.execute("create database dbtest"); - Assert.assertThrows(SQLException.class, () -> stmt.execute("create database dbtest")); } - + @Test public void setBoolean() throws SQLException { // given @@ -1097,9 +1096,9 @@ public class TSDBPreparedStatementTest { try { conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"); try (Statement stmt = conn.createStatement()) { - stmt.execute("drop database if exists test_pstmt_jni"); - stmt.execute("create database if not exists test_pstmt_jni"); - stmt.execute("use test_pstmt_jni"); + stmt.execute("drop database if exists " + dbname); + stmt.execute("create database if not exists " + dbname); + stmt.execute("use " + dbname); } } catch (SQLException e) { e.printStackTrace(); @@ -1109,6 +1108,9 @@ public class TSDBPreparedStatementTest { @AfterClass public static void afterClass() { try { + Statement statement = conn.createStatement(); + statement.execute("drop database if exists " + dbname); + statement.close(); if (conn != null) conn.close(); } catch (SQLException e) { diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java similarity index 55% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java index 2704d4cfa558ebdb6885c320d7ba775b36b99f09..212a751ec302ae02552d084248d34b35a7b21c59 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4174Test.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/DoubleQuoteInSqlTest.java @@ -7,56 +7,64 @@ import org.junit.*; import java.sql.*; import java.util.Properties; -public class TD4174Test { - private Connection conn; +public class DoubleQuoteInSqlTest { private static final String host = "127.0.0.1"; + private static final String dbname = "td4174"; + + private Connection conn; @Test public void test() { + // given long ts = System.currentTimeMillis(); + JSONObject value = new JSONObject(); + value.put("name", "John Smith"); + value.put("age", 20); + + // when + int ret = 0; try (PreparedStatement pstmt = conn.prepareStatement("insert into weather values(" + ts + ", ?)")) { - JSONObject value = new JSONObject(); - value.put("name", "John Smith"); - value.put("age", 20); - Assert.assertEquals("{\"name\":\"John Smith\",\"age\":20}",value.toJSONString()); pstmt.setString(1, value.toJSONString()); - - int ret = pstmt.executeUpdate(); - Assert.assertEquals(1, ret); + ret = pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } - } - public static void main(String[] args) { - JSONObject value = new JSONObject(); - value.put("name", "John Smith"); - value.put("age", 20); - System.out.println(value.toJSONString()); + // then + Assert.assertEquals("{\"name\":\"John Smith\",\"age\":20}", value.toJSONString()); + Assert.assertEquals(1, ret); } @Before - public void before() throws SQLException { + public void before() { String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"; Properties properties = new Properties(); properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8"); properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); - conn = DriverManager.getConnection(url, properties); - try (Statement stmt = conn.createStatement()) { - stmt.execute("drop database if exists td4174"); - stmt.execute("create database if not exists td4174"); - stmt.execute("use td4174"); + try { + conn = DriverManager.getConnection(url, properties); + Statement stmt = conn.createStatement(); + stmt.execute("drop database if exists " + dbname); + stmt.execute("create database if not exists " + dbname); + stmt.execute("use " + dbname); stmt.execute("create table weather(ts timestamp, text binary(64))"); + } catch (SQLException e) { + e.printStackTrace(); } } @After - public void after() throws SQLException { - if (conn != null) + public void after() { + try { + Statement stmt = conn.createStatement(); + stmt.execute("drop database if exists " + dbname); + stmt.close(); conn.close(); - + } catch (SQLException e) { + e.printStackTrace(); + } } } diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java similarity index 98% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java index f9b111bb12f189a7a42c7944237aa01ebb008d25..54e4273ea3e54c8db18ca11c10f960468ab91c75 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInJniTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionJNITest.java @@ -10,7 +10,7 @@ import org.junit.Test; import java.sql.*; import java.util.Properties; -public class TwoTypeTimestampPercisionInJniTest { +public class MicroSecondPrecisionJNITest { private static final String host = "127.0.0.1"; private static final String ms_timestamp_db = "ms_precision_test"; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java similarity index 99% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java index 5c83b5a9da527a55387a8ad399e78462b6fab63c..7e9f04cd6360431a3fe6c29a2f0eb61fbdc9e7c4 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TwoTypeTimestampPercisionInRestfulTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MicroSecondPrecisionRestfulTest.java @@ -10,10 +10,9 @@ import org.junit.Test; import java.sql.*; import java.util.Properties; -public class TwoTypeTimestampPercisionInRestfulTest { +public class MicroSecondPrecisionRestfulTest { private static final String host = "127.0.0.1"; - private static final String ms_timestamp_db = "ms_precision_test"; private static final String us_timestamp_db = "us_precision_test"; private static final long timestamp1 = System.currentTimeMillis(); diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java new file mode 100644 index 0000000000000000000000000000000000000000..4f2c87966ad6bb8390bab47b795e7d952725baf5 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampJNITest.java @@ -0,0 +1,182 @@ +package com.taosdata.jdbc.cases; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.*; +import java.time.Instant; +import java.util.Random; + +public class NanoSecondTimestampJNITest { + + private static final String host = "127.0.0.1"; + private static final String dbname = "nano_sec_test"; + private static final Random random = new Random(System.currentTimeMillis()); + private static Connection conn; + + @Test + public void insertUsingLongValue() { + // given + long ms = System.currentTimeMillis(); + long ns = ms * 1000_000 + random.nextInt(1000_000); + + // when + int ret = 0; + try (Statement stmt = conn.createStatement()) { + ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)"); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void insertUsingStringValue() { + // given + + // when + int ret = 0; + try (Statement stmt = conn.createStatement()) { + ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('2021-01-01 12:00:00.123456789', 12.3, 4)"); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void insertUsingTimestampValue() { + // given + long epochSec = System.currentTimeMillis() / 1000; + long nanoAdjustment = random.nextInt(1000_000_000); + Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + + // when + int ret = 0; + String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setTimestamp(1, ts); + pstmt.setFloat(2, 12.34f); + pstmt.setInt(3, 55); + ret = pstmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void selectUsingLongValue() throws SQLException { + // given + long ms = System.currentTimeMillis(); + long ns = ms * 1000_000L + random.nextInt(1000_000); + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)"); + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + long actual = rs.getLong(1); + Assert.assertEquals(ms, actual); + actual = rs.getLong("ts"); + Assert.assertEquals(ms, actual); + } + + @Test + public void selectUsingStringValue() throws SQLException { + // given + String timestampStr = "2021-01-01 12:00:00.123456789"; + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('" + timestampStr + "', 12.3, 4)"); + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + String actual = rs.getString(1); + Assert.assertEquals(timestampStr, actual); + actual = rs.getString("ts"); + Assert.assertEquals(timestampStr, actual); + } + + @Test + public void selectUsingTimestampValue() throws SQLException { + // given + long timeMillis = System.currentTimeMillis(); + long epochSec = timeMillis / 1000; + long nanoAdjustment = (timeMillis % 1000) * 1000_000L + random.nextInt(1000_000); + Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + + // insert one row + String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setTimestamp(1, ts); + pstmt.setFloat(2, 12.34f); + pstmt.setInt(3, 55); + pstmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Timestamp actual = rs.getTimestamp(1); + Assert.assertEquals(ts, actual); + actual = rs.getTimestamp("ts"); + Assert.assertEquals(ts, actual); + Assert.assertEquals(timeMillis, actual.getTime()); + Assert.assertEquals(nanoAdjustment, actual.getNanos()); + } + + @Before + public void before() { + try (Statement stmt = conn.createStatement()) { + stmt.execute("drop table if exists weather"); + stmt.execute("create table weather(ts timestamp, temperature float, humidity int)"); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @BeforeClass + public static void beforeClass() { + final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"; + try { + conn = DriverManager.getConnection(url); + Statement stmt = conn.createStatement(); + stmt.execute("drop database if exists " + dbname); + stmt.execute("create database if not exists " + dbname + " precision 'ns'"); + stmt.execute("use " + dbname); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4271f918b9b096000cc59b730d7b70f032a0ab29 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NanoSecondTimestampRestfulTest.java @@ -0,0 +1,182 @@ +package com.taosdata.jdbc.cases; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.*; +import java.time.Instant; +import java.util.Random; + +public class NanoSecondTimestampRestfulTest { + + private static final String host = "127.0.0.1"; + private static final String dbname = "nano_sec_test"; + private static final Random random = new Random(System.currentTimeMillis()); + private static Connection conn; + + @Test + public void insertUsingLongValue() { + // given + long ms = System.currentTimeMillis(); + long ns = ms * 1000_000 + random.nextInt(1000_000); + + // when + int ret = 0; + try (Statement stmt = conn.createStatement()) { + ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)"); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void insertUsingStringValue() { + // given + + // when + int ret = 0; + try (Statement stmt = conn.createStatement()) { + ret = stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('2021-01-01 12:00:00.123456789', 12.3, 4)"); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void insertUsingTimestampValue() { + // given + long epochSec = System.currentTimeMillis() / 1000; + long nanoAdjustment = random.nextInt(1000_000_000); + Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + + // when + int ret = 0; + String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setTimestamp(1, ts); + pstmt.setFloat(2, 12.34f); + pstmt.setInt(3, 55); + ret = pstmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(1, ret); + } + + @Test + public void selectUsingLongValue() throws SQLException { + // given + long ms = System.currentTimeMillis(); + long ns = ms * 1000_000L + random.nextInt(1000_000); + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("insert into weather(ts, temperature, humidity) values(" + ns + ", 12.3, 4)"); + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + long actual = rs.getLong(1); + Assert.assertEquals(ms, actual); + actual = rs.getLong("ts"); + Assert.assertEquals(ms, actual); + } + + @Test + public void selectUsingStringValue() throws SQLException { + // given + String timestampStr = "2021-01-01 12:00:00.123456789"; + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("insert into weather(ts, temperature, humidity) values('" + timestampStr + "', 12.3, 4)"); + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + String actual = rs.getString(1); + Assert.assertEquals(timestampStr, actual); + actual = rs.getString("ts"); + Assert.assertEquals(timestampStr, actual); + } + + @Test + public void selectUsingTimestampValue() throws SQLException { + // given + long timeMillis = System.currentTimeMillis(); + long epochSec = timeMillis / 1000; + long nanoAdjustment = (timeMillis % 1000) * 1000_000L + random.nextInt(1000_000); + Timestamp ts = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + + // insert one row + String sql = "insert into weather(ts, temperature, humidity) values( ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setTimestamp(1, ts); + pstmt.setFloat(2, 12.34f); + pstmt.setInt(3, 55); + pstmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // when + ResultSet rs = null; + try (Statement stmt = conn.createStatement()) { + rs = stmt.executeQuery("select * from weather"); + rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Timestamp actual = rs.getTimestamp(1); + Assert.assertEquals(ts, actual); + actual = rs.getTimestamp("ts"); + Assert.assertEquals(ts, actual); + Assert.assertEquals(timeMillis, actual.getTime()); + Assert.assertEquals(nanoAdjustment, actual.getNanos()); + } + + @Before + public void before() { + try (Statement stmt = conn.createStatement()) { + stmt.execute("drop table if exists weather"); + stmt.execute("create table weather(ts timestamp, temperature float, humidity int)"); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @BeforeClass + public static void beforeClass() { + final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"; + try { + conn = DriverManager.getConnection(url); + Statement stmt = conn.createStatement(); + stmt.execute("drop database if exists " + dbname); + stmt.execute("create database if not exists " + dbname + " precision 'ns'"); + stmt.execute("use " + dbname); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java similarity index 97% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java index 782125144c4fbe8dcc4bdfd4769e95e5119ea32f..076125a752e5c4e81e24cbfa3299fa349939094b 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcJniTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetJNITest.java @@ -6,7 +6,7 @@ import org.junit.Test; import java.sql.*; -public class NullValueInResultSetForJdbcJniTest { +public class NullValueInResultSetJNITest { private static final String host = "127.0.0.1"; Connection conn; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java similarity index 97% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java index f2ac94adc1b6e7d94e52650dcfbb5664c8f39760..ea6e36ec1d005e48f36ee1283935664aca6fcc47 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetForJdbcRestfulTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetRestfulTest.java @@ -6,7 +6,7 @@ import org.junit.Test; import java.sql.*; -public class NullValueInResultSetForJdbcRestfulTest { +public class NullValueInResultSetRestfulTest { private static final String host = "127.0.0.1"; Connection conn; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java similarity index 99% rename from src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java rename to src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java index c6fba81eb24b9b8c08fd553ca57b1e1d68bb81e0..61d767b5cf2bcd2e478de74e5f4bb8d66ad21678 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD3841Test.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/NullValueInResultSetTest.java @@ -7,7 +7,7 @@ import org.junit.*; import java.sql.*; import java.util.Properties; -public class TD3841Test { +public class NullValueInResultSetTest { private static final String host = "127.0.0.1"; private static Properties properties; private static Connection conn_restful; diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java new file mode 100644 index 0000000000000000000000000000000000000000..ed78c2561ec437e3b7c6a0ab8d3e91699c2572af --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertJNITest.java @@ -0,0 +1,98 @@ +package com.taosdata.jdbc.cases; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.sql.*; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PreparedStatementBatchInsertJNITest { + + private static final String host = "127.0.0.1"; + private static final String dbname = "td4668"; + + private final Random random = new Random(System.currentTimeMillis()); + private Connection conn; + + @Test + public void test() { + // given + long ts = System.currentTimeMillis(); + List rows = IntStream.range(0, 10).mapToObj(i -> { + Object[] row = new Object[6]; + final String groupId = String.format("%02d", random.nextInt(100)); + // table name (d + groupId)组合 + row[0] = "d" + groupId; + // tag + row[1] = groupId; + // ts + row[2] = ts + i; + // current 电流 + row[3] = random.nextFloat(); + // voltage 电压 + row[4] = Math.random() > 0.5 ? 220 : 380; + // phase 相位 + row[5] = random.nextInt(10); + return row; + }).collect(Collectors.toList()); + final String sql = "INSERT INTO ? (TS,CURRENT,VOLTAGE,PHASE) USING METERS TAGS (?) VALUES (?,?,?,?)"; + + // when + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + for (Object[] row : rows) { + for (int i = 0; i < row.length; i++) { + pstmt.setObject(i + 1, row[i]); + } + pstmt.addBatch(); + } + pstmt.executeBatch(); + } catch (SQLException e) { + e.printStackTrace(); + Assert.fail(); + } + + // then + try (Statement stmt = conn.createStatement()) { + ResultSet rs = stmt.executeQuery("select * from meters"); + int count = 0; + while (rs.next()) { + count++; + } + Assert.assertEquals(10, count); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Before + public void before() { + try { + conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"); + 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 meters(ts timestamp, current float, voltage int, phase int) tags(groupId int)"); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @After + 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/PreparedStatementBatchInsertRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertRestfulTest.java new file mode 100644 index 0000000000000000000000000000000000000000..90b285381a2ab57b170da327a95dde4c8991ce21 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/PreparedStatementBatchInsertRestfulTest.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 PreparedStatementBatchInsertRestfulTest { + + 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 rows = IntStream.range(0, 10).mapToObj(i -> { + Object[] row = new Object[6]; + final String groupId = String.format("%02d", random.nextInt(100)); + // table name (d + groupId)组合 + row[0] = "d" + groupId; + // tag + row[1] = groupId; + // ts + row[2] = ts + i; + // current 电流 + row[3] = random.nextFloat(); + // voltage 电压 + row[4] = Math.random() > 0.5 ? 220 : 380; + // phase 相位 + row[5] = random.nextInt(10); + return row; + }).collect(Collectors.toList()); + final String sql = "INSERT INTO ? (TS,CURRENT,VOLTAGE,PHASE) USING METERS TAGS (?) VALUES (?,?,?,?)"; + + // when + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + for (Object[] row : rows) { + for (int i = 0; i < row.length; i++) { + pstmt.setObject(i + 1, row[i]); + } + pstmt.addBatch(); + } + pstmt.executeBatch(); + } catch (SQLException e) { + e.printStackTrace(); + Assert.fail(); + } + + // then + try (Statement stmt = conn.createStatement()) { + ResultSet rs = stmt.executeQuery("select * from meters"); + int count = 0; + while (rs.next()) { + count++; + } + Assert.assertEquals(10, count); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Before + public void before() { + try { + conn = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"); + 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 meters(ts timestamp, current float, voltage int, phase int) tags(groupId int)"); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @After + 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/ResultSetMetaShouldNotBeNullRestfulTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ResultSetMetaShouldNotBeNullRestfulTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f6d6bb25566a8c6060311a1cf0c918a0456b8c24 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ResultSetMetaShouldNotBeNullRestfulTest.java @@ -0,0 +1,86 @@ +package com.taosdata.jdbc.cases; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.sql.*; + +public class ResultSetMetaShouldNotBeNullRestfulTest { + + private static final String host = "127.0.0.1"; + private static final String dbname = "td4745"; + + private Connection connection; + + @Test + public void testExecuteQuery() { + // given + ResultSetMetaData metaData = null; + int columnCount = -1; + + // when + try { + Statement statement = connection.createStatement(); + metaData = statement.executeQuery("select * from weather").getMetaData(); + columnCount = metaData.getColumnCount(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertNotNull(metaData); + Assert.assertEquals(0, columnCount); + } + + @Test + public void testExecute() { + // given + ResultSetMetaData metaData = null; + int columnCount = -1; + boolean execute = false; + // when + try { + Statement statement = connection.createStatement(); + execute = statement.execute("select * from weather"); + metaData = statement.getResultSet().getMetaData(); + columnCount = metaData.getColumnCount(); + } catch (SQLException e) { + e.printStackTrace(); + } + + // then + Assert.assertEquals(true, execute); + Assert.assertNotNull(metaData); + Assert.assertEquals(0, columnCount); + } + + @Before + public void before() { + try { + connection = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"); + Statement stmt = connection.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, temperature float)"); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @After + public void after() { + try { + Statement stmt = connection.createStatement(); + stmt.execute("drop database if exists " + dbname); + stmt.close(); + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4144Test.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4144Test.java deleted file mode 100644 index 6f29f64111c51600303ad73d517faaa7c59cfe7c..0000000000000000000000000000000000000000 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/TD4144Test.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.taosdata.jdbc.cases; - -import com.taosdata.jdbc.TSDBConnection; -import com.taosdata.jdbc.TSDBDriver; -import com.taosdata.jdbc.TSDBResultSet; -import com.taosdata.jdbc.TSDBSubscribe; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.sql.DriverManager; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -public class TD4144Test { - - private static TSDBConnection connection; - private static final String host = "127.0.0.1"; - - private static final String topic = "topic-meter-current-bg-10"; - private static final String sql = "select * from meters where current > 10"; - private static final String sql2 = "select * from meters where ts >= '2020-08-15 12:20:00.000'"; - - - @Test - public void test() throws SQLException { - TSDBSubscribe subscribe = null; - TSDBResultSet res = null; - boolean hasNext = false; - - try { - subscribe = connection.subscribe(topic, sql, false); - int count = 0; - while (true) { - // 等待1秒,避免频繁调用 consume,给服务端造成压力 - TimeUnit.SECONDS.sleep(1); - if (res == null) { - // 消费数据 - res = subscribe.consume(); - hasNext = res.next(); - } - - if (res == null) { - continue; - } - ResultSetMetaData metaData = res.getMetaData(); - int number = 0; - while (hasNext) { - int columnCount = metaData.getColumnCount(); - for (int i = 1; i <= columnCount; i++) { - System.out.print(metaData.getColumnLabel(i) + ": " + res.getString(i) + "\t"); - } - System.out.println(); - count++; - number++; - hasNext = res.next(); - if (!hasNext) { - res.close(); - res = null; - System.out.println("rows: " + count); - } - if (hasNext == true && number >= 10) { - System.out.println("batch" + number); - break; - } - } - - } - - } catch (SQLException | InterruptedException throwables) { - throwables.printStackTrace(); - } finally { - if (subscribe != null) - subscribe.close(true); - } - } - - @BeforeClass - public static void beforeClass() throws SQLException { - Properties properties = new Properties(); - properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); - properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); - String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata"; - connection = (DriverManager.getConnection(url, properties)).unwrap(TSDBConnection.class); - try (Statement stmt = connection.createStatement()) { - stmt.execute("drop database if exists power"); - stmt.execute("create database if not exists power"); - stmt.execute("use power"); - stmt.execute("create table meters(ts timestamp, current float, voltage int, phase int) tags(location binary(64), groupId int)"); - stmt.execute("create table d1001 using meters tags(\"Beijing.Chaoyang\", 2)"); - stmt.execute("create table d1002 using meters tags(\"Beijing.Haidian\", 2)"); - stmt.execute("insert into d1001 values(\"2020-08-15 12:00:00.000\", 12, 220, 1),(\"2020-08-15 12:10:00.000\", 12.3, 220, 2),(\"2020-08-15 12:20:00.000\", 12.2, 220, 1)"); - stmt.execute("insert into d1002 values(\"2020-08-15 12:00:00.000\", 9.9, 220, 1),(\"2020-08-15 12:10:00.000\", 10.3, 220, 1),(\"2020-08-15 12:20:00.000\", 11.2, 220, 1)"); - } - } - - @AfterClass - public static void afterClass() throws SQLException { - if (connection != null) - connection.close(); - } -} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/utils/UtilsTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/utils/UtilsTest.java index c861ef296607b244e4564423ad4024ea1f13df5d..ee83f6ceb2d412613129611e2a575a7ad4922db0 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/utils/UtilsTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/utils/UtilsTest.java @@ -3,22 +3,98 @@ package com.taosdata.jdbc.utils; import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.*; +import java.util.stream.Stream; public class UtilsTest { @Test public void escapeSingleQuota() { + // given String s = "'''''a\\'"; + // when String news = Utils.escapeSingleQuota(s); + // then Assert.assertEquals("\\'\\'\\'\\'\\'a\\'", news); + // given s = "\'''''a\\'"; + // when news = Utils.escapeSingleQuota(s); + // then Assert.assertEquals("\\'\\'\\'\\'\\'a\\'", news); + // given s = "\'\'\'\''a\\'"; + // when news = Utils.escapeSingleQuota(s); + // then Assert.assertEquals("\\'\\'\\'\\'\\'a\\'", news); } + + @Test + public void getNativeSqlReplaceQuestionMarks() { + // given + String nativeSql = "insert into ?.? (ts, temperature, humidity) using ?.? tags(?,?) values(now, ?, ?)"; + Object[] parameters = Stream.of("test", "t1", "test", "weather", "beijing", 1, 12.2, 4).toArray(); + + // when + String actual = Utils.getNativeSql(nativeSql, parameters); + + // then + String expected = "insert into test.t1 (ts, temperature, humidity) using test.weather tags('beijing',1) values(now, 12.2, 4)"; + Assert.assertEquals(expected, actual); + } + + @Test + public void getNativeSqlReplaceQuestionMarks2() { + // given + String nativeSql = "INSERT INTO ? (TS,CURRENT,VOLTAGE,PHASE) USING METERS TAGS (?) VALUES (?,?,?,?)"; + Object[] parameters = Stream.of("d1", 1, 123, 3.14, 220, 4).toArray(); + + // when + String actual = Utils.getNativeSql(nativeSql, parameters); + + // then + String expected = "INSERT INTO d1 (TS,CURRENT,VOLTAGE,PHASE) USING METERS TAGS (1) VALUES (123,3.14,220,4)"; + Assert.assertEquals(expected, actual); + } + + + @Test + public void getNativeSqlReplaceNothing() { + // given + String nativeSql = "insert into test.t1 (ts, temperature, humidity) using test.weather tags('beijing',1) values(now, 12.2, 4)"; + + // when + String actual = Utils.getNativeSql(nativeSql, null); + + // then + Assert.assertEquals(nativeSql, actual); + } + + @Test + public void getNativeSqlReplaceNothing2() { + // given + String nativeSql = "insert into test.t1 (ts, temperature, humidity) using test.weather tags('beijing',1) values(now, 12.2, 4)"; + Object[] parameters = Stream.of("test", "t1", "test", "weather", "beijing", 1, 12.2, 4).toArray(); + + // when + String actual = Utils.getNativeSql(nativeSql, parameters); + + // then + Assert.assertEquals(nativeSql, actual); + } + + @Test + public void getNativeSqlReplaceNothing3() { + // given + String nativeSql = "insert into ?.? (ts, temperature, humidity) using ?.? tags(?,?) values(now, ?, ?)"; + + // when + String actual = Utils.getNativeSql(nativeSql, null); + + // then + Assert.assertEquals(nativeSql, actual); + + } } \ No newline at end of file