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


##########
sql/core/src/main/scala/org/apache/spark/sql/execution/BaseScriptTransformationExec.scala:
##########
@@ -62,6 +80,12 @@ trait BaseScriptTransformationExec extends UnaryExecNode {
 
   override def outputPartitioning: Partitioning = child.outputPartitioning
 
+  // Snapshot at plan construction. CHAR_VARCHAR_STANDARD_SEMANTICS is 
PERSISTED, so a
+  // plan built under one setting must keep that path even if a later task 
SQLConf.get
+  // (ReadOnlySQLConf with the executing session) differs. SparkPlan.session is
+  // @transient, so executor `conf` cannot recover the planning session.
+  private val standardCharVarcharSemantics: Boolean = 
conf.charVarcharStandardSemantics

Review Comment:
   Addressed. `ScriptInputOutputSchema` now captures 
`standardCharVarcharSemantics` at parse under the query or persisted-view 
SQLConf, and `ScriptTransformationIOSchema` copies that value. The physical 
operator no longer snapshots `SQLConf` at plan construction.



##########
sql/hive/src/main/scala/org/apache/spark/sql/hive/execution/HiveScriptTransformationExec.scala:
##########
@@ -268,6 +273,24 @@ object HiveScriptIOSchema extends HiveInspectors {
     (columns, columnTypes)
   }
 
+  /**
+   * Hive LazySimpleSerDe CHAR/VARCHAR types truncate on deserialize. Under 
standard
+   * semantics, map them to STRING so Spark applies length checks. Only 
LazySimpleSerDe
+   * and subclasses get this rewrite; other SerDes keep the declared schema.
+   * preserveCharVarcharTypeInfo without standard semantics is unchanged.
+   */
+  private def outputTypesForSerDe(
+      serdeClassName: String,
+      columnTypes: Seq[DataType]): Seq[DataType] = {
+    val serdeClass = Utils.classForName[AbstractSerDe](serdeClassName)
+    if (SQLConf.get.charVarcharStandardSemantics &&

Review Comment:
   Addressed. Hive LazySimpleSerDe CHAR/VARCHAR rewrite now uses 
`ioschema.standardCharVarcharSemantics` instead of `SQLConf.get`, so a later 
session or task conf cannot change the wire schema.



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/BaseScriptTransformationExec.scala:
##########
@@ -376,6 +442,106 @@ case class ScriptTransformationIOSchema(
 }
 
 object ScriptTransformationIOSchema {
+  private[sql] def toUnboundedStringType(dataType: DataType): DataType = {
+    dataType.transformRecursively {
+      case c: CharType => c.toStringType
+      case v: VarcharType => v.toStringType
+    }
+  }
+
+  // JSON object keys are always strings. Rewrite every map key, including 
nested maps.
+  // `transformRecursively` would stop at the first matching MapType and skip 
children.
+  private[sql] def toJsonMapKeyType(dataType: DataType): DataType = dataType 
match {
+    case ArrayType(et, n) => ArrayType(toJsonMapKeyType(et), n)
+    case MapType(kt, vt, n) =>
+      val jsonKey = if (kt.isInstanceOf[StringType]) kt else StringType
+      MapType(jsonKey, toJsonMapKeyType(vt), n)
+    case StructType(fields) =>
+      StructType(fields.map(f => f.copy(dataType = 
toJsonMapKeyType(f.dataType))))
+    case other => other
+  }
+
+  /**
+   * Convert a Catalyst value from `sourceType` (JSON or unbounded STRING) to

Review Comment:
   Updated the Scaladoc. `sourceType` is the parsed Catalyst type, and maps 
rebuild through `ArrayBasedMapBuilder` only when the source and target map 
types differ or the target contains CHAR/VARCHAR.



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