srielau commented on code in PR #58080:
URL: https://github.com/apache/spark/pull/58080#discussion_r3817017413


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/basicLogicalOperators.scala:
##########
@@ -184,7 +184,24 @@ object Project {
         if (other == target) {
           col
         } else if (Cast.canANSIStoreAssign(other, target)) {
-          Cast(col, target, Option(conf.sessionLocalTimeZone), ansiEnabled = 
true)
+          // Store assignment must not use character-to-character CAST 
truncation (ISO 6.13).
+          // Cast to unconstrained STRING first, then apply the write-side 
length check.
+          // Avoid replaceCharVarcharWithString: first-class types keep 
CHAR/VARCHAR.
+          val (castTarget, lengthCheckType) = target match {
+            case c: CharType => (c.toStringType, Some(c: DataType))
+            case v: VarcharType => (v.toStringType, Some(v: DataType))
+            case otherType => (otherType, None)
+          }
+          val casted = if (other == castTarget) {
+            col
+          } else {
+            Cast(col, castTarget, Option(conf.sessionLocalTimeZone), 
ansiEnabled = true)
+          }
+          if (lengthCheckType.isDefined && !conf.charVarcharAsString) {

Review Comment:
   This uses the raw legacy `charVarcharAsString` flag, but `standardSemantics` 
takes precedence and keeps CHAR/VARCHAR first-class when both are true. In that 
combination this skips `stringLengthCheck` and returns unconstrained STRING, so 
`Dataset.to` can accept overflow.
   
   Please apply the check whenever the actual target is CHAR/VARCHAR (ignore 
the legacy flag if first-class types are present), and add the combined-config 
regression test. `TableOutputResolver` has the same gate -- worth aligning if 
INSERT can hit it too.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ToStringBase.scala:
##########
@@ -58,12 +58,16 @@ trait ToStringBase { self: UnaryExpression with 
TimeZoneAwareExpression =>
   // Returns a function to convert a value to pretty string. The function 
assumes input is not null.
   protected final def castToString(
       from: DataType, to: StringConstraint = NoConstraint): Any => UTF8String =
-    to match {
-      case FixedLength(length) =>
+    (to, from) match {
+      case (FixedLength(length), _: StringType) if 
SQLConf.get.charVarcharStandardSemantics =>
+        s => CharVarcharCodegenUtils.charTypeCast(castToString(from)(s), 
length)
+      case (MaxLength(length), _: StringType) if 
SQLConf.get.charVarcharStandardSemantics =>

Review Comment:
   This is documented as explicit-CAST truncation, but `ToStringBase` is shared 
by every `Cast` and has no explicit/implicit/store provenance. The Project 
STRING-then-`stringLengthCheck` workaround is a reach-around to recover 
assignment semantics.
   
   Please distinguish explicit CAST vs store assignment (a Cast flag, or one 
centralized store-assignment conversion all write paths use) so a new caller 
cannot inherit truncation by accident.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/CollationTypeCoercion.scala:
##########
@@ -115,6 +123,8 @@ object CollationTypeCoercion extends SQLConfHelper {
 
         expr match {
           case lit: Literal => lit.copy(dataType = newDataType)
+          case cast: Cast if needsCharPaddingCast(cast.dataType, newDataType) 
=>
+            Cast(cast, newDataType, timeZoneId = 
Some(conf.sessionLocalTimeZone))
           case cast: Cast => cast.copy(dataType = newDataType)

Review Comment:
   The CHAR-to-VARCHAR nest fixes the padding case (goldens now show the nested 
cast and `false`). This arm still retargets every other Cast.
   
   With truncating explicit CAST that changes semantics: 
`COALESCE(CAST('abcdef' AS VARCHAR(2)), CAST('x' AS VARCHAR(4)))` can become 
`CAST('abcdef' AS VARCHAR(4))` and return `abcd` instead of preserving `ab`. 
Numeric / TRY_CAST overflow can likewise disappear.
   
   Please preserve the explicit inner Cast and add an outer LCT Cast. Add 
CAST/TRY_CAST character truncation and numeric overflow inside COALESCE/CASE/IN 
(collated and not).



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