LukaZdravic commented on code in PR #58823:
URL: https://github.com/apache/spark/pull/58823#discussion_r4034835762


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/basicLogicalOperators.scala:
##########
@@ -2749,7 +2728,62 @@ object AsOfJoin {
     def isValidOperandType(dataType: DataType): Boolean =
       RowOrdering.isOrderable(dataType) && !containsEmptyStructType(dataType)
 
+    /**
+     * Top-level operand compatibility. A string vs non-string scalar pair is 
compatible only when
+     * the comparison operator has a common type for it, so it coerces like 
`>=` (accepting DATE vs
+     * STRING, rejecting STRING vs INTERVAL). Other scalars widen; 
STRUCT/ARRAY use the stricter
+     * [[areFieldTypesCompatible]] rule.
+     */
     def areOperandsCompatible(leftType: DataType, rightType: DataType): 
Boolean = {
+      if (!isValidOperandType(leftType) || !isValidOperandType(rightType)) {
+        false
+      } else if (isCompositeOperand(leftType, rightType)) {
+        areFieldTypesCompatible(leftType, rightType)
+      } else if (isExactlyOneStringPair(leftType, rightType)) {
+        matchComparisonCommonType(leftType, rightType).isDefined
+      } else {
+        TypeCoercion.findWiderTypeForTwo(leftType, rightType).isDefined
+      }
+    }
+
+    /**
+     * The type a string vs non-string scalar pair is cast to for comparison, 
ordering, and sort,
+     * mirroring the comparison operator's string coercion in the active mode 
(ANSI or default).
+     * Returns [[None]] for other pairs, whose monotonic widening keeps the 
raw operands.
+     */
+    private[catalyst] def matchComparisonCommonType(
+        leftType: DataType,
+        rightType: DataType): Option[DataType] = {
+      if (!isExactlyOneStringPair(leftType, rightType)) {
+        None
+      } else {
+        val commonType = if (SQLConf.get.ansiEnabled) {
+          AnsiStringPromotionTypeCoercion.findWiderTypeForString(leftType, 
rightType)
+        } else {
+          TypeCoercion.findCommonTypeForBinaryComparison(leftType, rightType, 
SQLConf.get)
+        }
+        commonType.filter(isValidOperandType)
+      }
+    }
+
+    /**
+     * True when either operand is a STRUCT or ARRAY. These keep the stricter 
widening rule and are
+     * left uncoerced; [[areOperandsCompatible]] and the leaf coercion both 
branch on this.
+     */
+    private[catalyst] def isCompositeOperand(
+        leftType: DataType,
+        rightType: DataType): Boolean =
+      Seq(leftType, rightType).exists(t => t.isInstanceOf[StructType] || 
t.isInstanceOf[ArrayType])
+
+    /** True when exactly one operand is a string, the only pair that needs 
comparison coercion. */
+    private def isExactlyOneStringPair(leftType: DataType, rightType: 
DataType): Boolean =
+      leftType.isInstanceOf[StringType] != rightType.isInstanceOf[StringType]

Review Comment:
   Order is now the same as the other appearance, thank you!



-- 
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]


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

Reply via email to