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 052a5f8bf8 [CALCITE-6617] TypeCoercion is not applied correctly to 
comparisons
052a5f8bf8 is described below

commit 052a5f8bf8abc12d0804071982b36189067c4453
Author: Mihai Budiu <[email protected]>
AuthorDate: Tue Oct 8 20:15:53 2024 -0700

    [CALCITE-6617] TypeCoercion is not applied correctly to comparisons
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../calcite/adapter/arrow/ArrowAdapterTest.java    |   6 +-
 .../validate/implicit/AbstractTypeCoercion.java    |  64 +++++++++-
 .../sql/validate/implicit/TypeCoercion.java        |   3 +-
 .../sql/validate/implicit/TypeCoercionImpl.java    |  14 +--
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java |  38 +++---
 .../org/apache/calcite/test/RelOptRulesTest.java   |   9 ++
 .../org/apache/calcite/test/TCatalogReader.java    |   4 +-
 .../calcite/test/TypeCoercionConverterTest.java    |   6 +-
 .../org/apache/calcite/test/TypeCoercionTest.java  | 132 ++++++++++++++++-----
 .../org/apache/calcite/test/RelOptRulesTest.xml    |  28 ++++-
 .../calcite/test/TypeCoercionConverterTest.xml     |  12 +-
 core/src/test/resources/sql/agg.iq                 |   2 +-
 core/src/test/resources/sql/sub-query.iq           |  80 +++++++++----
 .../org/apache/calcite/test/DruidAdapter2IT.java   |  30 ++---
 .../org/apache/calcite/test/DruidAdapterIT.java    |  32 ++---
 15 files changed, 319 insertions(+), 141 deletions(-)

diff --git 
a/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java 
b/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
index 295ae6eae6..05bc053afc 100644
--- a/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
+++ b/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
@@ -374,7 +374,7 @@ class ArrowAdapterTest {
     String sql = "select * from arrowdata\n"
         + " where \"floatField\"=15.0";
     String plan = "PLAN=ArrowToEnumerableConverter\n"
-        + "  ArrowFilter(condition=[=(CAST($2):DOUBLE, 15.0E0)])\n"
+        + "  ArrowFilter(condition=[=($2, 15.0E0)])\n"
         + "    ArrowTableScan(table=[[ARROW, ARROWDATA]], fields=[[0, 1, 2, 
3]])\n\n";
     String result = "intField=15; stringField=15; floatField=15.0; 
longField=15\n";
 
@@ -666,7 +666,7 @@ class ArrowAdapterTest {
   @Test void testFilteredAgg() {
     String sql = "select SUM(SAL) FILTER (WHERE COMM > 400) as SALESSUM from 
EMP";
     String plan = "PLAN=EnumerableAggregate(group=[{}], SALESSUM=[SUM($0) 
FILTER $1])\n"
-        + "  EnumerableCalc(expr#0..7=[{inputs}], expr#8=[400], expr#9=[>($t6, 
$t8)], "
+        + "  EnumerableCalc(expr#0..7=[{inputs}], expr#8=[400:DECIMAL(19, 0)], 
expr#9=[>($t6, $t8)], "
         + "expr#10=[IS TRUE($t9)], SAL=[$t5], $f1=[$t10])\n"
         + "    ArrowToEnumerableConverter\n"
         + "      ArrowTableScan(table=[[ARROW, EMP]], fields=[[0, 1, 2, 3, 4, 
5, 6, 7]])\n\n";
@@ -684,7 +684,7 @@ class ArrowAdapterTest {
     String sql = "select SUM(SAL) FILTER (WHERE COMM > 400) as SALESSUM from 
EMP group by EMPNO";
     String plan = "PLAN=EnumerableCalc(expr#0..1=[{inputs}], SALESSUM=[$t1])\n"
         + "  EnumerableAggregate(group=[{0}], SALESSUM=[SUM($1) FILTER $2])\n"
-        + "    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[400], 
expr#9=[>($t6, $t8)], "
+        + "    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[400:DECIMAL(19, 
0)], expr#9=[>($t6, $t8)], "
         + "expr#10=[IS TRUE($t9)], EMPNO=[$t0], SAL=[$t5], $f2=[$t10])\n"
         + "      ArrowToEnumerableConverter\n"
         + "        ArrowTableScan(table=[[ARROW, EMP]], fields=[[0, 1, 2, 3, 
