未验证 提交 b402062d 编写于 作者: M Minglei Jin 提交者: GitHub

Merge pull request #9231 from taosdata/fix/TD-12321

[TD-12321]<fix>: fix compatibility issues with the master and develop branches 
......@@ -53,7 +53,7 @@ ELSEIF (TD_WINDOWS)
#INSTALL(TARGETS taos RUNTIME DESTINATION driver)
#INSTALL(TARGETS shell RUNTIME DESTINATION .)
IF (TD_MVN_INSTALLED)
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.34-dist.jar DESTINATION connector/jdbc)
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.36-dist.jar DESTINATION connector/jdbc)
ENDIF ()
ELSEIF (TD_DARWIN)
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")
......
......@@ -41,6 +41,14 @@ JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_initImp
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions
(JNIEnv *, jclass, jint, jstring);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: setConfigImp
* Signature: (Ljava/lang/String;)Lcom/taosdata/jdbc/TSDBException;
*/
JNIEXPORT jobject JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setConfigImp
(JNIEnv *, jclass, jstring);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: getTsCharset
......@@ -231,6 +239,14 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsImp
(JNIEnv *, jobject, jlong, jstring, jint, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jlong);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: insertLinesImp
* Signature: ([Ljava/lang/String;JII)I
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp
(JNIEnv *, jobject, jobjectArray, jlong, jint, jint);
#ifdef __cplusplus
}
#endif
......
......@@ -200,6 +200,11 @@ JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_initImp(JNIEnv *e
jniDebug("jni initialized successfully, config directory: %s", configDir);
}
JNIEXPORT jobject JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setConfigImp(JNIEnv *env, jclass jobj,
jstring config) {
return NULL;// nothing to do
}
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions(JNIEnv *env, jobject jobj, jint optionIndex,
jstring optionValue) {
if (optionValue == NULL) {
......@@ -993,8 +998,8 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsI
return JNI_SUCCESS;
}
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *env, jobject jobj,
jobjectArray lines, jlong conn) {
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp
(JNIEnv *env, jobject jobj, jobjectArray lines, jlong conn, jint protocol, jint precision){
TAOS *taos = (TAOS *)conn;
if (taos == NULL) {
jniError("jobj:%p, connection already closed", jobj);
......
......@@ -8,7 +8,7 @@ IF (TD_MVN_INSTALLED)
ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME}
POST_BUILD
COMMAND mvn -Dmaven.test.skip=true install -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.34-dist.jar ${LIBRARY_OUTPUT_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.36-dist.jar ${LIBRARY_OUTPUT_PATH}
COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
COMMENT "build jdbc driver")
ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME})
......
......@@ -5,7 +5,7 @@
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.34</version>
<version>2.0.36</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>
......
......@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.34</version>
<version>2.0.36</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>
<url>https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc</url>
......@@ -58,6 +58,7 @@
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
......@@ -70,6 +71,18 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
......@@ -114,6 +127,7 @@
<excludes>
<exclude>**/HttpClientPoolUtilTest.java</exclude>
<exclude>**/AppMemoryLeakTest.java</exclude>
<exclude>**/JDBCTypeAndTypeCompareTest.java</exclude>
<exclude>**/ConnectMultiTaosdByRestfulWithDifferentTokenTest.java</exclude>
<exclude>**/DatetimeBefore1970Test.java</exclude>
<exclude>**/FailOverTest.java</exclude>
......
......@@ -107,16 +107,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
public void setCatalog(String catalog) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
/*
try (Statement stmt = createStatement()) {
boolean execute = stmt.execute("use " + catalog);
if (execute)
this.catalog = catalog;
} catch (SQLException e) {
// do nothing
}
*/
this.catalog = catalog;
}
......@@ -392,7 +382,7 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
//true if the connection is valid, false otherwise
if (isClosed())
return false;
if (timeout < 0) //SQLException - if the value supplied for timeout is less then 0
if (timeout < 0) //SQLException - if the value supplied for timeout is less than 0
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE);
ExecutorService executor = Executors.newCachedThreadPool();
......@@ -413,11 +403,9 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
status = future.get();
else
status = future.get(timeout, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException | ExecutionException ignored) {
} catch (TimeoutException e) {
future.cancel(true);
status = false;
} finally {
executor.shutdownNow();
}
......
......@@ -562,25 +562,27 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
try (Statement stmt = connection.createStatement()) {
stmt.execute("use " + catalog);
ResultSet tables = stmt.executeQuery("show tables");
while (tables.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(10);
rowData.setStringValue(1, catalog); //TABLE_CAT
rowData.setStringValue(2, null); //TABLE_SCHEM
rowData.setStringValue(3, tables.getString("table_name")); //TABLE_NAME
rowData.setStringValue(4, "TABLE"); //TABLE_TYPE
rowData.setStringValue(5, ""); //REMARKS
rowDataList.add(rowData);
try (ResultSet tables = stmt.executeQuery("show tables")) {
while (tables.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(10);
rowData.setStringValue(1, catalog); //TABLE_CAT
rowData.setStringValue(2, null); //TABLE_SCHEM
rowData.setStringValue(3, tables.getString("table_name")); //TABLE_NAME
rowData.setStringValue(4, "TABLE"); //TABLE_TYPE
rowData.setStringValue(5, ""); //REMARKS
rowDataList.add(rowData);
}
}
ResultSet stables = stmt.executeQuery("show stables");
while (stables.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(10);
rowData.setStringValue(1, catalog); //TABLE_CAT
rowData.setStringValue(2, null); //TABLE_SCHEM
rowData.setStringValue(3, stables.getString("name")); //TABLE_NAME
rowData.setStringValue(4, "TABLE"); //TABLE_TYPE
rowData.setStringValue(5, "STABLE"); //REMARKS
rowDataList.add(rowData);
try (ResultSet stables = stmt.executeQuery("show stables")) {
while (stables.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(10);
rowData.setStringValue(1, catalog); //TABLE_CAT
rowData.setStringValue(2, null); //TABLE_SCHEM
rowData.setStringValue(3, stables.getString("name")); //TABLE_NAME
rowData.setStringValue(4, "TABLE"); //TABLE_TYPE
rowData.setStringValue(5, "STABLE"); //REMARKS
rowDataList.add(rowData);
}
}
resultSet.setRowDataList(rowDataList);
}
......@@ -595,7 +597,7 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
return col4;
}
public ResultSet getSchemas() throws SQLException {
public ResultSet getSchemas() {
return getEmptyResultSet();
}
......@@ -627,7 +629,7 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
public abstract ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException;
protected ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern, Connection conn) {
protected ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern, Connection conn) throws SQLException {
if (catalog == null || catalog.isEmpty())
return null;
if (!isAvailableCatalog(conn, catalog))
......@@ -638,8 +640,9 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
resultSet.setColumnMetaDataList(buildGetColumnsColumnMetaDataList());
// set up rowDataList
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("describe " + catalog + "." + tableNamePattern);
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("describe " + catalog + "." + tableNamePattern)) {
int rowIndex = 0;
while (rs.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(24);
......@@ -679,8 +682,6 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
rowIndex++;
}
resultSet.setRowDataList(rowDataList);
} catch (SQLException e) {
e.printStackTrace();
}
return resultSet;
}
......@@ -1147,9 +1148,9 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
columnMetaDataList.add(buildTableCatalogMeta(1)); // 1. TABLE_CAT
resultSet.setColumnMetaDataList(columnMetaDataList);
try (Statement stmt = conn.createStatement()) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("show databases")) {
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
ResultSet rs = stmt.executeQuery("show databases");
while (rs.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(1);
rowData.setStringValue(1, rs.getString("name"));
......@@ -1168,12 +1169,13 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
return new EmptyResultSet();
DatabaseMetaDataResultSet resultSet = new DatabaseMetaDataResultSet();
try (Statement stmt = conn.createStatement()) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("describe " + catalog + "." + table)) {
// set up ColumnMetaDataList
resultSet.setColumnMetaDataList(buildGetPrimaryKeysMetadataList());
// set rowData
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
ResultSet rs = stmt.executeQuery("describe " + catalog + "." + table);
rs.next();
TSDBResultSetRowData rowData = new TSDBResultSetRowData(6);
rowData.setStringValue(1, catalog);
......@@ -1216,18 +1218,15 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
return col6;
}
private boolean isAvailableCatalog(Connection connection, String catalog) {
try (Statement stmt = connection.createStatement()) {
ResultSet databases = stmt.executeQuery("show databases");
private boolean isAvailableCatalog(Connection connection, String catalog) throws SQLException {
try (Statement stmt = connection.createStatement();
ResultSet databases = stmt.executeQuery("show databases")) {
while (databases.next()) {
String dbname = databases.getString("name");
this.precision = databases.getString("precision");
if (dbname.equalsIgnoreCase(catalog))
return true;
}
databases.close();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
......@@ -1246,17 +1245,18 @@ public abstract class AbstractDatabaseMetaData extends WrapperImpl implements Da
resultSet.setColumnMetaDataList(buildGetSuperTablesColumnMetaDataList());
// set result set row data
stmt.execute("use " + catalog);
ResultSet rs = stmt.executeQuery("show tables like '" + tableNamePattern + "'");
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
while (rs.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(4);
rowData.setStringValue(1, catalog);
rowData.setStringValue(2, null);
rowData.setStringValue(3, rs.getString("table_name"));
rowData.setStringValue(4, rs.getString("stable_name"));
rowDataList.add(rowData);
try (ResultSet rs = stmt.executeQuery("show tables like '" + tableNamePattern + "'")) {
List<TSDBResultSetRowData> rowDataList = new ArrayList<>();
while (rs.next()) {
TSDBResultSetRowData rowData = new TSDBResultSetRowData(4);
rowData.setStringValue(1, catalog);
rowData.setStringValue(2, null);
rowData.setStringValue(3, rs.getString("table_name"));
rowData.setStringValue(4, rs.getString("stable_name"));
rowDataList.add(rowData);
}
resultSet.setRowDataList(rowDataList);
}
resultSet.setRowDataList(rowDataList);
}
return resultSet;
}
......
......@@ -11,6 +11,11 @@ import java.util.Map;
public abstract class AbstractResultSet extends WrapperImpl implements ResultSet {
private int fetchSize;
protected boolean wasNull;
protected int timestampPrecision;
public void setTimestampPrecision(int timestampPrecision) {
this.timestampPrecision = timestampPrecision;
}
protected void checkAvailability(int columnIndex, int bounds) throws SQLException {
if (isClosed())
......
......@@ -9,6 +9,7 @@ public abstract class AbstractStatement extends WrapperImpl implements Statement
protected List<String> batchedArgs;
private int fetchSize;
protected int affectedRows = -1;
@Override
public abstract ResultSet executeQuery(String sql) throws SQLException;
......@@ -247,6 +248,7 @@ public abstract class AbstractStatement extends WrapperImpl implements Statement
public boolean getMoreResults(int current) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
this.affectedRows = -1;
switch (current) {
case Statement.CLOSE_CURRENT_RESULT:
return false;
......
......@@ -149,7 +149,7 @@ public class DatabaseMetaDataResultSet extends AbstractResultSet {
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
int colType = columnMetaDataList.get(columnIndex - 1).getColType();
double value = rowCursor.getDouble(columnIndex, colType);
return new BigDecimal(value);
return BigDecimal.valueOf(value);
}
@Override
......
package com.taosdata.jdbc;
import com.taosdata.jdbc.enums.SchemalessProtocolType;
import com.taosdata.jdbc.enums.SchemalessTimestampType;
import com.taosdata.jdbc.rs.RestfulConnection;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* This class is for schemaless lines(line/telnet/json) write to tdengine.
* e.g.:
* SchemalessWriter writer = new SchemalessWriter(connection);
* writer.write(lines, SchemalessProtocolType, SchemalessTimestampType);
*/
public class SchemalessWriter {
protected Connection connection;
public SchemalessWriter(Connection connection) {
this.connection = connection;
}
/**
* batch schemaless lines write to db
*
* @param lines schemaless lines
* @param protocolType schemaless type {@link SchemalessProtocolType}
* @param timestampType Time precision {@link SchemalessTimestampType}
* @throws SQLException execute exception
*/
public void write(String[] lines, SchemalessProtocolType protocolType, SchemalessTimestampType timestampType) throws SQLException {
if (connection instanceof TSDBConnection) {
TSDBConnection tsdbConnection = (TSDBConnection) connection;
tsdbConnection.getConnector().insertLines(lines, protocolType, timestampType);
} else if (connection instanceof RestfulConnection) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD, "restful connection is not supported currently");
} else {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown connection:" + connection.getMetaData().getURL());
}
}
/**
* only one line writes to db
*
* @param line schemaless line
* @param protocolType schemaless type {@link SchemalessProtocolType}
* @param timestampType Time precision {@link SchemalessTimestampType}
* @throws SQLException execute exception
*/
public void write(String line, SchemalessProtocolType protocolType, SchemalessTimestampType timestampType) throws SQLException {
write(new String[]{line}, protocolType, timestampType);
}
/**
* batch schemaless lines write to db with list
*
* @param lines schemaless list
* @param protocolType schemaless type {@link SchemalessProtocolType}
* @param timestampType Time precision {@link SchemalessTimestampType}
* @throws SQLException execute exception
*/
public void write(List<String> lines, SchemalessProtocolType protocolType, SchemalessTimestampType timestampType) throws SQLException {
String[] strings = lines.toArray(new String[0]);
write(strings, protocolType, timestampType);
}
}
/***************************************************************************
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package com.taosdata.jdbc;
import java.sql.*;
......@@ -66,7 +52,7 @@ public class TSDBConnection extends AbstractConnection {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
}
long id = this.connector.subscribe(topic, sql, restart, 0);
long id = this.connector.subscribe(topic, sql, restart);
if (id == 0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SUBSCRIBE_FAILED);
}
......
/***************************************************************************
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package com.taosdata.jdbc;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Logger;
/**
......@@ -118,9 +103,6 @@ public class TSDBDriver extends AbstractDriver {
}
public Connection connect(String url, Properties info) throws SQLException {
if (url == null)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
if (!acceptsURL(url))
return null;
......@@ -135,16 +117,14 @@ public class TSDBDriver extends AbstractDriver {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PASSWORD_IS_REQUIRED);
try {
TSDBJNIConnector.init((String) props.get(PROPERTY_KEY_CONFIG_DIR), (String) props.get(PROPERTY_KEY_LOCALE),
(String) props.get(PROPERTY_KEY_CHARSET), (String) props.get(PROPERTY_KEY_TIME_ZONE));
TSDBJNIConnector.init(props);
return new TSDBConnection(props, this.dbMetaData);
} catch (SQLWarning sqlWarning) {
sqlWarning.printStackTrace();
return new TSDBConnection(props, this.dbMetaData);
} catch (SQLException sqlEx) {
throw sqlEx;
} catch (Exception ex) {
throw new SQLException("SQLException:" + ex.toString(), ex);
throw new SQLException("SQLException:" + ex, ex);
}
}
......@@ -157,7 +137,7 @@ public class TSDBDriver extends AbstractDriver {
public boolean acceptsURL(String url) throws SQLException {
if (url == null)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
return url.length() > 0 && url.trim().length() > 0 && (url.startsWith(URL_PREFIX) || url.startsWith(URL_PREFIX1));
return url.trim().length() > 0 && (url.startsWith(URL_PREFIX) || url.startsWith(URL_PREFIX1));
}
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
......@@ -205,6 +185,7 @@ public class TSDBDriver extends AbstractDriver {
String dbProductName = url.substring(0, beginningOfSlashes);
dbProductName = dbProductName.substring(dbProductName.indexOf(":") + 1);
dbProductName = dbProductName.substring(0, dbProductName.indexOf(":"));
urlProps.setProperty(TSDBDriver.PROPERTY_KEY_PRODUCT_NAME, dbProductName);
// parse database name
url = url.substring(beginningOfSlashes + 2);
......
......@@ -35,6 +35,7 @@ public class TSDBError {
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TIMESTAMP_PRECISION, "unknown timestamp precision");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_USER_IS_REQUIRED, "user is required");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_PASSWORD_IS_REQUIRED, "password is required");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_JSON_FORMAT, "invalid json format");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown error");
......
package com.taosdata.jdbc;
public class TSDBException {
private int code;
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
\ No newline at end of file
/**
* *************************************************************************
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
* <p>
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* <p>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ***************************************************************************
*/
package com.taosdata.jdbc;
import com.alibaba.fastjson.JSONObject;
import com.taosdata.jdbc.enums.SchemalessProtocolType;
import com.taosdata.jdbc.enums.SchemalessTimestampType;
import com.taosdata.jdbc.utils.TaosInfo;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
/**
* JNI connector
*/
public class TSDBJNIConnector {
private static volatile Boolean isInitialized = false;
private static final Object LOCK = new Object();
private static volatile boolean isInitialized;
private final TaosInfo taosInfo = TaosInfo.getInstance();
private long taos = TSDBConstants.JNI_NULL_POINTER; // Connection pointer used in C
......@@ -38,24 +29,27 @@ public class TSDBJNIConnector {
System.loadLibrary("taos");
}
public boolean isClosed() {
return this.taos == TSDBConstants.JNI_NULL_POINTER;
}
public static void init(Properties props) throws SQLWarning {
synchronized (LOCK) {
if (!isInitialized) {
public boolean isResultsetClosed() {
return this.isResultsetClosed;
}
JSONObject configJSON = new JSONObject();
for (String key : props.stringPropertyNames()) {
configJSON.put(key, props.getProperty(key));
}
setConfigImp(configJSON.toJSONString());
public static void init(String configDir, String locale, String charset, String timezone) throws SQLWarning {
synchronized (isInitialized) {
if (!isInitialized) {
initImp(configDir);
initImp(props.getProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, null));
String locale = props.getProperty(TSDBDriver.PROPERTY_KEY_LOCALE);
if (setOptions(0, locale) < 0) {
throw TSDBError.createSQLWarning("Failed to set locale: " + locale + ". System default will be used.");
}
String charset = props.getProperty(TSDBDriver.PROPERTY_KEY_CHARSET);
if (setOptions(1, charset) < 0) {
throw TSDBError.createSQLWarning("Failed to set charset: " + charset + ". System default will be used.");
}
String timezone = props.getProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE);
if (setOptions(2, timezone) < 0) {
throw TSDBError.createSQLWarning("Failed to set timezone: " + timezone + ". System default will be used.");
}
......@@ -65,11 +59,13 @@ public class TSDBJNIConnector {
}
}
public static native void initImp(String configDir);
private static native void initImp(String configDir);
private static native int setOptions(int optionIndex, String optionValue);
public static native int setOptions(int optionIndex, String optionValue);
private static native String getTsCharset();
public static native String getTsCharset();
private static native TSDBException setConfigImp(String config);
public boolean connect(String host, int port, String dbName, String user, String password) throws SQLException {
if (this.taos != TSDBConstants.JNI_NULL_POINTER) {
......@@ -97,8 +93,7 @@ public class TSDBJNIConnector {
try {
pSql = this.executeQueryImp(sql.getBytes(TaosGlobalConfig.getCharset()), this.taos);
taosInfo.stmt_count_increment();
} catch (Exception e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
this.freeResultSetImp(this.taos, pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_ENCODING);
}
......@@ -159,6 +154,14 @@ public class TSDBJNIConnector {
private native long isUpdateQueryImp(long connection, long pSql);
public boolean isClosed() {
return this.taos == TSDBConstants.JNI_NULL_POINTER;
}
public boolean isResultsetClosed() {
return this.isResultsetClosed;
}
/**
* Free result set operation from C to release result set pointer by JNI
*/
......@@ -243,8 +246,8 @@ public class TSDBJNIConnector {
/**
* Create a subscription
*/
long subscribe(String topic, String sql, boolean restart, int period) {
return subscribeImp(this.taos, restart, topic, sql, period);
long subscribe(String topic, String sql, boolean restart) {
return subscribeImp(this.taos, restart, topic, sql, 0);
}
private native long subscribeImp(long connection, boolean restart, String topic, String sql, int period);
......@@ -267,16 +270,6 @@ public class TSDBJNIConnector {
private native void unsubscribeImp(long subscription, boolean isKeep);
/**
* Validate if a <I>create table</I> SQL statement is correct without actually creating that table
*/
public boolean validateCreateTableSql(String sql) {
int res = validateCreateTableSqlImp(taos, sql.getBytes());
return res == 0;
}
private native int validateCreateTableSqlImp(long connection, byte[] sqlBytes);
public long prepareStmt(String sql) throws SQLException {
long stmt = prepareStmtImp(sql.getBytes(), this.taos);
......@@ -301,7 +294,7 @@ public class TSDBJNIConnector {
public void setBindTableName(long stmt, String tableName) throws SQLException {
int code = setBindTableNameImp(stmt, tableName, this.taos);
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to set table name");
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "table name: " + tableName + ", failed to set table name");
}
}
......@@ -343,12 +336,14 @@ public class TSDBJNIConnector {
private native int closeStmt(long stmt, long con);
public void insertLines(String[] lines) throws SQLException {
int code = insertLinesImp(lines, this.taos);
public void insertLines(String[] lines, SchemalessProtocolType protocolType, SchemalessTimestampType timestampType) throws SQLException {
int code = insertLinesImp(lines, this.taos, protocolType.ordinal(), timestampType.ordinal());
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to insertLines");
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "schemaless line: " + Arrays.toString(lines) + ", failed to insertLines");
}
}
private native int insertLinesImp(String[] lines, long conn);
private native int insertLinesImp(String[] lines, long conn, int type, int precision);
}
......@@ -36,15 +36,15 @@ import java.util.regex.Pattern;
* compatibility needs.
*/
public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement {
// for jdbc preparedStatement interface
private String rawSql;
private Object[] parameters;
private ArrayList<ColumnInfo> colData;
// for parameter binding
private long nativeStmtHandle = 0;
private String tableName;
private ArrayList<TableTagInfo> tableTags;
private int tagValueLength;
private String tableName;
private long nativeStmtHandle = 0;
private ArrayList<ColumnInfo> colData;
TSDBPreparedStatement(TSDBConnection connection, String sql) {
super(connection);
......@@ -72,10 +72,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
preprocessSql();
}
/*
*
*/
/**
* 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
......@@ -250,13 +246,10 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
if (isClosed()) {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
if (parameterIndex < 1 && parameterIndex >= parameters.length) {
if (parameterIndex < 1 && parameterIndex >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
}
parameters[parameterIndex - 1] = x;
}
......@@ -335,7 +328,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
// TODO:
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
......@@ -419,7 +411,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
//TODO:
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
......@@ -477,7 +468,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@Override
......@@ -496,7 +486,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
///////////////////////////////////////////////////////////////////////
// NOTE: the following APIs are not JDBC compatible
// set the bind table name
// parameter binding
private static class ColumnInfo {
@SuppressWarnings("rawtypes")
private ArrayList data;
......@@ -539,7 +529,11 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
}
}
public void setTableName(String name) {
public void setTableName(String name) throws SQLException {
if (this.tableName != null) {
this.columnDataExecuteBatch();
this.columnDataClearBatchInternal();
}
this.tableName = name;
}
......@@ -617,7 +611,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
try {
this.tagValueLength += value.getBytes(charset).length;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
......@@ -792,7 +786,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
b = val.getBytes(charset);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
tagDataList.put(b);
......@@ -927,7 +921,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
b = val.getBytes(charset);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
if (val.length() > col1.bytes) {
......@@ -960,17 +954,22 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public void columnDataExecuteBatch() throws SQLException {
TSDBJNIConnector connector = ((TSDBConnection) this.getConnection()).getConnector();
connector.executeBatch(this.nativeStmtHandle);
this.columnDataClearBatch();
this.columnDataClearBatchInternal();
}
@Deprecated
public void columnDataClearBatch() {
columnDataClearBatchInternal();
}
private void columnDataClearBatchInternal() {
int size = this.colData.size();
this.colData.clear();
this.colData.addAll(Collections.nCopies(size, null));
this.tableName = null; // clear the table name
}
public void columnDataCloseBatch() throws SQLException {
TSDBJNIConnector connector = ((TSDBConnection) this.getConnection()).getConnector();
connector.closeBatch(this.nativeStmtHandle);
......@@ -978,4 +977,13 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
this.nativeStmtHandle = 0L;
this.tableName = null;
}
@Override
public void close() throws SQLException {
if (this.nativeStmtHandle != 0L) {
this.columnDataClearBatchInternal();
this.columnDataCloseBatch();
}
super.close();
}
}
......@@ -19,6 +19,7 @@ import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -73,9 +74,8 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
public boolean next() throws SQLException {
if (this.getBatchFetch()) {
if (this.blockData.forward()) {
if (this.blockData.forward())
return true;
}
int code = this.jniConnector.fetchBlock(this.resultSetPointer, this.blockData);
this.blockData.reset();
......@@ -213,7 +213,18 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
if (!lastWasNull) {
Object value = this.rowData.getObject(columnIndex);
if (value instanceof Timestamp) {
res = ((Timestamp) value).getTime();
Timestamp ts = (Timestamp) value;
long epochSec = ts.getTime() / 1000;
long nanoAdjustment = ts.getNanos();
switch (this.timestampPrecision) {
case 0:
default: // ms
return ts.getTime();
case 1: // us
return epochSec * 1000_000L + nanoAdjustment / 1000L;
case 2: // ns
return epochSec * 1000_000_000L + nanoAdjustment;
}
} else {
int nativeType = this.columnMetaDataList.get(columnIndex - 1).getColType();
res = this.rowData.getLong(columnIndex, nativeType);
......@@ -256,7 +267,11 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
public byte[] getBytes(int columnIndex) throws SQLException {
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (this.getBatchFetch())
return this.blockData.getString(columnIndex).getBytes();
Object value = this.rowData.getObject(columnIndex);
this.lastWasNull = value == null;
if (value == null)
return null;
......@@ -331,25 +346,26 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
return new BigDecimal(this.blockData.getLong(columnIndex - 1));
this.lastWasNull = this.rowData.wasNull(columnIndex);
BigDecimal res = null;
if (!lastWasNull) {
int nativeType = this.columnMetaDataList.get(columnIndex - 1).getColType();
switch (nativeType) {
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
res = new BigDecimal(Long.parseLong(this.rowData.getObject(columnIndex).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
res = BigDecimal.valueOf(Double.parseDouble(this.rowData.getObject(columnIndex).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return new BigDecimal(((Timestamp) this.rowData.getObject(columnIndex)).getTime());
default:
res = new BigDecimal(this.rowData.getObject(columnIndex).toString());
}
if (lastWasNull)
return null;
BigDecimal res;
int nativeType = this.columnMetaDataList.get(columnIndex - 1).getColType();
switch (nativeType) {
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
res = new BigDecimal(Long.parseLong(this.rowData.getObject(columnIndex).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
res = BigDecimal.valueOf(Double.parseDouble(this.rowData.getObject(columnIndex).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return new BigDecimal(((Timestamp) this.rowData.getObject(columnIndex)).getTime());
default:
res = new BigDecimal(this.rowData.getObject(columnIndex).toString());
}
return res;
}
......@@ -465,12 +481,6 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
public boolean isClosed() throws SQLException {
return isClosed;
// if (isClosed)
// return true;
// if (jniConnector != null) {
// isClosed = jniConnector.isResultsetClosed();
// }
// return isClosed;
}
public String getNString(int columnIndex) throws SQLException {
......
......@@ -92,75 +92,71 @@ public class TSDBResultSetBlockData {
}
public void setByteArray(int col, int length, byte[] value) {
try {
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
this.colData.set(col, sb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
this.colData.set(col, ib);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
FloatBuffer fb = buf.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
this.colData.set(col, fb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
DoubleBuffer db = buf.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
this.colData.set(col, db);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
this.colData.set(col, sb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
this.colData.set(col, ib);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
FloatBuffer fb = buf.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
this.colData.set(col, fb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
DoubleBuffer db = buf.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
this.colData.set(col, db);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
......@@ -283,14 +279,8 @@ public class TSDBResultSetBlockData {
return 0;
}
public Timestamp getTimestamp(int col) {
try {
return new Timestamp(getLong(col));
} catch (SQLException e) {
e.printStackTrace();
}
return null;
public Timestamp getTimestamp(int col) throws SQLException {
return new Timestamp(getLong(col));
}
public double getDouble(int col) {
......@@ -429,7 +419,7 @@ public class TSDBResultSetBlockData {
String charset = TaosGlobalConfig.getCharset();
return new String(dest, charset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
......
......@@ -16,6 +16,7 @@ package com.taosdata.jdbc;
import com.taosdata.jdbc.utils.NullType;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
......@@ -49,7 +50,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setBooleanValue(int col, boolean value) {
setBoolean(col - 1, value);
......@@ -86,7 +87,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setByteValue(int colIndex, byte value) {
setByte(colIndex - 1, value);
......@@ -100,7 +101,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setShortValue(int colIndex, short value) {
setShort(colIndex - 1, value);
......@@ -114,7 +115,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setIntValue(int colIndex, int value) {
setInt(colIndex - 1, value);
......@@ -189,12 +190,12 @@ public class TSDBResultSetRowData {
long value = (long) obj;
if (value < 0)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
return Long.valueOf(value).intValue();
return (int) value;
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setLongValue(int colIndex, long value) {
setLong(colIndex - 1, value);
......@@ -262,7 +263,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setFloatValue(int colIndex, float value) {
setFloat(colIndex - 1, value);
......@@ -302,7 +303,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setDoubleValue(int colIndex, double value) {
setDouble(colIndex - 1, value);
......@@ -342,7 +343,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setStringValue(int colIndex, String value) {
data.set(colIndex - 1, value);
......@@ -361,7 +362,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setByteArrayValue(int colIndex, byte[] value) {
setByteArray(colIndex - 1, value);
......@@ -378,8 +379,8 @@ public class TSDBResultSetRowData {
// this setByteArr(int, byte[]) to handle NCHAR value, we need to build a String with charsetEncoding by TaosGlobalConfig
try {
data.set(col, new String(value, TaosGlobalConfig.getCharset()));
} catch (Exception e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage());
}
}
......@@ -424,7 +425,7 @@ public class TSDBResultSetRowData {
}
/**
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use a index start from 1 in JDBC api
* $$$ this method is invoked by databaseMetaDataResultSet and so on which use an index start from 1 in JDBC api
*/
public void setTimestampValue(int colIndex, long value) {
setTimestamp(colIndex - 1, value, 0);
......
......@@ -23,7 +23,7 @@ import java.util.Calendar;
import java.util.Map;
/*
* TDengine only supports a subset of the standard SQL, thus this implemetation of the
* TDengine only supports a subset of the standard SQL, thus this implementation of the
* standard JDBC API contains more or less some adjustments customized for certain
* compatibility needs.
*/
......
......@@ -23,7 +23,6 @@ public class TSDBStatement extends AbstractStatement {
* Status of current statement
*/
private boolean isClosed;
private int affectedRows = -1;
private TSDBConnection connection;
private TSDBResultSet resultSet;
......@@ -48,6 +47,8 @@ public class TSDBStatement extends AbstractStatement {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql);
int timestampPrecision = this.connection.getConnector().getResultTimePrecision(pSql);
res.setTimestampPrecision(timestampPrecision);
res.setBatchFetch(this.connection.getBatchFetch());
return res;
}
......@@ -80,7 +81,7 @@ public class TSDBStatement extends AbstractStatement {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
// execute query
long pSql = this.connection.getConnector().executeQuery(sql);
// if pSql is create/insert/update/delete/alter SQL
......@@ -99,7 +100,7 @@ public class TSDBStatement extends AbstractStatement {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
return this.resultSet;
}
......@@ -113,14 +114,14 @@ public class TSDBStatement extends AbstractStatement {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
if (this.connection.getConnector() == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
}
return this.connection;
}
public void setConnection(TSDBConnection connection) {
this.connection = connection;
}
......
package com.taosdata.jdbc.enums;
import java.util.Arrays;
public enum SchemalessProtocolType {
UNKNOWN,
LINE,
TELNET,
JSON,
;
public static SchemalessProtocolType parse(String type) {
return Arrays.stream(SchemalessProtocolType.values())
.filter(protocol -> type.equalsIgnoreCase(protocol.name()))
.findFirst().orElse(UNKNOWN);
}
}
package com.taosdata.jdbc.enums;
public enum SchemalessTimestampType {
// Let the database decide
NOT_CONFIGURED,
HOURS,
MINUTES,
SECONDS,
MILLI_SECONDS,
MICRO_SECONDS,
NANO_SECONDS,
;
}
package com.taosdata.jdbc.enums;
public enum TimestampPrecision {
MS,
US,
NS,
UNKNOWN
public class TimestampPrecision {
public static final int MS = 0;
public static final int US = 1;
public static final int NS = 2;
}
......@@ -39,7 +39,7 @@ public class RestfulDriver extends AbstractDriver {
String port = props.getProperty(TSDBDriver.PROPERTY_KEY_PORT, "6041");
String database = props.containsKey(TSDBDriver.PROPERTY_KEY_DBNAME) ? props.getProperty(TSDBDriver.PROPERTY_KEY_DBNAME) : null;
String loginUrl = "http://" + host + ":" + port + "/rest/login/" + props.getProperty(TSDBDriver.PROPERTY_KEY_USER) + "/" + props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD) + "";
String loginUrl;
try {
if (!props.containsKey(TSDBDriver.PROPERTY_KEY_USER))
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_USER_IS_REQUIRED);
......@@ -50,9 +50,13 @@ public class RestfulDriver extends AbstractDriver {
String password = URLEncoder.encode(props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD), StandardCharsets.UTF_8.displayName());
loginUrl = "http://" + props.getProperty(TSDBDriver.PROPERTY_KEY_HOST) + ":" + props.getProperty(TSDBDriver.PROPERTY_KEY_PORT) + "/rest/login/" + user + "/" + password + "";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported UTF-8 concoding, user: " + props.getProperty(TSDBDriver.PROPERTY_KEY_USER) + ", password: " + props.getProperty(TSDBDriver.PROPERTY_KEY_PASSWORD));
}
int poolSize = Integer.parseInt(props.getProperty("httpPoolSize", HttpClientPoolUtil.DEFAULT_MAX_PER_ROUTE));
boolean keepAlive = Boolean.parseBoolean(props.getProperty("httpKeepAlive", HttpClientPoolUtil.DEFAULT_HTTP_KEEP_ALIVE));
HttpClientPoolUtil.init(poolSize, keepAlive);
String result = HttpClientPoolUtil.execute(loginUrl);
JSONObject jsonResult = JSON.parseObject(result);
String status = jsonResult.getString("status");
......@@ -64,9 +68,9 @@ public class RestfulDriver extends AbstractDriver {
RestfulConnection conn = new RestfulConnection(host, port, props, database, url, token);
if (database != null && !database.trim().replaceAll("\\s", "").isEmpty()) {
Statement stmt = conn.createStatement();
stmt.execute("use " + database);
stmt.close();
try (Statement stmt = conn.createStatement()) {
stmt.execute("use " + database);
}
}
return conn;
}
......@@ -75,7 +79,7 @@ public class RestfulDriver extends AbstractDriver {
public boolean acceptsURL(String url) throws SQLException {
if (url == null)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
return url.length() > 0 && url.trim().length() > 0 && url.startsWith(URL_PREFIX);
return url.trim().length() > 0 && url.startsWith(URL_PREFIX);
}
@Override
......
......@@ -14,13 +14,43 @@ import java.math.BigDecimal;
import java.sql.*;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class RestfulResultSet extends AbstractResultSet implements ResultSet {
public static DateTimeFormatter rfc3339Parser = null;
{
rfc3339Parser = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue(ChronoField.YEAR, 4)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 2, 9, true)
.optionalEnd()
.appendOffset("+HH:MM", "Z").toFormatter()
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(IsoChronology.INSTANCE);
}
private final Statement statement;
// data
private final List<List<Object>> resultSet = new ArrayList<>();
......@@ -168,35 +198,67 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
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)
if (value < 1_0000_0000_0000_0L) {
this.timestampPrecision = TimestampPrecision.MS;
return new Timestamp(value);
long epochSec = value / 1000_000L;
long nanoAdjustment = value % 1000_000L * 1000L;
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
}
if (value >= 1_0000_0000_0000_0L && value < 1_000_000_000_000_000_0l) {
this.timestampPrecision = TimestampPrecision.US;
long epochSec = value / 1000_000L;
long nanoAdjustment = value % 1000_000L * 1000L;
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
}
if (value >= 1_000_000_000_000_000_0l) {
this.timestampPrecision = TimestampPrecision.NS;
long epochSec = value / 1000_000_000L;
long nanoAdjustment = value % 1000_000_000L;
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;
if (value.lastIndexOf(":") > 19) {
ZonedDateTime parse = ZonedDateTime.parse(value, rfc3339Parser);
long nanoAdjustment;
if (value.length() > 32) {
// ns timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSSSSS+0x:00
this.timestampPrecision = TimestampPrecision.NS;
} else if (value.length() > 29) {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x:00
this.timestampPrecision = TimestampPrecision.US;
} else {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x:00
this.timestampPrecision = TimestampPrecision.MS;
}
return Timestamp.from(parse.toInstant());
} else {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00
nanoAdjustment = fractionalSec * 1000_000L;
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() > 32) {
// ns timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSSSSS+0x00
nanoAdjustment = fractionalSec;
this.timestampPrecision = TimestampPrecision.NS;
} else if (value.length() > 29) {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00
nanoAdjustment = fractionalSec * 1000L;
this.timestampPrecision = TimestampPrecision.US;
} else {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00
nanoAdjustment = fractionalSec * 1000_000L;
this.timestampPrecision = TimestampPrecision.MS;
}
ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5));
Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant();
return Timestamp.from(instant);
}
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);
int precision = Utils.guessTimestampPrecision(value);
this.timestampPrecision = precision;
if (precision == TimestampPrecision.MS) {
// ms timestamp: yyyy-MM-dd HH:mm:ss.SSS
return row.getTimestamp(colIndex);
......@@ -255,6 +317,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof byte[])
......@@ -267,11 +330,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return false;
}
wasNull = false;
if (value instanceof Boolean)
return (boolean) value;
return Boolean.parseBoolean(value.toString());
......@@ -282,11 +343,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return 0;
}
wasNull = false;
long valueAsLong = Long.parseLong(value.toString());
if (valueAsLong == Byte.MIN_VALUE)
return 0;
......@@ -306,11 +365,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return 0;
}
wasNull = false;
long valueAsLong = Long.parseLong(value.toString());
if (valueAsLong == Short.MIN_VALUE)
return 0;
......@@ -324,11 +381,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return 0;
}
wasNull = false;
long valueAsLong = Long.parseLong(value.toString());
if (valueAsLong == Integer.MIN_VALUE)
return 0;
......@@ -342,14 +397,20 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return 0;
}
wasNull = false;
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
Timestamp ts = (Timestamp) value;
switch (this.timestampPrecision) {
case TimestampPrecision.MS:
default:
return ts.getTime();
case TimestampPrecision.US:
return ts.getTime() * 1000 + ts.getNanos() / 1000 % 1000;
case TimestampPrecision.NS:
return ts.getTime() * 1000_000 + ts.getNanos() % 1000_000;
}
}
long valueAsLong = 0;
try {
......@@ -367,11 +428,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
wasNull = value == null;
if (value == null)
return 0;
}
wasNull = false;
if (value instanceof Float)
return (float) value;
if (value instanceof Double)
......@@ -384,11 +443,10 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
if (value instanceof Double || value instanceof Float)
return (double) value;
return Double.parseDouble(value.toString());
......@@ -399,6 +457,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof byte[])
......@@ -425,6 +484,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof Timestamp)
......@@ -437,6 +497,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof Timestamp)
......@@ -454,6 +515,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof Timestamp)
......@@ -470,6 +532,7 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
ret = Utils.parseTimestamp(value.toString());
} catch (Exception e) {
ret = null;
wasNull = true;
}
return ret;
}
......@@ -485,7 +548,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
public Object getObject(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
return resultSet.get(pos).get(columnIndex - 1);
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
return value;
}
@Override
......@@ -504,9 +569,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
wasNull = value == null;
if (value == null)
return null;
if (value instanceof Long || value instanceof Integer || value instanceof Short || value instanceof Byte)
return new BigDecimal(Long.parseLong(value.toString()));
if (value instanceof Double || value instanceof Float)
......@@ -663,4 +728,4 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
return isClosed;
}
}
\ No newline at end of file
}
......@@ -22,7 +22,6 @@ public class RestfulStatement extends AbstractStatement {
private final RestfulConnection conn;
private volatile RestfulResultSet resultSet;
private volatile int affectedRows;
public RestfulStatement(RestfulConnection conn, String database) {
this.conn = conn;
......@@ -73,6 +72,7 @@ public class RestfulStatement extends AbstractStatement {
}
this.database = sql.trim().replace("use", "").trim();
this.conn.setCatalog(this.database);
this.conn.setClientInfo(TSDBDriver.PROPERTY_KEY_DBNAME, this.database);
result = false;
} else if (SqlSyntaxValidator.isDatabaseUnspecifiedQuery(sql)) {
executeOneQuery(sql);
......@@ -122,7 +122,7 @@ public class RestfulStatement extends AbstractStatement {
throw TSDBError.createSQLException(resultJson.getInteger("code"), "sql: " + sql + ", desc: " + resultJson.getString("desc"));
}
this.resultSet = new RestfulResultSet(database, this, resultJson);
this.affectedRows = 0;
this.affectedRows = -1;
return resultSet;
}
......@@ -142,8 +142,9 @@ public class RestfulStatement extends AbstractStatement {
if (head.size() != 1 || !"affected_rows".equals(head.getString(0)))
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "invalid variable: [" + head.toJSONString() + "]");
JSONArray data = jsonObject.getJSONArray("data");
if (data != null)
if (data != null) {
return data.getJSONArray(0).getInteger(0);
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "invalid variable: [" + jsonObject.toJSONString() + "]");
}
......
......@@ -7,10 +7,10 @@ import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpEntity;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
......@@ -21,21 +21,20 @@ import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.concurrent.TimeUnit;
public class HttpClientPoolUtil {
private static final String DEFAULT_CONTENT_TYPE = "application/json";
private static final int DEFAULT_MAX_RETRY_COUNT = 5;
private static final int DEFAULT_MAX_TOTAL = 50;
private static final int DEFAULT_MAX_PER_ROUTE = 5;
public static final String DEFAULT_HTTP_KEEP_ALIVE = "true";
public static final String DEFAULT_MAX_PER_ROUTE = "20";
private static final int DEFAULT_HTTP_KEEP_TIME = -1;
private static String isKeepAlive;
private static final ConnectionKeepAliveStrategy DEFAULT_KEEP_ALIVE_STRATEGY = (response, context) -> {
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
......@@ -55,36 +54,39 @@ public class HttpClientPoolUtil {
private static CloseableHttpClient httpClient;
static {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
httpClient = HttpClients.custom()
.setKeepAliveStrategy(DEFAULT_KEEP_ALIVE_STRATEGY)
.setConnectionManager(connectionManager)
.setRetryHandler((exception, executionCount, httpContext) -> executionCount < DEFAULT_MAX_RETRY_COUNT)
.build();
public static void init(Integer connPoolSize, boolean keepAlive) {
if (httpClient == null) {
synchronized (HttpClientPoolUtil.class) {
if (httpClient == null) {
isKeepAlive = keepAlive ? HTTP.CONN_KEEP_ALIVE : HTTP.CONN_CLOSE;
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(connPoolSize * 10);
connectionManager.setDefaultMaxPerRoute(connPoolSize);
httpClient = HttpClients.custom()
.setKeepAliveStrategy(DEFAULT_KEEP_ALIVE_STRATEGY)
.setConnectionManager(connectionManager)
.setRetryHandler((exception, executionCount, httpContext) -> executionCount < DEFAULT_MAX_RETRY_COUNT)
.build();
}
}
}
}
/*** execute GET request ***/
public static String execute(String uri) throws SQLException {
HttpEntity httpEntity = null;
String responseBody = "";
try {
HttpRequestBase method = getRequest(uri, HttpGet.METHOD_NAME);
HttpContext context = HttpClientContext.create();
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
HttpRequestBase method = getRequest(uri, HttpGet.METHOD_NAME);
HttpContext context = HttpClientContext.create();
try (CloseableHttpResponse httpResponse = httpClient.execute(method, context)) {
httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
responseBody = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESTFul_Client_Protocol_Exception, e.getMessage());
} catch (IOException exception) {
exception.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESTFul_Client_IOException, exception.getMessage());
} finally {
if (httpEntity != null) {
......@@ -94,30 +96,27 @@ public class HttpClientPoolUtil {
return responseBody;
}
/*** execute POST request ***/
public static String execute(String uri, String data, String token) throws SQLException {
HttpEntityEnclosingRequestBase method = (HttpEntityEnclosingRequestBase) getRequest(uri, HttpPost.METHOD_NAME);
method.setHeader(HTTP.CONTENT_TYPE, "text/plain");
method.setHeader(HTTP.CONN_DIRECTIVE, isKeepAlive);
method.setHeader("Authorization", "Taosd " + token);
method.setEntity(new StringEntity(data, StandardCharsets.UTF_8));
HttpContext context = HttpClientContext.create();
HttpEntity httpEntity = null;
String responseBody = "";
try {
HttpEntityEnclosingRequestBase method = (HttpEntityEnclosingRequestBase) getRequest(uri, HttpPost.METHOD_NAME);
method.setHeader(HTTP.CONTENT_TYPE, "text/plain");
method.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE);
method.setHeader("Authorization", "Taosd " + token);
method.setEntity(new StringEntity(data, StandardCharsets.UTF_8));
HttpContext context = HttpClientContext.create();
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
try (CloseableHttpResponse httpResponse = httpClient.execute(method, context)) {
httpEntity = httpResponse.getEntity();
if (httpEntity == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_HTTP_ENTITY_IS_NULL, "httpEntity is null, sql: " + data);
}
responseBody = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
} catch (ClientProtocolException e) {
e.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESTFul_Client_Protocol_Exception, e.getMessage());
} catch (IOException exception) {
exception.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESTFul_Client_IOException, exception.getMessage());
} finally {
if (httpEntity != null) {
......@@ -148,4 +147,12 @@ public class HttpClientPoolUtil {
return method;
}
public static void reset() {
synchronized (HttpClientPoolUtil.class) {
ClientConnectionManager cm = httpClient.getConnectionManager();
cm.closeExpiredConnections();
cm.closeIdleConnections(100, TimeUnit.MILLISECONDS);
}
}
}
\ No newline at end of file
......@@ -16,9 +16,8 @@ public class TaosInfo implements TaosInfoMBean {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("TaosInfoMBean:name=TaosInfo");
server.registerMBean(TaosInfo.getInstance(), name);
} catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
e.printStackTrace();
} catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException ignored) {
throw new RuntimeException("registerMBean failed");
}
}
......
......@@ -49,14 +49,9 @@ public class Utils {
try {
return parseMicroSecTimestamp(timeStampStr);
} catch (DateTimeParseException ee) {
try {
return parseNanoSecTimestamp(timeStampStr);
} catch (DateTimeParseException eee) {
eee.printStackTrace();
}
return parseNanoSecTimestamp(timeStampStr);
}
}
return null;
}
private static LocalDateTime parseMilliSecTimestamp(String timeStampStr) throws DateTimeParseException {
......@@ -199,14 +194,14 @@ public class Utils {
return timestamp.toLocalDateTime().format(milliSecFormatter);
}
public static TimestampPrecision guessTimestampPrecision(String value) {
public static int guessTimestampPrecision(String value) {
if (isMilliSecFormat(value))
return TimestampPrecision.MS;
if (isMicroSecFormat(value))
return TimestampPrecision.US;
if (isNanoSecFormat(value))
return TimestampPrecision.NS;
return TimestampPrecision.UNKNOWN;
return TimestampPrecision.MS;
}
private static boolean isMilliSecFormat(String timestampStr) {
......
package com.taosdata.jdbc;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class ParameterBindTest {
private static final String host = "127.0.0.1";
private static final String stable = "weather";
private Connection conn;
private final Random random = new Random(System.currentTimeMillis());
@Test
public void test() {
// given
String[] tbnames = {"t1", "t2", "t3"};
int rows = 10;
// when
insertIntoTables(tbnames, 10);
// then
assertRows(stable, tbnames.length * rows);
for (String t : tbnames) {
assertRows(t, rows);
}
}
@Test
public void testMultiThreads() {
// given
String[][] tables = {{"t1", "t2", "t3"}, {"t4", "t5", "t6"}, {"t7", "t8", "t9"}, {"t10"}};
int rows = 10;
// when
List<Thread> threads = Arrays.stream(tables).map(tbnames -> new Thread(() -> insertIntoTables(tbnames, rows))).collect(Collectors.toList());
threads.forEach(Thread::start);
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// then
for (String[] table : tables) {
for (String t : table) {
assertRows(t, rows);
}
}
}
private void assertRows(String tbname, int rows) {
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("select count(*) from " + tbname);
while (rs.next()) {
int count = rs.getInt(1);
Assert.assertEquals(rows, count);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void insertIntoTables(String[] tbnames, int rowsEachTable) {
long current = System.currentTimeMillis();
String sql = "insert into ? using " + stable + " tags(?, ?) values(?, ?, ?)";
try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) {
for (int i = 0; i < tbnames.length; i++) {
pstmt.setTableName(tbnames[i]);
pstmt.setTagInt(0, random.nextInt(100));
pstmt.setTagInt(1, random.nextInt(100));
ArrayList<Long> timestampList = new ArrayList<>();
for (int j = 0; j < rowsEachTable; j++) {
timestampList.add(current + i * 1000 + j);
}
pstmt.setTimestamp(0, timestampList);
ArrayList<Integer> f1List = new ArrayList<>();
for (int j = 0; j < rowsEachTable; j++) {
f1List.add(random.nextInt(100));
}
pstmt.setInt(1, f1List);
ArrayList<Integer> f2List = new ArrayList<>();
for (int j = 0; j < rowsEachTable; j++) {
f2List.add(random.nextInt(100));
}
pstmt.setInt(2, f2List);
pstmt.columnDataAddBatch();
}
pstmt.columnDataExecuteBatch();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Before
public void before() {
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 test_pd");
stmt.execute("create database if not exists test_pd");
stmt.execute("use test_pd");
stmt.execute("create table " + stable + "(ts timestamp, f1 int, f2 int) tags(t1 int, t2 int)");
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void after() {
try {
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists test_pd");
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.taosdata.jdbc;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taosdata.jdbc.annotation.CatalogRunner;
import com.taosdata.jdbc.annotation.Description;
import com.taosdata.jdbc.annotation.TestTarget;
import com.taosdata.jdbc.enums.SchemalessProtocolType;
import com.taosdata.jdbc.enums.SchemalessTimestampType;
import org.junit.*;
import org.junit.runner.RunWith;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
@Ignore
@RunWith(CatalogRunner.class)
@TestTarget(alias = "Schemaless",author = "huolibo", version = "2.0.36")
public class SchemalessInsertTest {
private final String dbname = "test_schemaless_insert";
private Connection conn;
/**
* schemaless insert compatible with influxdb
*
* @throws SQLException execute error
*/
@Test
@Description("line insert")
public void schemalessInsert() throws SQLException {
// given
String[] lines = new String[]{
"st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000",
"st,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64 1626006833640000000"};
// when
SchemalessWriter writer = new SchemalessWriter(conn);
writer.write(lines, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO_SECONDS);
// then
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("show tables");
Assert.assertNotNull(rs);
ResultSetMetaData metaData = rs.getMetaData();
Assert.assertTrue(metaData.getColumnCount() > 0);
int rowCnt = 0;
while (rs.next()) {
rowCnt++;
}
Assert.assertEquals(lines.length, rowCnt);
rs.close();
statement.close();
}
/**
* telnet insert compatible with opentsdb
*
* @throws SQLException execute error
*/
@Test
@Description("telnet insert")
public void telnetInsert() throws SQLException {
// given
String[] lines = new String[]{
"stb0_0 1626006833 4 host=host0 interface=eth0",
"stb0_1 1626006833 4 host=host0 interface=eth0",
"stb0_2 1626006833 4 host=host0 interface=eth0 id=\"special_name\"",
};
// when
SchemalessWriter writer = new SchemalessWriter(conn);
writer.write(lines, SchemalessProtocolType.TELNET, SchemalessTimestampType.NOT_CONFIGURED);
// then
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("show tables");
Assert.assertNotNull(rs);
ResultSetMetaData metaData = rs.getMetaData();
Assert.assertTrue(metaData.getColumnCount() > 0);
int rowCnt = 0;
while (rs.next()) {
rowCnt++;
}
Assert.assertEquals(lines.length, rowCnt);
rs.close();
statement.close();
}
/**
* json insert compatible with opentsdb json format
*
* @throws SQLException execute error
*/
@Test
@Description("json insert")
public void jsonInsert() throws SQLException {
// given
String json = "[\n" +
" {\n" +
" \"metric\": \"cpu_load_1\",\n" +
" \"timestamp\": 1626006833,\n" +
" \"value\": 55.5,\n" +
" \"tags\": {\n" +
" \"host\": \"ubuntu\",\n" +
" \"interface\": \"eth1\",\n" +
" \"Id\": \"tb1\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"metric\": \"cpu_load_2\",\n" +
" \"timestamp\": 1626006834,\n" +
" \"value\": 55.5,\n" +
" \"tags\": {\n" +
" \"host\": \"ubuntu\",\n" +
" \"interface\": \"eth2\",\n" +
" \"Id\": \"tb2\"\n" +
" }\n" +
" }\n" +
"]";
// when
SchemalessWriter writer = new SchemalessWriter(conn);
writer.write(json, SchemalessProtocolType.JSON, SchemalessTimestampType.NOT_CONFIGURED);
// then
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("show tables");
Assert.assertNotNull(rs);
ResultSetMetaData metaData = rs.getMetaData();
Assert.assertTrue(metaData.getColumnCount() > 0);
int rowCnt = 0;
while (rs.next()) {
rowCnt++;
}
Assert.assertEquals(((JSONArray) JSONObject.parse(json)).size(), rowCnt);
rs.close();
statement.close();
}
@Test
public void telnetListInsert() throws SQLException {
// given
List<String> list = new ArrayList<>();
list.add("stb0_0 1626006833 4 host=host0 interface=eth0");
list.add("stb0_1 1626006833 4 host=host0 interface=eth0");
list.add("stb0_2 1626006833 4 host=host0 interface=eth0 id=\"special_name\"");
// when
SchemalessWriter writer = new SchemalessWriter(conn);
writer.write(list, SchemalessProtocolType.TELNET, SchemalessTimestampType.NOT_CONFIGURED);
// then
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("show tables");
Assert.assertNotNull(rs);
ResultSetMetaData metaData = rs.getMetaData();
Assert.assertTrue(metaData.getColumnCount() > 0);
int rowCnt = 0;
while (rs.next()) {
rowCnt++;
}
Assert.assertEquals(list.size(), rowCnt);
rs.close();
statement.close();
}
@Before
public void before() {
String host = "127.0.0.1";
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();
}
}
@After
public void after() {
try (Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists " + dbname);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.taosdata.jdbc;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class SetConfigurationInJNITest {
private String host = "127.0.0.1";
private String dbname = "test_set_config";
@Test
public void setConfigInUrl() {
try {
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata&debugFlag=143&rpcTimer=500");
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void setConfigInProperties() {
try {
Properties props = new Properties();
props.setProperty("debugFlag", "143");
props.setProperty("r pcTimer", "500");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case1:set debugFlag=135
//expect:debugFlag:135
//result:pass
public void setConfigfordebugFlag() {
try {
Properties props = new Properties();
//set debugFlag=135
props.setProperty("debugFlag", "135");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case2:set debugFlag=abc (wrong type)
//expect:debugFlag:135
//result:pass
public void setConfigforwrongtype() {
try {
Properties props = new Properties();
//set debugFlag=135
props.setProperty("debugFlag", "abc");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case3:set rpcTimer=0 (smaller than the boundary conditions)
//expect:rpcTimer:300
//result:pass
public void setConfigrpcTimer() {
try {
Properties props = new Properties();
//set rpcTimer=0
props.setProperty("rpcTimer", "0");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case4:set rpcMaxTime=10000 (bigger than the boundary conditions)
//expect:rpcMaxTime:600
//result:pass
public void setConfigforrpcMaxTime() {
try {
Properties props = new Properties();
//set rpcMaxTime=10000
props.setProperty("rpcMaxTime", "10000");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case5:set numOfThreadsPerCore=aaa (wrong type)
//expect:numOfThreadsPerCore:1.0
//result:pass
public void setConfigfornumOfThreadsPerCore() {
try {
Properties props = new Properties();
//set numOfThreadsPerCore=aaa
props.setProperty("numOfThreadsPerCore", "aaa");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case6:set numOfThreadsPerCore=100000 (bigger than the boundary conditions)
//expect:numOfThreadsPerCore:1.0
//result:pass
public void setConfignumOfThreadsPerCore() {
try {
Properties props = new Properties();
//set numOfThreadsPerCore=100000
props.setProperty("numOfThreadsPerCore", "100000");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
// test case7:set both true and wrong config(debugFlag=0,rpcDebugFlag=143,cDebugFlag=143,rpcTimer=100000)
// expect:rpcDebugFlag:143,cDebugFlag:143,rpcTimer:300
// result:pass
public void setConfigformaxTmrCtrl() {
try {
Properties props = new Properties();
props.setProperty("debugFlag", "0");
props.setProperty("rpcDebugFlag", "143");
props.setProperty("cDebugFlag", "143");
props.setProperty("rpcTimer", "100000");
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata", props);
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
//test case 8:use url to set with wrong type(debugFlag=abc,rpcTimer=abc)
//expect:default value
//result:pass
public void setConfigInUrlwithwrongtype() {
try {
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/?user=root&password=taosdata&debugFlag=abc&rpcTimer=abc");
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, f1 int) tags(loc nchar(10))");
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
......@@ -30,42 +30,6 @@ public class TSDBConnectionTest {
}
}
@Test
public void runSubscribe() {
try {
// given
TSDBConnection unwrap = conn.unwrap(TSDBConnection.class);
TSDBSubscribe subscribe = unwrap.subscribe("topic1", "select * from log.log", false);
// when
TSDBResultSet rs = subscribe.consume();
ResultSetMetaData metaData = rs.getMetaData();
// then
Assert.assertNotNull(rs);
Assert.assertEquals(4, metaData.getColumnCount());
Assert.assertEquals("ts", metaData.getColumnLabel(1));
Assert.assertEquals("level", metaData.getColumnLabel(2));
Assert.assertEquals("content", metaData.getColumnLabel(3));
Assert.assertEquals("ipaddr", metaData.getColumnLabel(4));
rs.next();
// row 1
{
Assert.assertNotNull(rs.getTimestamp(1));
Assert.assertNotNull(rs.getTimestamp("ts"));
Assert.assertNotNull(rs.getByte(2));
Assert.assertNotNull(rs.getByte("level"));
Assert.assertNotNull(rs.getString(3));
Assert.assertNotNull(rs.getString("content"));
Assert.assertNotNull(rs.getString(4));
Assert.assertNotNull(rs.getString("ipaddr"));
}
subscribe.close(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void prepareStatement() throws SQLException {
PreparedStatement pstmt = conn.prepareStatement("select server_status()");
......@@ -391,13 +355,9 @@ public class TSDBConnectionTest {
}
@Test
public void unwrap() {
try {
TSDBConnection tsdbConnection = conn.unwrap(TSDBConnection.class);
Assert.assertNotNull(tsdbConnection);
} catch (SQLException e) {
e.printStackTrace();
}
public void unwrap() throws SQLException {
TSDBConnection tsdbConnection = conn.unwrap(TSDBConnection.class);
Assert.assertNotNull(tsdbConnection);
}
@Test
......@@ -406,31 +366,25 @@ public class TSDBConnectionTest {
}
@BeforeClass
public static void beforeClass() {
try {
Class.forName("com.taosdata.jdbc.TSDBDriver");
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("jdbc:TAOS://" + host + ":6030/log?user=root&password=taosdata", properties);
// create test database for test cases
try (Statement stmt = conn.createStatement()) {
stmt.execute("create database if not exists test");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
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");
conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/log?user=root&password=taosdata", properties);
// create test database for test cases
try (Statement stmt = conn.createStatement()) {
stmt.execute("create database if not exists test");
}
}
@AfterClass
public static void afterClass() {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
public static void afterClass() throws SQLException {
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists test");
statement.close();
conn.close();
}
}
......
package com.taosdata.jdbc;
import org.junit.BeforeClass;
import org.junit.Test;
import java.sql.*;
......@@ -33,7 +32,6 @@ public class TSDBDriverTest {
conn = DriverManager.getConnection(url);
assertNotNull("failure - connection should not be null", conn);
} catch (SQLException e) {
e.printStackTrace();
fail("failure - should not throw Exception");
}
}
......@@ -49,7 +47,6 @@ public class TSDBDriverTest {
conn = DriverManager.getConnection(jdbcUrl, connProps);
assertNotNull("failure - connection should not be null", conn);
} catch (SQLException e) {
e.printStackTrace();
fail("failure - should not throw Exception");
}
}
......@@ -65,7 +62,6 @@ public class TSDBDriverTest {
conn = DriverManager.getConnection(jdbcUrl, connProps);
assertNotNull("failure - connection should not be null", conn);
} catch (SQLException e) {
e.printStackTrace();
fail("failure - should not throw Exception");
}
}
......@@ -157,16 +153,8 @@ public class TSDBDriverTest {
}
@Test
public void getParentLogger() throws SQLFeatureNotSupportedException {
public void getParentLogger() {
assertNull(new TSDBDriver().getParentLogger());
}
@BeforeClass
public static void before() {
try {
Class.forName("com.taosdata.jdbc.TSDBDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
package com.taosdata.jdbc;
import com.taosdata.jdbc.enums.SchemalessProtocolType;
import com.taosdata.jdbc.enums.SchemalessTimestampType;
import org.junit.Test;
import java.lang.management.ManagementFactory;
......@@ -8,6 +10,7 @@ import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
......@@ -17,116 +20,111 @@ public class TSDBJNIConnectorTest {
private static TSDBResultSetRowData rowData;
@Test
public void test() {
public void test() throws SQLException {
try {
try {
//change sleepSeconds when debugging with attach to process to find PID
int sleepSeconds = -1;
if (sleepSeconds>0) {
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
String jvmName = runtimeBean.getName();
long pid = Long.valueOf(jvmName.split("@")[0]);
System.out.println("JVM PID = " + pid);
Thread.sleep(sleepSeconds*1000);
}
}
catch (Exception e) {
e.printStackTrace();
//change sleepSeconds when debugging with attach to process to find PID
int sleepSeconds = -1;
if (sleepSeconds > 0) {
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
String jvmName = runtimeBean.getName();
long pid = Long.valueOf(jvmName.split("@")[0]);
System.out.println("JVM PID = " + pid);
Thread.sleep(sleepSeconds * 1000);
}
} catch (Exception e) {
e.printStackTrace();
}
// init
TSDBJNIConnector.init("/etc/taos", null, null, null);
// connect
TSDBJNIConnector connector = new TSDBJNIConnector();
connector.connect("127.0.0.1", 6030, null, "root", "taosdata");
// setup
String setupSqlStrs[] = {"create database if not exists d precision \"us\"",
"create table if not exists d.t(ts timestamp, f int)",
"create database if not exists d2",
"create table if not exists d2.t2(ts timestamp, f int)",
"insert into d.t values(now+100s, 100)",
"insert into d2.t2 values(now+200s, 200)"
};
for (String setupSqlStr : setupSqlStrs) {
long setupSql = connector.executeQuery(setupSqlStr);
assertEquals(0, connector.getResultTimePrecision(setupSql));
if (connector.isUpdateQuery(setupSql)) {
connector.freeResultSet(setupSql);
}
// init
Properties properties = new Properties();
properties.setProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, "/etc/taos");
TSDBJNIConnector.init(properties);
// connect
TSDBJNIConnector connector = new TSDBJNIConnector();
connector.connect("127.0.0.1", 6030, null, "root", "taosdata");
// setup
String setupSqlStrs[] = {"create database if not exists d precision \"us\"",
"create table if not exists d.t(ts timestamp, f int)",
"create database if not exists d2",
"create table if not exists d2.t2(ts timestamp, f int)",
"insert into d.t values(now+100s, 100)",
"insert into d2.t2 values(now+200s, 200)"
};
for (String setupSqlStr : setupSqlStrs) {
long setupSql = connector.executeQuery(setupSqlStr);
assertEquals(0, connector.getResultTimePrecision(setupSql));
if (connector.isUpdateQuery(setupSql)) {
connector.freeResultSet(setupSql);
}
}
{
long sqlObj1 = connector.executeQuery("select * from d2.t2");
assertEquals(0, connector.getResultTimePrecision(sqlObj1));
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(sqlObj1, columnMetaDataList);
rowData = new TSDBResultSetRowData(columnMetaDataList.size());
assertTrue(next(connector, sqlObj1));
assertEquals(0, connector.getResultTimePrecision(sqlObj1));
connector.freeResultSet(sqlObj1);
}
{
long sqlObj1 = connector.executeQuery("select * from d2.t2");
assertEquals(0, connector.getResultTimePrecision(sqlObj1));
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(sqlObj1, columnMetaDataList);
rowData = new TSDBResultSetRowData(columnMetaDataList.size());
assertTrue(next(connector, sqlObj1));
assertEquals(0, connector.getResultTimePrecision(sqlObj1));
connector.freeResultSet(sqlObj1);
}
// executeQuery
long pSql = connector.executeQuery("select * from d.t");
// executeQuery
long pSql = connector.executeQuery("select * from d.t");
if (connector.isUpdateQuery(pSql)) {
connector.freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
if (connector.isUpdateQuery(pSql)) {
connector.freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
assertEquals(1, connector.getResultTimePrecision(pSql));
assertEquals(1, connector.getResultTimePrecision(pSql));
// get schema
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
}
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
}
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
}
// get schema
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
}
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
}
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
}
assertEquals(1, connector.getResultTimePrecision(pSql));
int columnSize = columnMetaDataList.size();
// print metadata
for (int i = 0; i < columnSize; i++) {
// System.out.println(columnMetaDataList.get(i));
}
rowData = new TSDBResultSetRowData(columnSize);
// iterate resultSet
for (int i = 0; next(connector, pSql); i++) {
assertEquals(1, connector.getResultTimePrecision(pSql));
int columnSize = columnMetaDataList.size();
// print metadata
for (int i = 0; i < columnSize; i++) {
System.out.println(columnMetaDataList.get(i));
}
rowData = new TSDBResultSetRowData(columnSize);
// iterate resultSet
for (int i = 0; next(connector, pSql); i++) {
assertEquals(1, connector.getResultTimePrecision(pSql));
System.out.println();
}
// close resultSet
code = connector.freeResultSet(pSql);
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
}
// close statement
connector.executeQuery("use d");
String[] lines = new String[] {"st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000ns",
"st,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64 1626006833640000000ns"};
connector.insertLines(lines);
// close connection
connector.closeConnection();
} catch (SQLWarning throwables) {
throwables.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// close resultSet
code = connector.freeResultSet(pSql);
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
}
// close statement
connector.executeQuery("use d");
String[] lines = new String[]{
"st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000",
"st,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64 1626006833640000000"};
connector.insertLines(lines, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO_SECONDS);
// close connection
connector.executeQuery("drop database if exists d");
connector.executeQuery("drop database if exists d2");
connector.closeConnection();
}
private static boolean next(TSDBJNIConnector connector, long pSql) throws SQLException {
......@@ -140,11 +138,7 @@ public class TSDBJNIConnectorTest {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
} else if (code == TSDBConstants.JNI_FETCH_END) {
return false;
} else {
return true;
}
} else return code != TSDBConstants.JNI_FETCH_END;
}
}
......@@ -17,6 +17,7 @@ public class TSDBParameterMetaDataTest {
private static PreparedStatement pstmt_select;
private static ParameterMetaData parameterMetaData_insert;
private static ParameterMetaData parameterMetaData_select;
private static final String dbname = "test_pstmt";
@Test
public void getParameterCount() throws SQLException {
......@@ -152,9 +153,9 @@ public class TSDBParameterMetaDataTest {
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");
stmt.execute("create database if not exists test_pstmt");
stmt.execute("use test_pstmt");
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, f1 int, f2 bigint, f3 float, f4 double, f5 smallint, f6 tinyint, f7 bool, f8 binary(64), f9 nchar(64)) tags(loc nchar(64))");
stmt.execute("create table t1 using weather tags('beijing')");
}
......@@ -190,8 +191,12 @@ public class TSDBParameterMetaDataTest {
pstmt_insert.close();
if (pstmt_select != null)
pstmt_select.close();
if (conn != null)
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists " + dbname);
statement.close();
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
......
......@@ -1233,6 +1233,7 @@ public class TSDBPreparedStatementTest {
try {
Statement statement = conn.createStatement();
statement.execute("drop database if exists " + dbname);
statement.execute("drop database if exists dbtest");
statement.close();
if (conn != null)
conn.close();
......
......@@ -668,8 +668,12 @@ public class TSDBResultSetTest {
rs.close();
if (stmt != null)
stmt.close();
if (conn != null)
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists restful_test");
statement.close();
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
......
package com.taosdata.jdbc.annotation;
import java.util.ArrayList;
import java.util.List;
/**
* Test class
*/
public class CatalogClass {
private String name;
private String alias;
private String author;
private String version;
private List<CatalogMethod> methods = new ArrayList<>();
private int total;
private int failure;
public void setTotal(int total) {
this.total = total;
}
public void setFailure(int failure) {
this.failure = failure;
}
public void setAuthor(String author) {
this.author = author;
}
public void setVersion(String version) {
this.version = version;
}
public void setName(String name) {
this.name = name;
}
public void setAlias(String alias) {
this.alias = alias;
}
public void setMethods(List<CatalogMethod> methods) {
this.methods = methods;
}
@Override
public String toString() {
if (methods.size() < 1)
return null;
StringBuilder sb = new StringBuilder();
sb.append("ClassName: ").append(name);
String msg = trim(alias);
if (null != msg)
sb.append("\tAlias:").append(alias);
sb.append("\tTotal:").append(total)
.append("\tFailure:").append(failure).append("\n");
for (CatalogMethod method : methods) {
sb.append("\t").append(method.getName());
sb.append("\t").append(method.isSuccess());
sb.append("\t").append(method.getMessage());
String mAuthor = trim(method.getAuthor());
if (null == mAuthor) {
sb.append("\t").append(author);
} else {
sb.append("\t").append(method.getAuthor());
}
String mVersion = trim(method.getVersion());
if (null == mVersion) {
sb.append("\t").append(version);
} else {
sb.append("\t").append(mVersion);
}
sb.append("\n");
}
return sb.toString();
}
private String trim(String s) {
if (null == s || s.trim().equals("")) {
return null;
} else {
return s.trim();
}
}
}
package com.taosdata.jdbc.annotation;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import java.io.File;
import java.io.FileWriter;
import java.util.LinkedList;
public class CatalogListener extends RunListener {
public static final String CATALOG_FILE = "target/TestCaseCatalog.txt";
CatalogClass catalogClass = null;
private final LinkedList<CatalogMethod> methods = new LinkedList<>();
@Override
public void testRunStarted(Description description) throws Exception {
catalogClass = new CatalogClass();
TestTarget target = description.getAnnotation(TestTarget.class);
if (target != null) {
catalogClass.setAlias(target.alias());
catalogClass.setAuthor(target.author());
catalogClass.setVersion(target.version());
}
catalogClass.setName(getClassName(description.getClassName()));
}
private String getClassName(String name) {
if (null == name || name.trim().equals("")) {
return null;
}
name = name.trim();
int pos = name.lastIndexOf(".");
if (-1 == pos) {
return name;
}
return name.substring(pos + 1);
}
@Override
public void testRunFinished(Result result) throws Exception {
catalogClass.setMethods(methods);
catalogClass.setTotal(result.getRunCount());
catalogClass.setFailure(result.getFailureCount());
File file = new File(CATALOG_FILE);
if (!file.exists()) {
synchronized (CatalogListener.class) {
if (!file.exists()) {
file.createNewFile();
try (FileWriter writer = new FileWriter(file, true)) {
writer.write("\tName\tPass\tMessage\tAuthor\tVersion\n");
writer.write(catalogClass.toString());
}
}
}
} else {
try (FileWriter writer = new FileWriter(file, true)) {
writer.write(catalogClass.toString());
}
}
}
@Override
public void testStarted(Description description) throws Exception {
}
@Override
public void testFinished(Description description) throws Exception {
com.taosdata.jdbc.annotation.Description annotation
= description.getAnnotation(com.taosdata.jdbc.annotation.Description.class);
if (annotation != null) {
CatalogMethod method = new CatalogMethod();
method.setMessage(annotation.value());
method.setAuthor(annotation.author());
method.setVersion(annotation.version());
method.setSuccess(true);
method.setName(description.getMethodName());
methods.addLast(method);
}
}
@Override
public void testFailure(Failure failure) throws Exception {
com.taosdata.jdbc.annotation.Description annotation
= failure.getDescription().getAnnotation(com.taosdata.jdbc.annotation.Description.class);
CatalogMethod method = new CatalogMethod();
method.setMessage(annotation.value());
method.setAuthor(annotation.author());
method.setVersion(annotation.version());
method.setSuccess(false);
method.setName(failure.getDescription().getMethodName());
methods.addFirst(method);
}
@Override
public void testAssumptionFailure(Failure failure) {
}
@Override
public void testIgnored(Description description) throws Exception {
super.testIgnored(description);
}
}
\ No newline at end of file
package com.taosdata.jdbc.annotation;
/**
* Test method
*/
public class CatalogMethod {
private String name;
private boolean success;
private String message;
private String author;
private String version;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
package com.taosdata.jdbc.annotation;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
public class CatalogRunner extends BlockJUnit4ClassRunner {
public CatalogRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
@Override
public void run(RunNotifier notifier) {
//add user-defined listener
notifier.addListener(new CatalogListener());
EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription());
notifier.fireTestRunStarted(getDescription());
try {
Statement statement = classBlock(notifier);
statement.evaluate();
} catch (AssumptionViolatedException av) {
testNotifier.addFailedAssumption(av);
} catch (StoppedByUserException exception) {
throw exception;
} catch (Throwable e) {
testNotifier.addFailure(e);
}
}
}
\ No newline at end of file
package com.taosdata.jdbc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Description {
String value();
// git blame author
String author() default "";
// since which version;
String version() default "";
}
package com.taosdata.jdbc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface TestTarget {
String alias() default "";
String author();
String version() default "";
}
......@@ -2,7 +2,6 @@ package com.taosdata.jdbc.cases;
import com.taosdata.jdbc.TSDBErrorNumbers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
......
......@@ -19,16 +19,14 @@ public class BatchErrorIgnoreTest {
IntStream.range(1, 6).mapToObj(i -> "insert into test.t" + i + " values(now, " + i + ")").forEach(sql -> {
try {
stmt.addBatch(sql);
} catch (SQLException e) {
e.printStackTrace();
} catch (SQLException ignored) {
}
});
stmt.addBatch("insert into t11 values(now, 11)");
IntStream.range(6, 11).mapToObj(i -> "insert into test.t" + i + " values(now, " + i + "),(now + 1s, " + (10 * i) + ")").forEach(sql -> {
try {
stmt.addBatch(sql);
} catch (SQLException e) {
e.printStackTrace();
} catch (SQLException ignored) {
}
});
stmt.addBatch("select count(*) from test.weather");
......@@ -57,23 +55,19 @@ public class BatchErrorIgnoreTest {
IntStream.range(1, 6).mapToObj(i -> "insert into test.t" + i + " values(now, " + i + ")").forEach(sql -> {
try {
stmt.addBatch(sql);
} catch (SQLException e) {
e.printStackTrace();
} catch (SQLException ignored) {
}
});
stmt.addBatch("insert into t11 values(now, 11)");
IntStream.range(6, 11).mapToObj(i -> "insert into test.t" + i + " values(now, " + i + "),(now + 1s, " + (10 * i) + ")").forEach(sql -> {
try {
stmt.addBatch(sql);
} catch (SQLException e) {
e.printStackTrace();
} catch (SQLException ignored) {
}
});
stmt.addBatch("select count(*) from test.weather");
results = stmt.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
}
// then
......@@ -94,10 +88,10 @@ public class BatchErrorIgnoreTest {
}
@Before
public void before() {
try {
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement();
public void before() throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement();) {
stmt.execute("use test");
stmt.execute("drop table if exists weather");
stmt.execute("create table weather (ts timestamp, f1 float) tags(t1 int)");
......@@ -108,37 +102,25 @@ public class BatchErrorIgnoreTest {
e.printStackTrace();
}
});
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@BeforeClass
public static void beforeClass() {
try {
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement();
public static void beforeClass() throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists test");
stmt.execute("create database if not exists test");
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@AfterClass
public static void afterClass() {
try {
Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement();
public static void afterClass() throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists test");
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
......@@ -20,22 +20,20 @@ public class ConnectMultiTaosdByRestfulWithDifferentTokenTest {
private Connection conn2;
@Test
public void test() {
public void test() throws SQLException {
//when
executeSelectStatus(conn1);
executeSelectStatus(conn2);
executeSelectStatus(conn1);
}
private void executeSelectStatus(Connection connection) {
private void executeSelectStatus(Connection connection) throws SQLException {
try (Statement stmt = connection.createStatement()) {
ResultSet rs = stmt.executeQuery("select server_status()");
ResultSetMetaData meta = rs.getMetaData();
Assert.assertNotNull(meta);
while (rs.next()) {
}
} catch (SQLException e) {
e.printStackTrace();
}
}
......
......@@ -11,7 +11,7 @@ public class DatetimeBefore1970Test {
private Connection conn;
@Test
public void test() {
public void test() throws SQLException {
try (Statement stmt = conn.createStatement()) {
// given
stmt.executeUpdate("insert into weather(ts) values('1969-12-31 23:59:59.999')");
......@@ -45,36 +45,25 @@ public class DatetimeBefore1970Test {
// then
ts = rs.getTimestamp("ts");
Assert.assertEquals("1970-01-01 07:59:59.999", TimestampUtil.longToDatetime(ts.getTime()));
} 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 test_timestamp");
stmt.execute("create database if not exists test_timestamp keep 36500");
stmt.execute("use test_timestamp");
stmt.execute("create table weather(ts timestamp,f1 float)");
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
public void before() throws SQLException {
conn = DriverManager.getConnection("jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata");
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists test_timestamp");
stmt.execute("create database if not exists test_timestamp keep 36500");
stmt.execute("use test_timestamp");
stmt.execute("create table weather(ts timestamp,f1 float)");
stmt.close();
}
@After
public void after() {
try {
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists test_timestamp");
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
public void after() throws SQLException {
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists test_timestamp");
if (conn != null)
conn.close();
}
}
package com.taosdata.jdbc.cases;
import org.junit.Assert;
import org.junit.Test;
import java.sql.*;
import java.text.SimpleDateFormat;
public class GetLongWithDifferentTimestampPrecision {
private final String host = "127.0.0.1";
@Test
public void testRestful() throws SQLException {
// given
String url = "jdbc:TAOS-RS://" + host + ":6041/";
Connection conn = DriverManager.getConnection(url, "root", "taosdata");
long ts = System.currentTimeMillis();
// when and then
assertResultSet(conn, "ms", ts, ts);
assertResultSet(conn, "us", ts, ts * 1000);
assertResultSet(conn, "ns", ts, ts * 1000_000);
}
@Test
public void testJni() throws SQLException {
// given
String url = "jdbc:TAOS://" + host + ":6030/";
Connection conn = DriverManager.getConnection(url, "root", "taosdata");
long ts = System.currentTimeMillis();
// when and then
assertResultSet(conn, "ms", ts, ts);
assertResultSet(conn, "us", ts, ts * 1000);
assertResultSet(conn, "ns", ts, ts * 1000_000);
}
private void assertResultSet(Connection conn, String precision, long timestamp, long expect) throws SQLException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
try (Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists test");
stmt.execute("create database if not exists test precision '" + precision + "'");
stmt.execute("create table test.weather(ts timestamp, f1 int)");
String dateTimeStr = sdf.format(new Date(timestamp));
stmt.execute("insert into test.weather values('" + dateTimeStr + "', 1)");
ResultSet rs = stmt.executeQuery("select * from test.weather");
rs.next();
long actual = rs.getLong("ts");
Assert.assertEquals(expect, actual);
stmt.execute("drop database if exists test");
}
}
}
......@@ -17,29 +17,6 @@ public class ImportTest {
static String host = "127.0.0.1";
private static long ts;
@BeforeClass
public static void before() {
try {
Properties properties = new Properties();
properties.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
properties.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
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");
connection = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/", properties);
Statement stmt = connection.createStatement();
stmt.execute("create database if not exists " + dbName);
stmt.execute("create table if not exists " + dbName + "." + tName + " (ts timestamp, k int, v int)");
stmt.close();
ts = System.currentTimeMillis();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void case001_insertData() throws Exception {
try (Statement stmt = connection.createStatement()) {
......@@ -52,28 +29,25 @@ public class ImportTest {
}
@Test
public void case002_checkSum() {
public void case002_checkSum() throws SQLException {
Assert.assertEquals(50, select());
}
private int select() {
private int select() throws SQLException {
int count = 0;
try (Statement stmt = connection.createStatement()) {
String sql = "select * from " + dbName + "." + tName;
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
count++;
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
@Test
public void case003_importData() {
public void case003_importData() throws SQLException {
// 避免时间重复
try (Statement stmt = connection.createStatement()) {
StringBuilder sqlBuilder = new StringBuilder("import into ").append(dbName).append(".").append(tName).append(" values ");
......@@ -84,27 +58,40 @@ public class ImportTest {
}
int rows = stmt.executeUpdate(sqlBuilder.toString());
assertEquals(50, rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void case004_checkSum() {
public void case004_checkSum() throws SQLException {
Assert.assertEquals(100, select());
}
@BeforeClass
public static void before() throws SQLException {
Properties properties = new Properties();
properties.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
properties.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
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");
connection = DriverManager.getConnection("jdbc:TAOS://" + host + ":0/", properties);
Statement stmt = connection.createStatement();
stmt.execute("create database if not exists " + dbName);
stmt.execute("create table if not exists " + dbName + "." + tName + " (ts timestamp, k int, v int)");
stmt.close();
ts = System.currentTimeMillis();
}
@AfterClass
public static void close() {
try {
if (connection != null) {
Statement statement = connection.createStatement();
statement.executeUpdate("drop database " + dbName);
statement.close();
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
public static void close() throws SQLException {
if (connection != null) {
Statement statement = connection.createStatement();
statement.executeUpdate("drop database " + dbName);
statement.close();
connection.close();
}
}
}
package com.taosdata.jdbc.cases;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.*;
import org.junit.runners.MethodSorters;
import java.sql.*;
......@@ -16,36 +13,32 @@ public class InsertDbwithoutUseDbTest {
private static final String host = "127.0.0.1";
private static Properties properties;
private static final Random random = new Random(System.currentTimeMillis());
private static final String dbname = "inWithoutDb";
@Test
public void case001() throws SQLException {
// prepare schema
String url = "jdbc:TAOS://127.0.0.1:6030/?user=root&password=taosdata";
Connection conn = DriverManager.getConnection(url, properties);
try (Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists inWithoutDb");
stmt.execute("create database if not exists inWithoutDb");
stmt.execute("create table inWithoutDb.weather(ts timestamp, f1 int)");
}
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists " + dbname);
stmt.execute("create database if not exists " + dbname);
stmt.execute("create table " + dbname + ".weather(ts timestamp, f1 int)");
conn.close();
// execute insert
url = "jdbc:TAOS://127.0.0.1:6030/inWithoutDb?user=root&password=taosdata";
url = "jdbc:TAOS://127.0.0.1:6030/" + dbname + "?user=root&password=taosdata";
conn = DriverManager.getConnection(url, properties);
try (Statement stmt = conn.createStatement()) {
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
Assert.assertEquals(1, affectedRow);
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
Assert.assertEquals(false, flag);
ResultSet rs = stmt.executeQuery("select count(*) from weather");
rs.next();
int count = rs.getInt("count(*)");
Assert.assertEquals(2, count);
} catch (SQLException e) {
e.printStackTrace();
}
stmt = conn.createStatement();
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
Assert.assertEquals(1, affectedRow);
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
Assert.assertEquals(false, flag);
ResultSet rs = stmt.executeQuery("select count(*) from weather");
rs.next();
int count = rs.getInt("count(*)");
Assert.assertEquals(2, count);
conn.close();
}
......@@ -54,28 +47,25 @@ public class InsertDbwithoutUseDbTest {
// prepare the schema
final String url = "jdbc:TAOS-RS://" + host + ":6041/inWithoutDb?user=root&password=taosdata";
Connection conn = DriverManager.getConnection(url, properties);
try (Statement stmt = conn.createStatement()) {
stmt.execute("drop database if exists inWithoutDb");
stmt.execute("create database if not exists inWithoutDb");
stmt.execute("create table inWithoutDb.weather(ts timestamp, f1 int)");
}
conn.close();
Statement stmt = conn.createStatement();
stmt.execute("drop database if exists " + dbname);
stmt.execute("create database if not exists " + dbname);
stmt.execute("create table " + dbname + ".weather(ts timestamp, f1 int)");
stmt.close();
// execute
conn = DriverManager.getConnection(url, properties);
try (Statement stmt = conn.createStatement()) {
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
Assert.assertEquals(1, affectedRow);
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
Assert.assertEquals(false, flag);
ResultSet rs = stmt.executeQuery("select count(*) from weather");
rs.next();
int count = rs.getInt("count(*)");
Assert.assertEquals(2, count);
} catch (SQLException e) {
e.printStackTrace();
}
stmt = conn.createStatement();
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
Assert.assertEquals(1, affectedRow);
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
Assert.assertEquals(false, flag);
ResultSet rs = stmt.executeQuery("select count(*) from weather");
rs.next();
int count = rs.getInt("count(*)");
Assert.assertEquals(2, count);
stmt.execute("drop database if exists " + dbname);
stmt.close();
conn.close();
}
@BeforeClass
......
......@@ -427,8 +427,12 @@ public class InsertSpecialCharacterJniTest {
@AfterClass
public static void afterClass() throws SQLException {
if (conn != null)
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists " + dbName);
statement.close();
conn.close();
}
}
}
......@@ -391,8 +391,12 @@ public class InsertSpecialCharacterRestfulTest {
@AfterClass
public static void afterClass() throws SQLException {
if (conn != null)
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists "+ dbName);
statement.close();
conn.close();
}
}
}
package com.taosdata.jdbc.cases;
import org.junit.AfterClass;
import org.junit.Test;
import java.sql.*;
public class JDBCTypeAndTypeCompareTest {
private static Connection conn;
private static final String dbname = "test";
@Test
public void test() throws SQLException {
conn = DriverManager.getConnection("jdbc:TAOS://127.0.0.1:6030/", "root", "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 weather(ts timestamp, f1 int, f2 bigint, f3 float, f4 double, f5 smallint, f6 tinyint, f7 bool, f8 binary(10), f9 nchar(10) )");
stmt.execute("insert into weather values(now, 1, 2, 3.0, 4.0, 5, 6, true, 'test','test')");
ResultSet rs = stmt.executeQuery("select * from weather");
ResultSetMetaData meta = rs.getMetaData();
while (rs.next()) {
for (int i = 1; i <= meta.getColumnCount(); i++) {
String columnName = meta.getColumnName(i);
String columnTypeName = meta.getColumnTypeName(i);
Object value = rs.getObject(i);
System.out.printf("columnName : %s, columnTypeName: %s, JDBCType: %s\n", columnName, columnTypeName, value.getClass().getName());
}
}
stmt.close();
}
@AfterClass
public static void afterClass() {
try {
if (null != conn) {
Statement statement = conn.createStatement();
statement.execute("drop database if exists " + dbname);
statement.close();
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
......@@ -47,7 +47,7 @@ public class MicroSecondPrecisionJNITest {
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
ts = rs.getLong(1);
Assert.assertEquals(timestamp1, ts);
Assert.assertEquals(timestamp2, ts);
} catch (SQLException e) {
e.printStackTrace();
}
......@@ -79,8 +79,13 @@ public class MicroSecondPrecisionJNITest {
@AfterClass
public static void afterClass() {
try {
if (conn != null)
if (conn != null) {
Statement statement = conn.createStatement();
statement.execute("drop database " + ms_timestamp_db);
statement.execute("drop database " + us_timestamp_db);
statement.close();
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
......
#org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册