Skip to content

Commit

Permalink
jdbc: support server prepared statements
Browse files Browse the repository at this point in the history
Tarantool supports prepared statements since 2.3.1 that can be used
by java.sql.PreparedStatement to prepare the underlying query in
advance. If the driver connects to Tarantool which support prepared the
statements each PreparedStatement object acts as a corresponding server
prepared statement in terms of its behaviour (including expiration or
invalidation of statements - i.e. after DML operations).
It also makes possible to obtain statement meta data via getMetaData
and getParameterMetaData without having to execute the query.

This commit extends TarantoolConnection API by new `prepare` and
`deallocate` methods that allow to deal with server prepared statements.
It caused a small reworking of a query execution process in
SQLConnection where QueryCommand abstraction was introduced. Another
extension is support of PreparedStatement works in two different modes:
legacy mode when prepared statements are not available (driver will send
sql text + parameters as a separate queries when each execution is
performed) and new mode when they are (each PreparedStatement covers
the server prepared statement and sends statement id + parameters).

There are a few issues when using the prepared statement now.
The first, it is required to deallocate prepared statements explicitly,
(no an eviction strategy on the server side) so PreparedStatement tries
to perform it when close() is called. It causes next issue.
The second, Tarantool does not distinguish query duplicates within one
session that can cause unexpected user experience. Let's say there are
two PreparedStatements that were prepared using the same query string.
If one of them closes it makes another statement broken because of they
reused the same session prepared statement. To overcome this issue the
driver connection tracks its own statements references. When the
particular statement reference count reaches zero it will safely
unprepared on the server side.
The third, the prepared statement is invalidated by DDL queries or
the disconnection. Here, the PreparedStatement repeats behaviour of
structure implemented in LUA (box.prepare()) - return an error when it
runs. Tarantool does not support auto re-preparing after DDL operation
at this moment.

Closes: #198
  • Loading branch information
nicktorwald committed Jan 19, 2020
1 parent 02bf9ad commit 54ba30e
Show file tree
Hide file tree
Showing 12 changed files with 713 additions and 111 deletions.
15 changes: 14 additions & 1 deletion src/main/java/org/tarantool/SqlProtoUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,17 @@ public static List<List<Object>> getSQLData(TarantoolPacket pack) {
return (List<List<Object>>) pack.getBody().get(Key.DATA.getId());
}

public static List<SQLMetaData> getSQLBindMetadata(TarantoolPacket pack) {
return getMetadata(pack, Key.SQL_BIND_METADATA);
}

public static List<SQLMetaData> getSQLMetadata(TarantoolPacket pack) {
List<Map<Integer, Object>> meta = (List<Map<Integer, Object>>) pack.getBody().get(Key.SQL_METADATA.getId());
return getMetadata(pack, Key.SQL_METADATA);
}

private static List<SQLMetaData> getMetadata(TarantoolPacket pack, Key targetKey) {
List<Map<Integer, Object>> meta = (List<Map<Integer, Object>>) pack.getBody()
.getOrDefault(targetKey.getId(), Collections.emptyList());
List<SQLMetaData> values = new ArrayList<>(meta.size());
for (Map<Integer, Object> item : meta) {
values.add(new SQLMetaData(
Expand All @@ -42,6 +51,10 @@ public static List<SQLMetaData> getSQLMetadata(TarantoolPacket pack) {
return values;
}

public static Long getStatementId(TarantoolPacket pack) {
return ((Number) pack.getBody().get(Key.SQL_STATEMENT_ID.getId())).longValue();
}

public static Long getSQLRowCount(TarantoolPacket pack) {
Map<Key, Object> info = (Map<Key, Object>) pack.getBody().get(Key.SQL_INFO.getId());
Number rowCount;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/tarantool/TarantoolClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ public TarantoolClientOps<Integer, List<?>, Object, TupleTwo<List<?>, Long>> uns
return unsafeSchemaOps;
}

protected TarantoolRequest makeSqlRequest(String sql, List<Object> bind) {
private TarantoolRequest makeSqlRequest(String sql, List<Object> bind) {
return new TarantoolRequest(
Code.EXECUTE,
TarantoolRequestArgumentFactory.value(Key.SQL_TEXT),
Expand Down
Loading

0 comments on commit 54ba30e

Please sign in to comment.