yadavay-amzn commented on code in PR #57211:
URL: https://github.com/apache/spark/pull/57211#discussion_r3584094038


##########
sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/JsonExpressionsSuite.scala:
##########
@@ -909,6 +909,34 @@ class JsonExpressionsSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     }
   }
 
+  test("json_valid") {
+    Seq(
+      // null input returns null
+      (null, null),
+      // valid JSON values
+      ("""{"a":1}""", true),
+      ("""{"a": "b", "c": [1, 2, 3]}""", true),
+      ("[1, 2, 3]", true),
+      ("[]", true),
+      ("{}", true),
+      ("\"a string\"", true),
+      ("123", true),
+      ("true", true),
+      ("null", true),
+      // invalid JSON values
+      ("", false),
+      ("   ", false),
+      ("invalid", false),
+      ("""{"a":1} garbage""", false),
+      ("[1, 2, 3", false),
+      ("""{"a": }""", false)
+    ).foreach {
+      case (input, expected) =>
+        val literal = if (input == null) Literal.create(null, StringType) else 
Literal(input)
+        checkEvaluation(JsonValid(literal), expected)

Review Comment:
   Since the single-quote leniency is the one intentional departure from strict 
JSON, it might be worth a case here that pins it, e.g. `("{'a':1}", true)`, so 
the decision doesn't silently regress later.



##########
sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/json/JsonExpressionUtils.java:
##########
@@ -54,6 +54,26 @@ public static Integer lengthOfJsonArray(UTF8String json) {
     }
   }
 
+  public static Boolean isJsonValid(UTF8String json) {
+    if (json == null) {

Review Comment:
   I think this null check might be unreachable, since the `replacement` builds 
the `StaticInvoke` with the default `propagateNull = true`, so a null input 
gets short-circuited to null before this method runs. `lengthOfJsonArray` and 
`jsonObjectKeys` rely on that and skip the check, so it could go for 
consistency with its neighbors. Not harmful either way.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/jsonExpressions.scala:
##########
@@ -693,3 +693,52 @@ case class JsonObjectKeys(child: Expression)
   override protected def withNewChildInternal(newChild: Expression): 
JsonObjectKeys =
     copy(child = newChild)
 }
+
+/**
+ * A function that returns true if the input is a valid JSON string, false 
otherwise.
+ */
+@ExpressionDescription(
+  usage = "_FUNC_(jsonString) - Returns true if `jsonString` is a valid JSON 
string, " +

Review Comment:
   Since this reuses `SharedFactory`, it inherits `ALLOW_SINGLE_QUOTES` and 
`ALLOW_UNESCAPED_CONTROL_CHARS`, so something like `json_valid("{'a':1}")` 
returns true. That seems like a reasonable choice for consistency with 
`get_json_object` and the rest of the JSON family, but "valid JSON string" 
reads as strict RFC to most people. Might be worth a sentence here (and in the 
Scala/PySpark docstrings) noting it follows the same lenient parsing as the 
other JSON functions, so the single-quote / control-char behavior isn't a 
surprise.



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