This is an automated email from the ASF dual-hosted git repository.

ppa 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 c75b78b06b6 IGNITE-26314 Jdbc. Migrate JdbcDatabaseMetadata to use the 
new ResultSet implementation (#6965)
c75b78b06b6 is described below

commit c75b78b06b669a3c45cf7fe5c5cd1c0b7b7889bb
Author: Pavel Pereslegin <[email protected]>
AuthorDate: Sat Nov 15 11:46:13 2025 +0300

    IGNITE-26314 Jdbc. Migrate JdbcDatabaseMetadata to use the new ResultSet 
implementation (#6965)
---
 .../internal/jdbc/ItJdbcMetadataSelfTest.java      |  39 +-
 .../ignite/internal/jdbc/JdbcConnection.java       |   3 +-
 .../ignite/internal/jdbc/JdbcDatabaseMetadata.java | 600 +++++++++++----------
 .../org/apache/ignite/internal/jdbc/JdbcUtils.java | 335 ++++++++++++
 .../ignite/internal/jdbc2/ClientSyncResultSet.java |   5 +-
 .../internal/jdbc2/ClientSyncResultSetImpl.java    |   5 -
 .../ignite/internal/jdbc2/JdbcConnection2.java     |   2 +-
 .../ignite/internal/jdbc2/JdbcResultSet.java       |  11 +-
 .../ignite/internal/jdbc2/JdbcStatement2.java      |  17 +-
 .../jdbc/JdbcDatabaseMetadataSelfTest.java         |   3 +-
 .../internal/jdbc2/JdbcResultSet2SelfTest.java     | 329 +----------
 .../internal/jdbc2/JdbcStatement2SelfTest.java     |   3 +
 12 files changed, 707 insertions(+), 645 deletions(-)

diff --git 
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/internal/jdbc/ItJdbcMetadataSelfTest.java
 
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/internal/jdbc/ItJdbcMetadataSelfTest.java
index 2c95ec8e1c7..4ee44f2a613 100644
--- 
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/internal/jdbc/ItJdbcMetadataSelfTest.java
+++ 
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/internal/jdbc/ItJdbcMetadataSelfTest.java
@@ -36,10 +36,15 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.StringJoiner;
 import java.util.UUID;
-import org.apache.ignite.internal.jdbc.proto.event.JdbcColumnMeta;
+import org.apache.ignite.internal.jdbc2.JdbcResultSetMetadata;
+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.internal.sql.engine.util.SqlTestUtils;
 import org.apache.ignite.internal.type.NativeType;
 import org.apache.ignite.jdbc.AbstractJdbcSelfTest;
+import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.ColumnMetadata.ColumnOrigin;
 import org.apache.ignite.sql.ColumnType;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
@@ -77,24 +82,27 @@ public class ItJdbcMetadataSelfTest extends 
AbstractJdbcSelfTest {
         try {
             DatabaseMetaData dbMeta = conn.getMetaData();
 
-            List<JdbcColumnMeta> columnsMeta = new ArrayList<>();
+            List<ColumnMetadata> columnsMeta = new ArrayList<>();
             try (ResultSet rs = dbMeta.getColumns(null, "META", "TEST", null)) 
{
                 while (rs.next()) {
-                    JdbcColumnMeta meta = new JdbcColumnMeta(
-                            rs.getString("COLUMN_NAME"),
+                    ColumnOrigin origin = new ColumnOriginImpl(
                             rs.getString("TABLE_SCHEM"),
                             rs.getString("TABLE_NAME"),
+                            rs.getString("COLUMN_NAME")
+                    );
+                    ColumnMetadata meta = new ColumnMetadataImpl(
                             rs.getString("COLUMN_NAME"),
                             dataTypeToColumnType(rs.getInt("DATA_TYPE"), 
rs.getString("TYPE_NAME")),
-                            rs.getShort("COLUMN_SIZE"),
-                            rs.getShort("DECIMAL_DIGITS"),
-                            "YES".equals(rs.getString("IS_NULLABLE"))
+                            rs.getInt("COLUMN_SIZE"),
+                            rs.getInt("DECIMAL_DIGITS"),
+                            "YES".equals(rs.getString("IS_NULLABLE")),
+                            origin
                     );
                     columnsMeta.add(meta);
                 }
             }
 
-            ResultSetMetaData rsMeta = new JdbcResultSetMetadata(columnsMeta);
+            ResultSetMetaData rsMeta = new JdbcResultSetMetadata(new 
ResultSetMetadataImpl(columnsMeta));
             checkMeta(rsMeta);
         } finally {
             stmt.execute("DROP TABLE META.TEST;");
@@ -161,7 +169,6 @@ public class ItJdbcMetadataSelfTest extends 
AbstractJdbcSelfTest {
     }
 
     @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-26145";)
     public void testResultSetMetaDataColumns() throws Exception {
         createMetaTable();
 
@@ -169,10 +176,14 @@ public class ItJdbcMetadataSelfTest extends 
AbstractJdbcSelfTest {
             ResultSet rs = stmt.executeQuery("SELECT * FROM META.TEST t");
 
             assertNotNull(rs);
+            assertFalse(rs.isClosed());
 
             ResultSetMetaData meta = rs.getMetaData();
 
             checkMeta(meta);
+
+            rs.close();
+            assertTrue(rs.isClosed());
         } finally {
             stmt.execute("DROP TABLE META.TEST;");
         }
@@ -371,13 +382,13 @@ public class ItJdbcMetadataSelfTest extends 
AbstractJdbcSelfTest {
             expectColumn(metaData, 2, "TABLE_SCHEM", Types.VARCHAR);
             expectColumn(metaData, 3, "TABLE_NAME", Types.VARCHAR);
             expectColumn(metaData, 4, "COLUMN_NAME", Types.VARCHAR);
-            expectColumn(metaData, 5, "DATA_TYPE", Types.SMALLINT);
+            expectColumn(metaData, 5, "DATA_TYPE", Types.INTEGER);
             expectColumn(metaData, 6, "TYPE_NAME", Types.VARCHAR);
             expectColumn(metaData, 7, "COLUMN_SIZE", Types.INTEGER);
             expectColumn(metaData, 8, "BUFFER_LENGTH", Types.INTEGER);
             expectColumn(metaData, 9, "DECIMAL_DIGITS", Types.INTEGER);
             expectColumn(metaData, 10, "NUM_PREC_RADIX", Types.SMALLINT);
-            expectColumn(metaData, 11, "NULLABLE", Types.SMALLINT);
+            expectColumn(metaData, 11, "NULLABLE", Types.INTEGER);
             expectColumn(metaData, 12, "REMARKS", Types.VARCHAR);
             expectColumn(metaData, 13, "COLUMN_DEF", Types.VARCHAR);
             expectColumn(metaData, 14, "SQL_DATA_TYPE", Types.INTEGER);
@@ -923,7 +934,13 @@ public class ItJdbcMetadataSelfTest extends 
AbstractJdbcSelfTest {
             expectColumn(metaData, 1, "TABLE_TYPE", Types.VARCHAR);
 
             assertTrue(rs.next());
+
             assertEquals("TABLE", rs.getString("TABLE_TYPE"));
+
+            assertTrue(rs.next());
+
+            assertEquals("VIEW", rs.getString("TABLE_TYPE"));
+
             assertFalse(rs.next());
         }
     }
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java
index e6e12c1f2de..2485f8e6748 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java
@@ -477,7 +477,8 @@ public class JdbcConnection implements Connection {
         ensureNotClosed();
 
         if (metadata == null) {
-            metadata = new JdbcDatabaseMetadata(this, handler, 
connProps.getUrl(), connProps.getUsername());
+            metadata = new JdbcDatabaseMetadata(this, handler, 
connProps.getUrl(), connProps.getUsername(),
+                    connProps::getConnectionTimeZone);
         }
 
         return metadata;
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadata.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadata.java
index 8a7baea022b..6d4c911424b 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadata.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadata.java
@@ -24,6 +24,7 @@ import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
 import static java.sql.RowIdLifetime.ROWID_UNSUPPORTED;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
+import static 
org.apache.ignite.internal.jdbc.JdbcUtils.createObjectListResultSet;
 import static 
org.apache.ignite.internal.jdbc.proto.SqlStateCode.CONNECTION_CLOSED;
 
 import java.sql.Connection;
@@ -32,12 +33,13 @@ import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
 import java.sql.Types;
+import java.time.ZoneId;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.client.proto.ProtocolVersion;
 import org.apache.ignite.internal.jdbc.proto.IgniteQueryErrorCode;
 import org.apache.ignite.internal.jdbc.proto.JdbcQueryEventHandler;
@@ -54,6 +56,7 @@ import 
org.apache.ignite.internal.jdbc.proto.event.JdbcMetaTablesResult;
 import org.apache.ignite.internal.jdbc.proto.event.JdbcPrimaryKeyMeta;
 import org.apache.ignite.internal.jdbc.proto.event.JdbcTableMeta;
 import org.apache.ignite.internal.properties.IgniteProductVersion;
+import org.apache.ignite.internal.sql.ColumnMetadataImpl;
 import org.apache.ignite.sql.ColumnMetadata;
 import org.apache.ignite.sql.ColumnType;
 
@@ -84,6 +87,8 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData 
{
 
     private final Connection connection;
 
+    private final Supplier<ZoneId> timeZoneSupplier;
+
     /**
      * Constructor.
      *
@@ -91,17 +96,20 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
      * @param handler Handler.
      * @param url URL
      * @param userName User name,
+     * @param timeZoneSupplier Time zone supplier.
      */
     public JdbcDatabaseMetadata(
             Connection connection,
             JdbcQueryEventHandler handler,
             String url,
-            String userName
+            String userName,
+            Supplier<ZoneId> timeZoneSupplier
     ) {
         this.handler = handler;
         this.connection = connection;
         this.url = url;
         this.userName = userName;
+        this.timeZoneSupplier = timeZoneSupplier;
     }
 
     /** {@inheritDoc} */
@@ -819,16 +827,16 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String procedureNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("PROCEDURE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("PROCEDURE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("PROCEDURE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("", ColumnType.NULL),
-                new JdbcColumnMeta("", ColumnType.NULL),
-                new JdbcColumnMeta("", ColumnType.NULL),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("PROCEDURE_TYPE", ColumnType.INT16),
-                new JdbcColumnMeta("SPECIFIC_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("PROCEDURE_CAT", ColumnType.STRING),
+                columnMeta("PROCEDURE_SCHEM", ColumnType.STRING),
+                columnMeta("PROCEDURE_NAME", ColumnType.STRING),
+                columnMeta("", ColumnType.NULL),
+                columnMeta("", ColumnType.NULL),
+                columnMeta("", ColumnType.NULL),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("PROCEDURE_TYPE", ColumnType.INT16),
+                columnMeta("SPECIFIC_NAME", ColumnType.STRING)
         ));
     }
 
@@ -838,27 +846,27 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String colNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("PROCEDURE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("PROCEDURE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("PROCEDURE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_TYPE", ColumnType.INT16),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PRECISION", ColumnType.INT32),
-                new JdbcColumnMeta("LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("SCALE", ColumnType.INT16),
-                new JdbcColumnMeta("RADIX", ColumnType.INT16),
-                new JdbcColumnMeta("NULLABLE", ColumnType.INT16),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_DEF", ColumnType.STRING),
-                new JdbcColumnMeta("SQL_DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
-                new JdbcColumnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("ORDINAL_POSITION", ColumnType.INT32),
-                new JdbcColumnMeta("IS_NULLABLE", ColumnType.STRING),
-                new JdbcColumnMeta("SPECIFIC_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("PROCEDURE_CAT", ColumnType.STRING),
+                columnMeta("PROCEDURE_SCHEM", ColumnType.STRING),
+                columnMeta("PROCEDURE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_TYPE", ColumnType.INT16),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("PRECISION", ColumnType.INT32),
+                columnMeta("LENGTH", ColumnType.INT32),
+                columnMeta("SCALE", ColumnType.INT16),
+                columnMeta("RADIX", ColumnType.INT16),
+                columnMeta("NULLABLE", ColumnType.INT16),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("COLUMN_DEF", ColumnType.STRING),
+                columnMeta("SQL_DATA_TYPE", ColumnType.INT32),
+                columnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
+                columnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
+                columnMeta("ORDINAL_POSITION", ColumnType.INT32),
+                columnMeta("IS_NULLABLE", ColumnType.STRING),
+                columnMeta("SPECIFIC_NAME", ColumnType.STRING)
         ));
     }
 
@@ -868,17 +876,17 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             throws SQLException {
         ensureNotClosed();
 
-        final List<JdbcColumnMeta> meta = asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_TYPE", ColumnType.STRING),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("SELF_REFERENCING_COL_NAME", 
ColumnType.STRING),
-                new JdbcColumnMeta("REF_GENERATION", ColumnType.STRING));
+        List<ColumnMetadata> meta = asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("TABLE_TYPE", ColumnType.STRING),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("TYPE_CAT", ColumnType.STRING),
+                columnMeta("TYPE_SCHEM", ColumnType.STRING),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("SELF_REFERENCING_COL_NAME", ColumnType.STRING),
+                columnMeta("REF_GENERATION", ColumnType.STRING));
 
         boolean tblTypeMatch = false;
 
@@ -895,7 +903,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
         }
 
         if (!isValidCatalog(catalog) || !tblTypeMatch) {
-            return new JdbcResultSet(Collections.emptyList(), meta);
+            return createObjectListResultSet(meta);
         }
 
         try {
@@ -912,7 +920,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
                 rows.add(tableRow(tblMeta));
             }
 
-            return new JdbcResultSet(rows, meta);
+            return createObjectListResultSet(rows, meta, timeZoneSupplier);
         } catch (InterruptedException e) {
             throw new SQLException("Thread was interrupted.", e);
         } catch (ExecutionException e) {
@@ -933,13 +941,13 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getSchemas(String catalog, String schemaPtrn) throws 
SQLException {
         ensureNotClosed();
 
-        List<JdbcColumnMeta> meta = asList(
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_CATALOG", ColumnType.STRING)
+        List<ColumnMetadata> meta = asList(
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_CATALOG", ColumnType.STRING)
         );
 
         if (!isValidCatalog(catalog)) {
-            return new JdbcResultSet(Collections.emptyList(), meta);
+            return createObjectListResultSet(meta);
         }
 
         try {
@@ -960,7 +968,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
                 rows.add(row);
             }
 
-            return new JdbcResultSet(rows, meta);
+            return createObjectListResultSet(rows, meta, timeZoneSupplier);
         } catch (InterruptedException e) {
             throw new SQLException("Thread was interrupted.", e);
         } catch (ExecutionException e) {
@@ -976,8 +984,8 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getCatalogs() throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(singletonList(singletonList(CATALOG_NAME)),
-                asList(new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING)));
+        return 
createObjectListResultSet(singletonList(singletonList(CATALOG_NAME)),
+                asList(columnMeta("TABLE_CAT", ColumnType.STRING)), 
timeZoneSupplier);
     }
 
     /** {@inheritDoc} */
@@ -986,9 +994,9 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getTableTypes() throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(
-                asList(List.of(TYPE_TABLE, TYPE_VIEW)),
-                asList(new JdbcColumnMeta("TABLE_TYPE", ColumnType.STRING)));
+        return createObjectListResultSet(
+                asList(List.of(TYPE_TABLE), List.of(TYPE_VIEW)),
+                asList(columnMeta("TABLE_TYPE", ColumnType.STRING)), 
timeZoneSupplier);
     }
 
     /** {@inheritDoc} */
@@ -996,35 +1004,35 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getColumns(String catalog, String schemaPtrn, String 
tblNamePtrn, String colNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        final List<JdbcColumnMeta> meta = asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),      // 1
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),    // 2
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),     // 3
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),    // 4
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT16),       // 5
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),      // 6
-                new JdbcColumnMeta("COLUMN_SIZE", ColumnType.INT32),   // 7
-                new JdbcColumnMeta("BUFFER_LENGTH", ColumnType.INT32), // 8
-                new JdbcColumnMeta("DECIMAL_DIGITS", ColumnType.INT32), // 9
-                new JdbcColumnMeta("NUM_PREC_RADIX", ColumnType.INT16),  // 10
-                new JdbcColumnMeta("NULLABLE", ColumnType.INT16),        // 11
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),        // 12
-                new JdbcColumnMeta("COLUMN_DEF", ColumnType.STRING),     // 13
-                new JdbcColumnMeta("SQL_DATA_TYPE", ColumnType.INT32), // 14
-                new JdbcColumnMeta("SQL_DATETIME_SUB", ColumnType.INT32), // 15
-                new JdbcColumnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32), // 
16
-                new JdbcColumnMeta("ORDINAL_POSITION", ColumnType.INT32), // 17
-                new JdbcColumnMeta("IS_NULLABLE", ColumnType.STRING),    // 18
-                new JdbcColumnMeta("SCOPE_CATLOG", ColumnType.STRING),   // 19
-                new JdbcColumnMeta("SCOPE_SCHEMA", ColumnType.STRING),   // 20
-                new JdbcColumnMeta("SCOPE_TABLE", ColumnType.STRING),    // 21
-                new JdbcColumnMeta("SOURCE_DATA_TYPE", ColumnType.INT16), // 22
-                new JdbcColumnMeta("IS_AUTOINCREMENT", ColumnType.STRING), // 
23
-                new JdbcColumnMeta("IS_GENERATEDCOLUMN", ColumnType.STRING) // 
24
+        List<ColumnMetadata> meta = asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),      // 1
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),    // 2
+                columnMeta("TABLE_NAME", ColumnType.STRING),     // 3
+                columnMeta("COLUMN_NAME", ColumnType.STRING),    // 4
+                columnMeta("DATA_TYPE", ColumnType.INT32),       // 5
+                columnMeta("TYPE_NAME", ColumnType.STRING),      // 6
+                columnMeta("COLUMN_SIZE", ColumnType.INT32),   // 7
+                columnMeta("BUFFER_LENGTH", ColumnType.INT32), // 8
+                columnMeta("DECIMAL_DIGITS", ColumnType.INT32), // 9
+                columnMeta("NUM_PREC_RADIX", ColumnType.INT16),  // 10
+                columnMeta("NULLABLE", ColumnType.INT32),        // 11
+                columnMeta("REMARKS", ColumnType.STRING),        // 12
+                columnMeta("COLUMN_DEF", ColumnType.STRING),     // 13
+                columnMeta("SQL_DATA_TYPE", ColumnType.INT32), // 14
+                columnMeta("SQL_DATETIME_SUB", ColumnType.INT32), // 15
+                columnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32), // 16
+                columnMeta("ORDINAL_POSITION", ColumnType.INT32), // 17
+                columnMeta("IS_NULLABLE", ColumnType.STRING),    // 18
+                columnMeta("SCOPE_CATLOG", ColumnType.STRING),   // 19
+                columnMeta("SCOPE_SCHEMA", ColumnType.STRING),   // 20
+                columnMeta("SCOPE_TABLE", ColumnType.STRING),    // 21
+                columnMeta("SOURCE_DATA_TYPE", ColumnType.INT16), // 22
+                columnMeta("IS_AUTOINCREMENT", ColumnType.STRING), // 23
+                columnMeta("IS_GENERATEDCOLUMN", ColumnType.STRING) // 24
         );
 
         if (!isValidCatalog(catalog)) {
-            return new JdbcResultSet(Collections.emptyList(), meta);
+            return createObjectListResultSet(meta);
         }
 
         try {
@@ -1041,7 +1049,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
                 rows.add(columnRow(res.meta().get(i), i + 1));
             }
 
