sunchao commented on code in PR #56575:
URL: https://github.com/apache/spark/pull/56575#discussion_r3816855959


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringExpressions.scala:
##########
@@ -2690,29 +2690,40 @@ case class Substring(str: Expression, pos: Expression, 
len: Expression)
   since = "2.3.0",
   group = "string_funcs")
 // scalastyle:on line.size.limit
-case class Right(str: Expression, len: Expression) extends RuntimeReplaceable
-  with ImplicitCastInputTypes with BinaryLike[Expression] {
-
-  override lazy val replacement: Expression = If(
-    IsNull(str),
-    Literal(null, str.dataType),
-    If(
-      LessThanOrEqual(len, Literal(0)),
-      Literal(UTF8String.EMPTY_UTF8, str.dataType),
-      new Substring(str, UnaryMinus(len, failOnError = false))
-    )
-  )
+object Right extends DelegateFunction {
+  override val name: String = "right"
 
   override def inputTypes: Seq[AbstractDataType] =
-    Seq(
-      StringTypeWithCollation(supportsTrimCollation = true),
-      IntegerType
-    )
-  override def left: Expression = str
-  override def right: Expression = len
-  override protected def withNewChildrenInternal(
-      newLeft: Expression, newRight: Expression): Expression = {
-    copy(str = newLeft, len = newRight)
+    Seq(StringTypeWithCollation(supportsTrimCollation = true), IntegerType)
+
+  // At build time `str` is the not-yet-coerced argument (wrapped in an 
`ImplicitCastInput` marker
+  // that delegates `dataType` to its child), so `str.dataType` is the *input* 
type, which is not
+  // necessarily a string yet -- e.g. `right(12345, 2)` has an `IntegerType` 
child the implicit cast
+  // will turn into a string. Use it for the null/empty branch literals only 
when it is already a
+  // string-family type, so a CHAR(N)/VARCHAR(N) result (under
+  // `spark.sql.preserveCharVarcharTypeInfo`) or a non-default collation is 
preserved through the
+  // `If` branch unification; otherwise fall back to plain `StringType`, the 
type the implicit cast
+  // produces. Typing a UTF8String literal with a non-string type would be 
invalid.
+  override def lower(args: Seq[Expression]): Expression = {
+    val str = args(0)
+    val len = args(1)
+    val litType = str.dataType match {
+      case _: StringType | _: CharType | _: VarcharType => str.dataType
+      case _ => StringType
+    }
+    // Keep both arguments single-use while the analyzer extracts window 
expressions. The length
+    // is bound inside the non-null branch so right's null short-circuit is 
preserved.
+    With(str) { case Seq(strRef) =>

Review Comment:
   [P2] Follow-up on `0a33bc17`: the new constant-evaluation fix is still 
incomplete under the fixed-point analyzer.
   
   
[`EvalHelper.prepareForEval`](https://github.com/apache/spark/blob/0a33bc177b56b174a63bb7f83a82f40e026ceae6/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/EvalHelper.scala#L27-L39)
 now unwraps delegates and `With`, but it leaves valid, resolved 
`ImplicitCastInput`/`TypeCheckInput` markers in the result. 
`ResolveInlineTables` and `ResolveIdentifierClause` run during Resolution, 
before the separate `RemoveInputTypeMarkers` batch. Those markers are resolved 
but still `Unevaluable` and nonfoldable.
   
   Both of these reproduce on the current head with fixed-point analysis:
   
   ```sql
   VALUES (right('abc', 1));
   SELECT IDENTIFIER(right('xxa', 1)) FROM VALUES (1) AS t(a);
   ```
   
   The first still raises 
`INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE`; the second 
raises `NOT_A_CONSTANT_STRING.NOT_CONSTANT`. The newly added `right() supports 
constant inline-table values` test also fails in the existing SQL suite. Could 
preparation recurse into the children of **resolved** input markers, while 
retaining failed markers for proper type-error reporting?



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