diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f24988355476..b2379ba50af0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -513,6 +513,7 @@ jobs: include: - { modules: [ client/trino-jdbc, plugin/trino-base-jdbc, plugin/trino-thrift, plugin/trino-memory ] } - { modules: core/trino-main } + - { modules: core/trino-main, jdk: 19 } - { modules: plugin/trino-accumulo } - { modules: plugin/trino-bigquery } - { modules: plugin/trino-cassandra } @@ -576,6 +577,8 @@ jobs: github.event.client_payload.pull_request.head.sha == github.event.client_payload.slash_command.args.named.sha && format('refs/pull/{0}/head', github.event.client_payload.pull_request.number) || '' }} - uses: ./.github/actions/setup + with: + java-version: ${{ matrix.jdk != '' && matrix.jdk || '17' }} - name: Cleanup node # This is required as a virtual environment update 20210219.1 left too little space for MemSQL to work if: matrix.modules == 'plugin/trino-singlestore' diff --git a/core/trino-main/src/main/java/io/trino/dispatcher/DecoratingListeningExecutorService.java b/core/trino-main/src/main/java/io/trino/dispatcher/DecoratingListeningExecutorService.java index a032c02ad628..bd555bb43eba 100644 --- a/core/trino-main/src/main/java/io/trino/dispatcher/DecoratingListeningExecutorService.java +++ b/core/trino-main/src/main/java/io/trino/dispatcher/DecoratingListeningExecutorService.java @@ -17,14 +17,21 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; +import javax.annotation.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Objects.requireNonNull; @@ -32,6 +39,27 @@ public class DecoratingListeningExecutorService extends ForwardingListeningExecutorService implements ListeningExecutorService { + // TODO remove after requiring Java 19+ for runtime. + private static final @Nullable MethodHandle CLOSE_METHOD; + + static { + Method closeMethod; + try { + closeMethod = ExecutorService.class.getMethod("close"); + } + catch (NoSuchMethodException e) { + closeMethod = null; + } + try { + CLOSE_METHOD = closeMethod != null + ? MethodHandles.lookup().unreflect(closeMethod) + : null; + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + private final ListeningExecutorService delegate; private final TaskDecorator decorator; @@ -142,6 +170,23 @@ public boolean awaitTermination(long timeout, TimeUnit unit) return super.awaitTermination(timeout, unit); } + // TODO This is temporary, until Guava's ForwardingExecutorService has the method in their interface. See https://github.com/google/guava/issues/6296 + //@Override + public void close() + { + if (CLOSE_METHOD == null) { + throw new UnsupportedOperationException("ExecutorService.close has close() method since Java 19. " + + "The DecoratingListeningExecutorService supports the method only when run with Java 19 runtime."); + } + try { + CLOSE_METHOD.invoke(delegate()); + } + catch (Throwable e) { + throwIfUnchecked(e); + throw new RuntimeException(e); + } + } + public interface TaskDecorator { Runnable decorate(Runnable command); diff --git a/core/trino-main/src/test/java/io/trino/sql/planner/TestUnwrapCastInComparison.java b/core/trino-main/src/test/java/io/trino/sql/planner/TestUnwrapCastInComparison.java index f2bc80beac50..b55b5594e39a 100644 --- a/core/trino-main/src/test/java/io/trino/sql/planner/TestUnwrapCastInComparison.java +++ b/core/trino-main/src/test/java/io/trino/sql/planner/TestUnwrapCastInComparison.java @@ -628,12 +628,16 @@ public void testNoEffect() // INTEGER->REAL implicit cast is not injective if the real constant is >= 2^23 and <= 2^31 - 1 testUnwrap("integer", "a = REAL '8388608'", "CAST(a AS REAL) = REAL '8388608.0'"); - testUnwrap("integer", "a = REAL '2147483647'", "CAST(a AS REAL) = REAL '2.14748365E9'"); + testUnwrap("integer", "a = REAL '2147483647'", Runtime.version().feature() >= 19 + ? "CAST(a AS REAL) = REAL '2.1474836E9'" + : "CAST(a AS REAL) = REAL '2.14748365E9'"); // INTEGER->REAL implicit cast is not injective if the real constant is <= -2^23 and >= -2^31 + 1 testUnwrap("integer", "a = REAL '-8388608'", "CAST(a AS REAL) = REAL '-8388608.0'"); - testUnwrap("integer", "a = REAL '-2147483647'", "CAST(a AS REAL) = REAL '-2.14748365E9'"); + testUnwrap("integer", "a = REAL '-2147483647'", Runtime.version().feature() >= 19 + ? "CAST(a AS REAL) = REAL '-2.1474836E9'" + : "CAST(a AS REAL) = REAL '-2.14748365E9'"); // DECIMAL(p)->DOUBLE not injective for p > 15 testUnwrap("decimal(16)", "a = DOUBLE '1'", "CAST(a AS DOUBLE) = 1E0"); diff --git a/core/trino-main/src/test/java/io/trino/type/TestArrayOperators.java b/core/trino-main/src/test/java/io/trino/type/TestArrayOperators.java index 6d9825c31d93..ae9f73ded463 100644 --- a/core/trino-main/src/test/java/io/trino/type/TestArrayOperators.java +++ b/core/trino-main/src/test/java/io/trino/type/TestArrayOperators.java @@ -318,7 +318,9 @@ public void testArrayToJson() assertThat(assertions.expression("CAST(a AS JSON)") .binding("a", "ARRAY[3.14E0, 1e-323, 1e308, nan(), infinity(), -infinity(), null]")) .hasType(JSON) - .isEqualTo("[3.14,1.0E-323,1.0E308,\"NaN\",\"Infinity\",\"-Infinity\",null]"); + .isEqualTo(Runtime.version().feature() >= 19 + ? "[3.14,9.9E-324,1.0E308,\"NaN\",\"Infinity\",\"-Infinity\",null]" + : "[3.14,1.0E-323,1.0E308,\"NaN\",\"Infinity\",\"-Infinity\",null]"); assertThat(assertions.expression("CAST(a AS JSON)") .binding("a", "ARRAY[DECIMAL '3.14', null]")) diff --git a/core/trino-main/src/test/java/io/trino/type/TestDecimalCasts.java b/core/trino-main/src/test/java/io/trino/type/TestDecimalCasts.java index a66ad9d8d6b9..289dc1959e85 100644 --- a/core/trino-main/src/test/java/io/trino/type/TestDecimalCasts.java +++ b/core/trino-main/src/test/java/io/trino/type/TestDecimalCasts.java @@ -267,7 +267,9 @@ public void testDoubleToShortDecimalCasts() assertDecimalFunction("CAST(DOUBLE '-1234567890.0' AS DECIMAL(20,10))", decimal("-1234567890.0000000000", createDecimalType(20, 10))); assertDecimalFunction("CAST(DOUBLE '1234567890.0' AS DECIMAL(30,20))", decimal("1234567890.00000000000000000000", createDecimalType(30, 20))); assertDecimalFunction("CAST(DOUBLE '-1234567890.0' AS DECIMAL(30,20))", decimal("-1234567890.00000000000000000000", createDecimalType(30, 20))); - assertDecimalFunction("CAST(DOUBLE '123456789123456784' AS DECIMAL(18,0))", decimal("123456789123456784", createDecimalType(18))); + assertDecimalFunction("CAST(DOUBLE '123456789123456784' AS DECIMAL(18,0))", Runtime.version().feature() >= 19 + ? decimal("123456789123456780", createDecimalType(18)) + : decimal("123456789123456784", createDecimalType(18))); assertDecimalFunction("CAST(DOUBLE '123456789.123456790' AS DECIMAL(18,9))", decimal("123456789.123456790", createDecimalType(18, 9))); // test rounding @@ -367,18 +369,42 @@ public void testFloatToDecimalCasts() assertDecimalFunction("CAST(REAL '1000' AS DECIMAL(4,0))", decimal("1000", createDecimalType(4))); assertDecimalFunction("CAST(REAL '1000.01' AS DECIMAL(7,2))", decimal("01000.01", createDecimalType(7, 2))); assertDecimalFunction("CAST(REAL '-234.0' AS DECIMAL(3,0))", decimal("-234", createDecimalType(3))); - assertDecimalFunction("CAST(REAL '12345678400000000' AS DECIMAL(17,0))", decimal("12345678400000000", createDecimalType(17))); - assertDecimalFunction("CAST(REAL '-12345678400000000' AS DECIMAL(17,0))", decimal("-12345678400000000", createDecimalType(17))); - assertDecimalFunction("CAST(REAL '1234567940' AS DECIMAL(20,10))", decimal("1234567940.0000000000", createDecimalType(20, 10))); - assertDecimalFunction("CAST(REAL '-1234567940' AS DECIMAL(20,10))", decimal("-1234567940.0000000000", createDecimalType(20, 10))); - assertDecimalFunction("CAST(REAL '1234567940' AS DECIMAL(30,20))", decimal("1234567940.00000000000000000000", createDecimalType(30, 20))); - assertDecimalFunction("CAST(REAL '-1234567940' AS DECIMAL(30,20))", decimal("-1234567940.00000000000000000000", createDecimalType(30, 20))); - assertDecimalFunction("CAST(REAL '123456790519087104' AS DECIMAL(18,0))", decimal("123456791000000000", createDecimalType(18))); - assertDecimalFunction("CAST(REAL '-123456790519087104' AS DECIMAL(18,0))", decimal("-123456791000000000", createDecimalType(18))); - assertDecimalFunction("CAST(REAL '123456790519087104' AS DECIMAL(20,2))", decimal("123456791000000000.00", createDecimalType(20, 2))); - assertDecimalFunction("CAST(REAL '-123456790519087104' AS DECIMAL(20,2))", decimal("-123456791000000000.00", createDecimalType(20, 2))); - assertDecimalFunction("CAST(REAL '1234567905190871' AS DECIMAL(18,2))", decimal("1234567950000000.00", createDecimalType(18, 2))); - assertDecimalFunction("CAST(REAL '-1234567905190871' AS DECIMAL(18,2))", decimal("-1234567950000000.00", createDecimalType(18, 2))); + assertDecimalFunction("CAST(REAL '12345678400000000' AS DECIMAL(17,0))", Runtime.version().feature() >= 19 + ? decimal("12345678000000000", createDecimalType(17)) + : decimal("12345678400000000", createDecimalType(17))); + assertDecimalFunction("CAST(REAL '-12345678400000000' AS DECIMAL(17,0))", Runtime.version().feature() >= 19 + ? decimal("-12345678000000000", createDecimalType(17)) + : decimal("-12345678400000000", createDecimalType(17))); + assertDecimalFunction("CAST(REAL '1234567940' AS DECIMAL(20,10))", Runtime.version().feature() >= 19 + ? decimal("1234568000.0000000000", createDecimalType(20, 10)) + : decimal("1234567940.0000000000", createDecimalType(20, 10))); + assertDecimalFunction("CAST(REAL '-1234567940' AS DECIMAL(20,10))", Runtime.version().feature() >= 19 + ? decimal("-1234568000.0000000000", createDecimalType(20, 10)) + : decimal("-1234567940.0000000000", createDecimalType(20, 10))); + assertDecimalFunction("CAST(REAL '1234567940' AS DECIMAL(30,20))", Runtime.version().feature() >= 19 + ? decimal("1234568000.00000000000000000000", createDecimalType(30, 20)) + : decimal("1234567940.00000000000000000000", createDecimalType(30, 20))); + assertDecimalFunction("CAST(REAL '-1234567940' AS DECIMAL(30,20))", Runtime.version().feature() >= 19 + ? decimal("-1234568000.00000000000000000000", createDecimalType(30, 20)) + : decimal("-1234567940.00000000000000000000", createDecimalType(30, 20))); + assertDecimalFunction("CAST(REAL '123456790519087104' AS DECIMAL(18,0))", Runtime.version().feature() >= 19 + ? decimal("123456790000000000", createDecimalType(18)) + : decimal("123456791000000000", createDecimalType(18))); + assertDecimalFunction("CAST(REAL '-123456790519087104' AS DECIMAL(18,0))", Runtime.version().feature() >= 19 + ? decimal("-123456790000000000", createDecimalType(18)) + : decimal("-123456791000000000", createDecimalType(18))); + assertDecimalFunction("CAST(REAL '123456790519087104' AS DECIMAL(20,2))", Runtime.version().feature() >= 19 + ? decimal("123456790000000000.00", createDecimalType(20, 2)) + : decimal("123456791000000000.00", createDecimalType(20, 2))); + assertDecimalFunction("CAST(REAL '-123456790519087104' AS DECIMAL(20,2))", Runtime.version().feature() >= 19 + ? decimal("-123456790000000000.00", createDecimalType(20, 2)) + : decimal("-123456791000000000.00", createDecimalType(20, 2))); + assertDecimalFunction("CAST(REAL '1234567905190871' AS DECIMAL(18,2))", Runtime.version().feature() >= 19 + ? decimal("1234568000000000.00", createDecimalType(18, 2)) + : decimal("1234567950000000.00", createDecimalType(18, 2))); + assertDecimalFunction("CAST(REAL '-1234567905190871' AS DECIMAL(18,2))", Runtime.version().feature() >= 19 + ? decimal("-1234568000000000.00", createDecimalType(18, 2)) + : decimal("-1234567950000000.00", createDecimalType(18, 2))); assertDecimalFunction("CAST(REAL '1456213.432632456' AS DECIMAL(18,9))", decimal("001456213.400000000", createDecimalType(18, 9))); // test roundtrip @@ -390,7 +416,9 @@ public void testFloatToDecimalCasts() assertInvalidCast("CAST(REAL '234.0' AS DECIMAL(2,0))", "Cannot cast REAL '234.0' to DECIMAL(2, 0)"); assertInvalidCast("CAST(REAL '1000.01' AS DECIMAL(5,2))", "Cannot cast REAL '1000.01' to DECIMAL(5, 2)"); assertInvalidCast("CAST(REAL '-234.0' AS DECIMAL(2,0))", "Cannot cast REAL '-234.0' to DECIMAL(2, 0)"); - assertInvalidCast("CAST(REAL '98765430784.0' AS DECIMAL(20, 10))", "Cannot cast REAL '9.8765431E10' to DECIMAL(20, 10)"); + assertInvalidCast("CAST(REAL '98765430784.0' AS DECIMAL(20, 10))", Runtime.version().feature() >= 19 + ? "Cannot cast REAL '9.876543E10' to DECIMAL(20, 10)" + : "Cannot cast REAL '9.8765431E10' to DECIMAL(20, 10)"); assertInvalidCast("CAST(CAST(nan() as REAL) AS DECIMAL(10,5))", "Cannot cast REAL 'NaN' to DECIMAL(10, 5)"); assertInvalidCast("CAST(CAST(infinity() as REAL) AS DECIMAL(10,1))", "Cannot cast REAL 'Infinity' to DECIMAL(10, 1)"); diff --git a/core/trino-main/src/test/java/io/trino/type/TestMapOperators.java b/core/trino-main/src/test/java/io/trino/type/TestMapOperators.java index 2911fc85d8ac..4d1a531d6f82 100644 --- a/core/trino-main/src/test/java/io/trino/type/TestMapOperators.java +++ b/core/trino-main/src/test/java/io/trino/type/TestMapOperators.java @@ -278,7 +278,9 @@ public void testMapToJson() assertThat(assertions.expression("cast(a as JSON)") .binding("a", "MAP(ARRAY[1e-323,1e308,nan()], ARRAY[-323,308,null])")) .hasType(JSON) - .isEqualTo("{\"1.0E-323\":-323,\"1.0E308\":308,\"NaN\":null}"); + .isEqualTo(Runtime.version().feature() >= 19 + ? "{\"1.0E308\":308,\"9.9E-324\":-323,\"NaN\":null}" + : "{\"1.0E-323\":-323,\"1.0E308\":308,\"NaN\":null}"); assertThat(assertions.expression("cast(a as JSON)") .binding("a", "MAP(ARRAY[DECIMAL '3.14', DECIMAL '0.01'], ARRAY[0.14, null])")) @@ -329,7 +331,9 @@ public void testMapToJson() assertThat(assertions.expression("cast(a as JSON)") .binding("a", "MAP(ARRAY[1, 2, 3, 5, 8, 13, 21], ARRAY[3.14E0, 1e-323, 1e308, nan(), infinity(), -infinity(), null])")) .hasType(JSON) - .isEqualTo("{\"1\":3.14,\"13\":\"-Infinity\",\"2\":1.0E-323,\"21\":null,\"3\":1.0E308,\"5\":\"NaN\",\"8\":\"Infinity\"}"); + .isEqualTo(Runtime.version().feature() >= 19 + ? "{\"1\":3.14,\"13\":\"-Infinity\",\"2\":9.9E-324,\"21\":null,\"3\":1.0E308,\"5\":\"NaN\",\"8\":\"Infinity\"}" + : "{\"1\":3.14,\"13\":\"-Infinity\",\"2\":1.0E-323,\"21\":null,\"3\":1.0E308,\"5\":\"NaN\",\"8\":\"Infinity\"}"); assertThat(assertions.expression("cast(a as JSON)") .binding("a", "MAP(ARRAY[1, 2], ARRAY[DECIMAL '3.14', null])")) diff --git a/testing/trino-testing-services/src/main/java/io/trino/testng/services/ManageTestResources.java b/testing/trino-testing-services/src/main/java/io/trino/testng/services/ManageTestResources.java index 8a2d29a2f922..3b3046f54f57 100644 --- a/testing/trino-testing-services/src/main/java/io/trino/testng/services/ManageTestResources.java +++ b/testing/trino-testing-services/src/main/java/io/trino/testng/services/ManageTestResources.java @@ -250,6 +250,11 @@ private static Rule isAutoCloseable() if (!(value instanceof AutoCloseable)) { return false; } + if (value instanceof ExecutorService) { + // Covered by isLeftoverExecutorService. + // ExecutorService is AutoCloseable since Java 19. + return false; + } // Disallow AutoCloseable instances, even if not started, before class is run. // Allocation of such resources generally correlates with too eager initialization.