-            return new JdbcResultSet(rows, meta);
+            return createObjectListResultSet(rows, meta, timeZoneSupplier);
         } catch (InterruptedException e) {
             throw new SQLException("Thread was interrupted.", e);
         } catch (ExecutionException e) {
@@ -1057,15 +1065,15 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String colNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("GRANTOR", ColumnType.STRING),
-                new JdbcColumnMeta("GRANTEE", ColumnType.STRING),
-                new JdbcColumnMeta("PRIVILEGE", ColumnType.STRING),
-                new JdbcColumnMeta("IS_GRANTABLE", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("GRANTOR", ColumnType.STRING),
+                columnMeta("GRANTEE", ColumnType.STRING),
+                columnMeta("PRIVILEGE", ColumnType.STRING),
+                columnMeta("IS_GRANTABLE", ColumnType.STRING)
         ));
     }
 
@@ -1075,14 +1083,14 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String tblNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("GRANTOR", ColumnType.STRING),
-                new JdbcColumnMeta("GRANTEE", ColumnType.STRING),
-                new JdbcColumnMeta("PRIVILEGE", ColumnType.STRING),
-                new JdbcColumnMeta("IS_GRANTABLE", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("GRANTOR", ColumnType.STRING),
+                columnMeta("GRANTEE", ColumnType.STRING),
+                columnMeta("PRIVILEGE", ColumnType.STRING),
+                columnMeta("IS_GRANTABLE", ColumnType.STRING)
         ));
     }
 
