Repository: prestodb/presto
Issue: Error executing prepared statement when complex join criteria contains parameter

A query like this:

```sql
SELECT * FROM (VALUES 1) t(a) JOIN (VALUES 2) u(a) ON t.a + u.a < ?;
```

Fails to execute with "EXECUTE ... USING ..." with:

```
com.facebook.presto.sql.analyzer.SemanticException: line 1:67: query takes no parameters
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitParameter(ExpressionAnalyzer.java:896)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitParameter(ExpressionAnalyzer.java:254)
	at com.facebook.presto.sql.tree.Parameter.accept(Parameter.java:48)
	at com.facebook.presto.sql.tree.StackableAstVisitor.process(StackableAstVisitor.java:26)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.process(ExpressionAnalyzer.java:273)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.getOperator(ExpressionAnalyzer.java:1130)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitComparisonExpression(ExpressionAnalyzer.java:423)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitComparisonExpression(ExpressionAnalyzer.java:254)
	at com.facebook.presto.sql.tree.ComparisonExpression.accept(ComparisonExpression.java:68)
	at com.facebook.presto.sql.tree.StackableAstVisitor.process(StackableAstVisitor.java:26)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.process(ExpressionAnalyzer.java:273)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyze(ExpressionAnalyzer.java:230)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyzeExpressions(ExpressionAnalyzer.java:1391)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyzeExpressionsWithSymbols(ExpressionAnalyzer.java:1344)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypes(ExpressionAnalyzer.java:1310)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypes(ExpressionAnalyzer.java:1298)
	at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypes(ExpressionAnalyzer.java:1286)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.desugar(DesugaringOptimizer.java:118)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitFilter(DesugaringOptimizer.java:92)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitFilter(DesugaringOptimizer.java:64)
	at com.facebook.presto.sql.planner.plan.FilterNode.accept(FilterNode.java:71)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:85)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:96)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:83)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:64)
	at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:85)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:96)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:83)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:64)
	at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:85)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:96)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:83)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:64)
	at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:85)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:96)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:83)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer$Rewriter.visitProject(DesugaringOptimizer.java:64)
	at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.rewrite(SimplePlanRewriter.java:85)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.lambda$defaultRewrite$0(SimplePlanRewriter.java:74)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.Iterator.forEachRemaining(Iterator.java:116)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter$RewriteContext.defaultRewrite(SimplePlanRewriter.java:75)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter.visitPlan(SimplePlanRewriter.java:39)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter.visitPlan(SimplePlanRewriter.java:23)
	at com.facebook.presto.sql.planner.plan.PlanVisitor.visitOutput(PlanVisitor.java:50)
	at com.facebook.presto.sql.planner.plan.OutputNode.accept(OutputNode.java:81)
	at com.facebook.presto.sql.planner.plan.SimplePlanRewriter.rewriteWith(SimplePlanRewriter.java:28)
	at com.facebook.presto.sql.planner.optimizations.DesugaringOptimizer.optimize(DesugaringOptimizer.java:61)
	at com.facebook.presto.sql.planner.LogicalPlanner.plan(LogicalPlanner.java:120)
	at com.facebook.presto.testing.LocalQueryRunner.createPlan(LocalQueryRunner.java:676)
	at com.facebook.presto.testing.LocalQueryRunner.createPlan(LocalQueryRunner.java:642)
	at com.facebook.presto.testing.LocalQueryRunner.createPlan(LocalQueryRunner.java:629)
	at com.facebook.presto.testing.LocalQueryRunner.createDrivers(LocalQueryRunner.java:539)
	at com.facebook.presto.testing.LocalQueryRunner.executeInternal(LocalQueryRunner.java:500)
	at com.facebook.presto.testing.LocalQueryRunner.lambda$execute$2(LocalQueryRunner.java:473)
	at com.facebook.presto.transaction.TransactionBuilder.execute(TransactionBuilder.java:149)
	at com.facebook.presto.testing.LocalQueryRunner.inTransaction(LocalQueryRunner.java:485)
	at com.facebook.presto.testing.LocalQueryRunner.execute(LocalQueryRunner.java:473)
	at com.facebook.presto.tests.AbstractTestQueryFramework.computeActual(AbstractTestQueryFramework.java:88)
	at com.facebook.presto.tests.TestLocalQueries.testExecuteUsingx(TestLocalQueries.java:46)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:696)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:882)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1189)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:124)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
	at org.testng.TestRunner.privateRun(TestRunner.java:767)
	at org.testng.TestRunner.run(TestRunner.java:617)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
	at org.testng.SuiteRunner.run(SuiteRunner.java:254)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
	at org.testng.TestNG.run(TestNG.java:1057)
	at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
	at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:127)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
```

Changed files:
presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java, presto-main/src/main/java/com/facebook/presto/sql/planner/RelationPlanner.java

diff --git a/presto-main/src/main/java/com/facebook/presto/sql/planner/RelationPlanner.java b/presto-main/src/main/java/com/facebook/presto/sql/planner/RelationPlanner.java
index cf374dc82b..8c10f859f5 100644
--- a/presto-main/src/main/java/com/facebook/presto/sql/planner/RelationPlanner.java
+++ b/presto-main/src/main/java/com/facebook/presto/sql/planner/RelationPlanner.java
@@ -332,6 +332,7 @@ class RelationPlanner
             rootPlanBuilder = subqueryPlanner.handleSubqueries(rootPlanBuilder, complexJoinExpressions, node);
 
             for (Expression expression : complexJoinExpressions) {
+                expression = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(analysis.getParameters(), analysis), expression);
                 postInnerJoinConditions.add(rootPlanBuilder.rewrite(expression));
             }
             root = rootPlanBuilder.getRoot();
diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
index 16dbf46cd7..d2ff43afab 100644
--- a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
+++ b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
@@ -7478,6 +7478,18 @@ public abstract class AbstractTestQueries
                 "VALUES (2, 4), (3, 8), (4, 4)");
     }
 
+    @Test
+    public void testExecuteUsingComplexJoinCriteria()
+    {
+        String query = "SELECT * FROM (VALUES 1) t(a) JOIN (VALUES 2) u(a) ON t.a + u.a < ?";
+        Session session = Session.builder(getSession())
+                .addPreparedStatement("my_query", query)
+                .build();
+        assertQuery(session,
+                "EXECUTE my_query USING 5",
+                "VALUES (1, 2)");
+    }
+
     @Test
     public void testExecuteUsingWithSubquery()
     {