diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/BytecodeUtils.java b/core/trino-main/src/main/java/io/trino/sql/gen/BytecodeUtils.java index 1ac3b7212fef..b44d7a8a5302 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/BytecodeUtils.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/BytecodeUtils.java @@ -248,16 +248,7 @@ public static BytecodeNode generateFullInvocation( } else { BytecodeNode argument = argumentCompilers.get(i).apply(Optional.empty()); - if (argument instanceof InputReferenceNode) { - argumentConventions.add(BLOCK_POSITION); - } - else if (functionMetadata.getArgumentDefinitions().get(i).isNullable()) { - // a Java function can only have 255 arguments, so if the count is high use boxed nullable instead of the more efficient null flag - argumentConventions.add(argumentCompilers.size() > 100 ? BOXED_NULLABLE : NULL_FLAG); - } - else { - argumentConventions.add(NEVER_NULL); - } + argumentConventions.add(getPreferredArgumentConvention(argument, argumentCompilers.size(), functionMetadata.getArgumentDefinitions().get(i).isNullable())); arguments.add(argument); } } @@ -355,6 +346,21 @@ else if (type == ConnectorSession.class) { return block; } + private static InvocationArgumentConvention getPreferredArgumentConvention(BytecodeNode argument, int argumentCount, boolean nullable) + { + // a Java function can only have 255 arguments, so if the count is low use block position or boxed nullable as they are more efficient + if (argumentCount <= 100) { + if (argument instanceof InputReferenceNode) { + return BLOCK_POSITION; + } + if (nullable) { + return NULL_FLAG; + } + } + + return nullable ? BOXED_NULLABLE : NEVER_NULL; + } + public static BytecodeBlock unboxPrimitiveIfNecessary(Scope scope, Class boxedType) { BytecodeBlock block = new BytecodeBlock(); diff --git a/testing/trino-tests/src/test/java/io/trino/tests/TestServer.java b/testing/trino-tests/src/test/java/io/trino/tests/TestServer.java index 1d394a48f89e..6f4b1b0a0c2b 100644 --- a/testing/trino-tests/src/test/java/io/trino/tests/TestServer.java +++ b/testing/trino-tests/src/test/java/io/trino/tests/TestServer.java @@ -39,6 +39,7 @@ import org.testng.annotations.Test; import java.net.URI; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -257,25 +258,21 @@ public void testVersionOnError() @Test public void testVersionOnCompilerFailedError() { - int numberColumns = 170; String tableName = "memory.default.test_version_on_compiler_failed"; try (TestingTrinoClient testingClient = new TestingTrinoClient(server, testSessionBuilder().build())) { testingClient.execute("DROP TABLE IF EXISTS " + tableName); - testingClient.execute("CREATE TABLE " + tableName + " AS SELECT " + - IntStream.range(0, numberColumns) - .mapToObj(columnNumber -> format("'' AS f%s", columnNumber)) - .collect(joining(", "))); - - String pivotQuery = "SELECT x, y " + - "FROM " + tableName + " " + - "CROSS JOIN UNNEST(" + - IntStream.range(0, numberColumns) - .mapToObj(Integer::toString) - .collect(joining(", ", "ARRAY[", "]")) + "," + - IntStream.range(0, numberColumns) - .mapToObj(columnNumber -> format("f%s", columnNumber)) - .collect(joining(", ", "ARRAY[", "]")) + ") t(x, y)"; - checkVersionOnError(pivotQuery, "TrinoException: Compiler failed(?s:.*)at io.trino.sql.gen.PageFunctionCompiler.compileProjection"); + testingClient.execute("CREATE TABLE " + tableName + " AS SELECT '' as foo"); + + // This query is designed to cause a compile failure, and hopefully not run too long. + // The exact query is not important, just that it causes a failure. + String array = IntStream.range(0, 254) + .mapToObj(columnNumber -> "foo") + .collect(joining(", ", "ARRAY[", "]")); + String query = "SELECT " + + String.join(" || ", Collections.nCopies(10, array)) + + "FROM " + tableName; + + checkVersionOnError(query, "TrinoException: Compiler failed(?s:.*)at io.trino.sql.gen.ExpressionCompiler.compile"); } }