@@ -1090,15 +1098,15 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     @Override
     public ResultSet getBestRowIdentifier(String catalog, String schema, 
String tbl, int scope,
             boolean nullable) throws SQLException {
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("SCOPE", ColumnType.INT16),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_SIZE", ColumnType.INT32),
-                new JdbcColumnMeta("BUFFER_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("DECIMAL_DIGITS", ColumnType.INT16),
-                new JdbcColumnMeta("PSEUDO_COLUMN", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("SCOPE", ColumnType.INT16),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_SIZE", ColumnType.INT32),
+                columnMeta("BUFFER_LENGTH", ColumnType.INT32),
+                columnMeta("DECIMAL_DIGITS", ColumnType.INT16),
+                columnMeta("PSEUDO_COLUMN", ColumnType.INT16)
         ));
     }
 
@@ -1107,15 +1115,15 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getVersionColumns(String catalog, String schema, String 
tbl) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("SCOPE", ColumnType.INT16),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_SIZE", ColumnType.INT32),
-                new JdbcColumnMeta("BUFFER_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("DECIMAL_DIGITS", ColumnType.INT16),
-                new JdbcColumnMeta("PSEUDO_COLUMN", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("SCOPE", ColumnType.INT16),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_SIZE", ColumnType.INT32),
+                columnMeta("BUFFER_LENGTH", ColumnType.INT32),
+                columnMeta("DECIMAL_DIGITS", ColumnType.INT16),
+                columnMeta("PSEUDO_COLUMN", ColumnType.INT16)
         ));
     }
 
