Skip to content

Commit fb7a228

Browse files
committed
Support Statement.closeOnCompletion.
Check a statement after a dependent result set is closed. Extract TarantoolStatement as tarantool specific extension interface to be used for internal purposes as well as JDBC incompatible vendor API. Closes: #180
1 parent 494292b commit fb7a228

File tree

6 files changed

+104
-24
lines changed

6 files changed

+104
-24
lines changed

Diff for: src/main/java/org/tarantool/jdbc/SQLDatabaseMetadata.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,8 @@ private SQLNullResultSet sqlNullResultSet(List<String> columnNames, List<List<Ob
11261126
return new SQLNullResultSet(SQLResultHolder.ofQuery(meta, rows), createMetadataStatement());
11271127
}
11281128

1129-
private SQLStatement createMetadataStatement() throws SQLException {
1130-
return connection.createStatement().unwrap(SQLStatement.class);
1129+
private TarantoolStatement createMetadataStatement() throws SQLException {
1130+
return connection.createStatement().unwrap(TarantoolStatement.class);
11311131
}
11321132

11331133
private static <T> T ensureType(Class<T> cls, Object v) throws Exception {
@@ -1152,7 +1152,7 @@ private SQLNullResultSet emptyResultSet(List<String> colNames) throws SQLExcepti
11521152

11531153
protected class SQLNullResultSet extends SQLResultSet {
11541154

1155-
public SQLNullResultSet(SQLResultHolder holder, SQLStatement ownerStatement) throws SQLException {
1155+
public SQLNullResultSet(SQLResultHolder holder, TarantoolStatement ownerStatement) throws SQLException {
11561156
super(holder, ownerStatement);
11571157
}
11581158

Diff for: src/main/java/org/tarantool/jdbc/SQLResultSet.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838

3939
public class SQLResultSet implements ResultSet {
4040

41-
private final CursorIterator<List<Object>> iterator;
42-
private final SQLResultSetMetaData metaData;
41+
private CursorIterator<List<Object>> iterator;
42+
private SQLResultSetMetaData metaData;
4343

4444
private Map<String, Integer> columnByNameLookups;
4545

46-
private final Statement statement;
46+
private final TarantoolStatement statement;
4747
private final int maxRows;
4848

4949
private AtomicBoolean isClosed = new AtomicBoolean(false);
@@ -52,7 +52,7 @@ public class SQLResultSet implements ResultSet {
5252
private final int concurrencyLevel;
5353
private final int holdability;
5454

55-
public SQLResultSet(SQLResultHolder holder, SQLStatement ownerStatement) throws SQLException {
55+
public SQLResultSet(SQLResultHolder holder, TarantoolStatement ownerStatement) throws SQLException {
5656
metaData = new SQLResultSetMetaData(holder.getSqlMetadata());
5757
statement = ownerStatement;
5858
scrollType = statement.getResultSetType();
@@ -89,7 +89,13 @@ public List<Object> getCurrentRow() throws SQLException {
8989
@Override
9090
public void close() throws SQLException {
9191
if (isClosed.compareAndSet(false, true)) {
92-
iterator.close();
92+
try {
93+
iterator.close();
94+
iterator = null;
95+
metaData = null;
96+
} finally {
97+
statement.checkCompletion();
98+
}
9399
}
94100
}
95101

@@ -370,11 +376,13 @@ public String getCursorName() throws SQLException {
370376

371377
@Override
372378
public ResultSetMetaData getMetaData() throws SQLException {
379+
checkNotClosed();
373380
return metaData;
374381
}
375382

376383
@Override
377384
public int findColumn(String columnLabel) throws SQLException {
385+
checkNotClosed();
378386
return findColumnIndex(columnLabel);
379387
}
380388

@@ -1099,7 +1107,7 @@ public <T> T unwrap(Class<T> type) throws SQLException {
10991107
if (isWrapperFor(type)) {
11001108
return type.cast(this);
11011109
}
1102-
throw new SQLNonTransientException("ResultSet does not wrap " + type.getName());
1110+
throw new SQLNonTransientException("SQLResultSet does not wrap " + type.getName());
11031111
}
11041112

11051113
@Override

Diff for: src/main/java/org/tarantool/jdbc/SQLStatement.java

+19-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* types of cursors.
2323
* Supports only {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} holdability type.
2424
*/
25-
public class SQLStatement implements Statement {
25+
public class SQLStatement implements TarantoolStatement {
2626

2727
protected final SQLConnection connection;
2828

@@ -32,6 +32,8 @@ public class SQLStatement implements Statement {
3232
protected SQLResultSet resultSet;
3333
protected int updateCount;
3434

35+
private boolean isCloseOnCompletion;
36+
3537
private final int resultSetType;
3638
private final int resultSetConcurrency;
3739
private final int resultSetHoldability;
@@ -313,21 +315,33 @@ public boolean isPoolable() throws SQLException {
313315

314316
@Override
315317
public void closeOnCompletion() throws SQLException {
316-
318+
checkNotClosed();
319+
isCloseOnCompletion = true;
317320
}
318321

319322
@Override
320323
public boolean isCloseOnCompletion() throws SQLException {
321324
checkNotClosed();
322-
return false;
325+
return isCloseOnCompletion;
326+
}
327+
328+
@Override
329+
public void checkCompletion() throws SQLException {
330+
if (!isCloseOnCompletion) {
331+
return;
332+
}
333+
if (resultSet != null && !resultSet.isClosed()) {
334+
return;
335+
}
336+
close();
323337
}
324338

325339
@Override
326340
public <T> T unwrap(Class<T> type) throws SQLException {
327341
if (isWrapperFor(type)) {
328342
return type.cast(this);
329343
}
330-
throw new SQLNonTransientException("Statement does not wrap " + type.getName());
344+
throw new SQLNonTransientException("SQLStatement does not wrap " + type.getName());
331345
}
332346

333347
@Override
@@ -376,16 +390,7 @@ protected boolean executeInternal(String sql, Object... params) throws SQLExcept
376390
return holder.isQueryResult();
377391
}
378392

379-
/**
380-
* Returns {@link ResultSet} which will be initialized by <code>data</code>.
381-
*
382-
* @param data predefined result to be wrapped by {@link ResultSet}
383-
*
384-
* @return wrapped result
385-
*
386-
* @throws SQLException if a database access error occurs or
387-
* this method is called on a closed <code>Statement</code>
388-
*/
393+
@Override
389394
public ResultSet executeMetadata(SQLResultHolder data) throws SQLException {
390395
checkNotClosed();
391396
return createResultSet(data);
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.tarantool.jdbc;
2+
3+
import java.sql.ResultSet;
4+
import java.sql.SQLException;
5+
import java.sql.Statement;
6+
7+
/**
8+
* Tarantool specific statement extensions
9+
*/
10+
public interface TarantoolStatement extends Statement {
11+
12+
/**
13+
* Checks for statement completion and closes itself,
14+
* according to {@link Statement#closeOnCompletion()}
15+
*/
16+
void checkCompletion() throws SQLException;
17+
18+
/**
19+
* Returns {@link ResultSet} which will be initialized by <code>data</code>.
20+
*
21+
* @param data predefined result to be wrapped by {@link ResultSet}
22+
*
23+
* @return wrapped result
24+
*
25+
* @throws SQLException if a database access error occurs or
26+
* this method is called on a closed <code>Statement</code>
27+
*/
28+
ResultSet executeMetadata(SQLResultHolder data) throws SQLException;
29+
30+
}

Diff for: src/test/java/org/tarantool/jdbc/JdbcResultSetIT.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,12 @@ public void testResultSetMetadataAfterClose() throws SQLException {
167167
assertNotNull(resultSet);
168168
ResultSetMetaData metaData = resultSet.getMetaData();
169169
assertNotNull(metaData);
170+
171+
int expectedColumnSize = 2;
172+
assertEquals(expectedColumnSize, metaData.getColumnCount());
173+
170174
resultSet.close();
171-
assertEquals(metaData, resultSet.getMetaData());
175+
assertEquals(expectedColumnSize, metaData.getColumnCount());
172176
}
173177

174178
@Test

Diff for: src/test/java/org/tarantool/jdbc/JdbcStatementIT.java

+33
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,14 @@ public void execute() throws Throwable {
157157

158158
@Test
159159
public void testUnwrap() throws SQLException {
160+
assertEquals(stmt, stmt.unwrap(TarantoolStatement.class));
160161
assertEquals(stmt, stmt.unwrap(SQLStatement.class));
161162
assertThrows(SQLException.class, () -> stmt.unwrap(Integer.class));
162163
}
163164

164165
@Test
165166
public void testIsWrapperFor() throws SQLException {
167+
assertTrue(stmt.isWrapperFor(TarantoolStatement.class));
166168
assertTrue(stmt.isWrapperFor(SQLStatement.class));
167169
assertFalse(stmt.isWrapperFor(Integer.class));
168170
}
@@ -246,4 +248,35 @@ void testStatementConnection() throws SQLException {
246248
Statement statement = conn.createStatement();
247249
assertEquals(conn, statement.getConnection());
248250
}
251+
252+
@Test
253+
void testCloseOnCompletion() throws SQLException {
254+
assertFalse(stmt.isCloseOnCompletion());
255+
stmt.closeOnCompletion();
256+
assertTrue(stmt.isCloseOnCompletion());
257+
}
258+
259+
@Test
260+
void testCloseOnCompletionDisabled() throws SQLException {
261+
ResultSet resultSet = stmt.executeQuery("SELECT val FROM test WHERE id=1");
262+
assertFalse(stmt.isClosed());
263+
assertFalse(resultSet.isClosed());
264+
265+
resultSet.close();
266+
assertTrue(resultSet.isClosed());
267+
assertFalse(stmt.isClosed());
268+
}
269+
270+
@Test
271+
void testCloseOnCompletionEnabled() throws SQLException {
272+
stmt.closeOnCompletion();
273+
ResultSet resultSet = stmt.executeQuery("SELECT val FROM test WHERE id=1");
274+
assertFalse(stmt.isClosed());
275+
assertFalse(resultSet.isClosed());
276+
277+
resultSet.close();
278+
assertTrue(resultSet.isClosed());
279+
assertTrue(stmt.isClosed());
280+
}
281+
249282
}

0 commit comments

Comments
 (0)