diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5246b15..8e192a7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -5,6 +5,7 @@ on: branches: - master - develop + - release* pull_request: type: [opened, reopened, edited] diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c48351..58e1c2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.3 ## + +* Added SqlState info to YDB exceptions +* Fixed getUpdateCount() after getMoreResults() +* Fixed columns info for empty result sets from DatabaseMetaData + ## 2.0.2 ## * Removed obsolete options diff --git a/README.md b/README.md index 56ac6d8..d89b98e 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ Specify the YDB JDBC driver in the dependencies: tech.ydb.jdbc ydb-jdbc-driver - 2.0.0 + 2.0.3 tech.ydb.jdbc ydb-jdbc-driver-shaded - 2.0.0 + 2.0.3 ``` diff --git a/jdbc-shaded/pom.xml b/jdbc-shaded/pom.xml index 7f15645..b2b3b58 100644 --- a/jdbc-shaded/pom.xml +++ b/jdbc-shaded/pom.xml @@ -6,7 +6,7 @@ tech.ydb.jdbc ydb-jdbc-driver-parent - 2.0.2 + 2.0.3 ydb-jdbc-driver-shaded diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 1ce204c..009e3ae 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -6,7 +6,7 @@ tech.ydb.jdbc ydb-jdbc-driver-parent - 2.0.2 + 2.0.3 ydb-jdbc-driver diff --git a/jdbc/src/main/java/tech/ydb/jdbc/common/FixedResultSetFactory.java b/jdbc/src/main/java/tech/ydb/jdbc/common/FixedResultSetFactory.java new file mode 100644 index 0000000..4bccb52 --- /dev/null +++ b/jdbc/src/main/java/tech/ydb/jdbc/common/FixedResultSetFactory.java @@ -0,0 +1,465 @@ +package tech.ydb.jdbc.common; + +import java.nio.charset.Charset; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import tech.ydb.table.result.ResultSetReader; +import tech.ydb.table.result.ValueReader; +import tech.ydb.table.values.DecimalValue; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.table.values.Type; +import tech.ydb.table.values.Value; + +/** + * + * @author Aleksandr Gorshenin + */ +public class FixedResultSetFactory { + private final List columns; + private final Map columnIndexes; + + private FixedResultSetFactory(List columns) { + this.columns = columns; + this.columnIndexes = new HashMap<>(); + for (int idx = 0; idx < columns.size(); idx += 1) { + columnIndexes.put(columns.get(idx).name, idx); + } + } + + public interface ResultSetBuilder { + public interface RowBuilder { + RowBuilder withTextValue(String name, String value); + RowBuilder withIntValue(String name, int value); + RowBuilder withShortValue(String name, short value); + RowBuilder withLongValue(String name, long value); + RowBuilder withBoolValue(String name, boolean value); + + ResultSetBuilder build(); + } + + RowBuilder newRow(); + ResultSetReader build(); + } + + public ResultSetBuilder createResultSet() { + return new ResultSetBuilderImpl(); + } + + private class ResultSetBuilderImpl implements ResultSetBuilder { + private final List> rows = new ArrayList<>(); + + private class RowImpl implements RowBuilder { + private final Map values = new HashMap<>(); + + @Override + public RowBuilder withTextValue(String name, String value) { + Column column = columns.get(columnIndexes.get(name)); + if (value != null) { + values.put(column, new FixedValueReader(PrimitiveValue.newText(value), column.type)); + } + return this; + } + + @Override + public RowBuilder withIntValue(String name, int value) { + Column column = columns.get(columnIndexes.get(name)); + values.put(column, new FixedValueReader(PrimitiveValue.newInt32(value), column.type)); + return this; + } + + @Override + public RowBuilder withShortValue(String name, short value) { + Column column = columns.get(columnIndexes.get(name)); + values.put(column, new FixedValueReader(PrimitiveValue.newInt16(value), column.type)); + return this; + } + + @Override + public RowBuilder withLongValue(String name, long value) { + Column column = columns.get(columnIndexes.get(name)); + values.put(column, new FixedValueReader(PrimitiveValue.newInt64(value), column.type)); + return this; + } + + @Override + public RowBuilder withBoolValue(String name, boolean value) { + Column column = columns.get(columnIndexes.get(name)); + values.put(column, new FixedValueReader(PrimitiveValue.newBool(value), column.type)); + return this; + } + + @Override + public ResultSetBuilder build() { + // init null values + for (Column column: columns) { + if (!values.containsKey(column)) { + values.put(column, new FixedValueReader(null, column.type)); + } + } + rows.add(this.values); + return ResultSetBuilderImpl.this; + } + } + + + @Override + public RowBuilder newRow() { + return new RowImpl(); + } + + @Override + public ResultSetReader build() { + return new FixedResultSet(rows); + } + } + + private class FixedResultSet implements ResultSetReader { + private final List> rows; + private int rowIndex = 0; + + public FixedResultSet(List> rows) { + this.rows = rows; + } + + @Override + public boolean isTruncated() { + return false; + } + + @Override + public int getColumnCount() { + return columns.size(); + } + + @Override + public int getRowCount() { + return rows.size(); + } + + @Override + public void setRowIndex(int index) { + rowIndex = index; + } + + @Override + public boolean next() { + if (rowIndex >= rows.size()) { + return false; + } + rowIndex += 1; + return true; + } + + @Override + public String getColumnName(int index) { + return columns.get(index).name; + } + + @Override + public int getColumnIndex(String name) { + return columnIndexes.get(name); + } + + @Override + public ValueReader getColumn(int index) { + return rows.get(rowIndex).get(columns.get(index)); + } + + @Override + public ValueReader getColumn(String name) { + return rows.get(rowIndex).get(columns.get(columnIndexes.get(name))); + } + + @Override + public Type getColumnType(int index) { + return columns.get(index).type; + } + } + + private static class Column { + private final String name; + private final Type type; + + public Column(String name, Type type) { + this.name = name; + this.type = type; + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private final List columns = new ArrayList<>(); + + public Builder addTextColumn(String name) { + columns.add(new Column(name, PrimitiveType.Text.makeOptional())); + return this; + } + + public Builder addIntColumn(String name) { + columns.add(new Column(name, PrimitiveType.Int32.makeOptional())); + return this; + } + + public Builder addShortColumn(String name) { + columns.add(new Column(name, PrimitiveType.Int16.makeOptional())); + return this; + } + + public Builder addLongColumn(String name) { + columns.add(new Column(name, PrimitiveType.Int64.makeOptional())); + return this; + } + + public Builder addBooleanColumn(String name) { + columns.add(new Column(name, PrimitiveType.Bool.makeOptional())); + return this; + } + + public FixedResultSetFactory build() { + return new FixedResultSetFactory(columns); + } + } + + private static class FixedValueReader implements ValueReader { + private final PrimitiveValue value; + private final Type type; + + public FixedValueReader(PrimitiveValue value, Type type) { + this.value = value; + this.type = type; + } + + @Override + public boolean getBool() { + return value.getBool(); + } + + @Override + public byte getInt8() { + return value.getInt8(); + } + + @Override + public int getUint8() { + return value.getUint8(); + } + + @Override + public short getInt16() { + return value.getInt16(); + } + + @Override + public int getUint16() { + return value.getUint16(); + } + + @Override + public int getInt32() { + return value.getInt32(); + } + + @Override + public long getUint32() { + return value.getUint32(); + } + + @Override + public long getInt64() { + return value.getInt64(); + } + + @Override + public long getUint64() { + return value.getUint64(); + } + + @Override + public float getFloat() { + return value.getFloat(); + } + + @Override + public double getDouble() { + return value.getDouble(); + } + + @Override + public LocalDate getDate() { + return value.getDate(); + } + + @Override + public LocalDateTime getDatetime() { + return value.getDatetime(); + } + + @Override + public Instant getTimestamp() { + return value.getTimestamp(); + } + + @Override + public Duration getInterval() { + return value.getInterval(); + } + + @Override + public ZonedDateTime getTzDate() { + return value.getTzDate(); + } + + @Override + public ZonedDateTime getTzDatetime() { + return value.getTzDatetime(); + } + + @Override + public ZonedDateTime getTzTimestamp() { + return value.getTzTimestamp(); + } + + @Override + public byte[] getBytes() { + return value.getBytes(); + } + + @Override + public String getBytesAsString(Charset charset) { + return value.getBytesAsString(charset); + } + + @Override + public UUID getUuid() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getText() { + return value.getText(); + } + + @Override + public byte[] getYson() { + return value.getYson(); + } + + @Override + public String getJson() { + return value.getJson(); + } + + @Override + public String getJsonDocument() { + return value.getJsonDocument(); + } + + @Override + public DecimalValue getDecimal() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(value.toString()); + } + + @Override + public Value getValue() { + return value; + } + + @Override + public Type getType() { + return type; + } + + @Override + public boolean isOptionalItemPresent() { + return value != null; + } + + @Override + public ValueReader getOptionalItem() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getTupleElementsCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getTupleElement(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getListItemsCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getListItem(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getDictItemsCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getDictKey(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getDictValue(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getStructMembersCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getStructMemberName(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getStructMember(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getStructMember(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getVariantTypeIndex() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueReader getVariantItem() { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/jdbc/src/main/java/tech/ydb/jdbc/common/MappingResultSets.java b/jdbc/src/main/java/tech/ydb/jdbc/common/MappingResultSets.java deleted file mode 100644 index ef3f81c..0000000 --- a/jdbc/src/main/java/tech/ydb/jdbc/common/MappingResultSets.java +++ /dev/null @@ -1,94 +0,0 @@ -package tech.ydb.jdbc.impl; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import com.google.common.base.Preconditions; -import com.google.protobuf.NullValue; - -import tech.ydb.jdbc.exception.YdbRuntimeException; -import tech.ydb.proto.ValueProtos; -import tech.ydb.proto.ValueProtos.Type.PrimitiveTypeId; -import tech.ydb.table.result.ResultSetReader; -import tech.ydb.table.result.impl.ProtoValueReaders; - -public class MappingResultSets { - - private MappingResultSets() { - // - } - - @SuppressWarnings("unchecked") - public static LinkedHashMap stableMap(K key, Object value, Object... kv) { - Preconditions.checkArgument((kv.length & 1) == 0, "KeyValue list must be even"); - - LinkedHashMap map = new LinkedHashMap<>((kv.length / 2) + 1); - map.put(key, value); - for (int i = 0; i < kv.length; i += 2) { - map.put((K) kv[i], kv[i + 1]); - } - - return map; - } - - public static ResultSetReader readerFromList(List> list) { - if (list.isEmpty()) { - return emptyReader(); - } - ValueProtos.ResultSet.Builder resultSet = ValueProtos.ResultSet.newBuilder(); - for (Map.Entry entry : list.iterator().next().entrySet()) { - ValueProtos.Type.Builder itemBuilder = resultSet.addColumnsBuilder() - .setName(entry.getKey()) - .getTypeBuilder() - .getOptionalTypeBuilder() - .getItemBuilder(); - Object value = entry.getValue(); - if (value == null || value instanceof String) { - itemBuilder.setTypeId(PrimitiveTypeId.UTF8); - } else if (value instanceof Integer) { - itemBuilder.setTypeId(PrimitiveTypeId.INT32); - } else if (value instanceof Short) { - itemBuilder.setTypeId(PrimitiveTypeId.INT16); - } else if (value instanceof Boolean) { - itemBuilder.setTypeId(PrimitiveTypeId.BOOL); - } else { - throw new YdbRuntimeException("Internal error. Unsupported YDB type: " + value); - } - } - - for (Map map : list) { - ValueProtos.Value.Builder row = resultSet.addRowsBuilder(); - for (Map.Entry entry : map.entrySet()) { - ValueProtos.Value.Builder item = row.addItemsBuilder(); - Object value = entry.getValue(); - if (value == null) { - item.setNullFlagValue(NullValue.NULL_VALUE); - } else if (value instanceof String) { - item.setTextValue((String) value); - } else if (value instanceof Integer) { - item.setInt32Value((Integer) value); - } else if (value instanceof Short) { - item.setInt32Value((Short) value); - } else if (value instanceof Boolean) { - item.setBoolValue((Boolean) value); - } else { - throw new YdbRuntimeException("Internal error. Unsupported YDB type: " + value); - } - } - } - return ProtoValueReaders.forResultSet(resultSet.build()); - - } - - public static ResultSetReader readerFromMap(Map map) { - return readerFromList(Collections.singletonList(map)); - } - - public static ResultSetReader emptyReader() { - ValueProtos.ResultSet.Builder resultSet = ValueProtos.ResultSet.newBuilder(); - return ProtoValueReaders.forResultSet(resultSet.build()); - } - -} 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 b589465..d0784ba 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/context/YdbExecutor.java @@ -16,10 +16,8 @@ import tech.ydb.core.Issue; import tech.ydb.core.Result; import tech.ydb.core.Status; -import tech.ydb.jdbc.exception.YdbConditionallyRetryableException; import tech.ydb.jdbc.exception.YdbExecutionException; -import tech.ydb.jdbc.exception.YdbNonRetryableException; -import tech.ydb.jdbc.exception.YdbRetryableException; +import tech.ydb.jdbc.exception.YdbStatusException; import tech.ydb.table.Session; /** @@ -119,67 +117,8 @@ private void simpleExecute(Supplier> supplier) throws private void validate(String message, Status status) throws SQLException { issues.addAll(Arrays.asList(status.getIssues())); - - switch (status.getCode()) { - case SUCCESS: - return; - - case BAD_REQUEST: - case INTERNAL_ERROR: - case CLIENT_UNAUTHENTICATED: - // gRPC reports, request is not authenticated - // Maybe internal error, maybe some issue with token - case UNAUTHORIZED: - // Unauthorized by database - case SCHEME_ERROR: - case GENERIC_ERROR: - case CLIENT_CALL_UNIMPLEMENTED: - case UNSUPPORTED: - case UNUSED_STATUS: - case ALREADY_EXISTS: - throw new YdbNonRetryableException(message, status.getCode()); - - case ABORTED: - case UNAVAILABLE: - // Some of database parts are not available - case OVERLOADED: - // Database is overloaded, need to retry with exponential backoff - case TRANSPORT_UNAVAILABLE: - // Some issues with networking - case CLIENT_RESOURCE_EXHAUSTED: - // No resources to handle client request - case NOT_FOUND: - // Could be 'prepared query' issue, could be 'transaction not found' - // Should be retries with new session - case BAD_SESSION: - // Retry with new session - case SESSION_EXPIRED: - // Retry with new session - throw new YdbRetryableException(message, status.getCode()); - - case CANCELLED: - // Query was canceled due to query timeout (CancelAfter) - // Query was definitely canceled by database - case CLIENT_CANCELLED: - case CLIENT_INTERNAL_ERROR: - // Some unknown client side error, probably on transport layer - throw new YdbConditionallyRetryableException(message, status.getCode()); - - case UNDETERMINED: - case TIMEOUT: - // Database cannot respond in time, need to retry with exponential backoff - case PRECONDITION_FAILED: - case CLIENT_DEADLINE_EXCEEDED: - // Query was canceled on transport layer - case SESSION_BUSY: - // Another query is executing already, retry with new session - case CLIENT_DISCOVERY_FAILED: - // Some issue with database endpoints discovery - case CLIENT_LIMITS_REACHED: - // Client side session limit was reached - throw new YdbConditionallyRetryableException(message, status.getCode()); - default: - throw new YdbNonRetryableException(message, status.getCode()); + if (!status.isSuccess()) { + throw YdbStatusException.newException(message, status); } } } 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 4916fe5..599e60d 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,12 @@ package tech.ydb.jdbc.exception; -import tech.ydb.core.StatusCode; +import tech.ydb.core.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 = 1135970796364528563L; + private static final long serialVersionUID = -2371144941971339449L; - public YdbConditionallyRetryableException(String message, StatusCode statusCode) { - super(message, statusCode); + YdbConditionallyRetryableException(String message, String sqlState, Status status) { + super(message, sqlState, status); } } diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionStatusException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionStatusException.java deleted file mode 100644 index 720cc11..0000000 --- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbExecutionStatusException.java +++ /dev/null @@ -1,18 +0,0 @@ -package tech.ydb.jdbc.exception; - -import tech.ydb.core.StatusCode; - -public class YdbExecutionStatusException extends YdbExecutionException { - private static final long serialVersionUID = 4476269562160877309L; - - private final StatusCode statusCode; - - public YdbExecutionStatusException(String message, StatusCode statusCode) { - super(message, null, statusCode.getCode()); - this.statusCode = statusCode; - } - - public StatusCode getStatusCode() { - return statusCode; - } -} diff --git a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java index daa6c3d..8044984 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbNonRetryableException.java @@ -1,11 +1,11 @@ package tech.ydb.jdbc.exception; -import tech.ydb.core.StatusCode; +import tech.ydb.core.Status; -public class YdbNonRetryableException extends YdbExecutionStatusException { - private static final long serialVersionUID = 1170815831963616837L; +public class YdbNonRetryableException extends YdbStatusException { + private static final long serialVersionUID = 687247673341671225L; - public YdbNonRetryableException(String message, StatusCode statusCode) { - super(message, statusCode); + YdbNonRetryableException(String message, String sqlState, Status status) { + super(message, sqlState, status); } } 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 20bbd72..ed1b922 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,11 @@ package tech.ydb.jdbc.exception; -import tech.ydb.core.StatusCode; +import tech.ydb.core.Status; -public class YdbRetryableException extends YdbExecutionStatusException { - private static final long serialVersionUID = 688604408491567864L; +public class YdbRetryableException extends YdbStatusException { + private static final long serialVersionUID = 2082287790625648960L; - public YdbRetryableException(String message, StatusCode statusCode) { - super(message, statusCode); + YdbRetryableException(String message, String sqlState, Status status) { + super(message, sqlState, 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 new file mode 100644 index 0000000..4edb87b --- /dev/null +++ b/jdbc/src/main/java/tech/ydb/jdbc/exception/YdbStatusException.java @@ -0,0 +1,40 @@ +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 14d1054..3ed75ad 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/BaseYdbStatement.java @@ -8,9 +8,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.logging.Logger; @@ -18,6 +16,7 @@ import tech.ydb.jdbc.YdbConst; import tech.ydb.jdbc.YdbResultSet; 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.YdbQuery; @@ -39,6 +38,11 @@ public abstract class BaseYdbStatement implements YdbStatement { protected static final ResultState EMPTY_STATE = new ResultState(); + private static FixedResultSetFactory EXPLAIN_RS_FACTORY = FixedResultSetFactory.newBuilder() + .addTextColumn(YdbConst.EXPLAIN_COLUMN_AST) + .addTextColumn(YdbConst.EXPLAIN_COLUMN_PLAN) + .build(); + private final YdbConnection connection; private final YdbExecutor executor; private final YdbQueryOptions queryOptions; @@ -177,10 +181,12 @@ protected void executeSchemeQuery(YdbQuery query) throws SQLException { protected ResultState executeExplainQuery(YdbQuery query) throws SQLException { ExplainDataQueryResult explainDataQuery = connection.executeExplainQuery(query, executor); - Map row = new HashMap<>(); - row.put(YdbConst.EXPLAIN_COLUMN_AST, explainDataQuery.getQueryAst()); - row.put(YdbConst.EXPLAIN_COLUMN_PLAN, explainDataQuery.getQueryPlan()); - ResultSetReader result = MappingResultSets.readerFromMap(row); + ResultSetReader result = EXPLAIN_RS_FACTORY.createResultSet() + .newRow() + .withTextValue(YdbConst.EXPLAIN_COLUMN_AST, explainDataQuery.getQueryAst()) + .withTextValue(YdbConst.EXPLAIN_COLUMN_PLAN, explainDataQuery.getQueryPlan()) + .build() + .build(); List list = Collections.singletonList(new YdbResultSetImpl(this, result)); return new ResultState(list); @@ -297,16 +303,13 @@ public int getResultSetConcurrency() { protected static class ResultState { private final List results; private int resultSetIndex; - private final int updateCount; private ResultState() { results = null; resultSetIndex = -1; - updateCount = -1; } private ResultState(List list) { - updateCount = (list == null || list.isEmpty()) ? 1 : -1; // TODO: Get update count? results = list; resultSetIndex = 0; } @@ -315,8 +318,9 @@ public boolean hasResultSets() { return results != null && !results.isEmpty(); } + // TODO: YDB doesn't return the count of affected rows, so we use little hach to return always 1 public int getUpdateCount() { - return updateCount; + return (results != null && results.isEmpty() && resultSetIndex == 0) ? 1 : -1; } public YdbResultSet getCurrentResultSet() throws SQLException { @@ -336,6 +340,7 @@ public YdbResultSet getResultSet(int index) throws SQLException { public boolean getMoreResults(int current) throws SQLException { if (results == null || results.isEmpty()) { + resultSetIndex = -1; // reset updateCount return false; } diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/MetaDataTables.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/MetaDataTables.java new file mode 100644 index 0000000..b706022 --- /dev/null +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/MetaDataTables.java @@ -0,0 +1,416 @@ +package tech.ydb.jdbc.impl; + +import java.sql.DatabaseMetaData; + +import tech.ydb.jdbc.common.FixedResultSetFactory; + +/** + * + * @author Aleksandr Gorshenin + */ +public class MetaDataTables { + /** + * @see DatabaseMetaData#getProcedures(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory PROCEDURES = FixedResultSetFactory.newBuilder() + .addTextColumn("PROCEDURE_CAT") + .addTextColumn("PROCEDURE_SCHEM") + .addTextColumn("PROCEDURE_NAME") + .addTextColumn("reserved1") + .addTextColumn("reserved2") + .addTextColumn("reserved3") + .addTextColumn("REMARKS") + .addShortColumn("PROCEDURE_TYPE") + .addTextColumn("SPECIFIC_NAME") + .build(); + + /** + * @see DatabaseMetaData#getProcedureColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory PROCEDURE_COLUMNS = FixedResultSetFactory.newBuilder() + .addTextColumn("PROCEDURE_CAT") + .addTextColumn("PROCEDURE_SCHEM") + .addTextColumn("PROCEDURE_NAME") + .addTextColumn("COLUMN_NAME") + .addTextColumn("COLUMN_TYPE") + .addIntColumn("DATA_TYPE") + .addTextColumn("TYPE_NAME") + .addIntColumn("PRECISION") + .addIntColumn("LENGTH") + .addShortColumn("SCALE") + .addShortColumn("RADIX") + .addShortColumn("NULLABLE") + .addTextColumn("REMARKS") + .addTextColumn("COLUMN_DEF") + .addIntColumn("SQL_DATA_TYPE") + .addIntColumn("SQL_DATETIME_SUB") + .addIntColumn("CHAR_OCTET_LENGTH") + .addIntColumn("ORDINAL_POSITION") + .addTextColumn("IS_NULLABLE") + .addTextColumn("SPECIFIC_NAME") + .build(); + + /** + * @see DatabaseMetaData#getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) + */ + public final static FixedResultSetFactory TABLES = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("TABLE_TYPE") + .addTextColumn("REMARKS") + .addTextColumn("TYPE_CAT") + .addTextColumn("TYPE_SCHEM") + .addTextColumn("TYPE_NAME") + .addTextColumn("SELF_REFERENCING_COL_NAME") + .addTextColumn("REF_GENERATION") + .build(); + + /** + * @see DatabaseMetaData#getCatalogs() + */ + public final static FixedResultSetFactory CATALOGS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .build(); + + /** + * @see DatabaseMetaData#getTableTypes() + */ + public final static FixedResultSetFactory TABLE_TYPES = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_TYPE") + .build(); + + /** + * @see DatabaseMetaData#getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory COLUMNS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("COLUMN_NAME") + .addIntColumn("DATA_TYPE") + .addTextColumn("TYPE_NAME") + .addIntColumn("COLUMN_SIZE") + .addIntColumn("BUFFER_LENGTH") + .addIntColumn("DECIMAL_DIGITS") + .addIntColumn("NUM_PREC_RADIX") + .addIntColumn("NULLABLE") + .addTextColumn("REMARKS") + .addTextColumn("COLUMN_DEF") + .addIntColumn("SQL_DATA_TYPE") + .addIntColumn("SQL_DATETIME_SUB") + .addIntColumn("CHAR_OCTET_LENGTH") + .addIntColumn("ORDINAL_POSITION") + .addTextColumn("IS_NULLABLE") + .addTextColumn("SCOPE_CATALOG") + .addTextColumn("SCOPE_SCHEMA") + .addTextColumn("SCOPE_TABLE") + .addShortColumn("SOURCE_DATA_TYPE") + .addTextColumn("IS_AUTOINCREMENT") + .addTextColumn("IS_GENERATEDCOLUMN") + .build(); + + /** + * @see DatabaseMetaData#getColumnPrivileges(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory COLUMN_PRIVILEGES = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("COLUMN_NAME") + .addTextColumn("GRANTOR") + .addTextColumn("GRANTEE") + .addTextColumn("PRIVILEGE") + .addTextColumn("IS_GRANTABLE") + .build(); + + /** + * @see DatabaseMetaData#getTablePrivileges(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory TABLE_PRIVILEGES = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("GRANTOR") + .addTextColumn("GRANTEE") + .addTextColumn("PRIVILEGE") + .addTextColumn("IS_GRANTABLE") + .build(); + + /** + * @see DatabaseMetaData#getBestRowIdentifier(java.lang.String, java.lang.String, java.lang.String, int, boolean) + */ + public final static FixedResultSetFactory BEST_ROW_IDENTIFIERS = FixedResultSetFactory.newBuilder() + .addShortColumn("SCOPE") + .addTextColumn("COLUMN_NAME") + .addIntColumn("DATA_TYPE") + .addTextColumn("TYPE_NAME") + .addIntColumn("COLUMN_SIZE") + .addIntColumn("BUFFER_LENGTH") + .addShortColumn("DECIMAL_DIGITS") + .addShortColumn("PSEUDO_COLUMN") + .build(); + + /** + * @see DatabaseMetaData#getVersionColumns(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory VERSION_COLUMNS = FixedResultSetFactory.newBuilder() + .addShortColumn("SCOPE") + .addTextColumn("COLUMN_NAME") + .addIntColumn("DATA_TYPE") + .addTextColumn("TYPE_NAME") + .addIntColumn("COLUMN_SIZE") + .addIntColumn("BUFFER_LENGTH") + .addShortColumn("DECIMAL_DIGITS") + .addShortColumn("PSEUDO_COLUMN") + .build(); + + /** + * @see DatabaseMetaData#getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory PRIMARY_KEYS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("COLUMN_NAME") + .addShortColumn("KEY_SEQ") + .addTextColumn("PK_NAME") + .build(); + + /** + * @see DatabaseMetaData#getImportedKeys(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory IMPORTED_KEYS = FixedResultSetFactory.newBuilder() + .addTextColumn("PKTABLE_CAT") + .addTextColumn("PKTABLE_SCHEM") + .addTextColumn("PKTABLE_NAME") + .addTextColumn("PKCOLUMN_NAME") + .addTextColumn("PKTABLE_CAT") + .addTextColumn("FKTABLE_SCHEM") + .addTextColumn("FKTABLE_NAME") + .addTextColumn("FKCOLUMN_NAME") + .addShortColumn("KEY_SEQ") + .addShortColumn("UPDATE_RULE") + .addShortColumn("DELETE_RULE") + .addTextColumn("FK_NAME") + .addTextColumn("PK_NAME") + .addShortColumn("DEFERRABILITY") + .build(); + + /** + * @see DatabaseMetaData#getExportedKeys(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory EXPORTED_KEYS = FixedResultSetFactory.newBuilder() + .addTextColumn("PKTABLE_CAT") + .addTextColumn("PKTABLE_SCHEM") + .addTextColumn("PKTABLE_NAME") + .addTextColumn("PKCOLUMN_NAME") + .addTextColumn("PKTABLE_CAT") + .addTextColumn("FKTABLE_SCHEM") + .addTextColumn("FKTABLE_NAME") + .addTextColumn("FKCOLUMN_NAME") + .addShortColumn("KEY_SEQ") + .addShortColumn("UPDATE_RULE") + .addShortColumn("DELETE_RULE") + .addTextColumn("FK_NAME") + .addTextColumn("PK_NAME") + .addShortColumn("DEFERRABILITY") + .build(); + + /** + * @see DatabaseMetaData#getCrossReference(java.lang.String, java.lang.String, java.lang.String, java.lang.String, + * java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory CROSS_REFERENCES = FixedResultSetFactory.newBuilder() + .addTextColumn("PKTABLE_CAT") + .addTextColumn("PKTABLE_SCHEM") + .addTextColumn("PKTABLE_NAME") + .addTextColumn("PKCOLUMN_NAME") + .addTextColumn("PKTABLE_CAT") + .addTextColumn("FKTABLE_SCHEM") + .addTextColumn("FKTABLE_NAME") + .addTextColumn("FKCOLUMN_NAME") + .addShortColumn("KEY_SEQ") + .addShortColumn("UPDATE_RULE") + .addShortColumn("DELETE_RULE") + .addTextColumn("FK_NAME") + .addTextColumn("PK_NAME") + .addShortColumn("DEFERRABILITY") + .build(); + + /** + * @see DatabaseMetaData#getTypeInfo() + */ + public final static FixedResultSetFactory TYPE_INFOS = FixedResultSetFactory.newBuilder() + .addTextColumn("TYPE_NAME") + .addIntColumn("DATA_TYPE") + .addIntColumn("PRECISION") + .addTextColumn("LITERAL_PREFIX") + .addTextColumn("LITERAL_SUFFIX") + .addTextColumn("CREATE_PARAMS") + .addShortColumn("NULLABLE") + .addBooleanColumn("CASE_SENSITIVE") + .addShortColumn("SEARCHABLE") + .addBooleanColumn("UNSIGNED_ATTRIBUTE") + .addBooleanColumn("FIXED_PREC_SCALE") + .addBooleanColumn("AUTO_INCREMENT") + .addTextColumn("LOCAL_TYPE_NAME") + .addShortColumn("MINIMUM_SCALE") + .addShortColumn("MAXIMUM_SCALE") + .addIntColumn("SQL_DATA_TYPE") + .addIntColumn("SQL_DATETIME_SUB") + .addIntColumn("NUM_PREC_RADIX") + .build(); + + /** + * @see DatabaseMetaData#getIndexInfo(java.lang.String, java.lang.String, java.lang.String, boolean, boolean) + */ + public final static FixedResultSetFactory INDEX_INFOS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addBooleanColumn("NON_UNIQUE") + .addTextColumn("INDEX_QUALIFIER") + .addTextColumn("INDEX_NAME") + .addShortColumn("TYPE") + .addShortColumn("ORDINAL_POSITION") + .addTextColumn("COLUMN_NAME") + .addTextColumn("ASC_OR_DESC") + .addLongColumn("CARDINALITY") + .addLongColumn("PAGES") + .addTextColumn("FILTER_CONDITION") + .build(); + + /** + * @see DatabaseMetaData#getUDTs(java.lang.String, java.lang.String, java.lang.String, int[]) + */ + public final static FixedResultSetFactory UDTS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("CLASS_NAME") + .addIntColumn("DATA_TYPE") + .addTextColumn("REMARKS") + .addShortColumn("BASE_TYPE") + .build(); + + /** + * @see DatabaseMetaData#getSuperTypes(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory SUPER_TYPES = FixedResultSetFactory.newBuilder() + .addTextColumn("TYPE_CAT") + .addTextColumn("TYPE_SCHEM") + .addTextColumn("TYPE_NAME") + .addTextColumn("SUPERTYPE_CAT") + .addTextColumn("SUPERTYPE_SCHEM") + .addTextColumn("SUPERTYPE_NAME") + .build(); + + /** + * @see DatabaseMetaData#getSuperTables(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory SUPER_TABLES = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("SUPERTABLE_NAME") + .build(); + + /** + * @see DatabaseMetaData#getAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory ATTRIBUTES = FixedResultSetFactory.newBuilder() + .addTextColumn("TYPE_CAT") + .addTextColumn("TYPE_SCHEM") + .addTextColumn("TYPE_NAME") + .addTextColumn("ATTR_NAME") + .addIntColumn("DATA_TYPE") + .addTextColumn("ATTR_TYPE_NAME") + .addIntColumn("ATTR_SIZE") + .addIntColumn("DECIMAL_DIGITS") + .addIntColumn("NUM_PREC_RADIX") + .addIntColumn("NULLABLE") + .addTextColumn("REMARKS") + .addTextColumn("ATTR_DEF") + .addIntColumn("SQL_DATA_TYPE") + .addIntColumn("SQL_DATETIME_SUB") + .addIntColumn("CHAR_OCTET_LENGTH") + .addIntColumn("ORDINAL_POSITION") + .addTextColumn("IS_NULLABLE") + .addTextColumn("SCOPE_CATALOG") + .addTextColumn("SCOPE_SCHEMA") + .addTextColumn("SCOPE_TABLE") + .addShortColumn("SOURCE_DATA_TYPE") + .build(); + + /** + * @see DatabaseMetaData#getSchemas(java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory SCHEMAS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_CATALOG") + .build(); + + /** + * @see DatabaseMetaData#getClientInfoProperties() + */ + public final static FixedResultSetFactory CLIENT_INFO_PROPERTIES = FixedResultSetFactory.newBuilder() + .addTextColumn("NAME") + .addIntColumn("MAX_LEN") + .addTextColumn("DEFAULT_VALUE") + .addTextColumn("DESCRIPTION") + .build(); + + /** + * @see DatabaseMetaData#getFunctions(java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory FUNCTIONS = FixedResultSetFactory.newBuilder() + .addTextColumn("FUNCTION_CAT") + .addTextColumn("FUNCTION_SCHEM") + .addTextColumn("FUNCTION_NAME") + .addTextColumn("REMARKS") + .addShortColumn("FUNCTION_TYPE") + .addTextColumn("SPECIFIC_NAME") + .build(); + + /** + * @see DatabaseMetaData#getFunctionColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory FUNCTION_COLUMNS = FixedResultSetFactory.newBuilder() + .addTextColumn("FUNCTION_CAT") + .addTextColumn("FUNCTION_SCHEM") + .addTextColumn("FUNCTION_NAME") + .addTextColumn("COLUMN_NAME") + .addShortColumn("COLUMN_TYPE") + .addIntColumn("DATA_TYPE") + .addTextColumn("TYPE_NAME") + .addIntColumn("PRECISION") + .addIntColumn("LENGTH") + .addShortColumn("SCALE") + .addShortColumn("RADIX") + .addShortColumn("NULLABLE") + .addTextColumn("REMARKS") + .addIntColumn("CHAR_OCTET_LENGTH") + .addIntColumn("ORDINAL_POSITION") + .addTextColumn("IS_NULLABLE") + .addTextColumn("SPECIFIC_NAME") + .build(); + + /** + * @see DatabaseMetaData#getPseudoColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public final static FixedResultSetFactory PSEUDO_COLUMNS = FixedResultSetFactory.newBuilder() + .addTextColumn("TABLE_CAT") + .addTextColumn("TABLE_SCHEM") + .addTextColumn("TABLE_NAME") + .addTextColumn("COLUMN_NAME") + .addIntColumn("DATA_TYPE") + .addIntColumn("COLUMN_SIZE") + .addIntColumn("DECIMAL_DIGITS") + .addIntColumn("NUM_PREC_RADIX") + .addTextColumn("COLUMN_USAGE") + .addTextColumn("REMARKS") + .addIntColumn("CHAR_OCTET_LENGTH") + .addTextColumn("IS_NULLABLE") + .build(); +} 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 9b1a84c..cb0474b 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImpl.java @@ -5,11 +5,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -24,13 +21,16 @@ import com.google.common.base.Strings; +import tech.ydb.core.StatusCode; import tech.ydb.jdbc.YdbConnection; import tech.ydb.jdbc.YdbConst; import tech.ydb.jdbc.YdbDatabaseMetaData; import tech.ydb.jdbc.YdbDriverInfo; import tech.ydb.jdbc.YdbTypes; +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; @@ -660,13 +660,15 @@ public boolean dataDefinitionIgnoredInTransactions() { @Override public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) { - return fromEmptyResultSet(); // Procedures are not supported + // Procedures are not supported + return emptyResultSet(MetaDataTables.PROCEDURES); } @Override public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) { - return fromEmptyResultSet(); // Procedures are not supported + // Procedures are not supported + return emptyResultSet(MetaDataTables.PROCEDURE_COLUMNS); } @Override @@ -677,10 +679,10 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam new Object[]{catalog, schemaPattern, tableNamePattern, types == null ? "" : Arrays.asList(types)} ); if (!isMatchedCatalog(catalog)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.TABLES); } if (!isMatchedSchema(schemaPattern)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.TABLES); } boolean matchTables; @@ -696,37 +698,42 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam } if (!matchTables && !matchSystemTables) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.TABLES); } - List> rows = listTables(tableNamePattern).stream() - .map(tableName -> MappingResultSets.stableMap( - "TABLE_CAT", null, - "TABLE_SCHEM", null, - "TABLE_NAME", tableName, - "TABLE_TYPE", getTableType(tableName), - "REMARKS", null, - "TYPE_CAT", null, - "TYPE_SCHEM", null, - "TYPE_NAME", null, - "SELF_REFERENCING_COL_NAME", null, - "REF_GENERATION", null - )) - .filter(map -> (matchTables || !TABLE.equals(map.get("TABLE_TYPE"))) && - (matchSystemTables || !SYSTEM_TABLE.equals(map.get("TABLE_TYPE")))) - .sorted(Comparator - .comparing((Map m) -> (String) m.get("TABLE_TYPE")) - .thenComparing(m -> (String) m.get("TABLE_NAME"))) - .collect(Collectors.toList()); - - return fromRows(rows); - } - - private String getTableType(String tableName) { - if (tableName.startsWith(".sys/") || tableName.startsWith(".sys_health/")) { - return SYSTEM_TABLE; + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.TABLES.createResultSet(); + listTables(tableNamePattern).stream() + .map(TableRecord::new) + .filter(tr -> (matchTables && !tr.isSystem) || (matchSystemTables && tr.isSystem)) + .sorted() + .forEach(tr -> { + rs.newRow() + .withTextValue("TABLE_NAME", tr.name) + .withTextValue("TABLE_TYPE", tr.isSystem ? SYSTEM_TABLE : TABLE) + .build(); + }); + + return resultSet(rs.build()); + } + + private class TableRecord implements Comparable { + private final boolean isSystem; + private final String name; + + public TableRecord(String name) { + this.name = name; + this.isSystem = name.startsWith(".sys/") + || name.startsWith(".sys_health/") + || name.startsWith(".sys_health_dev/"); + } + + @Override + public int compareTo(TableRecord o) { + if (isSystem != o.isSystem) { + return isSystem ? 1 : -1; + } + return name.compareTo(o.name); } - return TABLE; } @Override @@ -736,15 +743,17 @@ public ResultSet getSchemas() { @Override public ResultSet getCatalogs() { - return fromEmptyResultSet(); // Does not support catalogs, all table names has full catalog prefix + // Does not support catalogs, all table names has full catalog prefix + return emptyResultSet(MetaDataTables.CATALOGS); } @Override public ResultSet getTableTypes() { - return fromRows(Arrays.asList( - Collections.singletonMap("TABLE_TYPE", TABLE), - Collections.singletonMap("TABLE_TYPE", SYSTEM_TABLE) - )); + ResultSetReader rs = MetaDataTables.TABLE_TYPES.createResultSet() + .newRow().withTextValue("TABLE_TYPE", TABLE).build() + .newRow().withTextValue("TABLE_TYPE", SYSTEM_TABLE).build() + .build(); + return resultSet(rs); } @Override @@ -756,75 +765,77 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa ); if (!isMatchedCatalog(catalog)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.COLUMNS); } if (!isMatchedSchema(schemaPattern)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.COLUMNS); } Predicate columnFilter = equalsFilter(columnNamePattern); - return fromTables(tableNamePattern, - (tableName, tableDesc, rows) -> { - short index = 0; - for (TableColumn column : tableDesc.getColumns()) { - index++; - if (!columnFilter.test(column.getName())) { - continue; - } - Type type = column.getType(); - - int nullable; - if (type.getKind() == Type.Kind.OPTIONAL) { - nullable = columnNullable; - type = type.unwrapOptional(); - } else { - nullable = columnNoNulls; - } - - rows.add(MappingResultSets.stableMap( - "TABLE_CAT", null, - "TABLE_SCHEM", null, - "TABLE_NAME", tableName, - "COLUMN_NAME", column.getName(), - "DATA_TYPE", types.toSqlType(type), - "TYPE_NAME", type.toString(), - "COLUMN_SIZE", types.getSqlPrecision(type), - "BUFFER_LENGTH", 0, - "DECIMAL_DIGITS", (short)(type.getKind() == Type.Kind.DECIMAL ? - YdbConst.SQL_DECIMAL_DEFAULT_PRECISION : - 0), - "NUM_PREC_RADIX", 10, - "NULLABLE", nullable, - "REMARKS", null, - "COLUMN_DEF", null, // no default values - "SQL_DATA_TYPE", 0, - "SQL_DATETIME_SUB", 0, - "CHAR_OCTET_LENGTH", 0, // unsupported yet - "ORDINAL_POSITION", index, - "IS_NULLABLE", "YES", - "SCOPE_CATALOG", null, - "SCOPE_SCHEMA", null, - "SCOPE_TABLE", null, - "SOURCE_DATA_TYPE", (short) 0, - "IS_AUTOINCREMENT", "NO", // no auto increments - "IS_GENERATEDCOLUMN", "NO" // no generated columns - )); - } - }, - Comparator - .comparing((Map m) -> (String) m.get("TABLE_NAME")) - .thenComparingInt(m -> (Short) m.get("ORDINAL_POSITION"))); + List tableNames = listTables(tableNamePattern); + Collections.sort(tableNames); + + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.COLUMNS.createResultSet(); + for (String tableName: tableNames) { + TableDescription tableDescription = describeTable(tableName); + if (tableDescription == null) { + continue; + } + + short index = 0; + for (TableColumn column : tableDescription.getColumns()) { + index++; + if (!columnFilter.test(column.getName())) { + continue; + } + Type type = column.getType(); + + int nullable; + if (type.getKind() == Type.Kind.OPTIONAL) { + nullable = columnNullable; + type = type.unwrapOptional(); + } else { + nullable = columnNoNulls; + } + + int decimalDigits = type.getKind() == Type.Kind.DECIMAL ? YdbConst.SQL_DECIMAL_DEFAULT_PRECISION : 0; + + rs.newRow() + .withTextValue("TABLE_NAME", tableName) + .withTextValue("COLUMN_NAME", column.getName()) + .withIntValue("DATA_TYPE", types.toSqlType(type)) + .withTextValue("TYPE_NAME", type.toString()) + .withIntValue("COLUMN_SIZE", types.getSqlPrecision(type)) + .withIntValue("BUFFER_LENGTH", 0) + .withIntValue("DECIMAL_DIGITS", decimalDigits) + .withIntValue("NUM_PREC_RADIX", 10) + .withIntValue("NULLABLE", nullable) + .withIntValue("SQL_DATA_TYPE", 0) + .withIntValue("SQL_DATETIME_SUB", 0) + .withIntValue("CHAR_OCTET_LENGTH", 0) // unsupported yet + .withIntValue("ORDINAL_POSITION", index) + .withTextValue("IS_NULLABLE", "YES") + .withShortValue("SOURCE_DATA_TYPE", (short) 0) + .withTextValue("IS_AUTOINCREMENT", "NO") // no auto increments + .withTextValue("IS_GENERATEDCOLUMN", "NO") // no generated columns + .build(); + } + } + + return resultSet(rs.build()); } @Override public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) { - return fromEmptyResultSet(); // No column-based privileges supported + // No column-based privileges supported + return emptyResultSet(MetaDataTables.COLUMN_PRIVILEGES); } @Override public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) { - return fromEmptyResultSet(); // Unable to collect privileges + // Unable to collect privileges + return emptyResultSet(MetaDataTables.TABLE_PRIVILEGES); } @Override @@ -836,49 +847,58 @@ public ResultSet getBestRowIdentifier(String catalog, String schema, String tabl ); if (!isMatchedCatalog(catalog)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.BEST_ROW_IDENTIFIERS); } if (!isMatchedSchema(schema)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.BEST_ROW_IDENTIFIERS); } if (isMatchedAny(table)) { - return fromEmptyResultSet(); // must be table name + // must be table name + return emptyResultSet(MetaDataTables.BEST_ROW_IDENTIFIERS); } if (!nullable) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.BEST_ROW_IDENTIFIERS); + } + + TableDescription description = describeTable(table); + if (description == null) { + return emptyResultSet(MetaDataTables.BEST_ROW_IDENTIFIERS); } + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.BEST_ROW_IDENTIFIERS.createResultSet(); + + Map columnMap = description.getColumns().stream() + .collect(Collectors.toMap(TableColumn::getName, Function.identity())); + // Only primary keys could be used as row identifiers - return fromTables(table, - (tableName, tableDesc, rows) -> { - Map columnMap = tableDesc.getColumns().stream() - .collect(Collectors.toMap(TableColumn::getName, Function.identity())); - for (String key : tableDesc.getPrimaryKeys()) { - - TableColumn column = columnMap.get(key); - Type type = column.getType(); - if (type.getKind() == Type.Kind.OPTIONAL) { - type = type.unwrapOptional(); - } - - rows.add(MappingResultSets.stableMap( - "SCOPE", (short)scope, - "COLUMN_NAME", key, - "DATA_TYPE", types.toSqlType(type), - "TYPE_NAME", type.toString(), - "COLUMN_SIZE", 0, - "BUFFER_LENGTH", 0, - "DECIMAL_DIGITS", (short) 0, // unknown - "PSEUDO_COLUMN", bestRowNotPseudo)); - } + for (String key : description.getPrimaryKeys()) { + TableColumn column = columnMap.get(key); + Type type = column.getType(); + if (type.getKind() == Type.Kind.OPTIONAL) { + type = type.unwrapOptional(); + } + + int decimalDigits = type.getKind() == Type.Kind.DECIMAL ? YdbConst.SQL_DECIMAL_DEFAULT_PRECISION : 0; + + rs.newRow() + .withShortValue("SCOPE", (short)scope) + .withTextValue("COLUMN_NAME", key) + .withIntValue("DATA_TYPE", types.toSqlType(type)) + .withTextValue("TYPE_NAME", type.toString()) + .withIntValue("COLUMN_SIZE", 0) + .withIntValue("BUFFER_LENGTH", 0) + .withShortValue("DECIMAL_DIGITS", (short) decimalDigits) + .withShortValue("PSEUDO_COLUMN", (short)bestRowNotPseudo) + .build(); + } - }, - Comparator.comparing(m -> (Short) m.get("SCOPE"))); + return resultSet(rs.build()); } @Override public ResultSet getVersionColumns(String catalog, String schema, String table) { - return fromEmptyResultSet(); // Version columns are not supported + // Version columns are not supported + return emptyResultSet(MetaDataTables.VERSION_COLUMNS); } @Override @@ -888,83 +908,82 @@ public ResultSet getPrimaryKeys(String catalog, String schema, String table) thr }); if (!isMatchedCatalog(catalog)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.PRIMARY_KEYS); } if (!isMatchedSchema(schema)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.PRIMARY_KEYS); } if (isMatchedAny(table)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.PRIMARY_KEYS); } - return fromTables(table, - (tableName, tableDesc, rows) -> { - short index = 0; - for (String key : tableDesc.getPrimaryKeys()) { - index++; - rows.add(MappingResultSets.stableMap( - "TABLE_CAT", null, - "TABLE_SCHEM", null, - "TABLE_NAME", tableName, - "COLUMN_NAME", key, - "KEY_SEQ", index, - "PK_NAME", null)); - } + TableDescription description = describeTable(table); + if (description == null) { + return emptyResultSet(MetaDataTables.PRIMARY_KEYS); + } - }, - Comparator.comparing(m -> (String) m.get("COLUMN_NAME"))); + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.PRIMARY_KEYS.createResultSet(); + short index = 0; + for (String key : description.getPrimaryKeys()) { + index++; + rs.newRow() + .withTextValue("TABLE_NAME", table) + .withTextValue("COLUMN_NAME", key) + .withShortValue("KEY_SEQ", index) + .build(); + } + return resultSet(rs.build()); } @Override public ResultSet getImportedKeys(String catalog, String schema, String table) { - return fromEmptyResultSet(); // Foreign keys are not supported + // Foreign keys are not supported + return emptyResultSet(MetaDataTables.IMPORTED_KEYS); } @Override public ResultSet getExportedKeys(String catalog, String schema, String table) { - return fromEmptyResultSet(); // Foreign keys are not supported + // Foreign keys are not supported + return emptyResultSet(MetaDataTables.EXPORTED_KEYS); } @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) { - return fromEmptyResultSet(); // Foreign keys are not supported + // Foreign keys are not supported + return emptyResultSet(MetaDataTables.CROSS_REFERENCES); } @Override public ResultSet getTypeInfo() { - List> rows = types.getAllDatabaseTypes().stream() - .map(type -> { - String literal = getLiteral(type); - int scale = type.getKind() == Type.Kind.DECIMAL ? YdbConst.SQL_DECIMAL_DEFAULT_SCALE : 0; - return MappingResultSets.stableMap( - "TYPE_NAME", type.toString(), - "DATA_TYPE", types.toSqlType(type), - "PRECISION", types.getSqlPrecision(type), - "LITERAL_PREFIX", literal, - "LITERAL_SUFFIX", literal, - "CREATE_PARAMS", null, - "NULLABLE", typeNullable, - "CASE_SENSITIVE", true, - "SEARCHABLE", getSearchable(type), - "UNSIGNED_ATTRIBUTE", getUnsigned(type), - "FIXED_PREC_SCALE", type.getKind() == Type.Kind.DECIMAL, - "AUTO_INCREMENT", false, // no auto-increments - "LOCAL_TYPE_NAME", null, - "MINIMUM_SCALE", scale, - "MAXIMUM_SCALE", scale, - "SQL_DATA_TYPE", 0, - "SQL_DATETIME_SUB", 0, - "NUM_PREC_RADIX", 10 - ); - }) - .sorted(Comparator.comparing((Map m) -> (Integer) m.get("DATA_TYPE"))) - .collect(Collectors.toList()); - - - return fromRows(rows); + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.TYPE_INFOS.createResultSet(); + + for (Type type: types.getAllDatabaseTypes()) { + String literal = getLiteral(type); + int scale = type.getKind() == Type.Kind.DECIMAL ? YdbConst.SQL_DECIMAL_DEFAULT_SCALE : 0; + rs.newRow() + .withTextValue("TYPE_NAME", type.toString()) + .withIntValue("DATA_TYPE", types.toSqlType(type)) + .withIntValue("PRECISION", types.getSqlPrecision(type)) + .withTextValue("LITERAL_PREFIX", literal) + .withTextValue("LITERAL_SUFFIX", literal) + .withShortValue("NULLABLE", (short)typeNullable) + .withBoolValue("CASE_SENSITIVE", true) + .withShortValue("SEARCHABLE", getSearchable(type)) + .withBoolValue("UNSIGNED_ATTRIBUTE", getUnsigned(type)) + .withBoolValue("FIXED_PREC_SCALE", type.getKind() == Type.Kind.DECIMAL) + .withBoolValue("AUTO_INCREMENT", false) // no auto-increments + .withShortValue("MINIMUM_SCALE", (short)scale) + .withShortValue("MAXIMUM_SCALE", (short)scale) + .withIntValue("SQL_DATA_TYPE", 0) + .withIntValue("SQL_DATETIME_SUB", 0) + .withIntValue("NUM_PREC_RADIX", 10) + .build(); + } + + return resultSet(rs.build()); } private short getSearchable(Type type) { @@ -1024,49 +1043,44 @@ public ResultSet getIndexInfo(String catalog, String schema, String table, boole ); if (!isMatchedCatalog(catalog)) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.INDEX_INFOS); } if (!isMatchedSchema(schema)) { // not exactly the same schema - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.INDEX_INFOS); } if (isMatchedAny(table)) { - return fromEmptyResultSet(); // must be table name + return emptyResultSet(MetaDataTables.INDEX_INFOS); } if (unique) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.INDEX_INFOS); } - return fromTables(table, - (tableName, tableDesc, rows) -> { - for (TableIndex tableIndex : tableDesc.getIndexes()) { - short index = 0; - for (String column : tableIndex.getColumns()) { - index++; - rows.add(MappingResultSets.stableMap( - "TABLE_CAT", null, - "TABLE_SCHEM", null, - "TABLE_NAME", tableName, - "NON_UNIQUE", true, - "INDEX_QUALIFIER", null, - "INDEX_NAME", tableIndex.getName(), - "TYPE", tableIndexHashed, // just an index? - "ORDINAL_POSITION", index, - "COLUMN_NAME", column, - "ASC_OR_DESC", null, // unknown sort sequence? - "CARDINALITY", 0, - "PAGES", 0, - "FILTER_CONDITION", null)); - } - } - }, - Comparator - .comparing((Map m) -> (Boolean) m.get("NON_UNIQUE")) - .thenComparing(m -> (Short) m.get("TYPE")) - .thenComparing(m -> (String) m.get("INDEX_NAME")) - .thenComparing(m -> (Short) m.get("ORDINAL_POSITION"))); + TableDescription description = describeTable(table); + if (description == null) { + return emptyResultSet(MetaDataTables.INDEX_INFOS); + } + + FixedResultSetFactory.ResultSetBuilder rs = MetaDataTables.INDEX_INFOS.createResultSet(); + for (TableIndex tableIndex : description.getIndexes()) { + short index = 0; + for (String column : tableIndex.getColumns()) { + index++; + rs.newRow() + .withTextValue("TABLE_NAME", table) + .withBoolValue("NON_UNIQUE", true) + .withTextValue("INDEX_NAME", tableIndex.getName()) + .withShortValue("TYPE", tableIndexHashed) // just an index? + .withShortValue("ORDINAL_POSITION", index) + .withTextValue("COLUMN_NAME", column) + .withLongValue("CARDINALITY", 0) + .withLongValue("PAGES", 0) + .build(); + } + } + return resultSet(rs.build()); } @Override @@ -1132,7 +1146,8 @@ public boolean supportsBatchUpdates() { @Override public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) { - return fromEmptyResultSet(); // UDTs are not supported + // UDTs are not supported + return emptyResultSet(MetaDataTables.UDTS); } @Override @@ -1162,18 +1177,21 @@ public boolean supportsGetGeneratedKeys() { @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) { - return fromEmptyResultSet(); // UDTs are not supported + // Super-types are not supported + return emptyResultSet(MetaDataTables.SUPER_TYPES); } @Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) { - return fromEmptyResultSet(); // Super-tables are not supported + // Super-tables are not supported + return emptyResultSet(MetaDataTables.SUPER_TABLES); } @Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) { - return fromEmptyResultSet(); // UDTss are not supported + // Attributes are not supported + return emptyResultSet(MetaDataTables.ATTRIBUTES); } @Override @@ -1228,7 +1246,7 @@ public RowIdLifetime getRowIdLifetime() { @Override public ResultSet getSchemas(String catalog, String schemaPattern) { - return fromEmptyResultSet(); + return emptyResultSet(MetaDataTables.SCHEMAS); } @Override @@ -1243,24 +1261,28 @@ public boolean autoCommitFailureClosesAllResultSets() { @Override public ResultSet getClientInfoProperties() { - return fromEmptyResultSet(); // No client info getOperationProperties? + // No client info getOperationProperties? + return emptyResultSet(MetaDataTables.CLIENT_INFO_PROPERTIES); } @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) { - return fromEmptyResultSet(); // Custom functions are not supported + // Custom functions are not supported + return emptyResultSet(MetaDataTables.FUNCTIONS); } @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) { - return fromEmptyResultSet(); // Custom functions are not supported + // Custom functions are not supported + return emptyResultSet(MetaDataTables.FUNCTION_COLUMNS); } @Override public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) { - return fromEmptyResultSet(); // Pseudo columns are not supported + // Pseudo columns are not supported + return emptyResultSet(MetaDataTables.PSEUDO_COLUMNS); } @Override @@ -1281,31 +1303,16 @@ public boolean isWrapperFor(Class iface) { return iface.isAssignableFrom(getClass()); } - private Map collectTableDescriptions(Session session, Collection tables) throws SQLException { - DescribeTableSettings settings = connection.withDefaultTimeout(new DescribeTableSettings()); - String databaseWithSuffix = withSuffix(connection.getCtx().getDatabase()); - - Map target = new LinkedHashMap<>(tables.size()); - - for (String table: tables) { - target.put(table, executor.call("Get table description for " + table, - () -> session.describeTable(databaseWithSuffix + table, settings) - )); - } - - return target; - } - - private Collection listTables(String tableNamePattern) throws SQLException { + private List listTables(String tableNamePattern) throws SQLException { Predicate filter = equalsFilter(tableNamePattern); - Collection allTables = listTables(filter); + List allTables = listTables(filter); LOGGER.log(Level.FINE, "Loaded {0} tables...", allTables.size()); return allTables; } - private Collection listTables(Predicate filter) throws SQLException { + private List listTables(Predicate filter) throws SQLException { String databaseWithSuffix = withSuffix(connection.getCtx().getDatabase()); return tables(databaseWithSuffix, databaseWithSuffix, filter); } @@ -1338,36 +1345,36 @@ private List tables(String databasePrefix, String path, Predicate> comparator) throws SQLException { - Collection tables = listTables(tableNamePattern); - if (tables.isEmpty()) { - return fromEmptyResultSet(); - } + private TableDescription describeTable(String table) throws SQLException { + DescribeTableSettings settings = connection.withDefaultTimeout(new DescribeTableSettings()); + String databaseWithSuffix = withSuffix(connection.getCtx().getDatabase()); try (Session session = executor.createSession(connection.getCtx())) { - Map tableMap = collectTableDescriptions(session, tables); - - List> rows = new ArrayList<>(tableMap.size() * 16); - for (Map.Entry entry : tableMap.entrySet()) { - tableCollector.collect(entry.getKey(), entry.getValue(), rows); + try { + return executor.call("Describe table " + table, + () -> 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() } + ); + + return null; } - rows.sort(comparator); - return fromRows(rows); } } - private ResultSet fromEmptyResultSet() { + private ResultSet emptyResultSet(FixedResultSetFactory factory) { YdbStatementImpl statement = new YdbStatementImpl(connection, ResultSet.TYPE_SCROLL_INSENSITIVE); - ResultSetReader reader = MappingResultSets.emptyReader(); - return new YdbResultSetImpl(statement, reader); + return new YdbResultSetImpl(statement, factory.createResultSet().build()); } - private ResultSet fromRows(List> rows) { + private ResultSet resultSet(ResultSetReader rsReader) { YdbStatementImpl statement = new YdbStatementImpl(connection, ResultSet.TYPE_SCROLL_INSENSITIVE); - ResultSetReader reader = MappingResultSets.readerFromList(rows); - return new YdbResultSetImpl(statement, reader); + return new YdbResultSetImpl(statement, rsReader); } private boolean isMatchedCatalog(String catalog) { @@ -1393,8 +1400,4 @@ private static Predicate equalsFilter(String name) { static String withSuffix(String prefix) { return prefix == null || prefix.endsWith("/") ? prefix : prefix + "/"; } - - interface TableCollector { - void collect(String tableName, TableDescription tableDescription, List> rows); - } } diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetImpl.java index 7eaff41..a8f9cfb 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetImpl.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetImpl.java @@ -26,10 +26,8 @@ import java.util.Objects; import java.util.Optional; import java.util.function.LongFunction; -import java.util.function.Supplier; - -import com.google.common.base.Suppliers; +import tech.ydb.jdbc.YdbConst; import tech.ydb.jdbc.YdbResultSet; import tech.ydb.jdbc.YdbResultSetMetaData; import tech.ydb.jdbc.YdbStatement; @@ -39,32 +37,13 @@ import tech.ydb.table.values.OptionalValue; import tech.ydb.table.values.Value; -import static tech.ydb.jdbc.YdbConst.ARRAYS_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.ASCII_STREAM_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.BLOB_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.CANNOT_UNWRAP_TO; -import static tech.ydb.jdbc.YdbConst.CLOB_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.COLUMN_NOT_FOUND; -import static tech.ydb.jdbc.YdbConst.CURSOR_UPDATING_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.FORWARD_ONLY_MODE; -import static tech.ydb.jdbc.YdbConst.INVALID_FETCH_DIRECTION; -import static tech.ydb.jdbc.YdbConst.INVALID_ROW; -import static tech.ydb.jdbc.YdbConst.NAMED_CURSORS_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.NCLOB_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.OBJECT_TYPED_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.REF_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.ROWID_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.SQLXML_UNSUPPORTED; -import static tech.ydb.jdbc.YdbConst.UNABLE_TO_CONVERT_AS_URL; - public class YdbResultSetImpl implements YdbResultSet { private final MutableState state = new MutableState(); private final YdbStatement statement; private final ResultSetReader result; - private final TypeDescription[] types; - private final Supplier metaDataSupplier; + private final YdbResultSetMetaDataImpl metaData; private final int rowCount; @@ -72,8 +51,7 @@ public YdbResultSetImpl(YdbStatement statement, ResultSetReader result) { this.statement = Objects.requireNonNull(statement); this.result = Objects.requireNonNull(result); this.rowCount = result.getRowCount(); - this.types = asDescription(result); - this.metaDataSupplier = Suppliers.memoize(() -> new YdbResultSetMetaDataImpl(result, types))::get; + this.metaData = new YdbResultSetMetaDataImpl(result); } @Override @@ -284,7 +262,7 @@ public void clearWarnings() { @Override public YdbResultSetMetaData getMetaData() { - return metaDataSupplier.get(); + return metaData; } @Override @@ -418,7 +396,7 @@ public boolean previous() throws SQLException { public void setFetchDirection(int direction) throws SQLException { int resultSetType = getType(); if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && direction != ResultSet.FETCH_FORWARD) { - throw new SQLException(String.format(INVALID_FETCH_DIRECTION, direction, resultSetType)); + throw new SQLException(String.format(YdbConst.INVALID_FETCH_DIRECTION, direction, resultSetType)); } state.direction = direction; } @@ -495,7 +473,7 @@ public URL getURL(int columnIndex) throws SQLException { try { return new URL(copy); } catch (MalformedURLException e) { - throw new SQLException(UNABLE_TO_CONVERT_AS_URL + result, e); + throw new SQLException(YdbConst.UNABLE_TO_CONVERT_AS_URL + result, e); } } @@ -578,10 +556,6 @@ private T getDateImpl(int columnIndex, LongFunction fromMillis) throws SQ } - private TypeDescription getDescription(int columnIndex) { - return types[columnIndex - 1]; - } - private boolean isNullValue(TypeDescription description, ValueReader value) { return description.isOptional() && !value.isOptionalItemPresent(); } @@ -589,26 +563,26 @@ private boolean isNullValue(TypeDescription description, ValueReader value) { private void initValueReader(int columnIndex) throws SQLException { try { ValueReader value = result.getColumn(columnIndex - 1); - TypeDescription description = getDescription(columnIndex); + TypeDescription description = TypeDescription.of(result.getColumnType(columnIndex - 1)); state.value = value; state.description = description; state.nullValue = isNullValue(description, value); } catch (IllegalStateException e) { - throw new SQLException(INVALID_ROW + state.rowIndex); + throw new SQLException(YdbConst.INVALID_ROW + state.rowIndex); } } private int getColumnIndex(String columnLabel) throws SQLException { int index = result.getColumnIndex(columnLabel); if (index < 0) { - throw new SQLException(COLUMN_NOT_FOUND + columnLabel); + throw new SQLException(YdbConst.COLUMN_NOT_FOUND + columnLabel); } return index + 1; } private void checkScroll() throws SQLException { if (getType() == ResultSet.TYPE_FORWARD_ONLY) { - throw new SQLException(FORWARD_ONLY_MODE); + throw new SQLException(YdbConst.FORWARD_ONLY_MODE); } } @@ -624,15 +598,6 @@ private boolean isRowIndexValid() { return state.rowIndex > 0 && state.rowIndex <= rowCount; } - private static TypeDescription[] asDescription(ResultSetReader result) { - // TODO: cache? - TypeDescription[] descriptions = new TypeDescription[result.getColumnCount()]; - for (int i = 0; i < descriptions.length; i++) { - descriptions[i] = TypeDescription.of(result.getColumnType(i)); - } - return descriptions; - } - private static class MutableState { private int rowIndex; // 1..rowCount, inclusive (first row is 1, second is 2 and so on) @@ -650,573 +615,573 @@ private static class MutableState { @Override public String getCursorName() throws SQLException { - throw new SQLFeatureNotSupportedException(NAMED_CURSORS_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.NAMED_CURSORS_UNSUPPORTED); } @Override public boolean rowUpdated() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public boolean rowInserted() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public boolean rowDeleted() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNull(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBoolean(int columnIndex, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateByte(int columnIndex, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateShort(int columnIndex, short x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateInt(int columnIndex, int x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateLong(int columnIndex, long x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateFloat(int columnIndex, float x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateDouble(int columnIndex, double x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateString(int columnIndex, String x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBytes(int columnIndex, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateDate(int columnIndex, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateTime(int columnIndex, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateObject(int columnIndex, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNull(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBoolean(String columnLabel, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateByte(String columnLabel, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateShort(String columnLabel, short x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateInt(String columnLabel, int x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateLong(String columnLabel, long x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateFloat(String columnLabel, float x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateDouble(String columnLabel, double x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateString(String columnLabel, String x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBytes(String columnLabel, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateDate(String columnLabel, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateTime(String columnLabel, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateObject(String columnLabel, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void insertRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void deleteRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void refreshRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void cancelRowUpdates() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void moveToInsertRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void moveToCurrentRow() throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateRef(int columnIndex, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateRef(String columnLabel, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(int columnIndex, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(String columnLabel, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(int columnIndex, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(String columnLabel, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateArray(int columnIndex, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateArray(String columnLabel, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public RowId getRowId(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(ROWID_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ROWID_UNSUPPORTED); } @Override public RowId getRowId(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(ROWID_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ROWID_UNSUPPORTED); } @Override public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateRowId(String columnLabel, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNString(int columnIndex, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNString(String columnLabel, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateNClob(String columnLabel, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(CURSOR_UPDATING_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CURSOR_UPDATING_UNSUPPORTED); } @Override public Object getObject(int columnIndex, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException(OBJECT_TYPED_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.OBJECT_TYPED_UNSUPPORTED); } @Override public Ref getRef(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(REF_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.REF_UNSUPPORTED); } @Override public Blob getBlob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(BLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.BLOB_UNSUPPORTED); } @Override public Clob getClob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(CLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CLOB_UNSUPPORTED); } @Override public Array getArray(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(ARRAYS_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ARRAYS_UNSUPPORTED); } @Override public Object getObject(String columnLabel, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException(OBJECT_TYPED_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.OBJECT_TYPED_UNSUPPORTED); } @Override public Ref getRef(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(REF_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.REF_UNSUPPORTED); } @Override public Blob getBlob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(BLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.BLOB_UNSUPPORTED); } @Override public Clob getClob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(CLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.CLOB_UNSUPPORTED); } @Override public Array getArray(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(ARRAYS_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ARRAYS_UNSUPPORTED); } @Override public NClob getNClob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(NCLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.NCLOB_UNSUPPORTED); } @Override public NClob getNClob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(NCLOB_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.NCLOB_UNSUPPORTED); } @Override public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(SQLXML_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.SQLXML_UNSUPPORTED); } @Override public SQLXML getSQLXML(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(SQLXML_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.SQLXML_UNSUPPORTED); } @Override public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(ASCII_STREAM_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ASCII_STREAM_UNSUPPORTED); } @Override public InputStream getAsciiStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(ASCII_STREAM_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.ASCII_STREAM_UNSUPPORTED); } @Override public T getObject(int columnIndex, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException(OBJECT_TYPED_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.OBJECT_TYPED_UNSUPPORTED); } @Override public T getObject(String columnLabel, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException(OBJECT_TYPED_UNSUPPORTED); + throw new SQLFeatureNotSupportedException(YdbConst.OBJECT_TYPED_UNSUPPORTED); } @Override @@ -1224,7 +1189,7 @@ public T unwrap(Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } - throw new SQLException(CANNOT_UNWRAP_TO + iface); + throw new SQLException(YdbConst.CANNOT_UNWRAP_TO + iface); } @Override diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetMetaDataImpl.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetMetaDataImpl.java index ff1be9c..00afebf 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetMetaDataImpl.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbResultSetMetaDataImpl.java @@ -3,30 +3,26 @@ import java.sql.SQLException; import java.util.Objects; -import com.google.common.base.Preconditions; - +import tech.ydb.jdbc.YdbConst; import tech.ydb.jdbc.YdbResultSetMetaData; import tech.ydb.jdbc.common.TypeDescription; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.values.Type; -import static tech.ydb.jdbc.YdbConst.CANNOT_UNWRAP_TO; -import static tech.ydb.jdbc.YdbConst.COLUMN_NOT_FOUND; -import static tech.ydb.jdbc.YdbConst.COLUMN_NUMBER_NOT_FOUND; - public class YdbResultSetMetaDataImpl implements YdbResultSetMetaData { private final ResultSetReader result; private final TypeDescription[] descriptions; private final String[] names; - YdbResultSetMetaDataImpl(ResultSetReader result, TypeDescription[] descriptions) { + YdbResultSetMetaDataImpl(ResultSetReader result) { this.result = Objects.requireNonNull(result); - this.descriptions = Objects.requireNonNull(descriptions); - this.names = asNames(result); - Preconditions.checkState(result.getColumnCount() == descriptions.length, - "Internal error, column count in resultSet must be equals to extract column descriptions"); - Preconditions.checkState(descriptions.length == names.length, - "Internal error, column description count must be equals to extract column names"); + this.descriptions = new TypeDescription[result.getColumnCount()]; + this.names = new String[result.getColumnCount()]; + + for (int i = 0; i < result.getColumnCount(); i++) { + descriptions[i] = TypeDescription.of(result.getColumnType(i)); + names[i] = result.getColumnName(i); + } } @Override @@ -147,7 +143,7 @@ public int getColumnIndex(String columnName) throws SQLException { if (index >= 0) { return index + 1; } else { - throw new SQLException(COLUMN_NOT_FOUND + columnName); + throw new SQLException(YdbConst.COLUMN_NOT_FOUND + columnName); } } @@ -156,7 +152,7 @@ public int getColumnIndex(String columnName) throws SQLException { private int getIndex(int column) throws SQLException { if (column <= 0 || column > descriptions.length) { - throw new SQLException(COLUMN_NUMBER_NOT_FOUND + column); + throw new SQLException(YdbConst.COLUMN_NUMBER_NOT_FOUND + column); } return column - 1; } @@ -166,20 +162,12 @@ private TypeDescription getDescription(int column) throws SQLException { } - private static String[] asNames(ResultSetReader result) { - String[] names = new String[result.getColumnCount()]; - for (int i = 0; i < names.length; i++) { - names[i] = result.getColumnName(i); - } - return names; - } - @Override public T unwrap(Class iface) throws SQLException { if (iface.isAssignableFrom(getClass())) { return iface.cast(this); } - throw new SQLException(CANNOT_UNWRAP_TO + iface); + throw new SQLException(YdbConst.CANNOT_UNWRAP_TO + iface); } @Override 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 19f4ccd..7a8585d 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypesImpl.java @@ -284,9 +284,12 @@ public Collection getSqlTypes() { public List getAllDatabaseTypes() { return Arrays.asList( PrimitiveType.Bool, + PrimitiveType.Int8, + PrimitiveType.Int16, PrimitiveType.Int32, PrimitiveType.Int64, PrimitiveType.Uint8, + PrimitiveType.Uint16, PrimitiveType.Uint32, PrimitiveType.Uint64, PrimitiveType.Float, diff --git a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java b/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java index 3546726..1ec911c 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/impl/params/BatchedParams.java @@ -8,10 +8,9 @@ import java.util.List; import java.util.Map; -import tech.ydb.core.StatusCode; import tech.ydb.jdbc.YdbConst; import tech.ydb.jdbc.common.TypeDescription; -import tech.ydb.jdbc.exception.YdbNonRetryableException; +import tech.ydb.jdbc.exception.YdbStatusException; import tech.ydb.jdbc.impl.YdbJdbcParams; import tech.ydb.table.query.Params; import tech.ydb.table.values.ListType; @@ -86,10 +85,7 @@ private StructValue validatedCurrentStruct() throws SQLException { continue; } - throw new YdbNonRetryableException( - YdbConst.MISSING_VALUE_FOR_PARAMETER + prm.displayName(), - StatusCode.BAD_REQUEST - ); + throw YdbStatusException.newBadRequest(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm.displayName()); } return StructValue.of(currentValues); } 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 d9274b9..361ec70 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java @@ -6,9 +6,8 @@ import java.util.List; import java.util.Map; -import tech.ydb.core.StatusCode; import tech.ydb.jdbc.YdbConst; -import tech.ydb.jdbc.exception.YdbNonRetryableException; +import tech.ydb.jdbc.exception.YdbStatusException; import tech.ydb.table.query.Params; import tech.ydb.table.values.Value; @@ -52,10 +51,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 new YdbNonRetryableException( - YdbConst.MISSING_VALUE_FOR_PARAMETER + prm, - StatusCode.BAD_REQUEST - ); + throw YdbStatusException.newBadRequest(YdbConst.MISSING_VALUE_FOR_PARAMETER + prm); } if (opts.isDeclareJdbcParameters()) { 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 6371fe6..7100bdd 100644 --- a/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java +++ b/jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryBuilder.java @@ -3,9 +3,8 @@ import java.util.ArrayList; import java.util.List; -import tech.ydb.core.StatusCode; import tech.ydb.jdbc.YdbConst; -import tech.ydb.jdbc.exception.YdbNonRetryableException; +import tech.ydb.jdbc.exception.YdbStatusException; /** * @@ -37,14 +36,13 @@ public String createNextArgName() { } } - public void setQueryType(QueryType type) throws YdbNonRetryableException { + public void setQueryType(QueryType type) throws YdbStatusException { if (forcedType != null) { return; } if (currentType != null && currentType != type) { - String msg = YdbConst.MULTI_TYPES_IN_ONE_QUERY + currentType + ", " + type; - throw new YdbNonRetryableException(msg, StatusCode.BAD_REQUEST); + throw YdbStatusException.newBadRequest(YdbConst.MULTI_TYPES_IN_ONE_QUERY + currentType + ", " + type); } this.currentType = type; } diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImplTest.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImplTest.java index 110d050..5577590 100644 --- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImplTest.java +++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbDatabaseMetaDataImplTest.java @@ -1,8 +1,5 @@ package tech.ydb.jdbc.impl; -import tech.ydb.jdbc.common.JdbcDriverVersion; -import tech.ydb.jdbc.common.YdbFunctions; - import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -25,6 +22,8 @@ import tech.ydb.jdbc.YdbDatabaseMetaData; import tech.ydb.jdbc.YdbDriverInfo; import tech.ydb.jdbc.YdbStatement; +import tech.ydb.jdbc.common.JdbcDriverVersion; +import tech.ydb.jdbc.common.YdbFunctions; import tech.ydb.jdbc.impl.helper.ExceptionAssert; import tech.ydb.jdbc.impl.helper.JdbcConnectionExtention; import tech.ydb.jdbc.impl.helper.SqlQueries; @@ -319,33 +318,33 @@ public void metaDataValuesTest() throws SQLException { @Test public void unsupportedListsTest() throws SQLException { - TableAssert.assertEmpty(metaData.getAttributes(null, null, null, null)); - TableAssert.assertEmpty(metaData.getClientInfoProperties()); + TableAssert.assertNotRows(metaData.getAttributes(null, null, null, null)); + TableAssert.assertNotRows(metaData.getClientInfoProperties()); - TableAssert.assertEmpty(metaData.getSchemas()); - TableAssert.assertEmpty(metaData.getCatalogs()); + TableAssert.assertNotRows(metaData.getSchemas()); + TableAssert.assertNotRows(metaData.getCatalogs()); - TableAssert.assertEmpty(metaData.getProcedures(null, null, null)); - TableAssert.assertEmpty(metaData.getProcedureColumns(null, null, null, null)); + TableAssert.assertNotRows(metaData.getProcedures(null, null, null)); + TableAssert.assertNotRows(metaData.getProcedureColumns(null, null, null, null)); - TableAssert.assertEmpty(metaData.getSuperTypes(null, null, null)); - TableAssert.assertEmpty(metaData.getSuperTables(null, null, null)); + TableAssert.assertNotRows(metaData.getSuperTypes(null, null, null)); + TableAssert.assertNotRows(metaData.getSuperTables(null, null, null)); - TableAssert.assertEmpty(metaData.getFunctions(null, null, null)); - TableAssert.assertEmpty(metaData.getFunctionColumns(null, null, null, null)); + TableAssert.assertNotRows(metaData.getFunctions(null, null, null)); + TableAssert.assertNotRows(metaData.getFunctionColumns(null, null, null, null)); - TableAssert.assertEmpty(metaData.getPseudoColumns(null, null, null, null)); - TableAssert.assertEmpty(metaData.getVersionColumns(null, null, null)); + TableAssert.assertNotRows(metaData.getPseudoColumns(null, null, null, null)); + TableAssert.assertNotRows(metaData.getVersionColumns(null, null, null)); - TableAssert.assertEmpty(metaData.getUDTs(null, null, null, null)); + TableAssert.assertNotRows(metaData.getUDTs(null, null, null, null)); - TableAssert.assertEmpty(metaData.getImportedKeys(null, null, null)); - TableAssert.assertEmpty(metaData.getExportedKeys(null, null, null)); + TableAssert.assertNotRows(metaData.getImportedKeys(null, null, null)); + TableAssert.assertNotRows(metaData.getExportedKeys(null, null, null)); - TableAssert.assertEmpty(metaData.getCrossReference(null, null, null, null, null, null)); + TableAssert.assertNotRows(metaData.getCrossReference(null, null, null, null, null, null)); - TableAssert.assertEmpty(metaData.getColumnPrivileges(null, null, null, null)); - TableAssert.assertEmpty(metaData.getTablePrivileges(null, null, null)); + TableAssert.assertNotRows(metaData.getColumnPrivileges(null, null, null, null)); + TableAssert.assertNotRows(metaData.getTablePrivileges(null, null, null)); } @Test @@ -373,15 +372,15 @@ public void getTypeInfo() throws SQLException { TableAssert.TextColumn prefix = types.addTextColumn("LITERAL_PREFIX", "Text").defaultNull(); TableAssert.TextColumn suffix = types.addTextColumn("LITERAL_SUFFIX", "Text").defaultNull(); /* createParams = */types.addTextColumn("CREATE_PARAMS", "Text").defaultNull(); - /* nullable = */types.addIntColumn("NULLABLE", "Int32").defaultValue(DatabaseMetaData.typeNullable); + /* nullable = */types.addShortColumn("NULLABLE", "Int16").defaultValue((short) DatabaseMetaData.typeNullable); /* caseSensitive = */types.addBoolColumn("CASE_SENSITIVE", "Bool").defaultValue(true); TableAssert.ShortColumn searchable = types.addShortColumn("SEARCHABLE", "Int16").defaultValue(searchBasic); TableAssert.BoolColumn unsigned = types.addBoolColumn("UNSIGNED_ATTRIBUTE", "Bool"); TableAssert.BoolColumn fixedPrec = types.addBoolColumn("FIXED_PREC_SCALE", "Bool").defaultValue(false); /* autoIncrement = */types.addBoolColumn("AUTO_INCREMENT", "Bool").defaultValue(false); /* localName = */types.addTextColumn("LOCAL_TYPE_NAME", "Text").defaultNull(); - TableAssert.IntColumn minScale = types.addIntColumn("MINIMUM_SCALE", "Int32").defaultValue(0); - TableAssert.IntColumn maxScale = types.addIntColumn("MAXIMUM_SCALE", "Int32").defaultValue(0); + TableAssert.ShortColumn minScale = types.addShortColumn("MINIMUM_SCALE", "Int16").defaultValue((short) 0); + TableAssert.ShortColumn maxScale = types.addShortColumn("MAXIMUM_SCALE", "Int16").defaultValue((short) 0); /* sqlDataType = */types.addIntColumn("SQL_DATA_TYPE", "Int32").defaultValue(0); /* sqlDatetimeSub = */types.addIntColumn("SQL_DATETIME_SUB", "Int32").defaultValue(0); /* numPrecRadix = */types.addIntColumn("NUM_PREC_RADIX", "Int32").defaultValue(10); @@ -389,34 +388,41 @@ public void getTypeInfo() throws SQLException { TableAssert.ResultSetAssert rs = types.check(metaData.getTypeInfo()) .assertMetaColumns(); + rs.nextRow(name.eq("Bool"), type.eq(Types.BOOLEAN), precision.eq(1), unsigned.eq(false)).assertAll(); + + rs.nextRow(name.eq("Int8"), type.eq(Types.SMALLINT), precision.eq(1), unsigned.eq(false)).assertAll(); + rs.nextRow(name.eq("Int16"), type.eq(Types.SMALLINT), precision.eq(2), unsigned.eq(false)).assertAll(); + rs.nextRow(name.eq("Int32"), type.eq(Types.INTEGER), precision.eq(4), unsigned.eq(false)).assertAll(); rs.nextRow(name.eq("Int64"), type.eq(Types.BIGINT), precision.eq(8), unsigned.eq(false)).assertAll(); + + rs.nextRow(name.eq("Uint8"), type.eq(Types.INTEGER), precision.eq(1), unsigned.eq(true)).assertAll(); + rs.nextRow(name.eq("Uint16"), type.eq(Types.INTEGER), precision.eq(2), unsigned.eq(true)).assertAll(); rs.nextRow(name.eq("Uint32"), type.eq(Types.BIGINT), precision.eq(4), unsigned.eq(true)).assertAll(); rs.nextRow(name.eq("Uint64"), type.eq(Types.BIGINT), precision.eq(8), unsigned.eq(true)).assertAll(); - rs.nextRow(name.eq("Interval"), type.eq(Types.BIGINT), precision.eq(8), unsigned.eq(false)).assertAll(); - rs.nextRow(name.eq("Bytes"), type.eq(Types.BINARY), precision.eq(YdbConst.MAX_COLUMN_SIZE), - prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchFull)).assertAll(); - rs.nextRow(name.eq("Yson"), type.eq(Types.BINARY), precision.eq(YdbConst.MAX_COLUMN_SIZE), - prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchNone)).assertAll(); - rs.nextRow(name.eq("Decimal(22, 9)"), type.eq(Types.DECIMAL), precision.eq(16), - unsigned.eq(false), fixedPrec.eq(true), minScale.eq(9), maxScale.eq(9)).assertAll(); - - rs.nextRow(name.eq("Int32"), type.eq(Types.INTEGER), precision.eq(4), unsigned.eq(false)).assertAll(); - rs.nextRow(name.eq("Uint8"), type.eq(Types.INTEGER), precision.eq(1), unsigned.eq(true)).assertAll(); rs.nextRow(name.eq("Float"), type.eq(Types.FLOAT), precision.eq(4), unsigned.eq(false)).assertAll(); rs.nextRow(name.eq("Double"), type.eq(Types.DOUBLE), precision.eq(8), unsigned.eq(false)).assertAll(); + rs.nextRow(name.eq("Bytes"), type.eq(Types.BINARY), precision.eq(YdbConst.MAX_COLUMN_SIZE), + prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchFull)).assertAll(); rs.nextRow(name.eq("Text"), type.eq(Types.VARCHAR), precision.eq(YdbConst.MAX_COLUMN_SIZE), prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchFull)).assertAll(); + rs.nextRow(name.eq("Json"), type.eq(Types.VARCHAR), precision.eq(YdbConst.MAX_COLUMN_SIZE), prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchNone)).assertAll(); rs.nextRow(name.eq("JsonDocument"), type.eq(Types.VARCHAR), precision.eq(YdbConst.MAX_COLUMN_SIZE), prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchNone)).assertAll(); - rs.nextRow(name.eq("Bool"), type.eq(Types.BOOLEAN), precision.eq(1), unsigned.eq(false)).assertAll(); + rs.nextRow(name.eq("Yson"), type.eq(Types.BINARY), precision.eq(YdbConst.MAX_COLUMN_SIZE), + prefix.eq("'"), suffix.eq("'"), unsigned.eq(false), searchable.eq(searchNone)).assertAll(); + rs.nextRow(name.eq("Date"), type.eq(Types.DATE), precision.eq(10), unsigned.eq(false)).assertAll(); rs.nextRow(name.eq("Datetime"), type.eq(Types.TIME), precision.eq(19), unsigned.eq(false)).assertAll(); rs.nextRow(name.eq("Timestamp"), type.eq(Types.TIMESTAMP), precision.eq(26), unsigned.eq(false)).assertAll(); + rs.nextRow(name.eq("Interval"), type.eq(Types.BIGINT), precision.eq(8), unsigned.eq(false)).assertAll(); + + rs.nextRow(name.eq("Decimal(22, 9)"), type.eq(Types.DECIMAL), precision.eq(16), + unsigned.eq(false), fixedPrec.eq(true), minScale.eq(9), maxScale.eq(9)).assertAll(); rs.assertNoRows(); } @@ -446,11 +452,11 @@ public void getTables() throws SQLException { /* refGeneration = */ tables.addTextColumn("REF_GENERATION", "Text").defaultNull(); // wrong filters - TableAssert.assertEmpty(metaData.getTables("-", null, null, null)); - TableAssert.assertEmpty(metaData.getTables(null, "-", null, null)); - TableAssert.assertEmpty(metaData.getTables(null, "-", "unknown-table", null)); - TableAssert.assertEmpty(metaData.getTables(null, "-", null, asArray("U-1"))); - TableAssert.assertEmpty(metaData.getTables(null, "-", null, new String[0])); + tables.check(metaData.getTables("-", null, null, null)).assertMetaColumns().assertNoRows(); + tables.check(metaData.getTables(null, "-", null, null)).assertMetaColumns().assertNoRows(); + tables.check(metaData.getTables(null, "-", "unknown-table", null)).assertMetaColumns().assertNoRows(); + tables.check(metaData.getTables(null, "-", null, asArray("U-1"))).assertMetaColumns().assertNoRows(); + tables.check(metaData.getTables(null, "-", null, new String[0])).assertMetaColumns().assertNoRows(); // fetch system tables List systemTables = new ArrayList<>(); @@ -503,16 +509,13 @@ public void getTables() throws SQLException { rs.assertNoRows(); // filter by name - TableAssert.assertEmpty(metaData.getTables(null, null, "dir1/t1", asArray(SYSTEM_TABLE_TYPE))); + tables.check(metaData.getTables(null, null, "dir1/t1", asArray(SYSTEM_TABLE_TYPE))) + .assertMetaColumns() + .assertNoRows(); } @Test public void getColumns() throws SQLException { - TableAssert.assertEmpty(metaData.getColumns("-", null, null, null)); - TableAssert.assertEmpty(metaData.getColumns(null, "-", null, null)); - TableAssert.assertEmpty(metaData.getColumns(null, "-", "unknown-table", null)); - TableAssert.assertEmpty(metaData.getColumns(null, "-", null, "x-column-unknown")); - TableAssert columns = new TableAssert(); columns.addTextColumn("TABLE_CAT", "Text").defaultNull(); columns.addTextColumn("TABLE_SCHEM", "Text").defaultNull(); @@ -522,8 +525,7 @@ public void getColumns() throws SQLException { TableAssert.TextColumn typeName = columns.addTextColumn("TYPE_NAME", "Text"); TableAssert.IntColumn columnSize = columns.addIntColumn("COLUMN_SIZE", "Int32"); columns.addIntColumn("BUFFER_LENGTH", "Int32").defaultValue(0); - TableAssert.ShortColumn decimalDigits = columns.addShortColumn("DECIMAL_DIGITS", "Int16") - .defaultValue((short)0); + TableAssert.IntColumn decimalDigits = columns.addIntColumn("DECIMAL_DIGITS", "Int32").defaultValue(0); columns.addIntColumn("NUM_PREC_RADIX", "Int32").defaultValue(10); columns.addIntColumn("NULLABLE", "Int32").defaultValue(DatabaseMetaData.columnNullable); columns.addTextColumn("REMARKS", "Text").defaultNull(); @@ -531,7 +533,7 @@ public void getColumns() throws SQLException { columns.addIntColumn("SQL_DATA_TYPE", "Int32").defaultValue(0); columns.addIntColumn("SQL_DATETIME_SUB", "Int32").defaultValue(0); columns.addIntColumn("CHAR_OCTET_LENGTH", "Int32").defaultValue(0); - TableAssert.ShortColumn ordinal = columns.addShortColumn("ORDINAL_POSITION", "Int16"); + TableAssert.IntColumn ordinal = columns.addIntColumn("ORDINAL_POSITION", "Int32"); columns.addTextColumn("IS_NULLABLE", "Text").defaultValue("YES"); columns.addTextColumn("SCOPE_CATALOG", "Text").defaultNull(); columns.addTextColumn("SCOPE_SCHEMA", "Text").defaultNull(); @@ -540,6 +542,11 @@ public void getColumns() throws SQLException { columns.addTextColumn("IS_AUTOINCREMENT", "Text").defaultValue("NO"); columns.addTextColumn("IS_GENERATEDCOLUMN", "Text").defaultValue("NO"); + columns.check(metaData.getColumns("-", null, null, null)).assertMetaColumns().assertNoRows(); + columns.check(metaData.getColumns(null, "-", null, null)).assertMetaColumns().assertNoRows(); + columns.check(metaData.getColumns(null, "-", "unknown-table", null)).assertMetaColumns().assertNoRows(); + columns.check(metaData.getColumns(null, "-", null, "x-column-unknown")).assertMetaColumns().assertNoRows(); + // get all columns for ALL_TYPES_TABLE TableAssert.ResultSetAssert rs = columns.check(metaData.getColumns(null, null, ALL_TYPES_TABLE, null)) .assertMetaColumns(); @@ -608,13 +615,6 @@ public void getColumns() throws SQLException { @Test public void getPrimaryKeys() throws SQLException { - TableAssert.assertEmpty(metaData.getPrimaryKeys("-", null, null)); - TableAssert.assertEmpty(metaData.getPrimaryKeys(null, "-", null)); - TableAssert.assertEmpty(metaData.getPrimaryKeys(null, null, "-")); - - // table name is a must - TableAssert.assertEmpty(metaData.getPrimaryKeys(null, null, null)); - TableAssert primaryKeys = new TableAssert(); primaryKeys.addTextColumn("TABLE_CAT", "Text").defaultNull(); primaryKeys.addTextColumn("TABLE_SCHEM", "Text").defaultNull(); @@ -623,6 +623,14 @@ public void getPrimaryKeys() throws SQLException { TableAssert.ShortColumn keySeq = primaryKeys.addShortColumn("KEY_SEQ", "Int16"); primaryKeys.addTextColumn("PK_NAME", "Text").defaultNull(); + primaryKeys.check(metaData.getPrimaryKeys("-", null, null)).assertMetaColumns().assertNoRows(); + primaryKeys.check(metaData.getPrimaryKeys("-", null, null)).assertMetaColumns().assertNoRows(); + primaryKeys.check(metaData.getPrimaryKeys(null, "-", null)).assertMetaColumns().assertNoRows(); + primaryKeys.check(metaData.getPrimaryKeys(null, null, "-")).assertMetaColumns().assertNoRows(); + + // table name is a must + primaryKeys.check(metaData.getPrimaryKeys(null, null, null)).assertMetaColumns().assertNoRows(); + // ALL_TYPES_TABLE has simple primary key primaryKeys.check(metaData.getPrimaryKeys(null, null, ALL_TYPES_TABLE)) .assertMetaColumns() @@ -639,16 +647,6 @@ public void getPrimaryKeys() throws SQLException { @Test public void getIndexInfo() throws SQLException { - TableAssert.assertEmpty(metaData.getIndexInfo("-", null, null, false, false)); - TableAssert.assertEmpty(metaData.getIndexInfo(null, "-", null, false, false)); - TableAssert.assertEmpty(metaData.getIndexInfo(null, null, "-", false, false)); - - // no unique indexes - TableAssert.assertEmpty(metaData.getIndexInfo(null, null, null, true, false)); - - // table name is a must - TableAssert.assertEmpty(metaData.getIndexInfo(null, null, null, false, false)); - TableAssert indexes = new TableAssert(); indexes.addTextColumn("TABLE_CAT", "Text").defaultNull(); indexes.addTextColumn("TABLE_SCHEM", "Text").defaultNull(); @@ -660,10 +658,20 @@ public void getIndexInfo() throws SQLException { TableAssert.ShortColumn ordinal = indexes.addShortColumn("ORDINAL_POSITION", "Int16"); TableAssert.TextColumn columnName = indexes.addTextColumn("COLUMN_NAME", "Text"); indexes.addTextColumn("ASC_OR_DESC", "Text").defaultNull(); - indexes.addIntColumn("CARDINALITY", "Int32").defaultValue(0); - indexes.addIntColumn("PAGES", "Int32").defaultValue(0); + indexes.addLongColumn("CARDINALITY", "Int64").defaultValue(0); + indexes.addLongColumn("PAGES", "Int64").defaultValue(0); indexes.addTextColumn("FILTER_CONDITION", "Text").defaultNull(); + indexes.check(metaData.getIndexInfo("-", null, null, false, false)).assertMetaColumns().assertNoRows(); + indexes.check(metaData.getIndexInfo(null, "-", null, false, false)).assertMetaColumns().assertNoRows(); + indexes.check(metaData.getIndexInfo(null, null, "-", false, false)).assertMetaColumns().assertNoRows(); + + // no unique indexes + indexes.check(metaData.getIndexInfo(null, null, null, true, false)).assertMetaColumns().assertNoRows(); + + // table name is a must + indexes.check(metaData.getIndexInfo(null, null, null, false, false)).assertMetaColumns().assertNoRows(); + indexes.check(metaData.getIndexInfo(null, null, INDEXES_TABLE, false, false)) .assertMetaColumns() .nextRow(tableName.eq(INDEXES_TABLE), indexName.eq("idx_1"), columnName.eq("value3"), @@ -680,17 +688,6 @@ public void getIndexInfo() throws SQLException { @Test public void getBestRowIdentifier() throws SQLException { - TableAssert.assertEmpty(metaData.getBestRowIdentifier("-", null, null, DatabaseMetaData.bestRowSession, true)); - TableAssert.assertEmpty(metaData.getBestRowIdentifier(null, "-", null, DatabaseMetaData.bestRowSession, true)); - TableAssert.assertEmpty(metaData.getBestRowIdentifier(null, null, "-", DatabaseMetaData.bestRowSession, true)); - - // expect exact column name - TableAssert.assertEmpty(metaData.getBestRowIdentifier(null, null, null, DatabaseMetaData.bestRowSession, true)); - - // only nullable columns supported - TableAssert.assertEmpty(metaData - .getBestRowIdentifier(null, null, ALL_TYPES_TABLE, DatabaseMetaData.bestRowSession, false)); - TableAssert rowIdentifiers = new TableAssert(); TableAssert.ShortColumn scope = rowIdentifiers.addShortColumn("SCOPE", "Int16"); TableAssert.TextColumn name = rowIdentifiers.addTextColumn("COLUMN_NAME", "Text"); @@ -699,7 +696,23 @@ public void getBestRowIdentifier() throws SQLException { rowIdentifiers.addIntColumn("COLUMN_SIZE", "Int32").defaultValue(0); rowIdentifiers.addIntColumn("BUFFER_LENGTH", "Int32").defaultValue(0); rowIdentifiers.addShortColumn("DECIMAL_DIGITS", "Int16").defaultValue((short)0); - rowIdentifiers.addIntColumn("PSEUDO_COLUMN", "Int32").defaultValue(DatabaseMetaData.bestRowNotPseudo); + rowIdentifiers.addShortColumn("PSEUDO_COLUMN", "Int16").defaultValue((short)DatabaseMetaData.bestRowNotPseudo); + + + rowIdentifiers.check(metaData.getBestRowIdentifier("-", null, null, DatabaseMetaData.bestRowSession, true)) + .assertMetaColumns().assertNoRows(); + rowIdentifiers.check(metaData.getBestRowIdentifier(null, "-", null, DatabaseMetaData.bestRowSession, true)) + .assertMetaColumns().assertNoRows(); + rowIdentifiers.check(metaData.getBestRowIdentifier(null, null, "-", DatabaseMetaData.bestRowSession, true)) + .assertMetaColumns().assertNoRows(); + + // expect exact column name + rowIdentifiers.check(metaData.getBestRowIdentifier(null, null, null, DatabaseMetaData.bestRowSession, true)) + .assertMetaColumns().assertNoRows(); + + // only nullable columns supported + rowIdentifiers.check(metaData + .getBestRowIdentifier(null, null, ALL_TYPES_TABLE, DatabaseMetaData.bestRowSession, false)); rowIdentifiers.check(metaData .getBestRowIdentifier(null, null, ALL_TYPES_TABLE, DatabaseMetaData.bestRowSession, true)) 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 be43910..0346d12 100644 --- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java +++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementImplTest.java @@ -427,7 +427,7 @@ public void executeScanQueryAsUpdate() throws SQLException { statement.setInt("key", 1); statement.setString("c_Text", "value-1"); - ExceptionAssert.ydbConditionallyRetryable("Scan query should have a single result set", + ExceptionAssert.ydbNonRetryable("Scan query should have a single result set", statement::executeScanQuery); } } 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 ff4f3d6..17d6651 100644 --- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java +++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementWithDataQueryImplTest.java @@ -290,7 +290,7 @@ public void executeScanQueryAsUpdate() throws SQLException { statement.setInt("key", 1); statement.setString("c_Text", "value-1"); - ExceptionAssert.ydbConditionallyRetryable("Scan query should have a single result set", statement::execute); + ExceptionAssert.ydbNonRetryable("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 710c711..fa5f231 100644 --- a/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java +++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/YdbStatementImplTest.java @@ -312,7 +312,7 @@ public void executeScanQueryOnSystemTable() throws SQLException { @Test public void executeScanQueryMultiResult() { - ExceptionAssert.ydbConditionallyRetryable("Scan query should have a single result set", + ExceptionAssert.ydbNonRetryable("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.ydbConditionallyRetryable("Scan query should have a single result set", + ExceptionAssert.ydbNonRetryable("Scan query should have a single result set", () -> statement.executeUpdate("SCAN\n" + TEST_UPSERT1_SQL) ); } @@ -378,9 +378,13 @@ public void getUpdateCount() throws SQLException { statement.execute(TEST_UPSERT1_SQL); Assertions.assertEquals(1, statement.getUpdateCount()); + Assertions.assertFalse(statement.getMoreResults()); + Assertions.assertEquals(-1, statement.getUpdateCount()); 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()); statement.execute("select 2 + 2"); Assertions.assertEquals(-1, statement.getUpdateCount()); diff --git a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/TableAssert.java b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/TableAssert.java index 7630c1a..d0a6a66 100644 --- a/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/TableAssert.java +++ b/jdbc/src/test/java/tech/ydb/jdbc/impl/helper/TableAssert.java @@ -21,9 +21,8 @@ public class TableAssert { private static final TableAssert SELECT_INT = new TableAssert(); private static final TableAssert.IntColumn INT_COLUMN = SELECT_INT.addIntColumn("column0", "Int32"); - public static void assertEmpty(ResultSet rs) throws SQLException { + public static void assertNotRows(ResultSet rs) throws SQLException { EMPTY.check(rs) - .assertMetaColumns() .assertNoRows(); } @@ -54,6 +53,12 @@ public IntColumn addIntColumn(String name, String typeName) { return column; } + public LongColumn addLongColumn(String name, String typeName) { + LongColumn column = new LongColumn(columns.size() + 1, name, typeName); + columns.add(column); + return column; + } + public ShortColumn addShortColumn(String name, String typeName) { ShortColumn column = new ShortColumn(columns.size() + 1, name, typeName); columns.add(column); @@ -295,4 +300,35 @@ public void assertValue(ResultSet rs) throws SQLException { }; } } + + public class LongColumn extends Column { + public LongColumn(int index, String name, String typeName) { + super(index, name, Types.BIGINT, typeName); + } + + public LongColumn defaultNull() { + defaultValues.put(this, new NullValueAssert(this)); + return this; + } + + public LongColumn defaultValue(long defaultValue) { + defaultValues.put(this, eq(defaultValue)); + return this; + } + + public ValueAssert eq(long value) { + return new ValueAssert(this) { + @Override + public void assertValue(ResultSet rs) throws SQLException { + Assertions.assertEquals(value, rs.getLong(column.name), + "Wrong long value for column label " + column.name); + Assertions.assertFalse(rs.wasNull(), "Null value for column label " + column.name); + + Assertions.assertEquals(value, rs.getLong(column.index), + "Wrong long value of column index " + column.index); + Assertions.assertFalse(rs.wasNull(), "Null value for column index " + column.index); + } + }; + } + } } diff --git a/pom.xml b/pom.xml index b83b6d9..8bf8336 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ tech.ydb.jdbc ydb-jdbc-driver-parent - 2.0.2 + 2.0.3 YDB JDBC Module JDBC Driver over YDB Java SDK