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

xiong 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 93f914c505 [CALCITE-6481] Optimize 'VALUES...UNION...VALUES' to a 
single 'VALUES' the IN-list contains CAST and it is converted to VALUES
93f914c505 is described below

commit 93f914c50560bd822e7153aafdbd5cbbf771dc3b
Author: Xiong Duan <[email protected]>
AuthorDate: Sat Aug 10 09:04:42 2024 +0800

    [CALCITE-6481] Optimize 'VALUES...UNION...VALUES' to a single 'VALUES' the 
IN-list contains CAST and it is converted to VALUES
---
 .../org/apache/calcite/rel/rules/CoreRules.java    |   5 +
 .../calcite/rel/rules/UnionToValuesRule.java       | 145 +++++++++
 .../org/apache/calcite/rel/type/RelDataType.java   |  27 ++
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java |  22 ++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 150 +++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 351 +++++++++++++++++++++
 .../org/apache/calcite/test/RelOptFixture.java     |   4 +
 7 files changed, 704 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java 
b/core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java
index aca746905d..69766761fb 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java
@@ -771,6 +771,11 @@ public class CoreRules {
   public static final UnionToDistinctRule UNION_TO_DISTINCT =
       UnionToDistinctRule.Config.DEFAULT.toRule();
 
+  /** Rule that translates a {@link Union} to {@link Values}
+   * if it's all input are {@link Values}. */
+  public static final UnionToValuesRule UNION_TO_VALUES =
+      UnionToValuesRule.Config.DEFAULT.toRule();
+
   /** Rule that rewrite {@link Sample} which is bernoulli to the {@link 
Filter}. */
   public static final SampleToFilterRule SAMPLE_TO_FILTER =
       SampleToFilterRule.Config.DEFAULT.toRule();
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/UnionToValuesRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/UnionToValuesRule.java
new file mode 100644
index 0000000000..dc16e591d4
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionToValuesRule.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.rel.rules;
+
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelRule;
+import org.apache.calcite.plan.hep.HepRelVertex;
+import org.apache.calcite.plan.volcano.RelSubset;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Union;
+import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexLiteral;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import org.immutables.value.Value;
+
+import java.util.List;
+
+/**
+ * Planner rule that converts
+ * {@link org.apache.calcite.rel.core.Union} with
+ * inputs only containing {@link org.apache.calcite.rel.core.Values}
+ * into an {@link org.apache.calcite.rel.core.Values}.
+ *
+ * <p>For example,
+ *
+ * <blockquote><pre>{@code
+ * Union(all=[true])
+ *     Values(tuples=[[{ 3, null }]])
+ *     Values(tuples=[[{ 7369, null }]])
+ *     Values(tuples=[[{ 1, 2 }]])
+ * }</pre></blockquote>
+ *
+ * <p>becomes
+ *
+ * <blockquote><pre>{@code
+ * Values(tuples=[[{ 3, null }, { 7369, null }, { 1, 2 }]])
+ * }</pre></blockquote>
+ *
+ * <p>If (<code>all</code> = <code>false</code>),
+ * {@link org.apache.calcite.rel.core.Values} value will be set list.
+ *
+ */
[email protected]
+public class UnionToValuesRule extends RelRule<UnionToValuesRule.Config>
+    implements TransformationRule {
+
+  /**
+   * Creates a UnionToValuesRule.
+   */
+  protected UnionToValuesRule(UnionToValuesRule.Config config) {
+    super(config);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  @Override public void onMatch(RelOptRuleCall call) {
+    Union union = call.rel(0);
+    List<RelNode> relNodeList = union.getInputs();
+    final RelDataType relDataType = union.getRowType();
+    if (!relNodeList.stream().allMatch(relNode ->
+        isValuesWithSpecifiedDataType(relNode, relDataType))) {
+      return;
+    }
+    ImmutableCollection.Builder<ImmutableList<RexLiteral>> tupleList =
+        getImmutableListBuilder(union.all, relNodeList);
+    Values values =
+        (Values) call.builder().values(tupleList.build(), 
union.getRowType()).build();
+    call.transformTo(values);
+  }
+
+  private static ImmutableCollection.Builder<ImmutableList<RexLiteral>> 
getImmutableListBuilder(
+      Boolean all, List<RelNode> relNodeList) {
+    ImmutableCollection.Builder<ImmutableList<RexLiteral>> tupleList;
+    if (all) {
+      tupleList = ImmutableList.builder();
+    } else {
+      tupleList = ImmutableSet.builder();
+    }
+    for (RelNode relNode : relNodeList) {
+      Values values = (Values) relNode.stripped();
+      ImmutableList<ImmutableList<RexLiteral>> immutableLists = 
values.getTuples();
+      for (ImmutableList<RexLiteral> immutableList : immutableLists) {
+        ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
+        for (RexLiteral rexLiteral : immutableList) {
+          tuple.add(rexLiteral);
+        }
+        tupleList.add(tuple.build());
+      }
+    }
+    return tupleList;
+  }
+
+  private static boolean isValuesWithSpecifiedDataType(RelNode node, 
RelDataType relDataType) {
+    if (node instanceof Values
+        && relDataType.equalsSansFieldNamesAndNullability(node.getRowType())) {
+      return true;
+    }
+    if (node instanceof HepRelVertex || node instanceof RelSubset) {
+      return isValuesWithSpecifiedDataType(node.stripped(), relDataType);
+    }
+    return false;
+  }
+
+  /**
+   * Rule configuration.
+   */
+  @Value.Immutable
+  public interface Config extends RelRule.Config {
+    Config DEFAULT = ImmutableUnionToValuesRule.Config.of()
+        .withDescription("UnionToValuesRule")
+        .withOperandFor(Union.class);
+
+    @Override default UnionToValuesRule toRule() {
+      return new UnionToValuesRule(this);
+    }
+
+    /**
+     * Defines an operand tree for the given classes.
+     */
+    default UnionToValuesRule.Config withOperandFor(Class<? extends Union> 
unionClass) {
+      return withOperandSupplier(b0 ->
+          b0.operand(unionClass).anyInputs())
+          .as(UnionToValuesRule.Config.class);
+    }
+  }
+}
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java 
b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
index bbd2bf5536..e1fa9fcfd7 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
@@ -286,6 +286,33 @@ public interface RelDataType {
     }
   }
 
+  /**
+   * Same as {@link #equalsSansFieldNames}, but ignore nullability also.
+   */
+  default boolean equalsSansFieldNamesAndNullability(@Nullable RelDataType 
that) {
+    if (this == that) {
+      return true;
+    }
+    if (that == null || getClass() != that.getClass()) {
+      return false;
+    }
+    if (isStruct()) {
+      List<RelDataTypeField> l1 = this.getFieldList();
+      List<RelDataTypeField> l2 = that.getFieldList();
+      if (l1.size() != l2.size()) {
+        return false;
+      }
+      for (int i = 0; i < l1.size(); i++) {
+        if (!SqlTypeUtil.equalSansNullability(l1.get(i).getType(), 
l2.get(i).getType())) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return equals(that);
+    }
+  }
+
   /** Returns whether this type is a measure.
    *
    * @see SqlTypeUtil#fromMeasure(RelDataTypeFactory, RelDataType)
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index bf80bd8fee..2542f1a3e9 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -491,6 +491,28 @@ class RelToSqlConverterTest {
     relFn(relFn).ok(expected);
   }
 
+  @Test void testSelectWhereIn2() {
+    final Function<RelBuilder, RelNode> relFn = b -> b
+        .scan("EMP")
+        .filter(b.in(b.field("COMM"), b.cast(b.literal(1.1), 
SqlTypeName.INTEGER), b.literal(2)))
+        .build();
+    final String expected = "SELECT *\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "WHERE \"COMM\" IN (1, 2)";
+    relFn(relFn).ok(expected);
+  }
+
+  @Test void testSelectWhereIn3() {
+    final Function<RelBuilder, RelNode> relFn = b -> b
+        .scan("EMP")
+        .filter(b.in(b.field("COMM"), b.cast(b.literal(1.1), 
SqlTypeName.INTEGER), b.literal(2)))
+        .build();
+    final String expected = "SELECT *\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "WHERE \"COMM\" IN (1, 2)";
+    relFn(relFn).ok(expected);
+  }
+
   @Test void testUsesSubqueryWhenSortingByIdThenOrdinal() {
     final Function<RelBuilder, RelNode> relFn = b -> b
         .scan("EMP")
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index f9eb6dad23..8b350a2051 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -3093,6 +3093,156 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6481";>[CALCITE-6481]
+   * Optimize 'VALUES...UNION...VALUES' to a single 'VALUES' the IN-list 
contains CAST
+   * and it is converted to VALUES</a>. */
+  @Test void testUnionToValuesByInList() {
+    final String sql = ""
+        + "\n"
+        + "with t1(a, y) as (select * from (values (1, 2), (3, null), (7369, 
null), (7499, 30), (null, 20), (null, 5)) as t1)\n"
+        + "select *\n"
+        + "from t1\n"
+        + "where (t1.a, t1.y) in ((1, 2), (3, null), (7369, null), (7499, 30), 
(null, 20), (null, 5))";
+    sql(sql)
+        .withRule(CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByInList2() {
+    final String sql = ""
+        + "\n"
+        + "with t1(a, y) as (select * from (values (1, 2), (3, null), (7369, 
null), (7499, 30), (null, 20), (null, 5)) as t1)\n"
+        + "select *\n"
+        + "from t1\n"
+        + "where (t1.a, t1.y) in ((cast(1.1 as int), 2), (3, null), (7369, 
null), (7499, 30), (null, cast(20.2 as int)), (null, 5))";
+    sql(sql)
+        .withRule(CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByInList3() {
+    final String sql = "select * from dept where deptno in (12, 34, cast(56.4 
as int))";
+    sql(sql)
+        .withRule(CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByInList4() {
+    final String sql = "select * from dept where deptno in (12, 34, cast(56.4 
as double))";
+    sql(sql)
+        .withRule(CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByInList5() {
+    final String sql = "select deptno in (12, 34, cast(56.4 as double)) from 
dept";
+    sql(sql)
+        .withRule(CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnion() {
+    final String sql = "select *\n"
+        + "from (values (1, 'a'), (2, 'b')) as t(x, y)\n"
+        + "union\n"
+        + "select *\n"
+        + "from (values (1, 'a'), (2, 'b'), (1, 'b'), (2, 'c'), (2, 'c')) as 
t(x, y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnion2() {
+    final String sql = "select *\n"
+        + "from (values ('a'), ('b')) as t(x)\n"
+        + "union\n"
+        + "select *\n"
+        + "from (values ('a'), ('b'), ('b'), ('c'), ('c')) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnion3() {
+    final String sql = "select *\n"
+        + "from (values (5.0)) as t(x)\n"
+        + "union\n"
+        + "select *\n"
+        + "from (values (5)) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnion4() {
+    final String sql = "select *\n"
+        + "from (values (cast(5.0 as int))) as t(x)\n"
+        + "union\n"
+        + "select *\n"
+        + "from (values (5)) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnionAll() {
+    final String sql = "select *\n"
+        + "from (values (1, 'a'), (2, 'b')) as t(x, y)\n"
+        + "union all\n"
+        + "select *\n"
+        + "from (values (1, 'a'), (2, 'b'), (1, 'b'), (2, 'c'), (2, 'c')) as 
t(x, y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnionAll2() {
+    final String sql = "select *\n"
+        + "from (values ('a'), ('b')) as t(x)\n"
+        + "union all\n"
+        + "select *\n"
+        + "from (values ('a'), ('b'), ('b'), ('c'), ('c')) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnionAll3() {
+    final String sql = "select *\n"
+        + "from (values (5.0)) as t(x)\n"
+        + "union all\n"
+        + "select *\n"
+        + "from (values (5)) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
+  @Test void testUnionToValuesByUnionAll4() {
+    final String sql = "select *\n"
+        + "from (values (cast(5.0 as int))) as t(x)\n"
+        + "union all\n"
+        + "select *\n"
+        + "from (values (5)) as t(y)";
+    sql(sql)
+        .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES)
+        .withInSubQueryThreshold(0)
+        .check();
+  }
+
   @Test void testMinusMergeRule() {
     final String sql = "select * from (\n"
         + "select * from (\n"
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 a849461992..3135c5e958 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -16334,6 +16334,357 @@ LogicalUnion(all=[false])
     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
   LogicalProject(DEPTNO=[$0], NAME=[$1])
     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByInList">
+    <Resource name="sql">
+      <![CDATA[
+with t1(a, y) as (select * from (values (1, 2), (3, null), (7369, null), 
(7499, 30), (null, 20), (null, 5)) as t1)
+select *
+from t1
+where (t1.a, t1.y) in ((1, 2), (3, null), (7369, null), (7499, 30), (null, 
20), (null, 5))]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(A=[$0], Y=[$1])
+  LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
+    LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
+      LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 
}, { null, 20 }, { null, 5 }]])
+    LogicalAggregate(group=[{0, 1}])
+      LogicalUnion(all=[true])
+        LogicalValues(tuples=[[{ 3, null }]])
+        LogicalValues(tuples=[[{ 7369, null }]])
+        LogicalValues(tuples=[[{ null, 20 }]])
+        LogicalValues(tuples=[[{ null, 5 }]])
+        LogicalValues(tuples=[[{ 1, 2 }, { 7499, 30 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(A=[$0], Y=[$1])
+  LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
+    LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
+      LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 
}, { null, 20 }, { null, 5 }]])
+    LogicalAggregate(group=[{0, 1}])
+      LogicalValues(tuples=[[{ 3, null }, { 7369, null }, { null, 20 }, { 
null, 5 }, { 1, 2 }, { 7499, 30 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByInList2">
+    <Resource name="sql">
+      <![CDATA[
+with t1(a, y) as (select * from (values (1, 2), (3, null), (7369, null), 
(7499, 30), (null, 20), (null, 5)) as t1)
+select *
+from t1
+where (t1.a, t1.y) in ((cast(1.1 as int), 2), (3, null), (7369, null), (7499, 
30), (null, cast(20.2 as int)), (null, 5))]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(A=[$0], Y=[$1])
+  LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
+    LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
+      LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 
}, { null, 20 }, { null, 5 }]])
+    LogicalAggregate(group=[{0, 1}])
+      LogicalUnion(all=[true])
+        LogicalValues(tuples=[[{ 1, 2 }]])
+        LogicalValues(tuples=[[{ 3, null }]])
+        LogicalValues(tuples=[[{ 7369, null }]])
+        LogicalValues(tuples=[[{ null, 20 }]])
+        LogicalValues(tuples=[[{ null, 5 }]])
+        LogicalValues(tuples=[[{ 7499, 30 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(A=[$0], Y=[$1])
+  LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
+    LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
+      LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 
}, { null, 20 }, { null, 5 }]])
+    LogicalAggregate(group=[{0, 1}])
+      LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { null, 20 
}, { null, 5 }, { 7499, 30 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByInList3">
+    <Resource name="sql">
+      <![CDATA[select * from dept where deptno in (12, 34, cast(56.4 as 
int))]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+  LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalUnion(all=[true])
+        LogicalValues(tuples=[[{ 56 }]])
+        LogicalValues(tuples=[[{ 12 }, { 34 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+  LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalValues(tuples=[[{ 56 }, { 12 }, { 34 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByInList4">
+    <Resource name="sql">
+      <![CDATA[select * from dept where deptno in (12, 34, cast(56.4 as 
double))]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+  LogicalJoin(condition=[=($2, $3)], joinType=[inner])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[CAST($0):DOUBLE NOT NULL])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalUnion(all=[true])
+        LogicalValues(tuples=[[{ 12 }]])
+        LogicalValues(tuples=[[{ 34 }]])
+        LogicalValues(tuples=[[{ 56.4 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+  LogicalJoin(condition=[=($2, $3)], joinType=[inner])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[CAST($0):DOUBLE NOT NULL])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalValues(tuples=[[{ 12 }, { 34 }, { 56.4 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByInList5">
+    <Resource name="sql">
+      <![CDATA[select deptno in (12, 34, cast(56.4 as double)) from dept]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[CAST(OR(AND(IS NOT NULL($6), <>($2, 0)), AND(<($3, $2), 
null, <>($2, 0), IS NULL($6)))):BOOLEAN NOT NULL])
+  LogicalJoin(condition=[=($4, $5)], joinType=[left])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$2], $f1=[$3], 
DEPTNO0=[CAST($0):DOUBLE NOT NULL])
+      LogicalJoin(condition=[true], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0)])
+          LogicalProject(EXPR$0=[$0], $f1=[true])
+            LogicalUnion(all=[true])
+              LogicalValues(tuples=[[{ 12 }]])
+              LogicalValues(tuples=[[{ 34 }]])
+              LogicalValues(tuples=[[{ 56.4 }]])
+    LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+      LogicalProject(EXPR$0=[$0], $f1=[true])
+        LogicalUnion(all=[true])
+          LogicalValues(tuples=[[{ 12 }]])
+          LogicalValues(tuples=[[{ 34 }]])
+          LogicalValues(tuples=[[{ 56.4 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[CAST(OR(AND(IS NOT NULL($6), <>($2, 0)), AND(<($3, $2), 
null, <>($2, 0), IS NULL($6)))):BOOLEAN NOT NULL])
+  LogicalJoin(condition=[=($4, $5)], joinType=[left])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$2], $f1=[$3], 
DEPTNO0=[CAST($0):DOUBLE NOT NULL])
+      LogicalJoin(condition=[true], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0)])
+          LogicalProject(EXPR$0=[$0], $f1=[true])
+            LogicalValues(tuples=[[{ 12 }, { 34 }, { 56.4 }]])
+    LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+      LogicalProject(EXPR$0=[$0], $f1=[true])
+        LogicalValues(tuples=[[{ 12 }, { 34 }, { 56.4 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnion">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (1, 'a'), (2, 'b')) as t(x, y)
+union
+select *
+from (values (1, 'a'), (2, 'b'), (1, 'b'), (2, 'c'), (2, 'c')) as t(x, y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[false])
+  LogicalProject(X=[$0], Y=[$1])
+    LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }]])
+  LogicalProject(X=[$0], Y=[$1])
+    LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }, { 1, 'b' }, { 2, 'c' }, { 
2, 'c' }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }, { 1, 'b' }, { 2, 'c' }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnion2">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values ('a'), ('b')) as t(x)
+union
+select *
+from (values ('a'), ('b'), ('b'), ('c'), ('c')) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[false])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 'a' }, { 'b' }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 'a' }, { 'b' }, { 'b' }, { 'c' }, { 'c' }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 'a' }, { 'b' }, { 'c' }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnion3">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (5.0)) as t(x)
+union
+select *
+from (values (5)) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[false])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 5.0 }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalUnion(all=[false])
+  LogicalValues(tuples=[[{ 5.0 }]])
+  LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnion4">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (cast(5.0 as int))) as t(x)
+union
+select *
+from (values (5)) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[false])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnionAll">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (1, 'a'), (2, 'b')) as t(x, y)
+union all
+select *
+from (values (1, 'a'), (2, 'b'), (1, 'b'), (2, 'c'), (2, 'c')) as t(x, y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[true])
+  LogicalProject(X=[$0], Y=[$1])
+    LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }]])
+  LogicalProject(X=[$0], Y=[$1])
+    LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }, { 1, 'b' }, { 2, 'c' }, { 
2, 'c' }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 1, 'a' }, { 2, 'b' }, { 1, 'a' }, { 2, 'b' }, { 1, 
'b' }, { 2, 'c' }, { 2, 'c' }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnionAll2">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values ('a'), ('b')) as t(x)
+union all
+select *
+from (values ('a'), ('b'), ('b'), ('c'), ('c')) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[true])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 'a' }, { 'b' }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 'a' }, { 'b' }, { 'b' }, { 'c' }, { 'c' }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 'a' }, { 'b' }, { 'a' }, { 'b' }, { 'b' }, { 'c' }, { 
'c' }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnionAll3">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (5.0)) as t(x)
+union all
+select *
+from (values (5)) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[true])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 5.0 }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalUnion(all=[true])
+  LogicalValues(tuples=[[{ 5.0 }]])
+  LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testUnionToValuesByUnionAll4">
+    <Resource name="sql">
+      <![CDATA[select *
+from (values (cast(5.0 as int))) as t(x)
+union all
+select *
+from (values (5)) as t(y)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalUnion(all=[true])
+  LogicalProject(X=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+  LogicalProject(Y=[$0])
+    LogicalValues(tuples=[[{ 5 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalValues(tuples=[[{ 5 }, { 5 }]])
 ]]>
     </Resource>
   </TestCase>
diff --git a/testkit/src/main/java/org/apache/calcite/test/RelOptFixture.java 
b/testkit/src/main/java/org/apache/calcite/test/RelOptFixture.java
index fbeda9527d..55e8ba283c 100644
--- a/testkit/src/main/java/org/apache/calcite/test/RelOptFixture.java
+++ b/testkit/src/main/java/org/apache/calcite/test/RelOptFixture.java
@@ -250,6 +250,10 @@ public class RelOptFixture {
     return withConfig(c -> c.withExpand(expand));
   }
 
+  public RelOptFixture withInSubQueryThreshold(final int inSubQueryThreshold) {
+    return withConfig(c -> c.withInSubQueryThreshold(inSubQueryThreshold));
+  }
+
   public RelOptFixture withConfig(
       UnaryOperator<SqlToRelConverter.Config> transform) {
     return withFactory(f -> f.withSqlToRelConfig(transform));

Reply via email to