Skip to content

Commit d36814b

Browse files
committed
jdbc: support for sub-set of JDBC escape syntax
Add a driver SQL pre-processing before sending it to the server. The driver supports sub-set of scalar functions defined by the spec (appendix C), outer joins, escape clause for SQL LIKE operator, and limit/offset clause. The processed result can be received using Connection.nativeSQL() method. Closes #79 Closes #76 Closes #81 Closes #83 Closes #84 Affects: #108
1 parent 2c4baed commit d36814b

13 files changed

+1585
-13
lines changed

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

+416
Large diffs are not rendered by default.

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

+444
Large diffs are not rendered by default.

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,15 @@ public class SQLConnection implements TarantoolConnection {
6363
private DatabaseMetaData cachedMetadata;
6464
private int resultSetHoldability = UNSET_HOLDABILITY;
6565

66+
private final EscapeSyntaxParser escapeSyntaxParser;
67+
6668
public SQLConnection(String url, Properties properties) throws SQLException {
6769
this.url = url;
6870
this.properties = properties;
6971

7072
try {
7173
client = makeSqlClient(makeAddress(properties), makeConfigFromProperties(properties));
74+
escapeSyntaxParser = new EscapeSyntaxParser(this);
7275
} catch (Exception e) {
7376
throw new SQLException("Couldn't initiate connection using " + SQLDriver.diagProperties(properties), e);
7477
}
@@ -189,7 +192,7 @@ public CallableStatement prepareCall(String sql,
189192
@Override
190193
public String nativeSQL(String sql) throws SQLException {
191194
checkNotClosed();
192-
throw new SQLFeatureNotSupportedException();
195+
return escapeSyntaxParser.translate(sql, true);
193196
}
194197

195198
@Override

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.tarantool.Version;
77
import org.tarantool.jdbc.type.TarantoolSqlType;
88
import org.tarantool.util.ServerVersion;
9+
import org.tarantool.util.StringUtils;
910
import org.tarantool.util.TupleTwo;
1011

1112
import java.sql.Connection;
@@ -179,17 +180,17 @@ public String getSQLKeywords() throws SQLException {
179180

180181
@Override
181182
public String getNumericFunctions() throws SQLException {
182-
return "";
183+
return StringUtils.toCsvList(EscapedFunctions.NumericFunction.values());
183184
}
184185

185186
@Override
186187
public String getStringFunctions() throws SQLException {
187-
return "";
188+
return StringUtils.toCsvList(EscapedFunctions.StringFunction.values());
188189
}
189190

190191
@Override
191192
public String getSystemFunctions() throws SQLException {
192-
return "";
193+
return StringUtils.toCsvList(EscapedFunctions.SystemFunction.values());
193194
}
194195

195196
@Override
@@ -274,7 +275,7 @@ public boolean supportsGroupByBeyondSelect() throws SQLException {
274275

275276
@Override
276277
public boolean supportsLikeEscapeClause() throws SQLException {
277-
return false;
278+
return true;
278279
}
279280

280281
@Override

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class SQLPreparedStatement extends SQLStatement implements PreparedStatem
4343

4444
public SQLPreparedStatement(SQLConnection connection, String sql, int autoGeneratedKeys) throws SQLException {
4545
super(connection);
46-
this.sql = sql;
46+
this.sql = translateQuery(sql);
4747
this.parameters = new HashMap<>();
4848
this.autoGeneratedKeys = autoGeneratedKeys;
4949
setPoolable(true);
@@ -55,7 +55,7 @@ public SQLPreparedStatement(SQLConnection connection,
5555
int resultSetConcurrency,
5656
int resultSetHoldability) throws SQLException {
5757
super(connection, resultSetType, resultSetConcurrency, resultSetHoldability);
58-
this.sql = sql;
58+
this.sql = translateQuery(sql);
5959
this.parameters = new HashMap<>();
6060
this.autoGeneratedKeys = NO_GENERATED_KEYS;
6161
setPoolable(true);

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

+10-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class SQLStatement implements TarantoolStatement {
4545
private List<String> batchQueries = new ArrayList<>();
4646

4747
private boolean isCloseOnCompletion;
48+
private boolean useEscapeProcessing = true;
4849

4950
private final int resultSetType;
5051
private final int resultSetConcurrency;
@@ -91,7 +92,7 @@ protected SQLStatement(SQLConnection sqlConnection,
9192
@Override
9293
public ResultSet executeQuery(String sql) throws SQLException {
9394
checkNotClosed();
94-
if (!executeInternal(NO_GENERATED_KEYS, sql)) {
95+
if (!executeInternal(NO_GENERATED_KEYS, translateQuery(sql))) {
9596
throw new SQLException("No results were returned", SQLStates.NO_DATA.getSqlState());
9697
}
9798
return resultSet;
@@ -106,7 +107,7 @@ public int executeUpdate(String sql) throws SQLException {
106107
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
107108
checkNotClosed();
108109
JdbcConstants.checkGeneratedKeysConstant(autoGeneratedKeys);
109-
if (executeInternal(autoGeneratedKeys, sql)) {
110+
if (executeInternal(autoGeneratedKeys, translateQuery(sql))) {
110111
throw new SQLException(
111112
"Result was returned but nothing was expected",
112113
SQLStates.TOO_MANY_RESULTS.getSqlState()
@@ -166,7 +167,8 @@ public void setMaxRows(int maxRows) throws SQLException {
166167

167168
@Override
168169
public void setEscapeProcessing(boolean enable) throws SQLException {
169-
throw new SQLFeatureNotSupportedException();
170+
checkNotClosed();
171+
useEscapeProcessing = enable;
170172
}
171173

172174
@Override
@@ -208,7 +210,7 @@ public void setCursorName(String name) throws SQLException {
208210
@Override
209211
public boolean execute(String sql) throws SQLException {
210212
checkNotClosed();
211-
return executeInternal(NO_GENERATED_KEYS, sql);
213+
return executeInternal(NO_GENERATED_KEYS, translateQuery(sql));
212214
}
213215

214216
@Override
@@ -511,4 +513,8 @@ protected SQLResultSet executeGeneratedKeys(List<Integer> generatedKeys) throws
511513
return createResultSet(SQLResultHolder.ofQuery(Collections.singletonList(sqlMetaData), rows));
512514
}
513515

516+
protected String translateQuery(String sql) throws SQLException {
517+
return useEscapeProcessing ? connection.nativeSQL(sql) : sql;
518+
}
519+
514520
}

Diff for: src/main/java/org/tarantool/util/SQLStates.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ public enum SQLStates {
77
CONNECTION_DOES_NOT_EXIST("08003"),
88
INVALID_PARAMETER_VALUE("22023"),
99
INVALID_CURSOR_STATE("24000"),
10-
INVALID_TRANSACTION_STATE("25000");
10+
INVALID_TRANSACTION_STATE("25000"),
11+
SYNTAX_ERROR("42000");
1112

1213
private final String sqlState;
1314

Diff for: src/main/java/org/tarantool/util/StringUtils.java

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package org.tarantool.util;
22

3+
import java.util.stream.Collectors;
4+
import java.util.stream.Stream;
5+
36
public class StringUtils {
47

58
public static boolean isEmpty(String string) {
@@ -18,4 +21,10 @@ public static boolean isNotBlank(String string) {
1821
return !isBlank(string);
1922
}
2023

24+
public static String toCsvList(Enum<?>[] values) {
25+
return Stream.of(values)
26+
.map(Enum::name)
27+
.collect(Collectors.joining(","));
28+
}
29+
2130
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.tarantool.util;
2+
3+
/**
4+
* Represents a function that accepts two arguments and
5+
* produces a result or throws an exception.
6+
*
7+
* @param <T> type of the first argument to the function
8+
* @param <U> type of the second argument to the function
9+
* @param <R> type of the result of the function
10+
* @param <E> type of the exception in case of error
11+
*/
12+
@FunctionalInterface
13+
public interface ThrowingBiFunction<T, U, R, E extends Exception> {
14+
15+
/**
16+
* Applies this function to the given arguments.
17+
*
18+
* @param argument1 first argument
19+
* @param argument2 second argument
20+
*
21+
* @return function result
22+
*
23+
* @throws E if any error occurs
24+
*/
25+
R apply(T argument1, U argument2) throws E;
26+
27+
}

0 commit comments

Comments
 (0)