This is an automated email from the ASF dual-hosted git repository.

snuyanzin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git


The following commit(s) were added to refs/heads/master by this push:
     new 45588b31410 [FLINK-37695][table] Fix parsing for built-in function 
JSON in JSON_OBJECT for all positions
45588b31410 is described below

commit 45588b31410fc612051b0294d379c08036f04079
Author: Gustavo de Morais <[email protected]>
AuthorDate: Wed Apr 30 16:19:33 2025 +0200

    [FLINK-37695][table] Fix parsing for built-in function JSON in JSON_OBJECT 
for all positions
---
 .../table/planner/codegen/ExprCodeGenerator.scala  | 12 ++---
 .../table/planner/codegen/JsonGenerateUtils.scala  | 11 +++++
 .../planner/functions/JsonFunctionsITCase.java     | 57 +++++++++++++++++++---
 3 files changed, 66 insertions(+), 14 deletions(-)

diff --git 
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExprCodeGenerator.scala
 
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExprCodeGenerator.scala
index d2f0f3e5e2d..c625bfd89b3 100644
--- 
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExprCodeGenerator.scala
+++ 
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExprCodeGenerator.scala
@@ -29,7 +29,7 @@ import 
org.apache.flink.table.planner.calcite.{FlinkTypeFactory, RexDistinctKeyV
 import org.apache.flink.table.planner.codegen.CodeGenUtils._
 import org.apache.flink.table.planner.codegen.GeneratedExpression.{NEVER_NULL, 
NO_CODE}
 import org.apache.flink.table.planner.codegen.GenerateUtils._
-import 
org.apache.flink.table.planner.codegen.JsonGenerateUtils.{isJsonArrayOperand, 
isJsonFunctionOperand, isJsonObjectOperand}
+import 
org.apache.flink.table.planner.codegen.JsonGenerateUtils.{isJsonFunctionOperand,
 isSupportedJsonOperand}
 import org.apache.flink.table.planner.codegen.calls._
 import org.apache.flink.table.planner.codegen.calls.ScalarOperatorGens._
 import 
org.apache.flink.table.planner.codegen.calls.SearchOperatorGen.generateSearch
@@ -464,8 +464,8 @@ class ExprCodeGenerator(ctx: CodeGeneratorContext, 
nullableInput: Boolean)
     // throw exception if json function is called outside JSON_OBJECT or 
JSON_ARRAY function
     if (isJsonFunctionOperand(call)) {
       throw new ValidationException(
-        "The JSON() function is currently only supported inside a 
JSON_OBJECT() or JSON_ARRAY()" +
-          " function. Example: JSON_OBJECT('a', JSON('{\"key\": \"value\"}')) 
or " +
+        "The JSON() function is currently only supported inside JSON_ARRAY() 
or as the VALUE param" +
+          " of JSON_OBJECT(). Example: JSON_OBJECT('a', JSON('{\"key\": 
\"value\"}')) or " +
           "JSON_ARRAY(JSON('{\"key\": \"value\"}')).")
     }
 
@@ -486,10 +486,8 @@ class ExprCodeGenerator(ctx: CodeGeneratorContext, 
nullableInput: Boolean)
             call.getOperator.getReturnTypeInference == ReturnTypes.ARG0 =>
         generateNullLiteral(resultType)
 
-      // We only support JSON function operands as the value param of a 
JSON_OBJECT or JSON_ARRAY function
-      case (operand: RexNode, i)
-          if isJsonFunctionOperand(operand) &&
-            (isJsonArrayOperand(call) || i == 2 && isJsonObjectOperand(call)) 
=>
+      // We only support the JSON function inside of JSON_OBJECT or JSON_ARRAY
+      case (operand: RexNode, i) if isSupportedJsonOperand(operand, call, i) =>
         generateJsonCall(operand)
 
       case (o @ _, _) => o.accept(this)
diff --git 
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/JsonGenerateUtils.scala
 
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/JsonGenerateUtils.scala
index 6ac502fda24..823837d2f5e 100644
--- 
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/JsonGenerateUtils.scala
+++ 
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/JsonGenerateUtils.scala
@@ -227,6 +227,17 @@ object JsonGenerateUtils {
     }
   }
 
