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


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonParser.scala:
##########
@@ -122,6 +122,8 @@ class JacksonParser(
   }
 
   private val variantAllowDuplicateKeys = 
SQLConf.get.getConf(SQLConf.VARIANT_ALLOW_DUPLICATE_KEYS)
+  private val variantvalidateUnicodeInJsonParsing =

Review Comment:
   Naming typo — `variantvalidateUnicodeInJsonParsing` has a lowercase `v` in 
the middle. The line directly above uses `variantAllowDuplicateKeys`; the new 
one should follow the same camelCase convention.
   
   ```suggestion
     private val variantValidateUnicodeInJsonParsing =
       SQLConf.get.getConf(SQLConf.VARIANT_VALIDATE_UNICODE_IN_JSON_PARSING)
   ```
   
   (And update the use on line 137 to match.)



##########
sql/core/src/test/scala/org/apache/spark/sql/VariantEndToEndSuite.scala:
##########
@@ -185,6 +185,28 @@ class VariantEndToEndSuite extends SharedSparkSession {
     checkAnswer(variantDF, Seq(Row(expected)))
   }
 
+  test("SPARK-56654: parse_json/from_json reject unpaired UTF-16 surrogates by 
default") {
+    val invalidJson = "\"\\uD835\""
+    val df = Seq(invalidJson).toDF("j")
+    checkAnswer(df.selectExpr("try_parse_json(j)"), Seq(Row(null)))
+    checkAnswer(df.selectExpr("from_json(j, 'variant')"), Seq(Row(null)))
+
+    val parseJsonError = intercept[SparkException] {
+      df.selectExpr("parse_json(j)").collect()
+    }
+    val cause = Option(parseJsonError.getCause).getOrElse(parseJsonError)
+    assert(cause.getMessage.contains("MALFORMED_RECORD_IN_PARSING"),
+      s"Unexpected error message: ${cause.getMessage}")

Review Comment:
   The same suite uses `checkError(...)` for typed assertions on this exact 
error class (see line 414). `getMessage.contains(...)` is weaker (no parameter 
check) and inconsistent with the rest of the file. Suggest:
   
   ```scala
   val parseJsonError = intercept[SparkException] {
     df.selectExpr("parse_json(j)").collect()
   }
   checkError(
     exception = parseJsonError,
     condition = "MALFORMED_RECORD_IN_PARSING.WITHOUT_SUGGESTION",
     parameters = Map("badRecord" -> invalidJson, "failFastMode" -> "FAILFAST")
   )
   ```
   
   Also, the PR description claims `from_json` throws in FAILFAST mode, but 
only the PERMISSIVE-returns-null path is tested — consider adding a 
`from_json(j, 'variant', map('mode', 'FAILFAST'))` check using the template at 
line 411.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala:
##########
@@ -6050,6 +6050,19 @@ object SQLConf {
       .booleanConf
       .createWithDefault(false)
 
+  val VARIANT_VALIDATE_UNICODE_IN_JSON_PARSING =
+    buildConf("spark.sql.variant.validateUnicodeInJsonParsing")
+      .internal()
+      .doc("When true, parsing variant from JSON rejects strings that contain 
unpaired UTF-16 " +
+        "surrogate code units (such as a lone high surrogate like \\uD835), 
which are invalid " +
+        "per RFC 8259 section 7. When false, restores the legacy permissive 
behavior in which " +
+        "the unpaired surrogate is silently replaced by the Unicode 
replacement character " +
+        "during UTF-8 encoding, causing data corruption that diverges from 
strict JSON parsers.")
+      .version("4.2.0")

Review Comment:
   This PR will be merged to `branch-4.x`, so the conf version should be 
`4.3.0`.
   
   ```suggestion
         .version("4.3.0")
   ```



##########
common/variant/src/main/java/org/apache/spark/types/variant/VariantBuilder.java:
##########
@@ -557,6 +593,30 @@ private void parseFloatingPoint(JsonParser parser) throws 
IOException {
     }
   }
 
+  // Reject JSON strings that contain unpaired UTF-16 surrogate code units. 
Java strings can
+  // hold lone surrogates, but RFC 8259 section 7 requires JSON string 
contents to be well-formed
+  // Unicode. Stricter parsers such as simdjson reject these inputs, while 
Jackson's
+  // `ReaderBasedJsonParser` accepts them and silently drops the invalid 
character to U+FFFD

Review Comment:
   Minor wording: "silently drops the invalid character to U+FFFD" reads 
awkwardly ("drops...to" mixes idioms). The Javadoc on the new `parseJson` 
overload (line 69) already uses cleaner phrasing — let's match it:
   
   ```suggestion
     // `ReaderBasedJsonParser` accepts them and silently replaces the invalid 
character with
     // U+FFFD when the result is encoded as UTF-8. That silent replacement 
causes data
   ```



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