diff --git a/docs/src/main/sphinx/connector/exasol.md b/docs/src/main/sphinx/connector/exasol.md
index 5f0c29a89f4b..2f069f5ac563 100644
--- a/docs/src/main/sphinx/connector/exasol.md
+++ b/docs/src/main/sphinx/connector/exasol.md
@@ -103,6 +103,12 @@ Trino data type mapping:
* - `HASHTYPE`
- `VARBINARY`
-
+* - `TIMESTAMP(n)`
+ - `TIMESTAMP(n)`
+ -
+* - `TIMESTAMP(n) WITH LOCAL TIME ZONE`
+ - `TIMESTAMP(n) WITH TIME ZONE`
+ -
:::
No other types are supported.
diff --git a/plugin/trino-exasol/src/main/java/io/trino/plugin/exasol/ExasolClient.java b/plugin/trino-exasol/src/main/java/io/trino/plugin/exasol/ExasolClient.java
index 8675aa509435..12dde6c89396 100644
--- a/plugin/trino-exasol/src/main/java/io/trino/plugin/exasol/ExasolClient.java
+++ b/plugin/trino-exasol/src/main/java/io/trino/plugin/exasol/ExasolClient.java
@@ -30,6 +30,8 @@
import io.trino.plugin.jdbc.JdbcTypeHandle;
import io.trino.plugin.jdbc.LongReadFunction;
import io.trino.plugin.jdbc.LongWriteFunction;
+import io.trino.plugin.jdbc.ObjectReadFunction;
+import io.trino.plugin.jdbc.ObjectWriteFunction;
import io.trino.plugin.jdbc.QueryBuilder;
import io.trino.plugin.jdbc.SliceReadFunction;
import io.trino.plugin.jdbc.SliceWriteFunction;
@@ -43,34 +45,57 @@
import io.trino.spi.connector.ColumnPosition;
import io.trino.spi.connector.ConnectorSession;
import io.trino.spi.connector.ConnectorTableMetadata;
+import io.trino.spi.type.LongTimestamp;
+import io.trino.spi.type.LongTimestampWithTimeZone;
+import io.trino.spi.type.TimeZoneKey;
+import io.trino.spi.type.TimestampType;
+import io.trino.spi.type.TimestampWithTimeZoneType;
import io.trino.spi.type.Type;
import java.sql.Connection;
import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
import java.sql.Types;
+import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.Set;
+import java.util.TimeZone;
import java.util.function.BiFunction;
+import static com.google.common.base.Preconditions.checkArgument;
+import static io.trino.plugin.jdbc.PredicatePushdownController.FULL_PUSHDOWN;
import static io.trino.plugin.jdbc.StandardColumnMappings.bigintColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.booleanColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.decimalColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.defaultCharColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.defaultVarcharColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.doubleColumnMapping;
+import static io.trino.plugin.jdbc.StandardColumnMappings.fromLongTrinoTimestamp;
+import static io.trino.plugin.jdbc.StandardColumnMappings.fromTrinoTimestamp;
import static io.trino.plugin.jdbc.StandardColumnMappings.integerColumnMapping;
import static io.trino.plugin.jdbc.StandardColumnMappings.smallintColumnMapping;
+import static io.trino.plugin.jdbc.StandardColumnMappings.toLongTrinoTimestamp;
+import static io.trino.plugin.jdbc.StandardColumnMappings.toTrinoTimestamp;
import static io.trino.plugin.jdbc.TypeHandlingJdbcSessionProperties.getUnsupportedTypeHandling;
import static io.trino.plugin.jdbc.UnsupportedTypeHandling.CONVERT_TO_VARCHAR;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static io.trino.spi.connector.ConnectorMetadata.MODIFYING_ROWS_MESSAGE;
+import static io.trino.spi.type.DateTimeEncoding.packDateTimeWithZone;
+import static io.trino.spi.type.DateTimeEncoding.unpackMillisUtc;
import static io.trino.spi.type.DateType.DATE;
import static io.trino.spi.type.DecimalType.createDecimalType;
+import static io.trino.spi.type.TimestampType.createTimestampType;
+import static io.trino.spi.type.TimestampWithTimeZoneType.createTimestampWithTimeZoneType;
+import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_MILLISECOND;
+import static io.trino.spi.type.Timestamps.PICOSECONDS_PER_NANOSECOND;
import static io.trino.spi.type.VarbinaryType.VARBINARY;
import static java.lang.String.format;
import static java.util.Locale.ENGLISH;
@@ -79,11 +104,15 @@
public class ExasolClient
extends BaseJdbcClient
{
+ private static final int EXASOL_TIMESTAMP_WITH_TIMEZONE = 124;
+
private static final Set
+ * Exasol {@code TIMESTAMP WITH LOCAL TIME ZONE} does not store any time zone information in the database.
+ * In Trino, it is mapped to {@code TIMESTAMP WITH TIME ZONE} with the hardcoded JVM time zone
+ *
+ * This limitation imposes some rules and restrictions on the tests:
+ *
+ *
+ *
+ * See for more details: https://docs.exasol.com/db/latest/sql_references/data_types/datatypedetails.htm + *
+ */
+ private void testTimestampWithTimeZone(ZoneId sessionZone)
+ {
+ Session session = Session.builder(getSession())
+ .setTimeZoneKey(TimeZoneKey.getTimeZoneKey(sessionZone.getId()))
+ .build();
+
+ SqlDataTypeTest.create()
+ .addRoundTrip("timestamp with local time zone", "NULL", createTimestampWithTimeZoneType(3), "CAST(NULL AS TIMESTAMP WITH TIME ZONE)")
+
+ // timestamp with precision 3 examples
+ .addRoundTrip("timestamp with local time zone", timestampWithTimeZoneInput("2019-03-18 10:01:17.123"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2019-03-18 10:01:17.123"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2018-10-27 19:33:17.456"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2018-10-27 19:33:17.456"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2018-10-28 03:33:33.333"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2018-10-28 03:33:33.333"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:13:42.000"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("1970-01-01 00:13:42.000"))
+
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2018-04-01 03:13:55.123"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2018-04-01 03:13:55.123"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.999"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2020-09-27 12:34:56.999"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2018-03-25 03:17:17.000"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2018-03-25 03:17:17.000"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("1986-01-01 00:13:07.000"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("1986-01-01 00:13:07.000"))
+
+ // timestamp with precision 6-9 examples
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2019-03-18 10:01:17.987654"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2019-03-18 10:01:17.987654"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2018-10-28 01:33:17.456789"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2018-10-28 01:33:17.456789"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2018-10-28 03:33:33.333333"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2018-10-28 03:33:33.333333"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:13:42.000000"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("1970-01-01 00:13:42.000000"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2018-04-01 03:13:55.123456"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2018-04-01 03:13:55.123456"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2018-03-25 03:17:17.000000"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2018-03-25 03:17:17.000000"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("1986-01-01 00:13:07.000000"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("1986-01-01 00:13:07.000000"))
+ .addRoundTrip("timestamp(7) with local time zone", timestampWithTimeZoneInput("1986-01-01 00:13:07.1234567"), createTimestampWithTimeZoneType(7), timestampWithTimeZoneExpected("1986-01-01 00:13:07.1234567"))
+ .addRoundTrip("timestamp(8) with local time zone", timestampWithTimeZoneInput("1986-01-01 00:13:07.12345678"), createTimestampWithTimeZoneType(8), timestampWithTimeZoneExpected("1986-01-01 00:13:07.12345678"))
+ .addRoundTrip("timestamp(9) with local time zone", timestampWithTimeZoneInput("1986-01-01 00:13:07.123456789"), createTimestampWithTimeZoneType(9), timestampWithTimeZoneExpected("1986-01-01 00:13:07.123456789"))
+
+ // tests for other precisions (0-5 and some 1's)
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("1970-01-01 00:00:01"))
+ .addRoundTrip("timestamp(1) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.1"), createTimestampWithTimeZoneType(1), timestampWithTimeZoneExpected("1970-01-01 00:00:01.1"))
+ .addRoundTrip("timestamp(1) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.9"), createTimestampWithTimeZoneType(1), timestampWithTimeZoneExpected("1970-01-01 00:00:01.9"))
+ .addRoundTrip("timestamp(2) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.12"), createTimestampWithTimeZoneType(2), timestampWithTimeZoneExpected("1970-01-01 00:00:01.12"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.123"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("1970-01-01 00:00:01.123"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.999"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("1970-01-01 00:00:01.999"))
+ .addRoundTrip("timestamp(4) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.1234"), createTimestampWithTimeZoneType(4), timestampWithTimeZoneExpected("1970-01-01 00:00:01.1234"))
+ .addRoundTrip("timestamp(5) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:01.12345"), createTimestampWithTimeZoneType(5), timestampWithTimeZoneExpected("1970-01-01 00:00:01.12345"))
+ .addRoundTrip("timestamp(1) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.1"), createTimestampWithTimeZoneType(1), timestampWithTimeZoneExpected("2020-09-27 12:34:56.1"))
+ .addRoundTrip("timestamp(1) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.9"), createTimestampWithTimeZoneType(1), timestampWithTimeZoneExpected("2020-09-27 12:34:56.9"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.123"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2020-09-27 12:34:56.123"))
+ .addRoundTrip("timestamp(3) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.999"), createTimestampWithTimeZoneType(3), timestampWithTimeZoneExpected("2020-09-27 12:34:56.999"))
+ .addRoundTrip("timestamp(6) with local time zone", timestampWithTimeZoneInput("2020-09-27 12:34:56.123456"), createTimestampWithTimeZoneType(6), timestampWithTimeZoneExpected("2020-09-27 12:34:56.123456"))
+
+ //test cases for timestamp with zero precision and with non-zero seconds
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("2017-07-01 00:00:01"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("2017-07-01 00:00:01")) // summer on northern hemisphere (possible DST)
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("2017-01-01 00:00:02"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("2017-01-01 00:00:02")) // winter on northern hemisphere (possible DST on southern hemisphere)
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("1970-01-01 00:00:03"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("1970-01-01 00:00:03")) // change forward at midnight in JVM
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("1983-04-01 00:00:04"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("1983-04-01 00:00:04")) // change forward at midnight in Vilnius
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("1983-10-01 00:00:05"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("1983-10-01 00:00:05")) // change backward at midnight in Vilnius
+ .addRoundTrip("timestamp(0) with local time zone", timestampWithTimeZoneInput("9999-12-31 00:00:59"), createTimestampWithTimeZoneType(0), timestampWithTimeZoneExpected("9999-12-31 00:00:59")) // max value in Exasol
+
+ .execute(getQueryRunner(), session, exasolCreateAndInsert(TEST_SCHEMA + "." + "test_timestamp"));
+ }
+
+ private String timestampWithTimeZoneInput(String jvmTimeZoneString)
+ {
+ return "TIMESTAMP '%s'".formatted(jvmTimeZoneString);
+ }
+
+ private String timestampWithTimeZoneExpected(String jvmTimeZoneString)
+ {
+ return "TIMESTAMP '%s %s'".formatted(jvmTimeZoneString, jvmZone.getId());
+ }
+
+ @Test
+ // See for more details: https://docs.exasol.com/db/latest/sql_references/data_types/datatypedetails.htm
+ void testUnsupportedTimestampValues()
+ {
+ // Below minimum supported TIMESTAMP value (must be >= 0001-01-01)
+ testUnsupportedInsertValue(
+ "TIMESTAMP",
+ "TIMESTAMP '10000-01-01 00:00:00.000000'",
+ "data exception - invalid character value for cast; Value: '10000-01-01 00:00:00.000000'");
+
+ // Above maximum supported TIMESTAMP value (must be <= 9999-12-31)
+ testUnsupportedInsertValue(
+ "TIMESTAMP",
+ "TIMESTAMP '0000-12-31 23:59:59.999999'",
+ "data exception - invalid date value; Value: '0000-12-31 23:59:59.999999'");
+
+ // Exceeds TIMESTAMP maximum supported fractional seconds precision (9 digits)
+ testUnsupportedInsertValue(
+ "TIMESTAMP",
+ "TIMESTAMP '2024-01-01 12:34:56.1234567890'",
+ "data exception - invalid character value for cast; Value: '2024-01-01 12:34:56.1234567890'");
+
+ // Negative precisions are not supported
+ testUnsupportedDefinition(
+ "TIMESTAMP(-1)",
+ "syntax error, unexpected '-', expecting UNSIGNED_INTEGER");
+ }
+
+ @Test
+ // See for more details: https://docs.exasol.com/db/latest/sql_references/data_types/datatypedetails.htm
+ void testUnsupportedTimestampWithLocalTimeZoneValues()
+ {
+ testUnsupportedDstGapJvmTimeZoneValue("2018-04-01 02:13:55.123", 3);
+ testUnsupportedDstGapJvmTimeZoneValue("2018-04-01 02:13:55.123456", 6);
+
+ // Below minimum supported TIMESTAMP WITH LOCAL TIME ZONE value (must be >= 0001-01-01)
+ testUnsupportedInsertValue(
+ "TIMESTAMP WITH LOCAL TIME ZONE",
+ "TIMESTAMP '10000-01-01 00:00:00.000000'",
+ "data exception - invalid character value for cast; Value: '10000-01-01 00:00:00.000000'");
+
+ // Above maximum supported TIMESTAMP WITH LOCAL TIME ZONE value (must be <= 9999-12-31)
+ testUnsupportedInsertValue(
+ "TIMESTAMP WITH LOCAL TIME ZONE",
+ "TIMESTAMP '0000-12-31 23:59:59.999999'",
+ "data exception - invalid date value; Value: '0000-12-31 23:59:59.999999'");
+
+ // Exceeds TIMESTAMP WITH LOCAL TIME ZONE maximum supported fractional seconds precision (9 digits)
+ testUnsupportedInsertValue(
+ "TIMESTAMP WITH LOCAL TIME ZONE",
+ "TIMESTAMP '2024-01-01 12:34:56.1234567890'",
+ "data exception - invalid character value for cast; Value: '2024-01-01 12:34:56.1234567890'");
+
+ // Negative precisions are not supported
+ testUnsupportedDefinition(
+ "TIMESTAMP(-1) WITH LOCAL TIME ZONE",
+ "syntax error, unexpected '-', expecting UNSIGNED_INTEGER");
+ }
+
+ private void testUnsupportedDstGapJvmTimeZoneValue(String dstGapJvmTimeZoneString, int precision)
+ {
+ try (TestTable table = new TestTable(onRemoteDatabase(), TestingExasolServer.TEST_SCHEMA + ".timestamp_dst_gap",
+ "(col TIMESTAMP(%d) WITH LOCAL TIME ZONE)".formatted(precision))) {
+ // Exasol successfully resolves dst gap value and saves it to database
+ onRemoteDatabase().execute(format("INSERT INTO %s (col) VALUES (%s)", table.getName(),
+ "TO_TIMESTAMP('%s', 'YYYY-MM-DD HH24:MI:SS.FF%d')".formatted(dstGapJvmTimeZoneString, precision)));
+ assertThat(exasolServer.getSingleResult(
+ "SELECT count(*) FROM %s WHERE col = TO_TIMESTAMP('%s', 'YYYY-MM-DD HH24:MI:SS.FF%d')".formatted(table.getName(), dstGapJvmTimeZoneString, precision),
+ String.class))
+ .matches("1");
+
+ //Trino query throws exception, because dst gap value is not valid for 'America/Bahia_Banderas' time zone
+ assertThat(query(
+ "SELECT count(*) FROM %s WHERE col = TIMESTAMP '%s %s'".formatted(table.getName(), dstGapJvmTimeZoneString, jvmZone.getId())))
+ .failure().hasMessageEndingWith("America/Bahia_Banderas' is not a valid TIMESTAMP literal");
+ }
+ }
+
// See for more details: https://docs.exasol.com/saas/microcontent/Resources/MicroContent/general/hash-data-type.htm
@Test
void testHashtype()
@@ -312,36 +548,36 @@ void testHashtype()
void testUnsupportedHashTypeDefinitions()
{
// Too few bytes (< 1)
- testUnsupportedHashTypeDefinition(
+ testUnsupportedDefinition(
"HASHTYPE(0 BYTE)",
"the given size of HASHTYPE is too small. A minimum of 1 bytes are required");
// Too many bytes (> 1024)
- testUnsupportedHashTypeDefinition(
+ testUnsupportedDefinition(
"HASHTYPE(1025 BYTE)",
"the given size of HASHTYPE is too large. At most 1024 bytes are allowed");
// Too few bits (< 8)
- testUnsupportedHashTypeDefinition(
+ testUnsupportedDefinition(
"HASHTYPE(7 BIT)",
"the given size of HASHTYPE is too small. A minimum of 8 bits are required");
// Too many bits (> 8192)
- testUnsupportedHashTypeDefinition(
+ testUnsupportedDefinition(
"HASHTYPE(8193 BIT)",
"the given size of HASHTYPE is too large. At most 8192 bits are allowed");
// Bits not divisible by 8
- testUnsupportedHashTypeDefinition(
+ testUnsupportedDefinition(
"HASHTYPE(9 BIT)",
"Bit size of HASHTYPE has to be a multiple of 8");
}
- private void testUnsupportedHashTypeDefinition(
+ private void testUnsupportedDefinition(
String exasolType,
String expectedException)
{
- String tableName = "test_unsupported_hashtype_" + randomNameSuffix();
+ String tableName = "test_unsupported_definition_" + randomNameSuffix();
assertExasolSqlQueryFails(
"CREATE TABLE %s.%s (col %s)".formatted(TEST_SCHEMA, tableName, exasolType),
expectedException);
@@ -352,43 +588,43 @@ private void testUnsupportedHashTypeDefinition(
void testUnsupportedHashTypeInsertValues()
{
// Invalid hex character
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(4 BYTE)",
"'GGGGGGGG'",
"data exception - Invalid hash format");
// Too short for declared size (expecting 4 bytes = 8 hex chars, got 6)
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(4 BYTE)",
"'AABBCC'",
"data exception - Invalid hash format");
// Too short for declared size (expecting 16 bytes = 32 hex chars, got 31)
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(16 BYTE)",
"'550e8400-e29b-11d4-a716-44665544000'",
"data exception - Invalid hash format");
// Too long for declared size (expecting 4 bytes = 8 hex chars, got 10)
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(4 BYTE)",
"'AABBCCDDEE'",
"data exception - Invalid hash format");
// Unexpected symbol inside
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(4 BYTE)",
"'AABB-CCZZ'",
"data exception - Invalid hash format");
// Parentheses instead of curly brackets
- testUnsupportedHashTypeInsertValue(
+ testUnsupportedInsertValue(
"HASHTYPE(4 BYTE)",
"'(AABB-CCCC)'",
"data exception - Invalid hash format");
}
- private void testUnsupportedHashTypeInsertValue(
+ private void testUnsupportedInsertValue(
String exasolType,
String inputLiteral,
String expectedException)
diff --git a/plugin/trino-exasol/src/test/java/io/trino/plugin/exasol/TestingExasolServer.java b/plugin/trino-exasol/src/test/java/io/trino/plugin/exasol/TestingExasolServer.java
index b3021a8b2f43..b70aa76e3e96 100644
--- a/plugin/trino-exasol/src/test/java/io/trino/plugin/exasol/TestingExasolServer.java
+++ b/plugin/trino-exasol/src/test/java/io/trino/plugin/exasol/TestingExasolServer.java
@@ -24,6 +24,7 @@
import java.io.UncheckedIOException;
import java.sql.Connection;
import java.sql.DriverManager;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
@@ -87,6 +88,27 @@ public void execute(@Language("SQL") String sql, String user, String password)
}
}
+ public