Skip to content

Commit aa9e300

Browse files
committed
Bug#35640263: Refactoring of json_diff/json_binary to enable HW
support for partial json [3/6, error handler, noclose] The functions that serialize JSON values currently take one error handler argument for each error that could be raised by the function. This does not scale well, as one new argument has to be added for each new error condition that is added to the function, and many function signatures have to be modified if errors are added or removed from one of these functions. This patch replaces the many error handler arguments with a single error handler that has one virtual member function per error. This allows new errors to be added without changing the signatures of the serialization functions. Change-Id: If341dbcb98e556c1341934cb69f4427aafe9708c
1 parent 5216c96 commit aa9e300

18 files changed

+320
-364
lines changed

client/json_client_library_main.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,23 @@
3939
#include "mysql_time.h"
4040
#include "sql-common/json_binary.h"
4141
#include "sql-common/json_dom.h"
42+
#include "sql-common/json_error_handler.h"
4243
#include "sql-common/json_path.h"
4344
#include "sql-common/my_decimal.h"
4445
#include "sql_string.h"
4546

47+
namespace {
4648
void CoutDefaultDepthHandler() { std::cout << "Doc too deep"; }
47-
void CoutDefaultKeyErrorHandler() { std::cout << "Key too big"; }
48-
void CoutDefaultValueErrorHandler() { std::cout << "Value too big"; }
49-
void InvalidJsonErrorHandler() { std::cout << "Invalid JSON"; }
49+
50+
class CoutSerializationErrorHandler : public JsonSerializationErrorHandler {
51+
public:
52+
void KeyTooBig() const override { std::cout << "Key too big"; }
53+
void ValueTooBig() const override { std::cout << "Value too big"; }
54+
void TooDeep() const override { CoutDefaultDepthHandler(); }
55+
void InvalidJson() const override { std::cout << "Invalid JSON"; }
56+
};
57+
58+
} // namespace
5059

