fhueske commented on code in PR #24967: URL: https://github.com/apache/flink/pull/24967#discussion_r1669010333
########## docs/data/sql_functions.yml: ########## @@ -377,6 +377,12 @@ string: - sql: SUBSTR(string, integer1[, integer2]) table: STRING.substr(INTEGER1[, INTEGER2]) description: Returns a substring of string starting from position integer1 with length integer2 (to the end by default). + - sql: JSON_QUOTE(string) + table: STRING.JsonQuote() + description: Quotes a string as a JSON value by wrapping it with double quote characters, escaping interior quote and special characters ('"', '\', '/', 'b', 'f', 'n', 'r', 't'), and returning the result as a string. If the argument is NULL, the function returns NULL. + - sql: JSON_UNQUOTE(string) + table: STRING.JsonUnquote() + description: Unquotes JSON value, escapes special characters ('"', '\', '/', 'b', 'f', 'n', 'r', 't', 'u' hex hex hex hex), and returns the result as a string. If the argument is NULL, returns NULL. If the value starts and ends with double quotes but is not a valid JSON string literal, the value is passed through unmodified. Review Comment: ```suggestion description: Unquotes JSON value, unescapes escaped special characters ('"', '\', '/', 'b', 'f', 'n', 'r', 't', 'u' hex hex hex hex), and returns the result as a string. If the argument is NULL, returns NULL. If the value starts and ends with double quotes but is not a valid JSON string literal, the value is passed through unmodified. ``` we are unescaping (previously) escaped characters, right? ########## flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java: ########## @@ -794,6 +795,196 @@ private static List<TestSetSpec> jsonObjectSpec() { STRING().notNull())); } + private static List<TestSetSpec> jsonQuoteSpec() { + + return Arrays.asList( + TestSetSpec.forFunction(BuiltInFunctionDefinitions.JSON_QUOTE) + .onFieldsWithData(0) + .testResult( + nullOf(STRING()).jsonQuote(), + "JSON_QUOTE(CAST(NULL AS STRING))", + null, + STRING().nullable()), + TestSetSpec.forFunction(BuiltInFunctionDefinitions.JSON_QUOTE) + .onFieldsWithData( + "V", + "\"null\"", + "[1, 2, 3]", + "This is a \t test \n with special characters: \" \\ \b \f \r \u0041", + "\"kv_pair_test\": \"\\b\\f\\r\"", + "\ttab and fwd slash /", + "this will not be quoted \\u006z", + "this will be quoted ≠", + null) + .andDataTypes( + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().notNull(), + STRING().nullable()) + .testResult( + $("f0").jsonQuote(), "JSON_QUOTE(f0)", "\"V\"", STRING().notNull()) + .testResult( + $("f1").jsonQuote(), + "JSON_QUOTE(f1)", + "\"\\\"null\\\"\"", + STRING().notNull()) + .testResult( + $("f2").jsonQuote(), + "JSON_QUOTE(f2)", + "\"[1, 2, 3]\"", + STRING().notNull()) + .testResult( + $("f3").jsonQuote(), + "JSON_QUOTE(f3)", + "\"This is a \\t test \\n with special characters: \\\" \\\\ \\b \\f \\r A\"", + STRING().notNull()) + .testResult( + $("f4").jsonQuote(), + "JSON_QUOTE(f4)", + "\"\\\"kv_pair_test\\\": \\\"\\\\b\\\\f\\\\r\\\"\"", + STRING().notNull()) + .testResult( + $("f5").jsonQuote(), + "JSON_QUOTE(f5)", + "\"\\ttab and fwd slash \\/\"", + STRING().notNull()) + .testResult( + $("f6").jsonQuote(), + "JSON_QUOTE(f6)", + "\"this will not be quoted \\\\u006z\"", + STRING().notNull()) + .testResult( + $("f7").jsonQuote(), + "JSON_QUOTE(f7)", + "\"this will be quoted \\u2260\"", + STRING().notNull()) + .testResult( + $("f8").jsonQuote(), "JSON_QUOTE(f8)", null, STRING().nullable())); + } + + private static List<TestSetSpec> jsonUnquoteSpec() { + + return Arrays.asList( + TestSetSpec.forFunction(BuiltInFunctionDefinitions.JSON_UNQUOTE) + .onFieldsWithData(0) + .testResult( + nullOf(STRING()).jsonQuote(), + "JSON_UNQUOTE(CAST(NULL AS STRING))", + null, + STRING().nullable()), + TestSetSpec.forFunction(BuiltInFunctionDefinitions.JSON_UNQUOTE) Review Comment: can we split the TestSetSpec into two specs, one with valid Json input and the other with invalid (for which the input is returned)? ########## flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/expressions/ScalarFunctionsTest.scala: ########## @@ -604,6 +604,49 @@ class ScalarFunctionsTest extends ScalarTypesTestBase { "foothebar") } + @Test + def testJsonQuote(): Unit = { + testSqlApi("JSON_QUOTE('null')", "\"null\"") + testSqlApi("JSON_QUOTE('\"null\"')", "\"\\\"null\\\"\"") + testSqlApi("JSON_QUOTE('[1,2,3]')", "\"[1,2,3]\"") + testSqlApi("JSON_UNQUOTE(JSON_QUOTE('[1,2,3]'))", "[1,2,3]") + testSqlApi( + "JSON_QUOTE('This is a \\t test \\n with special characters: \" \\ \\b \\f \\r \\u0041')", + "\"This is a \\\\t test \\\\n with special characters: \\\" \\\\ \\\\b \\\\f \\\\r \\\\u0041\"" + ) + testSqlApi( + "JSON_QUOTE('\"special\": \"\\b\\f\\r\"')", + "\"\\\"special\\\": \\\"\\\\b\\\\f\\\\r\\\"\"") + testSqlApi( + "JSON_QUOTE('skipping backslash \')", + "\"skipping backslash \"" + ) + testSqlApi( + "JSON_QUOTE('this will be quoted ≠')", + "\"this will be quoted \\u2260\"" + ) + } + + @Test + def testJsonUnquote(): Unit = { Review Comment: Add some test cases with invalid JSON input? ########## flink-python/pyflink/table/expression.py: ########## @@ -1954,6 +1956,25 @@ def json_query(self, path: str, wrapping_behavior=JsonQueryWrapper.WITHOUT_ARRAY on_empty._to_j_json_query_on_error_or_empty(), on_error._to_j_json_query_on_error_or_empty()) + def json_quote(self) -> 'Expression': + """ + Quotes a string as a JSON value by wrapping it with double quote characters, + escaping interior quote and special characters + ('"', '\', '/', 'b', 'f', 'n', 'r', 't'), and returning + the result as a string. If the argument is NULL, the function returns NULL. + """ + return _unary_op("jsonQuote")(self) + + def json_unquote(self) -> 'Expression': + """ + Unquotes JSON value, escapes spacial characters Review Comment: ```suggestion Unquotes JSON value, unescapes escaped spacial characters ``` -- 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: issues-unsubscr...@flink.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org