4, 5, 6, 7]])\n\n";
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
index 8475797717..e313a7bfd1 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
@@ -492,8 +492,8 @@ public abstract class AbstractTypeCoercion implements 
TypeCoercion {
   }
 
   /**
-   * Determines common type for a comparison operator when one operand is 
String type and the
-   * other is not. For date + timestamp operands, use timestamp as common type,
+   * Determines common type for a comparison operator.
+   * For date and timestamp operands, use timestamp as common type,
    * i.e. Timestamp(2017-01-01 00:00 ...) &gt; Date(2018) evaluates to be 
false.
    */
   @Override public @Nullable RelDataType commonTypeForBinaryComparison(
@@ -509,9 +509,11 @@ public abstract class AbstractTypeCoercion implements 
TypeCoercion {
       return null;
     }
 
-    // DATETIME + CHARACTER -> DATETIME
-    // REVIEW Danny 2019-09-23: There is some legacy redundant code in 
SqlToRelConverter
-    // that coerce Datetime and CHARACTER comparison.
+    if (SqlTypeUtil.sameNamedType(type1, type2)) {
+      return factory.leastRestrictive(ImmutableList.of(type1, type2));
+    }
+
+    // DATETIME < CHARACTER -> DATETIME
     if (SqlTypeUtil.isCharacter(type1) && SqlTypeUtil.isDatetime(type2)) {
       return factory.createTypeWithNullability(type2, type1.isNullable());
     }
@@ -520,7 +522,7 @@ public abstract class AbstractTypeCoercion implements 
TypeCoercion {
       return factory.createTypeWithNullability(type1, type2.isNullable());
     }
 
-    // DATE + TIMESTAMP -> TIMESTAMP
+    // DATE < TIMESTAMP -> TIMESTAMP
     if (SqlTypeUtil.isDate(type1) && SqlTypeUtil.isTimestamp(type2)) {
       return factory.createTypeWithNullability(type2, type1.isNullable());
     }
@@ -556,6 +558,19 @@ public abstract class AbstractTypeCoercion implements 
TypeCoercion {
       return null;
     }
 
+    if (SqlTypeUtil.isString(type1) && SqlTypeUtil.isString(type2)) {
+      // Return the string with the larger precision
+      if (type1.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED) {
+        return factory.createTypeWithNullability(type1, type2.isNullable());
+      } else if (type2.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED) {
+        return factory.createTypeWithNullability(type2, type1.isNullable());
+      } else if (type1.getPrecision() > type2.getPrecision()) {
+        return factory.createTypeWithNullability(type1, type2.isNullable());
+      } else {
+        return factory.createTypeWithNullability(type2, type1.isNullable());
+      }
+    }
+
     // 1 > '1' will be coerced to 1 > 1.
     if (SqlTypeUtil.isAtomic(type1) && SqlTypeUtil.isCharacter(type2)) {
       if (SqlTypeUtil.isTimestamp(type1)) {
@@ -581,6 +596,43 @@ public abstract class AbstractTypeCoercion implements 
TypeCoercion {
       }
     }
 
+    if (SqlTypeUtil.isApproximateNumeric(type1) && 
SqlTypeUtil.isApproximateNumeric(type2)) {
+      if (type1.getPrecision() > type2.getPrecision()) {
+        return factory.createTypeWithNullability(type1, type2.isNullable());
+      } else {
+        return factory.createTypeWithNullability(type2, type1.isNullable());
+      }
+    }
+
+    if (SqlTypeUtil.isApproximateNumeric(type1) && 
SqlTypeUtil.isExactNumeric(type2)) {
+      return factory.createTypeWithNullability(type1, type2.isNullable());
+    }
+
+    if (SqlTypeUtil.isApproximateNumeric(type2) && 
SqlTypeUtil.isExactNumeric(type1)) {
+      return factory.createTypeWithNullability(type2, type1.isNullable());
+    }
+
+    if (SqlTypeUtil.isExactNumeric(type1) && 
SqlTypeUtil.isExactNumeric(type2)) {
+      if (SqlTypeUtil.isDecimal(type1)) {
+        // Use max precision
+        RelDataType result =
+            factory.createSqlType(type1.getSqlTypeName(),
+                Math.max(type1.getPrecision(), type2.getPrecision()), 
type1.getScale());
+        return factory.createTypeWithNullability(result, type1.isNullable() || 
type2.isNullable());
+      } else if (SqlTypeUtil.isDecimal(type2)) {
+        // Use max precision
+        RelDataType result =
+            factory.createSqlType(type2.getSqlTypeName(),
+                Math.max(type1.getPrecision(), type2.getPrecision()), 
type2.getScale());
+        return factory.createTypeWithNullability(result, type1.isNullable() || 
type2.isNullable());
+      }
+      if (type1.getPrecision() > type2.getPrecision()) {
+        return factory.createTypeWithNullability(type1, type2.isNullable());
+      } else {
+        return factory.createTypeWithNullability(type2, type1.isNullable());
+      }
+    }
+
     return null;
   }
 
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java
index e3a6176486..2a343cca1b 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java
@@ -93,8 +93,7 @@ public interface TypeCoercion {
       @Nullable RelDataType type1, @Nullable RelDataType type2);
 
   /**
-   * Determines common type for a comparison operator whose operands are STRING
-   * type and the other (non STRING) type.
+   * Determines common type for a comparison operator.
    */
   @Nullable RelDataType commonTypeForBinaryComparison(
       @Nullable RelDataType type1, @Nullable RelDataType type2);
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
index 73de170e5c..711c8d22dc 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
@@ -48,7 +48,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import java.math.BigDecimal;
 import java.util.AbstractList;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -291,18 +290,9 @@ public class TypeCoercionImpl extends AbstractTypeCoercion 
{
       return null;
     }
 
-    RelDataType commonType;
-    if (SqlTypeUtil.sameNamedType(type1, type2)) {
-      commonType = factory.leastRestrictive(Arrays.asList(type1, type2));
-    } else {
-      commonType = commonTypeForBinaryComparison(type1, type2);
-    }
+    RelDataType commonType = commonTypeForBinaryComparison(type1, type2);
     for (int i = 2; i < dataTypes.size() && commonType != null; i++) {
-      if (SqlTypeUtil.sameNamedType(commonType, dataTypes.get(i))) {
-        commonType = factory.leastRestrictive(Arrays.asList(commonType, 
dataTypes.get(i)));
-      } else {
-        commonType = commonTypeForBinaryComparison(commonType, 
dataTypes.get(i));
-      }
+      commonType = commonTypeForBinaryComparison(commonType, dataTypes.get(i));
     }
     return commonType;
   }
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 c52851e14e..fd72b876b0 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
@@ -319,33 +319,33 @@ class RelToSqlConverterTest {
         + "where \"product_id\" > 0\n"
         + "group by \"product_id\"";
     final String expectedDefault = "SELECT"
-        + " SUM(\"shelf_width\") FILTER (WHERE \"net_weight\" > 0 IS TRUE),"
+        + " SUM(\"shelf_width\") FILTER (WHERE \"net_weight\" > 0E0 IS TRUE),"
         + " SUM(\"shelf_width\")\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "WHERE \"product_id\" > 0\n"
         + "GROUP BY \"product_id\"";
     final String expectedBigQuery = "SELECT"
-        + " SUM(CASE WHEN net_weight > 0 IS TRUE"
+        + " SUM(CASE WHEN net_weight > 0E0 IS TRUE"
         + " THEN shelf_width ELSE NULL END), "
         + "SUM(shelf_width)\n"
         + "FROM foodmart.product\n"
         + "WHERE product_id > 0\n"
         + "GROUP BY product_id";
     final String expectedFirebolt = "SELECT"
-        + " SUM(CASE WHEN \"net_weight\" > 0 IS TRUE"
+        + " SUM(CASE WHEN \"net_weight\" > 0E0 IS TRUE"
         + " THEN \"shelf_width\" ELSE NULL END), "
         + "SUM(\"shelf_width\")\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "WHERE \"product_id\" > 0\n"
         + "GROUP BY \"product_id\"";
     final String expectedMysql = "SELECT"
-        + " SUM(CASE WHEN `net_weight` > 0 IS TRUE"
+        + " SUM(CASE WHEN `net_weight` > 0E0 IS TRUE"
         + " THEN `shelf_width` ELSE NULL END), SUM(`shelf_width`)\n"
         + "FROM `foodmart`.`product`\n"
         + "WHERE `product_id` > 0\n"
         + "GROUP BY `product_id`";
     final String expectedStarRocks = "SELECT"
-        + " SUM(CASE WHEN `net_weight` > 0 IS TRUE"
+        + " SUM(CASE WHEN `net_weight` > 0E0 IS TRUE"
         + " THEN `shelf_width` ELSE NULL END), SUM(`shelf_width`)\n"
         + "FROM `foodmart`.`product`\n"
         + "WHERE `product_id` > 0\n"
@@ -539,7 +539,7 @@ class RelToSqlConverterTest {
     final String expected = "SELECT *\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "WHERE (\"product_id\" = 10 OR \"product_id\" <= 5) "
-        + "AND (80 >= \"shelf_width\" OR \"shelf_width\" > 30)";
+        + "AND (CAST(80 AS DOUBLE) >= \"shelf_width\" OR \"shelf_width\" > 
CAST(30 AS DOUBLE))";
     sql(query).ok(expected);
   }
 
@@ -2097,26 +2097,26 @@ class RelToSqlConverterTest {
         + "  sum(\"gross_weight\") as \"" + alias + "\"\n"
         + "from \"product\"\n"
         + "group by \"product_id\"\n"
-        + "having sum(\"product\".\"gross_weight\") < 200";
+        + "having sum(\"product\".\"gross_weight\") < 2.000E2";
     // PostgreSQL has isHavingAlias=false, case-sensitive=true
     final String expectedPostgresql = "SELECT \"product_id\" + 1,"
         + " SUM(\"gross_weight\") AS \"" + alias + "\"\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "GROUP BY \"product_id\"\n"
-        + "HAVING SUM(\"gross_weight\") < 200";
+        + "HAVING SUM(\"gross_weight\") < 2.000E2";
     // MySQL has isHavingAlias=true, case-sensitive=true
     final String expectedMysql = "SELECT `product_id` + 1, `" + alias + "`\n"
         + "FROM (SELECT `product_id`, SUM(`gross_weight`) AS `" + alias + "`\n"
         + "FROM `foodmart`.`product`\n"
         + "GROUP BY `product_id`\n"
-        + "HAVING `" + alias + "` < 200) AS `t1`";
+        + "HAVING `" + alias + "` < 2.000E2) AS `t1`";
     // BigQuery has isHavingAlias=true, case-sensitive=false
     final String expectedBigQuery = upperAlias
         ? "SELECT product_id + 1, GROSS_WEIGHT\n"
             + "FROM (SELECT product_id, SUM(gross_weight) AS GROSS_WEIGHT\n"
             + "FROM foodmart.product\n"
             + "GROUP BY product_id\n"
-            + "HAVING GROSS_WEIGHT < 200) AS t1"
+            + "HAVING GROSS_WEIGHT < 2.000E2) AS t1"
         // Before [CALCITE-3896] was fixed, we got
         // "HAVING SUM(gross_weight) < 200) AS t1"
         // which on BigQuery gives you an error about aggregating aggregates
@@ -2124,7 +2124,7 @@ class RelToSqlConverterTest {
             + "FROM (SELECT product_id, SUM(gross_weight) AS gross_weight\n"
             + "FROM foodmart.product\n"
             + "GROUP BY product_id\n"
-            + "HAVING gross_weight < 200) AS t1";
+            + "HAVING gross_weight < 2.000E2) AS t1";
     sql(query)
         .withBigQuery().ok(expectedBigQuery)
         .withPostgresql().ok(expectedPostgresql)
@@ -2144,11 +2144,11 @@ class RelToSqlConverterTest {
     final String expected = "SELECT \"product_id\"\n"
         + "FROM (SELECT \"product_id\", AVG(\"gross_weight\") AS \"AGW\"\n"
         + "FROM \"foodmart\".\"product\"\n"
-        + "WHERE \"net_weight\" < 100\n"
+        + "WHERE \"net_weight\" < CAST(100 AS DOUBLE)\n"
         + "GROUP BY \"product_id\"\n"
-        + "HAVING AVG(\"gross_weight\") > 50) AS \"t2\"\n"
+        + "HAVING AVG(\"gross_weight\") > CAST(50 AS DOUBLE)) AS \"t2\"\n"
         + "GROUP BY \"product_id\"\n"
-        + "HAVING AVG(\"AGW\") > 60";
+        + "HAVING AVG(\"AGW\") > 6.00E1";
     sql(query).ok(expected);
   }
 
@@ -5366,21 +5366,21 @@ class RelToSqlConverterTest {
         + "UNION ALL\n"
         + "SELECT NULL) END AS `$f0`\n"
         + "FROM `foodmart`.`product`) AS `t0` ON TRUE\n"
-        + "WHERE `product`.`net_weight` > `t0`.`$f0`";
+        + "WHERE `product`.`net_weight` > CAST(`t0`.`$f0` AS DOUBLE)";
     final String expectedPostgresql = "SELECT \"product\".\"product_class_id\" 
AS \"C\"\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "LEFT JOIN (SELECT CASE COUNT(*) WHEN 0 THEN NULL WHEN 1 THEN 
MIN(\"product_class_id\") ELSE (SELECT CAST(NULL AS INTEGER)\n"
         + "UNION ALL\n"
         + "SELECT CAST(NULL AS INTEGER)) END AS \"$f0\"\n"
         + "FROM \"foodmart\".\"product\") AS \"t0\" ON TRUE\n"
-        + "WHERE \"product\".\"net_weight\" > \"t0\".\"$f0\"";
+        + "WHERE \"product\".\"net_weight\" > CAST(\"t0\".\"$f0\" AS DOUBLE 
PRECISION)";
     final String expectedHsqldb = "SELECT product.product_class_id AS C\n"
         + "FROM foodmart.product\n"
         + "LEFT JOIN (SELECT CASE COUNT(*) WHEN 0 THEN NULL WHEN 1 THEN 
MIN(product_class_id) ELSE ((VALUES 0E0)\n"
         + "UNION ALL\n"
         + "(VALUES 0E0)) END AS $f0\n"
         + "FROM foodmart.product) AS t0 ON TRUE\n"
-        + "WHERE product.net_weight > t0.$f0";
+        + "WHERE product.net_weight > CAST(t0.$f0 AS DOUBLE)";
     sql(query)
         .withConfig(c -> c.withExpand(true))
         .withMysql().ok(expectedMysql)
@@ -6905,7 +6905,7 @@ class RelToSqlConverterTest {
         + "within group (order by \"net_weight\" desc) filter (where 
\"net_weight\" > 0)"
         + "from \"product\" group by \"product_class_id\"";
     final String expected = "SELECT \"product_class_id\", 
COLLECT(\"net_weight\") "
-        + "FILTER (WHERE \"net_weight\" > 0 IS TRUE) "
+        + "FILTER (WHERE \"net_weight\" > 0E0 IS TRUE) "
         + "WITHIN GROUP (ORDER BY \"net_weight\" DESC)\n"
         + "FROM \"foodmart\".\"product\"\n"
         + "GROUP BY \"product_class_id\"";
@@ -8241,7 +8241,7 @@ class RelToSqlConverterTest {
     final String expected = "SELECT *\n"
         + "FROM TABLE(DEDUP(CURSOR ((SELECT \"product_id\", \"product_name\"\n"
         + "FROM \"foodmart\".\"product\"\n"
-        + "WHERE \"net_weight\" > 100 AND \"product_name\" = 'Hello World')), "
+        + "WHERE \"net_weight\" > CAST(100 AS DOUBLE) AND \"product_name\" = 
'Hello World')), "
         + "CURSOR ((SELECT \"employee_id\", \"full_name\"\n"
         + "FROM \"foodmart\".\"employee\"\n"
         + "GROUP BY \"employee_id\", \"full_name\")), 'NAME'))";
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 380b543409..4862a89039 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -3112,6 +3112,15 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6617";>[CALCITE-6617]
+   * TypeCoercion is not applied correctly to comparisons</a>. */
+  @Test void testRand() {
+    final String sql = "SELECT * FROM (SELECT 1, ROUND(RAND()) AS A)\n"
+        + "WHERE A BETWEEN 1 AND 10 OR A IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)";
+    sql(sql).withRule(CoreRules.PROJECT_REDUCE_EXPRESSIONS).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
diff --git a/core/src/test/java/org/apache/calcite/test/TCatalogReader.java 
b/core/src/test/java/org/apache/calcite/test/TCatalogReader.java
index afd195211a..c6ebd03869 100644
--- a/core/src/test/java/org/apache/calcite/test/TCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/TCatalogReader.java
@@ -49,7 +49,7 @@ public class TCatalogReader extends MockCatalogReader {
     t1.addColumn("t1_smallint", f.smallintType);
     t1.addColumn("t1_int", f.intType);
     t1.addColumn("t1_bigint", f.bigintType);
-    t1.addColumn("t1_float", f.floatType);
+    t1.addColumn("t1_real", f.realType);
     t1.addColumn("t1_double", f.doubleType);
     t1.addColumn("t1_decimal", f.decimalType);
     t1.addColumn("t1_timestamp", f.timestampType);
@@ -64,7 +64,7 @@ public class TCatalogReader extends MockCatalogReader {
     t2.addColumn("t2_smallint", f.smallintType);
     t2.addColumn("t2_int", f.intType);
     t2.addColumn("t2_bigint", f.bigintType);
-    t2.addColumn("t2_float", f.floatType);
+    t2.addColumn("t2_real", f.realType);
     t2.addColumn("t2_double", f.doubleType);
     t2.addColumn("t2_decimal", f.decimalType);
     t2.addColumn("t2_timestamp", f.timestampType);
diff --git 
a/core/src/test/java/org/apache/calcite/test/TypeCoercionConverterTest.java 
b/core/src/test/java/org/apache/calcite/test/TypeCoercionConverterTest.java
index 41c14ed8d9..228b569062 100644
--- a/core/src/test/java/org/apache/calcite/test/TypeCoercionConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TypeCoercionConverterTest.java
@@ -161,14 +161,14 @@ class TypeCoercionConverterTest extends SqlToRelTestBase {
     // char decimal float double
     // char decimal smallint double
     final String sql = "select t1_int, t1_decimal, t1_smallint, t1_double from 
t1 "
-        + "union select t2_varchar20, t2_decimal, t2_float, t2_bigint from t2 "
-        + "union select t1_varchar20, t1_decimal, t1_float, t1_double from t1 "
+        + "union select t2_varchar20, t2_decimal, t2_real, t2_bigint from t2 "
+        + "union select t1_varchar20, t1_decimal, t1_real, t1_double from t1 "
         + "union select t2_varchar20, t2_decimal, t2_smallint, t2_double from 
t2";
     sql(sql).ok();
   }
 
   @Test void testInsertQuerySourceCoercion() {
-    final String sql = "insert into t1 select t2_smallint, t2_int, t2_bigint, 
t2_float,\n"
+    final String sql = "insert into t1 select t2_smallint, t2_int, t2_bigint, 
t2_real,\n"
         + "t2_double, t2_decimal, t2_int, t2_date, t2_timestamp, t2_varchar20, 
t2_int from t2";
     sql(sql).ok();
   }
diff --git a/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java 
b/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
index b20c32ebc7..dc7e357e69 100644
--- a/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
@@ -33,6 +33,7 @@ import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableList;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
@@ -118,17 +119,17 @@ class TypeCoercionTest {
     f.checkCommonType(f.intType, f.bigintType, f.bigintType, true);
     f.checkCommonType(f.bigintType, f.bigintType, f.bigintType, true);
     // FLOAT/DOUBLE
-    f.checkCommonType(f.nullType, f.floatType, f.nullableFloatType, true);
+    f.checkCommonType(f.nullType, f.realType, f.nullableRealType, true);
     f.checkCommonType(f.nullType, f.doubleType, f.nullableDoubleType, true);
     // Use RelDataTypeFactory#leastRestrictive to find the common type; it's 
not
     // symmetric but it's ok because precision does not become lower.
-    f.checkCommonType(f.floatType, f.doubleType, f.floatType, false);
-    f.checkCommonType(f.floatType, f.floatType, f.floatType, true);
+    f.checkCommonType(f.realType, f.doubleType, f.doubleType, false);
+    f.checkCommonType(f.realType, f.realType, f.realType, true);
     f.checkCommonType(f.doubleType, f.doubleType, f.doubleType, true);
     // EXACT + FRACTIONAL
-    f.checkCommonType(f.intType, f.floatType, f.floatType, true);
+    f.checkCommonType(f.intType, f.realType, f.realType, true);
     f.checkCommonType(f.intType, f.doubleType, f.doubleType, true);
-    f.checkCommonType(f.bigintType, f.floatType, f.floatType, true);
+    f.checkCommonType(f.bigintType, f.realType, f.realType, true);
     f.checkCommonType(f.bigintType, f.doubleType, f.doubleType, true);
     // Fixed precision decimal
     RelDataType decimal54 =
@@ -226,12 +227,12 @@ class TypeCoercionTest {
     sql("select LOCALTIME from (values(true)) union values '1'")
         .type("RecordType(VARCHAR NOT NULL LOCALTIME) NOT NULL");
     sql("select t1_int, t1_decimal, t1_smallint, t1_double from t1 "
-        + "union select t2_varchar20, t2_decimal, t2_float, t2_bigint from t2 "
-        + "union select t1_varchar20, t1_decimal, t1_float, t1_double from t1 "
+        + "union select t2_varchar20, t2_decimal, t2_real, t2_bigint from t2 "
+        + "union select t1_varchar20, t1_decimal, t1_real, t1_double from t1 "
         + "union select t2_varchar20, t2_decimal, t2_smallint, t2_double from 
t2")
         .type("RecordType(VARCHAR NOT NULL T1_INT,"
             + " DECIMAL(19, 0) NOT NULL T1_DECIMAL,"
-            + " FLOAT NOT NULL T1_SMALLINT,"
+            + " REAL NOT NULL T1_SMALLINT,"
             + " DOUBLE NOT NULL T1_DOUBLE) NOT NULL");
     // (int) union (int) union (varchar(20))
     sql("select t1_int from t1 "
@@ -253,17 +254,17 @@ class TypeCoercionTest {
 
     // intersect
     sql("select t1_int, t1_decimal, t1_smallint, t1_double from t1 "
-        + "intersect select t2_varchar20, t2_decimal, t2_float, t2_bigint from 
t2 ")
+        + "intersect select t2_varchar20, t2_decimal, t2_real, t2_bigint from 
t2 ")
         .type("RecordType(VARCHAR NOT NULL T1_INT,"
             + " DECIMAL(19, 0) NOT NULL T1_DECIMAL,"
-            + " FLOAT NOT NULL T1_SMALLINT,"
+            + " REAL NOT NULL T1_SMALLINT,"
             + " DOUBLE NOT NULL T1_DOUBLE) NOT NULL");
     // except
     sql("select t1_int, t1_decimal, t1_smallint, t1_double from t1 "
-        + "except select t2_varchar20, t2_decimal, t2_float, t2_bigint from t2 
")
+        + "except select t2_varchar20, t2_decimal, t2_real, t2_bigint from t2 
")
         .type("RecordType(VARCHAR NOT NULL T1_INT,"
             + " DECIMAL(19, 0) NOT NULL T1_DECIMAL,"
-            + " FLOAT NOT NULL T1_SMALLINT,"
+            + " REAL NOT NULL T1_SMALLINT,"
             + " DOUBLE NOT NULL T1_DOUBLE) NOT NULL");
   }
 
@@ -353,11 +354,65 @@ class TypeCoercionTest {
         .columnType("BOOLEAN NOT NULL");
   }
 
+  @Test void testComparisonCoercion() {
+    // NULL
+    final Fixture f = fixture();
+    f.comparisonCommonType(f.nullType, f.nullType, f.nullType);
+    // BOOLEAN
+    f.comparisonCommonType(f.nullType, f.booleanType, null);
+    f.comparisonCommonType(f.booleanType, f.booleanType, f.booleanType);
+    f.comparisonCommonType(f.intType, f.booleanType, null);
+    f.comparisonCommonType(f.bigintType, f.booleanType, null);
+    // INT
+    f.comparisonCommonType(f.smallintType, f.intType, f.intType);
+    f.comparisonCommonType(f.smallintType, f.bigintType, f.bigintType);
+    f.comparisonCommonType(f.intType, f.bigintType, f.bigintType);
+    f.comparisonCommonType(f.bigintType, f.bigintType, f.bigintType);
+    // FLOAT/DOUBLE
+    f.comparisonCommonType(f.realType, f.doubleType, f.doubleType);
+    f.comparisonCommonType(f.realType, f.realType, f.realType);
+    f.comparisonCommonType(f.doubleType, f.doubleType, f.doubleType);
+    // EXACT + FRACTIONAL
+    f.comparisonCommonType(f.intType, f.realType, f.realType);
+    f.comparisonCommonType(f.intType, f.doubleType, f.doubleType);
+    f.comparisonCommonType(f.bigintType, f.realType, f.realType);
+    f.comparisonCommonType(f.bigintType, f.doubleType, f.doubleType);
+    // Fixed precision decimal
+    RelDataType decimal54 =
+        f.typeFactory.createSqlType(SqlTypeName.DECIMAL, 5, 4);
+    RelDataType decimal71 =
+        f.typeFactory.createSqlType(SqlTypeName.DECIMAL, 7, 1);
+    RelDataType decimal104 =
+        f.typeFactory.createSqlType(SqlTypeName.DECIMAL, 10, 4);
+    f.comparisonCommonType(decimal54, decimal71, decimal104);
+    f.comparisonCommonType(decimal54, f.doubleType, f.doubleType);
+    f.comparisonCommonType(decimal54, f.intType, decimal104);
+    // CHAR/VARCHAR
+    f.comparisonCommonType(f.charType, f.varcharType, f.varcharType);
+    f.comparisonCommonType(f.intType, f.charType, f.intType);
+    f.comparisonCommonType(f.doubleType, f.charType, f.doubleType);
+    // TIMESTAMP
+    f.comparisonCommonType(f.timestampType, f.timestampType, f.timestampType);
+    f.comparisonCommonType(f.dateType, f.timestampType, f.timestampType);
+    f.comparisonCommonType(f.intType, f.timestampType, null);
+    f.comparisonCommonType(f.varcharType, f.timestampType, f.timestampType);
+    // generic
+    f.comparisonCommonType(f.charType, f.mapType(f.intType, f.charType), null);
+    f.comparisonCommonType(f.arrayType(f.intType), 
f.recordType(ImmutableList.of()),
+        null);
+    f.comparisonCommonType(f.recordType("a", f.intType),
+        f.recordType("a", f.intType), f.recordType("a", f.intType));
+    f.comparisonCommonType(f.recordType("a", f.arrayType(f.intType)),
+        f.recordType("a", f.arrayType(f.intType)),
+        f.recordType("a", f.arrayType(f.intType)));
+  }
+
+
   /** Test case for case when expression and COALESCE operator. */
   @Test void testCaseWhen() {
     // coalesce
     // double int float
-    sql("select COALESCE(t1_double, t1_int, t1_float) from t1")
+    sql("select COALESCE(t1_double, t1_int, t1_real) from t1")
         .type("RecordType(DOUBLE NOT NULL EXPR$0) NOT NULL");
     // bigint int decimal
     sql("select COALESCE(t1_bigint, t1_int, t1_decimal) from t1")
@@ -369,13 +424,13 @@ class TypeCoercionTest {
     sql("select COALESCE(t1_varchar20, t1_timestamp) from t1")
         .type("RecordType(VARCHAR NOT NULL EXPR$0) NOT NULL");
     // null float int
-    sql("select COALESCE(null, t1_float, t1_int) from t1")
-        .type("RecordType(FLOAT EXPR$0) NOT NULL");
+    sql("select COALESCE(null, t1_real, t1_int) from t1")
+        .type("RecordType(REAL EXPR$0) NOT NULL");
     // null int decimal double
     sql("select COALESCE(null, t1_int, t1_decimal, t1_double) from t1")
         .type("RecordType(DOUBLE EXPR$0) NOT NULL");
     // null float double varchar
-    sql("select COALESCE(null, t1_float, t1_double, t1_varchar20) from t1")
+    sql("select COALESCE(null, t1_real, t1_double, t1_varchar20) from t1")
         .type("RecordType(VARCHAR EXPR$0) NOT NULL");
     // timestamp int varchar
     sql("select COALESCE(t1_timestamp, t1_int, t1_varchar20) from t1")
@@ -404,7 +459,7 @@ class TypeCoercionTest {
         + "else t2_varchar20 end from t2")
         .type("RecordType(VARCHAR NOT NULL EXPR$0) NOT NULL");
     // float decimal
-    sql("select case when 1 > 0 then t2_float else t2_decimal end from t2")
+    sql("select case when 1 > 0 then t2_real else t2_decimal end from t2")
         .type("RecordType(DOUBLE NOT NULL EXPR$0) NOT NULL");
     // bigint decimal
     sql("select case when 1 > 0 then t2_bigint else t2_decimal end from t2")
@@ -459,7 +514,7 @@ class TypeCoercionTest {
     f.shouldNotCast(checkedType4, SqlTypeFamily.APPROXIMATE_NUMERIC);
 
     // FLOAT/REAL
-    RelDataType checkedType5 = f.floatType;
+    RelDataType checkedType5 = f.realType;
     f.checkShouldCast(checkedType5, combine(f.numericTypes, charTypes));
     f.shouldCast(checkedType5, SqlTypeFamily.DECIMAL,
         f.typeFactory.decimalOf(checkedType5));
@@ -581,7 +636,7 @@ class TypeCoercionTest {
     expr("select t1_smallint||t1_int||t1_double from t1")
         .columnType("VARCHAR");
     // boolean float smallint
-    expr("select t1_boolean||t1_float||t1_smallint from t1")
+    expr("select t1_boolean||t1_real||t1_smallint from t1")
         .columnType("VARCHAR");
     // decimal
     expr("select t1_decimal||t1_varchar20 from t1")
@@ -598,7 +653,7 @@ class TypeCoercionTest {
         + "SMALLINT NOT NULL t1_smallint, "
         + "INTEGER NOT NULL t1_int, "
         + "BIGINT NOT NULL t1_bigint, "
-        + "FLOAT NOT NULL t1_float, "
+        + "REAL NOT NULL t1_real, "
         + "DOUBLE NOT NULL t1_double, "
         + "DECIMAL(19, 0) NOT NULL t1_decimal, "
         + "TIMESTAMP(0) NOT NULL t1_timestamp, "
@@ -606,12 +661,12 @@ class TypeCoercionTest {
         + "BINARY(1) NOT NULL t1_binary, "
         + "BOOLEAN NOT NULL t1_boolean) NOT NULL";
 
-    final String sql = "insert into t1 select t2_smallint, t2_int, t2_bigint, 
t2_float,\n"
+    final String sql = "insert into t1 select t2_smallint, t2_int, t2_bigint, 
t2_real,\n"
         + "t2_double, t2_decimal, t2_int, t2_date, t2_timestamp, t2_varchar20, 
t2_int from t2";
     sql(sql).type(expectRowType);
 
     final String sql1 = "insert into ^t1^(t1_varchar20, t1_date, t1_int)\n"
-        + "select t2_smallint, t2_timestamp, t2_float from t2";
+        + "select t2_smallint, t2_timestamp, t2_real from t2";
     sql(sql1).fails("(?s).*Column 't1_smallint' has no default value and does 
not allow NULLs.*");
 
     final String sql2 = "update t1 set t1_varchar20=123, "
@@ -647,8 +702,8 @@ class TypeCoercionTest {
     final RelDataType nullableIntType;
     final RelDataType bigintType;
     final RelDataType nullableBigintType;
-    final RelDataType floatType;
-    final RelDataType nullableFloatType;
+    final RelDataType realType;
+    final RelDataType nullableRealType;
     final RelDataType doubleType;
     final RelDataType nullableDoubleType;
     final RelDataType decimalType;
@@ -695,8 +750,8 @@ class TypeCoercionTest {
       nullableIntType = this.typeFactory.createTypeWithNullability(intType, 
true);
       bigintType = this.typeFactory.createSqlType(SqlTypeName.BIGINT);
       nullableBigintType = 
this.typeFactory.createTypeWithNullability(bigintType, true);
-      floatType = this.typeFactory.createSqlType(SqlTypeName.FLOAT);
-      nullableFloatType = 
this.typeFactory.createTypeWithNullability(floatType, true);
+      realType = this.typeFactory.createSqlType(SqlTypeName.REAL);
+      nullableRealType = this.typeFactory.createTypeWithNullability(realType, 
true);
       doubleType = this.typeFactory.createSqlType(SqlTypeName.DOUBLE);
       nullableDoubleType = 
this.typeFactory.createTypeWithNullability(doubleType, true);
       decimalType = this.typeFactory.createSqlType(SqlTypeName.DECIMAL);
@@ -871,7 +926,7 @@ class TypeCoercionTest {
       return false;
     }
 
-    private String toStringNullable(Object o1) {
+    private String toStringNullable(@Nullable Object o1) {
       if (o1 == null) {
         return "NULL";
       }
@@ -882,7 +937,7 @@ class TypeCoercionTest {
     private void checkCommonType(
         RelDataType type1,
         RelDataType type2,
-        RelDataType expected,
+        @Nullable RelDataType expected,
         boolean isSymmetric) {
       RelDataType result = typeCoercion.getTightestCommonType(type1, type2);
       assertThat("Expected " + toStringNullable(expected)
@@ -901,11 +956,30 @@ class TypeCoercionTest {
       }
     }
 
+    private void comparisonCommonType(
+        RelDataType type1,
+        RelDataType type2,
+        @Nullable RelDataType expected) {
+      RelDataType result = typeCoercion.commonTypeForBinaryComparison(type1, 
type2);
+      assertThat("Expected " + toStringNullable(expected)
+              + " as comparison common type for " + type1
+              + " and " + type2
+              + ", but found " + toStringNullable(result),
+          result,
+          sameInstance(expected));
+      RelDataType result1 = typeCoercion.commonTypeForBinaryComparison(type2, 
type1);
+      assertThat("Expected " + toStringNullable(expected)
+              + " as common type for " + type2
+              + " and " + type1
+              + ", but found " + toStringNullable(result1),
+          result1, sameInstance(expected));
+    }
+
     /** Decision method for finding a wider type. */
     private void checkWiderType(
         RelDataType type1,
         RelDataType type2,
-        RelDataType expected,
+        @Nullable RelDataType expected,
         boolean stringPromotion,
         boolean symmetric) {
       RelDataType result =
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 eca85f5e4b..babaae6201 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1566,7 +1566,7 @@ case when cast(ename as double) < 5 then 0.0
     </Resource>
     <Resource name="planBefore">
       <![CDATA[
-LogicalProject(T=[CASE(<(CAST(CASE(>($1, 'abc'), $1, 
null:VARCHAR(20))):DOUBLE, 5), 0.0E0:DOUBLE, CASE(IS NOT NULL(CAST(CASE(>($1, 
'abc'), $1, null:VARCHAR(20))):DOUBLE), CAST(CAST(CASE(>($1, 'abc'), $1, 
null:VARCHAR(20))):DOUBLE):DOUBLE NOT NULL, 1.0E0:DOUBLE))])
+LogicalProject(T=[CASE(<(CAST(CASE(>($1, 'abc'), $1, 
null:VARCHAR(20))):DOUBLE, 5.0E0), 0.0E0:DOUBLE, CASE(IS NOT 
NULL(CAST(CASE(>($1, 'abc'), $1, null:VARCHAR(20))):DOUBLE), 
CAST(CAST(CASE(>($1, 'abc'), $1, null:VARCHAR(20))):DOUBLE):DOUBLE NOT NULL, 
1.0E0:DOUBLE))])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
@@ -12192,6 +12192,28 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)])
     LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)])
       LogicalProject(ENAME=[$1], MGR=[$3])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testRand">
+    <Resource name="sql">
+      <![CDATA[SELECT * FROM (SELECT 1, ROUND(RAND()) AS A)
+WHERE A BETWEEN 1 AND 10 OR A IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[$0], A=[$1])
+  LogicalFilter(condition=[OR(AND(>=($1, CAST(1):DOUBLE NOT NULL), <=($1, 
CAST(10):DOUBLE NOT NULL)), =($1, CAST(1):DOUBLE NOT NULL), =($1, 
CAST(2):DOUBLE NOT NULL), =($1, CAST(3):DOUBLE NOT NULL), =($1, CAST(4):DOUBLE 
NOT NULL), =($1, CAST(5):DOUBLE NOT NULL), =($1, CAST(6):DOUBLE NOT NULL), 
=($1, CAST(7):DOUBLE NOT NULL), =($1, CAST(8):DOUBLE NOT NULL), =($1, 
CAST(9):DOUBLE NOT NULL), =($1, CAST(10):DOUBLE NOT NULL))])
+    LogicalProject(EXPR$0=[1], A=[ROUND(RAND())])
+      LogicalValues(tuples=[[{ 0 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[1], A=[$1])
+  LogicalFilter(condition=[OR(AND(>=($1, CAST(1):DOUBLE NOT NULL), <=($1, 
CAST(10):DOUBLE NOT NULL)), =($1, CAST(1):DOUBLE NOT NULL), =($1, 
CAST(2):DOUBLE NOT NULL), =($1, CAST(3):DOUBLE NOT NULL), =($1, CAST(4):DOUBLE 
NOT NULL), =($1, CAST(5):DOUBLE NOT NULL), =($1, CAST(6):DOUBLE NOT NULL), 
=($1, CAST(7):DOUBLE NOT NULL), =($1, CAST(8):DOUBLE NOT NULL), =($1, 
CAST(9):DOUBLE NOT NULL), =($1, CAST(10):DOUBLE NOT NULL))])
+    LogicalProject(EXPR$0=[1], A=[ROUND(RAND())])
+      LogicalValues(tuples=[[{ 0 }]])
 ]]>
     </Resource>
   </TestCase>
@@ -13080,14 +13102,14 @@ LogicalProject($0=[$3], $1=[$4])
     <Resource name="planBefore">
       <![CDATA[
 LogicalProject(ENAME=[$1])
-  LogicalFilter(condition=[>($5, 100.0:DECIMAL(4, 1))])
+  LogicalFilter(condition=[>(CAST($5):DECIMAL(10, 1) NOT NULL, 100.0)])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
 LogicalProject(ENAME=[$1])
-  LogicalCalc(expr#0..8=[{inputs}], expr#9=[10:BIGINT], expr#10=[*($t5, $t9)], 
expr#11=[100.0:DECIMAL(4, 1)], expr#12=[Reinterpret($t11)], expr#13=[>($t10, 
$t12)], proj#0..8=[{exprs}], $condition=[$t13])
+  LogicalCalc(expr#0..8=[{inputs}], expr#9=[10:BIGINT], expr#10=[*($t5, $t9)], 
expr#11=[true], expr#12=[Reinterpret($t10, $t11)], expr#13=[Reinterpret($t12)], 
expr#14=[100.0:DECIMAL(10, 1)], expr#15=[Reinterpret($t14)], expr#16=[>($t13, 
$t15)], proj#0..8=[{exprs}], $condition=[$t16])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
diff --git 
a/core/src/test/resources/org/apache/calcite/test/TypeCoercionConverterTest.xml 
b/core/src/test/resources/org/apache/calcite/test/TypeCoercionConverterTest.xml
index c5476150a7..4253f0b7e1 100644
--- 
a/core/src/test/resources/org/apache/calcite/test/TypeCoercionConverterTest.xml
+++ 
b/core/src/test/resources/org/apache/calcite/test/TypeCoercionConverterTest.xml
@@ -136,13 +136,13 @@ LogicalProject(F0=[null:BOOLEAN], 
F1=[CAST(true):BOOLEAN], F2=[null:BOOLEAN], F3
   </TestCase>
   <TestCase name="testInsertQuerySourceCoercion">
     <Resource name="sql">
-      <![CDATA[insert into t1 select t2_smallint, t2_int, t2_bigint, t2_float,
+      <![CDATA[insert into t1 select t2_smallint, t2_int, t2_bigint, t2_real,
 t2_double, t2_decimal, t2_int, t2_date, t2_timestamp, t2_varchar20, t2_int 
from t2]]>
     </Resource>
     <Resource name="plan">
       <![CDATA[
 LogicalTableModify(table=[[CATALOG, SALES, T1]], operation=[INSERT], 
flattened=[false])
-  LogicalProject(t1_varchar20=[CAST($1):VARCHAR(20) NOT NULL], 
t1_smallint=[CAST($2):SMALLINT NOT NULL], t1_int=[CAST($3):INTEGER NOT NULL], 
t1_bigint=[CAST($4):BIGINT NOT NULL], t1_float=[CAST($5):FLOAT NOT NULL], 
t1_double=[CAST($6):DOUBLE NOT NULL], t1_decimal=[CAST($2):DECIMAL(19, 0) NOT 
NULL], t1_timestamp=[CAST($8):TIMESTAMP(0) NOT NULL], t1_date=[CAST($7):DATE 
NOT NULL], t1_binary=[CAST($0):BINARY(1) NOT NULL], t1_boolean=[<>($2, 0)])
+  LogicalProject(t1_varchar20=[CAST($1):VARCHAR(20) NOT NULL], 
t1_smallint=[CAST($2):SMALLINT NOT NULL], t1_int=[CAST($3):INTEGER NOT NULL], 
t1_bigint=[CAST($4):BIGINT NOT NULL], t1_real=[CAST($5):REAL NOT NULL], 
t1_double=[CAST($6):DOUBLE NOT NULL], t1_decimal=[CAST($2):DECIMAL(19, 0) NOT 
NULL], t1_timestamp=[CAST($8):TIMESTAMP(0) NOT NULL], t1_date=[CAST($7):DATE 
NOT NULL], t1_binary=[CAST($0):BINARY(1) NOT NULL], t1_boolean=[<>($2, 0)])
     LogicalTableScan(table=[[CATALOG, SALES, T2]])
 ]]>
     </Resource>
@@ -211,7 +211,7 @@ LogicalProject(F0=[null:BOOLEAN], F1=[CAST(false):BOOLEAN], 
F2=[null:BOOLEAN], F
   </TestCase>
   <TestCase name="testSetOperation">
     <Resource name="sql">
-      <![CDATA[select t1_int, t1_decimal, t1_smallint, t1_double from t1 union 
select t2_varchar20, t2_decimal, t2_float, t2_bigint from t2 union select 
t1_varchar20, t1_decimal, t1_float, t1_double from t1 union select 
t2_varchar20, t2_decimal, t2_smallint, t2_double from t2]]>
+      <![CDATA[select t1_int, t1_decimal, t1_smallint, t1_double from t1 union 
select t2_varchar20, t2_decimal, t2_real, t2_bigint from t2 union select 
t1_varchar20, t1_decimal, t1_real, t1_double from t1 union select t2_varchar20, 
t2_decimal, t2_smallint, t2_double from t2]]>
     </Resource>
     <Resource name="plan">
       <![CDATA[
@@ -220,9 +220,9 @@ LogicalUnion(all=[false])
     LogicalUnion(all=[false])
       LogicalProject(T1_INT=[CAST($2):VARCHAR NOT NULL], T1_DECIMAL=[$6], 
T1_SMALLINT=[$1], T1_DOUBLE=[$5])
         LogicalTableScan(table=[[CATALOG, SALES, T1]])
-      LogicalProject(T2_VARCHAR20=[$0], T2_DECIMAL=[$6], T2_FLOAT=[$4], 
T2_BIGINT=[$3])
+      LogicalProject(T2_VARCHAR20=[$0], T2_DECIMAL=[$6], T2_REAL=[$4], 
T2_BIGINT=[$3])
         LogicalTableScan(table=[[CATALOG, SALES, T2]])
-    LogicalProject(T1_VARCHAR20=[$0], T1_DECIMAL=[$6], T1_FLOAT=[$4], 
T1_DOUBLE=[$5])
+    LogicalProject(T1_VARCHAR20=[$0], T1_DECIMAL=[$6], T1_REAL=[$4], 
T1_DOUBLE=[$5])
       LogicalTableScan(table=[[CATALOG, SALES, T1]])
   LogicalProject(T2_VARCHAR20=[$0], T2_DECIMAL=[$6], T2_SMALLINT=[$1], 
T2_DOUBLE=[$5])
     LogicalTableScan(table=[[CATALOG, SALES, T2]])
@@ -250,7 +250,7 @@ LogicalUnion(all=[false])
     <Resource name="plan">
       <![CDATA[
 LogicalTableModify(table=[[CATALOG, SALES, T1]], operation=[UPDATE], 
updateColumnList=[[t1_varchar20, t1_date, t1_int]], 
sourceExpressionList=[[CAST(123):VARCHAR(20) NOT NULL, CAST(2020-01-03 
10:14:34):DATE NOT NULL, CAST(12.3:DECIMAL(3, 1)):INTEGER NOT NULL]], 
flattened=[false])
-  LogicalProject(t1_varchar20=[$0], t1_smallint=[$1], t1_int=[$2], 
t1_bigint=[$3], t1_float=[$4], t1_double=[$5], t1_decimal=[$6], 
t1_timestamp=[$7], t1_date=[$8], t1_binary=[$9], t1_boolean=[$10], 
EXPR$0=[123], EXPR$1=[2020-01-03 10:14:34], EXPR$2=[12.3:DECIMAL(3, 1)])
+  LogicalProject(t1_varchar20=[$0], t1_smallint=[$1], t1_int=[$2], 
t1_bigint=[$3], t1_real=[$4], t1_double=[$5], t1_decimal=[$6], 
t1_timestamp=[$7], t1_date=[$8], t1_binary=[$9], t1_boolean=[$10], 
EXPR$0=[123], EXPR$1=[2020-01-03 10:14:34], EXPR$2=[12.3:DECIMAL(3, 1)])
     LogicalTableScan(table=[[CATALOG, SALES, T1]])
 ]]>
     </Resource>
diff --git a/core/src/test/resources/sql/agg.iq 
b/core/src/test/resources/sql/agg.iq
index d109a763f5..733ae7a9c0 100644
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -3120,7 +3120,7 @@ group by dept.deptno;
 
 !ok
 EnumerableAggregate(group=[{0}], S=[COLLECT($1) WITHIN GROUP ([1 DESC])], 
S1=[COLLECT($1) WITHIN GROUP ([2])], S2=[COLLECT($1) WITHIN GROUP ([1]) FILTER 
$3])
-  EnumerableCalc(expr#0..3=[{inputs}], expr#4=[1], expr#5=[2000], 
expr#6=[>($t2, $t5)], expr#7=[IS TRUE($t6)], DEPTNO=[$t0], SAL=[$t2], 
$f2=[$t4], $f3=[$t7])
+  EnumerableCalc(expr#0..3=[{inputs}], expr#4=[1], 
expr#5=[CAST($t2):DECIMAL(10, 2)], expr#6=[2000.00:DECIMAL(10, 2)], 
expr#7=[>($t5, $t6)], expr#8=[IS TRUE($t7)], DEPTNO=[$t0], SAL=[$t2], 
$f2=[$t4], $f3=[$t8])
     EnumerableHashJoin(condition=[=($0, $3)], joinType=[inner])
       EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
         EnumerableTableScan(table=[[scott, DEPT]])
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index 7bfedac3a8..ace96e5ec6 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -2176,8 +2176,8 @@ where sal + 100 not in (
 
 !ok
 EnumerableAggregate(group=[{}], C=[COUNT()])
-  EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0], expr#9=[=($t1, $t8)], 
expr#10=[IS NULL($t0)], expr#11=[IS NOT NULL($t6)], expr#12=[<($t2, $t1)], 
expr#13=[OR($t10, $t11, $t12)], expr#14=[IS NOT TRUE($t13)], expr#15=[OR($t9, 
$t14)], proj#0..7=[{exprs}], $condition=[$t15])
-    EnumerableMergeJoin(condition=[AND(=($3, $5), =($4, $7))], joinType=[left])
+  EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0], expr#9=[=($t1, $t8)], 
expr#10=[IS NULL($t0)], expr#11=[IS NOT NULL($t7)], expr#12=[<($t2, $t1)], 
expr#13=[OR($t10, $t11, $t12)], expr#14=[IS NOT TRUE($t13)], expr#15=[OR($t9, 
$t14)], proj#0..7=[{exprs}], $condition=[$t15])
+    EnumerableMergeJoin(condition=[AND(=($3, $5), =($4, $6))], joinType=[left])
       EnumerableSort(sort0=[$3], sort1=[$4], dir0=[ASC], dir1=[ASC])
         EnumerableCalc(expr#0..6=[{inputs}], expr#7=[100], expr#8=[+($t2, 
$t7)], expr#9=[CAST($t1):VARCHAR(14)], SAL=[$t2], c=[$t4], ck=[$t5], $f5=[$t8], 
ENAME0=[$t9])
           EnumerableMergeJoin(condition=[=($3, $6)], joinType=[left])
@@ -2187,8 +2187,8 @@ EnumerableAggregate(group=[{}], C=[COUNT()])
             EnumerableSort(sort0=[$2], dir0=[ASC])
               EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1:BIGINT], 
expr#4=[IS NOT NULL($t1)], c=[$t3], ck=[$t3], DNAME=[$t1], $condition=[$t4])
                 EnumerableTableScan(table=[[scott, DEPT]])
-      EnumerableSort(sort0=[$0], sort1=[$2], dir0=[ASC], dir1=[ASC])
-        EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[IS NOT 
NULL($t1)], DEPTNO=[$t0], i=[$t3], DNAME=[$t1], $condition=[$t4])
+      EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
+        EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):DECIMAL(13, 2) 
NOT NULL], expr#4=[true], expr#5=[IS NOT NULL($t1)], EXPR$0=[$t3], DNAME=[$t1], 
i=[$t4], $condition=[$t5])
           EnumerableTableScan(table=[[scott, DEPT]])
 !plan
 
@@ -2894,7 +2894,7 @@ EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS 
NULL($t1)], DEPTNO=[$t0], $condi
     EnumerableAggregate(group=[{0}])
       EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[1], 
expr#5=[>($t2, $t4)], i=[$t3], $condition=[$t5])
         EnumerableAggregate(group=[{5, 7}], c=[COUNT()])
-          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(12, 
2)], expr#9=[3000.00:DECIMAL(12, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
+          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(10, 
2)], expr#9=[3000.00:DECIMAL(10, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
             EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -2920,7 +2920,7 @@ EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS 
NULL($t1)], DEPTNO=[$t0], U=[$t2
     EnumerableAggregate(group=[{0}])
       EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[1], 
expr#5=[>($t2, $t4)], i=[$t3], $condition=[$t5])
         EnumerableAggregate(group=[{5, 7}], c=[COUNT()])
-          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(12, 
2)], expr#9=[3000.00:DECIMAL(12, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
+          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(10, 
2)], expr#9=[3000.00:DECIMAL(10, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
             EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -2946,7 +2946,7 @@ EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS NOT 
NULL($t1)], DEPTNO=[$t0], U=
     EnumerableAggregate(group=[{0}])
       EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], expr#4=[1], 
expr#5=[>($t2, $t4)], i=[$t3], $condition=[$t5])
         EnumerableAggregate(group=[{5, 7}], c=[COUNT()])
-          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(12, 
2)], expr#9=[3000.00:DECIMAL(12, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
+          EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t5):DECIMAL(10, 
2)], expr#9=[3000.00:DECIMAL(10, 2)], expr#10=[=($t8, $t9)], expr#11=[IS NOT 
NULL($t7)], expr#12=[AND($t10, $t11)], proj#0..7=[{exprs}], $condition=[$t12])
             EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -3290,7 +3290,7 @@ select *, (comm <> 300 and comm <> 500 and comm <> null) 
as i from "scott".emp;
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t6):DECIMAL(12, 2)], 
expr#9=[Sarg[(-∞..300.00:DECIMAL(12, 2)), (300.00:DECIMAL(12, 
2)..500.00:DECIMAL(12, 2)), (500.00:DECIMAL(12, 2)..+∞)]:DECIMAL(12, 2)], 
expr#10=[SEARCH($t8, $t9)], expr#11=[null:BOOLEAN], expr#12=[AND($t10, $t11)], 
proj#0..7=[{exprs}], I=[$t12])
+EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t6):DECIMAL(10, 2)], 
expr#9=[Sarg[(-∞..300.00:DECIMAL(10, 2)), (300.00:DECIMAL(10, 
2)..500.00:DECIMAL(10, 2)), (500.00:DECIMAL(10, 2)..+∞)]:DECIMAL(10, 2)], 
expr#10=[SEARCH($t8, $t9)], expr#11=[null:BOOLEAN], expr#12=[AND($t10, $t11)], 
proj#0..7=[{exprs}], I=[$t12])
   EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -3927,16 +3927,23 @@ select comm, comm in (500, 300, 0) from emp;
 EnumerableCalc(expr#0..5=[{inputs}], expr#6=[IS NOT NULL($t5)], 
expr#7=[0:BIGINT], expr#8=[<>($t1, $t7)], expr#9=[AND($t6, $t8)], expr#10=[IS 
NULL($t3)], expr#11=[<($t2, $t1)], expr#12=[OR($t10, $t11)], 
expr#13=[null:BOOLEAN], expr#14=[IS NULL($t5)], expr#15=[AND($t12, $t13, $t8, 
$t14)], expr#16=[OR($t9, $t15)], COMM=[$t0], EXPR$1=[$t16])
   EnumerableMergeJoin(condition=[=($3, $4)], joinType=[left])
     EnumerableSort(sort0=[$3], dir0=[ASC])
