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 supports the prepared
statements then each PreparedStatement object acts as a corresponding
server prepared statement in terms of its behaviour (including
expiration or invalidation of statements - i.e. after DDL 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 that works in two different
modes now: legacy mode when server 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 supported (each
PreparedStatement covers the server prepared statement and sends
statement id + parameters).

There are a few issues on 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() method is called. It causes the second 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 it on the server side.
The third, the prepared statement is invalidated by DDL queries or
the disconnection. Tarantool does not support auto re-preparing after
DDL operation at this moment, so it requires to be re-prepared for all
cached statements. Here, the PreparedStatement repeats behaviour of
Lua implementation for `box` module - returns an error when it
expired or deleted.

Closes: #198
  • Loading branch information
nicktorwald committed Jan 20, 2020
1 parent 02bf9ad commit 5b6524e
Show file tree
Hide file tree
Showing 12 changed files with 732 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 5b6524e

Please sign in to comment.