diff --git a/fe/src/main/java/com/cloudera/impala/analysis/BinaryPredicate.java b/fe/src/main/java/com/cloudera/impala/analysis/BinaryPredicate.java index 62b259d47..e544748eb 100644 --- a/fe/src/main/java/com/cloudera/impala/analysis/BinaryPredicate.java +++ b/fe/src/main/java/com/cloudera/impala/analysis/BinaryPredicate.java @@ -15,6 +15,7 @@ package com.cloudera.impala.analysis; import java.util.ArrayList; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -185,11 +186,20 @@ public class BinaryPredicate extends Predicate { throw new AnalysisException("Multiple subqueries are not supported in binary " + "predicates: " + toSql()); } - if (contains(InPredicate.class) || contains(ExistsPredicate.class)) { - throw new AnalysisException("IN and/or EXISTS subquery predicates are not " + + if (contains(ExistsPredicate.class)) { + throw new AnalysisException("EXISTS subquery predicates are not " + "supported in binary predicates: " + toSql()); } + List inPredicates = Lists.newArrayList(); + collect(InPredicate.class, inPredicates); + for (InPredicate inPredicate: inPredicates) { + if (inPredicate.contains(Subquery.class)) { + throw new AnalysisException("IN subquery predicates are not supported in " + + "binary predicates: " + toSql()); + } + } + // Don't perform any casting for predicates with subqueries here. Any casting // required will be performed when the subquery is unnested. if (!contains(Subquery.class)) castForFunctionCall(true); diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java index f1fa5d53c..7c90ab547 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java @@ -574,6 +574,12 @@ public class AnalyzeExprsTest extends AnalyzerTest { // Test NULLs. AnalyzesOk("select * from functional.alltypes where " + "NULL in (NULL, NULL)"); + // Test IN in binary predicates + AnalyzesOk("select bool_col = (int_col in (1,2)), " + + "case when tinyint_col in (10, NULL) then tinyint_col else NULL end " + + "from functional.alltypestiny where int_col > (bool_col in (false)) " + + "and (int_col in (1,2)) = (select min(bool_col) from functional.alltypes) " + + "and (int_col in (3,4)) = (tinyint_col in (4,5))"); // Incompatible types. AnalysisError("select * from functional.alltypes where " + "string_col in (bool_col, double_col)", diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeSubqueriesTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeSubqueriesTest.java index 3f74a3af9..016a50a6c 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeSubqueriesTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeSubqueriesTest.java @@ -383,6 +383,13 @@ public class AnalyzeSubqueriesTest extends AnalyzerTest { "min(bigint_col) OVER (PARTITION BY bool_col) FROM " + "functional.alltypessmall t2 WHERE t1.id < t2.id"); + // IN subquery in binary predicate + AnalysisError("select * from functional.alltypestiny where " + + "(tinyint_col in (1,2)) = (bool_col in (select bool_col from " + + "functional.alltypes))", "IN subquery predicates are not supported " + + "in binary predicates: (tinyint_col IN (1, 2)) = (bool_col IN (SELECT " + + "bool_col FROM functional.alltypes))"); + // Column labels may conflict after the rewrite as an inline view AnalyzesOk("select int_col from functional.alltypestiny where " + "int_col in (select 1 as int_col from functional.alltypesagg)"); @@ -522,7 +529,7 @@ public class AnalyzeSubqueriesTest extends AnalyzerTest { // EXISTS subquery in a binary predicate AnalysisError("select * from functional.alltypes where " + "if(exists(select * from functional.alltypesagg), 1, 0) = 1", - "IN and/or EXISTS subquery predicates are not supported in binary predicates: " + + "EXISTS subquery predicates are not supported in binary predicates: " + "if(EXISTS (SELECT * FROM functional.alltypesagg), 1, 0) = 1"); // Correlated subquery with a LIMIT clause AnalyzesOk("select count(*) from functional.alltypes t where exists " + diff --git a/testdata/workloads/functional-query/queries/QueryTest/exprs.test b/testdata/workloads/functional-query/queries/QueryTest/exprs.test index c3d9de8f9..cf8a35195 100644 --- a/testdata/workloads/functional-query/queries/QueryTest/exprs.test +++ b/testdata/workloads/functional-query/queries/QueryTest/exprs.test @@ -917,6 +917,21 @@ WHERE month IN (cast(tinyint_col as decimal(34,0)), int_col + 1, 12345, float_co int,tinyint,int,float ==== ---- QUERY +# Regression test for IMPALA-1949 +select bool_col = (tinyint_col in (1,2)) from alltypestiny +---- RESULTS +false +false +false +false +false +false +false +false +---- TYPES +boolean +==== +---- QUERY # CASE expr - Basic functionality select date_string_col, count(*) from alltypesagg where case date_string_col when "01/06/10" then (true) else (false) end group by 1