@@ -1124,16 +1132,16 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getPrimaryKeys(String catalog, String schema, String tbl) 
throws SQLException {
         ensureNotClosed();
 
-        final List<JdbcColumnMeta> meta = asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("KEY_SEQ", ColumnType.INT16),
-                new JdbcColumnMeta("PK_NAME", ColumnType.STRING));
+        List<ColumnMetadata> meta = asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("KEY_SEQ", ColumnType.INT16),
+                columnMeta("PK_NAME", ColumnType.STRING));
 
         if (!isValidCatalog(catalog)) {
-            return new JdbcResultSet(Collections.emptyList(), meta);
+            return createObjectListResultSet(meta);
         }
 
         try {
@@ -1149,7 +1157,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
                 rows.addAll(primaryKeyRows(pkMeta));
             }
 
-            return new JdbcResultSet(rows, meta);
+            return createObjectListResultSet(rows, meta, timeZoneSupplier);
         } catch (InterruptedException e) {
             throw new SQLException("Thread was interrupted.", e);
         } catch (ExecutionException e) {
@@ -1164,21 +1172,21 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getImportedKeys(String catalog, String schema, String 
tbl) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("PKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("KEY_SEQ", ColumnType.INT16),
-                new JdbcColumnMeta("UPDATE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("DELETE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("FK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DEFERRABILITY", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("PKTABLE_CAT", ColumnType.STRING),
+                columnMeta("PKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("PKTABLE_NAME", ColumnType.STRING),
+                columnMeta("PKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("FKTABLE_CAT", ColumnType.STRING),
+                columnMeta("FKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("FKTABLE_NAME", ColumnType.STRING),
+                columnMeta("FKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("KEY_SEQ", ColumnType.INT16),
+                columnMeta("UPDATE_RULE", ColumnType.INT16),
+                columnMeta("DELETE_RULE", ColumnType.INT16),
+                columnMeta("FK_NAME", ColumnType.STRING),
+                columnMeta("PK_NAME", ColumnType.STRING),
+                columnMeta("DEFERRABILITY", ColumnType.INT16)
         ));
     }
 
@@ -1187,21 +1195,21 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
     public ResultSet getExportedKeys(String catalog, String schema, String 
tbl) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("PKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("KEY_SEQ", ColumnType.INT16),
-                new JdbcColumnMeta("UPDATE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("DELETE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("FK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DEFERRABILITY", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("PKTABLE_CAT", ColumnType.STRING),
+                columnMeta("PKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("PKTABLE_NAME", ColumnType.STRING),
+                columnMeta("PKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("FKTABLE_CAT", ColumnType.STRING),
+                columnMeta("FKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("FKTABLE_NAME", ColumnType.STRING),
+                columnMeta("FKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("KEY_SEQ", ColumnType.INT16),
+                columnMeta("UPDATE_RULE", ColumnType.INT16),
+                columnMeta("DELETE_RULE", ColumnType.INT16),
+                columnMeta("FK_NAME", ColumnType.STRING),
+                columnMeta("PK_NAME", ColumnType.STRING),
+                columnMeta("DEFERRABILITY", ColumnType.INT16)
         ));
     }
 
@@ -1211,21 +1219,21 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String foreignCatalog, String foreignSchema, String foreignTbl) 
throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("PKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("PKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("FKTABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("FKCOLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("KEY_SEQ", ColumnType.INT16),
-                new JdbcColumnMeta("UPDATE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("DELETE_RULE", ColumnType.INT16),
-                new JdbcColumnMeta("FK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PK_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DEFERRABILITY", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("PKTABLE_CAT", ColumnType.STRING),
+                columnMeta("PKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("PKTABLE_NAME", ColumnType.STRING),
+                columnMeta("PKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("FKTABLE_CAT", ColumnType.STRING),
+                columnMeta("FKTABLE_SCHEM", ColumnType.STRING),
+                columnMeta("FKTABLE_NAME", ColumnType.STRING),
+                columnMeta("FKCOLUMN_NAME", ColumnType.STRING),
+                columnMeta("KEY_SEQ", ColumnType.INT16),
+                columnMeta("UPDATE_RULE", ColumnType.INT16),
+                columnMeta("DELETE_RULE", ColumnType.INT16),
+                columnMeta("FK_NAME", ColumnType.STRING),
+                columnMeta("PK_NAME", ColumnType.STRING),
+                columnMeta("DEFERRABILITY", ColumnType.INT16)
         ));
     }
 
@@ -1326,26 +1334,26 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
                 (short) typeNullable, false, (short) typeSearchable, false, 
false, false, "ARRAY", 0, 0,
                 Types.ARRAY, 0, null));
 
-        return new JdbcResultSet(types, asList(
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("PRECISION", ColumnType.INT32),
-                new JdbcColumnMeta("LITERAL_PREFIX", ColumnType.STRING),
-                new JdbcColumnMeta("LITERAL_SUFFIX", ColumnType.STRING),
-                new JdbcColumnMeta("CREATE_PARAMS", ColumnType.STRING),
-                new JdbcColumnMeta("NULLABLE", ColumnType.INT16),
-                new JdbcColumnMeta("CASE_SENSITIVE", ColumnType.BOOLEAN),
-                new JdbcColumnMeta("SEARCHABLE", ColumnType.INT16),
-                new JdbcColumnMeta("UNSIGNED_ATTRIBUTE", ColumnType.BOOLEAN),
-                new JdbcColumnMeta("FIXED_PREC_SCALE", ColumnType.BOOLEAN),
-                new JdbcColumnMeta("AUTO_INCREMENT", ColumnType.BOOLEAN),
-                new JdbcColumnMeta("LOCAL_TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("MINIMUM_SCALE", ColumnType.INT16),
-                new JdbcColumnMeta("MAXIMUM_SCALE", ColumnType.INT16),
-                new JdbcColumnMeta("SQL_DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
-                new JdbcColumnMeta("NUM_PREC_RADIX", ColumnType.INT32)
-        ));
+        return createObjectListResultSet(types, asList(
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("PRECISION", ColumnType.INT32),
+                columnMeta("LITERAL_PREFIX", ColumnType.STRING),
+                columnMeta("LITERAL_SUFFIX", ColumnType.STRING),
+                columnMeta("CREATE_PARAMS", ColumnType.STRING),
+                columnMeta("NULLABLE", ColumnType.INT16),
+                columnMeta("CASE_SENSITIVE", ColumnType.BOOLEAN),
+                columnMeta("SEARCHABLE", ColumnType.INT16),
+                columnMeta("UNSIGNED_ATTRIBUTE", ColumnType.BOOLEAN),
+                columnMeta("FIXED_PREC_SCALE", ColumnType.BOOLEAN),
+                columnMeta("AUTO_INCREMENT", ColumnType.BOOLEAN),
+                columnMeta("LOCAL_TYPE_NAME", ColumnType.STRING),
+                columnMeta("MINIMUM_SCALE", ColumnType.INT16),
+                columnMeta("MAXIMUM_SCALE", ColumnType.INT16),
+                columnMeta("SQL_DATA_TYPE", ColumnType.INT32),
+                columnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
+                columnMeta("NUM_PREC_RADIX", ColumnType.INT32)
+        ), timeZoneSupplier);
     }
 
     /** {@inheritDoc} */
@@ -1354,23 +1362,23 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             boolean approximate) throws SQLException {
         ensureNotClosed();
 
-        final List<JdbcColumnMeta> meta = asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("NON_UNIQUE", ColumnType.BOOLEAN),
-                new JdbcColumnMeta("INDEX_QUALIFIER", ColumnType.STRING),
-                new JdbcColumnMeta("INDEX_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE", ColumnType.INT16),
-                new JdbcColumnMeta("ORDINAL_POSITION", ColumnType.INT16),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("ASC_OR_DESC", ColumnType.STRING),
-                new JdbcColumnMeta("CARDINALITY", ColumnType.INT32),
-                new JdbcColumnMeta("PAGES", ColumnType.INT32),
-                new JdbcColumnMeta("FILTER_CONDITION", ColumnType.STRING));
+        List<ColumnMetadata> meta = asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("NON_UNIQUE", ColumnType.BOOLEAN),
+                columnMeta("INDEX_QUALIFIER", ColumnType.STRING),
+                columnMeta("INDEX_NAME", ColumnType.STRING),
+                columnMeta("TYPE", ColumnType.INT16),
+                columnMeta("ORDINAL_POSITION", ColumnType.INT16),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("ASC_OR_DESC", ColumnType.STRING),
+                columnMeta("CARDINALITY", ColumnType.INT32),
+                columnMeta("PAGES", ColumnType.INT32),
+                columnMeta("FILTER_CONDITION", ColumnType.STRING));
 
         if (!isValidCatalog(catalog)) {
-            return new JdbcResultSet(Collections.emptyList(), meta);
+            return createObjectListResultSet(meta);
         }
 
         throw new UnsupportedOperationException("Index info is not supported 
yet.");
@@ -1454,14 +1462,14 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             int[] types) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TYPE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("CLASS_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("BASE_TYPE", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("TYPE_CAT", ColumnType.STRING),
+                columnMeta("TYPE_SCHEM", ColumnType.STRING),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("CLASS_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("BASE_TYPE", ColumnType.INT16)
         ));
     }
 
@@ -1501,13 +1509,13 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String typeNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TYPE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("SUPERTYPE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("SUPERTYPE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("SUPERTYPE_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("TYPE_CAT", ColumnType.STRING),
+                columnMeta("TYPE_SCHEM", ColumnType.STRING),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("SUPERTYPE_CAT", ColumnType.STRING),
+                columnMeta("SUPERTYPE_SCHEM", ColumnType.STRING),
+                columnMeta("SUPERTYPE_NAME", ColumnType.STRING)
         ));
     }
 
@@ -1517,11 +1525,11 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String tblNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("SUPERTABLE_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("SUPERTABLE_NAME", ColumnType.STRING)
         ));
     }
 
@@ -1531,28 +1539,28 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String attributeNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TYPE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("ATTR_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("ATTR_TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("ATTR_SIZE", ColumnType.INT32),
-                new JdbcColumnMeta("DECIMAL_DIGITS", ColumnType.INT32),
-                new JdbcColumnMeta("NUM_PREC_RADIX", ColumnType.INT32),
-                new JdbcColumnMeta("NULLABLE", ColumnType.INT32),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("ATTR_DEF", ColumnType.STRING),
-                new JdbcColumnMeta("SQL_DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
-                new JdbcColumnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("ORDINAL_POSITION", ColumnType.INT32),
-                new JdbcColumnMeta("IS_NULLABLE", ColumnType.STRING),
-                new JdbcColumnMeta("SCOPE_CATALOG", ColumnType.STRING),
-                new JdbcColumnMeta("SCOPE_SCHEMA", ColumnType.STRING),
-                new JdbcColumnMeta("SCOPE_TABLE", ColumnType.STRING),
-                new JdbcColumnMeta("SOURCE_DATA_TYPE", ColumnType.INT16)
+        return createObjectListResultSet(asList(
+                columnMeta("TYPE_CAT", ColumnType.STRING),
+                columnMeta("TYPE_SCHEM", ColumnType.STRING),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("ATTR_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("ATTR_TYPE_NAME", ColumnType.STRING),
+                columnMeta("ATTR_SIZE", ColumnType.INT32),
+                columnMeta("DECIMAL_DIGITS", ColumnType.INT32),
+                columnMeta("NUM_PREC_RADIX", ColumnType.INT32),
+                columnMeta("NULLABLE", ColumnType.INT32),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("ATTR_DEF", ColumnType.STRING),
+                columnMeta("SQL_DATA_TYPE", ColumnType.INT32),
+                columnMeta("SQL_DATETIME_SUB", ColumnType.INT32),
+                columnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
+                columnMeta("ORDINAL_POSITION", ColumnType.INT32),
+                columnMeta("IS_NULLABLE", ColumnType.STRING),
+                columnMeta("SCOPE_CATALOG", ColumnType.STRING),
+                columnMeta("SCOPE_SCHEMA", ColumnType.STRING),
+                columnMeta("SCOPE_TABLE", ColumnType.STRING),
+                columnMeta("SOURCE_DATA_TYPE", ColumnType.INT16)
         ));
     }
 
@@ -1630,14 +1638,14 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
 
     /** {@inheritDoc} */
     @Override
-    public ResultSet getClientInfoProperties() throws SQLException {
+    public ResultSet getClientInfoProperties() {
         // We do not check whether connection is closed as 
         // this operation is not expected to do any server calls.  
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("NAME", ColumnType.STRING),
-                new JdbcColumnMeta("MAX_LEN", ColumnType.INT32),
-                new JdbcColumnMeta("DEFAULT_VALUE", ColumnType.STRING),
-                new JdbcColumnMeta("DESCRIPTION", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("NAME", ColumnType.STRING),
+                columnMeta("MAX_LEN", ColumnType.INT32),
+                columnMeta("DEFAULT_VALUE", ColumnType.STRING),
+                columnMeta("DESCRIPTION", ColumnType.STRING)
         ));
     }
 
@@ -1649,13 +1657,13 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String functionNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("FUNCTION_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("FUNCTION_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("FUNCTION_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("FUNCTION_TYPE", ColumnType.STRING),
-                new JdbcColumnMeta("SPECIFIC_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("FUNCTION_CAT", ColumnType.STRING),
+                columnMeta("FUNCTION_SCHEM", ColumnType.STRING),
+                columnMeta("FUNCTION_NAME", ColumnType.STRING),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("FUNCTION_TYPE", ColumnType.STRING),
+                columnMeta("SPECIFIC_NAME", ColumnType.STRING)
         ));
     }
 
@@ -1665,24 +1673,24 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String colNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("FUNCTION_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("FUNCTION_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("FUNCTION_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_TYPE", ColumnType.INT16),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("TYPE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("PRECISION", ColumnType.INT32),
-                new JdbcColumnMeta("LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("SCALE", ColumnType.INT16),
-                new JdbcColumnMeta("RADIX", ColumnType.INT16),
-                new JdbcColumnMeta("NULLABLE", ColumnType.INT16),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("ORDINAL_POSITION", ColumnType.INT32),
-                new JdbcColumnMeta("IS_NULLABLE", ColumnType.STRING),
-                new JdbcColumnMeta("SPECIFIC_NAME", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("FUNCTION_CAT", ColumnType.STRING),
+                columnMeta("FUNCTION_SCHEM", ColumnType.STRING),
+                columnMeta("FUNCTION_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_TYPE", ColumnType.INT16),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("TYPE_NAME", ColumnType.STRING),
+                columnMeta("PRECISION", ColumnType.INT32),
+                columnMeta("LENGTH", ColumnType.INT32),
+                columnMeta("SCALE", ColumnType.INT16),
+                columnMeta("RADIX", ColumnType.INT16),
+                columnMeta("NULLABLE", ColumnType.INT16),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
+                columnMeta("ORDINAL_POSITION", ColumnType.INT32),
+                columnMeta("IS_NULLABLE", ColumnType.STRING),
+                columnMeta("SPECIFIC_NAME", ColumnType.STRING)
         ));
     }
 
@@ -1708,19 +1716,19 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             String colNamePtrn) throws SQLException {
         ensureNotClosed();
 
-        return new JdbcResultSet(Collections.emptyList(), asList(
-                new JdbcColumnMeta("TABLE_CAT", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_SCHEM", ColumnType.STRING),
-                new JdbcColumnMeta("TABLE_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("COLUMN_NAME", ColumnType.STRING),
-                new JdbcColumnMeta("DATA_TYPE", ColumnType.INT32),
-                new JdbcColumnMeta("COLUMN_SIZE", ColumnType.INT32),
-                new JdbcColumnMeta("DECIMAL_DIGITS", ColumnType.INT32),
-                new JdbcColumnMeta("NUM_PREC_RADIX", ColumnType.INT32),
-                new JdbcColumnMeta("COLUMN_USAGE", ColumnType.INT32),
-                new JdbcColumnMeta("REMARKS", ColumnType.STRING),
-                new JdbcColumnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
-                new JdbcColumnMeta("IS_NULLABLE", ColumnType.STRING)
+        return createObjectListResultSet(asList(
+                columnMeta("TABLE_CAT", ColumnType.STRING),
+                columnMeta("TABLE_SCHEM", ColumnType.STRING),
+                columnMeta("TABLE_NAME", ColumnType.STRING),
+                columnMeta("COLUMN_NAME", ColumnType.STRING),
+                columnMeta("DATA_TYPE", ColumnType.INT32),
+                columnMeta("COLUMN_SIZE", ColumnType.INT32),
+                columnMeta("DECIMAL_DIGITS", ColumnType.INT32),
+                columnMeta("NUM_PREC_RADIX", ColumnType.INT32),
+                columnMeta("COLUMN_USAGE", ColumnType.INT32),
+                columnMeta("REMARKS", ColumnType.STRING),
+                columnMeta("CHAR_OCTET_LENGTH", ColumnType.INT32),
+                columnMeta("IS_NULLABLE", ColumnType.STRING)
         ));
     }
 
@@ -1777,7 +1785,7 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
         row.add(CATALOG_NAME);                  // 1. TABLE_CAT
         row.add(colMeta.schemaName());          // 2. TABLE_SCHEM
         row.add(colMeta.tableName());           // 3. TABLE_NAME
-        row.add(colMeta.columnLabel());          // 4. COLUMN_NAME
+        row.add(colMeta.columnLabel());         // 4. COLUMN_NAME
         row.add(colMeta.dataType());            // 5. DATA_TYPE
         row.add(colMeta.dataTypeName());        // 6. TYPE_NAME
         row.add(colMeta.precision() == -1 ? null : colMeta.precision()); // 7. 
COLUMN_SIZE
@@ -1832,4 +1840,8 @@ public class JdbcDatabaseMetadata implements 
DatabaseMetaData {
             throw new SQLException("Connection is closed.", CONNECTION_CLOSED);
         }
     }
+
+    private static ColumnMetadata columnMeta(String name, ColumnType type) {
+        return new ColumnMetadataImpl(name, type, -1, -1, true, null);
+    }
 }
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java
new file mode 100644
index 00000000000..0a5e56a8f20
--- /dev/null
+++ b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java
@@ -0,0 +1,335 @@
+/*
+ * 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.jdbc;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import java.util.function.Supplier;
+import org.apache.ignite.internal.jdbc2.ClientSyncResultSet;
+import org.apache.ignite.internal.jdbc2.JdbcResultSet;
+import org.apache.ignite.internal.sql.ResultSetMetadataImpl;
+import org.apache.ignite.internal.util.TransformingIterator;
+import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.ResultSetMetadata;
+import org.apache.ignite.sql.SqlRow;
+import org.apache.ignite.table.Tuple;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Helper methods for creating a {@link ResultSet} using a list of objects.
+ */
+public class JdbcUtils {
+    /** System time zone supplier. */
+    private static final Supplier<ZoneId> defaultZoneSupplier = 
ZoneId::systemDefault;
+
+    /** Creates an empty {@link ResultSet} using the provided metadata. */
+    static ResultSet createObjectListResultSet(List<ColumnMetadata> 
columnsMeta) {
+        return createObjectListResultSet(List.of(), columnsMeta, 
defaultZoneSupplier);
+    }
+
+    /** Creates a {@link ResultSet} using the provided list of objects and 
metadata. */
+    public static ResultSet createObjectListResultSet(
+            List<List<Object>> rows,
+            List<ColumnMetadata> columnsMeta,
+            Supplier<ZoneId> timeZoneSupplier
+    ) {
+        return createObjectListResultSet(rows, columnsMeta, timeZoneSupplier, 
0);
+    }
+
+    /** Creates a {@link ResultSet} using the provided list of objects and 
metadata. */
+    public static ResultSet createObjectListResultSet(
+            List<List<Object>> rows,
+            List<ColumnMetadata> columnsMeta,
+            Supplier<ZoneId> timeZoneSupplier,
+            int maxRows
+    ) {
+        ResultSetMetadata meta = new ResultSetMetadataImpl(columnsMeta);
+
+        TransformingIterator<List<Object>, SqlRow> transformer =
+                new TransformingIterator<>(rows.iterator(), row -> {
+                    assert row.size() == meta.columns().size() : "rows=" + 
rows.size() + ", meta=" + meta.columns().size();
+
+                    return new ObjectListToSqlRowAdapter(row);
+                });
+
+        return new JdbcResultSet(
+                new IteratorBasedClientSyncResultSet(transformer, meta),
+                null,
+                timeZoneSupplier,
+                false,
+                maxRows
+        );
+    }
+
+    private static class IteratorBasedClientSyncResultSet implements 
ClientSyncResultSet {
+        private final ResultSetMetadata metadata;
+        private final Iterator<SqlRow> rowsIterator;
+
+        IteratorBasedClientSyncResultSet(Iterator<SqlRow> rowsIterator, 
ResultSetMetadata metadata) {
+            this.rowsIterator = rowsIterator;
+            this.metadata = metadata;
+        }
+
+        @Override
+        public ResultSetMetadata metadata() {
+            return metadata;
+        }
+
+        @Override
+        public boolean hasRowSet() {
+            return true;
+        }
+
+        @Override
+        public long affectedRows() {
+            return -1;
+        }
+
+        @Override
+        public boolean hasNextResultSet() {
+            return false;
+        }
+
+        @Override
+        public ClientSyncResultSet nextResultSet() {
+            throw new NoSuchElementException("Query has no more results");
+        }
+
+        @Override
+        public void close() {
+            // No-op.
+        }
+
+        @Override
+        public boolean hasNext() {
+            return rowsIterator.hasNext();
+        }
+
+        @Override
+        public SqlRow next() {
+            return rowsIterator.next();
+        }
+    }
+
+    private static class ObjectListToSqlRowAdapter implements SqlRow {
+        private final List<Object> row;
+
+        ObjectListToSqlRowAdapter(List<Object> row) {
+            this.row = row;
+        }
+
+        @Override
+        public <T> @Nullable T value(int columnIndex) {
+            return (T) row.get(columnIndex);
+        }
+
+        @Override
+        public <T> @Nullable T value(String columnName) throws 
IllegalArgumentException {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public ResultSetMetadata metadata() {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public int columnCount() {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public String columnName(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public int columnIndex(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public <T> @Nullable T valueOrDefault(String columnName, @Nullable T 
defaultValue) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public Tuple set(String columnName, @Nullable Object value) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public boolean booleanValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public boolean booleanValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public byte byteValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public byte byteValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public short shortValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public short shortValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public int intValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public int intValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public long longValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public long longValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public float floatValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public float floatValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public double doubleValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public double doubleValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public BigDecimal decimalValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public BigDecimal decimalValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public String stringValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public String stringValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public byte[] bytesValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public byte[] bytesValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public UUID uuidValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public UUID uuidValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalDate dateValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalDate dateValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalTime timeValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalTime timeValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalDateTime datetimeValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public LocalDateTime datetimeValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public Instant timestampValue(String columnName) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+
+        @Override
+        public Instant timestampValue(int columnIndex) {
+            throw new UnsupportedOperationException("This method should not be 
called.");
+        }
+    }
+}
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSet.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSet.java
index a565e073947..7ea83dcb6bc 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSet.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSet.java
@@ -26,7 +26,8 @@ import org.apache.ignite.sql.SqlRow;
 /**
  * Sync result set.
  */
-interface ClientSyncResultSet extends Iterator<SqlRow> {
+// TODO https://issues.apache.org/jira/browse/IGNITE-26145 Remove "public" 
modifier
+public interface ClientSyncResultSet extends Iterator<SqlRow> {
 
     ResultSetMetadata EMPTY_METADATA = new ResultSetMetadataImpl(List.of());
 
@@ -36,8 +37,6 @@ interface ClientSyncResultSet extends Iterator<SqlRow> {
 
     long affectedRows();
 
-    boolean wasApplied();
-
     boolean hasNextResultSet();
 
     ClientSyncResultSet nextResultSet();
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSetImpl.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSetImpl.java
index 2d1f49e909e..4074c9cfdf2 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSetImpl.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/ClientSyncResultSetImpl.java
@@ -52,11 +52,6 @@ final class ClientSyncResultSetImpl implements 
ClientSyncResultSet {
         return syncRs.affectedRows();
     }
 
-    @Override
-    public boolean wasApplied() {
-        return syncRs.wasApplied();
-    }
-
     @Override
     public boolean hasNextResultSet() {
         return rs.hasNextResultSet();
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection2.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection2.java
index d0bc1ee21db..b0048857158 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection2.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection2.java
@@ -161,7 +161,7 @@ public class JdbcConnection2 implements Connection {
         properties = props;
 
         //noinspection ThisEscapedInObjectConstruction
-        metadata = new JdbcDatabaseMetadata(this, eventHandler, 
props.getUrl(), props.getUsername());
+        metadata = new JdbcDatabaseMetadata(this, eventHandler, 
props.getUrl(), props.getUsername(), props::getConnectionTimeZone);
     }
 
     /** {@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
index 6863ffc40c3..7217037a804 100644
--- 
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
@@ -84,7 +84,7 @@ public class JdbcResultSet implements ResultSet {
 
     private final Supplier<ZoneId> zoneIdSupplier;
 
-    private final Statement statement;
+    private final @Nullable Statement statement;
 
     private final JdbcResultSetMetadata jdbcMeta;
 
@@ -105,9 +105,10 @@ public class JdbcResultSet implements ResultSet {
     /**
      * Constructor.
      */
-    JdbcResultSet(
+    // TODO https://issues.apache.org/jira/browse/IGNITE-26145 Remove "public" 
modifier
+    public JdbcResultSet(
             ClientSyncResultSet rs,
-            Statement statement,
+            @Nullable Statement statement,
             Supplier<ZoneId> zoneIdSupplier,
             boolean closeOnCompletion,
             int maxRows
@@ -135,6 +136,8 @@ public class JdbcResultSet implements ResultSet {
             return null;
         }
 
+        assert statement != null;
+
         ClientSyncResultSet clientResultSet;
 
         try {
@@ -1895,7 +1898,7 @@ public class JdbcResultSet implements ResultSet {
     /** {@inheritDoc} */
     @Override
     public boolean isClosed() throws SQLException {
-        return closed || statement.isClosed();
+        return closed || (statement != null && statement.isClosed());
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement2.java
 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement2.java
index 79efecb640d..04d272eac55 100644
--- 
a/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement2.java
+++ 
b/modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement2.java
@@ -510,12 +510,25 @@ public class JdbcStatement2 implements Statement {
         return FETCH_FORWARD;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * Gives the JDBC driver a hint as to the number of rows that should
+     * be fetched from the database. If the value specified is zero, then
+     * the hint is ignored. The default value is zero.
+     *
+     * <p>Note: the current implementation does not provide any means to 
change the number
+     * of rows after the statement has executed. Thus, changing this value 
after the statement
+     * has executed will not apply to the previously retrieved ResultSet.
+     *
+     * @param fetchSize the number of rows to fetch
+     * @exception SQLException if the condition {@code fetchSize >= 0} is not 
satisfied.
+     * @since 1.2
+     * @see #getFetchSize
+     */
     @Override
     public void setFetchSize(int fetchSize) throws SQLException {
         ensureNotClosed();
 
-        if (fetchSize <= 0) {
+        if (fetchSize < 0) {
             throw new SQLException("Invalid fetch size.");
         }
 
diff --git 
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadataSelfTest.java
 
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadataSelfTest.java
index 8713a69fd53..5c3be2cb10a 100644
--- 
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadataSelfTest.java
+++ 
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadataSelfTest.java
@@ -27,6 +27,7 @@ import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
+import java.time.ZoneId;
 import java.util.concurrent.ThreadLocalRandom;
 import org.apache.ignite.internal.client.proto.ProtocolVersion;
 import org.apache.ignite.internal.properties.IgniteProductVersion;
@@ -46,7 +47,7 @@ public class JdbcDatabaseMetadataSelfTest extends 
BaseIgniteAbstractTest {
 
         JdbcClientQueryEventHandler handler = 
Mockito.mock(JdbcClientQueryEventHandler.class);
         Connection connection = Mockito.mock(Connection.class);
-        DatabaseMetaData metaData = new JdbcDatabaseMetadata(connection, 
handler, jdbcUrl, username);
+        DatabaseMetaData metaData = new JdbcDatabaseMetadata(connection, 
handler, jdbcUrl, username, ZoneId::systemDefault);
 
         // Basic info
         assertTrue(metaData.allProceduresAreCallable());
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
index 54d52830544..ae7cbffe2b8 100644
--- 
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
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.jdbc2;
 
+import static 
org.apache.ignite.internal.jdbc.JdbcUtils.createObjectListResultSet;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -32,24 +33,15 @@ 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 java.util.function.Supplier;
 import org.apache.ignite.internal.jdbc.ColumnDefinition;
 import org.apache.ignite.internal.jdbc.JdbcResultSetBaseSelfTest;
@@ -59,9 +51,7 @@ 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.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -243,8 +233,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
     @Test
     public void maxRows() throws SQLException {
         ColumnMetadataImpl column = new ColumnMetadataImpl("C1", 
ColumnType.INT32, 0, 0, false, null);
-        ResultSetMetadata apiMeta = new ResultSetMetadataImpl(List.of(column));
-        Statement statement = Mockito.mock(Statement.class);
+        List<ColumnMetadata> meta = List.of(column);
         Supplier<ZoneId> zoneIdSupplier = ZoneId::systemDefault;
 
         List<List<Object>> rows = List.of(
@@ -254,7 +243,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
                 List.of(4)
         );
 
-        try (ResultSet rs = new JdbcResultSet(new ResultSetStub(apiMeta, 
rows), statement, zoneIdSupplier, false, 3)) {
+        try (ResultSet rs = createObjectListResultSet(rows, meta, 
zoneIdSupplier, 3)) {
             assertTrue(rs.next());
             assertTrue(rs.next());
             assertTrue(rs.next());
@@ -265,7 +254,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
 
         // no limit
 
-        try (ResultSet rs = new JdbcResultSet(new ResultSetStub(apiMeta, 
rows), statement, zoneIdSupplier, false, 0)) {
+        try (ResultSet rs = createObjectListResultSet(rows, meta, 
zoneIdSupplier, 0)) {
             assertTrue(rs.next());
             assertTrue(rs.next());
             assertTrue(rs.next());
@@ -277,45 +266,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
 
     @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);
-    }
-
-    private static ResultSet createResultSet(
-            Statement statement,
-            @SuppressWarnings("unused")
-            @Nullable ZoneId zoneId,
-            List<ColumnDefinition> cols,
-            List<List<Object>> rows
-    ) {
-        return createResultSet(statement, zoneId, cols, rows, 0);
-    }
-
-    private static ResultSet createResultSet(
-            Statement statement,
-            @SuppressWarnings("unused")
-            @Nullable ZoneId zoneId,
-            List<ColumnDefinition> cols,
-            List<List<Object>> rows,
-            int maxRows
-    ) {
-
-        Supplier<ZoneId> zoneIdSupplier = () -> {
-            if (zoneId != null) {
-                return zoneId;
-            } else {
-                return ZoneId.systemDefault();
-            }
-        };
-
-        // ResultSet has no metadata
-        if (cols.isEmpty() && rows.isEmpty()) {
-            ClientSyncResultSet rs = Mockito.mock(ClientSyncResultSet.class);
-            when(rs.metadata()).thenReturn(ClientSyncResultSet.EMPTY_METADATA);
-
-            return new JdbcResultSet(rs, statement, zoneIdSupplier, false, 0);
-        }
+        ZoneId timeZone = zoneId == null ? ZoneId.systemDefault() : zoneId;
 
         List<ColumnMetadata> apiCols = new ArrayList<>();
         for (ColumnDefinition c : cols) {
@@ -327,274 +278,6 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
             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, 
zoneIdSupplier, false, maxRows);
-    }
-
-    private static class ResultSetStub implements ClientSyncResultSet {
-        private final ResultSetMetadata meta;
-        private final Iterator<List<Object>> it;
-        private @Nullable 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 boolean hasNextResultSet() {
-            return false;
-        }
-
-        @Override
-        public ClientSyncResultSet nextResultSet() {
-            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();
-        }
+        return createObjectListResultSet(rows, apiCols, () -> timeZone, 0);
     }
 }
diff --git 
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatement2SelfTest.java
 
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatement2SelfTest.java
index 9b820028415..bb25988eae3 100644
--- 
a/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatement2SelfTest.java
+++ 
b/modules/jdbc/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatement2SelfTest.java
@@ -263,6 +263,9 @@ public class JdbcStatement2SelfTest extends 
BaseIgniteAbstractTest {
             stmt.setFetchSize(1000);
             assertEquals(1000, stmt.getFetchSize());
 
+            stmt.setFetchSize(0);
+            assertEquals(0, stmt.getFetchSize());
+
             assertThrowsSqlException(SQLException.class,
                     "Invalid fetch size.",
                     () -> stmt.setFetchSize(-1)


Reply via email to