-      EnumerableCalc(expr#0..3=[{inputs}], COMM=[$t1], $f0=[$t2], $f1=[$t3], 
COMM0=[$t1])
+      EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t1):DECIMAL(10, 2)], 
COMM=[$t1], $f0=[$t2], $f1=[$t3], COMM0=[$t4])
         EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
           EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], COMM=[$t6])
             EnumerableTableScan(table=[[scott, EMP]])
           EnumerableCalc(expr#0=[{inputs}], $f0=[$t0], $f00=[$t0])
             EnumerableAggregate(group=[{}], agg#0=[COUNT()])
-              EnumerableValues(tuples=[[{ 500.00 }, { 300.00 }, { 0.00 }]])
+              EnumerableUnion(all=[true])
+                EnumerableValues(tuples=[[{ 500.00 }]])
+                EnumerableValues(tuples=[[{ 300.00 }]])
+                EnumerableValues(tuples=[[{ 0.00 }]])
     EnumerableSort(sort0=[$0], dir0=[ASC])
-      EnumerableCalc(expr#0=[{inputs}], expr#1=[true], proj#0..1=[{exprs}])
-        EnumerableValues(tuples=[[{ 500.00 }, { 300.00 }, { 0.00 }]])
+      EnumerableAggregate(group=[{0}], agg#0=[MIN($1)])
+        EnumerableCalc(expr#0=[{inputs}], expr#1=[true], proj#0..1=[{exprs}])
+          EnumerableUnion(all=[true])
+            EnumerableValues(tuples=[[{ 500.00 }]])
+            EnumerableValues(tuples=[[{ 300.00 }]])
+            EnumerableValues(tuples=[[{ 0.00 }]])
 !plan
 
 # Test LHS is nullable and RHS is nullable
@@ -3967,15 +3974,24 @@ select comm, comm in (500, 300, 0, null) from emp;
 EnumerableCalc(expr#0..5=[{inputs}], expr#6=[IS NOT NULL($t5)], 
expr#7=[0:BIGINT], expr#8=[<>($t1, $t7)], expr#9=[AND($t6, $t8)], expr#10=[IS 
NULL($t3)], expr#11=[<($t2, $t1)], expr#12=[OR($t10, $t11)], 
expr#13=[null:BOOLEAN], expr#14=[IS NULL($t5)], expr#15=[AND($t12, $t13, $t8, 
$t14)], expr#16=[OR($t9, $t15)], COMM=[$t0], EXPR$1=[$t16])
   EnumerableMergeJoin(condition=[=($3, $4)], joinType=[left])
     EnumerableSort(sort0=[$3], dir0=[ASC])
-      EnumerableCalc(expr#0..3=[{inputs}], COMM=[$t1], $f0=[$t2], $f1=[$t3], 
COMM0=[$t1])
+      EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t1):DECIMAL(12, 2)], 
COMM=[$t1], $f0=[$t2], $f1=[$t3], COMM0=[$t4])
         EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
           EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], COMM=[$t6])
             EnumerableTableScan(table=[[scott, EMP]])
           EnumerableAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0)])
