diff --git a/dbms/src/Functions/FunctionsJSON.cpp b/dbms/src/Functions/FunctionsJSON.cpp index 41983af8bf8..b5ec5fd6c64 100644 --- a/dbms/src/Functions/FunctionsJSON.cpp +++ b/dbms/src/Functions/FunctionsJSON.cpp @@ -309,16 +309,105 @@ public: } }; -// class JSONExtractRawImpl: public JSONNullableImplBase -// { -// public: -// static constexpr auto name {"JSONExtractRaw"}; +class JSONExtractRawImpl: public JSONNullableImplBase +{ +public: + static constexpr auto name {"JSONExtractRaw"}; -// static Field getValue(ParsedJson::iterator & pjh) -// { -// // -// } -// }; + static Field getValue(ParsedJson::iterator & pjh) + { + WriteBufferFromOwnString buf; + traverse(pjh, buf); + return {std::move(buf.str())}; + } + +private: + static void traverse(ParsedJson::iterator & pjh, WriteBuffer & buf) + { + switch (pjh.get_type()) + { + case '{': + { + writeChar('{', buf); + if (pjh.down()) + { + writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings()); + writeChar(':', buf); + pjh.next(); + traverse(pjh, buf); + while (pjh.next()) + { + writeChar(',', buf); + writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings()); + writeChar(':', buf); + pjh.next(); + traverse(pjh, buf); + } + pjh.up(); + } + writeChar('}', buf); + break; + } + case '[': + { + writeChar('[', buf); + if (pjh.down()) + { + traverse(pjh, buf); + while (pjh.next()) + { + writeChar(',', buf); + traverse(pjh, buf); + } + pjh.up(); + } + writeChar(']', buf); + break; + } + case '"': + { + writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings()); + break; + } + case 'l': + { + writeIntText(pjh.get_integer(), buf); + break; + } + case 'd': + { + writeFloatText(pjh.get_double(), buf); + break; + } + case 't': + { + writeCString("true", buf); + break; + } + case 'f': + { + writeCString("false", buf); + break; + } + case 'n': + { + writeCString("null", buf); + break; + } + } + } + + static const FormatSettings & format_settings() + { + static const FormatSettings the_instance = [] + { + FormatSettings settings; + settings.json.escape_forward_slashes = false; + return settings; + }(); + return the_instance; + } +}; class JSONExtractStringImpl : public JSONNullableImplBase { @@ -360,7 +449,7 @@ struct JSONExtractUIntImpl { static constexpr auto name{"JSONExtractUInt"}; }; struct JSONExtractIntImpl { static constexpr auto name{"JSONExtractInt"}; }; struct JSONExtractFloatImpl { static constexpr auto name{"JSONExtractFloat"}; }; struct JSONExtractBoolImpl { static constexpr auto name{"JSONExtractBool"}; }; -//struct JSONExtractRawImpl { static constexpr auto name {"JSONExtractRaw"}; }; +struct JSONExtractRawImpl { static constexpr auto name {"JSONExtractRaw"}; }; struct JSONExtractStringImpl { static constexpr auto name{"JSONExtractString"}; }; struct JSONExtractKeyImpl { static constexpr auto name{"JSONExtractKey"}; }; } @@ -382,10 +471,7 @@ void registerFunctionsJSON(FunctionFactory & factory) factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); - // factory.registerFunction>(); + factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); return; @@ -399,7 +485,7 @@ void registerFunctionsJSON(FunctionFactory & factory) factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); - //factory.registerFunction>(); + factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); } diff --git a/dbms/tests/queries/0_stateless/00918_json_functions_avx2.reference b/dbms/tests/queries/0_stateless/00918_json_functions_avx2.reference index 38f816cd820..ba6d2eeaa4a 100644 --- a/dbms/tests/queries/0_stateless/00918_json_functions_avx2.reference +++ b/dbms/tests/queries/0_stateless/00918_json_functions_avx2.reference @@ -17,3 +17,10 @@ Array [-100,NULL,300] ['a','hello','b',NULL] [(NULL,NULL,NULL),(NULL,NULL,NULL),(NULL,NULL,NULL),(-100,200,44)] +{"a":"hello","b":[-100,200,300],"c":{"d":[121,144]}} +"hello" +[-100,200,300] +-100 +{"d":[121,144]} +[121,144] +144 diff --git a/dbms/tests/queries/0_stateless/00918_json_functions_avx2.sql b/dbms/tests/queries/0_stateless/00918_json_functions_avx2.sql index 3d4f63b854f..5c5ddbd3985 100644 --- a/dbms/tests/queries/0_stateless/00918_json_functions_avx2.sql +++ b/dbms/tests/queries/0_stateless/00918_json_functions_avx2.sql @@ -17,3 +17,10 @@ SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(String, Str SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Array(Int32)', 'b'); SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Array(String)'); SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Array(Tuple(Int16, Float32, UInt8))'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'a'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'b'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'b', 1); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c', 'd'); +SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c', 'd', 2); diff --git a/docs/en/query_language/functions/json_functions.md b/docs/en/query_language/functions/json_functions.md index 38a6a6f7404..d20a7a38d2b 100644 --- a/docs/en/query_language/functions/json_functions.md +++ b/docs/en/query_language/functions/json_functions.md @@ -157,3 +157,16 @@ select JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(String, Str ``` The usage of accessors is the same as above. + +## JSONExtractRaw(params[, accessors]...) + +Returns a part of JSON. +If the part does not exist or has a wrong type, `null` will be returned. + +Examples: + +``` +select JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, 200.0, 300]' +``` + +The usage of accessors is the same as above.