From d6b21dadd0eeaf1297d5cad404abe72054a2c6b3 Mon Sep 17 00:00:00 2001 From: jyhou Date: Sat, 3 Aug 2019 17:50:18 +0800 Subject: [PATCH] Fix issue #270 --- src/connector/jdbc/pom.xml | 2 +- .../java/com/taosdata/jdbc/TSDBConstants.java | 2 + .../com/taosdata/jdbc/TSDBJNIConnector.java | 64 +++++++++++++------ .../taosdata/jdbc/TSDBPreparedStatement.java | 2 +- .../java/com/taosdata/jdbc/TSDBStatement.java | 60 +++++++++++++++-- tests/examples/JDBC/JDBCDemo/pom.xml | 2 +- 6 files changed, 104 insertions(+), 28 deletions(-) diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml index 05989178c7..d29700fe8a 100755 --- a/src/connector/jdbc/pom.xml +++ b/src/connector/jdbc/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.taosdata.jdbc taos-jdbcdriver - 1.0.0 + 1.0.1 JDBCDriver TDengine JDBC Driver diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConstants.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConstants.java index ba0c6d939e..3940e80930 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConstants.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBConstants.java @@ -24,6 +24,8 @@ public abstract class TSDBConstants { public static final String INVALID_VARIABLES = "invalid variables"; public static Map DATATYPE_MAP = null; + public static final long JNI_NULL_POINTER = 0L; + public static final int JNI_SUCCESS = 0; public static final int JNI_TDENGINE_ERROR = -1; public static final int JNI_CONNECTION_NULL = -2; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java index b1c3891424..6f305cc2c7 100755 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java @@ -19,7 +19,6 @@ import java.sql.SQLWarning; import java.util.List; public class TSDBJNIConnector { - static final long INVALID_CONNECTION_POINTER_VALUE = 0l; static volatile Boolean isInitialized = false; static { @@ -29,7 +28,12 @@ public class TSDBJNIConnector { /** * Connection pointer used in C */ - private long taos = INVALID_CONNECTION_POINTER_VALUE; + private long taos = TSDBConstants.JNI_NULL_POINTER; + + /** + * Result set pointer for the current connection + */ + private long taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER; /** * result set status in current connection @@ -41,7 +45,7 @@ public class TSDBJNIConnector { * Whether the connection is closed */ public boolean isClosed() { - return this.taos == INVALID_CONNECTION_POINTER_VALUE; + return this.taos == TSDBConstants.JNI_NULL_POINTER; } /** @@ -86,13 +90,13 @@ public class TSDBJNIConnector { * @throws SQLException */ public boolean connect(String host, int port, String dbName, String user, String password) throws SQLException { - if (this.taos != INVALID_CONNECTION_POINTER_VALUE) { + if (this.taos != TSDBConstants.JNI_NULL_POINTER) { this.closeConnectionImp(this.taos); - this.taos = INVALID_CONNECTION_POINTER_VALUE; + this.taos = TSDBConstants.JNI_NULL_POINTER; } this.taos = this.connectImp(host, port, dbName, user, password); - if (this.taos == INVALID_CONNECTION_POINTER_VALUE) { + if (this.taos == TSDBConstants.JNI_NULL_POINTER) { throw new SQLException(TSDBConstants.WrapErrMsg(this.getErrMsg()), "", this.getErrCode()); } @@ -108,13 +112,7 @@ public class TSDBJNIConnector { */ public int executeQuery(String sql) throws SQLException { if (!this.isResultsetClosed) { - //throw new RuntimeException(TSDBConstants.WrapErrMsg("Connection already has an open result set")); - long resultSetPointer = this.getResultSet(); - if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) { - //do nothing - } else { - this.freeResultSet(resultSetPointer); - } + freeResultSet(taosResultSetPointer); } int code; @@ -133,7 +131,14 @@ public class TSDBJNIConnector { throw new SQLException(TSDBConstants.FixErrMsg(code), "", this.getErrCode()); } } - + + // Try retrieving result set for the executed SQLusing the current connection pointer. If the executed + // SQL is a DML/DDL which doesn't return a result set, then taosResultSetPointer should be 0L. Otherwise, + // taosResultSetPointer should be a non-zero value. + taosResultSetPointer = this.getResultSetImp(this.taos); + if (taosResultSetPointer != TSDBConstants.JNI_NULL_POINTER) { + isResultsetClosed = false; + } return code; } @@ -162,8 +167,7 @@ public class TSDBJNIConnector { * Each connection should have a single open result set at a time */ public long getResultSet() { - long res = this.getResultSetImp(this.taos); - return res; + return taosResultSetPointer; } private native long getResultSetImp(long connection); @@ -172,11 +176,31 @@ public class TSDBJNIConnector { * Free resultset operation from C to release resultset pointer by JNI */ public int freeResultSet(long result) { - int res = this.freeResultSetImp(this.taos, result); - this.isResultsetClosed = true; // reset resultSetPointer to 0 after freeResultSetImp() return - return res; + int res = TSDBConstants.JNI_SUCCESS; + if (result != taosResultSetPointer && taosResultSetPointer != TSDBConstants.JNI_NULL_POINTER) { + throw new RuntimeException("Invalid result set pointer"); + } else if (taosResultSetPointer != TSDBConstants.JNI_NULL_POINTER){ + res = this.freeResultSetImp(this.taos, result); + isResultsetClosed = true; // reset resultSetPointer to 0 after freeResultSetImp() return + taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER; + } + return res; } + /** + * Close the open result set which is associated to the current connection. If the result set is already + * closed, return 0 for success. + * @return + */ + public int freeResultSet() { + int resCode = TSDBConstants.JNI_SUCCESS; + if (!isResultsetClosed) { + resCode = this.freeResultSetImp(this.taos, this.taosResultSetPointer); + taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER; + } + return resCode; + } + private native int freeResultSetImp(long connection, long result); /** @@ -220,7 +244,7 @@ public class TSDBJNIConnector { if (code < 0) { throw new SQLException(TSDBConstants.FixErrMsg(code), "", this.getErrCode()); } else if (code == 0){ - this.taos = INVALID_CONNECTION_POINTER_VALUE; + this.taos = TSDBConstants.JNI_NULL_POINTER; } else { throw new SQLException("Undefined error code returned by TDengine when closing a connection"); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java index d613c252f0..bd45fbfb7a 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java @@ -244,7 +244,7 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat @Override public boolean execute() throws SQLException { - return executeUpdate(getNativeSql()) == 0; + return super.execute(getNativeSql()); } @Override diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java index 7d4f4c4691..455b73bb92 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java @@ -27,8 +27,14 @@ public class TSDBStatement implements Statement { /** Timeout for a query */ protected int queryTimeout = 0; + /** + * Status of current statement + */ + private boolean isClosed = true; + TSDBStatement(TSDBJNIConnector connecter) { this.connecter = connecter; + this.isClosed = false; } public T unwrap(Class iface) throws SQLException { @@ -40,13 +46,16 @@ public class TSDBStatement implements Statement { } public ResultSet executeQuery(String sql) throws SQLException { + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } this.connecter.executeQuery(sql); long resultSetPointer = this.connecter.getResultSet(); if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) { throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL)); - } else if (resultSetPointer == 0) { + } else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) { return null; } else { return new TSDBResultSet(this.connecter, resultSetPointer); @@ -54,7 +63,20 @@ public class TSDBStatement implements Statement { } public int executeUpdate(String sql) throws SQLException { - return this.connecter.executeQuery(sql); + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } + int res = this.connecter.executeQuery(sql); + long resultSetPointer = this.connecter.getResultSet(); + + if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) { + throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL)); + } else if (resultSetPointer != TSDBConstants.JNI_NULL_POINTER) { + this.connecter.freeResultSet(); + throw new SQLException("The executed SQL is not a DML or a DDL"); + } else { + return res; + } } public String getErrorMsg() { @@ -62,6 +84,12 @@ public class TSDBStatement implements Statement { } public void close() throws SQLException { + if (!isClosed) { + if (!this.connecter.isResultsetClosed()) { + this.connecter.freeResultSet(); + } + isClosed = true; + } } public int getMaxFieldSize() throws SQLException { @@ -110,19 +138,38 @@ public class TSDBStatement implements Statement { } public boolean execute(String sql) throws SQLException { - return executeUpdate(sql) == 0; + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } + boolean res = true; + this.connecter.executeQuery(sql); + long resultSetPointer = this.connecter.getResultSet(); + + if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) { + throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL)); + } else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) { + // no result set is retrieved + res = false; + } + return res; } public ResultSet getResultSet() throws SQLException { + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } long resultSetPointer = connecter.getResultSet(); TSDBResultSet resSet = null; - if (resultSetPointer != 0l) { + if (resultSetPointer != TSDBConstants.JNI_NULL_POINTER) { resSet = new TSDBResultSet(connecter, resultSetPointer); } return resSet; } public int getUpdateCount() throws SQLException { + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } return this.connecter.getAffectedRows(); } @@ -171,6 +218,9 @@ public class TSDBStatement implements Statement { } public int[] executeBatch() throws SQLException { + if (isClosed) { + throw new SQLException("Invalid method call on a closed statement."); + } if (batchedArgs == null) { throw new SQLException(TSDBConstants.WrapErrMsg("Batch is empty!")); } else { @@ -223,7 +273,7 @@ public class TSDBStatement implements Statement { } public boolean isClosed() throws SQLException { - throw new SQLException(TSDBConstants.UNSUPPORT_METHOD_EXCEPTIONZ_MSG); + return isClosed; } public void setPoolable(boolean poolable) throws SQLException { diff --git a/tests/examples/JDBC/JDBCDemo/pom.xml b/tests/examples/JDBC/JDBCDemo/pom.xml index 1c62379af9..d015c62772 100644 --- a/tests/examples/JDBC/JDBCDemo/pom.xml +++ b/tests/examples/JDBC/JDBCDemo/pom.xml @@ -63,7 +63,7 @@ com.taosdata.jdbc taos-jdbcdriver - 1.0.0 + 1.0.1 -- GitLab