This is an automated email from the ASF dual-hosted git repository.
korlov pushed a commit to branch jdbc_over_thin_sql
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/jdbc_over_thin_sql by this
push:
new 913e7f9798f IGNITE-26354 Jdbc. ResultSet backed by thin client without
data accessors (#6530)
913e7f9798f is described below
commit 913e7f9798ff226e049de976ff2ab82809bf056b
Author: Max Zhuravkov <[email protected]>
AuthorDate: Mon Sep 15 13:53:24 2025 +0300
IGNITE-26354 Jdbc. ResultSet backed by thin client without data accessors
(#6530)
---
.../ignite/internal/jdbc/proto/SqlStateCode.java | 3 +
.../ignite/jdbc/ItJdbcErrorsAbstractSelfTest.java | 11 +-
.../apache/ignite/internal/jdbc/JdbcResultSet.java | 34 +-
.../ignite/internal/jdbc2/JdbcResultSet.java | 1801 ++++++++++++++++++++
.../ignite/internal/jdbc/ColumnDefinition.java | 2 +-
.../internal/jdbc/JdbcResultSetBaseSelfTest.java | 77 +-
.../internal/jdbc/JdbcResultSetSelfTest.java | 15 +
.../internal/jdbc2/JdbcResultSet2SelfTest.java | 541 ++++++
8 files changed, 2441 insertions(+), 43 deletions(-)
diff --git
a/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/proto/SqlStateCode.java
b/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/proto/SqlStateCode.java
index 27aea346318..892a3e6f486 100644
---
a/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/proto/SqlStateCode.java
+++
b/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/proto/SqlStateCode.java
@@ -40,6 +40,9 @@ public final class SqlStateCode {
/** IO error during communication. */
public static final String CONNECTION_FAILURE = "08006";
+ /** Invalid argument. */
+ public static final String INVALID_ARGUMENT = "22000";
+
/** Null value occurred where it wasn't expected to. */
public static final String NULL_VALUE = "22004";
diff --git
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcErrorsAbstractSelfTest.java
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcErrorsAbstractSelfTest.java
index ea3197a62de..6e7b8b54bb1 100644
---
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcErrorsAbstractSelfTest.java
+++
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcErrorsAbstractSelfTest.java
@@ -26,7 +26,6 @@ import static
org.apache.ignite.internal.jdbc.proto.SqlStateCode.UNSUPPORTED_OPE
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
-import java.net.URL;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
@@ -358,13 +357,9 @@ public abstract class ItJdbcErrorsAbstractSelfTest extends
AbstractJdbcSelfTest
}, CONVERSION_FAILED, "Cannot convert to timestamp");
}
- /**
- * Test error code for the case when user attempts to get {@link URL}
value from column whose
- * value can't be converted to a {@link URL}.
- */
@Test
- public void testInvalidUrlFormat() {
- checkErrorState(() -> {
+ public void getUrlIsNotSupported() {
+ checkNotSupported(() -> {
try (PreparedStatement stmt = conn.prepareStatement("SELECT
'zzz'")) {
ResultSet rs = stmt.executeQuery();
@@ -372,7 +367,7 @@ public abstract class ItJdbcErrorsAbstractSelfTest extends
AbstractJdbcSelfTest
rs.getURL(1);
}
- }, CONVERSION_FAILED, "Cannot convert to URL");
+ });
}
/**
diff --git
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
index 25efcc7592f..9444e056efe 100644
---
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
+++
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
@@ -23,7 +23,6 @@ import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.RoundingMode;
-import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.sql.Array;
@@ -1003,7 +1002,7 @@ public class JdbcResultSet implements ResultSet {
public String getCursorName() throws SQLException {
ensureNotClosed();
- return null;
+ throw new SQLFeatureNotSupportedException("Cursor name is not
supported.");
}
/** {@inheritDoc} */
@@ -1019,10 +1018,7 @@ public class JdbcResultSet implements ResultSet {
public int findColumn(String colLb) throws SQLException {
ensureNotClosed();
- Objects.requireNonNull(colLb);
-
- Integer order = columnOrder().get(colLb.toUpperCase());
-
+ Integer order = colLb != null ? columnOrder().get(colLb.toUpperCase())
: null;
if (order == null) {
throw new SQLException("Column not found: " + colLb,
SqlStateCode.PARSING_EXCEPTION);
}
@@ -1203,7 +1199,7 @@ public class JdbcResultSet implements ResultSet {
public boolean rowUpdated() throws SQLException {
ensureNotClosed();
- return false;
+ throw new SQLFeatureNotSupportedException("Updates checks are not
supported.");
}
/** {@inheritDoc} */
@@ -1211,7 +1207,7 @@ public class JdbcResultSet implements ResultSet {
public boolean rowInserted() throws SQLException {
ensureNotClosed();
- return false;
+ throw new SQLFeatureNotSupportedException("Insert checks are not
supported.");
}
/** {@inheritDoc} */
@@ -1219,7 +1215,7 @@ public class JdbcResultSet implements ResultSet {
public boolean rowDeleted() throws SQLException {
ensureNotClosed();
- return false;
+ throw new SQLFeatureNotSupportedException("Delete checks are not
supported.");
}
/** {@inheritDoc} */
@@ -1797,25 +1793,9 @@ public class JdbcResultSet implements ResultSet {
/** {@inheritDoc} */
@Override
public URL getURL(int colIdx) throws SQLException {
- Object val = getValue(colIdx);
-
- if (val == null) {
- return null;
- }
-
- Class<?> cls = val.getClass();
+ ensureNotClosed();
- if (cls == URL.class) {
- return (URL) val;
- } else if (cls == String.class) {
- try {
- return new URL(val.toString());
- } catch (MalformedURLException e) {
- throw new SQLException("Cannot convert to URL: " + val,
SqlStateCode.CONVERSION_FAILED, e);
- }
- } else {
- throw new SQLException("Cannot convert to URL: " + val,
SqlStateCode.CONVERSION_FAILED);
- }
+ throw new SQLFeatureNotSupportedException("SQL-specific types are not
supported.");
}
/** {@inheritDoc} */
diff --git
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java
new file mode 100644
index 00000000000..32f64f76441
--- /dev/null
+++
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java
@@ -0,0 +1,1801 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.jdbc2;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.internal.jdbc.proto.SqlStateCode;
+import org.apache.ignite.internal.lang.IgniteExceptionMapperUtil;
+import org.apache.ignite.internal.sql.ResultSetMetadataImpl;
+import org.apache.ignite.sql.ResultSetMetadata;
+import org.apache.ignite.sql.SqlRow;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * JDBC ResultSet adapter backed by {@link org.apache.ignite.sql.ResultSet}.
+ */
+public class JdbcResultSet implements ResultSet {
+
+ private static final String UPDATES_ARE_NOT_SUPPORTED = "Updates are not
supported.";
+
+ private static final String SQL_STRUCTURED_TYPE_ARE_NOT_SUPPORTED = "SQL
structured type are not supported.";
+
+ private static final String SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED =
"SQL-specific types are not supported.";
+
+ private static final ResultSetMetadata EMPTY_METADATA = new
ResultSetMetadataImpl(List.of());
+
+ private final org.apache.ignite.sql.ResultSet<SqlRow> rs;
+
+ private final ResultSetMetadata rsMetadata;
+
+ private final Statement statement;
+
+ private int fetchSize;
+
+ private @Nullable SqlRow currentRow;
+
+ private int currentPosition;
+
+ private boolean closed;
+
+ private boolean wasNull;
+
+ private JdbcResultSetMetadata jdbcMeta;
+
+ /**
+ * Constructor.
+ */
+ public JdbcResultSet(
+ org.apache.ignite.sql.ResultSet<SqlRow> rs,
+ Statement statement
+ ) {
+ this.rs = rs;
+
+ ResultSetMetadata metadata = rs.metadata();
+ this.rsMetadata = metadata != null ? metadata : EMPTY_METADATA;
+
+ this.statement = statement;
+ this.currentRow = null;
+ this.closed = false;
+ this.wasNull = false;
+ }
+
+ @Override
+ public boolean next() throws SQLException {
+ ensureNotClosed();
+
+ try {
+ if (!rs.hasNext()) {
+ currentRow = null;
+ return false;
+ }
+ currentRow = rs.next();
+ currentPosition += 1;
+ return true;
+ } catch (Exception e) {
+ Throwable cause =
IgniteExceptionMapperUtil.mapToPublicException(e);
+ throw new SQLException(cause.getMessage(), cause);
+ }
+ }
+
+ @Override
+ public void close() throws SQLException {
+ if (closed) {
+ return;
+ }
+ closed = true;
+
+ try {
+ rs.close();
+ } catch (Exception e) {
+ Throwable cause =
IgniteExceptionMapperUtil.mapToPublicException(e);
+ throw new SQLException(cause.getMessage(), cause);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean wasNull() throws SQLException {
+ ensureNotClosed();
+
+ return wasNull;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getString(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getString(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean getBoolean(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean getBoolean(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte getByte(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte getByte(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public short getShort(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public short getShort(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getInt(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getInt(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long getLong(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long getLong(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public float getFloat(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public float getFloat(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getDouble(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getDouble(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BigDecimal getBigDecimal(int colIdx, int scale) throws SQLException
{
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BigDecimal getBigDecimal(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BigDecimal getBigDecimal(String colLb, int scale) throws
SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BigDecimal getBigDecimal(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] getBytes(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] getBytes(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Date getDate(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Date getDate(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Date getDate(int colIdx, Calendar cal) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Date getDate(String colLb, Calendar cal) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Time getTime(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Time getTime(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Time getTime(int colIdx, Calendar cal) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Time getTime(String colLb, Calendar cal) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Timestamp getTimestamp(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Timestamp getTimestamp(int colIdx, Calendar cal) throws
SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ return getTimestamp(colIdx);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Timestamp getTimestamp(String colLb, Calendar cal) throws
SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Timestamp getTimestamp(String colLb) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getAsciiStream(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getAsciiStream(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getUnicodeStream(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getUnicodeStream(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getBinaryStream(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Stream are not supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public InputStream getBinaryStream(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public SQLWarning getWarnings() throws SQLException {
+ ensureNotClosed();
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void clearWarnings() throws SQLException {
+ ensureNotClosed();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getCursorName() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Cursor name is not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ResultSetMetaData getMetaData() throws SQLException {
+ ensureNotClosed();
+
+ return initMetadata();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int findColumn(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ try {
+ int index = rsMetadata.indexOf(colLb);
+ if (index >= 0) {
+ return index + 1;
+ }
+ } catch (Exception ignore) {
+ // ignore
+ }
+
+ throw new SQLException("Column not found: " + colLb,
SqlStateCode.INVALID_ARGUMENT);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Reader getCharacterStream(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Reader getCharacterStream(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Streams are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isBeforeFirst() throws SQLException {
+ ensureNotClosed();
+
+ return currentRow == null && rs.hasNext();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isAfterLast() throws SQLException {
+ ensureNotClosed();
+
+ boolean hasNext = rs.hasNext();
+ // Result set is empty
+ if (currentPosition == 0 && !hasNext) {
+ return false;
+ } else {
+ return currentRow == null && !hasNext;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isFirst() throws SQLException {
+ ensureNotClosed();
+
+ return currentRow != null && currentPosition == 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isLast() throws SQLException {
+ ensureNotClosed();
+
+ return currentRow != null && !rs.hasNext();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void beforeFirst() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void afterLast() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean first() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean last() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getRow() throws SQLException {
+ ensureNotClosed();
+
+ return isAfterLast() ? 0 : currentPosition;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean absolute(int row) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean relative(int rows) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean previous() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLException("Result set is forward-only.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setFetchDirection(int direction) throws SQLException {
+ ensureNotClosed();
+
+ if (direction != FETCH_FORWARD) {
+ throw new SQLFeatureNotSupportedException("Only forward direction
is supported");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getFetchDirection() throws SQLException {
+ ensureNotClosed();
+
+ return FETCH_FORWARD;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setFetchSize(int fetchSize) throws SQLException {
+ ensureNotClosed();
+
+ if (fetchSize <= 0) {
+ throw new SQLException("Fetch size must be greater than zero.");
+ }
+
+ this.fetchSize = fetchSize;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getFetchSize() throws SQLException {
+ ensureNotClosed();
+
+ return fetchSize;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getType() throws SQLException {
+ ensureNotClosed();
+
+ return TYPE_FORWARD_ONLY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getConcurrency() throws SQLException {
+ ensureNotClosed();
+
+ return CONCUR_READ_ONLY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean rowUpdated() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean rowInserted() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean rowDeleted() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNull(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNull(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBoolean(int colIdx, boolean x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBoolean(String colLb, boolean x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateByte(int colIdx, byte x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateByte(String colLb, byte x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateShort(int colIdx, short x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateShort(String colLb, short x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateInt(int colIdx, int x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateInt(String colLb, int x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateLong(int colIdx, long x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateLong(String colLb, long x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateFloat(int colIdx, float x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateFloat(String colLb, float x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateDouble(int colIdx, double x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateDouble(String colLb, double x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBigDecimal(int colIdx, BigDecimal x) throws SQLException
{
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBigDecimal(String colLb, BigDecimal x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateString(int colIdx, String x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateString(String colLb, String x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBytes(int colIdx, byte[] x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBytes(String colLb, byte[] x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateDate(int colIdx, Date x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateDate(String colLb, Date x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateTime(int colIdx, Time x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateTime(String colLb, Time x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateTimestamp(int colIdx, Timestamp x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateTimestamp(String colLb, Timestamp x) throws SQLException
{
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(int colIdx, InputStream x, int len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(String colLb, InputStream x, int len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(int colIdx, InputStream x, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(String colLb, InputStream x, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(int colIdx, InputStream x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateAsciiStream(String colLb, InputStream x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(int colIdx, InputStream x, int len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(int colIdx, InputStream x, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(String colLb, InputStream x, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(int colIdx, InputStream x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(String colLb, InputStream x, int len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBinaryStream(String colLb, InputStream x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(int colIdx, Reader x, int len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(String colLb, Reader reader, int len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(int colIdx, Reader x, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(String colLb, Reader reader, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(int colIdx, Reader x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCharacterStream(String colLb, Reader reader) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateObject(int colIdx, Object x, int scaleOrLen) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateObject(int colIdx, Object x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateObject(String colLb, Object x, int scaleOrLen) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateObject(String colLb, Object x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void insertRow() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateRow() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void deleteRow() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void refreshRow() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Row refreshing is not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void cancelRowUpdates() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException("Row updates are not
supported.");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void moveToInsertRow() throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void moveToCurrentRow() throws SQLException {
+ ensureNotClosed();
+
+ if (getConcurrency() == CONCUR_READ_ONLY) {
+ throw new SQLException("The result set concurrency is
CONCUR_READ_ONLY");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Statement getStatement() throws SQLException {
+ ensureNotClosed();
+
+ return statement;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Object getObject(int colIdx, Map<String, Class<?>> map) throws
SQLException {
+ throw new
SQLFeatureNotSupportedException(SQL_STRUCTURED_TYPE_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public <T> T getObject(int colIdx, Class<T> targetCls) throws SQLException
{
+ ensureNotClosed();
+
+ return (T) getObject0(colIdx, targetCls);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public <T> T getObject(String colLb, Class<T> type) throws SQLException {
+ int colIdx = findColumn(colLb);
+
+ return getObject(colIdx, type);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public Object getObject(int colIdx) throws SQLException {
+ return getValue(colIdx);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public Object getObject(String colLb) throws SQLException {
+ int colIdx = findColumn(colLb);
+
+ return getValue(colIdx);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Object getObject(String colLb, Map<String, Class<?>> map) throws
SQLException {
+ throw new
SQLFeatureNotSupportedException(SQL_STRUCTURED_TYPE_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Ref getRef(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Ref getRef(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Blob getBlob(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Blob getBlob(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Clob getClob(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Clob getClob(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Array getArray(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Array getArray(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public URL getURL(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public URL getURL(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateRef(int colIdx, Ref x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateRef(String colLb, Ref x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(int colIdx, Blob x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(String colLb, Blob x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(int colIdx, InputStream inputStream, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(String colLb, InputStream inputStream, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(int colIdx, InputStream inputStream) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateBlob(String colLb, InputStream inputStream) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(int colIdx, Clob x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(String colLb, Clob x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(int colIdx, Reader reader, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(String colLb, Reader reader, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(int colIdx, Reader reader) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateClob(String colLb, Reader reader) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateArray(int colIdx, Array x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateArray(String colLb, Array x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RowId getRowId(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RowId getRowId(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateRowId(int colIdx, RowId x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateRowId(String colLb, RowId x) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getHoldability() throws SQLException {
+ ensureNotClosed();
+
+ return HOLD_CURSORS_OVER_COMMIT;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isClosed() throws SQLException {
+ return closed || statement.isClosed();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNString(int colIdx, String val) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNString(String colLb, String val) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(int colIdx, NClob val) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(String colLb, NClob val) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(int colIdx, Reader reader, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(String colLb, Reader reader, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(int colIdx, Reader reader) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNClob(String colLb, Reader reader) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public NClob getNClob(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public NClob getNClob(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public SQLXML getSQLXML(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public SQLXML getSQLXML(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateSQLXML(int colIdx, SQLXML xmlObj) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateSQLXML(String colLb, SQLXML xmlObj) throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getNString(int colIdx) throws SQLException {
+ return getString(colIdx);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getNString(String colLb) throws SQLException {
+ return getString(colLb);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Reader getNCharacterStream(int colIdx) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Reader getNCharacterStream(String colLb) throws SQLException {
+ ensureNotClosed();
+
+ throw new
SQLFeatureNotSupportedException(SQL_SPECIFIC_TYPES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNCharacterStream(int colIdx, Reader x, long len) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNCharacterStream(String colLb, Reader reader, long len)
throws SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNCharacterStream(int colIdx, Reader x) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateNCharacterStream(String colLb, Reader reader) throws
SQLException {
+ ensureNotClosed();
+
+ throw new SQLFeatureNotSupportedException(UPDATES_ARE_NOT_SUPPORTED);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ if (!isWrapperFor(iface)) {
+ throw new SQLException("Result set is not a wrapper for " +
iface.getName());
+ }
+
+ return (T) this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return iface != null && iface.isAssignableFrom(JdbcResultSet.class);
+ }
+
+ /**
+ * Gets object field value by index.
+ *
+ * @param colIdx Column index.
+ * @return Object field value.
+ * @throws SQLException In case of error.
+ */
+ @Nullable
+ Object getValue(int colIdx) throws SQLException {
+ ensureNotClosed();
+ ensureHasCurrentRow();
+
+ if (colIdx < 1 || colIdx > rsMetadata.columns().size()) {
+ throw new SQLException("Invalid column index: " + colIdx,
SqlStateCode.INVALID_ARGUMENT);
+ }
+
+ try {
+ assert currentRow != null;
+ Object val = currentRow.value(colIdx - 1);
+
+ wasNull = val == null;
+
+ return val;
+ } catch (Exception e) {
+ Throwable cause =
IgniteExceptionMapperUtil.mapToPublicException(e);
+ throw new SQLException("Unable to value for column: " + colIdx,
cause);
+ }
+ }
+
+ /**
+ * Ensures that result set is positioned on a row.
+ *
+ * @throws SQLException If result set is not positioned on a row.
+ */
+ private void ensureHasCurrentRow() throws SQLException {
+ if (currentRow == null) {
+ throw new SQLException("Result set is not positioned on a row.");
+ }
+ }
+
+ /**
+ * Ensures that result set is not closed.
+ *
+ * @throws SQLException If result set is closed.
+ */
+ private void ensureNotClosed() throws SQLException {
+ if (closed) {
+ throw new SQLException("Result set is closed.",
SqlStateCode.INVALID_CURSOR_STATE);
+ }
+ }
+
+ /**
+ * Get object of given class.
+ *
+ * @param colIdx Column index.
+ * @param targetCls Class representing the Java data type to convert the
designated column to.
+ * @return Converted object.
+ * @throws SQLException On error.
+ */
+ private @Nullable Object getObject0(int colIdx, Class<?> targetCls) throws
SQLException {
+ if (targetCls == Boolean.class) {
+ return getBoolean(colIdx);
+ } else if (targetCls == Byte.class) {
+ return getByte(colIdx);
+ } else if (targetCls == Short.class) {
+ return getShort(colIdx);
+ } else if (targetCls == Integer.class) {
+ return getInt(colIdx);
+ } else if (targetCls == Long.class) {
+ return getLong(colIdx);
+ } else if (targetCls == Float.class) {
+ return getFloat(colIdx);
+ } else if (targetCls == Double.class) {
+ return getDouble(colIdx);
+ } else if (targetCls == String.class) {
+ return getString(colIdx);
+ } else if (targetCls == BigDecimal.class) {
+ return getBigDecimal(colIdx);
+ } else if (targetCls == Date.class) {
+ return getDate(colIdx);
+ } else if (targetCls == Time.class) {
+ return getTime(colIdx);
+ } else if (targetCls == Timestamp.class) {
+ return getTimestamp(colIdx);
+ } else if (targetCls == byte[].class) {
+ return getBytes(colIdx);
+ } else {
+ Object val = getValue(colIdx);
+
+ if (val == null) {
+ return null;
+ }
+
+ Class<?> cls = val.getClass();
+
+ if (targetCls.isAssignableFrom(cls)) {
+ return val;
+ } else {
+ throw new SQLException("Cannot convert to " +
targetCls.getName() + ": " + val, SqlStateCode.CONVERSION_FAILED);
+ }
+ }
+ }
+
+ private JdbcResultSetMetadata initMetadata() {
+ if (jdbcMeta == null) {
+ jdbcMeta = new JdbcResultSetMetadata(rsMetadata);
+ }
+ return jdbcMeta;
+ }
+}
diff --git
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/ColumnDefinition.java
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/ColumnDefinition.java
index 77d09118a96..720c0787237 100644
---
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/ColumnDefinition.java
+++
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/ColumnDefinition.java
@@ -31,7 +31,7 @@ public final class ColumnDefinition {
public final int scale;
public final boolean nullable;
- ColumnDefinition(
+ public ColumnDefinition(
String label,
ColumnType type,
int precision,
diff --git
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetBaseSelfTest.java
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetBaseSelfTest.java
index 0b20789a76c..c9ba5c1a0cc 100644
---
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetBaseSelfTest.java
+++
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetBaseSelfTest.java
@@ -51,6 +51,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
import org.apache.ignite.sql.ColumnType;
import org.jetbrains.annotations.Nullable;
@@ -128,6 +130,9 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
expectNotSupported(() -> rs.getSQLXML(1));
expectNotSupported(() -> rs.getSQLXML("C"));
+ expectNotSupported(() -> rs.getURL(1));
+ expectNotSupported(() -> rs.getURL("C"));
+
expectNotSupported(() -> rs.getObject(1, Map.of()));
expectNotSupported(() -> rs.getObject("C", Map.of()));
}
@@ -149,10 +154,14 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
}
@Test
- public void updateMethodsAreNotSupported() throws Exception {
+ public void notSupportedMethods() throws Exception {
try (ResultSet rs = createSingleRow(new ColumnDefinition("C",
ColumnType.STRING, 3, 0, false), "ABC")) {
assertTrue(rs.next());
+ expectNotSupported(rs::rowInserted);
+ expectNotSupported(rs::rowUpdated);
+ expectNotSupported(rs::rowDeleted);
+
expectNotSupported(() -> rs.updateBoolean(1, true));
expectNotSupported(() -> rs.updateBoolean("C", true));
@@ -273,11 +282,34 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
expectNotSupported(rs::insertRow);
expectNotSupported(rs::moveToInsertRow);
+
+ expectNotSupported(rs::getCursorName);
}
}
@Test
public void navigationMethods() throws SQLException {
+ // Empty result set
+ try (ResultSet rs = createResultSet(null,
+ List.of(new ColumnDefinition("C", ColumnType.STRING, 3, 0,
false)),
+ List.of())
+ ) {
+ assertFalse(rs.isBeforeFirst());
+ assertFalse(rs.isAfterLast());
+ assertFalse(rs.isFirst());
+ assertFalse(rs.isLast());
+ assertEquals(0, rs.getRow());
+
+ assertFalse(rs.next());
+
+ assertFalse(rs.isBeforeFirst());
+ assertFalse(rs.isAfterLast());
+ assertFalse(rs.isFirst());
+ assertFalse(rs.isLast());
+ assertEquals(0, rs.getRow());
+ }
+
+ // Non empty result set
try (ResultSet rs = createResultSet(null,
List.of(new ColumnDefinition("C", ColumnType.STRING, 3, 0,
false)),
List.of(List.of("A"), List.of("B")))
@@ -337,6 +369,11 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
rs.setFetchDirection(ResultSet.FETCH_FORWARD);
assertEquals(ResultSet.FETCH_FORWARD, rs.getFetchDirection());
+ expectSqlException(() ->
rs.setFetchDirection(ResultSet.FETCH_UNKNOWN),
+ "Only forward direction is supported");
+ expectSqlException(() ->
rs.setFetchDirection(ResultSet.FETCH_REVERSE),
+ "Only forward direction is supported");
+
assertEquals(ResultSet.CONCUR_READ_ONLY, rs.getConcurrency());
assertEquals(ResultSet.TYPE_FORWARD_ONLY, rs.getType());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
rs.getHoldability());
@@ -737,16 +774,11 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
expectPositioned(() -> rs.getBytes(1));
expectPositioned(() -> rs.getBytes("C"));
- expectPositioned(() -> rs.getURL(1));
- expectPositioned(() -> rs.getURL("C"));
-
// Do not require positioning
assertThat(rs.getType(), any(Integer.class));
assertThat(rs.getConcurrency(), any(Integer.class));
- assertNull(rs.getCursorName());
-
assertThat(rs.getFetchDirection(), any(Integer.class));
assertThat(rs.getFetchSize(), any(Integer.class));
@@ -777,6 +809,37 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
}
}
+ @Test
+ public void findColumn() throws SQLException {
+ List<ColumnDefinition> columns = List.of(
+ // Normalized - converted to uppercase
+ new ColumnDefinition("COLUMN", ColumnType.BOOLEAN, 0, 0,
false),
+ // Metadata stores ids in unquoted form
+ new ColumnDefinition("column", ColumnType.BOOLEAN, 0, 0,
false),
+ new ColumnDefinition("Column N", ColumnType.BOOLEAN, 0, 0,
false),
+ new ColumnDefinition(" ", ColumnType.BOOLEAN, 0, 0, false),
+ new ColumnDefinition(":)", ColumnType.BOOLEAN, 0, 0, false)
+ );
+
+ List<List<Object>> rows = IntStream.range(0, columns.size())
+ .mapToObj(i -> List.of((Object) true))
+ .collect(Collectors.toList());
+
+ try (ResultSet rs = createResultSet(null, columns, rows)) {
+ assertEquals(1, rs.findColumn("COLUMN"));
+ assertEquals(2, rs.findColumn("\"column\""));
+ assertEquals(3, rs.findColumn("\"Column N\""));
+ assertEquals(4, rs.findColumn("\" \""));
+ assertEquals(5, rs.findColumn("\":)\""));
+
+ expectSqlException(() -> rs.findColumn(" COLUMN "), "Column not
found: COLUMN ");
+ expectSqlException(() -> rs.findColumn(" column "), "Column not
found: column ");
+ expectSqlException(() -> rs.findColumn("x"), "Column not found:
x");
+ expectSqlException(() -> rs.findColumn(null), "Column not found:
null");
+ expectSqlException(() -> rs.findColumn(""), "Column not found: ");
+ }
+ }
+
@Test
public void close() throws SQLException {
try (ResultSet rs = createResultSet(null,
@@ -1058,7 +1121,7 @@ public abstract class JdbcResultSetBaseSelfTest extends
BaseIgniteAbstractTest {
assertThrows(SQLFeatureNotSupportedException.class, m::call);
}
- private static void expectSqlException(ResultSetMethod m, String message) {
+ protected static void expectSqlException(ResultSetMethod m, String
message) {
SQLException err = assertThrows(SQLException.class, m::call);
assertThat(err.getMessage(), containsString(message));
}
diff --git
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetSelfTest.java
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetSelfTest.java
index 773c4359235..fbacdef6b02 100644
---
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetSelfTest.java
+++
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcResultSetSelfTest.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.ignite.internal.jdbc.proto.event.JdbcColumnMeta;
import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.Disabled;
import org.mockito.Mockito;
/**
@@ -61,4 +62,18 @@ public class JdbcResultSetSelfTest extends
JdbcResultSetBaseSelfTest {
throw new RuntimeException("Unexpected exception", e);
}
}
+
+ // findColumn has bugs in the current JDBC driver it is not worth fixing
them
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140")
+ @Override
+ public void findColumn() throws SQLException {
+ super.navigationMethods();
+ }
+
+ // isAfterLast has bugs in the current JDBC driver it is not worth fixing
them
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140")
+ @Override
+ public void navigationMethods() throws SQLException {
+ super.navigationMethods();
+ }
}
diff --git
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcResultSet2SelfTest.java
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcResultSet2SelfTest.java
new file mode 100644
index 00000000000..c74a57f6dc8
--- /dev/null
+++
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcResultSet2SelfTest.java
@@ -0,0 +1,541 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.jdbc2;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.UUID;
+import org.apache.ignite.internal.jdbc.ColumnDefinition;
+import org.apache.ignite.internal.jdbc.JdbcResultSetBaseSelfTest;
+import org.apache.ignite.internal.sql.ColumnMetadataImpl;
+import org.apache.ignite.internal.sql.ColumnMetadataImpl.ColumnOriginImpl;
+import org.apache.ignite.internal.sql.ResultSetMetadataImpl;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.ColumnType;
+import org.apache.ignite.sql.ResultSetMetadata;
+import org.apache.ignite.sql.SqlRow;
+import org.apache.ignite.table.Tuple;
+import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.mockito.Mockito;
+import org.mockito.internal.stubbing.answers.ThrowsException;
+
+/**
+ * Runs JdbcResultSetCompatibilityBaseTest against modern
org.apache.ignite.internal.jdbc2.JdbcResultSet.
+ */
+public class JdbcResultSet2SelfTest extends JdbcResultSetBaseSelfTest {
+
+ // getXXX are not implemented yet
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26369: numerics
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26379: datetime
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140")
+ @Override
+ @ParameterizedTest
+ @EnumSource(names = {"PERIOD", "DURATION"}, mode = EnumSource.Mode.EXCLUDE)
+ public void wasNullPositional(ColumnType columnType) throws SQLException {
+ super.wasNullPositional(columnType);
+ }
+
+ // getXXX are not implemented yet
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26369: numerics
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26379: datetime
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140")
+ @Override
+ @ParameterizedTest
+ @EnumSource(names = {"PERIOD", "DURATION"}, mode = EnumSource.Mode.EXCLUDE)
+ public void wasNullNamed(ColumnType columnType) throws SQLException {
+ super.wasNullNamed(columnType);
+ }
+
+ // getXXX are not implemented yet
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26369: numerics
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26379: datetime
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140")
+ @Test
+ @Override
+ public void getUnknownColumn() throws SQLException {
+ super.getUnknownColumn();
+ }
+
+ @Test
+ public void unwrap() throws SQLException {
+ try (ResultSet rs = createResultSet(null,
+ List.of(new ColumnDefinition("C", ColumnType.BOOLEAN, 0, 0,
false)),
+ List.of(List.of(true)))
+ ) {
+ {
+ assertTrue(rs.isWrapperFor(JdbcResultSet.class));
+ JdbcResultSet unwrapped = rs.unwrap(JdbcResultSet.class);
+ assertNotNull(unwrapped);
+ }
+
+ {
+ assertTrue(rs.isWrapperFor(ResultSet.class));
+ ResultSet unwrapped = rs.unwrap(ResultSet.class);
+ assertNotNull(unwrapped);
+ }
+
+ {
+ assertFalse(rs.isWrapperFor(Connection.class));
+ SQLException err = assertThrows(SQLException.class, () ->
rs.unwrap(Connection.class));
+ assertThat(err.getMessage(), containsString("Result set is not
a wrapper for " + Connection.class.getName()));
+ }
+ }
+ }
+
+ @Test
+ @Override
+ public void getMetadata() throws SQLException {
+ try (ResultSet rs = createResultSet(null,
+ List.of(new ColumnDefinition("C", ColumnType.BOOLEAN, 0, 0,
false)),
+ List.of(List.of(true)))
+ ) {
+ ResultSetMetaData metaData = rs.getMetaData();
+ assertEquals(1, metaData.getColumnCount());
+ }
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void nextExceptionIsWrapped() {
+ // ClientResultSet hasNext() throws
+ {
+ Statement statement = Mockito.mock(Statement.class);
+
+ org.apache.ignite.sql.ResultSet<SqlRow> igniteRs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+
+ RuntimeException cause = new RuntimeException("Some error");
+ when(igniteRs.hasNext()).thenThrow(cause);
+
+ ResultSet rs = new JdbcResultSet(igniteRs, statement);
+
+ SQLException err = assertThrows(SQLException.class, rs::next);
+ assertEquals("Some error", err.getMessage());
+ assertInstanceOf(IgniteException.class, err.getCause());
+ assertSame(cause, err.getCause().getCause());
+ }
+
+ // ClientResultSet next() throws
+ {
+ Statement statement = Mockito.mock(Statement.class);
+
+ org.apache.ignite.sql.ResultSet<SqlRow> igniteRs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+
+ RuntimeException cause = new RuntimeException("Some error");
+ when(igniteRs.hasNext()).thenReturn(true);
+ when(igniteRs.next()).thenThrow(cause);
+
+ ResultSet rs = new JdbcResultSet(igniteRs, statement);
+
+ SQLException err = assertThrows(SQLException.class, rs::next);
+ assertEquals("Some error", err.getMessage());
+ assertInstanceOf(IgniteException.class, err.getCause());
+ assertSame(cause, err.getCause().getCause());
+ }
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void closeClosesResultSet() throws SQLException {
+ Statement statement = Mockito.mock(Statement.class);
+
+ org.apache.ignite.sql.ResultSet<SqlRow> igniteRs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+ when(igniteRs.metadata()).thenReturn(new
ResultSetMetadataImpl(List.of()));
+
+ ResultSet rs = new JdbcResultSet(igniteRs, statement);
+
+ rs.close();
+ rs.close();
+
+ verify(igniteRs, times(1)).close();
+ verify(igniteRs, times(1)).metadata();
+ verifyNoMoreInteractions(igniteRs);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void closeExceptionIsWrapped() {
+ Statement statement = Mockito.mock(Statement.class);
+
+ org.apache.ignite.sql.ResultSet<SqlRow> igniteRs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+
+ RuntimeException cause = new RuntimeException("Some error");
+ doAnswer(new ThrowsException(cause)).when(igniteRs).close();
+
+ ResultSet rs = new JdbcResultSet(igniteRs, statement);
+
+ SQLException err = assertThrows(SQLException.class, rs::close);
+ assertEquals("Some error", err.getMessage());
+ assertInstanceOf(IgniteException.class, err.getCause());
+ assertSame(cause, err.getCause().getCause());
+ }
+
+ @Test
+ public void getValueExceptionIsWrapped() throws SQLException {
+ Statement statement = Mockito.mock(Statement.class);
+
+ org.apache.ignite.sql.ResultSet<SqlRow> igniteRs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+ SqlRow row = Mockito.mock(SqlRow.class);
+
+ ColumnMetadataImpl column = new ColumnMetadataImpl("C",
ColumnType.INT32, 0, 0, false, null);
+
+ when(igniteRs.metadata()).thenReturn(new
ResultSetMetadataImpl(List.of(column)));
+ when(igniteRs.hasNext()).thenReturn(true);
+ when(igniteRs.next()).thenReturn(row);
+
+ RuntimeException cause = new RuntimeException("Corrupted value");
+ when(row.value(0)).thenThrow(cause);
+
+ JdbcResultSet rs = new JdbcResultSet(igniteRs, statement);
+ assertTrue(rs.next());
+
+ SQLException err = assertThrows(SQLException.class, () ->
rs.getValue(1));
+ assertEquals("Unable to value for column: 1", err.getMessage());
+ assertInstanceOf(IgniteException.class, err.getCause());
+ assertSame(cause, err.getCause().getCause());
+ }
+
+ @Override
+ protected ResultSet createResultSet(@Nullable ZoneId zoneId,
List<ColumnDefinition> cols, List<List<Object>> rows) {
+ Statement statement = Mockito.mock(Statement.class);
+
+ return createResultSet(statement, zoneId, cols, rows);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static ResultSet createResultSet(
+ Statement statement,
+ @SuppressWarnings("unused")
+ @Nullable ZoneId zoneId,
+ List<ColumnDefinition> cols,
+ List<List<Object>> rows
+ ) {
+
+ // ResultSet has no metadata
+ if (cols.isEmpty() && rows.isEmpty()) {
+ org.apache.ignite.sql.ResultSet<SqlRow> rs =
Mockito.mock(org.apache.ignite.sql.ResultSet.class);
+ when(rs.metadata()).thenReturn(null);
+
+ return new JdbcResultSet(rs, statement);
+ }
+
+ List<ColumnMetadata> apiCols = new ArrayList<>();
+ for (ColumnDefinition c : cols) {
+ String schema = c.schema;
+ String table = c.table;
+ String column = c.column != null ? c.column :
c.label.toUpperCase(Locale.US);
+ boolean nullable = true;
+ ColumnOriginImpl origin = new ColumnOriginImpl(schema, table,
column);
+ apiCols.add(new ColumnMetadataImpl(c.label, c.type, c.precision,
c.scale, nullable, origin));
+ }
+
+ ResultSetMetadata apiMeta = new ResultSetMetadataImpl(apiCols);
+
+ return new JdbcResultSet(new ResultSetStub(apiMeta, rows), statement);
+ }
+
+ private static class ResultSetStub implements
org.apache.ignite.sql.ResultSet<SqlRow> {
+ private final ResultSetMetadata meta;
+ private final Iterator<List<Object>> it;
+ private List<Object> current;
+
+ ResultSetStub(ResultSetMetadata meta, List<List<Object>> rows) {
+ this.meta = Objects.requireNonNull(meta, "meta");
+ this.it = rows.iterator();
+ this.current = null;
+ }
+
+ @Override
+ public ResultSetMetadata metadata() {
+ return meta;
+ }
+
+ @Override
+ public boolean hasRowSet() {
+ return true;
+ }
+
+ @Override
+ public long affectedRows() {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public boolean wasApplied() {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public void close() {
+ // Does nothing, checked separately.
+ }
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public SqlRow next() {
+ if (!it.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ current = it.next();
+ return new UnmodifiableSqlRow(current, meta);
+ }
+ }
+
+ private static class UnmodifiableSqlRow implements SqlRow {
+ private final List<Object> values;
+ private final ResultSetMetadata meta;
+
+ UnmodifiableSqlRow(List<Object> values, ResultSetMetadata meta) {
+ this.values = values;
+ this.meta = meta;
+ }
+
+ @Override
+ public ResultSetMetadata metadata() {
+ return meta;
+ }
+
+ @Override
+ public int columnCount() {
+ return meta.columns().size();
+ }
+
+ @Override
+ public String columnName(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public int columnIndex(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public <T> T valueOrDefault(String columnName, T defaultValue) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public Tuple set(String columnName, Object value) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public <T> T value(String columnName) throws IllegalArgumentException {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public <T> T value(int columnIndex) {
+ return (T) values.get(columnIndex);
+ }
+
+ @Override
+ public boolean booleanValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public boolean booleanValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public byte byteValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public byte byteValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public short shortValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public short shortValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public int intValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public int intValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public long longValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public long longValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public float floatValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public float floatValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public double doubleValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public double doubleValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public BigDecimal decimalValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public BigDecimal decimalValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public String stringValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public String stringValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public byte[] bytesValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public byte[] bytesValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public UUID uuidValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public UUID uuidValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalDate dateValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalDate dateValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalTime timeValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalTime timeValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalDateTime datetimeValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public LocalDateTime datetimeValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public Instant timestampValue(String columnName) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public Instant timestampValue(int columnIndex) {
+ throw new IllegalStateException("Should not be called");
+ }
+
+ @Override
+ public Iterator<Object> iterator() {
+ return values.iterator();
+ }
+ }
+}