From a977e40defa5a3c945e46db5cf3cd45f46473ece Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 7 May 2019 07:51:01 -0700 Subject: Add parse_array_or_object() --- sql/field.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- sql/field.h | 10 +++++++--- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 3a234afc719..0d758a08455 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -11226,7 +11226,57 @@ bool Field_mysql_json::val_json (Json_wrapper *wr) wr->steal(&w); return false; } +/** + Read an offset or size field from a buffer. The offset could be either + a two byte unsigned integer or a four byte unsigned integer. + + @param data the buffer to read from + @param large tells if the large or small storage format is used; true + means read four bytes, false means read two bytes +*/ +size_t read_offset_or_size(const char *data, bool large) +{ + return large ? uint4korr(data) : uint2korr(data); +} + +bool parse_array_or_object(Field_mysql_json::enum_type t, const char *data, size_t len, + bool large) +{ + //DBUG_ASSERT(t == Field_mysql_json::ARRAY || t == Field_mysql_json::OBJECT); + /* + Make sure the document is long enough to contain the two length fields + (both number of elements or members, and number of bytes). + */ + const size_t offset_size= large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE; + if (len < 2 * offset_size) + return true; + const size_t element_count= read_offset_or_size(data, large); + const size_t bytes= read_offset_or_size(data + offset_size, large); + + // The value can't have more bytes than what's available in the data buffer. + if (bytes > len) + return true; + /* + Calculate the size of the header. It consists of: + - two length fields + - if it is a JSON object, key entries with pointers to where the keys + are stored + - value entries with pointers to where the actual values are stored + */ + size_t header_size= 2 * offset_size; + if (t==Field_mysql_json::OBJECT) + header_size+= element_count * + (large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL); + header_size+= element_count * + (large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL); + + // The header should not be larger than the full size of the value. + if (header_size > bytes) + return true; /* purecov: inspected */ + //return Value(t, data, bytes, element_count, large); + return 1; +} bool Field_mysql_json::parse_mysql(String *s, bool json_quoted, const char *func_name) const { @@ -11261,13 +11311,13 @@ bool Field_mysql_json::parse_mysql(String *s, bool json_quoted, size_t type= data[0]; - //const char* data1=data+1; - //size_t len=len-1; + const char* data1=data+1; + size_t len=length-1; switch (type) { case JSONB_TYPE_SMALL_OBJECT: - return false; //this->parse_array_or_object(Field_mysql_json::OBJECT, data1, len, false); + return parse_array_or_object(Field_mysql_json::OBJECT, data1, len, false); case JSONB_TYPE_LARGE_OBJECT: return false; //this->parse_array_or_object(Field_mysql_json::OBJECT, data1, len, true); case JSONB_TYPE_SMALL_ARRAY: @@ -11278,8 +11328,8 @@ bool Field_mysql_json::parse_mysql(String *s, bool json_quoted, return false;//this->parse_scalar(type, data, len); } - } + String *Field_mysql_json::val_str(String *buf1_tmp, String *buf2 __attribute__((unused))) { ASSERT_COLUMN_MARKED_FOR_READ; diff --git a/sql/field.h b/sql/field.h index 14e4b104c3e..b50cbc85b7f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4924,7 +4924,7 @@ class Field_mysql_json :public Field_blob @param[in,out] buf1 string buffer for converting JSON value to string @param[in,out] buf2 unused */ - enum enum_type + enum enum_type { OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE, LITERAL_FALSE, @@ -4934,8 +4934,12 @@ class Field_mysql_json :public Field_blob }; String *val_str(String *, String *); bool parse_mysql(String*, bool, const char *) const; - bool parse_array_or_object(); - bool parse_scalar(); + //size_t read_offset_or_size(const char *, bool); + //enum_type type() const {return m_type;} + //bool parse_array_or_object(bool, const char *,size_t ,bool); + //bool parse_scalar(); + //private: + // const enum_type m_type; }; -- cgit v1.2.1