+  /**
+   * Determines whether a JSON function is allowed in the current context. 
JSON functions are
+   * allowed as values in JSON_ARRAY calls or as value parameters in 
JSON_OBJECT calls. In the case
+   * of a JSON_OBJECT call, we do (i % 2) == 0 to check if it's being used in 
second parameter, the
+   * values' parameter.
+   */
+  def isSupportedJsonOperand(operand: RexNode, call: RexNode, i: Int): Boolean 
= {
+    isJsonFunctionOperand(operand) &&
+    (isJsonArrayOperand(call) || isJsonObjectOperand(call) && (i % 2) == 0)
+  }
+
   /** Generates a method to convert arrays into [[ArrayNode]]. */
   private def generateArrayConverter(
       ctx: CodeGeneratorContext,
diff --git 
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
 
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
index 2ce19701dc4..e26401951c4 100644
--- 
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
+++ 
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
@@ -782,11 +782,54 @@ class JsonFunctionsITCase extends BuiltInFunctionTestBase 
{
                         .testTableApiRuntimeError(
                                 jsonObject(JsonOnNull.NULL, "K", json("{")),
                                 TableRuntimeException.class,
-                                "Invalid JSON string in JSON(value) function"),
-                // Tests for JSON calls inside of JSON_ARRAY
-                TestSetSpec.forFunction(BuiltInFunctionDefinitions.JSON_ARRAY)
-                        .onFieldsWithData("{\"key\":\"value\"}", "{\"key\": 
{\"value\": 42}}")
-                        .andDataTypes(STRING(), STRING())
+                                "Invalid JSON string in JSON(value) function")
+
+                        // Tests for JSON_OBJECT with multiple parameters
+                        .testResult(
+                                jsonObject(JsonOnNull.NULL, "key1", "val", 
"key2", json($("f1"))),
+                                "JSON_OBJECT(KEY 'key1' VALUE 'val', KEY 
'key2' VALUE JSON(f1))",
+                                
"{\"key1\":\"val\",\"key2\":{\"key\":{\"value\":42}}}",
+                                STRING().notNull())
+                        .testResult(
+                                jsonObject(
+                                        JsonOnNull.NULL,
+                                        "key1",
+                                        json($("f0")),
+                                        "key2",
+                                        json($("f1"))),
+                                "JSON_OBJECT(KEY 'key1' VALUE JSON(f0), KEY 
'key2' VALUE JSON(f1))",
+                                
"{\"key1\":{\"key\":\"value\"},\"key2\":{\"key\":{\"value\":42}}}",
+                                STRING().notNull())
+                        .testResult(
+                                jsonObject(
+                                        JsonOnNull.NULL,
+                                        "outerKey",
+                                        "outerValue",
+                                        "nestedObject",
+                                        jsonObject(JsonOnNull.NULL, 
"innerKey", json($("f0")))),
+                                "JSON_OBJECT(KEY 'outerKey' VALUE 
'outerValue', KEY 'nestedObject' VALUE JSON_OBJECT(KEY 'innerKey' VALUE 
JSON(f0)))",
+                                
"{\"nestedObject\":{\"innerKey\":{\"key\":\"value\"}},\"outerKey\":\"outerValue\"}",
+                                STRING().notNull())
+                        .testResult(
+                                jsonObject(
+                                        JsonOnNull.NULL,
+                                        "p1",
+                                        json($("f0")),
+                                        "p2",
+                                        json($("f1")),
+                                        "p3",
+                                        json("[1, 2, 3]")),
+                                "JSON_OBJECT(KEY 'p1' VALUE JSON(f0), KEY 'p2' 
VALUE JSON(f1), KEY 'p3' VALUE JSON('[1, 2, 3]'))",
+                                
"{\"p1\":{\"key\":\"value\"},\"p2\":{\"key\":{\"value\":42}},\"p3\":[1,2,3]}",
+                                STRING().notNull())
+                        .testSqlValidationError(
+                                "JSON_OBJECT(KEY JSON('{}') VALUE 'value' 
ABSENT ON NULL)",
+                                "The JSON() function is currently only 
supported inside JSON_ARRAY() or as the VALUE param of JSON_OBJECT()")
+                        .testTableApiValidationError(
+                                jsonObject(JsonOnNull.NULL, json($("f0")), 
"value"),
+                                "Invalid function call:\n"
+                                        + "JSON_OBJECT(SYMBOL NOT NULL, 
STRING, CHAR(5) NOT NULL)")
+                        // Tests for JSON calls inside of JSON_ARRAY
                         .testResult(
                                 jsonArray(JsonOnNull.NULL, json("{}")),
                                 "JSON_ARRAY(JSON('{}'))",
@@ -865,10 +908,10 @@ class JsonFunctionsITCase extends BuiltInFunctionTestBase 
{
                                 "line: 1, column: 1")
                         .testTableApiValidationError(
                                 json($("f0")),
-                                "The JSON() function is currently only 
supported inside a JSON_OBJECT() or JSON_ARRAY() function.")
+                                "The JSON() function is currently only 
supported inside JSON_ARRAY() or as the VALUE param of JSON_OBJECT()")
                         .testSqlValidationError(
                                 "JSON(f0)",
-                                "The JSON() function is currently only 
supported inside a JSON_OBJECT() or JSON_ARRAY() function."));
+                                "The JSON() function is currently only 
supported inside JSON_ARRAY() or as the VALUE param of JSON_OBJECT()"));
     }
 
     private static List<TestSetSpec> jsonObjectSpec() {

Reply via email to