This is an automated email from the ASF dual-hosted git repository.

mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new 3fce658c05 [CALCITE-6786] ANY/SOME operator yields multiple rows in 
correlated queries
3fce658c05 is described below

commit 3fce658c05aa88b44af8cbcfd0809a420896d62b
Author: Rafael Acevedo <[email protected]>
AuthorDate: Wed Jan 15 08:10:10 2025 -0300

    [CALCITE-6786] ANY/SOME operator yields multiple rows in correlated queries
---
 .../calcite/rel/rules/SubQueryRemoveRule.java      | 13 ++--
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 18 +++---
 core/src/test/resources/sql/some.iq                | 35 +++++++++++
 core/src/test/resources/sql/sub-query.iq           | 73 +++++++++++++---------
 4 files changed, 94 insertions(+), 45 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
index 88065c61d5..585d938d7f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
@@ -705,16 +705,15 @@ private static RexNode rewriteIn(RexSubQuery e, 
Set<CorrelationId> variablesSet,
         if (variablesSet.isEmpty()) {
           builder.aggregate(builder.groupKey(builder.field("cs")),
               builder.count(false, "c"));
-
-          // sorts input with desc order since we are interested
-          // only in the case when one of the values is true.
-          // When true value is absent then we are interested
-          // only in false value.
-          builder.sortLimit(0, 1,
-              ImmutableList.of(builder.desc(builder.field("cs"))));
         } else {
           builder.distinct();
         }
+        // sorts input with desc order since we are interested
+        // only in the case when one of the values is true.
+        // When true value is absent then we are interested
+        // only in false value.
+        builder.sortLimit(0, 1,
+            ImmutableList.of(builder.desc(builder.field("cs"))));
       }
       // clears expressionOperands and fields lists since
       // all expressions were used in the filter
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 038ca94a57..60c683ee50 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3662,18 +3662,20 @@ LogicalProject(EMPNO=[$0])
         LogicalCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
           LogicalProject(EMPNO=[$0], ENAME=[$1])
             LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
+          LogicalSort(sort0=[$0], dir0=[DESC], fetch=[1])
+            LogicalAggregate(group=[{0}])
+              LogicalProject(cs=[IS NOT NULL($0)])
+                LogicalFilter(condition=[OR(=(1, $0), IS NULL($0))])
+                  LogicalProject(DEPTNO=[$0])
+                    LogicalFilter(condition=[AND(=($cor0.ENAME, 
CAST($1):VARCHAR(20)), >($0, 10))])
+                      LogicalTableScan(table=[[CATALOG, SALES, DEPTNULLABLES]])
+        LogicalSort(sort0=[$0], dir0=[DESC], fetch=[1])
           LogicalAggregate(group=[{0}])
             LogicalProject(cs=[IS NOT NULL($0)])
-              LogicalFilter(condition=[OR(=(1, $0), IS NULL($0))])
+              LogicalFilter(condition=[OR(=(2, $0), IS NULL($0))])
                 LogicalProject(DEPTNO=[$0])
-                  LogicalFilter(condition=[AND(=($cor0.ENAME, 
CAST($1):VARCHAR(20)), >($0, 10))])
+                  LogicalFilter(condition=[AND(=($cor0.ENAME, 
CAST($1):VARCHAR(20)), <($0, 20))])
                     LogicalTableScan(table=[[CATALOG, SALES, DEPTNULLABLES]])
-        LogicalAggregate(group=[{0}])
-          LogicalProject(cs=[IS NOT NULL($0)])
-            LogicalFilter(condition=[OR(=(2, $0), IS NULL($0))])
-              LogicalProject(DEPTNO=[$0])
-                LogicalFilter(condition=[AND(=($cor0.ENAME, 
CAST($1):VARCHAR(20)), <($0, 20))])
-                  LogicalTableScan(table=[[CATALOG, SALES, DEPTNULLABLES]])
 ]]>
     </Resource>
   </TestCase>
diff --git a/core/src/test/resources/sql/some.iq 
b/core/src/test/resources/sql/some.iq
index 4cb8692a17..8b76390081 100644
--- a/core/src/test/resources/sql/some.iq
+++ b/core/src/test/resources/sql/some.iq
@@ -895,6 +895,41 @@ where sal > some (4000, 2000);
 
 !ok
 
