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

jooger 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 dbece16fc9d IGNITE-26379 Jdbc. Add accessor methods to thin 
client-backed ResultSet (datetime types) (#6565)
dbece16fc9d is described below

commit dbece16fc9df01f48e8318aafc71f9e5ab0f26c1
Author: Max Zhuravkov <[email protected]>
AuthorDate: Tue Sep 23 10:36:19 2025 +0300

    IGNITE-26379 Jdbc. Add accessor methods to thin client-backed ResultSet 
(datetime types) (#6565)
---
 .../apache/ignite/internal/jdbc/JdbcResultSet.java |  25 +-
 .../ignite/internal/jdbc2/JdbcResultSet.java       | 287 +++++--
 .../internal/jdbc/JdbcResultSetBaseSelfTest.java   | 950 +++++++++++++++++++++
 .../internal/jdbc2/JdbcResultSet2SelfTest.java     |  30 +-
 4 files changed, 1210 insertions(+), 82 deletions(-)

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 3f05102064f..bb04f28be56 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
@@ -218,7 +218,7 @@ public class JdbcResultSet implements ResultSet {
     /**
      * Creates new result set.
      *
-     * @exception SQLException if a database access error occurs
+     * @throws SQLException if a database access error occurs
      */
     @TestOnly
     JdbcResultSet(List<List<Object>> rows, List<JdbcColumnMeta> meta, 
JdbcStatement stmt) throws SQLException {
@@ -345,7 +345,6 @@ public class JdbcResultSet implements ResultSet {
      * Close result set.
      *
      * @param removeFromResources If {@code true} cursor need to be removed 
from client resources.
-     *
      * @throws SQLException On error.
      */
     void close0(boolean removeFromResources) throws SQLException {
@@ -2226,7 +2225,7 @@ public class JdbcResultSet implements ResultSet {
     /**
      * Get object of given class.
      *
-     * @param colIdx    Column index.
+     * @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.
@@ -2376,20 +2375,28 @@ public class JdbcResultSet implements ResultSet {
             return formatWithPrecision(DATE_TIME, value, colIdx, jdbcMeta);
         }
 
-        static String formatDate(LocalDate value) {
-            return DATE.format(value);
+        static String formatDate(LocalDate value) throws SQLException {
+            try {
+                return DATE.format(value);
+            } catch (Exception e) {
+                throw new SQLException("Cannot convert to string: " + value, 
SqlStateCode.CONVERSION_FAILED, e);
+            }
         }
 
         private static String formatWithPrecision(
-                DateTimeFormatter formatter, 
-                TemporalAccessor value, 
+                DateTimeFormatter formatter,
+                TemporalAccessor value,
                 int colIdx,
                 JdbcResultSetMetadata jdbcMeta
         ) throws SQLException {
 
             StringBuilder sb = new StringBuilder();
 
-            formatter.formatTo(value, sb);
+            try {
+                formatter.formatTo(value, sb);
+            } catch (Exception e) {
+                throw new SQLException("Cannot convert to string: " + value, 
SqlStateCode.CONVERSION_FAILED, e);
+            }
 
             int precision = jdbcMeta.getPrecision(colIdx);
             if (precision <= 0) {
@@ -2400,7 +2407,7 @@ public class JdbcResultSet implements ResultSet {
 
             // Append nano seconds according to the specified precision.
             long nanos = value.getLong(ChronoField.NANO_OF_SECOND);
-            long scaled  = nanos / (long) Math.pow(10, 9 - precision);
+            long scaled = nanos / (long) Math.pow(10, 9 - precision);
 
             sb.append('.');
             for (int i = 0; i < precision; i++) {
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 31f00ee846b..b1f59cf45e9 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
@@ -40,14 +40,23 @@ import java.sql.SQLXML;
 import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.time.temporal.Temporal;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
 import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
+import java.util.function.Supplier;
 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.internal.util.StringUtils;
 import org.apache.ignite.sql.ColumnMetadata;
 import org.apache.ignite.sql.ColumnType;
 import org.apache.ignite.sql.ResultSetMetadata;
@@ -75,6 +84,8 @@ public class JdbcResultSet implements ResultSet {
 
     private final ResultSetMetadata rsMetadata;
 
+    private final Supplier<ZoneId> zoneIdSupplier;
+
     private final Statement statement;
 
     private int fetchSize;
@@ -94,17 +105,20 @@ public class JdbcResultSet implements ResultSet {
      */
     public JdbcResultSet(
             org.apache.ignite.sql.ResultSet<SqlRow> rs,
-            Statement statement
+            Statement statement,
+            Supplier<ZoneId> zoneIdSupplier
     ) {
         this.rs = rs;
 
         ResultSetMetadata metadata = rs.metadata();
         this.rsMetadata = metadata != null ? metadata : EMPTY_METADATA;
 
+        this.zoneIdSupplier = zoneIdSupplier;
         this.statement = statement;
         this.currentRow = null;
         this.closed = false;
         this.wasNull = false;
+        this.jdbcMeta = new JdbcResultSetMetadata(rsMetadata);
     }
 
     @Override
@@ -150,24 +164,41 @@ public class JdbcResultSet implements ResultSet {
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public String getString(int colIdx) throws SQLException {
         ensureNotClosed();
         ensureHasCurrentRow();
 
-        Object value = getValue(colIdx);
-        if (value == null) {
+        Object val = getValue(colIdx);
+        if (val == null) {
             return null;
         }
 
-        if (value instanceof Temporal || value instanceof byte[] || value 
instanceof UUID) {
-            throw new UnsupportedOperationException();
-        } else {
-            return String.valueOf(value);
+        ColumnType columnType = getColumnType(colIdx);
+        try {
+            switch (columnType) {
+                case DATE:
+                    return Formatters.formatDate((LocalDate) val);
+                case TIME:
+                    return Formatters.formatTime((LocalTime) val, 
getColumnPrecision(colIdx));
+                case DATETIME:
+                    return Formatters.formatDateTime((LocalDateTime) val, 
getColumnPrecision(colIdx));
+                case TIMESTAMP:
+                    LocalDateTime localDateTime = 
instantWithLocalTimeZone((Instant) val);
+                    return Formatters.formatDateTime(localDateTime, 
getColumnPrecision(colIdx));
+                case BYTE_ARRAY:
+                    return StringUtils.toHexString((byte[]) val);
+                default:
+                    return String.valueOf(val);
+            }
+        } catch (Exception e) {
+            throw conversionError("string", e);
         }
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public String getString(String colLb) throws SQLException {
         int colIdx = findColumn(colLb);
 
@@ -205,7 +236,7 @@ public class JdbcResultSet implements ResultSet {
                 // Fallthrough
         }
 
-        throw new SQLException("Cannot convert to boolean: " + val, 
SqlStateCode.CONVERSION_FAILED);
+        throw conversionError("boolean", val);
     }
 
     /** {@inheritDoc} */
@@ -537,10 +568,10 @@ public class JdbcResultSet implements ResultSet {
                 try {
                     return new BigDecimal(val.toString());
                 } catch (Exception e) {
-                    throw new SQLException("Cannot convert to BigDecimal: " + 
val, SqlStateCode.CONVERSION_FAILED, e);
+                    throw conversionError("BigDecimal", val, e);
                 }
             default:
-                throw new SQLException("Cannot convert to BigDecimal: " + val, 
SqlStateCode.CONVERSION_FAILED);
+                throw conversionError("BigDecimal", val);
         }
     }
 
@@ -574,118 +605,163 @@ public class JdbcResultSet implements ResultSet {
     /** {@inheritDoc} */
     @Override
     public byte[] getBytes(String colLb) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getBytes(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Date getDate(int colIdx) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        Object val = getValue(colIdx);
 
-        throw new UnsupportedOperationException();
+        if (val == null) {
+            return null;
+        }
+
+        ColumnType columnType = getColumnType(colIdx);
+        switch (columnType) {
+            case TIME:
+                return new Date(Time.valueOf((LocalTime) val).getTime());
+            case DATE:
+                return Date.valueOf((LocalDate) val);
+            case DATETIME:
+                return Date.valueOf(((LocalDateTime) val).toLocalDate());
+            case TIMESTAMP:
+                LocalDateTime localDateTime = 
instantWithLocalTimeZone((Instant) val);
+                return Date.valueOf(localDateTime.toLocalDate());
+            default:
+                throw conversionError("date", val);
+        }
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Date getDate(String colLb) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getDate(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Date getDate(int colIdx, Calendar cal) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
-
-        throw new UnsupportedOperationException();
+        return getDate(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Date getDate(String colLb, Calendar cal) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getDate(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Time getTime(int colIdx) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        Object val = getValue(colIdx);
 
-        throw new UnsupportedOperationException();
+        if (val == null) {
+            return null;
+        }
+
+        ColumnType columnType = getColumnType(colIdx);
+        switch (columnType) {
+            case TIME:
+                return Time.valueOf((LocalTime) val);
+            case DATE:
+                return new Time(Date.valueOf((LocalDate) val).getTime());
+            case DATETIME:
+                return Time.valueOf(((LocalDateTime) val).toLocalTime());
+            case TIMESTAMP:
+                LocalDateTime localDateTime = 
instantWithLocalTimeZone((Instant) val);
+                LocalTime localTime = localDateTime.toLocalTime();
+                return Time.valueOf(localTime);
+            default:
+                throw conversionError("time", val);
+        }
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Time getTime(String colLb) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getTime(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Time getTime(int colIdx, Calendar cal) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
-
-        throw new UnsupportedOperationException();
+        return getTime(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Time getTime(String colLb, Calendar cal) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getTime(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Timestamp getTimestamp(int colIdx) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        Object val = getValue(colIdx);
 
-        throw new UnsupportedOperationException();
+        if (val == null) {
+            return null;
+        }
+
+        ColumnType columnType = getColumnType(colIdx);
+        switch (columnType) {
+            case TIME:
+                return new Timestamp(Time.valueOf((LocalTime) val).getTime());
+            case DATE:
+                return new Timestamp(Date.valueOf((LocalDate) val).getTime());
+            case DATETIME:
+                return Timestamp.valueOf((LocalDateTime) val);
+            case TIMESTAMP:
+                LocalDateTime localDateTime = 
instantWithLocalTimeZone((Instant) val);
+                return Timestamp.valueOf(localDateTime);
+            default:
+                throw conversionError("timestamp", val);
+        }
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Timestamp getTimestamp(int colIdx, Calendar cal) throws 
SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
-
         return getTimestamp(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Timestamp getTimestamp(String colLb, Calendar cal) throws 
SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getTimestamp(colIdx);
     }
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public Timestamp getTimestamp(String colLb) throws SQLException {
-        ensureNotClosed();
-        ensureHasCurrentRow();
+        int colIdx = findColumn(colLb);
 
-        throw new UnsupportedOperationException();
+        return getTimestamp(colIdx);
     }
 
     /** {@inheritDoc} */
@@ -764,7 +840,7 @@ public class JdbcResultSet implements ResultSet {
     public ResultSetMetaData getMetaData() throws SQLException {
         ensureNotClosed();
 
-        return initMetadata();
+        return jdbcMeta;
     }
 
     /** {@inheritDoc} */
@@ -1860,6 +1936,7 @@ public class JdbcResultSet implements ResultSet {
 
     /** {@inheritDoc} */
     @Override
+    @Nullable
     public String getNString(int colIdx) throws SQLException {
         return getString(colIdx);
     }
@@ -2037,18 +2114,17 @@ public class JdbcResultSet implements ResultSet {
         }
     }
 
-    private JdbcResultSetMetadata initMetadata() {
-        if (jdbcMeta == null) {
-            jdbcMeta = new JdbcResultSetMetadata(rsMetadata);
-        }
-        return jdbcMeta;
-    }
-
     private ColumnType getColumnType(int colIdx) {
         ColumnMetadata column = rsMetadata.columns().get(colIdx - 1);
         return column.type();
     }
 
+    private int getColumnPrecision(int colIdx) {
+        int precision = rsMetadata.columns().get(colIdx - 1).precision();
+        assert precision <= 9 : "Precision is out of range. Precision: " + 
precision + ". Column: " + colIdx;
+        return precision;
+    }
+
     private static long getLongValue(long val, String typeName, long min, long 
max) throws SQLException {
         if (val < min || val > max) {
             throw conversionError(typeName, val);
@@ -2101,4 +2177,93 @@ public class JdbcResultSet implements ResultSet {
     private static SQLException conversionError(String typeName, Object val, 
@Nullable Throwable cause) {
         return new SQLException(format("Cannot convert to {}: {}", typeName, 
val), SqlStateCode.CONVERSION_FAILED, cause);
     }
+
+    private LocalDateTime instantWithLocalTimeZone(Instant val) {
+        ZoneId zoneId = zoneIdSupplier.get();
+        if (zoneId == null) {
+            zoneId = ZoneId.systemDefault();
+        }
+        return LocalDateTime.ofInstant(val, zoneId);
+    }
+
+    private static class Formatters {
+        static final DateTimeFormatter TIME = new DateTimeFormatterBuilder()
+                .appendValue(ChronoField.HOUR_OF_DAY, 2)
+                .appendLiteral(':')
+                .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+                .appendLiteral(':')
+                .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+                .toFormatter();
+
+        static final DateTimeFormatter DATE = new DateTimeFormatterBuilder()
+                .appendValue(ChronoField.YEAR, 4)
+                .appendLiteral('-')
+                .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+                .appendLiteral('-')
+                .appendValue(ChronoField.DAY_OF_MONTH, 2)
+                .toFormatter();
+
+        static final DateTimeFormatter DATE_TIME = new 
DateTimeFormatterBuilder()
+                .appendValue(ChronoField.YEAR, 4)
+                .appendLiteral('-')
+                .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+                .appendLiteral('-')
+                .appendValue(ChronoField.DAY_OF_MONTH, 2)
+                .appendLiteral(' ')
+                .appendValue(ChronoField.HOUR_OF_DAY, 2)
+                .appendLiteral(':')
+                .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+                .appendLiteral(':')
+                .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+                .toFormatter();
+
+        static String formatTime(LocalTime value, int precision) {
+            return formatWithPrecision(TIME, value, precision);
+        }
+
+        static String formatDateTime(LocalDateTime value, int precision) {
+            return formatWithPrecision(DATE_TIME, value, precision);
+        }
+
+        static String formatDate(LocalDate value) {
+            return DATE.format(value);
+        }
+
+        private static String formatWithPrecision(
+                DateTimeFormatter formatter,
+                TemporalAccessor value,
+                int precision
+        ) {
+
+            StringBuilder sb = new StringBuilder();
+
+            formatter.formatTo(value, sb);
+
+            if (precision <= 0) {
+                return sb.toString();
+            }
+
+            // Append nano seconds according to the specified precision.
+            long nanos = value.getLong(ChronoField.NANO_OF_SECOND);
+            long scaled = nanos / (long) Math.pow(10, 9 - precision);
+
+            sb.append('.');
+            for (int i = 0; i < precision; i++) {
+                sb.append('0');
+            }
+
+            int pos = precision - 1;
+            int start = sb.length() - precision;
+
+            do {
+                int digit = (int) (scaled % 10);
+                char c = (char) ('0' + digit);
+                sb.setCharAt(start + pos, c);
+                scaled /= 10;
+                pos--;
+            } while (scaled != 0 && pos >= 0);
+
+            return sb.toString();
+        }
+    }
 }
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 48efc7cf7ed..5347a1b8413 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
@@ -41,11 +41,16 @@ import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.time.Clock;
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -157,6 +162,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(boolValue, rs.getObject(1));
@@ -186,6 +209,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -280,6 +312,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -309,6 +359,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -478,6 +537,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -509,6 +586,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -682,6 +768,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -715,6 +819,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -888,6 +1001,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -923,6 +1054,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -1081,7 +1221,9 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(decimalVal, rs.getBigDecimal(1));
             assertEquals(decimalVal, rs.getBigDecimal("C"));
 
+            //noinspection deprecation
             assertEquals(decimalScaledVal, rs.getBigDecimal(1, 2));
+            //noinspection deprecation
             assertEquals(decimalScaledVal, rs.getBigDecimal("C", 2));
 
             assertEquals(strVal, rs.getString(1));
@@ -1090,6 +1232,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -1127,6 +1287,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -1256,7 +1425,9 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             //noinspection NumericCastThatLosesPrecision
             assertEquals((long) value, rs.getLong("C"));
 
+            //noinspection NumericCastThatLosesPrecision
             assertEquals((float) value, rs.getFloat(1));
+            //noinspection NumericCastThatLosesPrecision
             assertEquals((float) value, rs.getFloat("C"));
 
             assertEquals(value, rs.getDouble(1));
@@ -1276,6 +1447,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -1315,6 +1504,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -1444,6 +1642,24 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(value, rs.getBigDecimal(1));
             assertEquals(value, rs.getBigDecimal("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
             //noinspection deprecation
             assertEquals(decimalScaledVal, rs.getBigDecimal(1, 2));
             //noinspection deprecation
@@ -1455,6 +1671,23 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getNString(1));
             assertEquals(strVal, rs.getNString("C"));
 
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+
             // getObject
 
             assertEquals(value, rs.getObject(1));
@@ -1484,6 +1717,15 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
             assertEquals(strVal, rs.getObject(1, String.class));
             assertEquals(strVal, rs.getObject("C", String.class));
 
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+
             expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
             expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
         }
@@ -1718,6 +1960,714 @@ public abstract class JdbcResultSetBaseSelfTest extends 
BaseIgniteAbstractTest {
         }
     }
 
+    @ParameterizedTest
+    @ValueSource(strings = {"", "abc"})
+    public void getString(String value) throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.STRING, 0, 0, false), value)) {
+            assertTrue(rs.next());
+
+            expectSqlConversionError(() -> rs.getBoolean(1), "boolean");
+            expectSqlConversionError(() -> rs.getBoolean("C"), "boolean");
+
+            expectSqlConversionError(() -> rs.getByte(1), "byte");
+            expectSqlConversionError(() -> rs.getByte("C"), "byte");
+
+            expectSqlConversionError(() -> rs.getShort(1), "short");
+            expectSqlConversionError(() -> rs.getShort("C"), "short");
+
+            expectSqlConversionError(() -> rs.getInt(1), "int");
+            expectSqlConversionError(() -> rs.getInt("C"), "int");
+
+            expectSqlConversionError(() -> rs.getLong(1), "long");
+            expectSqlConversionError(() -> rs.getLong("C"), "long");
+
+            expectSqlConversionError(() -> rs.getFloat(1), "float");
+            expectSqlConversionError(() -> rs.getFloat("C"), "float");
+
+            expectSqlConversionError(() -> rs.getDouble(1), "double");
+            expectSqlConversionError(() -> rs.getDouble("C"), "double");
+
+            expectSqlConversionError(() -> rs.getBigDecimal(1), "BigDecimal");
+            expectSqlConversionError(() -> rs.getBigDecimal("C"), 
"BigDecimal");
+
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal(1, 2), 
"BigDecimal");
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal("C", 4), 
"BigDecimal");
+
+            assertEquals(value, rs.getString(1));
+            assertEquals(value, rs.getString("C"));
+
+            assertEquals(value, rs.getNString(1));
+            assertEquals(value, rs.getNString("C"));
+
+            expectSqlConversionError(() -> rs.getDate(1), "date");
+            expectSqlConversionError(() -> rs.getDate("C"), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1), "time");
+            expectSqlConversionError(() -> rs.getTime("C"), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C"), "timestamp");
+
+            expectSqlConversionError(() -> rs.getDate(1, 
Calendar.getInstance()), "date");
+            expectSqlConversionError(() -> rs.getDate("C", 
Calendar.getInstance()), "date");
+
+            expectSqlConversionError(() -> rs.getTime(1, 
Calendar.getInstance()), "time");
+            expectSqlConversionError(() -> rs.getTime("C", 
Calendar.getInstance()), "time");
+
+            expectSqlConversionError(() -> rs.getTimestamp(1, 
Calendar.getInstance()), "timestamp");
+            expectSqlConversionError(() -> rs.getTimestamp("C", 
Calendar.getInstance()), "timestamp");
+
+            // getObject
+
+            assertEquals(value, rs.getObject(1));
+            assertEquals(value, rs.getObject("C"));
+
+            expectSqlConversionError(() -> rs.getObject(1, Boolean.class), 
"boolean");
+            expectSqlConversionError(() -> rs.getObject("C", Boolean.class), 
"boolean");
+
+            expectSqlConversionError(() -> rs.getObject(1, Byte.class), 
"byte");
+            expectSqlConversionError(() -> rs.getObject("C", Byte.class), 
"byte");
+
+            expectSqlConversionError(() -> rs.getObject(1, Short.class), 
"short");
+            expectSqlConversionError(() -> rs.getObject("C", Short.class), 
"short");
+
+            expectSqlConversionError(() -> rs.getObject(1, Integer.class), 
"int");
+            expectSqlConversionError(() -> rs.getObject("C", Integer.class), 
"int");
+
+            expectSqlConversionError(() -> rs.getObject(1, Long.class), 
"long");
+            expectSqlConversionError(() -> rs.getObject("C", Long.class), 
"long");
+
+            expectSqlConversionError(() -> rs.getObject(1, BigDecimal.class), 
"BigDecimal");
+            expectSqlConversionError(() -> rs.getObject("C", 
BigDecimal.class), "BigDecimal");
+
+            assertEquals(value, rs.getObject(1, String.class));
+            assertEquals(value, rs.getObject("C", String.class));
+
+            expectSqlConversionError(() -> rs.getObject(1, Date.class), 
"date");
+            expectSqlConversionError(() -> rs.getObject("C", Date.class), 
"date");
+
+            expectSqlConversionError(() -> rs.getObject(1, Time.class), 
"time");
+            expectSqlConversionError(() -> rs.getObject("C", Time.class), 
"time");
+
+            expectSqlConversionError(() -> rs.getObject(1, Timestamp.class), 
"timestamp");
+            expectSqlConversionError(() -> rs.getObject("C", Timestamp.class), 
"timestamp");
+        }
+    }
+
+    @ParameterizedTest
+    @MethodSource("getDateValues")
+    public void getDate(LocalDate value) throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.DATE, 0, 0, false), value)) {
+            assertTrue(rs.next());
+
+            String strVal = value.format(DateTimeFormatter.ISO_DATE);
+
+            expectSqlConversionError(() -> rs.getBoolean(1), "boolean");
+            expectSqlConversionError(() -> rs.getBoolean("C"), "boolean");
+
+            expectSqlConversionError(() -> rs.getByte(1), "byte");
+            expectSqlConversionError(() -> rs.getByte("C"), "byte");
+
+            expectSqlConversionError(() -> rs.getShort(1), "short");
+            expectSqlConversionError(() -> rs.getShort("C"), "short");
+
+            expectSqlConversionError(() -> rs.getInt(1), "int");
+            expectSqlConversionError(() -> rs.getInt("C"), "int");
+
+            expectSqlConversionError(() -> rs.getLong(1), "long");
+            expectSqlConversionError(() -> rs.getLong("C"), "long");
+
+            expectSqlConversionError(() -> rs.getFloat(1), "float");
+            expectSqlConversionError(() -> rs.getFloat("C"), "float");
+
+            expectSqlConversionError(() -> rs.getDouble(1), "double");
+            expectSqlConversionError(() -> rs.getDouble("C"), "double");
+
+            expectSqlConversionError(() -> rs.getBigDecimal(1), "BigDecimal");
+            expectSqlConversionError(() -> rs.getBigDecimal("C"), 
"BigDecimal");
+
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal(1, 2), 
"BigDecimal");
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal("C", 4), 
"BigDecimal");
+
+            assertEquals(strVal, rs.getString(1));
+            assertEquals(strVal, rs.getString("C"));
+
+            assertEquals(strVal, rs.getNString(1));
+            assertEquals(strVal, rs.getNString("C"));
+
+            assertEquals(Date.valueOf(value), rs.getDate(1));
+            assertEquals(Date.valueOf(value), rs.getDate("C"));
+
+            assertEquals(LocalTime.of(0, 0, 0), rs.getTime(1).toLocalTime());
+            assertEquals(LocalTime.of(0, 0, 0), rs.getTime("C").toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getTimestamp(1));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getTimestamp("C"));
+
+            assertEquals(Date.valueOf(value), rs.getDate(1, 
Calendar.getInstance()));
+            assertEquals(Date.valueOf(value), rs.getDate("C", 
Calendar.getInstance()));
+
+            assertEquals(LocalTime.of(0, 0, 0), rs.getTime(1, 
Calendar.getInstance()).toLocalTime());
+            assertEquals(LocalTime.of(0, 0, 0), rs.getTime("C", 
Calendar.getInstance()).toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getTimestamp(1, Calendar.getInstance()));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getTimestamp("C", Calendar.getInstance()));
+
+            // getObject
+
+            expectSqlConversionError(() -> rs.getObject(1, Boolean.class), 
"boolean");
+            expectSqlConversionError(() -> rs.getObject("C", Boolean.class), 
"boolean");
+
+            expectSqlConversionError(() -> rs.getObject(1, Byte.class), 
"byte");
+            expectSqlConversionError(() -> rs.getObject("C", Byte.class), 
"byte");
+
+            expectSqlConversionError(() -> rs.getObject(1, Short.class), 
"short");
+            expectSqlConversionError(() -> rs.getObject("C", Short.class), 
"short");
+
+            expectSqlConversionError(() -> rs.getObject(1, Integer.class), 
"int");
+            expectSqlConversionError(() -> rs.getObject("C", Integer.class), 
"int");
+
+            expectSqlConversionError(() -> rs.getObject(1, Long.class), 
"long");
+            expectSqlConversionError(() -> rs.getObject("C", Long.class), 
"long");
+
+            expectSqlConversionError(() -> rs.getObject(1, BigDecimal.class), 
"BigDecimal");
+            expectSqlConversionError(() -> rs.getObject("C", 
BigDecimal.class), "BigDecimal");
+
+            assertEquals(Date.valueOf(value), rs.getObject(1, Date.class));
+            assertEquals(Date.valueOf(value), rs.getObject("C", Date.class));
+
+            assertEquals(LocalTime.of(0, 0, 0), rs.getObject(1, 
Time.class).toLocalTime());
+            assertEquals(LocalTime.of(0, 0, 0), rs.getObject("C", 
Time.class).toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getObject(1, Timestamp.class));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(value, 
LocalTime.of(0, 0, 0))), rs.getObject("C", Timestamp.class));
+
+            expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
+            expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {"Europe/Paris", "America/Los_Angeles", 
"Asia/Tokyo"})
+    public void getDateFromDateTimeTypes(String zone) throws SQLException {
+        ZoneId zoneId = ZoneId.of(zone);
+
+        Clock clock = 
Clock.fixed(Instant.now().truncatedTo(ChronoUnit.SECONDS), 
ZoneId.systemDefault());
+        Instant instant = clock.instant();
+        LocalDateTime dateTime = LocalDateTime.now(clock);
+        LocalTime time = LocalTime.now(clock);
+        LocalDate date = LocalDate.now(clock);
+
+        try (ResultSet rs = createMultiRow(
+                zoneId,
+                new ColumnDefinition[]{
+                        new ColumnDefinition("C1", ColumnType.TIME, 0, 0, 
false),
+                        new ColumnDefinition("C2", ColumnType.DATE, 0, 0, 
false),
+                        new ColumnDefinition("C3", ColumnType.DATETIME, 0, 0, 
false),
+                        new ColumnDefinition("C4", ColumnType.TIMESTAMP, 0, 0, 
false),
+                },
+                new Object[]{time, date, dateTime, instant})) {
+
+            assertTrue(rs.next());
+
+            // from time
+            assertEquals(LocalDate.of(1970, 1, 1), 
rs.getDate(1).toLocalDate());
+
+            // from date
+            assertEquals(date, rs.getDate(2).toLocalDate());
+
+            // from datetime
+            assertEquals(dateTime.toLocalDate(), rs.getDate(3).toLocalDate());
+
+            // from timestamp with local timezone
+            Timestamp ts = rs.getTimestamp(4);
+            assertEquals(ts.toLocalDateTime().toLocalDate(), 
rs.getDate(4).toLocalDate());
+        }
+    }
+
+    private static Stream<LocalDate> getDateValues() {
+        return Stream.of(
+                LocalDate.of(1, 1, 1),
+                LocalDate.of(1000, 12, 31),
+                LocalDate.of(1900, 1, 1),
+                LocalDate.of(1947, 9, 30),
+                LocalDate.of(2025, 4, 27),
+                LocalDate.of(2120, 7, 31)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getDateStringValues")
+    public void getStringFromDate(boolean valid, LocalDate date, String value) 
throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.DATE, 0, 0, false), date)) {
+            assertTrue(rs.next());
+
+            if (valid) {
+                assertEquals(value, rs.getString(1));
+                assertEquals(value, rs.getString("C"));
+
+                assertEquals(value, rs.getObject(1, String.class));
+                assertEquals(value, rs.getObject("C", String.class));
+            } else {
+                expectSqlConversionError(() -> rs.getString(1), "string");
+                expectSqlConversionError(() -> rs.getString("C"), "string");
+
+                expectSqlConversionError(() -> rs.getObject(1, String.class), 
"string");
+                expectSqlConversionError(() -> rs.getObject("C", 
String.class), "string");
+            }
+        }
+    }
+
+    private static Stream<Arguments> getDateStringValues() {
+        return Stream.of(
+                Arguments.of(true, LocalDate.of(1, 1, 1), "0001-01-01"),
+                Arguments.of(true, LocalDate.of(200, 3, 17), "0200-03-17"),
+                Arguments.of(true, LocalDate.of(1000, 1, 4), "1000-01-04"),
+                Arguments.of(true, LocalDate.of(2000, 12, 31), "2000-12-31"),
+                Arguments.of(true, LocalDate.of(9999, 12, 31), "9999-12-31"),
+                Arguments.of(false, LocalDate.of(10000, 1, 1), null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getTimeValues")
+    public void getTime(LocalTime value) throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.TIME, 3, 0, false), value)) {
+            assertTrue(rs.next());
+
+            String strVal = 
value.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"));
+
+            expectSqlConversionError(() -> rs.getBoolean(1), "boolean");
+            expectSqlConversionError(() -> rs.getBoolean("C"), "boolean");
+
+            expectSqlConversionError(() -> rs.getByte(1), "byte");
+            expectSqlConversionError(() -> rs.getByte("C"), "byte");
+
+            expectSqlConversionError(() -> rs.getShort(1), "short");
+            expectSqlConversionError(() -> rs.getShort("C"), "short");
+
+            expectSqlConversionError(() -> rs.getInt(1), "int");
+            expectSqlConversionError(() -> rs.getInt("C"), "int");
+
+            expectSqlConversionError(() -> rs.getLong(1), "long");
+            expectSqlConversionError(() -> rs.getLong("C"), "long");
+
+            expectSqlConversionError(() -> rs.getFloat(1), "float");
+            expectSqlConversionError(() -> rs.getFloat("C"), "float");
+
+            expectSqlConversionError(() -> rs.getDouble(1), "double");
+            expectSqlConversionError(() -> rs.getDouble("C"), "double");
+
+            expectSqlConversionError(() -> rs.getBigDecimal(1), "BigDecimal");
+            expectSqlConversionError(() -> rs.getBigDecimal("C"), 
"BigDecimal");
+
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal(1, 2), 
"BigDecimal");
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal("C", 4), 
"BigDecimal");
+
+            assertEquals(strVal, rs.getString(1));
+            assertEquals(strVal, rs.getString("C"));
+
+            assertEquals(strVal, rs.getNString(1));
+            assertEquals(strVal, rs.getNString("C"));
+
+            assertEquals(LocalDate.of(1970, 1, 1), 
rs.getDate(1).toLocalDate());
+            assertEquals(LocalDate.of(1970, 1, 1), 
rs.getDate("C").toLocalDate());
+
+            assertEquals(value.withNano(0), rs.getTime(1).toLocalTime());
+            assertEquals(value.withNano(0), rs.getTime("C").toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))), rs.getTimestamp(1));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))), rs.getTimestamp("C"));
+
+            assertEquals(LocalDate.of(1970, 1, 1), rs.getDate(1, 
Calendar.getInstance()).toLocalDate());
+            assertEquals(LocalDate.of(1970, 1, 1), rs.getDate("C", 
Calendar.getInstance()).toLocalDate());
+
+            assertEquals(value.withNano(0), rs.getTime(1, 
Calendar.getInstance()).toLocalTime());
+            assertEquals(value.withNano(0), rs.getTime("C", 
Calendar.getInstance()).toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))),
+                    rs.getTimestamp(1, Calendar.getInstance()));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))),
+                    rs.getTimestamp("C", Calendar.getInstance()));
+
+            // getObject
+
+            expectSqlConversionError(() -> rs.getObject(1, Boolean.class), 
"boolean");
+            expectSqlConversionError(() -> rs.getObject("C", Boolean.class), 
"boolean");
+
+            expectSqlConversionError(() -> rs.getObject(1, Byte.class), 
"byte");
+            expectSqlConversionError(() -> rs.getObject("C", Byte.class), 
"byte");
+
+            expectSqlConversionError(() -> rs.getObject(1, Short.class), 
"short");
+            expectSqlConversionError(() -> rs.getObject("C", Short.class), 
"short");
+
+            expectSqlConversionError(() -> rs.getObject(1, Integer.class), 
"int");
+            expectSqlConversionError(() -> rs.getObject("C", Integer.class), 
"int");
+
+            expectSqlConversionError(() -> rs.getObject(1, Long.class), 
"long");
+            expectSqlConversionError(() -> rs.getObject("C", Long.class), 
"long");
+
+            expectSqlConversionError(() -> rs.getObject(1, BigDecimal.class), 
"BigDecimal");
+            expectSqlConversionError(() -> rs.getObject("C", 
BigDecimal.class), "BigDecimal");
+
+            assertEquals(LocalDate.of(1970, 1, 1), rs.getObject(1, 
Date.class).toLocalDate());
+            assertEquals(LocalDate.of(1970, 1, 1), rs.getObject("C", 
Date.class).toLocalDate());
+
+            assertEquals(value.withNano(0), rs.getObject(1, 
Time.class).toLocalTime());
+            assertEquals(value.withNano(0), rs.getObject("C", 
Time.class).toLocalTime());
+
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))),
+                    rs.getObject(1, Timestamp.class));
+            assertEquals(Timestamp.valueOf(LocalDateTime.of(LocalDate.of(1970, 
1, 1), value.withNano(0))),
+                    rs.getObject("C", Timestamp.class));
+
+            expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
+            expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
+        }
+    }
+
+    private static Stream<LocalTime> getTimeValues() {
+        return Stream.of(
+                LocalTime.of(0, 1, 12),
+                LocalTime.of(12, 0, 59).with(ChronoField.MILLI_OF_SECOND, 678)
+        );
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {"Europe/Paris", "America/Los_Angeles", 
"Asia/Tokyo"})
+    public void getTimeWithTimeZone(String zone) throws SQLException {
+        ZoneId zoneId = ZoneId.of(zone);
+
+        Clock clock = 
Clock.fixed(Instant.now().truncatedTo(ChronoUnit.SECONDS), 
ZoneId.systemDefault());
+        Instant instant = clock.instant();
+        LocalDateTime dateTime = LocalDateTime.now(clock);
+        LocalTime time = LocalTime.now(clock);
+        LocalDate date = LocalDate.now(clock);
+
+        try (ResultSet rs = createMultiRow(
+                zoneId,
+                new ColumnDefinition[]{
+                        new ColumnDefinition("C1", ColumnType.TIME, 0, 0, 
false),
+                        new ColumnDefinition("C2", ColumnType.DATE, 0, 0, 
false),
+                        new ColumnDefinition("C3", ColumnType.DATETIME, 0, 0, 
false),
+                        new ColumnDefinition("C4", ColumnType.TIMESTAMP, 0, 0, 
false),
+                },
+                new Object[]{time, date, dateTime, instant})) {
+
+            assertTrue(rs.next());
+
+            // from time
+            assertEquals(time, rs.getTime(1).toLocalTime());
+
+            // from date
+            assertEquals(LocalTime.of(0, 0, 0), rs.getTime(2).toLocalTime());
+
+            // from datetime
+            assertEquals(dateTime.toLocalTime(), rs.getTime(3).toLocalTime());
+
+            // from instant / timestamp ltz
+            Timestamp ts = rs.getTimestamp(4);
+            assertEquals(ts.toLocalDateTime().toLocalTime(), 
rs.getTime(4).toLocalTime());
+        }
+    }
+
+    @ParameterizedTest
+    @MethodSource("getTimeStringValues")
+    public void getStringFromTimeWithPrecision(LocalTime time, int precision, 
String value) throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.TIME, precision, 0, false), time)) {
+            assertTrue(rs.next());
+
+            assertEquals(value, rs.getString(1));
+            assertEquals(value, rs.getString("C"));
+
+            assertEquals(value, rs.getObject(1, String.class));
+            assertEquals(value, rs.getObject("C", String.class));
+        }
+    }
+
+    private static Stream<Arguments> getTimeStringValues() {
+        return Stream.of(
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 0, "00:00:00"),
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 1, "00:00:00.0"),
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 2, "00:00:00.00"),
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 3, "00:00:00.000"),
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 6, "00:00:00.000000"),
+                Arguments.of(LocalTime.of(0, 0, 0, 0), 9, 
"00:00:00.000000000"),
+
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 0, "13:05:02"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 1, "13:05:02.0"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 2, 
"13:05:02.00"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 3, 
"13:05:02.000"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 5, 
"13:05:02.00012"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 6, 
"13:05:02.000123"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_456), 9, 
"13:05:02.000123456"),
+
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 0, "13:05:02"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 1, 
"13:05:02.0"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 2, 
"13:05:02.01"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 3, 
"13:05:02.012"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 5, 
"13:05:02.01234"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 6, 
"13:05:02.012345"),
+                Arguments.of(LocalTime.of(13, 5, 2, 12345600), 9, 
"13:05:02.012345600"),
+
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 0, 
"13:05:02"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 1, 
"13:05:02.1"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 2, 
"13:05:02.12"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 3, 
"13:05:02.123"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 6, 
"13:05:02.123000"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123_000_000), 9, 
"13:05:02.123000000"),
+
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 0, "13:05:02"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 1, 
"13:05:02.1"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 2, 
"13:05:02.12"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 3, 
"13:05:02.123"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 6, 
"13:05:02.123456"),
+                Arguments.of(LocalTime.of(13, 5, 2, 123456789), 9, 
"13:05:02.123456789")
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getTimestampValues")
+    public void getTimestamp(Instant value) throws SQLException {
+        ZoneId zoneId = ZoneId.of("UTC");
+
+        try (ResultSet rs = createResultSet(
+                zoneId,
+                List.of(new ColumnDefinition("C", ColumnType.TIMESTAMP, 3, 0, 
false)),
+                List.of(List.of(value)))
+        ) {
+            assertTrue(rs.next());
+
+            DateTimeFormatter formatter = 
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
+            String strVal = LocalDateTime.ofInstant(value, 
zoneId).format(formatter);
+
+            expectSqlConversionError(() -> rs.getBoolean(1), "boolean");
+            expectSqlConversionError(() -> rs.getBoolean("C"), "boolean");
+
+            expectSqlConversionError(() -> rs.getByte(1), "byte");
+            expectSqlConversionError(() -> rs.getByte("C"), "byte");
+
+            expectSqlConversionError(() -> rs.getShort(1), "short");
+            expectSqlConversionError(() -> rs.getShort("C"), "short");
+
+            expectSqlConversionError(() -> rs.getInt(1), "int");
+            expectSqlConversionError(() -> rs.getInt("C"), "int");
+
+            expectSqlConversionError(() -> rs.getLong(1), "long");
+            expectSqlConversionError(() -> rs.getLong("C"), "long");
+
+            expectSqlConversionError(() -> rs.getFloat(1), "float");
+            expectSqlConversionError(() -> rs.getFloat("C"), "float");
+
+            expectSqlConversionError(() -> rs.getDouble(1), "double");
+            expectSqlConversionError(() -> rs.getDouble("C"), "double");
+
+            expectSqlConversionError(() -> rs.getBigDecimal(1), "BigDecimal");
+            expectSqlConversionError(() -> rs.getBigDecimal("C"), 
"BigDecimal");
+
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal(1, 2), 
"BigDecimal");
+            //noinspection deprecation
+            expectSqlConversionError(() -> rs.getBigDecimal("C", 4), 
"BigDecimal");
+
+            assertEquals(strVal, rs.getString(1));
+            assertEquals(strVal, rs.getString("C"));
+
+            assertEquals(strVal, rs.getNString(1));
+            assertEquals(strVal, rs.getNString("C"));
+
+            LocalDate date = LocalDate.ofInstant(value, zoneId);
+            assertEquals(date, rs.getDate(1).toLocalDate());
+            assertEquals(date, rs.getDate("C").toLocalDate());
+
+            LocalTime time = LocalTime.ofInstant(value, zoneId);
+            assertEquals(time.withNano(0), rs.getTime(1).toLocalTime());
+            assertEquals(time.withNano(0), rs.getTime("C").toLocalTime());
+
+            Timestamp ts = Timestamp.valueOf(LocalDateTime.ofInstant(value, 
zoneId));
+            assertEquals(ts, rs.getTimestamp(1));
+            assertEquals(ts, rs.getTimestamp("C"));
+
+            assertEquals(date, rs.getDate(1, 
Calendar.getInstance()).toLocalDate());
+            assertEquals(date, rs.getDate("C", 
Calendar.getInstance()).toLocalDate());
+
+            assertEquals(time.withNano(0), rs.getTime(1, 
Calendar.getInstance()).toLocalTime());
+            assertEquals(time.withNano(0), rs.getTime("C", 
Calendar.getInstance()).toLocalTime());
+
+            assertEquals(ts, rs.getTimestamp(1, Calendar.getInstance()));
+            assertEquals(ts, rs.getTimestamp("C", Calendar.getInstance()));
+
+            // getObject
+
+            expectSqlConversionError(() -> rs.getObject(1, Boolean.class), 
"boolean");
+            expectSqlConversionError(() -> rs.getObject("C", Boolean.class), 
"boolean");
+
+            expectSqlConversionError(() -> rs.getObject(1, Byte.class), 
"byte");
+            expectSqlConversionError(() -> rs.getObject("C", Byte.class), 
"byte");
+
+            expectSqlConversionError(() -> rs.getObject(1, Short.class), 
"short");
+            expectSqlConversionError(() -> rs.getObject("C", Short.class), 
"short");
+
+            expectSqlConversionError(() -> rs.getObject(1, Integer.class), 
"int");
+            expectSqlConversionError(() -> rs.getObject("C", Integer.class), 
"int");
+
+            expectSqlConversionError(() -> rs.getObject(1, Long.class), 
"long");
+            expectSqlConversionError(() -> rs.getObject("C", Long.class), 
"long");
+
+            expectSqlConversionError(() -> rs.getObject(1, BigDecimal.class), 
"BigDecimal");
+            expectSqlConversionError(() -> rs.getObject("C", 
BigDecimal.class), "BigDecimal");
+
+            assertEquals(date, rs.getObject(1, Date.class).toLocalDate());
+            assertEquals(date, rs.getObject("C", Date.class).toLocalDate());
+
+            assertEquals(time.withNano(0), rs.getObject(1, 
Time.class).toLocalTime());
+            assertEquals(time.withNano(0), rs.getObject("C", 
Time.class).toLocalTime());
+
+            assertEquals(ts, rs.getObject(1, Timestamp.class));
+            assertEquals(ts, rs.getObject("C", Timestamp.class));
+
+            expectSqlConversionError(() -> rs.getObject(1, UUID.class), 
"java.util.UUID");
+            expectSqlConversionError(() -> rs.getObject("C", UUID.class), 
"java.util.UUID");
+        }
+    }
+
+    private static Stream<Instant> getTimestampValues() {
+        return Stream.of(
+                LocalDateTime.of(LocalDate.of(1, 1, 1), LocalTime.of(0, 0, 0)),
+                LocalDateTime.of(LocalDate.of(1000, 12, 31), LocalTime.of(23, 
59, 59)),
+                LocalDateTime.of(LocalDate.of(1900, 1, 1), LocalTime.of(0, 0, 
0)),
+                LocalDateTime.of(LocalDate.of(1947, 2, 26), LocalTime.of(12, 
0, 59).with(ChronoField.MILLI_OF_SECOND, 678)),
+                LocalDateTime.of(LocalDate.of(1947, 2, 26), LocalTime.of(23, 
59, 59).with(ChronoField.MILLI_OF_SECOND, 999)),
+                LocalDateTime.of(LocalDate.of(2000, 1, 1), LocalTime.of(0, 0, 
0)),
+                LocalDateTime.of(LocalDate.of(2024, 8, 31), LocalTime.of(0, 1, 
12)),
+                LocalDateTime.of(LocalDate.of(2124, 12, 31), LocalTime.of(23, 
1, 12))
+        ).map(dt -> dt.toInstant(ZoneOffset.UTC));
+    }
+
+    @ParameterizedTest
+    @MethodSource("getStringDateTimeValues")
+    public void getStringFromDateTimeWithPrecision(LocalDateTime time, int 
precision, String value) throws SQLException {
+        try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.DATETIME, precision, 0, false), time)) {
+            assertTrue(rs.next());
+
+            assertEquals(value, rs.getString(1));
+            assertEquals(value, rs.getString("C"));
+
+            assertEquals(value, rs.getObject(1, String.class));
+            assertEquals(value, rs.getObject("C", String.class));
+        }
+    }
+
+    private static Stream<Arguments> getStringDateTimeValues() {
+        LocalTime time = LocalTime.of(13, 5, 2, 12345600);
+
+        LocalDate date2 = LocalDate.of(2, 5, 17);
+        LocalDate date20 = LocalDate.of(20, 5, 17);
+        LocalDate date200 = LocalDate.of(200, 5, 17);
+        LocalDate date2000 = LocalDate.of(2000, 5, 17);
+
+        return Stream.of(
+                // 2
+                Arguments.of(LocalDateTime.of(date2, time), 0, "0002-05-17 
13:05:02"),
+                Arguments.of(LocalDateTime.of(date2, time), 1, "0002-05-17 
13:05:02.0"),
+                Arguments.of(LocalDateTime.of(date2, time), 2, "0002-05-17 
13:05:02.01"),
+                Arguments.of(LocalDateTime.of(date2, time), 3, "0002-05-17 
13:05:02.012"),
+                Arguments.of(LocalDateTime.of(date2, time), 5, "0002-05-17 
13:05:02.01234"),
+                Arguments.of(LocalDateTime.of(date2, time), 6, "0002-05-17 
13:05:02.012345"),
+                Arguments.of(LocalDateTime.of(date2, time), 9, "0002-05-17 
13:05:02.012345600"),
+
+                // 20
+                Arguments.of(LocalDateTime.of(date20, time), 0, "0020-05-17 
13:05:02"),
+                Arguments.of(LocalDateTime.of(date20, time), 1, "0020-05-17 
13:05:02.0"),
+                Arguments.of(LocalDateTime.of(date20, time), 2, "0020-05-17 
13:05:02.01"),
+                Arguments.of(LocalDateTime.of(date20, time), 3, "0020-05-17 
13:05:02.012"),
+                Arguments.of(LocalDateTime.of(date20, time), 5, "0020-05-17 
13:05:02.01234"),
+                Arguments.of(LocalDateTime.of(date20, time), 6, "0020-05-17 
13:05:02.012345"),
+                Arguments.of(LocalDateTime.of(date20, time), 9, "0020-05-17 
13:05:02.012345600"),
+
+                // 200
+                Arguments.of(LocalDateTime.of(date200, time), 0, "0200-05-17 
13:05:02"),
+                Arguments.of(LocalDateTime.of(date200, time), 1, "0200-05-17 
13:05:02.0"),
+                Arguments.of(LocalDateTime.of(date200, time), 2, "0200-05-17 
13:05:02.01"),
+                Arguments.of(LocalDateTime.of(date200, time), 3, "0200-05-17 
13:05:02.012"),
+                Arguments.of(LocalDateTime.of(date200, time), 5, "0200-05-17 
13:05:02.01234"),
+                Arguments.of(LocalDateTime.of(date200, time), 6, "0200-05-17 
13:05:02.012345"),
+                Arguments.of(LocalDateTime.of(date200, time), 9, "0200-05-17 
13:05:02.012345600"),
+
+                // 2000
+                Arguments.of(LocalDateTime.of(date2000, time), 0, "2000-05-17 
13:05:02"),
+                Arguments.of(LocalDateTime.of(date2000, time), 1, "2000-05-17 
13:05:02.0"),
+                Arguments.of(LocalDateTime.of(date2000, time), 2, "2000-05-17 
13:05:02.01"),
+                Arguments.of(LocalDateTime.of(date2000, time), 3, "2000-05-17 
13:05:02.012"),
+                Arguments.of(LocalDateTime.of(date2000, time), 5, "2000-05-17 
13:05:02.01234"),
+                Arguments.of(LocalDateTime.of(date2000, time), 6, "2000-05-17 
13:05:02.012345"),
+                Arguments.of(LocalDateTime.of(date2000, time), 9, "2000-05-17 
13:05:02.012345600")
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getStringDateTimeValues")
+    public void getStringFromTimestampWithPrecision(LocalDateTime dateTime, 
int precision, String value) throws SQLException {
+        ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutes(3, 30);
+        Instant instant = dateTime.toInstant(zoneOffset);
+
+        try (ResultSet rs = createResultSet(zoneOffset,
+                List.of(new ColumnDefinition("C", ColumnType.TIMESTAMP, 
precision, 0, false)),
+                List.of(List.of(instant))
+        )) {
+            assertTrue(rs.next());
+
+            assertEquals(value, rs.getString(1));
+            assertEquals(value, rs.getString("C"));
+
+            assertEquals(value, rs.getObject(1, String.class));
+            assertEquals(value, rs.getObject("C", String.class));
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {"Europe/Paris", "America/Los_Angeles", 
"Asia/Tokyo"})
+    public void getTimestampWithTimeZone(String zone) throws SQLException {
+        ZoneId zoneId = ZoneId.of(zone);
+
+        Clock clock = 
Clock.fixed(Instant.now().truncatedTo(ChronoUnit.SECONDS), 
ZoneId.systemDefault());
+        Instant instant = clock.instant();
+        LocalDateTime dateTime = LocalDateTime.now(clock);
+        LocalTime time = LocalTime.now(clock);
+        LocalDate date = LocalDate.now(clock);
+
+        try (ResultSet rs = createMultiRow(
+                zoneId,
+                new ColumnDefinition[]{
+                        new ColumnDefinition("C1", ColumnType.TIME, 0, 0, 
false),
+                        new ColumnDefinition("C2", ColumnType.DATE, 0, 0, 
false),
+                        new ColumnDefinition("C3", ColumnType.DATETIME, 0, 0, 
false),
+                        new ColumnDefinition("C4", ColumnType.TIMESTAMP, 0, 0, 
false),
+                },
+                new Object[]{time, date, dateTime, instant})) {
+
+            assertTrue(rs.next());
+
+            // from time
+            assertEquals(LocalDateTime.of(LocalDate.of(1970, 1, 1), time), 
rs.getTimestamp(1).toLocalDateTime());
+
+            // from date
+            assertEquals(LocalDateTime.of(date, LocalTime.of(0, 0, 0)), 
rs.getTimestamp(2).toLocalDateTime());
+
+            // from datetime
+            assertEquals(dateTime, rs.getTimestamp(3).toLocalDateTime());
+
+            // from instant / timestamp ltz
+            assertEquals(LocalDateTime.ofInstant(instant, zoneId), 
rs.getTimestamp(4).toLocalDateTime());
+        }
+    }
+
     @Test
     public void getNotSupportedTypes() throws SQLException {
         try (ResultSet rs = createSingleRow(new ColumnDefinition("C", 
ColumnType.STRING, 3, 0, false), "ABC")) {
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 45014c3b8ba..182bf1e8c22 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
@@ -50,6 +50,7 @@ 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;
 import org.apache.ignite.internal.sql.ColumnMetadataImpl;
@@ -74,7 +75,7 @@ import org.mockito.internal.stubbing.answers.ThrowsException;
  */
 public class JdbcResultSet2SelfTest extends JdbcResultSetBaseSelfTest {
 
-    // TODO https://issues.apache.org/jira/browse/IGNITE-26379: datetime
+    // getBytes is not implemented yet
     @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140";)
     @Override
     @ParameterizedTest
@@ -83,7 +84,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
         super.wasNullPositional(columnType);
     }
 
-    // TODO https://issues.apache.org/jira/browse/IGNITE-26379: datetime
+    // getBytes is not implemented yet
     @Disabled("https://issues.apache.org/jira/browse/IGNITE-26140";)
     @Override
     @ParameterizedTest
@@ -92,9 +93,6 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
         super.wasNullNamed(columnType);
     }
 
-    // getXXX are not implemented yet
-    // 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 {
@@ -157,7 +155,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
             RuntimeException cause = new RuntimeException("Some error");
             when(igniteRs.hasNext()).thenThrow(cause);
 
-            ResultSet rs = new JdbcResultSet(igniteRs, statement);
+            ResultSet rs = new JdbcResultSet(igniteRs, statement, 
ZoneId::systemDefault);
 
             SQLException err = assertThrows(SQLException.class, rs::next);
             assertEquals("Some error", err.getMessage());
@@ -175,7 +173,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
             when(igniteRs.hasNext()).thenReturn(true);
             when(igniteRs.next()).thenThrow(cause);
 
-            ResultSet rs = new JdbcResultSet(igniteRs, statement);
+            ResultSet rs = new JdbcResultSet(igniteRs, statement, 
ZoneId::systemDefault);
 
             SQLException err = assertThrows(SQLException.class, rs::next);
             assertEquals("Some error", err.getMessage());
@@ -192,7 +190,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
         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);
+        ResultSet rs = new JdbcResultSet(igniteRs, statement, 
ZoneId::systemDefault);
 
         rs.close();
         rs.close();
@@ -212,7 +210,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
         RuntimeException cause = new RuntimeException("Some error");
         doAnswer(new ThrowsException(cause)).when(igniteRs).close();
 
-        ResultSet rs = new JdbcResultSet(igniteRs, statement);
+        ResultSet rs = new JdbcResultSet(igniteRs, statement, 
ZoneId::systemDefault);
 
         SQLException err = assertThrows(SQLException.class, rs::close);
         assertEquals("Some error", err.getMessage());
@@ -236,7 +234,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
         RuntimeException cause = new RuntimeException("Corrupted value");
         when(row.value(0)).thenThrow(cause);
 
-        JdbcResultSet rs = new JdbcResultSet(igniteRs, statement);
+        JdbcResultSet rs = new JdbcResultSet(igniteRs, statement, 
ZoneId::systemDefault);
         assertTrue(rs.next());
 
         SQLException err = assertThrows(SQLException.class, () -> 
rs.getValue(1));
@@ -261,12 +259,20 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
             List<List<Object>> rows
     ) {
 
+        Supplier<ZoneId> zoneIdSupplier = () -> {
+            if (zoneId != null) {
+                return zoneId;
+            } else {
+                return ZoneId.systemDefault();
+            }
+        };
+
         // 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);
+            return new JdbcResultSet(rs, statement, zoneIdSupplier);
         }
 
         List<ColumnMetadata> apiCols = new ArrayList<>();
@@ -281,7 +287,7 @@ public class JdbcResultSet2SelfTest extends 
JdbcResultSetBaseSelfTest {
 
         ResultSetMetadata apiMeta = new ResultSetMetadataImpl(apiCols);
 
-        return new JdbcResultSet(new ResultSetStub(apiMeta, rows), statement);
+        return new JdbcResultSet(new ResultSetStub(apiMeta, rows), statement, 
zoneIdSupplier);
     }
 
     private static class ResultSetStub implements 
org.apache.ignite.sql.ResultSet<SqlRow> {

Reply via email to