voonhous commented on code in PR #19475:
URL: https://github.com/apache/hudi/pull/19475#discussion_r4452790255


##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/spark/sql/HoodieSparkTypeUtils.scala:
##########
@@ -35,10 +36,24 @@ object HoodieSparkTypeUtils {
    */
   def isCastPreservingOrdering(from: DataType, to: DataType): Boolean =
     (from, to) match {
-      // NOTE: In the casting rules defined by Spark, only casting from String 
to Numeric
-      // (and vice versa) are the only casts that might break the ordering of 
the elements after casting
+      // NOTE: Casting between String and Numeric types re-orders elements 
(for ex, "10" < "9"
+      //       lexicographically)
       case (StringType, _: NumericType) => false
       case (_: NumericType, StringType) => false
+      // NOTE: Cast.canUpCast rejects decimal to float/double as lossy, but 
rounding is monotonic
+      //       and every decimal fits within float range. Spark's type 
coercion inserts this cast
+      //       when a decimal column is compared with a float/double (for ex, 
`price > 99.5D`)
+      case (_: DecimalType, FloatType | DoubleType) => true
+      // NOTE: Narrowing numeric casts (for ex, bigint to int) overflow and 
wrap around in
+      //       non-ANSI mode, breaking ordering; only up-casts are guaranteed 
order-preserving.
+      //       This is conservative (for ex, double to float rounds 
monotonically but is
+      //       rejected), which only costs pruning opportunity, never 
correctness
+      case (fromNum: NumericType, toNum: NumericType) => 
Cast.canUpCast(fromNum, toNum)
+      // NOTE: Timestamps cast to numbers through their epoch seconds, which 
only fit bigint and
+      //       floating-point targets; narrower integral targets wrap around 
and decimals overflow
+      //       into NULL in non-ANSI mode
+      case (TimestampType, LongType | FloatType | DoubleType) => true
+      case (TimestampType, _: NumericType) => false
 
       case _ => true

Review Comment:
   Both are rejected now in e3265df. I rejected every non-boolean cast to 
boolean, not just numeric ones, because string to boolean breaks the same way.
   
   I added a test for each in `TestDataSkippingUtils`. Both fail without the 
fix:
   - `CAST(C AS STRING) > '2026-11-01 01:20:00'` in America/New_York, which is 
your probe case. The file holds 01:30 EDT and 01:10 EST, and the 01:30 row 
matches but the file was skipped.
   - `CAST(A AS BOOLEAN) = false` on a file with min -5 and max 5. Both bounds 
become `true`, so the file was skipped even though it holds a 0.
   
   Deny-by-default is the better shape. #20458 rewrites the same match, so I'd 
rather flip it once that lands than stack a third conflicting change here. I'll 
track it on the #19445 checklist.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to