+# CALCITE-6786: ANY/SOME operator yields multiple rows in correlated queries
+
+WITH tb as (select array(SELECT * FROM (VALUES (TRUE), (NULL)) as x(a)) as a)
+SELECT TRUE IN (SELECT b FROM UNNEST(a) AS x1(b)) AS test FROM tb;
++------+
+| TEST |
++------+
+| true |
++------+
+(1 row)
+
+!ok
+
+WITH tb as (select array(SELECT * FROM (VALUES (FALSE), (NULL)) as x(a)) as a)
+SELECT TRUE IN (SELECT b FROM UNNEST(a) AS x1(b)) AS test FROM tb;
++------+
+| TEST |
++------+
+|      |
++------+
+(1 row)
+
+!ok
+
+WITH tb as (select array(SELECT * FROM (VALUES (FALSE), (TRUE)) as x(a)) as a)
+SELECT TRUE IN (SELECT b FROM UNNEST(a) AS x1(b)) AS test FROM tb;
++------+
+| TEST |
++------+
+| true |
++------+
+(1 row)
+
+!ok
+
 select sal, sal > some (4000, 2000, null) from "scott".emp;
 +---------+--------+
 | SAL     | EXPR$1 |
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index 45e3e72a1b..1bee162a1e 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -1871,13 +1871,15 @@ select sal from "scott".emp e
 (0 rows)
 
 !ok
-EnumerableCalc(expr#0..4=[{inputs}], expr#5=[RAND()], 
expr#6=[CAST($t5):INTEGER NOT NULL], expr#7=[2], expr#8=[MOD($t6, $t7)], 
expr#9=[3], expr#10=[=($t8, $t9)], expr#11=[OR($t10, $t4)], SAL=[$t1], 
$condition=[$t11])
-  EnumerableMergeJoin(condition=[=($2, $3)], joinType=[left])
-    EnumerableSort(sort0=[$2], dir0=[ASC])
-      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], 
DEPTNO=[$t7])
-        EnumerableTableScan(table=[[scott, EMP]])
-    EnumerableCalc(expr#0..2=[{inputs}], expr#3=[false], DEPTNO=[$t0], 
$f1=[$t3])
-      EnumerableTableScan(table=[[scott, DEPT]])
+EnumerableCalc(expr#0..2=[{inputs}], expr#3=[RAND()], 
expr#4=[CAST($t3):INTEGER NOT NULL], expr#5=[2], expr#6=[MOD($t4, $t5)], 
expr#7=[3], expr#8=[=($t6, $t7)], expr#9=[OR($t8, $t2)], SAL=[$t0], 
$condition=[$t9])
+  EnumerableCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
+    EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+    EnumerableLimit(fetch=[1])
+      EnumerableSort(sort0=[$0], dir0=[DESC])
+        EnumerableAggregate(group=[{0}])
+          EnumerableCalc(expr#0..2=[{inputs}], expr#3=[false], expr#4=[$cor0], 
expr#5=[$t4.DEPTNO], expr#6=[=($t0, $t5)], cs=[$t3], $condition=[$t6])
+            EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
 # Test filter null IN nullable correlated
@@ -1958,13 +1960,15 @@ select sal from "scott".emp e
 (0 rows)
 
 !ok
-EnumerableCalc(expr#0..4=[{inputs}], expr#5=[NOT($t4)], expr#6=[IS NOT 
NULL($t4)], expr#7=[OR($t5, $t6)], expr#8=[IS NOT TRUE($t7)], SAL=[$t1], 
$condition=[$t8])
-  EnumerableMergeJoin(condition=[=($2, $3)], joinType=[left])
-    EnumerableSort(sort0=[$2], dir0=[ASC])
-      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], 
DEPTNO=[$t7])
-        EnumerableTableScan(table=[[scott, EMP]])
-    EnumerableCalc(expr#0..2=[{inputs}], expr#3=[false], DEPTNO=[$t0], 
$f1=[$t3])
-      EnumerableTableScan(table=[[scott, DEPT]])
+EnumerableCalc(expr#0..2=[{inputs}], expr#3=[NOT($t2)], expr#4=[IS NOT 
NULL($t2)], expr#5=[OR($t3, $t4)], expr#6=[IS NOT TRUE($t5)], SAL=[$t0], 
$condition=[$t6])
+  EnumerableCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
+    EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+    EnumerableLimit(fetch=[1])
+      EnumerableSort(sort0=[$0], dir0=[DESC])
+        EnumerableAggregate(group=[{0}])
+          EnumerableCalc(expr#0..2=[{inputs}], expr#3=[false], expr#4=[$cor0], 
expr#5=[$t4.DEPTNO], expr#6=[=($t5, $t0)], cs=[$t3], $condition=[$t6])
+            EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
 # Test filter null NOT IN literal correlated
@@ -2027,13 +2031,14 @@ select sal from "scott".emp e
 (11 rows)
 
 !ok
-EnumerableCalc(expr#0..4=[{inputs}], expr#5=[NOT($t4)], expr#6=[IS NOT 
NULL($t4)], expr#7=[OR($t5, $t6)], expr#8=[IS NOT TRUE($t7)], SAL=[$t1], 
$condition=[$t8])
-  EnumerableMergeJoin(condition=[=($2, $3)], joinType=[left])
-    EnumerableSort(sort0=[$2], dir0=[ASC])
-      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], 
DEPTNO=[$t7])
-        EnumerableTableScan(table=[[scott, EMP]])
-    EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[10], 
expr#5=[CAST($t0):INTEGER NOT NULL], expr#6=[=($t4, $t5)], DEPTNO1=[$t0], 
$f1=[$t3], $condition=[$t6])
-      EnumerableTableScan(table=[[scott, DEPT]])
+EnumerableCalc(expr#0..2=[{inputs}], expr#3=[NOT($t2)], expr#4=[IS NOT 
NULL($t2)], expr#5=[OR($t3, $t4)], expr#6=[IS NOT TRUE($t5)], SAL=[$t0], 
$condition=[$t6])
+  EnumerableCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
+    EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+    EnumerableLimit(fetch=[1])
+      EnumerableSort(sort0=[$0], dir0=[DESC])
+        EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[$cor0], 
expr#5=[$t4.DEPTNO], expr#6=[=($t5, $t0)], expr#7=[10], 
expr#8=[CAST($t0):INTEGER NOT NULL], expr#9=[=($t7, $t8)], expr#10=[AND($t6, 
$t9)], cs=[$t3], $condition=[$t10])
+          EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
 # Test filter literal NOT IN nullable correlated
