ganeshashree commented on code in PR #58034:
URL: https://github.com/apache/spark/pull/58034#discussion_r4250581908


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/jsonExpressions.scala:
##########
@@ -2272,3 +2331,424 @@ case class JsonTypeof(child: Expression)
   override protected def withNewChildInternal(newChild: Expression): 
JsonTypeof =
     copy(child = newChild)
 }
+
+/**
+ * The SQL:2016 `JSON_OBJECT` constructor function (feature T811): constructs 
a JSON object from
+ * key-value pairs, written `key VALUE value`, `KEY key VALUE value`, `key : 
value`, or the
+ * MySQL-style `key, value`.
+ *
+ * Keys must be non-null strings; a null key is an error. The `ON NULL` clause 
controls whether
+ * null-valued pairs are included (NULL ON NULL, the standard default) or 
omitted (ABSENT ON NULL).
+ *
+ * A value is spliced in raw (unquoted) when it carries `FORMAT JSON` (tracked 
per member by
+ * `rawJson`): the explicit clause (e.g. `JSON_OBJECT('a' VALUE '{"b":1}' 
FORMAT JSON)`), or the
+ * implicit form carried by a nested JSON constructor / `JSON_QUERY` under 
KEEP QUOTES (see
+ * `rawJsonValue`). Explicit `FORMAT JSON` on a non-constructor is arbitrary 
user text, so
+ * `needsValidation` marks it for JSON validation at eval; a nested 
constructor is trusted.
+ *
+ * Examples:
+ *   JSON_OBJECT('id' VALUE 7, 'name' VALUE 'Ada')      -> 
'{"id":7,"name":"Ada"}'
+ *   JSON_OBJECT('id': 7, 'v': NULL)                    -> '{"id":7,"v":null}'
+ *   JSON_OBJECT('id': 7, 'v': NULL ABSENT ON NULL)     -> '{"id":7}'
+ *   JSON_OBJECT()                                       -> '{}'
+ *
+ * A clause-free call that is not itself lexically nested in an enclosing 
constructor's *value*
+ * position routes through function resolution and is rebuilt by 
`JsonObjectExpressionBuilder`, so a
+ * same-named routine can shadow the built-in `json_object`: always for the 
comma form (a nested
+ * producer value routes too, carrying its raw-splice eligibility via 
`JsonImplicitFormatCarrier`),
+ * but for the `VALUE` / `:` forms only when no member carries a raw value 
(`rawJson.contains(true)`
+ * -- an explicit `FORMAT JSON` or a nested producer in *value* position -- 
keeps it direct).
+ * Otherwise it is built directly from the grammar (clause-bearing, or 
value-nested); a nested
+ * *key*-position call stays routable (see `AstBuilder.visitJsonObject`).
+ * The user-facing reference lives in 
`docs/sql-ref-syntax-qry-select-json-object.md`.
+ */
+case class JsonObjectExpr(
+    members: Seq[(Expression, Expression)],
+    rawJson: Seq[Boolean],
+    needsValidation: Seq[Boolean],
+    nullBehavior: JsonConstructorNullBehavior = 
JsonConstructorNullBehavior.Null,
+    returning: DataType = StringType,
+    timeZoneId: Option[String] = None)
+  extends Expression
+  with TimeZoneAwareExpression
+  with CodegenFallback

Review Comment:
   This is a bigger architectural change than a localized fix. Done properly it 
means replacing the per-member rendering (each key/value serialized through its 
own one-element `StructsToJsonEvaluator`, with the enclosing `Project` dropped 
from whole-stage codegen via `CodegenFallback`) with a single object-level 
evaluator that writes the whole object through one Jackson lifecycle and plugs 
into codegen the way `to_json` does with `RuntimeReplaceable` + `Invoke`, while 
preserving key-before-value null ordering, per-member raw/validation flags, 
ABSENT vs NULL, collated RETURNING, and the routing boundaries.
   
   The catch is that `JsonObjectExpr` deliberately mirrors the already-merged 
`JsonArray`, which uses the exact same `CodegenFallback` + per-element 
evaluator design. Fixing only JSON_OBJECT would diverge the two sibling 
constructors, so I'd rather scope both into a dedicated follow-up PR that 
converts JSON_ARRAY and JSON_OBJECT to the single-evaluator codegen path 
together, keeping them consistent and getting one round of review for the 
shared design. It's a non-blocking P2 with no observable-semantics change, so 
I'd prefer to keep it out of this PR, but I'm happy to implement it here 
instead if you prefer. I'll file the follow-up JIRA and link it here.
   



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