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


##########
connector/avro/src/main/scala/org/apache/spark/sql/avro/AvroDataToCatalyst.scala:
##########
@@ -25,24 +25,46 @@ import org.apache.avro.io.{BinaryDecoder, DecoderFactory}
 import org.apache.spark.SparkException
 import org.apache.spark.sql.catalyst.expressions.{ExpectsInputTypes, 
Expression, SpecificInternalRow, UnaryExpression}
 import org.apache.spark.sql.catalyst.expressions.codegen.{CodegenContext, 
CodeGenerator, ExprCode}
-import org.apache.spark.sql.catalyst.util.{FailFastMode, ParseMode, 
PermissiveMode}
+import org.apache.spark.sql.catalyst.util.{CharVarcharUtils, FailFastMode, 
ParseMode, PermissiveMode}
 import org.apache.spark.sql.errors.QueryCompilationErrors
+import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types._
 
 case class AvroDataToCatalyst(
     child: Expression,
     jsonFormatSchema: String,
-    options: Map[String, String])
+    options: Map[String, String],
+    // PERSISTED: capture at analysis (like JsonToStructs) so copy()/views keep
+    // creation-time CHAR/VARCHAR map-key checks, not the caller's session 
setting.
+    // No default args: TreeNode.makeCopy would otherwise re-read live SQLConf.
+    charVarcharStandardSemantics: Boolean,
+    charVarcharFirstClassTypes: Boolean)
   extends UnaryExpression with ExpectsInputTypes {
 
+  // Tests and 3-arg apply capture the current session flags.
+  def this(child: Expression, jsonFormatSchema: String, options: Map[String, 
String]) =
+    this(
+      child,
+      jsonFormatSchema,
+      options,
+      SQLConf.get.charVarcharStandardSemantics,
+      SQLConf.get.charVarcharFirstClassTypes)
+
   override def inputTypes: Seq[AbstractDataType] = Seq(BinaryType)
 
   override lazy val dataType: DataType = {
-    val dt = SchemaConverters.toSqlType(
+    val converted = SchemaConverters.toSqlType(
       expectedSchema,
       avroOptions.useStableIdForUnionType,
       avroOptions.stableIdPrefixForUnionType,
       avroOptions.recursiveFieldMaxDepth).dataType
+    // SchemaConverters restores CHAR/VARCHAR stamps from Avro even when 
first-class types
+    // are off. Use the analysis-time snapshot so copy() cannot drop CHAR map 
keys.
+    val dt = if (charVarcharFirstClassTypes) {
+      converted
+    } else {
+      CharVarcharUtils.replaceCharVarcharWithString(converted)

Review Comment:
   Fixed in 882633ae4e9: `dataType` now uses 
`CharVarcharUtils.replaceCharVarcharWithStringAlways` when the persisted 
snapshot is false, so a copy in a first-class session cannot revive 
CHAR/VARCHAR. Added a temp-view test that creates from_avro with both flags off 
and queries it after SET standardSemantics true; the column stays STRING and 
the over-long value is unchanged.



##########
connector/avro/src/test/scala/org/apache/spark/sql/avro/AvroSuite.scala:
##########
@@ -4012,11 +4012,18 @@ abstract class AvroSuite
       withTempPath { dir =>
         Seq("abcdef").toDF("c").write.format("avro").save(dir.getCanonicalPath)
         Seq("CHAR", "VARCHAR").foreach { typ =>
+          // Avro file reads wrap the row-level SparkRuntimeException in 
SparkException

Review Comment:
   Restored the original `intercept[SparkRuntimeException]` and dropped the 
FAILED_READ_FILE comment in 882633ae4e9. Scan overflow for this CHAR/VARCHAR 
column still comes from ApplyCharTypePadding, not a wrapped file-read error.



##########
connector/avro/src/main/scala/org/apache/spark/sql/avro/AvroDataToCatalyst.scala:
##########
@@ -25,24 +25,46 @@ import org.apache.avro.io.{BinaryDecoder, DecoderFactory}
 import org.apache.spark.SparkException
 import org.apache.spark.sql.catalyst.expressions.{ExpectsInputTypes, 
Expression, SpecificInternalRow, UnaryExpression}
 import org.apache.spark.sql.catalyst.expressions.codegen.{CodegenContext, 
CodeGenerator, ExprCode}
-import org.apache.spark.sql.catalyst.util.{FailFastMode, ParseMode, 
PermissiveMode}
+import org.apache.spark.sql.catalyst.util.{CharVarcharUtils, FailFastMode, 
ParseMode, PermissiveMode}
 import org.apache.spark.sql.errors.QueryCompilationErrors
+import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types._
 
 case class AvroDataToCatalyst(
     child: Expression,
     jsonFormatSchema: String,
-    options: Map[String, String])
+    options: Map[String, String],
+    // PERSISTED: capture at analysis (like JsonToStructs) so copy()/views keep
+    // creation-time CHAR/VARCHAR map-key checks, not the caller's session 
setting.
+    // No default args: TreeNode.makeCopy would otherwise re-read live SQLConf.

Review Comment:
   Dropped that sentence in 882633ae4e9. `copy()` / `makeCopy` keep the product 
fields; JsonToStructs already persists the same kind of flag with a default 
argument.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/avroSqlFunctions.scala:
##########
@@ -62,12 +63,30 @@ import org.apache.spark.util.Utils
   since = "4.0.0"
 )
 // scalastyle:on line.size.limit
-case class FromAvro(child: Expression, jsonFormatSchema: Expression, options: 
Expression)
+case class FromAvro(
+    child: Expression,
+    jsonFormatSchema: Expression,
+    options: Expression,
+    // PERSISTED: copy()/views keep analysis-time CHAR/VARCHAR flags. FromAvro 
is
+    // RuntimeReplaceable, so a new replacement would otherwise re-read 
SQLConf.
+    // No default args: copy() must keep these, and FunctionRegistry must still

Review Comment:
   Dropped the default-arg rationale in 882633ae4e9. `copy()` keeps the fields 
either way; the explicit 3-arg `def this` is what FunctionRegistry needs for 
the SQL form.



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