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


##########
sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveInspectors.scala:
##########
@@ -1122,6 +1258,51 @@ private[hive] trait HiveInspectors {
     case _: JavaVoidObjectInspector => NullType
   }
 
+  /**
+   * Analysis snapshots the Catalyst return type, but runtime inspectors are 
rebuilt from the
+   * current children (including foldability and session CHAR/VARCHAR 
settings). STRING may drift
+   * to or from a bounded string type across that boundary. Two bounded types 
must match exactly:
+   * accepting a different kind or length would apply the snapshotted 
conversion to an incompatible
+   * runtime value.
+   */
+  def checkCompatibleHiveReturnType(
+      inspector: ObjectInspector,
+      expectedType: DataType): Unit = {
+    checkCompatibleHiveReturnType(
+      inspectorToDataType(inspector, preserveCharVarchar = true),
+      expectedType)
+  }
+
+  def checkCompatibleHiveReturnType(
+      runtimeType: DataType,
+      expectedType: DataType): Unit = {
+    if (!compatibleHiveReturnType(runtimeType, expectedType)) {
+      throw SparkException.internalError(
+        s"Hive function runtime type ${runtimeType.catalogString} is 
incompatible " +
+          s"with analysis type ${expectedType.catalogString}.")
+    }
+  }
+
+  private def compatibleHiveReturnType(
+      runtimeType: DataType,
+      expectedType: DataType): Boolean = {
+    (runtimeType, expectedType) match {
+      case (rt: CharType, et: CharType) => rt == et
+      case (rt: VarcharType, et: VarcharType) => rt == et
+      case (_: CharType | _: VarcharType, _: CharType | _: VarcharType) => 
false
+      case (_: StringType, _: CharType | _: VarcharType) => true
+      case (_: CharType | _: VarcharType, _: StringType) => true
+      case (ArrayType(rt, _), ArrayType(et, _)) => 
compatibleHiveReturnType(rt, et)
+      case (MapType(rk, rv, _), MapType(ek, ev, _)) =>
+        compatibleHiveReturnType(rk, ek) && compatibleHiveReturnType(rv, ev)
+      case (rt: StructType, et: StructType) if rt.length == et.length =>
+        rt.fields.zip(et.fields).forall { case (rf, ef) =>

Review Comment:
   Could we include the struct field name in this recursive compatibility 
check? `unwrapperFor(StructObjectInspector, StructType)` pairs runtime 
inspector fields with the snapshotted schema by ordinal, so runtime 
`struct<b:int,a:int>` is currently accepted against analysis 
`struct<a:int,b:int>` and its values are silently exposed under the wrong 
names. Requiring corresponding names to match before recursing keeps the 
snapshot guard from accepting renamed or reordered output.



##########
sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveInspectors.scala:
##########
@@ -897,6 +971,25 @@ private[hive] trait HiveInspectors {
         (value: Any, row: InternalRow, ordinal: Int) => row(ordinal) = 
unwrapper(value)
     }
 
+  /**
+   * Builds an in-place unwrapper using the target Catalyst `dataType` only 
when target-aware
+   * conversion is required. Other types retain the primitive setter fast 
paths.
+   */
+  def unwrapperFor(

Review Comment:
   After Script TRANSFORM support moved to the follow-up, this overload has no 
production caller; the only remaining calls are in `HiveInspectorSuite`. Could 
we remove it and the now-orphaned in-place/nanosecond test coverage from this 
PR, and let the follow-up introduce it together with its production call?



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