-            EnumerableValues(tuples=[[{ 500.00 }, { 300.00 }, { 0.00 }, { null 
}]])
+            EnumerableUnion(all=[true])
+              EnumerableValues(tuples=[[{ 500.00 }]])
+              EnumerableValues(tuples=[[{ 300.00 }]])
+              EnumerableValues(tuples=[[{ 0.00 }]])
+              EnumerableValues(tuples=[[{ null }]])
     EnumerableSort(sort0=[$0], dir0=[ASC])
-      EnumerableCalc(expr#0=[{inputs}], expr#1=[true], proj#0..1=[{exprs}])
-        EnumerableValues(tuples=[[{ 500.00 }, { 300.00 }, { 0.00 }, { null }]])
+      EnumerableAggregate(group=[{0}], agg#0=[MIN($1)])
+        EnumerableCalc(expr#0=[{inputs}], expr#1=[true], proj#0..1=[{exprs}])
+          EnumerableUnion(all=[true])
+            EnumerableValues(tuples=[[{ 500.00 }]])
+            EnumerableValues(tuples=[[{ 300.00 }]])
+            EnumerableValues(tuples=[[{ 0.00 }]])
+            EnumerableValues(tuples=[[{ null }]])
 !plan
 
 # Test LHS is (not nullable, not nullable) and RHS is (not nullable, not 
nullable)
@@ -4046,16 +4062,23 @@ select comm, (comm, comm) in ((500, 500), (300, 300), 
(0, 0)) from emp;
 EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t7)], 
