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

viirya pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new 7a6f47f8 fix: Normalize NaN and zeros for floating number comparison 
(#953)
7a6f47f8 is described below

commit 7a6f47f8a3d16c2b94009e633f38ea40d7f573ee
Author: Liang-Chi Hsieh <[email protected]>
AuthorDate: Sun Sep 22 14:09:39 2024 -0700

    fix: Normalize NaN and zeros for floating number comparison (#953)
    
    * fix: Normalize NaN and zeros for floating number comparison
    
    * fix
    
    * fix
    
    * update
    
    * Add doc
---
 docs/source/user-guide/compatibility.md            |  8 ++++
 .../apache/comet/CometSparkSessionExtensions.scala | 52 +++++++++++++++++++++-
 .../approved-plans-v1_4-spark3_5/q21/explain.txt   |  2 +-
 .../approved-plans-v1_4-spark3_5/q34/explain.txt   |  2 +-
 .../approved-plans-v1_4-spark3_5/q39a/explain.txt  |  8 ++--
 .../approved-plans-v1_4-spark3_5/q39b/explain.txt  |  8 ++--
 .../approved-plans-v1_4-spark3_5/q73/explain.txt   |  2 +-
 .../approved-plans-v1_4-spark4_0/q21/explain.txt   |  2 +-
 .../approved-plans-v1_4-spark4_0/q34/explain.txt   |  2 +-
 .../approved-plans-v1_4-spark4_0/q39a/explain.txt  |  8 ++--
 .../approved-plans-v1_4-spark4_0/q39b/explain.txt  |  8 ++--
 .../approved-plans-v1_4-spark4_0/q73/explain.txt   |  2 +-
 .../approved-plans-v1_4/q21/explain.txt            |  2 +-
 .../approved-plans-v1_4/q34/explain.txt            |  2 +-
 .../approved-plans-v1_4/q39a/explain.txt           |  8 ++--
 .../approved-plans-v1_4/q39b/explain.txt           |  8 ++--
 .../approved-plans-v1_4/q73/explain.txt            |  2 +-
 .../approved-plans-v2_7-spark3_5/q34/explain.txt   |  2 +-
 .../approved-plans-v2_7-spark4_0/q34/explain.txt   |  2 +-
 .../approved-plans-v2_7/q34/explain.txt            |  2 +-
 .../org/apache/comet/CometExpressionSuite.scala    | 16 +++++++
 21 files changed, 110 insertions(+), 38 deletions(-)

diff --git a/docs/source/user-guide/compatibility.md 
b/docs/source/user-guide/compatibility.md
index 5e849992..031322e9 100644
--- a/docs/source/user-guide/compatibility.md
+++ b/docs/source/user-guide/compatibility.md
@@ -38,6 +38,14 @@ Comet uses the Rust regexp crate for evaluating regular 
expressions, and this ha
 regular expression engine. Comet will fall back to Spark for patterns that are 
known to produce different results, but
 this can be overridden by setting `spark.comet.regexp.allowIncompatible=true`.
 
+## Floating number comparison
+
+Spark normalizes NaN and zero for floating point numbers for several cases. 
See `NormalizeFloatingNumbers` optimization rule in Spark.
+However, one exception is comparison. Spark does not normalize NaN and zero 
when comparing values
+because they are handled well in Spark (e.g., 
`SQLOrderingUtil.compareFloats`). But the comparison
+functions of arrow-rs used by DataFusion do not normalize NaN and zero (e.g., 
[arrow::compute::kernels::cmp::eq](https://docs.rs/arrow/latest/arrow/compute/kernels/cmp/fn.eq.html#)).
+So Comet will add additional normalization expression of NaN and zero for 
comparison.
+
 ## Cast
 
 Cast operations in Comet fall into three levels of support:
diff --git 
a/spark/src/main/scala/org/apache/comet/CometSparkSessionExtensions.scala 
b/spark/src/main/scala/org/apache/comet/CometSparkSessionExtensions.scala
index e4057fff..7190ab54 100644
--- a/spark/src/main/scala/org/apache/comet/CometSparkSessionExtensions.scala
+++ b/spark/src/main/scala/org/apache/comet/CometSparkSessionExtensions.scala
@@ -25,8 +25,9 @@ import org.apache.spark.SparkConf
 import org.apache.spark.internal.Logging
 import org.apache.spark.network.util.ByteUnit
 import org.apache.spark.sql.{SparkSession, SparkSessionExtensions}
-import org.apache.spark.sql.catalyst.expressions.{Expression, PlanExpression}
+import org.apache.spark.sql.catalyst.expressions.{EqualNullSafe, EqualTo, 
Expression, GreaterThan, GreaterThanOrEqual, KnownFloatingPointNormalized, 
LessThan, LessThanOrEqual, NamedExpression, PlanExpression}
 import org.apache.spark.sql.catalyst.expressions.aggregate.{Final, Partial}
+import org.apache.spark.sql.catalyst.optimizer.NormalizeNaNAndZero
 import org.apache.spark.sql.catalyst.rules.Rule
 import org.apache.spark.sql.catalyst.trees.TreeNode
 import org.apache.spark.sql.comet._
@@ -47,6 +48,7 @@ import 
org.apache.spark.sql.execution.exchange.{BroadcastExchangeExec, ReusedExc
 import org.apache.spark.sql.execution.joins.{BroadcastHashJoinExec, 
ShuffledHashJoinExec, SortMergeJoinExec}
 import org.apache.spark.sql.execution.window.WindowExec
 import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.types.{DoubleType, FloatType}
 
 import org.apache.comet.CometConf._
 import org.apache.comet.CometExplainInfo.getActualPlan
@@ -840,6 +842,52 @@ class CometSparkSessionExtensions
       }
     }
 
+    def normalizePlan(plan: SparkPlan): SparkPlan = {
+      plan.transformUp {
+        case p: ProjectExec =>
+          val newProjectList = 
p.projectList.map(normalize(_).asInstanceOf[NamedExpression])
+          ProjectExec(newProjectList, p.child)
+        case f: FilterExec =>
+          val newCondition = normalize(f.condition)
+          FilterExec(newCondition, f.child)
+      }
+    }
+
+    // Spark will normalize NaN and zero for floating point numbers for 
several cases.
+    // See `NormalizeFloatingNumbers` optimization rule in Spark.
+    // However, one exception is for comparison operators. Spark does not 
normalize NaN and zero
+    // because they are handled well in Spark (e.g., 
`SQLOrderingUtil.compareFloats`). But the
+    // comparison functions in arrow-rs do not normalize NaN and zero. So we 
need to normalize NaN
+    // and zero for comparison operators in Comet.
+    def normalize(expr: Expression): Expression = {
+      expr.transformUp {
+        case EqualTo(left, right) =>
+          EqualTo(normalizeNaNAndZero(left), normalizeNaNAndZero(right))
+        case EqualNullSafe(left, right) =>
+          EqualNullSafe(normalizeNaNAndZero(left), normalizeNaNAndZero(right))
+        case GreaterThan(left, right) =>
+          GreaterThan(normalizeNaNAndZero(left), normalizeNaNAndZero(right))
+        case GreaterThanOrEqual(left, right) =>
+          GreaterThanOrEqual(normalizeNaNAndZero(left), 
normalizeNaNAndZero(right))
+        case LessThan(left, right) =>
+          LessThan(normalizeNaNAndZero(left), normalizeNaNAndZero(right))
+        case LessThanOrEqual(left, right) =>
+          LessThanOrEqual(normalizeNaNAndZero(left), 
normalizeNaNAndZero(right))
+      }
+    }
+
+    def normalizeNaNAndZero(expr: Expression): Expression = {
+      expr match {
+        case _: KnownFloatingPointNormalized => expr
+        case _ =>
+          expr.dataType match {
+            case _: FloatType | _: DoubleType =>
+              KnownFloatingPointNormalized(NormalizeNaNAndZero(expr))
+            case _ => expr
+          }
+      }
+    }
+
     override def apply(plan: SparkPlan): SparkPlan = {
       // DataFusion doesn't have ANSI mode. For now we just disable CometExec 
if ANSI mode is
       // enabled.
@@ -865,7 +913,7 @@ class CometSparkSessionExtensions
           plan
         }
       } else {
-        var newPlan = transform(plan)
+        var newPlan = transform(normalizePlan(plan))
 
         // if the plan cannot be run fully natively then explain why (when 
appropriate
         // config is enabled)
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q21/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q21/explain.txt
index dce72db2..e432933e 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q21/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q21/explain.txt
@@ -129,7 +129,7 @@ Functions [2]: [sum(CASE WHEN (d_date#12 < 2000-03-11) THEN 
inv_quantity_on_hand
 
 (22) CometFilter
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#15, inv_after#16]
-Condition : (CASE WHEN (inv_before#15 > 0) THEN ((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)) >= 0.666667) END AND CASE WHEN (inv_before#15 
> 0) THEN ((cast(inv_after#16 as double) / cast(inv_before#15 as double)) <= 
1.5) END)
+Condition : (CASE WHEN (inv_before#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)))) >= 
knownfloatingpointnormalized(normalizenanandzero(0.666667))) END AND CASE WHEN 
(inv_before#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)))) <= 
knownfloatingpointnormalized(normalizenanandzero(1.5))) END)
 
 (23) CometTakeOrderedAndProject
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#15, inv_after#16]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q34/explain.txt
index dccad575..7cfddd6a 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39a/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39a/explain.txt
index 58e0e664..96e213ff 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39a/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39a/explain.txt
@@ -152,11 +152,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#3 
as double)), avg(inv_qua
 
 (22) CometFilter
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (23) CometProject
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN (mean#18 = 0.0) 
THEN null ELSE (stdev#17 / mean#18) END AS cov#19]
+Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#19]
 
 (24) Scan parquet spark_catalog.default.inventory
 Output [4]: [inv_item_sk#20, inv_warehouse_sk#21, inv_quantity_on_hand#22, 
inv_date_sk#23]
@@ -238,11 +238,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#22 
as double)), avg(inv_qu
 
 (41) CometFilter
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (42) CometProject
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(mean#18 = 0.0) THEN null ELSE (stdev#17 / mean#18) END AS cov#37]
+Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#37]
 
 (43) CometBroadcastExchange
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39b/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39b/explain.txt
index c246e93a..90b948ef 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39b/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q39b/explain.txt
@@ -152,11 +152,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#3 
as double)), avg(inv_qua
 
 (22) CometFilter
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Condition : (CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END AND CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.5) END)
+Condition : (CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END AND CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((s [...]
 
 (23) CometProject
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN (mean#18 = 0.0) 
THEN null ELSE (stdev#17 / mean#18) END AS cov#19]
+Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#19]
 
 (24) Scan parquet spark_catalog.default.inventory
 Output [4]: [inv_item_sk#20, inv_warehouse_sk#21, inv_quantity_on_hand#22, 
inv_date_sk#23]
@@ -238,11 +238,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#22 
as double)), avg(inv_qu
 
 (41) CometFilter
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (42) CometProject
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(mean#18 = 0.0) THEN null ELSE (stdev#17 / mean#18) END AS cov#37]
+Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#37]
 
 (43) CometBroadcastExchange
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q73/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q73/explain.txt
index 8b4e36c9..7530f5aa 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q73/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark3_5/q73/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.0) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q21/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q21/explain.txt
index b2f81dbc..de5cc951 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q21/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q21/explain.txt
@@ -136,7 +136,7 @@ Results [4]: [w_warehouse_name#7, i_item_id#9, sum(CASE 
WHEN (d_date#12 < 2000-0
 
 (23) Filter [codegen id : 2]
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#19, inv_after#20]
-Condition : (CASE WHEN (inv_before#19 > 0) THEN ((cast(inv_after#20 as double) 
/ cast(inv_before#19 as double)) >= 0.666667) END AND CASE WHEN (inv_before#19 
> 0) THEN ((cast(inv_after#20 as double) / cast(inv_before#19 as double)) <= 
1.5) END)
+Condition : (CASE WHEN (inv_before#19 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#20 as double) 
/ cast(inv_before#19 as double)))) >= 
knownfloatingpointnormalized(normalizenanandzero(0.666667))) END AND CASE WHEN 
(inv_before#19 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#20 as double) 
/ cast(inv_before#19 as double)))) <= 
knownfloatingpointnormalized(normalizenanandzero(1.5))) END)
 
 (24) TakeOrderedAndProject
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#19, inv_after#20]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q34/explain.txt
index dccad575..7cfddd6a 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39a/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39a/explain.txt
index 33cc5e3f..ac784651 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39a/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39a/explain.txt
@@ -161,10 +161,10 @@ Results [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, 
stddev_samp(cast(inv_quan
 
 (23) Filter [codegen id : 4]
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#24, mean#25]
-Condition : CASE WHEN (mean#25 = 0.0) THEN false ELSE ((stdev#24 / mean#25) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#25)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#24 / mean#25))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (24) Project [codegen id : 4]
-Output [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#25, CASE WHEN 
(mean#25 = 0.0) THEN null ELSE (stdev#24 / mean#25) END AS cov#26]
+Output [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#25, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#25)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#24 / mean#25) END AS cov#26]
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#24, mean#25]
 
 (25) Scan parquet spark_catalog.default.inventory
@@ -254,10 +254,10 @@ Results [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, 
stddev_samp(cast(inv_qu
 
 (43) Filter [codegen id : 3]
 Input [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, stdev#48, mean#49]
-Condition : CASE WHEN (mean#49 = 0.0) THEN false ELSE ((stdev#48 / mean#49) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#49)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#48 / mean#49))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (44) Project [codegen id : 3]
-Output [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, mean#49, CASE WHEN 
(mean#49 = 0.0) THEN null ELSE (stdev#48 / mean#49) END AS cov#50]
+Output [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, mean#49, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#49)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#48 / mean#49) END AS cov#50]
 Input [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, stdev#48, mean#49]
 
 (45) BroadcastExchange
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39b/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39b/explain.txt
index d9135d90..39b03000 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39b/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q39b/explain.txt
@@ -161,10 +161,10 @@ Results [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, 
stddev_samp(cast(inv_quan
 
 (23) Filter [codegen id : 4]
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#24, mean#25]
-Condition : (CASE WHEN (mean#25 = 0.0) THEN false ELSE ((stdev#24 / mean#25) > 
1.0) END AND CASE WHEN (mean#25 = 0.0) THEN false ELSE ((stdev#24 / mean#25) > 
1.5) END)
+Condition : (CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#25)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#24 / mean#25))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END AND CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#25)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((s [...]
 
 (24) Project [codegen id : 4]
-Output [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#25, CASE WHEN 
(mean#25 = 0.0) THEN null ELSE (stdev#24 / mean#25) END AS cov#26]
+Output [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#25, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#25)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#24 / mean#25) END AS cov#26]
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#24, mean#25]
 
 (25) Scan parquet spark_catalog.default.inventory
@@ -254,10 +254,10 @@ Results [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, 
stddev_samp(cast(inv_qu
 
 (43) Filter [codegen id : 3]
 Input [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, stdev#48, mean#49]
-Condition : CASE WHEN (mean#49 = 0.0) THEN false ELSE ((stdev#48 / mean#49) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#49)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#48 / mean#49))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (44) Project [codegen id : 3]
-Output [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, mean#49, CASE WHEN 
(mean#49 = 0.0) THEN null ELSE (stdev#48 / mean#49) END AS cov#50]
+Output [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, mean#49, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#49)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#48 / mean#49) END AS cov#50]
 Input [5]: [w_warehouse_sk#33, i_item_sk#32, d_moy#37, stdev#48, mean#49]
 
 (45) BroadcastExchange
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q73/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q73/explain.txt
index 8b4e36c9..7530f5aa 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q73/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4-spark4_0/q73/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.0) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q21/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q21/explain.txt
index dce72db2..e432933e 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q21/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q21/explain.txt
@@ -129,7 +129,7 @@ Functions [2]: [sum(CASE WHEN (d_date#12 < 2000-03-11) THEN 
inv_quantity_on_hand
 
 (22) CometFilter
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#15, inv_after#16]
-Condition : (CASE WHEN (inv_before#15 > 0) THEN ((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)) >= 0.666667) END AND CASE WHEN (inv_before#15 
> 0) THEN ((cast(inv_after#16 as double) / cast(inv_before#15 as double)) <= 
1.5) END)
+Condition : (CASE WHEN (inv_before#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)))) >= 
knownfloatingpointnormalized(normalizenanandzero(0.666667))) END AND CASE WHEN 
(inv_before#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(inv_after#16 as double) 
/ cast(inv_before#15 as double)))) <= 
knownfloatingpointnormalized(normalizenanandzero(1.5))) END)
 
 (23) CometTakeOrderedAndProject
 Input [4]: [w_warehouse_name#7, i_item_id#9, inv_before#15, inv_after#16]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q34/explain.txt
index dccad575..7cfddd6a 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39a/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39a/explain.txt
index 58e0e664..96e213ff 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39a/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39a/explain.txt
@@ -152,11 +152,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#3 
as double)), avg(inv_qua
 
 (22) CometFilter
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (23) CometProject
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN (mean#18 = 0.0) 
THEN null ELSE (stdev#17 / mean#18) END AS cov#19]
+Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#19]
 
 (24) Scan parquet spark_catalog.default.inventory
 Output [4]: [inv_item_sk#20, inv_warehouse_sk#21, inv_quantity_on_hand#22, 
inv_date_sk#23]
@@ -238,11 +238,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#22 
as double)), avg(inv_qu
 
 (41) CometFilter
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (42) CometProject
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(mean#18 = 0.0) THEN null ELSE (stdev#17 / mean#18) END AS cov#37]
+Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#37]
 
 (43) CometBroadcastExchange
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39b/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39b/explain.txt
index c246e93a..90b948ef 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39b/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q39b/explain.txt
@@ -152,11 +152,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#3 
as double)), avg(inv_qua
 
 (22) CometFilter
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Condition : (CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END AND CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.5) END)
+Condition : (CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END AND CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((s [...]
 
 (23) CometProject
 Input [5]: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN (mean#18 = 0.0) 
THEN null ELSE (stdev#17 / mean#18) END AS cov#19]
+Arguments: [w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, cov#19], 
[w_warehouse_sk#7, i_item_sk#6, d_moy#11, mean#18, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#19]
 
 (24) Scan parquet spark_catalog.default.inventory
 Output [4]: [inv_item_sk#20, inv_warehouse_sk#21, inv_quantity_on_hand#22, 
inv_date_sk#23]
@@ -238,11 +238,11 @@ Functions [2]: [stddev_samp(cast(inv_quantity_on_hand#22 
as double)), avg(inv_qu
 
 (41) CometFilter
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Condition : CASE WHEN (mean#18 = 0.0) THEN false ELSE ((stdev#17 / mean#18) > 
1.0) END
+Condition : CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN false ELSE 
(knownfloatingpointnormalized(normalizenanandzero((stdev#17 / mean#18))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END
 
 (42) CometProject
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, stdev#17, mean#18]
-Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(mean#18 = 0.0) THEN null ELSE (stdev#17 / mean#18) END AS cov#37]
+Arguments: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37], 
[w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#18 AS mean#36, CASE WHEN 
(knownfloatingpointnormalized(normalizenanandzero(mean#18)) = 
knownfloatingpointnormalized(normalizenanandzero(0.0))) THEN null ELSE 
(stdev#17 / mean#18) END AS cov#37]
 
 (43) CometBroadcastExchange
 Input [5]: [w_warehouse_sk#26, i_item_sk#25, d_moy#30, mean#36, cov#37]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q73/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q73/explain.txt
index 8b4e36c9..7530f5aa 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q73/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v1_4/q73/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.0) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.0))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark3_5/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark3_5/q34/explain.txt
index a8800a70..dd509720 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark3_5/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark3_5/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark4_0/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark4_0/q34/explain.txt
index a8800a70..dd509720 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark4_0/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7-spark4_0/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7/q34/explain.txt
 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7/q34/explain.txt
index a8800a70..dd509720 100644
--- 
a/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7/q34/explain.txt
+++ 
b/spark/src/test/resources/tpcds-plan-stability/approved-plans-v2_7/q34/explain.txt
@@ -110,7 +110,7 @@ ReadSchema: 
struct<hd_demo_sk:int,hd_buy_potential:string,hd_dep_count:int,hd_ve
 
 (16) CometFilter
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
-Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
((cast(hd_dep_count#14 as double) / cast(hd_vehicle_count#15 as double)) > 1.2) 
END) AND isnotnull(hd_demo_sk#12))
+Condition : ((((isnotnull(hd_vehicle_count#15) AND ((hd_buy_potential#13 = 
>10000         ) OR (hd_buy_potential#13 = unknown        ))) AND 
(hd_vehicle_count#15 > 0)) AND CASE WHEN (hd_vehicle_count#15 > 0) THEN 
(knownfloatingpointnormalized(normalizenanandzero((cast(hd_dep_count#14 as 
double) / cast(hd_vehicle_count#15 as double)))) > 
knownfloatingpointnormalized(normalizenanandzero(1.2))) END) AND 
isnotnull(hd_demo_sk#12))
 
 (17) CometProject
 Input [4]: [hd_demo_sk#12, hd_buy_potential#13, hd_dep_count#14, 
hd_vehicle_count#15]
diff --git a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala 
b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
index 3a1e9071..7cd7ebca 100644
--- a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
@@ -41,6 +41,22 @@ import 
org.apache.comet.CometSparkSessionExtensions.{isSpark33Plus, isSpark34Plu
 class CometExpressionSuite extends CometTestBase with AdaptiveSparkPlanHelper {
   import testImplicits._
 
+  test("compare true/false to negative zero") {
+    Seq(false, true).foreach { dictionary =>
+      withSQLConf("parquet.enable.dictionary" -> dictionary.toString) {
+        val table = "test"
+        withTable(table) {
+          sql(s"create table $table(col1 boolean, col2 float) using parquet")
+          sql(s"insert into $table values(true, -0.0)")
+          sql(s"insert into $table values(false, -0.0)")
+
+          checkSparkAnswerAndOperator(
+            s"SELECT col1, negative(col2), cast(col1 as float), col1 = 
negative(col2) FROM $table")
+        }
+      }
+    }
+  }
+
   test("coalesce should return correct datatype") {
     Seq(true, false).foreach { dictionaryEnabled =>
       withTempDir { dir =>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to