Repository: prestodb/presto
Issue: Array constructor with too many values causes ClassFormatError

Queries that contain very large array constructors cause bytecode to be generated that contains too many method arguments.

```
SELECT ARRAY['1','1','1','2','1','1','-1','1','1','1','1','1','-1','1','1','1','1','1','1','1','1','1','-1','1','-1','1','1','1','1','1','1','1','-1','-1','-1','1','-1','1','-1','3','-1','1','1','1','1','-1','-1','1','1','-1','-1','1','1','1','1','1','-1','1','1','1','1','1','-1','-1','1','-1','1','-1','1','1','1','-1','1','1','-1','1','1','-1','1','-1','-1','-1','1','1','-1','1','1','1','1','1','-1','1','-1','1','-1','1','1','1','1','-1','-1','-1','1','-1','-1','-1','1','1','1','-1','1','-1','-1','-1','-1','1','-1','-1','-1','1','-1','1','1','3','1','-1','-1','1','-1','-1','1','-1','-1','1','1','1','-1','-1','-1','1','1','1','-1','1','1','1','1','-1','-1','-1','1','-1','1','-1','3','-1','-1','1','-1','1','1','-1','-1','3','-1','1','-1','-1','-1','1','-1','-1','1','1','1','1','1','-1','1','1','-1','-1','-1','1','1','1','-1','1','-1','1','1','1','-1','-1','1','1','-1','-1','-1','-1','1','-1','-1','1','-1','1','1','-1','1','-1','-1','1','1','-1','-1','-1','-1','1','1','1','-1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','-1','-1','-1','-1','1','-1','1','-1','-1','1','3','-1','-1','1','1','3','1','1','1','1','1','1','1','1','-1','1','1','3','3','1','1','1','-1','-1','1','1','1','3','1','1','1','1','1','1','1','1','1','1','1','1','1','1','-1','1','1','1','1','1','1','1','3','1','1','1','1','1','1','1','1','1','1','1','1','-1','1','1','1','1','1','-1','1','3','1','1','1','1','1','3','1','3','1','1','1','1','3','-1','-1','-1','1','1','1','-1','-1','-1','-1','-1','1','-1','1','1','3','1','1','1','1','-1','-1','3','1','1','3','-1','1','1','1','-1','-1','1','1','1','-1','1','1','1','-1','1','3','1','1','1','1','3','3','-1','1','1','-1','3','3','1','1','3','-1','-1','1','1','-1','-1','1','1','3','1','-1','3','3','1','1','3','1','1','1','3','3','1','1','3','3','3','1','1','1','1','-1','-1','1','1','3','1','1','3','3','1','1','3','3','1','-1','1','1','1','1','-1','1','1','1','1','1','3','3','-1','-1','-1','1','-1','1','1','3','1','3','1','1','1','1','1','3','1','1','-1','1','3','3','3','1','1','3','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','3','1','3','3','1','1','1','1','1','1','1','1','1','1','1','1','1','3','3','1','1'];
```

fails with

```
com.google.common.util.concurrent.ExecutionError: java.lang.ClassFormatError: Too many arguments in method signature i
n class file com_facebook_presto_$gen_SliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSlice
SliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSli
ceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceS
liceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSlic
eSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSl
iceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSlice
SliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSli
ceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceSliceS
liceSliceSliceSliceSliceSliceSliceSlice
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2201)
        at com.google.common.cache.LocalCache.get(LocalCache.java:3937)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3941)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4824)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4830)
        at com.facebook.presto.metadata.FunctionRegistry.getScalarFunctionImplementation(FunctionRegistry.java:586)
        at com.facebook.presto.sql.planner.ExpressionInterpreter$Visitor.visitFunctionCall(ExpressionInterpreter.java:
798)
        at com.facebook.presto.sql.planner.ExpressionInterpreter$Visitor.visitArrayConstructor(ExpressionInterpreter.j
ava:940)
        at com.facebook.presto.sql.tree.ArrayConstructor.accept(ArrayConstructor.java:54)
        at com.facebook.presto.sql.tree.AstVisitor.process(AstVisitor.java:22)
        at com.facebook.presto.sql.planner.ExpressionInterpreter.optimize(ExpressionInterpreter.java:251)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.simplifyExpression(SimplifyExpre
ssions.java:133)
        at com.google.common.collect.Maps$7.transformEntry(Maps.java:1812)
        at com.google.common.collect.Maps$10.getValue(Maps.java:1857)
        at com.google.common.collect.ImmutableMap.copyOf(ImmutableMap.java:292)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.visitProject(SimplifyExpressions
.java:92)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.visitProject(SimplifyExpressions
.java:70)
        at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
        at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:86)
        at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:97)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.visitProject(SimplifyExpressions
.java:91)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.visitProject(SimplifyExpressions
.java:70)
        at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
        at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:86)
        at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:97)
        at com.facebook.presto.sql.planner.optimizations.SimplifyExpressions$Rewriter.visitProject(SimplifyExpressions
.java:91)
...
```


Changed files:
presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
presto-main/src/main/java/com/facebook/presto/sql/planner/ExpressionInterpreter.java