expr#9=[0:BIGINT], expr#10=[<>($t1, $t9)], expr#11=[AND($t8, $t10)], 
expr#12=[IS NULL($t3)], expr#13=[IS NULL($t4)], expr#14=[<($t2, $t1)], 
expr#15=[OR($t12, $t13, $t14)], expr#16=[null:BOOLEAN], expr#17=[IS NULL($t7)], 
expr#18=[AND($t15, $t16, $t10, $t17)], expr#19=[OR($t11, $t18)], COMM=[$t0], 
EXPR$1=[$t19])
   EnumerableMergeJoin(condition=[AND(=($3, $5), =($4, $6))], joinType=[left])
     EnumerableSort(sort0=[$3], sort1=[$4], dir0=[ASC], dir1=[ASC])
-      EnumerableCalc(expr#0..3=[{inputs}], COMM=[$t1], $f0=[$t2], $f1=[$t3], 
COMM0=[$t1], COMM1=[$t1])
+      EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t1):DECIMAL(10, 2)], 
COMM=[$t1], $f0=[$t2], $f1=[$t3], COMM0=[$t4], COMM1=[$t4])
         EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
           EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], COMM=[$t6])
             EnumerableTableScan(table=[[scott, EMP]])
           EnumerableCalc(expr#0=[{inputs}], $f0=[$t0], $f00=[$t0])
             EnumerableAggregate(group=[{}], agg#0=[COUNT()])
-              EnumerableValues(tuples=[[{ 500.00, 500.00 }, { 300.00, 300.00 
}, { 0.00, 0.00 }]])
+              EnumerableUnion(all=[true])
+                EnumerableValues(tuples=[[{ 500.00, 500.00 }]])
+                EnumerableValues(tuples=[[{ 300.00, 300.00 }]])
+                EnumerableValues(tuples=[[{ 0.00, 0.00 }]])
     EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
-      EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], proj#0..2=[{exprs}])
-        EnumerableValues(tuples=[[{ 500.00, 500.00 }, { 300.00, 300.00 }, { 
0.00, 0.00 }]])
+      EnumerableAggregate(group=[{0, 1}], agg#0=[MIN($2)])
+        EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], 
proj#0..2=[{exprs}])
+          EnumerableUnion(all=[true])
+            EnumerableValues(tuples=[[{ 500.00, 500.00 }]])
+            EnumerableValues(tuples=[[{ 300.00, 300.00 }]])
+            EnumerableValues(tuples=[[{ 0.00, 0.00 }]])
 !plan
 
 # Test LHS is (nullable, nullable) and RHS is (nullable, nullable)
@@ -4086,15 +4109,24 @@ select comm, (comm, comm) in ((500, 500), (300, 300), 
(0, 0), (null , null)) fro
 EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t7)], 
