Fix stack overflow in JSONMergePatch

This commit is contained in:
Alexey Milovidov 2024-08-04 18:25:36 +02:00
parent 98c791160e
commit 87e0cf6b76
2 changed files with 29 additions and 17 deletions

View File

@ -3,6 +3,10 @@
#include "config.h" #include "config.h"
#if USE_RAPIDJSON #if USE_RAPIDJSON
/// Prevent stack overflow:
#define RAPIDJSON_PARSE_DEFAULT_FLAGS (kParseIterativeFlag)
#include <base/types.h> #include <base/types.h>
#include <base/defines.h> #include <base/defines.h>
#include <rapidjson/document.h> #include <rapidjson/document.h>

View File

@ -10,12 +10,14 @@
#if USE_RAPIDJSON #if USE_RAPIDJSON
#include "rapidjson/document.h" /// Prevent stack overflow:
#include "rapidjson/writer.h" #define RAPIDJSON_PARSE_DEFAULT_FLAGS (kParseIterativeFlag)
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h" #include <rapidjson/document.h>
#include "rapidjson/prettywriter.h" #include <rapidjson/writer.h>
#include "rapidjson/filereadstream.h" #include <rapidjson/stringbuffer.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/error/en.h>
namespace DB namespace DB
@ -31,17 +33,17 @@ namespace ErrorCodes
namespace namespace
{ {
// select jsonMergePatch('{"a":1}','{"name": "joey"}','{"name": "tom"}','{"name": "zoey"}'); // select JSONMergePatch('{"a":1}','{"name": "joey"}','{"name": "tom"}','{"name": "zoey"}');
// || // ||
// \/ // \/
// ┌───────────────────────┐ // ┌───────────────────────┐
// │ {"a":1,"name":"zoey"} │ // │ {"a":1,"name":"zoey"} │
// └───────────────────────┘ // └───────────────────────┘
class FunctionjsonMergePatch : public IFunction class FunctionJSONMergePatch : public IFunction
{ {
public: public:
static constexpr auto name = "jsonMergePatch"; static constexpr auto name = "JSONMergePatch";
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionjsonMergePatch>(); } static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionJSONMergePatch>(); }
String getName() const override { return name; } String getName() const override { return name; }
bool isVariadic() const override { return true; } bool isVariadic() const override { return true; }
@ -98,7 +100,11 @@ namespace
const char * json = str_ref.data; const char * json = str_ref.data;
document.Parse(json); document.Parse(json);
if (document.HasParseError() || !document.IsObject())
if (document.HasParseError())
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Wrong JSON string to merge: {}", rapidjson::GetParseError_En(document.GetParseError()));
if (!document.IsObject())
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Wrong JSON string to merge. Expected JSON object"); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Wrong JSON string to merge. Expected JSON object");
}; };
@ -162,10 +168,12 @@ namespace
} }
REGISTER_FUNCTION(jsonMergePatch) REGISTER_FUNCTION(JSONMergePatch)
{ {
factory.registerFunction<FunctionjsonMergePatch>(FunctionDocumentation{ factory.registerFunction<FunctionJSONMergePatch>(FunctionDocumentation{
.description="Returns the merged JSON object string, which is formed by merging multiple JSON objects."}); .description="Returns the merged JSON object string, which is formed by merging multiple JSON objects."});
factory.registerAlias("jsonMergePatch", "JSONMergePatch");
} }
} }