5160
int main() {
5261
Json_object o;
@@ -68,8 +77,7 @@ int main() {
6877
wr.set_alias();
6978

7079
StringBuffer<20000> buf;
71-
if (wr.to_binary(&buf, CoutDefaultDepthHandler, CoutDefaultKeyErrorHandler,
72-
CoutDefaultValueErrorHandler, InvalidJsonErrorHandler)) {
80+
if (wr.to_binary(CoutSerializationErrorHandler(), &buf)) {
7381
std::cout << "error";
7482
} else {
7583
const json_binary::Value v(
@@ -128,9 +136,7 @@ int main() {
128136
my_decimal m;
129137
double2my_decimal(0, 3.14000000001, &m);
130138
const Json_decimal jd(m);
131-
if (json_binary::serialize(&jd, &buf, CoutDefaultDepthHandler,
132-
CoutDefaultKeyErrorHandler,
133-
CoutDefaultValueErrorHandler))
139+
if (json_binary::serialize(&jd, CoutSerializationErrorHandler(), &buf))
134140
std::cout << "ERRROR!!" << std::endl;
135141

136142
json_binary::Value v = json_binary::parse_binary(buf.ptr(), buf.length());
@@ -150,9 +156,7 @@ int main() {
150156
dt.time_type = MYSQL_TIMESTAMP_DATE;
151157
const Json_datetime jd(dt, MYSQL_TYPE_DATETIME);
152158

153-
if (json_binary::serialize(&jd, &buf, CoutDefaultDepthHandler,
154-
CoutDefaultKeyErrorHandler,
155-
CoutDefaultValueErrorHandler))
159+
if (json_binary::serialize(&jd, CoutSerializationErrorHandler(), &buf))
156160
std::cout << "ERRROR!!" << std::endl;
157161

158162
json_binary::Value v = json_binary::parse_binary(buf.ptr(), buf.length());

sql-common/json_binary.cc

Lines changed: 71 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,32 @@
3030
#include <memory>
3131
#include <string>
3232
#include <utility>
33+
#include <vector>
34+
35+
#ifdef MYSQL_SERVER
36+
#include <sys/types.h>
37+
#endif // MYSQL_SERVER
3338

3439
#include "my_byteorder.h"
35-
#include "my_sys.h"
40+
#include "my_dbug.h"
41+
#include "my_inttypes.h"
3642
#include "mysql/strings/m_ctype.h"
37-
#include "mysqld_error.h"
38-
#ifdef MYSQL_SERVER
39-
#include "sql/check_stack.h"
40-
#endif
4143
#include "sql-common/json_dom.h" // Json_dom
44+
#include "sql-common/json_error_handler.h"
4245
#include "sql-common/json_syntax_check.h"
43-
#include "sql/field.h" // Field_json
44-
#include "sql/sql_class.h" // THD
4546
#include "sql/sql_const.h"
46-
#include "sql/system_variables.h"
47-
#include "sql/table.h" // TABLE::add_binary_diff()
4847
#include "sql_string.h"
4948
#include "template_utils.h" // down_cast
5049

50+
#ifdef MYSQL_SERVER
51+
#include "my_sys.h"
52+
#include "mysqld_error.h"
53+
#include "sql/check_stack.h"
54+
#include "sql/current_thd.h"
55+
#include "sql/field.h"
56+
#include "sql/table.h"
57+
#endif // MYSQL_SERVER
58+
5159
namespace {
5260

5361
constexpr char JSONB_TYPE_SMALL_OBJECT = 0x0;
@@ -125,28 +133,36 @@ enum enum_serialization_result {
125133
};
126134

127135
static enum_serialization_result serialize_json_value(
128-
const Json_dom *dom, size_t type_pos, String *dest, size_t depth,
129-
bool small_parent, const JsonErrorHandler &json_depth_handler);
136+
const Json_dom *dom, size_t type_pos, size_t depth, bool small_parent,
137+
const JsonSerializationErrorHandler &error_handler, String *dest);
130138
static void write_offset_or_size(char *dest, size_t offset_or_size, bool large);
131139
static uint8 offset_size(bool large);
132140

133-
bool serialize(const Json_dom *dom, String *dest,
134-
const JsonErrorHandler &json_depth_handler,
135-
const JsonErrorHandler &json_key_handler,
136-
const JsonErrorHandler &json_value_handler) {
141+
bool serialize(const Json_dom *dom,
142+
const JsonSerializationErrorHandler &error_handler,
143+
String *dest) {
137144
// Reset the destination buffer.
138145
dest->length(0);
139146
dest->set_charset(&my_charset_bin);
140147

141148
// Reserve space (one byte) for the type identifier.
142149
if (dest->append('\0')) return true; /* purecov: inspected */
143-
enum_serialization_result result =
144-
serialize_json_value(dom, 0, dest, 0, false, json_depth_handler);
145150

146-
if (result == JSON_KEY_TOO_BIG) json_key_handler();
147-
if (result == VALUE_TOO_BIG) json_value_handler();
151+
switch (serialize_json_value(dom, /*type_pos=*/0, /*depth=*/0,
152+
/*small_parent=*/false, error_handler, dest)) {
153+
case OK:
154+
return false;
155+
case VALUE_TOO_BIG:
156+
error_handler.ValueTooBig();
157+
return true;
158+
case JSON_KEY_TOO_BIG:
159+
error_handler.KeyTooBig();
160+
return true;
161+
case FAILURE:
162+
return true;
163+
}
148164

149-
return result != OK;
165+
return true; /* purecov: deadcode */
150166
}
151167

152168
/**
@@ -496,16 +512,15 @@ static bool attempt_inline_value(const Json_dom *value, String *dest,
496512
Serialize a JSON array at the end of the destination string.
497513
498514
@param array the JSON array to serialize
499-
@param dest the destination string
500515
@param large if true, the large storage format will be used
501516
@param depth the current nesting level
502-
@param json_depth_handler handler which will be called for JSON documents
503-
exceeding the maximum allowed depth
517+
@param error_handler a handler that is invoked if an error occurs
518+
@param dest the destination string
504519
@return serialization status
505520
*/
506521
static enum_serialization_result serialize_json_array(
507-
const Json_array *array, String *dest, bool large, size_t depth,
508-
const JsonErrorHandler &json_depth_handler) {
522+
const Json_array *array, bool large, size_t depth,
523+
const JsonSerializationErrorHandler &error_handler, String *dest) {
509524
#ifdef MYSQL_SERVER
510525
if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
511526
return FAILURE; /* purecov: inspected */
@@ -514,7 +529,7 @@ static enum_serialization_result serialize_json_array(
514529
const size_t start_pos = dest->length();
515530
const size_t size = array->size();
516531

517-
if (check_json_depth(++depth, json_depth_handler)) {
532+
if (check_json_depth(++depth, error_handler)) {
518533
return FAILURE;
519534
}
520535

@@ -542,8 +557,8 @@ static enum_serialization_result serialize_json_array(
542557
size_t offset = dest->length() - start_pos;
543558
if (is_too_big_for_json(offset, large)) return VALUE_TOO_BIG;
544559
insert_offset_or_size(dest, entry_pos + 1, offset, large);
545-
auto res = serialize_json_value(elt, entry_pos, dest, depth, !large,
546-
json_depth_handler);
560+
auto res = serialize_json_value(elt, entry_pos, depth, !large,
561+
error_handler, dest);
547562
if (res != OK) return res;
548563
}
549564
entry_pos += entry_size;
@@ -562,16 +577,15 @@ static enum_serialization_result serialize_json_array(
562577
Serialize a JSON object at the end of the destination string.
563578
564579
@param object the JSON object to serialize
565-
@param dest the destination string
566580
@param large if true, the large storage format will be used
567581
@param depth the current nesting level
568-
@param json_depth_handler handler which will be called for JSON documents
569-
exceeding the maximum allowed depth
582+
@param error_handler a handler that is invoked if an error occurs
583+
@param dest the destination string
570584
@return serialization status
571585
*/
572586
static enum_serialization_result serialize_json_object(
573-
const Json_object *object, String *dest, bool large, size_t depth,
574-
const JsonErrorHandler &json_depth_handler) {
587+
const Json_object *object, bool large, size_t depth,
588+
const JsonSerializationErrorHandler &error_handler, String *dest) {
575589
#ifdef MYSQL_SERVER
576590
if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
577591
return FAILURE; /* purecov: inspected */
@@ -580,7 +594,7 @@ static enum_serialization_result serialize_json_object(
580594
const size_t start_pos = dest->length();
581595
const size_t size = object->cardinality();
582596

583-
if (check_json_depth(++depth, json_depth_handler)) {
597+
if (check_json_depth(++depth, error_handler)) {
584598
return FAILURE;
585599
}
586600

@@ -630,8 +644,8 @@ static enum_serialization_result serialize_json_object(
630644
size_t offset = dest->length() - start_pos;
631645
if (is_too_big_for_json(offset, large)) return VALUE_TOO_BIG;
632646
insert_offset_or_size(dest, entry_pos + 1, offset, large);
633-
res = serialize_json_value(child, entry_pos, dest, depth, !large,
634-
json_depth_handler);
647+
res = serialize_json_value(child, entry_pos, depth, !large, error_handler,
648+
dest);
635649
if (res != OK) return res;
636650
}
637651
entry_pos += value_entry_size;
@@ -714,14 +728,13 @@ static enum_serialization_result serialize_datetime(const Json_datetime *jdt,
714728
@param depth the current nesting level
715729
@param small_parent tells if @a dom is contained in an array or object
716730
which is stored in the small storage format
717-
@param json_depth_handler handler which will be called for JSON documents
718-
exceeding the maximum allowed depth
731+
@param error_handler a handler that is invoked if an error occurs
719732
720733
@return serialization status
721734
*/
722735
static enum_serialization_result serialize_json_value(
723-
const Json_dom *dom, size_t type_pos, String *dest, size_t depth,
724-
bool small_parent, const JsonErrorHandler &json_depth_handler) {
736+
const Json_dom *dom, size_t type_pos, size_t depth, bool small_parent,
737+
const JsonSerializationErrorHandler &error_handler, String *dest) {
725738
const size_t start_pos = dest->length();
726739
assert(type_pos < start_pos);
727740

@@ -731,8 +744,8 @@ static enum_serialization_result serialize_json_value(
731744
case enum_json_type::J_ARRAY: {
732745
const Json_array *array = down_cast<const Json_array *>(dom);
733746
(*dest)[type_pos] = JSONB_TYPE_SMALL_ARRAY;
734-
result =
735-
serialize_json_array(array, dest, false, depth, json_depth_handler);
747+
result = serialize_json_array(array, /*large=*/false, depth,
748+
error_handler, dest);
736749
/*
737750
If the array was too large to fit in the small storage format,
738751
reset the destination buffer and retry with the large storage
@@ -747,16 +760,16 @@ static enum_serialization_result serialize_json_value(
747760
if (small_parent) return VALUE_TOO_BIG;
748761
dest->length(start_pos);
749762
(*dest)[type_pos] = JSONB_TYPE_LARGE_ARRAY;
750-
result =
751-
serialize_json_array(array, dest, true, depth, json_depth_handler);
763+
result = serialize_json_array(array, /*large=*/true, depth,
764+
error_handler, dest);
752765
}
753766
break;
754767
}
755768
case enum_json_type::J_OBJECT: {
756769
const Json_object *object = down_cast<const Json_object *>(dom);
757770
(*dest)[type_pos] = JSONB_TYPE_SMALL_OBJECT;
758-
result =
759-
serialize_json_object(object, dest, false, depth, json_depth_handler);
771+
result = serialize_json_object(object, /*large=*/false, depth,
772+
error_handler, dest);
760773
/*
761774
If the object was too large to fit in the small storage format,
762775
reset the destination buffer and retry with the large storage
@@ -771,8 +784,8 @@ static enum_serialization_result serialize_json_value(
771784
if (small_parent) return VALUE_TOO_BIG;
772785
dest->length(start_pos);
773786
(*dest)[type_pos] = JSONB_TYPE_LARGE_OBJECT;
774-
result = serialize_json_object(object, dest, true, depth,
775-
json_depth_handler);
787+
result = serialize_json_object(object, /*large=*/true, depth,
788+
error_handler, dest);
776789
}
777790
break;
778791
}
@@ -1262,18 +1275,12 @@ bool Value::is_backed_by(const String *str) const {
12621275
Copy the binary representation of this value into a buffer,
12631276
replacing the contents of the receiving buffer.
12641277
1278+
@param error_handler a handler that is invoked if an error occurs
12651279
@param buf the receiving buffer
1266-
@param json_depth_handler handler which will be called for JSON documents
1267-
exceeding the maximum allowed depth
1268-
@param json_key_handler handler which will be called for JSON documents
1269-
having keys too large
1270-
@param json_value_handler handler which will be called for JSON documents
1271-
having values too large
12721280
@return false on success, true otherwise
12731281
*/
1274-
bool Value::raw_binary(String *buf, const JsonErrorHandler &json_depth_handler,
1275-
const JsonErrorHandler &json_key_handler,
1276-
const JsonErrorHandler &json_value_handler) const {
1282+
bool Value::raw_binary(const JsonSerializationErrorHandler &error_handler,
1283+
String *buf) const {
12771284
// It's not safe to overwrite ourselves.
12781285
assert(!is_backed_by(buf));
12791286

@@ -1296,29 +1303,24 @@ bool Value::raw_binary(String *buf, const JsonErrorHandler &json_depth_handler,
12961303
buf->append(m_data, m_length);
12971304
case INT: {
12981305
Json_int i(get_int64());
1299-
return serialize(&i, buf, json_depth_handler, json_key_handler,
1300-
json_value_handler);
1306+
return serialize(&i, error_handler, buf);
13011307
}
13021308
case UINT: {
13031309
Json_uint i(get_uint64());
1304-
return serialize(&i, buf, json_depth_handler, json_key_handler,
1305-
json_value_handler);
1310+
return serialize(&i, error_handler, buf);
13061311
}
13071312
case DOUBLE: {
13081313
Json_double d(get_double());
1309-
return serialize(&d, buf, json_depth_handler, json_key_handler,
1310-
json_value_handler);
1314+
return serialize(&d, error_handler, buf);
13111315
}
13121316
case LITERAL_NULL: {
13131317
Json_null n;
1314-
return serialize(&n, buf, json_depth_handler, json_key_handler,
1315-
json_value_handler);
1318+
return serialize(&n, error_handler, buf);
13161319
}
13171320
case LITERAL_TRUE:
13181321
case LITERAL_FALSE: {
13191322
Json_boolean b(m_type == LITERAL_TRUE);
1320-
return serialize(&b, buf, json_depth_handler, json_key_handler,
1321-
json_value_handler);
1323+
return serialize(&b, error_handler, buf);
13221324
}
13231325
case OPAQUE:
13241326
return buf->append(JSONB_TYPE_OPAQUE) || buf->append(field_type()) ||
@@ -1567,8 +1569,7 @@ bool space_needed(const Json_wrapper *value, bool large, size_t *needed) {
15671569

15681570
// Serialize the value to a temporary buffer to find out how big it is.
15691571
StringBuffer<STRING_BUFFER_USUAL_SIZE> buf;
1570-
if (value->to_binary(&buf, JsonDepthErrorHandler, JsonKeyTooBigErrorHandler,
1571-
JsonValueTooBigErrorHandler, InvalidJsonErrorHandler))
1572+
if (value->to_binary(JsonSerializationDefaultErrorHandler(), &buf))
15721573
return true; /* purecov: inspected */
15731574

15741575
assert(buf.length() > 1);
@@ -1780,9 +1781,7 @@ bool Value::update_in_shadow(const Field_json *field, size_t pos,
17801781
char *value_dest = destination + value_offset;
17811782

17821783
StringBuffer<STRING_BUFFER_USUAL_SIZE> buffer;
1783-
if (new_value->to_binary(
1784-
&buffer, JsonDepthErrorHandler, JsonKeyTooBigErrorHandler,
1785-
JsonValueTooBigErrorHandler, InvalidJsonErrorHandler))
1784+
if (new_value->to_binary(JsonSerializationDefaultErrorHandler(), &buffer))
17861785
return true; /* purecov: inspected */
17871786

17881787
assert(buffer.length() > 1);

0 commit comments

Comments
 (0)