cloud-fan commented on code in PR #58545:
URL: https://github.com/apache/spark/pull/58545#discussion_r3962178699


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/xml/StaxXmlParser.scala:
##########
@@ -310,27 +314,27 @@ class StaxXmlParser(
         startElementName: String,
         attributes: Array[Attribute]): Any = dt match {
       case st: StructType => convertObject(parser, st)
-      case MapType(StringType, vt, _) => convertMap(parser, vt, attributes)
+      case MapType(kt: StringType, vt, _) => convertMap(parser, kt, vt, 
attributes)
       case ArrayType(st, _) => convertField(parser, st, startElementName)
       case VariantType =>
         StaxXmlParser.convertVariant(parser, attributes, options)
-      case _: StringType =>
+      case dt: StringType =>
         convertTo(
           StaxXmlParserUtils.currentStructureAsString(
             parser, startElementName, options),
-          StringType)
+          dt)
     }
 
     (parser.peek, dataType) match {
       case (_: StartElement, dt: DataType) =>
         convertComplicatedType(dt, startElementName, attributes)
-      case (_: EndElement, _: StringType) =>
+      case (_: EndElement, dt: StringType) =>
         StaxXmlParserUtils.skipNextEndElement(parser, startElementName, 
options)
         // Empty. It's null if "" is the null value
         if (options.nullValue == "") {
           null
         } else {
-          UTF8String.fromString("")
+          CharVarcharUtils.applyTextParseSemantics(UTF8String.fromString(""), 
dt)

Review Comment:
   **Non-blocking (P2):** Please add a focused `BasicCharVarcharTestSuite` case 
for `from_xml('<ROW><a></a></ROW>', 'a CHAR(5)', map('nullValue', 'NULL'))` and 
assert exactly five spaces. The existing character-content and overflow cases 
do not exercise this empty-element branch or distinguish the required padded 
value from null and `""`.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/xml/StaxXmlParser.scala:
##########
@@ -374,31 +378,41 @@ class StaxXmlParser(
    */
   private def convertMap(
       parser: XMLEventReader,
+      keyType: DataType,
       valueType: DataType,
       attributes: Array[Attribute]): MapData = {
     val kvPairs = ArrayBuffer.empty[(UTF8String, Any)]
+    def mapKey(raw: String): UTF8String = {
+      CharVarcharUtils.applyTextParseSemantics(UTF8String.fromString(raw), 
keyType)
+    }
     attributes.foreach { attr =>
-      kvPairs += (UTF8String.fromString(options.attributePrefix + 
attr.getName.getLocalPart)
-        -> convertTo(attr.getValue, valueType))
+      kvPairs += (mapKey(options.attributePrefix + attr.getName.getLocalPart) 
->
+        convertTo(attr.getValue, valueType))
     }
     var shouldStop = false
     while (!shouldStop) {
       parser.nextEvent match {
         case e: StartElement =>
           val key = StaxXmlParserUtils.getName(e.asStartElement.getName, 
options)
-          kvPairs +=
-          (UTF8String.fromString(key) -> convertField(parser, valueType, key))
+          kvPairs += (mapKey(key) -> convertField(parser, valueType, key))

Review Comment:
   **Blocking (P1):** `mapKey(key)` can throw before `convertField` consumes 
`<abc>`. In permissive mode, the enclosing `convertObject` then resumes on the 
same reader and can treat `</abc>` as the end of the row, so 
`from_xml('<ROW><m><abc>1</abc></m><tail>2</tail></ROW>', 'm MAP<CHAR(2), INT>, 
tail INT')` loses `tail = 2`. Please consume or recover the entry value before 
applying constrained-key semantics, and append the key/value pair atomically so 
a rejected key leaves the reader positioned at the next sibling.
   
   **Recommended change:** Consume or recover each XML map entry value before 
applying CHAR/VARCHAR key normalization, then commit the normalized key and 
converted value together.
   
   **Why this works:** Moving key validation after value consumption preserves 
the XMLEventReader position expected by convertObject's recoverable-error path 
and prevents partially committed map entries.
   
   **Scope:** StaxXmlParser.convertMap and focused XML partial-result tests for 
an oversized constrained map key followed by a valid sibling field.
   
   **Compatibility:** Successful maps, ordinary STRING-key handling, parse 
modes, and duplicate-policy behavior should remain unchanged; only recovery 
after an invalid constrained key is corrected.
   
   **Risks:** Changing conversion order can alter which error wins when both a 
key and its value are invalid. Incorrect event advancement could skip a nested 
value or the following map entry.
   
   **Constraints:** Invoke the value converter at most once per entry. Keep key 
and value assembly atomic on every partial-result path. Preserve the configured 
normalized-key duplicate policy.
   
   **Success:** With partial results enabled, an oversized CHAR/VARCHAR XML map 
key no longer hides a valid later row field, while existing successful and 
duplicate-policy cases retain their behavior.



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