ganeshashree commented on code in PR #57957:
URL: https://github.com/apache/spark/pull/57957#discussion_r3818419325
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/json/JsonExpressionEvalUtils.scala:
##########
@@ -392,6 +392,34 @@ object JsonValueLookup {
case class Scalar(text: UTF8String) extends JsonValueLookup
}
+/**
+ * The result of a single-value [[JsonTableEvaluator.queryLookup]] for
`JSON_QUERY`. Unlike
+ * [[JsonValueLookup]] -- which reports an object/array match as `NonScalar`
without serializing it,
+ * since `JSON_VALUE` never returns a non-scalar -- `Found` here always
carries the matched value's
+ * verbatim JSON text (`JSON_QUERY` returns objects, arrays, and scalars
alike). `structural`
Review Comment:
Done.
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/json/JsonExpressionEvalUtils.scala:
##########
@@ -550,6 +578,69 @@ case class JsonTableEvaluator(containerPath:
Seq[PathInstruction], explodeRoot:
}
}
+ /**
+ * Resolves `containerPath` against a single JSON value for `JSON_QUERY`,
serializing the matched
+ * value as verbatim JSON text. Returns:
+ *
+ * - `None` if the input is not a single well-formed JSON value (malformed
/ trailing garbage /
+ * empty), which the caller maps to ON ERROR;
+ * - `Some(Missing)` if the path matches nothing (ON EMPTY);
+ * - `Some(Found(raw, structural, unquoted))` if the path matches, where
`raw` is the value's
+ * verbatim JSON text, `structural` is true for an object or array (as
opposed to a scalar,
+ * including a JSON `null`, whose text is `null`), and `unquoted` is the
`OMIT QUOTES` form
+ * (a matched JSON string's decoded content; `raw` for every other
value).
+ *
+ * `omitQuotes` mirrors the caller's `OMIT QUOTES` clause: only a matched
JSON string's `unquoted`
+ * form differs from `raw`, and only `OMIT QUOTES` consumes it, so the
decode-and-allocate is done
+ * for a string only when `omitQuotes` is true -- the default `KEEP QUOTES`
path leaves `unquoted`
+ * equal to `raw` and skips the work.
+ *
+ * A `null` input is the caller's responsibility. Like [[lookup]] this
navigates and validates
+ * with a single parser: after the matched value is serialized (which
consumes it),
+ * [[drainToRootEnd]]
+ * walks out of the enclosing containers and rejects any trailing content,
so a valid prefix
+ * followed by garbage is rejected exactly as a fully malformed document is.
+ */
+ final def queryLookup(json: UTF8String, omitQuotes: Boolean):
Option[JsonQueryLookup] = {
+ Utils.tryWithResource(CreateJacksonParser.utf8String(jsonFactory, json)) {
parser =>
+ try {
+ if (parser.nextToken() == null) {
+ None // empty or whitespace-only
+ } else {
+ val result = positionAt(parser, containerPath) match {
+ case PositionResult.Missing => JsonQueryLookup.Missing
+ // A JSON `null` literal is a scalar value for JSON_QUERY:
serialize it to the text
+ // `null` rather than reporting it specially. The parser is
positioned on the token.
+ case PositionResult.NullValue =>
+ val raw = serializeCurrentValue(parser)
+ JsonQueryLookup.Found(raw, structural = false, unquoted = raw)
+ case PositionResult.AtValue =>
+ parser.currentToken match {
+ case JsonToken.START_OBJECT | JsonToken.START_ARRAY =>
+ val raw = serializeCurrentValue(parser)
+ JsonQueryLookup.Found(raw, structural = true, unquoted = raw)
+ case JsonToken.VALUE_STRING if omitQuotes =>
+ // Capture the decoded string straight from the parser so
`OMIT QUOTES` need not
+ // re-parse the serialized (re-quoted) form. Only decode for
`OMIT QUOTES`: the
+ // default `KEEP QUOTES` path (below) discards it, so the
allocation is skipped.
+ val unquoted = UTF8String.fromString(parser.getText)
+ JsonQueryLookup.Found(serializeCurrentValue(parser),
structural = false, unquoted)
Review Comment:
Done.
--
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]