@@ -2057,13 +2062,14 @@ select sal from "scott".emp e
 (11 rows)
 
 !ok
-EnumerableCalc(expr#0..4=[{inputs}], expr#5=[NOT($t3)], expr#6=[IS NOT 
NULL($t3)], expr#7=[OR($t5, $t6)], expr#8=[IS NOT TRUE($t7)], SAL=[$t1], 
$condition=[$t8])
-  EnumerableMergeJoin(condition=[=($2, $4)], joinType=[left])
-    EnumerableSort(sort0=[$2], dir0=[ASC])
-      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], 
DEPTNO=[$t7])
-        EnumerableTableScan(table=[[scott, EMP]])
-    EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], 
expr#4=[CAST($t0):INTEGER], expr#5=[10], expr#6=[=($t4, $t5)], cs=[$t3], 
DEPTNO=[$t0], $condition=[$t6])
-      EnumerableTableScan(table=[[scott, DEPT]])
+EnumerableCalc(expr#0..2=[{inputs}], expr#3=[NOT($t2)], expr#4=[IS NOT 
NULL($t2)], expr#5=[OR($t3, $t4)], expr#6=[IS NOT TRUE($t5)], SAL=[$t0], 
$condition=[$t6])
+  EnumerableCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
+    EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+    EnumerableLimit(fetch=[1])
+      EnumerableSort(sort0=[$0], dir0=[DESC])
+        EnumerableCalc(expr#0..2=[{inputs}], expr#3=[IS NOT NULL($t0)], 
expr#4=[$cor0], expr#5=[$t4.DEPTNO], expr#6=[=($t5, $t0)], 
expr#7=[CAST($t0):INTEGER], expr#8=[10], expr#9=[=($t7, $t8)], 
expr#10=[AND($t6, $t9)], cs=[$t3], $condition=[$t10])
+          EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
 # Test filter null IN required is unknown correlated
@@ -2090,8 +2096,15 @@ select sal from "scott".emp e
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5])
-  EnumerableTableScan(table=[[scott, EMP]])
+EnumerableCalc(expr#0..2=[{inputs}], SAL=[$t0])
+  EnumerableCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{1}])
+    EnumerableCalc(expr#0..7=[{inputs}], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+    EnumerableLimit(fetch=[1])
+      EnumerableSort(sort0=[$0], dir0=[DESC])
+        EnumerableAggregate(group=[{0}])
+          EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[$cor0], 
expr#5=[$t4.DEPTNO], expr#6=[=($t5, $t0)], cs=[$t3], $condition=[$t6])
+            EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
 

Reply via email to