expr#9=[0:BIGINT], expr#10=[<>($t1, $t9)], expr#11=[AND($t8, $t10)], 
expr#12=[IS NULL($t3)], expr#13=[IS NULL($t4)], expr#14=[<($t2, $t1)], 
expr#15=[OR($t12, $t13, $t14)], expr#16=[null:BOOLEAN], expr#17=[IS NULL($t7)], 
expr#18=[AND($t15, $t16, $t10, $t17)], expr#19=[OR($t11, $t18)], COMM=[$t0], 
EXPR$1=[$t19])
   EnumerableMergeJoin(condition=[AND(=($3, $5), =($4, $6))], joinType=[left])
     EnumerableSort(sort0=[$3], sort1=[$4], dir0=[ASC], dir1=[ASC])
-      EnumerableCalc(expr#0..3=[{inputs}], COMM=[$t1], $f0=[$t2], $f1=[$t3], 
COMM0=[$t1], COMM1=[$t1])
+      EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t1):DECIMAL(10, 2)], 
COMM=[$t1], $f0=[$t2], $f1=[$t3], COMM0=[$t4], COMM1=[$t4])
         EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
           EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], COMM=[$t6])
             EnumerableTableScan(table=[[scott, EMP]])
           EnumerableAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0, 
$1)])
-            EnumerableValues(tuples=[[{ 500.00, 500.00 }, { 300.00, 300.00 }, 
{ 0.00, 0.00 }, { null, null }]])
+            EnumerableUnion(all=[true])
+              EnumerableValues(tuples=[[{ 500.00, 500.00 }]])
+              EnumerableValues(tuples=[[{ 300.00, 300.00 }]])
+              EnumerableValues(tuples=[[{ 0.00, 0.00 }]])
+              EnumerableValues(tuples=[[{ null, null }]])
     EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