diff --git a/presto-main/src/main/java/com/facebook/presto/sql/planner/ExpressionInterpreter.java b/presto-main/src/main/java/com/facebook/presto/sql/planner/ExpressionInterpreter.java
index 3b49320335..4bdf002a0b 100644
--- a/presto-main/src/main/java/com/facebook/presto/sql/planner/ExpressionInterpreter.java
+++ b/presto-main/src/main/java/com/facebook/presto/sql/planner/ExpressionInterpreter.java
@@ -25,6 +25,8 @@ import com.facebook.presto.spi.ConnectorSession;
 import com.facebook.presto.spi.PrestoException;
 import com.facebook.presto.spi.RecordCursor;
 import com.facebook.presto.spi.block.Block;
+import com.facebook.presto.spi.block.BlockBuilder;
+import com.facebook.presto.spi.block.BlockBuilderStatus;
 import com.facebook.presto.spi.type.StandardTypes;
 import com.facebook.presto.spi.type.Type;
 import com.facebook.presto.sql.analyzer.AnalysisContext;
@@ -68,6 +70,7 @@ import com.facebook.presto.sql.tree.SimpleCaseExpression;
 import com.facebook.presto.sql.tree.StringLiteral;
 import com.facebook.presto.sql.tree.SubscriptExpression;
 import com.facebook.presto.sql.tree.WhenClause;
+import com.facebook.presto.type.ArrayType;
 import com.facebook.presto.type.LikeFunctions;
 import com.facebook.presto.util.Failures;
 import com.facebook.presto.util.FastutilSetHelper;
@@ -93,6 +96,7 @@ import java.util.stream.Stream;
 
 import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
 import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
+import static com.facebook.presto.spi.type.TypeUtils.writeNativeValue;
 import static com.facebook.presto.sql.analyzer.ExpressionAnalyzer.createConstantAnalyzer;
 import static com.facebook.presto.sql.analyzer.SemanticErrorCode.EXPRESSION_NOT_CONSTANT;
 import static com.facebook.presto.sql.planner.LiteralInterpreter.toExpression;
@@ -936,7 +940,18 @@ public class ExpressionInterpreter
         @Override
         protected Object visitArrayConstructor(ArrayConstructor node, Object context)
         {
-            return visitFunctionCall(new FunctionCall(QualifiedName.of(ArrayConstructor.ARRAY_CONSTRUCTOR), node.getValues()), context);
+            Type elementType = ((ArrayType) expressionTypes.get(node)).getElementType();
+            BlockBuilder arrayBlockBuilder = elementType.createBlockBuilder(new BlockBuilderStatus(), node.getValues().size());
+
+            for (Expression expression : node.getValues()) {
+                Object value = process(expression, context);
+                if (value instanceof Expression) {
+                    return visitFunctionCall(new FunctionCall(QualifiedName.of(ArrayConstructor.ARRAY_CONSTRUCTOR), node.getValues()), context);
+                }
+                writeNativeValue(elementType, arrayBlockBuilder, value);
+            }
+
+            return arrayBlockBuilder.build();
         }
 
         @Override
diff --git a/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java b/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
index 70d3b8c032..41f09f57d5 100644
--- a/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
+++ b/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
@@ -33,6 +33,7 @@ import com.facebook.presto.sql.tree.LikePredicate;
 import com.facebook.presto.sql.tree.QualifiedName;
 import com.facebook.presto.sql.tree.QualifiedNameReference;
 import com.facebook.presto.sql.tree.StringLiteral;
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import io.airlift.slice.Slice;
@@ -48,6 +49,7 @@ import org.testng.annotations.Test;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
 
 import static com.facebook.presto.SessionTestUtils.TEST_SESSION;
 import static com.facebook.presto.spi.type.BigintType.BIGINT;
@@ -64,6 +66,7 @@ import static com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionT
 import static com.facebook.presto.sql.planner.ExpressionInterpreter.expressionInterpreter;
 import static com.facebook.presto.sql.planner.ExpressionInterpreter.expressionOptimizer;
 import static io.airlift.slice.Slices.utf8Slice;
+import static java.lang.String.format;
 import static java.util.Locale.ENGLISH;
 import static org.testng.Assert.assertEquals;
 
@@ -929,6 +932,26 @@ public class TestExpressionInterpreter
         optimize("0 / 0");
     }
 
+    @Test
+    public void testMassiveArrayConstructor()
+    {
+        optimize(format("ARRAY [%s]", Joiner.on(", ").join(IntStream.range(0, 10_000).mapToObj(i -> "(bound_long + " + i + ")").iterator())));
+        optimize(format("ARRAY [%s]", Joiner.on(", ").join(IntStream.range(0, 10_000).mapToObj(i -> "'" + i + "'").iterator())));
+        optimize(format("ARRAY [%s]", Joiner.on(", ").join(IntStream.range(0, 10_000).mapToObj(i -> "ARRAY['" + i + "']").iterator())));
+    }
+
+    @Test
+    public void testArrayConstructor()
+    {
+        optimize("ARRAY []");
+        assertOptimizedEquals("ARRAY [(unbound_long + 0), (unbound_long + 1), (unbound_long + 2)]",
+                "array_constructor((unbound_long + 0), (unbound_long + 1), (unbound_long + 2))");
+        assertOptimizedEquals("ARRAY [(bound_long + 0), (unbound_long + 1), (bound_long + 2)]",
+                "array_constructor((bound_long + 0), (unbound_long + 1), (bound_long + 2))");
+        assertOptimizedEquals("ARRAY [(bound_long + 0), (unbound_long + 1), NULL]",
+                "array_constructor((bound_long + 0), (unbound_long + 1), NULL)");
+    }
+
     @Test(expectedExceptions = PrestoException.class)
     public void testArraySubscriptConstantNegativeIndex()
     {