diff --git a/jdbc-shaded/pom.xml b/jdbc-shaded/pom.xml
index b2b3b58..41c33ca 100644
--- a/jdbc-shaded/pom.xml
+++ b/jdbc-shaded/pom.xml
@@ -6,7 +6,7 @@
tech.ydb.jdbc
ydb-jdbc-driver-parent
- 2.0.3
+ 2.0.4
ydb-jdbc-driver-shaded
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
index 009e3ae..9764992 100644
--- a/jdbc/pom.xml
+++ b/jdbc/pom.xml
@@ -6,7 +6,7 @@
tech.ydb.jdbc
ydb-jdbc-driver-parent
- 2.0.3
+ 2.0.4
ydb-jdbc-driver
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/YdbDriver.java b/jdbc/src/main/java/tech/ydb/jdbc/YdbDriver.java
index 55ce441..27c14ff 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/YdbDriver.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/YdbDriver.java
@@ -58,7 +58,7 @@ public YdbConnection connect(String url, Properties info) throws SQLException {
return new YdbConnectionImpl(getCachedContext(config));
}
- // create new context
+ // findOrCreateJdbcParams new context
final YdbContext context = YdbContext.createContext(config);
return new YdbConnectionImpl(context) {
@Override
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java b/jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java
index 206127f..3a3b152 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java
@@ -22,7 +22,6 @@
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
-import tech.ydb.jdbc.exception.YdbExecutionException;
import tech.ydb.table.values.DecimalType;
import tech.ydb.table.values.DecimalValue;
import tech.ydb.table.values.ListType;
@@ -461,7 +460,7 @@ static CharStream fromReader(Reader reader, long length) {
return CharStreams.toString(reader);
}
} catch (IOException e) {
- throw new YdbExecutionException(CANNOT_LOAD_DATA_FROM_READER + e.getMessage(), e);
+ throw new RuntimeException(CANNOT_LOAD_DATA_FROM_READER + e.getMessage(), e);
}
};
}
@@ -480,7 +479,7 @@ static ByteStream fromInputStream(InputStream stream, long length) {
return ByteStreams.toByteArray(stream);
}
} catch (IOException e) {
- throw new YdbExecutionException(CANNOT_LOAD_DATA_FROM_IS + e.getMessage(), e);
+ throw new RuntimeException(CANNOT_LOAD_DATA_FROM_IS + e.getMessage(), e);
}
};
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/context/YdbContext.java b/jdbc/src/main/java/tech/ydb/jdbc/context/YdbContext.java
index cf4f56a..ed7a07c 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/context/YdbContext.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/context/YdbContext.java
@@ -1,16 +1,34 @@
package tech.ydb.jdbc.context;
+import java.sql.SQLDataException;
import java.sql.SQLException;
+import java.time.Duration;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import tech.ydb.core.Result;
+import tech.ydb.core.UnexpectedResultException;
import tech.ydb.core.grpc.GrpcTransport;
import tech.ydb.core.grpc.GrpcTransportBuilder;
-import tech.ydb.jdbc.exception.YdbConfigurationException;
+import tech.ydb.jdbc.YdbConst;
+import tech.ydb.jdbc.YdbPrepareMode;
+import tech.ydb.jdbc.exception.ExceptionFactory;
+import tech.ydb.jdbc.query.JdbcParams;
+import tech.ydb.jdbc.query.JdbcQueryLexer;
+import tech.ydb.jdbc.query.YdbQuery;
+import tech.ydb.jdbc.query.YdbQueryBuilder;
import tech.ydb.jdbc.query.YdbQueryOptions;
+import tech.ydb.jdbc.query.params.BatchedParams;
+import tech.ydb.jdbc.query.params.InMemoryParams;
+import tech.ydb.jdbc.query.params.PreparedParams;
import tech.ydb.jdbc.settings.ParsedProperty;
import tech.ydb.jdbc.settings.YdbClientProperties;
import tech.ydb.jdbc.settings.YdbClientProperty;
@@ -18,9 +36,15 @@
import tech.ydb.jdbc.settings.YdbConnectionProperty;
import tech.ydb.jdbc.settings.YdbOperationProperties;
import tech.ydb.scheme.SchemeClient;
+import tech.ydb.table.SessionRetryContext;
import tech.ydb.table.TableClient;
+import tech.ydb.table.description.TableDescription;
import tech.ydb.table.impl.PooledTableClient;
import tech.ydb.table.rpc.grpc.GrpcTableRpc;
+import tech.ydb.table.settings.DescribeTableSettings;
+import tech.ydb.table.settings.PrepareDataQuerySettings;
+import tech.ydb.table.settings.RequestSettings;
+import tech.ydb.table.values.Type;
/**
*
@@ -41,6 +65,10 @@ public class YdbContext implements AutoCloseable {
private final PooledTableClient tableClient;
private final SchemeClient schemeClient;
private final YdbQueryOptions queryOptions;
+ private final SessionRetryContext retryCtx;
+
+ private final Cache queriesCache;
+ private final Cache> queryParamsCache;
private final boolean autoResizeSessionPool;
private final AtomicInteger connectionsCount = new AtomicInteger();
@@ -52,8 +80,20 @@ private YdbContext(YdbConfig config, GrpcTransport transport, PooledTableClient
this.schemeClient = SchemeClient.newClient(transport).build();
this.queryOptions = YdbQueryOptions.createFrom(config.getOperationProperties());
this.autoResizeSessionPool = autoResize;
+ this.retryCtx = SessionRetryContext.create(tableClient).build();
+
+ int cacheSize = config.getOperationProperties().getPreparedStatementCacheSize();
+ if (cacheSize > 0) {
+ queriesCache = CacheBuilder.newBuilder().maximumSize(cacheSize).build();
+ queryParamsCache = CacheBuilder.newBuilder().maximumSize(cacheSize).build();
+ } else {
+ queriesCache = null;
+ queryParamsCache = null;
+ }
}
+
+
public String getDatabase() {
return grpcTransport.getDatabase();
}
@@ -70,10 +110,6 @@ public String getUrl() {
return config.getUrl();
}
- public YdbQueryOptions getQueryOptions() {
- return queryOptions;
- }
-
public int getConnectionsCount() {
return connectionsCount.get();
}
@@ -131,8 +167,8 @@ public static YdbContext createContext(YdbConfig config) throws SQLException {
boolean autoResize = buildTableClient(tableClient, clientProps);
return new YdbContext(config, grpcTransport, tableClient.build(), autoResize);
- } catch (Exception ex) {
- throw new YdbConfigurationException("Cannot connect to YDB: " + ex.getMessage(), ex);
+ } catch (RuntimeException ex) {
+ throw new SQLException("Cannot connect to YDB: " + ex.getMessage(), ex);
}
}
@@ -148,6 +184,17 @@ public static GrpcTransport buildGrpcTransport(YdbConnectionProperties props) {
builder = builder.withAuthProvider(props.getStaticCredentials());
}
+ // Use custom single thread scheduler because JDBC driver doesn't need to execute retries except for DISCOERY
+ builder.withSchedulerFactory(() -> {
+ final String namePrefix = "ydb-jdbc-scheduler[" + props.hashCode() +"]-thread-";
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ return Executors.newScheduledThreadPool(1, (Runnable r) -> {
+ Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ });
+ });
+
return builder.build();
}
@@ -179,4 +226,73 @@ private static boolean buildTableClient(TableClient.Builder builder, YdbClientPr
builder.sessionPoolSize(minSize, maxSize);
return false;
}
+
+ public > T withDefaultTimeout(T settings) {
+ Duration operation = config.getOperationProperties().getDeadlineTimeout();
+ if (!operation.isZero() && !operation.isNegative()) {
+ settings.setOperationTimeout(operation);
+ settings.setTimeout(operation.plusSeconds(1));
+ }
+ return settings;
+ }
+
+ public CompletableFuture> describeTable(String tablePath, DescribeTableSettings settings) {
+ return retryCtx.supplyResult(session -> session.describeTable(tablePath, settings));
+ }
+
+ public YdbQuery parseYdbQuery(String sql) throws SQLException {
+ YdbQueryBuilder builder = new YdbQueryBuilder(sql, queryOptions.getForcedQueryType());
+ JdbcQueryLexer.buildQuery(builder, queryOptions);
+ return builder.build(queryOptions);
+ }
+
+ public YdbQuery findOrParseYdbQuery(String sql) throws SQLException {
+ if (queriesCache == null) {
+ return parseYdbQuery(sql);
+ }
+
+ YdbQuery cached = queriesCache.getIfPresent(sql);
+ if (cached == null) {
+ cached = parseYdbQuery(sql);
+ queriesCache.put(sql, cached);
+ }
+
+ return cached;
+ }
+
+ public JdbcParams findOrCreateJdbcParams(YdbQuery query, YdbPrepareMode mode) throws SQLException {
+ if (query.hasIndexesParameters()
+ || mode == YdbPrepareMode.IN_MEMORY
+ || !queryOptions.iPrepareDataQueries()) {
+ return new InMemoryParams(query.getIndexesParameters());
+ }
+
+ String yql = query.getYqlQuery(null);
+ PrepareDataQuerySettings settings = withDefaultTimeout(new PrepareDataQuerySettings());
+ try {
+ Map types = queryParamsCache.getIfPresent(query.originSQL());
+ if (types == null) {
+ types = retryCtx.supplyResult(session -> session.prepareDataQuery(yql, settings))
+ .join()
+ .getValue()
+ .types();
+ queryParamsCache.put(query.originSQL(), types);
+ }
+
+ boolean requireBatch = mode == YdbPrepareMode.DATA_QUERY_BATCH;
+ if (requireBatch || (mode == YdbPrepareMode.AUTO && queryOptions.isDetectBatchQueries())) {
+ BatchedParams params = BatchedParams.tryCreateBatched(types);
+ if (params != null) {
+ return params;
+ }
+
+ if (requireBatch) {
+ throw new SQLDataException(YdbConst.STATEMENT_IS_NOT_A_BATCH + query.originSQL());
+ }
+ }
+ return new PreparedParams(types);
+ } catch (UnexpectedResultException ex) {
+ throw ExceptionFactory.createException("Cannot prepare data query: " + ex.getMessage(), ex);
+ }
+ }
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java b/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java
index d0784ba..3d27988 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java
@@ -16,8 +16,8 @@
import tech.ydb.core.Issue;
import tech.ydb.core.Result;
import tech.ydb.core.Status;
-import tech.ydb.jdbc.exception.YdbExecutionException;
-import tech.ydb.jdbc.exception.YdbStatusException;
+import tech.ydb.core.UnexpectedResultException;
+import tech.ydb.jdbc.exception.ExceptionFactory;
import tech.ydb.table.Session;
/**
@@ -62,7 +62,7 @@ public Session createSession(YdbContext ctx) throws SQLException {
public void execute(String msg, Supplier> runnableSupplier) throws SQLException {
if (!isDebug) {
- simpleExecute(runnableSupplier);
+ simpleExecute(msg, runnableSupplier);
return;
}
@@ -70,7 +70,7 @@ public void execute(String msg, Supplier> runnableSupp
Stopwatch sw = Stopwatch.createStarted();
try {
- simpleExecute(runnableSupplier);
+ simpleExecute(msg, runnableSupplier);
logger.log(Level.FINEST, "[{0}] OK ", sw.stop());
} catch (SQLException | RuntimeException ex) {
logger.log(Level.FINE, "[{0}] {1} ", new Object[] { sw.stop(), ex.getMessage() });
@@ -80,14 +80,14 @@ public void execute(String msg, Supplier> runnableSupp
public T call(String msg, Supplier>> callSupplier) throws SQLException {
if (!isDebug) {
- return simpleCall(callSupplier);
+ return simpleCall(msg, callSupplier);
}
logger.finest(msg);
Stopwatch sw = Stopwatch.createStarted();
try {
- T value = simpleCall(callSupplier);
+ T value = simpleCall(msg, callSupplier);
logger.log(Level.FINEST, "[{0}] OK ", sw.stop());
return value;
} catch (SQLException | RuntimeException ex) {
@@ -96,29 +96,22 @@ public T call(String msg, Supplier>> callSupplie
}
}
- private T simpleCall(Supplier>> supplier) throws SQLException {
+ private T simpleCall(String msg, Supplier>> supplier) throws SQLException {
try {
Result result = supplier.get().join();
- validate(result.getStatus().toString(), result.getStatus());
+ issues.addAll(Arrays.asList(result.getStatus().getIssues()));
return result.getValue();
- } catch (RuntimeException ex) {
- throw new YdbExecutionException(ex.getMessage(), ex);
+ } catch (UnexpectedResultException ex) {
+ throw ExceptionFactory.createException("Cannot call '" + msg + "' with " + ex.getStatus(), ex);
}
}
- private void simpleExecute(Supplier> supplier) throws SQLException {
- try {
- Status status = supplier.get().join();
- validate(status.toString(), status);
- } catch (RuntimeException ex) {
- throw new YdbExecutionException(ex.getMessage(), ex);
- }
- }
-
- private void validate(String message, Status status) throws SQLException {
+ private void simpleExecute(String msg, Supplier> supplier) throws SQLException {
+ Status status = supplier.get().join();
issues.addAll(Arrays.asList(status.getIssues()));
if (!status.isSuccess()) {
- throw YdbStatusException.newException(message, status);
+ throw ExceptionFactory.createException("Cannot execute '" + msg + "' with " + status,
+ new UnexpectedResultException("Unexpected status", status));
}
}
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/ExceptionFactory.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/ExceptionFactory.java
new file mode 100644
index 0000000..0d1ed73
--- /dev/null
+++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/ExceptionFactory.java
@@ -0,0 +1,36 @@
+package tech.ydb.jdbc.exception;
+
+import java.sql.SQLException;
+
+import tech.ydb.core.StatusCode;
+import tech.ydb.core.UnexpectedResultException;
+
+/**
+ *
+ * @author Aleksandr Gorshenin
+ */
+public class ExceptionFactory {
+ static String getSQLState(StatusCode status) {
+ // TODO: Add SQLSTATE message with order with https://en.wikipedia.org/wiki/SQLSTATE
+ return null;
+ }
+
+ static int getVendorCode(StatusCode code) {
+ return code.getCode();
+ }
+
+ public static SQLException createException(String message, UnexpectedResultException cause) {
+ StatusCode code = cause.getStatus().getCode();
+ String sqlState = getSQLState(code);
+ int vendorCode = getVendorCode(code);
+
+ if (code.isRetryable(false)) {
+ return new YdbRetryableException(message, sqlState, vendorCode, cause);
+ }
+ if (code.isRetryable(true)) {
+ return new YdbConditionallyRetryableException(message, sqlState, vendorCode, cause);
+ }
+
+ return new YdbSQLException(message, sqlState, vendorCode, cause);
+ }
+}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConditionallyRetryableException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConditionallyRetryableException.java
index 599e60d..2a45d0a 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConditionallyRetryableException.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConditionallyRetryableException.java
@@ -1,12 +1,20 @@
package tech.ydb.jdbc.exception;
+import java.sql.SQLTransientException;
+
import tech.ydb.core.Status;
+import tech.ydb.core.UnexpectedResultException;
+
+public class YdbConditionallyRetryableException extends SQLTransientException {
+ private static final long serialVersionUID = 2155728765762467203L;
+ private final Status status;
-// Treat this as non retryable exception by nature, i.e. need to handle in consciously
-public class YdbConditionallyRetryableException extends YdbNonRetryableException {
- private static final long serialVersionUID = -2371144941971339449L;
+ YdbConditionallyRetryableException(String message, String sqlState, int code, UnexpectedResultException cause) {
+ super(message, sqlState, code, cause);
+ this.status = cause.getStatus();
+ }
- YdbConditionallyRetryableException(String message, String sqlState, Status status) {
- super(message, sqlState, status);
+ public Status getStatus() {
+ return status;
}
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConfigurationException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConfigurationException.java
deleted file mode 100644
index 2812b6f..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbConfigurationException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-import java.sql.SQLException;
-
-public class YdbConfigurationException extends SQLException {
- private static final long serialVersionUID = -9023124863392765984L;
-
- public YdbConfigurationException(String message) {
- super(message);
- }
-
- public YdbConfigurationException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionException.java
deleted file mode 100644
index 9da7bad..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-import java.sql.SQLException;
-
-public class YdbExecutionException extends SQLException {
- private static final long serialVersionUID = -9189855688894485591L;
-
- public YdbExecutionException(String reason) {
- super(reason);
- }
-
- public YdbExecutionException(String reason, Throwable cause) {
- super(reason, cause);
- }
-
- public YdbExecutionException(String reason, String SQLState, int vendorCode) {
- super(reason, SQLState, vendorCode);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java
deleted file mode 100644
index 8044984..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-import tech.ydb.core.Status;
-
-public class YdbNonRetryableException extends YdbStatusException {
- private static final long serialVersionUID = 687247673341671225L;
-
- YdbNonRetryableException(String message, String sqlState, Status status) {
- super(message, sqlState, status);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbResultTruncatedException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbResultTruncatedException.java
deleted file mode 100644
index 092192c..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbResultTruncatedException.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-public class YdbResultTruncatedException extends YdbExecutionException {
- private static final long serialVersionUID = -1887300249465409232L;
-
- public YdbResultTruncatedException(String reason) {
- super(reason);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRetryableException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRetryableException.java
index ed1b922..ae1c384 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRetryableException.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRetryableException.java
@@ -1,11 +1,20 @@
package tech.ydb.jdbc.exception;
+import java.sql.SQLRecoverableException;
+
import tech.ydb.core.Status;
+import tech.ydb.core.UnexpectedResultException;
+
+public class YdbRetryableException extends SQLRecoverableException {
+ private static final long serialVersionUID = -7171306648623023924L;
+ private final Status status;
-public class YdbRetryableException extends YdbStatusException {
- private static final long serialVersionUID = 2082287790625648960L;
+ YdbRetryableException(String message, String sqlState, int code, UnexpectedResultException cause) {
+ super(message, sqlState, code, cause);
+ this.status = cause.getStatus();
+ }
- YdbRetryableException(String message, String sqlState, Status status) {
- super(message, sqlState, status);
+ public Status getStatus() {
+ return status;
}
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRuntimeException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRuntimeException.java
deleted file mode 100644
index 0feb754..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbRuntimeException.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-public class YdbRuntimeException extends RuntimeException {
- private static final long serialVersionUID = 7195253335276429670L;
-
- public YdbRuntimeException(String message) {
- super(message);
- }
-
- public YdbRuntimeException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbSQLException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbSQLException.java
new file mode 100644
index 0000000..c8af441
--- /dev/null
+++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbSQLException.java
@@ -0,0 +1,21 @@
+package tech.ydb.jdbc.exception;
+
+import java.sql.SQLException;
+
+import tech.ydb.core.Status;
+import tech.ydb.core.UnexpectedResultException;
+
+public class YdbSQLException extends SQLException {
+ private static final long serialVersionUID = 6204553083196091739L;
+
+ private final Status status;
+
+ YdbSQLException(String message, String sqlState, int code, UnexpectedResultException cause) {
+ super(message, sqlState, code, cause);
+ this.status = cause.getStatus();
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbStatusException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbStatusException.java
deleted file mode 100644
index 4edb87b..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbStatusException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package tech.ydb.jdbc.exception;
-
-import tech.ydb.core.Status;
-import tech.ydb.core.StatusCode;
-
-public class YdbStatusException extends YdbExecutionException {
- private static final long serialVersionUID = -8082086858749679589L;
-
- private final Status status;
-
- protected YdbStatusException(String message, String state, Status status) {
- super(message, state, status.getCode().getCode());
- this.status = status;
- }
-
- public Status getStatus() {
- return status;
- }
-
- public static YdbStatusException newException(String message, Status status) {
- if (status.getCode().isRetryable(false)) {
- String sqlState = "Retryable[" + status.toString() + "]";
- return new YdbRetryableException(message, sqlState, status);
- }
-
- if (status.getCode().isRetryable(true)) {
- String sqlState = "ConditionallyRetryable[" + status.toString() + "]";
- return new YdbConditionallyRetryableException(message, sqlState, status);
- }
-
- String sqlState = "NonRetryable[" + status.toString() + "]";
- return new YdbNonRetryableException(message, sqlState, status);
- }
-
- public static YdbStatusException newBadRequest(String message) {
- Status status = Status.of(StatusCode.BAD_REQUEST);
- String sqlState = "NonRetryable[" + status.toString() + "]";
- return new YdbNonRetryableException(message, sqlState, status);
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java
index 3ed75ad..aac17b3 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java
@@ -18,9 +18,8 @@
import tech.ydb.jdbc.YdbStatement;
import tech.ydb.jdbc.common.FixedResultSetFactory;
import tech.ydb.jdbc.context.YdbExecutor;
-import tech.ydb.jdbc.exception.YdbResultTruncatedException;
+import tech.ydb.jdbc.query.YdbExpression;
import tech.ydb.jdbc.query.YdbQuery;
-import tech.ydb.jdbc.query.YdbQueryOptions;
import tech.ydb.jdbc.settings.YdbOperationProperties;
import tech.ydb.table.query.DataQueryResult;
import tech.ydb.table.query.ExplainDataQueryResult;
@@ -28,15 +27,16 @@
import tech.ydb.table.result.ResultSetReader;
import tech.ydb.table.settings.ExecuteDataQuerySettings;
-import static tech.ydb.jdbc.YdbConst.NAMED_CURSORS_UNSUPPORTED;
-import static tech.ydb.jdbc.YdbConst.RESULT_SET_MODE_UNSUPPORTED;
-
/**
*
* @author Aleksandr Gorshenin
*/
public abstract class BaseYdbStatement implements YdbStatement {
- protected static final ResultState EMPTY_STATE = new ResultState();
+ private static final ResultState EMPTY_STATE = new ResultState(null);
+ private static final YdbResult NO_UPDATED = new YdbResult(0);
+
+ // TODO: YDB doesn't return the count of affected rows, so we use little hach to return always 1
+ private static final YdbResult HAS_UPDATED = new YdbResult(1);
private static FixedResultSetFactory EXPLAIN_RS_FACTORY = FixedResultSetFactory.newBuilder()
.addTextColumn(YdbConst.EXPLAIN_COLUMN_AST)
@@ -45,7 +45,6 @@ public abstract class BaseYdbStatement implements YdbStatement {
private final YdbConnection connection;
private final YdbExecutor executor;
- private final YdbQueryOptions queryOptions;
private final int resultSetType;
private final int maxRows;
private final boolean failOnTruncatedResult;
@@ -59,7 +58,6 @@ public BaseYdbStatement(Logger logger, YdbConnection connection, int resultSetTy
this.connection = Objects.requireNonNull(connection);
this.executor = new YdbExecutor(logger);
this.resultSetType = resultSetType;
- this.queryOptions = connection.getCtx().getQueryOptions();
this.isPoolable = isPoolable;
YdbOperationProperties props = connection.getCtx().getOperationProperties();
@@ -73,10 +71,6 @@ public YdbConnection getConnection() {
return connection;
}
- public YdbQuery createYdbQuery(String sql) throws SQLException {
- return YdbQuery.from(queryOptions, sql);
- }
-
@Override
public void close() {
isClosed = true;
@@ -169,16 +163,23 @@ protected void cleanState() throws SQLException {
state = EMPTY_STATE;
}
- protected boolean updateState(ResultState results) {
- state = results;
- return results.hasResultSets();
+ protected boolean updateState(List results) {
+ state = results == null ? EMPTY_STATE : new ResultState(results);
+ return state.hasResultSets();
}
- protected void executeSchemeQuery(YdbQuery query) throws SQLException {
+ protected List executeSchemeQuery(YdbQuery query) throws SQLException {
connection.executeSchemeQuery(query, executor);
+
+ int expressionsCount = query.getExpressions().isEmpty() ? 1 : query.getExpressions().size();
+ List results = new ArrayList<>();
+ for (int i = 0; i < expressionsCount; i++) {
+ results.add(NO_UPDATED);
+ }
+ return results;
}
- protected ResultState executeExplainQuery(YdbQuery query) throws SQLException {
+ protected List executeExplainQuery(YdbQuery query) throws SQLException {
ExplainDataQueryResult explainDataQuery = connection.executeExplainQuery(query, executor);
ResultSetReader result = EXPLAIN_RS_FACTORY.createResultSet()
@@ -188,17 +189,15 @@ protected ResultState executeExplainQuery(YdbQuery query) throws SQLException {
.build()
.build();
- List list = Collections.singletonList(new YdbResultSetImpl(this, result));
- return new ResultState(list);
+ return Collections.singletonList(new YdbResult(new YdbResultSetImpl(this, result)));
}
- protected ResultState executeScanQuery(YdbQuery query, Params params) throws SQLException {
+ protected List executeScanQuery(YdbQuery query, Params params) throws SQLException {
ResultSetReader result = connection.executeScanQuery(query, executor, params);
- List list = Collections.singletonList(new YdbResultSetImpl(this, result));
- return new ResultState(list);
+ return Collections.singletonList(new YdbResult(new YdbResultSetImpl(this, result)));
}
- protected ResultState executeDataQuery(YdbQuery query, Params params) throws SQLException {
+ protected List executeDataQuery(YdbQuery query, Params params) throws SQLException {
int timeout = getQueryTimeout();
ExecuteDataQuerySettings settings = new ExecuteDataQuerySettings()
.setOperationTimeout(Duration.ofSeconds(timeout))
@@ -208,23 +207,47 @@ protected ResultState executeDataQuery(YdbQuery query, Params params) throws SQL
}
DataQueryResult result = connection.executeDataQuery(query, executor, settings, params);
- List list = new ArrayList<>();
- for (int idx = 0; idx < result.getResultSetCount(); idx += 1) {
+
+ List results = new ArrayList<>();
+ int idx = 0;
+ for (YdbExpression exp: query.getExpressions()) {
+ if (exp.isDDL()) {
+ results.add(NO_UPDATED);
+ continue;
+ }
+ if (!exp.isSelect()) {
+ results.add(HAS_UPDATED);
+ continue;
+ }
+
+ if (idx < result.getResultSetCount()) {
+ ResultSetReader rs = result.getResultSet(idx);
+ if (failOnTruncatedResult && rs.isTruncated()) {
+ String msg = String.format(YdbConst.RESULT_IS_TRUNCATED, idx, rs.getRowCount());
+ throw new SQLException(msg);
+ }
+ results.add(new YdbResult(new YdbResultSetImpl(this, rs)));
+ idx++;
+ }
+ }
+
+ while (idx < result.getResultSetCount()) {
ResultSetReader rs = result.getResultSet(idx);
if (failOnTruncatedResult && rs.isTruncated()) {
String msg = String.format(YdbConst.RESULT_IS_TRUNCATED, idx, rs.getRowCount());
- throw new YdbResultTruncatedException(msg);
+ throw new SQLException(msg);
}
- list.add(new YdbResultSetImpl(this, rs));
+ results.add(new YdbResult(new YdbResultSetImpl(this, rs)));
+ idx++;
}
- return new ResultState(list);
+ return results;
}
// UNSUPPORTED
@Override
public void setCursorName(String name) throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException(NAMED_CURSORS_UNSUPPORTED);
+ throw new SQLFeatureNotSupportedException(YdbConst.NAMED_CURSORS_UNSUPPORTED);
}
@Override
@@ -300,47 +323,62 @@ public int getResultSetConcurrency() {
return ResultSet.CONCUR_READ_ONLY;
}
- protected static class ResultState {
- private final List results;
- private int resultSetIndex;
+ protected static class YdbResult {
+ private final int updateCount;
+ private final YdbResultSet resultSet;
- private ResultState() {
- results = null;
- resultSetIndex = -1;
+ YdbResult(int updateCount) {
+ this.updateCount = updateCount;
+ this.resultSet = null;
}
- private ResultState(List list) {
- results = list;
- resultSetIndex = 0;
+ YdbResult(YdbResultSet resultSet) {
+ this.updateCount = -1;
+ this.resultSet = resultSet;
}
+ }
+
+ private static class ResultState {
+ private final List results;
+ private int resultIndex;
- public boolean hasResultSets() {
- return results != null && !results.isEmpty();
+ ResultState(List results) {
+ this.results = results;
+ this.resultIndex = 0;
}
- // TODO: YDB doesn't return the count of affected rows, so we use little hach to return always 1
- public int getUpdateCount() {
- return (results != null && results.isEmpty() && resultSetIndex == 0) ? 1 : -1;
+ boolean hasResultSets() {
+ if (results == null || resultIndex >= results.size()) {
+ return false;
+ }
+
+ return results.get(resultIndex).resultSet != null;
}
- public YdbResultSet getCurrentResultSet() throws SQLException {
- return getResultSet(resultSetIndex);
+ int getUpdateCount() {
+ if (results == null || resultIndex >= results.size()) {
+ return -1;
+ }
+
+ return results.get(resultIndex).updateCount;
}
- public YdbResultSet getResultSet(int index) throws SQLException {
- if (results == null) {
+ YdbResultSet getCurrentResultSet() {
+ if (results == null || resultIndex >= results.size()) {
return null;
}
- if (index < 0 || index >= results.size()) {
+ return results.get(resultIndex).resultSet;
+ }
+
+ YdbResultSet getResultSet(int index) {
+ if (results == null || index < 0 || index >= results.size()) {
return null;
}
-
- return results.get(index);
+ return results.get(index).resultSet;
}
- public boolean getMoreResults(int current) throws SQLException {
- if (results == null || results.isEmpty()) {
- resultSetIndex = -1; // reset updateCount
+ boolean getMoreResults(int current) throws SQLException {
+ if (results == null || resultIndex >= results.size()) {
return false;
}
@@ -348,19 +386,19 @@ public boolean getMoreResults(int current) throws SQLException {
case Statement.KEEP_CURRENT_RESULT:
break;
case Statement.CLOSE_CURRENT_RESULT:
- results.get(resultSetIndex).close();
+ results.get(resultIndex).resultSet.close();
break;
case Statement.CLOSE_ALL_RESULTS:
- for (int idx = 0; idx <= resultSetIndex; idx += 1) {
- results.get(idx).close();
+ for (int idx = 0; idx <= resultIndex; idx += 1) {
+ results.get(idx).resultSet.close();
}
break;
default:
- throw new SQLException(RESULT_SET_MODE_UNSUPPORTED + current);
+ throw new SQLException(YdbConst.RESULT_SET_MODE_UNSUPPORTED + current);
}
- resultSetIndex += 1;
- return resultSetIndex >= 0 && resultSetIndex < results.size();
+ resultIndex += 1;
+ return hasResultSets();
}
}
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbConnectionImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbConnectionImpl.java
index 4e735c6..0bcefff 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbConnectionImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbConnectionImpl.java
@@ -1,5 +1,6 @@
package tech.ydb.jdbc.impl;
+
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
@@ -36,13 +37,12 @@
import tech.ydb.jdbc.context.YdbContext;
import tech.ydb.jdbc.context.YdbExecutor;
import tech.ydb.jdbc.context.YdbTxState;
-import tech.ydb.jdbc.exception.YdbExecutionException;
+import tech.ydb.jdbc.query.JdbcParams;
import tech.ydb.jdbc.query.QueryType;
import tech.ydb.jdbc.query.YdbQuery;
import tech.ydb.jdbc.settings.FakeTxMode;
import tech.ydb.jdbc.settings.YdbOperationProperties;
import tech.ydb.table.Session;
-import tech.ydb.table.query.DataQuery;
import tech.ydb.table.query.DataQueryResult;
import tech.ydb.table.query.ExplainDataQueryResult;
import tech.ydb.table.query.Params;
@@ -54,8 +54,6 @@
import tech.ydb.table.settings.ExecuteSchemeQuerySettings;
import tech.ydb.table.settings.ExplainDataQuerySettings;
import tech.ydb.table.settings.KeepAliveSessionSettings;
-import tech.ydb.table.settings.PrepareDataQuerySettings;
-import tech.ydb.table.settings.RequestSettings;
import tech.ydb.table.settings.RollbackTxSettings;
public class YdbConnectionImpl implements YdbConnection {
@@ -82,15 +80,6 @@ public YdbConnectionImpl(YdbContext context) throws SQLException {
this.ctx.register();
}
- > T withDefaultTimeout(T settings) {
- Duration operation = ctx.getOperationProperties().getDeadlineTimeout();
- if (!operation.isZero() && !operation.isNegative()) {
- settings.setOperationTimeout(operation);
- settings.setTimeout(operation.plusSeconds(1));
- }
- return settings;
- }
-
@Override
public YdbStatement createStatement() throws SQLException {
return createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY,
@@ -106,7 +95,7 @@ public YdbPreparedStatement prepareStatement(String sql) throws SQLException {
@Override
public String nativeSQL(String sql) {
try {
- return YdbQuery.from(ctx.getQueryOptions(), sql).getYqlQuery(null);
+ return ctx.parseYdbQuery(sql).getYqlQuery(null);
} catch (SQLException ex) {
return ex.getMessage();
}
@@ -150,7 +139,7 @@ public void commit() throws SQLException {
}
Session session = state.getSession(ctx, executor);
- CommitTxSettings settings = withDefaultTimeout(new CommitTxSettings());
+ CommitTxSettings settings = ctx.withDefaultTimeout(new CommitTxSettings());
try {
executor.clearWarnings();
@@ -172,7 +161,7 @@ public void rollback() throws SQLException {
}
Session session = state.getSession(ctx, executor);
- RollbackTxSettings settings = withDefaultTimeout(new RollbackTxSettings());
+ RollbackTxSettings settings = ctx.withDefaultTimeout(new RollbackTxSettings());
try {
executor.clearWarnings();
@@ -270,13 +259,13 @@ public void executeSchemeQuery(YdbQuery query, YdbExecutor executor) throws SQLE
break;
case ERROR:
default:
- throw new YdbExecutionException(YdbConst.SCHEME_QUERY_INSIDE_TRANSACTION);
+ throw new SQLException(YdbConst.SCHEME_QUERY_INSIDE_TRANSACTION);
}
}
// Scheme query does not affect transactions or result sets
- ExecuteSchemeQuerySettings settings = withDefaultTimeout(new ExecuteSchemeQuerySettings());
+ ExecuteSchemeQuerySettings settings = ctx.withDefaultTimeout(new ExecuteSchemeQuerySettings());
final String yql = query.getYqlQuery(null);
try (Session session = executor.createSession(ctx)) {
@@ -317,8 +306,7 @@ public ResultSetReader executeScanQuery(YdbQuery query, YdbExecutor executor, Pa
break;
case ERROR:
default:
- throw new YdbExecutionException(YdbConst.SCAN_QUERY_INSIDE_TRANSACTION);
-
+ throw new SQLException(YdbConst.SCAN_QUERY_INSIDE_TRANSACTION);
}
}
@@ -341,22 +329,13 @@ public ExplainDataQueryResult executeExplainQuery(YdbQuery query, YdbExecutor ex
ensureOpened();
String yql = query.getYqlQuery(null);
- ExplainDataQuerySettings settings = withDefaultTimeout(new ExplainDataQuerySettings());
+ ExplainDataQuerySettings settings = ctx.withDefaultTimeout(new ExplainDataQuerySettings());
try (Session session = executor.createSession(ctx)) {
String msg = QueryType.EXPLAIN_QUERY + " >>\n" + yql;
return executor.call(msg, () -> session.explainDataQuery(yql, settings));
}
}
- DataQuery prepareDataQuery(YdbQuery query) throws SQLException {
- String yql = query.getYqlQuery(null);
- PrepareDataQuerySettings settings = withDefaultTimeout(new PrepareDataQuerySettings());
- try (Session session = executor.createSession(ctx)) {
- String msg = "Preparing Query >>\n" + yql;
- return executor.call(msg, () -> session.prepareDataQuery(yql, settings));
- }
- }
-
@Override
public YdbStatement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
@@ -426,13 +405,13 @@ private YdbPreparedStatement prepareStatement(String sql, int resultSetType, Ydb
ensureOpened();
executor.clearWarnings();
- YdbQuery query = YdbQuery.from(ctx.getQueryOptions(), sql);
+ YdbQuery query = ctx.findOrParseYdbQuery(sql);
if (query.type() != QueryType.DATA_QUERY && query.type() != QueryType.SCAN_QUERY) {
throw new SQLException(YdbConst.UNSUPPORTED_QUERY_TYPE_IN_PS + query.type());
}
- YdbJdbcParams params = YdbJdbcParams.create(this, query, mode);
+ JdbcParams params = ctx.findOrCreateJdbcParams(query, mode);
return new YdbPreparedStatementImpl(this, query, params, resultSetType);
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java
index cb0474b..099218f 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java
@@ -21,6 +21,7 @@
import com.google.common.base.Strings;
+import tech.ydb.core.Result;
import tech.ydb.core.StatusCode;
import tech.ydb.jdbc.YdbConnection;
import tech.ydb.jdbc.YdbConst;
@@ -30,11 +31,9 @@
import tech.ydb.jdbc.common.FixedResultSetFactory;
import tech.ydb.jdbc.common.YdbFunctions;
import tech.ydb.jdbc.context.YdbExecutor;
-import tech.ydb.jdbc.exception.YdbStatusException;
import tech.ydb.proto.scheme.SchemeOperationProtos;
import tech.ydb.scheme.SchemeClient;
import tech.ydb.scheme.description.ListDirectoryResult;
-import tech.ydb.table.Session;
import tech.ydb.table.description.TableColumn;
import tech.ydb.table.description.TableDescription;
import tech.ydb.table.description.TableIndex;
@@ -1345,26 +1344,24 @@ private List tables(String databasePrefix, String path, Predicate session.describeTable(databaseWithSuffix + table, settings)
- );
- } catch (YdbStatusException ex) {
- if (ex.getStatus().getCode() != StatusCode.SCHEME_ERROR) { // ignore scheme errors like path not found
- throw ex;
- }
- LOGGER.log(Level.WARNING, "Cannot describe table {0} -> {1}",
- new Object[]{ table, ex.getMessage() }
- );
+ String databaseWithSuffix = withSuffix(connection.getCtx().getDatabase());
- return null;
- }
- }
+ return executor.call("Describe table " + table, () -> connection.getCtx()
+ .describeTable(databaseWithSuffix + table, settings)
+ .thenApply(result -> {
+ // ignore scheme errors like path not found
+ if (result.getStatus().getCode() == StatusCode.SCHEME_ERROR) {
+ LOGGER.log(Level.WARNING, "Cannot describe table {0} -> {1}",
+ new Object[]{ table, result.getStatus() });
+ return Result.success(null);
+ }
+ return result;
+ })
+ );
}
private ResultSet emptyResultSet(FixedResultSetFactory factory) {
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbJdbcParams.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbJdbcParams.java
deleted file mode 100644
index 79264e7..0000000
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbJdbcParams.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package tech.ydb.jdbc.impl;
-
-import java.sql.SQLException;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import tech.ydb.jdbc.YdbConst;
-import tech.ydb.jdbc.YdbPrepareMode;
-import tech.ydb.jdbc.common.TypeDescription;
-import tech.ydb.jdbc.exception.YdbExecutionException;
-import tech.ydb.jdbc.impl.params.BatchedParams;
-import tech.ydb.jdbc.impl.params.InMemoryParams;
-import tech.ydb.jdbc.impl.params.PreparedParams;
-import tech.ydb.jdbc.query.YdbQuery;
-import tech.ydb.jdbc.query.YdbQueryOptions;
-import tech.ydb.table.query.DataQuery;
-import tech.ydb.table.query.Params;
-import tech.ydb.table.values.Type;
-
-/**
- *
- * @author Aleksandr Gorshenin
- */
-public interface YdbJdbcParams {
- void clearParameters();
-
- void setParam(int index, @Nullable Object obj, @Nonnull Type type) throws SQLException;
- void setParam(String name, @Nullable Object obj, @Nonnull Type type) throws SQLException;
-
- String getNameByIndex(int index) throws SQLException;
-
- void addBatch() throws SQLException;
- void clearBatch();
- int batchSize();
-
- int parametersCount();
-
- TypeDescription getDescription(int index) throws SQLException;
-
- List getBatchParams() throws SQLException;
- Params getCurrentParams() throws SQLException;
-
- static YdbJdbcParams create(YdbConnectionImpl connection, YdbQuery query, YdbPrepareMode mode) throws SQLException {
- YdbQueryOptions opts = connection.getCtx().getQueryOptions();
-
- if (query.hasIndexesParameters()
- || mode == YdbPrepareMode.IN_MEMORY
- || !opts.iPrepareDataQueries()) {
- return new InMemoryParams(query.getIndexesParameters());
- }
-
- DataQuery prepared = connection.prepareDataQuery(query);
-
- boolean requireBatch = mode == YdbPrepareMode.DATA_QUERY_BATCH;
- if (requireBatch || (mode == YdbPrepareMode.AUTO && opts.isDetectBatchQueries())) {
- BatchedParams params = BatchedParams.tryCreateBatched(prepared.types());
- if (params != null) {
- return params;
- }
-
- if (requireBatch) {
- throw new YdbExecutionException(YdbConst.STATEMENT_IS_NOT_A_BATCH + query.originSQL());
- }
- }
-
- return new PreparedParams(prepared.types());
- }
-}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbParameterMetaDataImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbParameterMetaDataImpl.java
index 3a25a29..5fd57b2 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbParameterMetaDataImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbParameterMetaDataImpl.java
@@ -1,6 +1,7 @@
package tech.ydb.jdbc.impl;
+
import java.sql.ParameterMetaData;
import java.sql.SQLException;
import java.sql.Types;
@@ -10,10 +11,12 @@
import static tech.ydb.jdbc.YdbConst.CANNOT_UNWRAP_TO;
+import tech.ydb.jdbc.query.JdbcParams;
+
public class YdbParameterMetaDataImpl implements YdbParameterMetaData {
- private final YdbJdbcParams params;
+ private final JdbcParams params;
- public YdbParameterMetaDataImpl(YdbJdbcParams params) {
+ public YdbParameterMetaDataImpl(JdbcParams params) {
this.params = params;
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbPreparedStatementImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbPreparedStatementImpl.java
index c94bbd2..806ac0e 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbPreparedStatementImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbPreparedStatementImpl.java
@@ -1,5 +1,6 @@
package tech.ydb.jdbc.impl;
+
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
@@ -12,6 +13,7 @@
import java.sql.Ref;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
+import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLXML;
@@ -20,6 +22,7 @@
import java.sql.Types;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;
@@ -30,19 +33,19 @@
import tech.ydb.jdbc.YdbResultSet;
import tech.ydb.jdbc.YdbTypes;
import tech.ydb.jdbc.common.MappingSetters;
-import tech.ydb.jdbc.exception.YdbExecutionException;
import tech.ydb.jdbc.query.YdbQuery;
import tech.ydb.table.query.Params;
import tech.ydb.table.values.Type;
import tech.ydb.table.values.VoidType;
+import tech.ydb.jdbc.query.JdbcParams;
public class YdbPreparedStatementImpl extends BaseYdbStatement implements YdbPreparedStatement {
private static final Logger LOGGER = Logger.getLogger(YdbPreparedStatementImpl.class.getName());
private final YdbQuery query;
- private final YdbJdbcParams params;
+ private final JdbcParams params;
private final YdbTypes types;
- public YdbPreparedStatementImpl(YdbConnection connection, YdbQuery query, YdbJdbcParams params, int resultSetType) {
+ public YdbPreparedStatementImpl(YdbConnection connection, YdbQuery query, JdbcParams params, int resultSetType) {
super(LOGGER, connection, resultSetType, true); // is poolable by default
this.query = Objects.requireNonNull(query);
@@ -123,7 +126,7 @@ public boolean execute() throws SQLException {
cleanState();
clearBatch();
- ResultState newState = EMPTY_STATE;
+ List newState = null;
switch (query.type()) {
case DATA_QUERY:
newState = executeDataQuery(query, params.getCurrentParams());
@@ -142,7 +145,7 @@ public boolean execute() throws SQLException {
@Override
public YdbResultSet executeScanQuery() throws SQLException {
cleanState();
- ResultState state = executeScanQuery(query, params.getCurrentParams());
+ List state = executeScanQuery(query, params.getCurrentParams());
params.clearParameters();
updateState(state);
return getResultSet();
@@ -151,7 +154,7 @@ public YdbResultSet executeScanQuery() throws SQLException {
@Override
public YdbResultSet executeExplainQuery() throws SQLException {
cleanState();
- ResultState state = executeExplainQuery(query);
+ List state = executeExplainQuery(query);
updateState(state);
return getResultSet();
}
@@ -193,7 +196,7 @@ public void setObject(int parameterIndex, Object value, Type type) throws SQLExc
@Override
public void setObject(String parameterName, Object x) throws SQLException {
if (x == null) {
- throw new YdbExecutionException(String.format(YdbConst.UNABLE_TO_SET_NULL_OBJECT));
+ throw new SQLDataException(YdbConst.UNABLE_TO_SET_NULL_OBJECT);
}
params.setParam(parameterName, x, ydbType(x.getClass()));
}
@@ -201,7 +204,7 @@ public void setObject(String parameterName, Object x) throws SQLException {
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
if (x == null) {
- throw new YdbExecutionException(String.format(YdbConst.UNABLE_TO_SET_NULL_OBJECT));
+ throw new SQLDataException(YdbConst.UNABLE_TO_SET_NULL_OBJECT);
}
params.setParam(parameterIndex, x, ydbType(x.getClass()));
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbStatementImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbStatementImpl.java
index d909b0f..158398d 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbStatementImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbStatementImpl.java
@@ -29,7 +29,7 @@ public void executeSchemeQuery(String sql) throws SQLException {
cleanState();
clearBatch();
- YdbQuery query = createYdbQuery(sql);
+ YdbQuery query = getConnection().getCtx().parseYdbQuery(sql);
executeSchemeQuery(query);
}
@@ -38,8 +38,8 @@ public YdbResultSet executeScanQuery(String sql) throws SQLException {
cleanState();
clearBatch();
- YdbQuery query = createYdbQuery(sql);
- ResultState results = executeScanQuery(query, Params.empty());
+ YdbQuery query = getConnection().getCtx().parseYdbQuery(sql);
+ List results = executeScanQuery(query, Params.empty());
if (!updateState(results)) {
throw new SQLException(YdbConst.QUERY_EXPECT_RESULT_SET);
}
@@ -51,8 +51,8 @@ public YdbResultSet executeExplainQuery(String sql) throws SQLException {
cleanState();
clearBatch();
- YdbQuery query = createYdbQuery(sql);
- ResultState newState = executeExplainQuery(query);
+ YdbQuery query = getConnection().getCtx().parseYdbQuery(sql);
+ List newState = executeExplainQuery(query);
if (!updateState(newState)) {
throw new SQLException(YdbConst.QUERY_EXPECT_RESULT_SET);
}
@@ -79,11 +79,11 @@ public int executeUpdate(String sql) throws SQLException {
public boolean execute(String sql) throws SQLException {
cleanState();
- YdbQuery query = createYdbQuery(sql);
- ResultState newState = EMPTY_STATE;
+ YdbQuery query = getConnection().getCtx().parseYdbQuery(sql);
+ List newState = null;
switch (query.type()) {
case SCHEME_QUERY:
- executeSchemeQuery(query);
+ newState = executeSchemeQuery(query);
break;
case DATA_QUERY:
newState = executeDataQuery(query, Params.empty());
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java
index 7a8585d..440e4bf 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java
@@ -25,7 +25,6 @@
import tech.ydb.jdbc.YdbConst;
import tech.ydb.jdbc.YdbTypes;
-import tech.ydb.jdbc.exception.YdbRuntimeException;
import tech.ydb.table.values.DecimalValue;
import tech.ydb.table.values.PrimitiveType;
import tech.ydb.table.values.Type;
@@ -210,8 +209,7 @@ public int unwrapYdbJdbcType(int sqlType) {
Integer value = sqlTypeByPrimitiveNumId.get(type);
if (value == null) {
- throw new YdbRuntimeException("Internal error. Unsupported YDB type: " + idType +
- " as " + type);
+ throw new RuntimeException("Internal error. Unsupported YDB type: " + idType + " as " + type);
}
return value;
} else {
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcParams.java b/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcParams.java
new file mode 100644
index 0000000..9b961a4
--- /dev/null
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcParams.java
@@ -0,0 +1,35 @@
+package tech.ydb.jdbc.query;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import tech.ydb.jdbc.common.TypeDescription;
+import tech.ydb.table.query.Params;
+import tech.ydb.table.values.Type;
+
+/**
+ *
+ * @author Aleksandr Gorshenin
+ */
+public interface JdbcParams {
+ void clearParameters();
+
+ void setParam(int index, @Nullable Object obj, @Nonnull Type type) throws SQLException;
+ void setParam(String name, @Nullable Object obj, @Nonnull Type type) throws SQLException;
+
+ String getNameByIndex(int index) throws SQLException;
+
+ void addBatch() throws SQLException;
+ void clearBatch();
+ int batchSize();
+
+ int parametersCount();
+
+ TypeDescription getDescription(int index) throws SQLException;
+
+ List getBatchParams() throws SQLException;
+ Params getCurrentParams() throws SQLException;
+}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcQueryLexer.java b/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcQueryLexer.java
index 4002c22..beeae22 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcQueryLexer.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/JdbcQueryLexer.java
@@ -68,14 +68,19 @@ public static void buildQuery(YdbQueryBuilder builder, YdbQueryOptions options)
}
// Detect data query expression - starts with SELECT, UPDATE, INSERT, UPSERT, DELETE, REPLACE
- if (parseSelectKeyword(chars, i)
- || parseUpdateKeyword(chars, i)
+ if (parseSelectKeyword(chars, i)) {
+ builder.addExpression(QueryType.DATA_QUERY, YdbExpression.SELECT);
+ detectJdbcArgs = options.isDetectJdbcParameters();
+ break;
+ }
+
+ if (parseUpdateKeyword(chars, i)
|| parseInsertKeyword(chars, i)
|| parseUpsertKeyword(chars, i)
|| parseDeleteKeyword(chars, i)
|| parseReplaceKeyword(chars, i)
) {
- builder.setQueryType(QueryType.DATA_QUERY);
+ builder.addExpression(QueryType.DATA_QUERY, YdbExpression.OTHER_DML);
detectJdbcArgs = options.isDetectJdbcParameters();
break;
}
@@ -84,13 +89,13 @@ public static void buildQuery(YdbQueryBuilder builder, YdbQueryOptions options)
if (parseAlterKeyword(chars, i)
|| parseCreateKeyword(chars, i)
|| parseDropKeyword(chars, i)) {
- builder.setQueryType(QueryType.SCHEME_QUERY);
+ builder.addExpression(QueryType.SCHEME_QUERY, YdbExpression.DDL);
break;
}
// Detect scan expression - starts with SCAN
if (parseScanKeyword(chars, i)) {
- builder.setQueryType(QueryType.SCAN_QUERY);
+ builder.addExpression(QueryType.SCAN_QUERY, YdbExpression.SELECT);
detectJdbcArgs = options.isDetectJdbcParameters();
// Skip SCAN prefix
@@ -101,7 +106,7 @@ public static void buildQuery(YdbQueryBuilder builder, YdbQueryOptions options)
// Detect explain expression - starts with EXPLAIN
if (parseExplainKeyword(chars, i)) {
- builder.setQueryType(QueryType.EXPLAIN_QUERY);
+ builder.addExpression(QueryType.EXPLAIN_QUERY, YdbExpression.SELECT);
detectJdbcArgs = options.isDetectJdbcParameters();
// Skip EXPLAIN prefix
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbExpression.java b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbExpression.java
new file mode 100644
index 0000000..96c54ea
--- /dev/null
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbExpression.java
@@ -0,0 +1,27 @@
+package tech.ydb.jdbc.query;
+
+/**
+ *
+ * @author Aleksandr Gorshenin
+ */
+public class YdbExpression {
+ static YdbExpression SELECT = new YdbExpression(false, true);
+ static YdbExpression DDL = new YdbExpression(true, false);
+ static YdbExpression OTHER_DML = new YdbExpression(false, false);
+
+ private final boolean isDDL; // CREATE, DROP and ALTER
+ private final boolean isSelect;
+
+ private YdbExpression(boolean isDDL, boolean isSelect) {
+ this.isDDL = isDDL;
+ this.isSelect = isSelect;
+ }
+
+ public boolean isDDL() {
+ return isDDL;
+ }
+
+ public boolean isSelect() {
+ return isSelect;
+ }
+}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java
index 361ec70..888618d 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java
@@ -2,12 +2,12 @@
+import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import tech.ydb.jdbc.YdbConst;
-import tech.ydb.jdbc.exception.YdbStatusException;
import tech.ydb.table.query.Params;
import tech.ydb.table.values.Value;
@@ -21,19 +21,25 @@ public class YdbQuery {
private final String yqlQuery;
private final QueryType type;
private final List indexesArgsNames;
+ private final List expressions;
- private YdbQuery(YdbQueryOptions opts, YdbQueryBuilder builder) {
+ YdbQuery(YdbQueryOptions opts, YdbQueryBuilder builder) {
this.opts = opts;
this.originSQL = builder.getOriginSQL();
this.yqlQuery = builder.buildYQL();
this.indexesArgsNames = builder.getIndexedArgs();
this.type = builder.getQueryType();
+ this.expressions = builder.getExpressions();
}
public String originSQL() {
return originSQL;
}
+ public List getExpressions() {
+ return expressions;
+ }
+
public boolean hasIndexesParameters() {
return indexesArgsNames != null && !indexesArgsNames.isEmpty();
}
@@ -51,7 +57,7 @@ public String getYqlQuery(Params params) throws SQLException {
for (int idx = 0; idx < indexesArgsNames.size(); idx += 1) {
String prm = indexesArgsNames.get(idx);
if (!values.containsKey(prm)) {
- throw YdbStatusException.newBadRequest(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm);
+ throw new SQLDataException(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm);
}
if (opts.isDeclareJdbcParameters()) {
@@ -78,10 +84,4 @@ public String getYqlQuery(Params params) throws SQLException {
public QueryType type() {
return type;
}
-
- public static YdbQuery from(YdbQueryOptions opts, String sql) throws SQLException {
- YdbQueryBuilder builder = new YdbQueryBuilder(sql, opts.getForcedQueryType());
- JdbcQueryLexer.buildQuery(builder, opts);
- return new YdbQuery(opts, builder);
- }
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java
index 7100bdd..4e08600 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java
@@ -1,10 +1,11 @@
package tech.ydb.jdbc.query;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import tech.ydb.jdbc.YdbConst;
-import tech.ydb.jdbc.exception.YdbStatusException;
/**
*
@@ -15,6 +16,7 @@ public class YdbQueryBuilder {
private final StringBuilder query;
private final List args = new ArrayList<>();
private final QueryType forcedType;
+ private final List expressions = new ArrayList<>();
private int argsCounter = 0;
private QueryType currentType = null;
@@ -36,13 +38,15 @@ public String createNextArgName() {
}
}
- public void setQueryType(QueryType type) throws YdbStatusException {
+ public void addExpression(QueryType type, YdbExpression expression) throws SQLException {
+ expressions.add(expression);
+
if (forcedType != null) {
return;
}
if (currentType != null && currentType != type) {
- throw YdbStatusException.newBadRequest(YdbConst.MULTI_TYPES_IN_ONE_QUERY + currentType + ", " + type);
+ throw new SQLFeatureNotSupportedException(YdbConst.MULTI_TYPES_IN_ONE_QUERY + currentType + ", " + type);
}
this.currentType = type;
}
@@ -59,6 +63,10 @@ public QueryType getQueryType() {
return QueryType.DATA_QUERY;
}
+ public List getExpressions() {
+ return expressions;
+ }
+
public String getOriginSQL() {
return origin;
}
@@ -82,4 +90,8 @@ public void append(char ch) {
public void append(String string) {
query.append(string);
}
+
+ public YdbQuery build(YdbQueryOptions opts) {
+ return new YdbQuery(opts, this);
+ }
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java b/jdbc/src/main/java/tech/ydb/jdbc/query/params/BatchedParams.java
similarity index 69%
rename from jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java
rename to jdbc/src/main/java/tech/ydb/jdbc/query/params/BatchedParams.java
index 1ec911c..2338697 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/params/BatchedParams.java
@@ -1,17 +1,20 @@
-package tech.ydb.jdbc.impl.params;
+package tech.ydb.jdbc.query.params;
+import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
import tech.ydb.jdbc.YdbConst;
import tech.ydb.jdbc.common.TypeDescription;
-import tech.ydb.jdbc.exception.YdbStatusException;
-import tech.ydb.jdbc.impl.YdbJdbcParams;
import tech.ydb.table.query.Params;
import tech.ydb.table.values.ListType;
import tech.ydb.table.values.ListValue;
@@ -19,12 +22,13 @@
import tech.ydb.table.values.StructValue;
import tech.ydb.table.values.Type;
import tech.ydb.table.values.Value;
+import tech.ydb.jdbc.query.JdbcParams;
/**
*
* @author Aleksandr Gorshenin
*/
-public class BatchedParams implements YdbJdbcParams {
+public class BatchedParams implements JdbcParams {
private final String batchParamName;
private final Map paramsByName;
private final ParamDescription[] params;
@@ -37,14 +41,44 @@ private BatchedParams(String listName, StructType structType) {
this.paramsByName = new HashMap<>();
this.params = new ParamDescription[structType.getMembersCount()];
+ Map types = new HashMap<>();
for (int idx = 0; idx < structType.getMembersCount(); idx += 1) {
- String paramName = structType.getMemberName(idx);
- String displayName = YdbConst.VARIABLE_PARAMETER_PREFIX + paramName;
- TypeDescription type = TypeDescription.of(structType.getMemberType(idx));
+ types.put(structType.getMemberName(idx), structType.getMemberType(idx));
+ }
+
+ // Firstly put all indexed params (p1, p2, ..., pN) in correct places of paramNames
+ Set indexedNames = new HashSet<>();
+ for (int idx = 0; idx < structType.getMembersCount(); idx += 1) {
+ String indexedName = YdbConst.INDEXED_PARAMETER_PREFIX + (1 + idx);
+ if (types.containsKey(indexedName)) {
+ String displayName = YdbConst.VARIABLE_PARAMETER_PREFIX + indexedName;
+ TypeDescription typeDesc = TypeDescription.of(types.get(indexedName));
+ ParamDescription paramDesc = new ParamDescription(idx, indexedName, displayName, typeDesc);
+
+ params[idx] = paramDesc;
+ paramsByName.put(indexedName, paramDesc);
+ indexedNames.add(indexedName);
+ }
+ }
+
+ // Then put all others params in free places of paramNames in alphabetic order
+ Iterator sortedIter = new TreeSet<>(types.keySet()).iterator();
+ for (int idx = 0; idx < params.length; idx += 1) {
+ if (params[idx] != null) {
+ continue;
+ }
+
+ String param = sortedIter.next();
+ while (indexedNames.contains(param)) {
+ param = sortedIter.next();
+ }
+
+ String displayName = YdbConst.VARIABLE_PARAMETER_PREFIX + param;
+ TypeDescription typeDesc = TypeDescription.of(types.get(param));
+ ParamDescription paramDesc = new ParamDescription(idx, param, displayName, typeDesc);
- ParamDescription param = new ParamDescription(idx, paramName, displayName, type);
- params[idx] = param;
- paramsByName.put(paramName, param);
+ params[idx] = paramDesc;
+ paramsByName.put(param, paramDesc);
}
}
@@ -85,7 +119,7 @@ private StructValue validatedCurrentStruct() throws SQLException {
continue;
}
- throw YdbStatusException.newBadRequest(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm.displayName());
+ throw new SQLDataException(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm.displayName());
}
return StructValue.of(currentValues);
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/InMemoryParams.java b/jdbc/src/main/java/tech/ydb/jdbc/query/params/InMemoryParams.java
similarity index 95%
rename from jdbc/src/main/java/tech/ydb/jdbc/impl/params/InMemoryParams.java
rename to jdbc/src/main/java/tech/ydb/jdbc/query/params/InMemoryParams.java
index 003fa67..d8babfa 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/InMemoryParams.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/params/InMemoryParams.java
@@ -1,4 +1,4 @@
-package tech.ydb.jdbc.impl.params;
+package tech.ydb.jdbc.query.params;
@@ -10,17 +10,17 @@
import tech.ydb.jdbc.YdbConst;
import tech.ydb.jdbc.common.TypeDescription;
-import tech.ydb.jdbc.impl.YdbJdbcParams;
import tech.ydb.table.query.Params;
import tech.ydb.table.values.Type;
import tech.ydb.table.values.Value;
+import tech.ydb.jdbc.query.JdbcParams;
/**
*
* @author Aleksandr Gorshenin
*/
-public class InMemoryParams implements YdbJdbcParams {
+public class InMemoryParams implements JdbcParams {
private final String[] paramNames;
private final Map> paramValues;
private final List batchList;
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/ParamDescription.java b/jdbc/src/main/java/tech/ydb/jdbc/query/params/ParamDescription.java
similarity index 98%
rename from jdbc/src/main/java/tech/ydb/jdbc/impl/params/ParamDescription.java
rename to jdbc/src/main/java/tech/ydb/jdbc/query/params/ParamDescription.java
index a8d41b2..41922fc 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/ParamDescription.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/params/ParamDescription.java
@@ -1,4 +1,4 @@
-package tech.ydb.jdbc.impl.params;
+package tech.ydb.jdbc.query.params;
import java.sql.SQLException;
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/PreparedParams.java b/jdbc/src/main/java/tech/ydb/jdbc/query/params/PreparedParams.java
similarity index 86%
rename from jdbc/src/main/java/tech/ydb/jdbc/impl/params/PreparedParams.java
rename to jdbc/src/main/java/tech/ydb/jdbc/query/params/PreparedParams.java
index d76239d..597be96 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/PreparedParams.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/query/params/PreparedParams.java
@@ -1,6 +1,7 @@
-package tech.ydb.jdbc.impl.params;
+package tech.ydb.jdbc.query.params;
+import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -13,16 +14,16 @@
import tech.ydb.jdbc.YdbConst;
import tech.ydb.jdbc.common.TypeDescription;
-import tech.ydb.jdbc.impl.YdbJdbcParams;
import tech.ydb.table.query.Params;
import tech.ydb.table.values.Type;
import tech.ydb.table.values.Value;
+import tech.ydb.jdbc.query.JdbcParams;
/**
*
* @author Aleksandr Gorshenin
*/
-public class PreparedParams implements YdbJdbcParams {
+public class PreparedParams implements JdbcParams {
private final Map params;
private final String[] paramNames;
@@ -94,7 +95,7 @@ public void clearParameters() {
}
@Override
- public void addBatch() {
+ public void addBatch() throws SQLException {
batchList.add(getCurrentParams());
clearParameters();
}
@@ -114,14 +115,23 @@ public int batchSize() {
return batchList.size();
}
+ private Params validateParams(Map> values) throws SQLException {
+ for (String key: this.params.keySet()) {
+ if (!values.containsKey(key)) {
+ throw new SQLDataException(YdbConst.MISSING_VALUE_FOR_PARAMETER + key);
+ }
+ }
+ return Params.copyOf(values);
+ }
+
@Override
public List getBatchParams() {
return batchList;
}
@Override
- public Params getCurrentParams() {
- return Params.copyOf(paramValues);
+ public Params getCurrentParams() throws SQLException {
+ return validateParams(paramValues);
}
@Override
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/settings/PropertyConverter.java b/jdbc/src/main/java/tech/ydb/jdbc/settings/PropertyConverter.java
index 44f5358..ccbe86d 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/settings/PropertyConverter.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/settings/PropertyConverter.java
@@ -5,7 +5,6 @@
import java.time.format.DateTimeParseException;
import java.util.Locale;
-import tech.ydb.jdbc.exception.YdbConfigurationException;
interface PropertyConverter {
T convert(String value) throws SQLException;
@@ -31,7 +30,7 @@ static PropertyConverter durationValue() {
try {
return Duration.parse(targetValue);
} catch (DateTimeParseException e) {
- throw new YdbConfigurationException("Unable to parse value [" + value + "] -> [" +
+ throw new RuntimeException("Unable to parse value [" + value + "] -> [" +
targetValue + "] as Duration: " + e.getMessage(), e);
}
};
@@ -42,7 +41,7 @@ static PropertyConverter integerValue() {
try {
return Integer.valueOf(value);
} catch (NumberFormatException e) {
- throw new YdbConfigurationException("Unable to parse value [" + value + "] as Integer: " +
+ throw new RuntimeException("Unable to parse value [" + value + "] as Integer: " +
e.getMessage(), e);
}
};
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbJdbcTools.java b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbJdbcTools.java
index 80a9d4a..48515c5 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbJdbcTools.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbJdbcTools.java
@@ -14,7 +14,6 @@
import tech.ydb.core.utils.URITools;
import tech.ydb.jdbc.YdbConst;
-import tech.ydb.jdbc.exception.YdbConfigurationException;
/**
@@ -31,7 +30,7 @@ public static boolean isYdb(String url) {
public static YdbProperties from(String jdbcURL, Properties origProperties) throws SQLException {
if (!isYdb(jdbcURL)) {
String msg = "[" + jdbcURL + "] is not a YDB URL, must starts from " + YdbConst.JDBC_YDB_PREFIX;
- throw new YdbConfigurationException(msg);
+ throw new SQLException(msg);
}
try {
@@ -111,7 +110,7 @@ public static YdbProperties from(String jdbcURL, Properties origProperties) thro
return new YdbProperties(ydbConnectionProps, ydbClientProperties, ydbOperationProperties);
} catch (URISyntaxException | RuntimeException | UnsupportedEncodingException ex) {
- throw new YdbConfigurationException(ex.getMessage(), ex);
+ throw new SQLException(ex.getMessage(), ex);
}
}
@@ -130,16 +129,15 @@ public static YdbProperties from(String jdbcURL, Properties origProperties) thro
String stringValue = (String) value;
try {
parsed = new ParsedProperty(stringValue, converter.convert(stringValue));
- } catch (SQLException e) {
- throw new YdbConfigurationException("Unable to convert property " +
- title + ": " + e.getMessage(), e);
+ } catch (RuntimeException e) {
+ throw new SQLException("Unable to convert property " + title + ": " + e.getMessage(), e);
}
} else {
if (property.getType().isAssignableFrom(value.getClass())) {
parsed = new ParsedProperty("", value);
} else {
- throw new SQLException("Invalid object property " + title +
- ", must be " + property.getType() + ", got " + value.getClass());
+ throw new SQLException("Invalid object property " + title +", must be " + property.getType() +
+ ", got " + value.getClass());
}
}
} else {
@@ -147,9 +145,8 @@ public static YdbProperties from(String jdbcURL, Properties origProperties) thro
if (stringValue != null) {
try {
parsed = new ParsedProperty(stringValue, converter.convert(stringValue));
- } catch (SQLException e) {
- throw new YdbConfigurationException("Unable to convert property " +
- title + ": " + e.getMessage(), e);
+ } catch (RuntimeException e) {
+ throw new SQLException("Unable to convert property " + title + ": " + e.getMessage(), e);
}
} else {
parsed = null;
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperties.java b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperties.java
index 87ce018..4c18787 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperties.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperties.java
@@ -20,6 +20,7 @@ public class YdbOperationProperties {
private final int transactionLevel;
private final int maxRows;
private final boolean cacheConnectionsInDriver;
+ private final int preparedStatementCacheSize;
private final FakeTxMode scanQueryTxMode;
private final FakeTxMode schemeQueryTxMode;
@@ -38,6 +39,8 @@ public YdbOperationProperties(Map, ParsedProperty> param
this.transactionLevel = params.get(YdbOperationProperty.TRANSACTION_LEVEL).getParsedValue();
this.maxRows = MAX_ROWS;
this.cacheConnectionsInDriver = params.get(YdbOperationProperty.CACHE_CONNECTIONS_IN_DRIVER).getParsedValue();
+ this.preparedStatementCacheSize = Math.max(0,
+ params.get(YdbOperationProperty.PREPARED_STATEMENT_CACHE_SIZE).getParsedValue());
this.scanQueryTxMode = params.get(YdbOperationProperty.SCAN_QUERY_TX_MODE).getParsedValue();
this.schemeQueryTxMode = params.get(YdbOperationProperty.SCHEME_QUERY_TX_MODE).getParsedValue();
@@ -101,4 +104,8 @@ public int getMaxRows() {
public boolean isCacheConnectionsInDriver() {
return cacheConnectionsInDriver;
}
+
+ public int getPreparedStatementCacheSize() {
+ return preparedStatementCacheSize;
+ }
}
diff --git a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperty.java b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperty.java
index 8aef66c..3d414a9 100644
--- a/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperty.java
+++ b/jdbc/src/main/java/tech/ydb/jdbc/settings/YdbOperationProperty.java
@@ -87,6 +87,13 @@ public class YdbOperationProperty extends AbstractYdbProperty {
Boolean.class,
PropertyConverter.booleanValue());
+ public static final YdbOperationProperty PREPARED_STATEMENT_CACHE_SIZE =
+ new YdbOperationProperty<>("preparedStatementCacheQueries",
+ "Specifies the maximum number of entries in per-transport cache of prepared statements. "
+ + "A value of {@code 0} disables the cache.",
+ "256",
+ Integer.class,
+ PropertyConverter.integerValue());
public static final YdbOperationProperty DISABLE_DETECT_SQL_OPERATIONS =
new YdbOperationProperty<>("disableDetectSqlOperations",
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverExampleTest.java b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverExampleTest.java
index 52e12e5..87d9a10 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverExampleTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverExampleTest.java
@@ -137,8 +137,7 @@ public void testYdb() throws SQLException {
public void testYdbNotNull() throws SQLException {
try (Connection connection = DriverManager.getConnection(jdbcURL())) {
try {
- connection.createStatement()
- .execute("drop table table_sample");
+ connection.createStatement().execute("drop table table_sample");
} catch (SQLException e) {
//
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverProperitesTest.java b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverProperitesTest.java
index ca7a8a3..6177a04 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverProperitesTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverProperitesTest.java
@@ -29,7 +29,6 @@
import org.junit.jupiter.params.provider.MethodSource;
import tech.ydb.auth.AuthProvider;
-import tech.ydb.jdbc.exception.YdbConfigurationException;
import tech.ydb.jdbc.impl.helper.ExceptionAssert;
import tech.ydb.jdbc.settings.ParsedProperty;
import tech.ydb.jdbc.settings.YdbClientProperty;
@@ -51,7 +50,7 @@ public class YdbDriverProperitesTest {
private YdbDriver driver;
@BeforeAll
- public static void beforeAll() throws YdbConfigurationException, IOException {
+ public static void beforeAll() throws SQLException, IOException {
TOKEN_FILE = safeCreateFile(TOKEN_FROM_FILE);
CERTIFICATE_FILE = safeCreateFile(CERTIFICATE_FROM_FILE);
}
@@ -222,7 +221,10 @@ public void getTokenAs(String token, String expectValue) throws SQLException {
@MethodSource("unknownFiles")
public void getTokenAsInvalid(String token, String expectException) {
String url = "jdbc:ydb:ydb-demo.testhost.org:2135/test/db?token=" + token;
- ExceptionAssert.ydbConfiguration(expectException, () -> YdbJdbcTools.from(url, new Properties()));
+ ExceptionAssert.sqlException(
+ "Unable to convert property token: " + expectException,
+ () -> YdbJdbcTools.from(url, new Properties())
+ );
}
@ParameterizedTest(name = "[{index}] {1}")
@@ -246,14 +248,17 @@ public void getCaCertificateAs(String certificate, String expectValue) throws SQ
public void getCaCertificateAsInvalid(String certificate, String expectException) {
String url = "jdbc:ydb:ydb-demo.testhost.org:2135/test/db" +
"?secureConnectionCertificate=" + certificate;
- ExceptionAssert.ydbConfiguration(expectException, () -> YdbJdbcTools.from(url, new Properties()));
+ ExceptionAssert.sqlException(
+ "Unable to convert property secureConnectionCertificate: " + expectException,
+ () -> YdbJdbcTools.from(url, new Properties())
+ );
}
@ParameterizedTest
@MethodSource("invalidDurationParams")
public void invalidDuration(String param) {
String url = "jdbc:ydb:ydb-demo.testhost.org:2135/test/db?" + param + "=1bc";
- ExceptionAssert.ydbConfiguration("Unable to convert property " + param +
+ ExceptionAssert.sqlException("Unable to convert property " + param +
": Unable to parse value [1bc] -> [PT1BC] as Duration: Text cannot be parsed to a Duration",
() -> YdbJdbcTools.from(url, new Properties()));
}
@@ -262,7 +267,7 @@ public void invalidDuration(String param) {
@MethodSource("invalidIntegerParams")
public void invalidInteger(String param) {
String url = "jdbc:ydb:ydb-demo.testhost.org:2135/test/db?" + param + "=1bc";
- ExceptionAssert.ydbConfiguration("Unable to convert property " + param +
+ ExceptionAssert.sqlException("Unable to convert property " + param +
": Unable to parse value [1bc] as Integer: For input string: \"1bc\"",
() -> YdbJdbcTools.from(url, new Properties()));
}
@@ -323,6 +328,7 @@ static DriverPropertyInfo[] defaultPropertyInfo(@Nullable String localDatacenter
YdbOperationProperty.TRANSACTION_LEVEL.toDriverPropertyInfo("8"),
YdbOperationProperty.CACHE_CONNECTIONS_IN_DRIVER.toDriverPropertyInfo("true"),
+ YdbOperationProperty.PREPARED_STATEMENT_CACHE_SIZE.toDriverPropertyInfo("256"),
YdbOperationProperty.DISABLE_DETECT_SQL_OPERATIONS.toDriverPropertyInfo("false"),
YdbOperationProperty.DISABLE_PREPARE_DATAQUERY.toDriverPropertyInfo("false"),
@@ -363,6 +369,7 @@ static Properties customizedProperties() {
properties.setProperty("transactionLevel", "4");
properties.setProperty("cacheConnectionsInDriver", "false");
+ properties.setProperty("preparedStatementCacheQueries", "100");
properties.setProperty("disablePrepareDataQuery", "true");
properties.setProperty("disableAutoPreparedBatches", "true");
@@ -403,6 +410,7 @@ static DriverPropertyInfo[] customizedPropertyInfo() {
YdbOperationProperty.TRANSACTION_LEVEL.toDriverPropertyInfo("4"),
YdbOperationProperty.CACHE_CONNECTIONS_IN_DRIVER.toDriverPropertyInfo("false"),
+ YdbOperationProperty.PREPARED_STATEMENT_CACHE_SIZE.toDriverPropertyInfo("100"),
YdbOperationProperty.DISABLE_DETECT_SQL_OPERATIONS.toDriverPropertyInfo("true"),
YdbOperationProperty.DISABLE_PREPARE_DATAQUERY.toDriverPropertyInfo("true"),
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverStaticCredsTest.java b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverStaticCredsTest.java
index 3531d14..1e22e41 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverStaticCredsTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/YdbDriverStaticCredsTest.java
@@ -73,7 +73,7 @@ private void testConnection(ConnectionSupplier connectionSupplier) throws SQLExc
}
private void wrongConnection(ConnectionSupplier connectionSupplier) {
- ExceptionAssert.ydbConfiguration("Cannot connect to YDB: gRPC error: (INTERNAL) get token exception: "
+ ExceptionAssert.sqlException("Cannot connect to YDB: gRPC error: (INTERNAL) get token exception: "
+ "Can't login, code: UNAUTHORIZED, issues: [#400020 Invalid password (S_FATAL)]",
() -> testConnection(connectionSupplier));
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbConnectionImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbConnectionImplTest.java
index ec96d5a..ea5cfeb 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbConnectionImplTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbConnectionImplTest.java
@@ -249,7 +249,7 @@ public void invalidSQLCancelTransaction() throws SQLException {
String txId = getTxId(jdbc.connection());
Assertions.assertNotNull(txId);
- ExceptionAssert.ydbNonRetryable("Column reference 'x' (S_ERROR)", () -> statement.execute("select 2 + x"));
+ ExceptionAssert.ydbException("Column reference 'x' (S_ERROR)", () -> statement.execute("select 2 + x"));
statement.execute(SELECT_2_2);
Assertions.assertNotNull(getTxId(jdbc.connection()));
@@ -480,7 +480,7 @@ public void commitInvalidTx() throws SQLException {
statement.execute(SIMPLE_UPSERT);
statement.execute(SIMPLE_UPSERT);
- ExceptionAssert.ydbNonRetryable("Member not found: key2. Did you mean key?",
+ ExceptionAssert.ydbException("Member not found: key2. Did you mean key?",
() -> statement.executeQuery(QUERIES.wrongSelectSQL()));
Assertions.assertNull(getTxId(jdbc.connection()));
@@ -502,7 +502,7 @@ public void rollbackInvalidTx() throws SQLException {
statement.execute(SIMPLE_UPSERT);
- ExceptionAssert.ydbNonRetryable("Member not found: key2. Did you mean key?",
+ ExceptionAssert.ydbException("Member not found: key2. Did you mean key?",
() -> statement.executeQuery(QUERIES.wrongSelectSQL()));
Assertions.assertNull(getTxId(jdbc.connection()));
@@ -737,7 +737,6 @@ public void testAnsiLexerForIdea() throws SQLException {
@DisplayName("Check unsupported by storage type {arguments}")
@ParameterizedTest()
@ValueSource(strings = {
- "Uuid",
"TzDate",
"TzDatetime",
"TzTimestamp",
@@ -747,7 +746,7 @@ public void testUnsupportedByStorageTableTypes(String type) throws SQLException
String sql = "create table " + tableName + " (key Int32, payload " + type + ", primary key(key))";
try (Statement statement = jdbc.connection().createStatement()) {
- ExceptionAssert.ydbNonRetryable("is not supported by storage", () -> statement.execute(sql));
+ ExceptionAssert.ydbException("is not supported by storage", () -> statement.execute(sql));
}
}
@@ -763,7 +762,7 @@ public void testUnsupportedComplexTypes(String type) throws SQLException {
String sql = "create table " + tableName + " (key Int32, payload " + type + ", primary key(key))";
try (Statement statement = jdbc.connection().createStatement()) {
- ExceptionAssert.ydbNonRetryable("Invalid type for column: payload.",
+ ExceptionAssert.ydbException("Invalid type for column: payload.",
() -> statement.execute(sql));
}
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java
index 0346d12..3141948 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java
@@ -143,7 +143,6 @@ public void unknownColumns(SqlQueries.YqlQuery mode) throws SQLException {
statement.setInt("key", 1);
ExceptionAssert.sqlException("Parameter not found: column0", () -> statement.setObject("column0", "value"));
- statement.execute();
}
}
@@ -268,8 +267,8 @@ public void addAndClearBatch(SqlQueries.YqlQuery mode) throws SQLException {
public void executeEmptyBatch(SqlQueries.YqlQuery mode) throws SQLException {
String yql = TEST_TABLE.upsertOne(mode, "c_Text", "Text");
try (YdbPreparedStatement statement = jdbc.connection().unwrap(YdbConnection.class).prepareStatement(yql)) {
- ExceptionAssert.ydbNonRetryable("Missing value for parameter", () -> statement.execute());
- ExceptionAssert.ydbNonRetryable("Missing value for parameter", () -> statement.executeUpdate());
+ ExceptionAssert.sqlDataException("Missing value for parameter", () -> statement.execute());
+ ExceptionAssert.sqlDataException("Missing value for parameter", () -> statement.executeUpdate());
statement.executeBatch();
}
@@ -303,7 +302,7 @@ public void executeQueryBatchWithScanRead() throws SQLException {
}
}
- ExceptionAssert.ydbResultTruncated("Result #0 was truncated to 1000 rows", () -> {
+ ExceptionAssert.sqlException("Result #0 was truncated to 1000 rows", () -> {
// Result is truncated (and we catch that)
try (PreparedStatement select = prepareSimpleSelect("c_Text")) {
select.executeQuery();
@@ -427,7 +426,7 @@ public void executeScanQueryAsUpdate() throws SQLException {
statement.setInt("key", 1);
statement.setString("c_Text", "value-1");
- ExceptionAssert.ydbNonRetryable("Scan query should have a single result set",
+ ExceptionAssert.ydbException("Scan query should have a single result set",
statement::executeScanQuery);
}
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementTest.java
index fecd81c..f30c610 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementTest.java
@@ -1,12 +1,22 @@
package tech.ydb.jdbc.impl;
+import java.sql.Date;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
-
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
+
+import org.junit.Assert;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@@ -31,6 +41,13 @@ public class YdbPreparedStatementTest {
private static final SqlQueries TEST_TABLE = new SqlQueries("ydb_prepared_test");
+ private static final Instant INSTANT = Instant.ofEpochMilli(1585932011123l); // Friday, April 3, 2020 4:40:11.123 PM
+
+ // remove time part from instant in UTC
+ private static Instant calcStartDayUTC(Instant instant) {
+ return instant.atOffset(ZoneOffset.UTC).toLocalDate().atStartOfDay().toInstant(ZoneOffset.UTC);
+ }
+
@BeforeAll
public static void createTable() throws SQLException {
try (Statement statement = jdbc.connection().createStatement();) {
@@ -46,17 +63,12 @@ public static void dropTable() throws SQLException {
}
}
- @AfterEach
- public void afterEach() throws SQLException {
- if (jdbc.connection().isClosed()) {
- return;
- }
-
- try (Statement statement = jdbc.connection().createStatement()) {
+ @BeforeEach
+ public void beforaEach() throws SQLException {
+ try (Statement statement = jdbc.connection().createStatement();) {
+ // clean table
statement.execute(TEST_TABLE.deleteAllSQL());
}
-
- jdbc.connection().close();
}
@ParameterizedTest(name = "with {0}")
@@ -104,7 +116,7 @@ public void executeWithMissingParameter(SqlQueries.JdbcQuery query) throws SQLEx
try (PreparedStatement statement = jdbc.connection().prepareStatement(sql)) {
statement.setInt(1, 1);
- ExceptionAssert.ydbNonRetryable("Missing value for parameter", statement::execute);
+ ExceptionAssert.sqlDataException("Missing value for parameter", statement::execute);
}
}
@@ -198,4 +210,128 @@ public void batchUpsertTest(SqlQueries.JdbcQuery query) throws SQLException {
.noNextRows();
}
};
+
+ private void fillRowValues(PreparedStatement statement, int id) throws SQLException {
+ statement.setInt(1, id); // id
+
+ statement.setBoolean(2, id % 2 == 0); // c_Bool
+
+ statement.setByte(3, (byte)(id + 1)); // c_Int8
+ statement.setShort(4, (short)(id + 2)); // c_Int16
+ statement.setInt(5, id + 3); // c_Int32
+ statement.setLong(6, id + 4); // c_Int64
+
+ statement.setByte(7, (byte)(id + 5)); // c_Uint8
+ statement.setShort(8, (short)(id + 6)); // c_Uint16
+ statement.setInt(9, id + 7); // c_Uint32
+ statement.setLong(10, id + 8); // c_Uint64
+
+ statement.setFloat(11, 1.5f * id); // c_Float
+ statement.setDouble(12, 2.5d * id); // c_Double
+
+ statement.setBytes(13, new byte[] { (byte)id }); // c_Bytes
+ statement.setString(14, "Text_" + id); // c_Text
+ statement.setString(15, "{\"json\": " + id + "}"); // c_Json
+ statement.setString(16, "{\"jsonDoc\": " + id + "}"); // c_JsonDocument
+ statement.setString(17, "{yson=" + id + "}"); // c_Yson
+
+
+ Date sqlDate = new Date(calcStartDayUTC(INSTANT.plus(id, ChronoUnit.DAYS)).toEpochMilli());
+ LocalDateTime dateTime = LocalDateTime.ofInstant(INSTANT, ZoneOffset.UTC).plusMinutes(id);
+ Timestamp timestamp = Timestamp.from(INSTANT.plusSeconds(id));
+ Duration duration = Duration.ofMinutes(id);
+
+ statement.setDate(18, sqlDate); // c_Date
+ statement.setObject(19, dateTime); // c_Datetime
+ statement.setTimestamp(20, timestamp); // c_Timestamp
+ statement.setObject(21, duration); // c_Interval
+
+ statement.setNull(22, Types.DECIMAL); // c_Decimal
+ }
+
+ private void assertRowValues(ResultSet rs, int id) throws SQLException {
+ Assert.assertTrue(rs.next());
+
+ Assert.assertEquals(id, rs.getInt("key"));
+
+ Assert.assertEquals(id % 2 == 0, rs.getBoolean("c_Bool"));
+
+ Assert.assertEquals(id + 1, rs.getByte("c_Int8"));
+ Assert.assertEquals(id + 2, rs.getShort("c_Int16"));
+ Assert.assertEquals(id + 3, rs.getInt("c_Int32"));
+ Assert.assertEquals(id + 4, rs.getLong("c_Int64"));
+
+ Assert.assertEquals(id + 5, rs.getByte("c_Uint8"));
+ Assert.assertEquals(id + 6, rs.getShort("c_Uint16"));
+ Assert.assertEquals(id + 7, rs.getInt("c_Uint32"));
+ Assert.assertEquals(id + 8, rs.getLong("c_Uint64"));
+
+ Assert.assertEquals(1.5f * id, rs.getFloat("c_Float"), 0.001f);
+ Assert.assertEquals(2.5d * id, rs.getDouble("c_Double"), 0.001d);
+
+ Assert.assertArrayEquals(new byte[] { (byte)id }, rs.getBytes("c_Bytes"));
+ Assert.assertEquals("Text_" + id, rs.getString("c_Text"));
+ Assert.assertEquals("{\"json\": " + id + "}", rs.getString("c_Json"));
+ Assert.assertEquals("{\"jsonDoc\":" + id + "}", rs.getString("c_JsonDocument"));
+ Assert.assertEquals("{yson=" + id + "}", rs.getString("c_Yson"));
+
+
+ Date sqlDate = new Date(calcStartDayUTC(INSTANT.plus(id, ChronoUnit.DAYS)).toEpochMilli());
+ LocalDateTime dateTime = LocalDateTime.ofInstant(INSTANT, ZoneOffset.UTC).plusMinutes(id)
+ .truncatedTo(ChronoUnit.SECONDS);
+ Timestamp timestamp = Timestamp.from(INSTANT.plusSeconds(id));
+ Duration duration = Duration.ofMinutes(id);
+
+ Date rsDate = rs.getDate("c_Date");
+
+ Assert.assertEquals(sqlDate, rsDate);
+ Assert.assertEquals(dateTime, rs.getObject("c_Datetime"));
+ Assert.assertEquals(timestamp, rs.getTimestamp("c_Timestamp"));
+ Assert.assertEquals(duration, rs.getObject("c_Interval"));
+
+ Assert.assertNull(rs.getString("c_Decimal"));
+ Assert.assertTrue(rs.wasNull());
+ }
+
+ @ParameterizedTest(name = "with {0}")
+ @EnumSource(SqlQueries.JdbcQuery.class)
+ public void batchUpsertAllTest(SqlQueries.JdbcQuery query) throws SQLException {
+ String upsert = TEST_TABLE.upsertAll(query);
+
+ try (PreparedStatement statement = jdbc.connection().prepareStatement(upsert)) {
+ // ----- base usage -----
+ fillRowValues(statement, 1);
+ statement.addBatch();
+
+ fillRowValues(statement, 2);
+ statement.addBatch();
+
+ statement.executeBatch();
+
+ // ----- executeBatch without addBatch -----
+ fillRowValues(statement, 3);
+ statement.addBatch();
+
+ fillRowValues(statement, 4);
+ statement.executeBatch();
+
+ // ----- execute instead of executeBatch -----
+ fillRowValues(statement, 5);
+ statement.addBatch();
+
+ fillRowValues(statement, 6);
+ statement.execute();
+ }
+
+ try (Statement statement = jdbc.connection().createStatement()) {
+ try (ResultSet rs = statement.executeQuery(TEST_TABLE.selectSQL())) {
+ assertRowValues(rs, 1);
+ assertRowValues(rs, 2);
+ assertRowValues(rs, 3);
+ assertRowValues(rs, 6);
+
+ Assert.assertFalse(rs.next());
+ }
+ }
+ };
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryBatchedImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryBatchedImplTest.java
index 9f4d86e..924a6d4 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryBatchedImplTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryBatchedImplTest.java
@@ -119,7 +119,7 @@ private PreparedStatement prepareScanSelect(String column) throws SQLException {
@Test
public void testInvalidStruct() throws SQLException {
- ExceptionAssert.ydbNonRetryable("Duplicated member: key", () -> {
+ ExceptionAssert.ydbException("Duplicated member: key", () -> {
jdbc.connection().unwrap(YdbConnection.class).prepareStatement(
invalidBatchUpsertSql("c_Text", "Text"),
YdbPrepareMode.DATA_QUERY_BATCH);
@@ -283,7 +283,7 @@ public void executeQueryBatchWithScanRead() throws SQLException {
jdbc.connection().commit();
- ExceptionAssert.ydbResultTruncated("Result #0 was truncated to 1000 rows", () -> {
+ ExceptionAssert.sqlException("Result #0 was truncated to 1000 rows", () -> {
// Result is truncated (and we catch that)
try (PreparedStatement select = prepareSimpleSelect("c_Text")) {
select.executeQuery();
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java
index 17d6651..4d1e459 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java
@@ -119,7 +119,7 @@ public void executeWrongParameters() throws SQLException {
String sql = upsertSql("c_Text", "Text"); // Must be Text?
try (YdbPreparedStatement statement = jdbc.connection().unwrap(YdbConnection.class).prepareStatement(sql)) {
statement.setInt("key", 1);
- ExceptionAssert.ydbNonRetryable("Missing value for parameter", statement::execute);
+ ExceptionAssert.sqlDataException("Missing value for parameter", statement::execute);
}
try (YdbPreparedStatement statement = jdbc.connection().unwrap(YdbConnection.class).prepareStatement(sql)) {
@@ -290,7 +290,7 @@ public void executeScanQueryAsUpdate() throws SQLException {
statement.setInt("key", 1);
statement.setString("c_Text", "value-1");
- ExceptionAssert.ydbNonRetryable("Scan query should have a single result set", statement::execute);
+ ExceptionAssert.ydbException("Scan query should have a single result set", statement::execute);
}
}
}
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java
index fa5f231..e1d5417 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java
@@ -270,7 +270,7 @@ public void executeSchemeQueryExplicitly() throws SQLException {
statement.execute("create table scheme_query_test(id Int32, primary key(id))");
String dropSql = "scan drop table scheme_query_test";
- ExceptionAssert.ydbNonRetryable("Operation is not supported in current execution mode, check query type. ",
+ ExceptionAssert.ydbException("Operation is not supported in current execution mode, check query type. ",
() -> statement.unwrap(YdbStatement.class).executeQuery(dropSql));
statement.unwrap(YdbStatement.class).executeSchemeQuery(dropSql);
}
@@ -312,7 +312,7 @@ public void executeScanQueryOnSystemTable() throws SQLException {
@Test
public void executeScanQueryMultiResult() {
- ExceptionAssert.ydbNonRetryable("Scan query should have a single result set",
+ ExceptionAssert.ydbException("Scan query should have a single result set",
() -> statement.executeUpdate("scan select 2 + 2;scan select 2 + 3")
);
}
@@ -320,7 +320,7 @@ public void executeScanQueryMultiResult() {
@Test
public void executeScanQueryAsUpdate() {
// Looks weird
- ExceptionAssert.ydbNonRetryable("Scan query should have a single result set",
+ ExceptionAssert.ydbException("Scan query should have a single result set",
() -> statement.executeUpdate("SCAN\n" + TEST_UPSERT1_SQL)
);
}
@@ -360,10 +360,10 @@ public void executeQueryExplainAndExplicitly() throws SQLException {
public void getResultSet() throws SQLException {
Assertions.assertNull(statement.getResultSet());
- statement.execute("select 2 + 2");
+ Assertions.assertTrue(statement.execute("select 2 + 2"));
Assertions.assertNotNull(statement.getResultSet());
- statement.execute(TEST_UPSERT1_SQL);
+ Assertions.assertFalse(statement.execute(TEST_UPSERT1_SQL));
Assertions.assertNull(statement.getResultSet());
jdbc.connection().commit();
@@ -373,7 +373,7 @@ public void getResultSet() throws SQLException {
public void getUpdateCount() throws SQLException {
Assertions.assertEquals(-1, statement.getUpdateCount());
- statement.execute("select 2 + 2");
+ Assertions.assertTrue(statement.execute("select 2 + 2"));
Assertions.assertEquals(-1, statement.getUpdateCount());
statement.execute(TEST_UPSERT1_SQL);
@@ -384,9 +384,11 @@ public void getUpdateCount() throws SQLException {
statement.execute(TEST_UPSERT1_SQL + ";\n" + TEST_UPSERT2_SQL + ";");
Assertions.assertEquals(1, statement.getUpdateCount()); // just a single statement
Assertions.assertFalse(statement.getMoreResults());
+ Assertions.assertEquals(1, statement.getUpdateCount());
+ Assertions.assertFalse(statement.getMoreResults());
Assertions.assertEquals(-1, statement.getUpdateCount());
- statement.execute("select 2 + 2");
+ Assertions.assertTrue(statement.execute("select 2 + 2"));
Assertions.assertEquals(-1, statement.getUpdateCount());
jdbc.connection().commit();
@@ -413,12 +415,47 @@ public void getMoreResults() throws SQLException {
Assertions.assertNotSame(rs0, rs1);
Assertions.assertNotSame(rs0, rs2);
-
Assertions.assertSame(rs0, statement.unwrap(YdbStatement.class).getResultSetAt(0));
Assertions.assertSame(rs1, statement.unwrap(YdbStatement.class).getResultSetAt(1));
Assertions.assertSame(rs2, statement.unwrap(YdbStatement.class).getResultSetAt(2));
}
+ @Test
+ public void testMixedStatements() throws SQLException {
+ Assertions.assertTrue(statement.execute("select 2 + 1; " + TEST_UPSERT1_SQL + ";" + "select 2 + 3;"));
+
+ Assertions.assertEquals(-1, statement.getUpdateCount());
+
+ ResultSet rs0 = statement.getResultSet();
+
+ Assertions.assertFalse(statement.getMoreResults());
+ Assertions.assertEquals(1, statement.getUpdateCount());
+
+ Assertions.assertTrue(statement.getMoreResults());
+ Assertions.assertEquals(-1, statement.getUpdateCount());
+
+ ResultSet rs1 = statement.getResultSet();
+ Assertions.assertNotSame(rs0, rs1);
+
+ Assertions.assertFalse(statement.getMoreResults());
+ Assertions.assertEquals(-1, statement.getUpdateCount());
+ }
+
+ @Test
+ public void testSchemeStatements() throws SQLException {
+ Assertions.assertFalse(statement.execute("CREATE TABLE tmp_table (id Int32, primary key (id))"));
+ Assertions.assertEquals(0, statement.getUpdateCount());
+
+ Assertions.assertFalse(statement.getMoreResults());
+ Assertions.assertEquals(-1, statement.getUpdateCount());
+
+ Assertions.assertFalse(statement.execute("DROP TABLE tmp_table"));
+ Assertions.assertEquals(0, statement.getUpdateCount());
+
+ Assertions.assertFalse(statement.getMoreResults());
+ Assertions.assertEquals(-1, statement.getUpdateCount());
+ }
+
@Test
public void getMoreResultsDifferentMode() throws SQLException {
statement.execute("select 1 + 2; select 2 + 3; select 3 + 4");
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/ExceptionAssert.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/ExceptionAssert.java
index 0e59076..8911729 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/ExceptionAssert.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/ExceptionAssert.java
@@ -1,16 +1,14 @@
package tech.ydb.jdbc.impl.helper;
+import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLRecoverableException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
-import tech.ydb.jdbc.exception.YdbConditionallyRetryableException;
-import tech.ydb.jdbc.exception.YdbConfigurationException;
-import tech.ydb.jdbc.exception.YdbExecutionException;
-import tech.ydb.jdbc.exception.YdbNonRetryableException;
-import tech.ydb.jdbc.exception.YdbResultTruncatedException;
+import tech.ydb.jdbc.exception.YdbSQLException;
/**
*
@@ -19,42 +17,28 @@
public class ExceptionAssert {
private ExceptionAssert() { }
- public static void ydbConfiguration(String message, Executable exec) {
- YdbConfigurationException ex = Assertions.assertThrows(YdbConfigurationException.class, exec,
- "Invalid statement must throw YdbConfigurationException"
- );
- Assertions.assertEquals(message, ex.getMessage());
- }
-
- public static void ydbNonRetryable(String message, Executable exec) {
- YdbNonRetryableException ex = Assertions.assertThrows(YdbNonRetryableException.class, exec,
- "Invalid statement must throw YdbNonRetryableException"
+ public static void ydbException(String message, Executable exec) {
+ YdbSQLException ex = Assertions.assertThrows(YdbSQLException.class, exec,
+ "Invalid statement must throw YdbSQLException"
);
Assertions.assertTrue(ex.getMessage().contains(message),
"YdbNonRetryableException '" + ex.getMessage() + "' doesn't contain message '" + message + "'");
}
- public static void ydbExecution(String message, Executable exec) {
- YdbExecutionException ex = Assertions.assertThrows(YdbExecutionException.class, exec,
- "Invalid statement must throw YdbExecutionException"
- );
- Assertions.assertEquals(message, ex.getMessage());
- }
-
- public static void ydbResultTruncated(String message, Executable exec) {
- YdbResultTruncatedException ex = Assertions.assertThrows(YdbResultTruncatedException.class, exec,
- "Invalid statement must throw YdbExecutionException"
+ public static void sqlDataException(String message, Executable exec) {
+ SQLDataException ex = Assertions.assertThrows(SQLDataException.class, exec,
+ "Invalid statement must throw SQLDataException"
);
- Assertions.assertEquals(message, ex.getMessage());
+ Assertions.assertTrue(ex.getMessage().contains(message),
+ "SQLDataException '" + ex.getMessage() + "' doesn't contain message '" + message + "'");
}
- public static void ydbConditionallyRetryable(String message, Executable exec) {
- YdbConditionallyRetryableException ex = Assertions.assertThrows(YdbConditionallyRetryableException.class, exec,
- "Invalid statement must throw YdbConditionallyRetryableException"
+ public static void sqlRecoverable(String message, Executable exec) {
+ SQLRecoverableException ex = Assertions.assertThrows(SQLRecoverableException.class, exec,
+ "Invalid statement must throw SQLRecoverableException"
);
Assertions.assertTrue(ex.getMessage().contains(message),
- "YdbConditionallyRetryableException '" + ex.getMessage()
- + "' doesn't contain message '" + message + "'");
+ "SQLRecoverableException '" + ex.getMessage() + "' doesn't contain message '" + message + "'");
}
public static void sqlFeatureNotSupported(String message, Executable exec) {
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/SqlQueries.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/SqlQueries.java
index 6609e6a..67c2066 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/SqlQueries.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/SqlQueries.java
@@ -28,10 +28,12 @@ public enum YqlQuery {
private static final String SELECT = YdbLookup.stringFileReference("classpath:sql/select.sql");
- private static final String SIMPLE_UPSERT_ALL = YdbLookup.stringFileReference("classpath:sql/upsert/simple.sql");
- private static final String NAMED_UPSERT_ALL = YdbLookup.stringFileReference("classpath:sql/upsert/named.sql");
- private static final String BATCHED_UPSERT_ALL = YdbLookup.stringFileReference("classpath:sql/upsert/batched.sql");
- private static final String INDEXED_UPSERT_ALL = YdbLookup.stringFileReference("classpath:sql/upsert/types.sql");
+ private static final String SIMPLE_UPSERT = YdbLookup.stringFileReference("classpath:sql/upsert/simple.sql");
+ private static final String NAMED_UPSERT = YdbLookup.stringFileReference("classpath:sql/upsert/named.sql");
+ private static final String TYPED_UPSERT = YdbLookup.stringFileReference("classpath:sql/upsert/typed.sql");
+
+ private static final String NAMED_BATCH = YdbLookup.stringFileReference("classpath:sql/upsert/named_batch.sql");
+ private static final String TYPED_BATCH = YdbLookup.stringFileReference("classpath:sql/upsert/typed_batch.sql");
private static final String SELECT_ALL = "select * from #tableName";
private static final String DELETE_ALL = "delete from #tableName";
@@ -109,20 +111,24 @@ public String deleteAllSQL() {
public String namedUpsertAll(YqlQuery mode) {
switch (mode) {
case BATCHED:
- return withTableName(BATCHED_UPSERT_ALL, tableName);
+ return withTableName(NAMED_BATCH, tableName);
case SIMPLE:
default:
- return withTableName(NAMED_UPSERT_ALL, tableName);
+ return withTableName(NAMED_UPSERT, tableName);
}
}
- public String simpleUpsertAllSQL() {
- return withTableName(SIMPLE_UPSERT_ALL, tableName);
- }
-
- public String indexesUpsertAllSQL() {
- return withTableName(INDEXED_UPSERT_ALL, tableName);
+ public String upsertAll(JdbcQuery mode) {
+ switch (mode) {
+ case BATCHED:
+ return withTableName(TYPED_BATCH, tableName);
+ case TYPED:
+ return withTableName(TYPED_UPSERT, tableName);
+ case STANDART:
+ default:
+ return withTableName(SIMPLE_UPSERT, tableName);
+ }
}
/**
diff --git a/jdbc/src/test/java/tech/ydb/jdbc/query/QueryLexerTest.java b/jdbc/src/test/java/tech/ydb/jdbc/query/QueryLexerTest.java
index d3c2acc..80f9107 100644
--- a/jdbc/src/test/java/tech/ydb/jdbc/query/QueryLexerTest.java
+++ b/jdbc/src/test/java/tech/ydb/jdbc/query/QueryLexerTest.java
@@ -7,18 +7,20 @@
import org.junit.jupiter.api.Test;
+
/**
*
* @author Aleksandr Gorshenin
*/
public class QueryLexerTest {
-
- private QueryType parseQueryType(YdbQueryOptions opts, String sql) throws SQLException {
- return YdbQuery.from(opts, sql).type();
+ private static YdbQuery parseQuery(YdbQueryOptions opts, String sql) throws SQLException {
+ YdbQueryBuilder builder = new YdbQueryBuilder(sql, opts.getForcedQueryType());
+ JdbcQueryLexer.buildQuery(builder, opts);
+ return builder.build(opts);
}
- private String parseQuery(YdbQueryOptions opts, String sql) throws SQLException {
- return YdbQuery.from(opts, sql).getYqlQuery(null);
+ private static QueryType parsedQueryType(YdbQueryOptions opts, String sql) throws SQLException {
+ return parseQuery(opts, sql).type();
}
private void assertMixType(YdbQueryOptions opts, String types, String sql) {
@@ -33,44 +35,44 @@ private void assertMixType(YdbQueryOptions opts, String types, String sql) {
public void queryTypesTest() throws SQLException {
YdbQueryOptions opts = new YdbQueryOptions(true, false, false, false, false, null);
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"CREATE TABLE test_table (id int, value text)"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"\tcreate TABLE test_table2 (id int, value text);"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
" drop TABLE test_table1 (id int, value text);" +
"ALTER TABLE test_table2 (id int, value text);"
));
- Assertions.assertEquals(QueryType.DATA_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.DATA_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table"
));
- Assertions.assertEquals(QueryType.DATA_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.DATA_QUERY, parsedQueryType(opts,
"UPSERT INTO test_table VALUES (?, ?)"
));
- Assertions.assertEquals(QueryType.DATA_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.DATA_QUERY, parsedQueryType(opts,
"DELETE FROM test_table"
));
- Assertions.assertEquals(QueryType.DATA_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.DATA_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table;\n" +
"UPSERT INTO test_table VALUES (?, ?);" +
"DELETE FROM test_table"
));
- Assertions.assertEquals(QueryType.DATA_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.DATA_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table;\n" +
"UPDATE test_table SET value = ? WHERE id = ?;" +
"SELECT id, value FROM test_table WHERE id=CREATE"
));
- Assertions.assertEquals(QueryType.SCAN_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCAN_QUERY, parsedQueryType(opts,
"SCAN SELECT id, value FROM test_table"
));
- Assertions.assertEquals(QueryType.EXPLAIN_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.EXPLAIN_QUERY, parsedQueryType(opts,
"EXPLAIN SELECT id, value FROM test_table"
));
}
@@ -101,61 +103,61 @@ public void mixQueryExceptionTest() throws SQLException {
public void forsedTypeTest() throws SQLException {
YdbQueryOptions opts = new YdbQueryOptions(true, false, false, false, false, QueryType.SCHEME_QUERY);
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"CREATE TABLE test_table (id int, value text)"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"\tcreate TABLE test_table2 (id int, value text);"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
" drop TABLE test_table1 (id int, value text);" +
"ALTER TABLE test_table2 (id int, value text);"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"UPSERT INTO test_table VALUES (?, ?)"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"DELETE FROM test_table"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table;\n" +
"UPSERT INTO test_table VALUES (?, ?);" +
"DELETE FROM test_table"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SELECT id, value FROM test_table;\n" +
"UPDATE test_table SET value = ? WHERE id = ?;" +
"SELECT id, value FROM test_table WHERE id=CREATE"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SCAN SELECT id, value FROM test_table"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"EXPLAIN SELECT id, value FROM test_table"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"CREATE TABLE test_table (id int, value text);" +
"SELECT * FROM test_table;"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"DROP TABLE test_table (id int, value text);SELECT * FROM test_table;"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SELECT * FROM test_table;CREATE TABLE test_table (id int, value text);"
));
- Assertions.assertEquals(QueryType.SCHEME_QUERY, parseQueryType(opts,
+ Assertions.assertEquals(QueryType.SCHEME_QUERY, parsedQueryType(opts,
"SELECT * FROM test_table;\n\tCREATE TABLE test_table (id int, value text);"
));
}
diff --git a/jdbc/src/test/resources/sql/upsert/batched.sql b/jdbc/src/test/resources/sql/upsert/named_batch.sql
similarity index 100%
rename from jdbc/src/test/resources/sql/upsert/batched.sql
rename to jdbc/src/test/resources/sql/upsert/named_batch.sql
diff --git a/jdbc/src/test/resources/sql/upsert/simple.sql b/jdbc/src/test/resources/sql/upsert/simple.sql
index a05f87c..2abe87f 100644
--- a/jdbc/src/test/resources/sql/upsert/simple.sql
+++ b/jdbc/src/test/resources/sql/upsert/simple.sql
@@ -1,4 +1,4 @@
-upsert into #tableName (
+UPSERT INTO #tableName (
key,
c_Bool,
@@ -28,8 +28,33 @@ upsert into #tableName (
c_Interval,
c_Decimal
-) values (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
- ?, ?, ?, ?, ?, ?, ?, ? ,? ,?,
- ?, ?
+) VALUES (
+ ?, -- key
+ ?, -- c_Bool
+
+ CAST(? AS Int8), -- c_Int8
+ CAST(? AS Int16), -- c_Int16
+ ?, -- c_Int32
+ ?, -- c_Int64
+
+ CAST(? AS Uint8), -- c_Uint8
+ CAST(? AS Uint16), -- c_Uint16
+ CAST(? AS Uint32), -- c_Uint32
+ CAST(? AS Uint64), -- c_Uint64
+
+ ?, -- c_Float
+ ?, -- c_Double
+
+ ?, -- c_Bytes
+ ?, -- c_Text
+ CAST(? AS Json), -- c_Json
+ CAST(? AS JsonDocument), -- c_JsonDocument
+ CAST(? AS Yson), -- c_Yson
+
+ ?, -- c_Date
+ ?, -- c_Datetime
+ ?, -- c_Timestamp
+ ?, -- c_Interval
+
+ ? -- c_Decimal
)
\ No newline at end of file
diff --git a/jdbc/src/test/resources/sql/upsert/types.sql b/jdbc/src/test/resources/sql/upsert/typed.sql
similarity index 99%
rename from jdbc/src/test/resources/sql/upsert/types.sql
rename to jdbc/src/test/resources/sql/upsert/typed.sql
index fd17536..0bba3a0 100644
--- a/jdbc/src/test/resources/sql/upsert/types.sql
+++ b/jdbc/src/test/resources/sql/upsert/typed.sql
@@ -80,5 +80,5 @@ upsert into #tableName (
$p19,
$p20,
$p21,
- $p22,
+ $p22
)
\ No newline at end of file
diff --git a/jdbc/src/test/resources/sql/upsert/typed_batch.sql b/jdbc/src/test/resources/sql/upsert/typed_batch.sql
new file mode 100644
index 0000000..d8ed1c8
--- /dev/null
+++ b/jdbc/src/test/resources/sql/upsert/typed_batch.sql
@@ -0,0 +1,63 @@
+declare $list as List,
+
+ p3:Optional,
+ p4:Optional,
+ p5:Optional,
+ p6:Optional,
+
+ p7:Optional,
+ p8:Optional,
+ p9:Optional,
+ p10:Optional,
+
+ p11:Optional,
+ p12:Optional,
+
+ p13:Optional,
+ p14:Optional,
+ p15:Optional,
+ p16:Optional,
+ p17:Optional,
+
+ p18:Optional,
+ p19:Optional,
+ p20:Optional,
+ p21:Optional,
+
+ p22:Optional
+>>;
+
+upsert into #tableName select
+ p1 as key,
+
+ p2 as c_Bool,
+
+ p3 as c_Int8,
+ p4 as c_Int16,
+ p5 as c_Int32,
+ p6 as c_Int64,
+
+ p7 as c_Uint8,
+ p8 as c_Uint16,
+ p9 as c_Uint32,
+ p10 as c_Uint64,
+
+ p11 as c_Float,
+ p12 as c_Double,
+
+ p13 as c_Bytes,
+ p14 as c_Text,
+ p15 as c_Json,
+ p16 as c_JsonDocument,
+ p17 as c_Yson,
+
+ p18 as c_Date,
+ p19 as c_Datetime,
+ p20 as c_Timestamp,
+ p21 as c_Interval,
+
+ p22 as c_Decimal
+from as_table($list);
diff --git a/pom.xml b/pom.xml
index 8bf8336..8cc503b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
tech.ydb.jdbc
ydb-jdbc-driver-parent
- 2.0.3
+ 2.0.4
YDB JDBC Module
JDBC Driver over YDB Java SDK