-      EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], proj#0..2=[{exprs}])
-        EnumerableValues(tuples=[[{ 500.00, 500.00 }, { 300.00, 300.00 }, { 
0.00, 0.00 }, { null, null }]])
+      EnumerableAggregate(group=[{0, 1}], agg#0=[MIN($2)])
+        EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], 
proj#0..2=[{exprs}])
+          EnumerableUnion(all=[true])
+            EnumerableValues(tuples=[[{ 500.00, 500.00 }]])
+            EnumerableValues(tuples=[[{ 300.00, 300.00 }]])
+            EnumerableValues(tuples=[[{ 0.00, 0.00 }]])
+            EnumerableValues(tuples=[[{ null, null }]])
 !plan
 
 # End sub-query.iq
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java 
b/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
index a44add8094..384d98409b 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
@@ -2374,14 +2374,14 @@ public class DruidAdapter2IT {
         "PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
             + 
"intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], filter=[>"
-            + "($91, 10)], projects=[[$90, IS TRUE(>($91, 10))]], groups=[{}], 
aggs=[[SUM($0)"
+            + "($91, 10.0E0)], projects=[[$90, IS TRUE(>($91, 10.0E0))]], 
groups=[{}], aggs=[[SUM($0)"
             + "]])";
 
     sql(sql)
         .explainContains(expectedSubExplain)
         .queryContains(
             new DruidChecker("\"queryType\":\"timeseries\"", 
"\"filter\":{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"10\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"10.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .returnsUnordered("EXPR$0=25.06");
   }
@@ -2392,13 +2392,13 @@ public class DruidAdapter2IT {
     String expectedSubExplain = "PLAN="
         + "EnumerableCalc(expr#0..1=[{inputs}], EXPR$0=[$t1], 
product_id=[$t0])\n"
         + "  EnumerableInterpreter\n"
-        + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], 
filter=[AND(>(CAST($1):INTEGER, 1553), >($91, 5))], projects=[[$1, $90]], 
groups=[{0}], aggs=[[SUM($1)]])";
+        + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], 
filter=[AND(>(CAST($1):INTEGER, 1553), >($91, 5.0E0))], projects=[[$1, $90]], 
groups=[{0}], aggs=[[SUM($1)]])";
 
     CalciteAssert.AssertQuery q = sql(sql)
         .explainContains(expectedSubExplain)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"));
     q.returnsUnordered("EXPR$0=10.16; product_id=1554",
         "EXPR$0=45.05; product_id=1556",
@@ -2413,7 +2413,7 @@ public class DruidAdapter2IT {
     sql(sql)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .returnsUnordered("EXPR$0=10.6; product_id=1556",
             "EXPR$0=10.6; product_id=1556",
@@ -3150,7 +3150,7 @@ public class DruidAdapter2IT {
         + "<= ((floor(\\'store_sales\\') * 25) + 2))'}";
     final String likeExpressionFilter = 
"{'type':'expression','expression':'like(\\'product_id\\'";
     final String likeExpressionFilter2 = "1%";
-    final String simpleBound = 
"{'type':'bound','dimension':'store_cost','lower':'1',"
+    final String simpleBound = 
"{'type':'bound','dimension':'store_cost','lower':'1.0',"
         + "'lowerStrict':true,'ordering':'numeric'}";
     final String timeSimpleFilter =
         
"{'type':'bound','dimension':'__time','upper':'1997-01-02T00:00:00.000Z',"
@@ -3169,7 +3169,7 @@ public class DruidAdapter2IT {
     final String plan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
         + "2992-01-10T00:00:00.000Z]], filter=[AND(<=(/(+(CAST($1):INTEGER, 
$90), "
-        + "-($91, 5)), +(*(FLOOR($90), 25), 2)), >($90, 0), LIKE($1, '1%'), 
>($91, 1), "
+        + "-($91, 5)), +(*(FLOOR($90), 25), 2)), >($90, 0.0E0), LIKE($1, 
'1%'), >($91, 1.0E0), "
         + "<($0, 1997-01-02 00:00:00), =(EXTRACT(FLAG(MONTH), $0), 1), "
         + "=(EXTRACT(FLAG(DAY), $0), 1), =(+(/(EXTRACT(FLAG(MONTH), $0), 4), 
1), 1))], "
         + "groups=[{}], aggs=[[COUNT()]])";
@@ -3194,7 +3194,7 @@ public class DruidAdapter2IT {
         + " AND ceil(\"timestamp\" TO SECOND) > CAST('1997-01-01' AS 
TIMESTAMP) ";
     final String plan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1997-01-01T00:00:00.001Z/"
-        + "1997-01-04T00:00:00.001Z]], filter=[>(CEIL($90), 1)], groups=[{}], 
aggs=[[COUNT()]])";
+        + "1997-01-04T00:00:00.001Z]], filter=[>(CEIL($90), 1.0E0)], 
groups=[{}], aggs=[[COUNT()]])";
     sql(sql)
         .explainContains(plan)
         .returnsOrdered("EXPR$0=408");
@@ -3272,7 +3272,7 @@ public class DruidAdapter2IT {
     sql(sql)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .runs();
   }
@@ -3355,7 +3355,7 @@ public class DruidAdapter2IT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  BindableSort(sort0=[$2], dir0=[ASC], fetch=[3])\n"
             + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20)], 
projects=[[+(COS($90), 1), SIN($91),"
+            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20.0E0)], 
projects=[[+(COS($90), 1), SIN($91),"
             + " +(EXTRACT(FLAG(DAY), $0), 1)]])");
   }
 
@@ -3371,7 +3371,7 @@ public class DruidAdapter2IT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  BindableSort(sort0=[$1], dir0=[ASC], fetch=[3])\n"
             + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20)], 
projects=[[+(COS(+($90, $91)), 1), "
+            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20.0E0)], 
projects=[[+(COS(+($90, $91)), 1), "
             + "+(EXTRACT(FLAG(DAY), $0), 1)]])");
   }
 
@@ -3501,7 +3501,7 @@ public class DruidAdapter2IT {
     final String query = 
"{'queryType':'timeseries','dataSource':'foodmart','descending':false,"
         + 
"'granularity':'all','aggregations':[{'type':'filtered','filter':{'type':'or','fields':"
         + 
"[{'type':'selector','dimension':'state_province','value':'CA'},{'type':'and','fields':"
-        + 
"[{'type':'bound','dimension':'store_sales','lower':'100','lowerStrict':true,"
+        + 
"[{'type':'bound','dimension':'store_sales','lower':'100.0','lowerStrict':true,"
         + 
"'ordering':'numeric'},{'type':'not','field':{'type':'selector','dimension':'product_id',"
         + 
"'value':'100'}}]}]},'aggregator':{'type':'filtered','filter':{'type':'not',"
         + 
"'field':{'type':'selector','dimension':'product_id','value':null}},'aggregator':"
@@ -3637,10 +3637,10 @@ public class DruidAdapter2IT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
             + "2992-01-10T00:00:00.000Z]], projects=[[$1, $90]], groups=[{0}], 
aggs=[[SUM($1)]], "
-            + "filter=[>($1, 220)], sort0=[0], dir0=[ASC], fetch=[2])")
+            + "filter=[>($1, 220.0E0)], sort0=[0], dir0=[ASC], fetch=[2])")
         .queryContains(
             new 
DruidChecker("'having':{'type':'filter','filter':{'type':'bound',"
-                + 
"'dimension':'S','lower':'220','lowerStrict':true,'ordering':'numeric'}}"));
+                + 
"'dimension':'S','lower':'220.0','lowerStrict':true,'ordering':'numeric'}}"));
     q.returnsOrdered("P=1; S=236.55", "P=10; S=230.04");
   }
 
@@ -3652,7 +3652,7 @@ public class DruidAdapter2IT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
             + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], 
projects=[[$1, $90]], groups=[{0}],"
-            + " aggs=[[SUM($1)]], filter=[>($1, 220)], sort0=[0], dir0=[ASC], 
fetch=[2])\n")
+            + " aggs=[[SUM($1)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
         .queryContains(
             new 
DruidChecker("{'queryType':'groupBy','dataSource':'foodmart','granularity':'all'"));
     q.returnsOrdered("P=100; S=343.2", "P=1000; S=532.62");
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java 
b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
index 9e140f3293..e47fe4376e 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -2691,14 +2691,14 @@ public class DruidAdapterIT {
         + "EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], "
         + "intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], 
filter=[>"
-        + "($91, 10)], projects=[[$90, IS TRUE(>($91, 10))]], groups=[{}], 
aggs=[[SUM($0)"
+        + "($91, 10.0E0)], projects=[[$90, IS TRUE(>($91, 10.0E0))]], 
groups=[{}], aggs=[[SUM($0)"
         + "]])";
 
     sql(sql)
         .explainContains(expectedSubExplain)
         .queryContains(
             new DruidChecker("\"queryType\":\"timeseries\"", 
"\"filter\":{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"10\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"10.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .returnsUnordered("EXPR$0=25.06");
   }
@@ -2712,14 +2712,14 @@ public class DruidAdapterIT {
         + "EnumerableCalc(expr#0..1=[{inputs}], EXPR$0=[$t1], 
product_id=[$t0])\n"
         + "  EnumerableInterpreter\n"
         + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00"
-        + ".000Z/2992-01-10T00:00:00.000Z]], filter=[AND(>(CAST($1):INTEGER, 
1553), >($91, 5))], "
+        + ".000Z/2992-01-10T00:00:00.000Z]], filter=[AND(>(CAST($1):INTEGER, 
1553), >($91, 5.0E0))], "
         + "projects=[[$1, $90]], groups=[{0}], aggs=[[SUM($1)]])";
 
     CalciteAssert.AssertQuery q = sql(sql)
         .explainContains(expectedSubExplain)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"));
     q.returnsUnordered("EXPR$0=10.16; product_id=1554",
         "EXPR$0=45.05; product_id=1556",
@@ -2736,7 +2736,7 @@ public class DruidAdapterIT {
     sql(sql)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .returnsUnordered("EXPR$0=10.6; product_id=1556",
             "EXPR$0=10.6; product_id=1556",
@@ -3792,7 +3792,7 @@ public class DruidAdapterIT {
         + "<= ((floor(\\'store_sales\\') * 25) + 2))'}";
     final String likeExpressionFilter = 
"{'type':'expression','expression':'like(\\'product_id\\'";
     final String likeExpressionFilter2 = "1%";
-    final String simpleBound = 
"{'type':'bound','dimension':'store_cost','lower':'1',"
+    final String simpleBound = 
"{'type':'bound','dimension':'store_cost','lower':'1.0',"
         + "'lowerStrict':true,'ordering':'numeric'}";
     final String timeSimpleFilter =
         
"{'type':'bound','dimension':'__time','upper':'1997-01-02T00:00:00.000Z',"
@@ -3812,12 +3812,12 @@ public class DruidAdapterIT {
     // 1. https://issues.apache.org/jira/browse/CALCITE-2590
     // 2. https://issues.apache.org/jira/browse/CALCITE-2838
     final String booleanAsFilter = 
"{\"type\":\"bound\",\"dimension\":\"store_sales\","
-        + "\"lower\":\"0\",\"lowerStrict\":true,\"ordering\":\"numeric\"}";
+        + "\"lower\":\"0.0\",\"lowerStrict\":true,\"ordering\":\"numeric\"}";
     final String plan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], "
         + "intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], "
         + "filter=[AND(<=(/(+(CAST($1):INTEGER, $90), -($91, 5)), 
+(*(FLOOR($90), 25), 2)), "
-        + ">($90, 0), LIKE($1, '1%'), >($91, 1), <($0, 1997-01-02 00:00:00), "
+        + ">($90, 0.0E0), LIKE($1, '1%'), >($91, 1.0E0), <($0, 1997-01-02 
00:00:00), "
         + "=(EXTRACT(FLAG(MONTH), $0), 1), =(EXTRACT(FLAG(DAY), $0), 1), "
         + "=(+(/(EXTRACT(FLAG(MONTH), $0), 4), 1), 1))], groups=[{}], 
aggs=[[COUNT()]])";
     sql(sql, FOODMART)
@@ -3841,7 +3841,7 @@ public class DruidAdapterIT {
         + " AND ceil(\"timestamp\" TO SECOND) > CAST('1997-01-01' AS 
TIMESTAMP) ";
     final String plan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1997-01-01T00:00:00.001Z/"
-        + "1997-01-04T00:00:00.001Z]], filter=[>(CEIL($90), 1)], groups=[{}], 
aggs=[[COUNT()]])";
+        + "1997-01-04T00:00:00.001Z]], filter=[>(CEIL($90), 1.0E0)], 
groups=[{}], aggs=[[COUNT()]])";
     sql(sql, FOODMART)
         .explainContains(plan)
         .returnsOrdered("EXPR$0=408");
@@ -3923,7 +3923,7 @@ public class DruidAdapterIT {
     sql(sql)
         .queryContains(
             new DruidChecker("\"queryType\":\"groupBy\"", 
"{\"type\":\"bound\","
-                + 
"\"dimension\":\"store_cost\",\"lower\":\"5\",\"lowerStrict\":true,"
+                + 
"\"dimension\":\"store_cost\",\"lower\":\"5.0\",\"lowerStrict\":true,"
                 + "\"ordering\":\"numeric\"}"))
         .runs();
   }
@@ -4010,7 +4010,7 @@ public class DruidAdapterIT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  BindableSort(sort0=[$2], dir0=[ASC], fetch=[3])\n"
             + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20)], 
projects=[[+(COS($90), 1), SIN($91),"
+            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20.0E0)], 
projects=[[+(COS($90), 1), SIN($91),"
             + " +(EXTRACT(FLAG(DAY), $0), 1)]])");
   }
 
@@ -4026,7 +4026,7 @@ public class DruidAdapterIT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  BindableSort(sort0=[$1], dir0=[ASC], fetch=[3])\n"
             + "    DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20)], 
projects=[[+(COS(+($90, $91)), 1), "
+            + "2992-01-10T00:00:00.000Z]], filter=[<($90, 20.0E0)], 
projects=[[+(COS(+($90, $91)), 1), "
             + "+(EXTRACT(FLAG(DAY), $0), 1)]])");
   }
 
@@ -4166,7 +4166,7 @@ public class DruidAdapterIT {
     final String query = 
"{'queryType':'timeseries','dataSource':'foodmart','descending':false,"
         + 
"'granularity':'all','aggregations':[{'type':'filtered','filter':{'type':'or','fields':"
         + 
"[{'type':'selector','dimension':'state_province','value':'CA'},{'type':'and','fields':"
-        + 
"[{'type':'bound','dimension':'store_sales','lower':'100','lowerStrict':true,"
+        + 
"[{'type':'bound','dimension':'store_sales','lower':'100.0','lowerStrict':true,"
         + 
"'ordering':'numeric'},{'type':'not','field':{'type':'selector','dimension':'product_id',"
         + 
"'value':'100'}}]}]},'aggregator':{'type':'filtered','filter':{'type':'not',"
         + 
"'field':{'type':'selector','dimension':'product_id','value':null}},'aggregator':"
@@ -4326,10 +4326,10 @@ public class DruidAdapterIT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
             + "2992-01-10T00:00:00.000Z]], projects=[[$1, $90]], groups=[{0}], 
aggs=[[SUM($1)]], "
-            + "filter=[>($1, 220)], sort0=[0], dir0=[ASC], fetch=[2])")
+            + "filter=[>($1, 220.0E0)], sort0=[0], dir0=[ASC], fetch=[2])")
         .queryContains(
             new 
DruidChecker("'having':{'type':'filter','filter':{'type':'bound',"
-                + 
"'dimension':'S','lower':'220','lowerStrict':true,'ordering':'numeric'}}"));
+                + 
"'dimension':'S','lower':'220.0','lowerStrict':true,'ordering':'numeric'}}"));
     q.returnsOrdered("P=1; S=236.55", "P=10; S=230.04");
   }
 
@@ -4341,7 +4341,7 @@ public class DruidAdapterIT {
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
             + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], 
projects=[[$1, $90]], groups=[{0}],"
-            + " aggs=[[SUM($1)]], filter=[>($1, 220)], sort0=[0], dir0=[ASC], 
fetch=[2])\n")
+            + " aggs=[[SUM($1)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
         .queryContains(
             new 
DruidChecker("{'queryType':'groupBy','dataSource':'foodmart','granularity':'all'"));
     q.returnsOrdered("P=100; S=343.2", "P=1000; S=532.62");

Reply via email to