MySQL 9.1.0
Source Code Documentation
|
#include "sql-common/json_dom.h"
#include <float.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <compare>
#include <functional>
#include <new>
#include <numeric>
#include <string_view>
#include <utility>
#include "my_rapidjson_size_t.h"
#include <rapidjson/encodings.h>
#include <rapidjson/error/en.h>
#include <rapidjson/error/error.h>
#include <rapidjson/memorystream.h>
#include <rapidjson/reader.h>
#include <rapidjson/allocators.h>
#include <rapidjson/fwd.h>
#include "base64.h"
#include "decimal.h"
#include "dig_vec.h"
#include "my_byteorder.h"
#include "my_checksum.h"
#include "my_compare.h"
#include "my_dbug.h"
#include "my_decimal.h"
#include "my_double2ulonglong.h"
#include "my_sys.h"
#include "my_time.h"
#include "mysql/service_mysql_alloc.h"
#include "mysql/strings/dtoa.h"
#include "mysql/strings/m_ctype.h"
#include "mysql/strings/my_strtoll10.h"
#include "mysqld_error.h"
#include "sql-common/json_binary.h"
#include "sql-common/json_error_handler.h"
#include "sql-common/json_path.h"
#include "sql-common/json_syntax_check.h"
#include "sql/malloc_allocator.h"
#include "sql/sql_const.h"
#include "sql_string.h"
#include "string_with_len.h"
#include "template_utils.h"
#include "mysql/strings/int2str.h"
#include "mysql_com.h"
#include "sql/current_thd.h"
#include "sql/derror.h"
#include "sql/field.h"
#include "sql/psi_memory_key.h"
#include "sql/sql_class.h"
#include "sql/sql_error.h"
#include "sql/sql_sort.h"
#include "sql/sql_time.h"
#include "sql/system_variables.h"
Classes | |
class | anonymous_namespace{json_dom.cc}::Rapid_json_handler |
This class implements rapidjson's Handler concept to make our own handler which will construct our DOM from the parsing of the JSON text. More... | |
struct | anonymous_namespace{json_dom.cc}::Json_child_equal |
Functor which compares a child DOM of a JSON array or JSON object for equality. More... | |
class | anonymous_namespace{json_dom.cc}::Cmp_json |
class | anonymous_namespace{json_dom.cc}::Eq_json |
struct | anonymous_namespace{json_dom.cc}::Json_seek_params |
Input and output parameters to seek_no_dup_elimination that remain constant in recursive calls. More... | |
class | anonymous_namespace{json_dom.cc}::Wrapper_sort_key |
Wrapper around a sort key buffer. More... | |
class | anonymous_namespace{json_dom.cc}::Wrapper_hash_key |
Helper class for building a hash key. More... | |
Namespaces | |
namespace | anonymous_namespace{json_dom.cc} |
Macros | |
#define | DUMP_CALLBACK(name, state) |
#define | MAX_NUMBER_SORT_PAD (std::max(DBL_DIG, DECIMAL_MAX_POSSIBLE_PRECISION) + VARLEN_PREFIX + 3) |
Typedefs | |
using | Sorted_index_array = Prealloced_array< size_t, 16 > |
Enumerations | |
enum class | anonymous_namespace{json_dom.cc}::enum_json_opaque_type { anonymous_namespace{json_dom.cc}::J_OPAQUE_BLOB = static_cast<int>(enum_json_type::J_ERROR) + 1 , anonymous_namespace{json_dom.cc}::J_OPAQUE_BIT } |
Extended type ids so that JSON_TYPE() can give useful type names to certain sub-types of J_OPAQUE. More... | |
Functions | |
static Json_dom * | json_binary_to_dom_template (const json_binary::Value &v) |
Create a DOM template for the provided json_binary::Value. More... | |
static Json_array_ptr | wrap_in_array (Json_dom_ptr dom) |
Auto-wrap a dom in an array if it is not already an array. More... | |
Json_dom_ptr | merge_doms (Json_dom_ptr left, Json_dom_ptr right) |
Merge two doms. More... | |
static bool | add_if_missing (Json_dom *candidate, Json_dom_vector *duplicates, Json_dom_vector *result) |
Add a value to a vector if it isn't already there. More... | |
static bool | is_seek_done (const Json_dom_vector *hits, bool only_need_one) |
Check if a seek operation performed by find_child_doms() or Json_dom::seek() is done. More... | |
static bool | find_child_doms (Json_dom *dom, const Json_path_iterator ¤t_leg, const Json_path_iterator &last_leg, bool auto_wrap, bool only_need_one, Json_dom_vector *duplicates, Json_dom_vector *result) |
Find the child Json_dom objects identified by the given path. More... | |
static bool | path_gives_duplicates (const Json_path_iterator &begin, const Json_path_iterator &end, bool auto_wrap) |
Does a search on this path, using Json_dom::seek() or Json_wrapper::seek(), need duplicate elimination? More... | |
static enum_json_type | bjson2json (const json_binary::Value::enum_type bintype) |
Map the JSON type used by the binary representation to the type used by Json_dom and Json_wrapper. More... | |
static std::string | get_string_data (const json_binary::Value &v) |
Get string data as std::string from a json_binary::Value. More... | |
static bool | reserve (String *buffer, size_t needed) |
Reserve space in a string buffer. More... | |
static bool | escape_character (char c, String *buf) |
Escape a special character in a JSON string, as described in double_quote(), and append it to a buffer. More... | |
bool | double_quote (const char *cptr, size_t length, String *buf) |
Perform quoting on a JSON string to make an external representation of it. More... | |
template<typename T > | |
static Json_wrapper & | assign_json_wrapper (T &&from, Json_wrapper *to) |
Common implementation of move-assignment and copy-assignment for Json_wrapper. More... | |
static bool | single_quote (String *buffer, bool json_quoted) |
Possibly append a single quote to a buffer. More... | |
static bool | print_string (String *buffer, bool json_quoted, std::string_view data) |
Pretty-print a string to an evolving buffer, double-quoting if requested. More... | |
static bool | newline_and_indent (String *buffer, size_t level) |
Helper function for wrapper_to_string() which adds a newline and indentation up to the specified level. More... | |
static bool | append_comma (String *buffer, bool pretty) |
Append a comma to separate elements in JSON arrays and objects. More... | |
static bool | wrapper_to_string (const Json_wrapper &wr, String *buffer, bool json_quoted, bool pretty, const char *func_name, size_t depth, const JsonErrorHandler &depth_handler) |
Helper function which does all the heavy lifting for Json_wrapper::to_string(). More... | |
static bool | seek_no_dup_elimination (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Finds all of the JSON sub-documents which match the path expression. More... | |
static std::function< bool(const json_binary::Value &, const Json_path_iterator &, const Json_seek_params &)> | get_seek_func (const Json_path_iterator &it, const Json_seek_params ¶ms) |
Get which helper function of seek_no_dup_elimination() should be used for this path leg. More... | |
static bool | seek_member (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles jpl_member path legs. More... | |
static bool | seek_member_wildcard (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles jpl_member_wildcard path legs. More... | |
static bool | seek_array_cell (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles jpl_array_cell path legs. More... | |
static bool | seek_array_range (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles jpl_array_cell_wildcard and jpl_array_range path legs. More... | |
static bool | seek_ellipsis (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles jpl_ellipsis path legs. More... | |
static bool | seek_end (const json_binary::Value &value, const Json_path_iterator ¤t_leg, const Json_seek_params ¶ms) |
Helper function for seek_no_dup_elimination which handles the end of the path. More... | |
static int | compare_json_decimal_double (const my_decimal &a, double b) |
Compare a decimal value to a double by converting the double to a decimal. More... | |
static int | compare_json_decimal_int (const my_decimal &a, longlong b) |
Compare a decimal value to a signed integer by converting the integer to a decimal. More... | |
static int | compare_json_decimal_uint (const my_decimal &a, ulonglong b) |
Compare a decimal value to an unsigned integer by converting the integer to a decimal. More... | |
static int | compare_json_double_int (double a, longlong b) |
Compare a JSON double to a JSON signed integer. More... | |
static int | compare_json_double_uint (double a, ulonglong b) |
Compare a JSON double to a JSON unsigned integer. More... | |
static int | compare_json_int_uint (longlong a, ulonglong b) |
Compare a JSON signed integer to a JSON unsigned integer. More... | |
static int | compare_json_strings (std::string_view str1, std::string_view str2, const CHARSET_INFO *cs=nullptr) |
Compare the contents of two strings in a JSON value. More... | |
static void | make_json_numeric_sort_key (const char *from, size_t len, bool negative, Wrapper_sort_key *to) |
Make a sort key for a JSON numeric value from its string representation. More... | |
static bool | sort_and_remove_dups (const Json_wrapper &orig, Sorted_index_array *v) |
Sort the elements of a JSON array and remove duplicates. More... | |
bool | json_wrapper_contains (const Json_wrapper &doc_wrapper, const Json_wrapper &containee_wr, bool *result) |
Check if one Json_wrapper contains all the elements of another Json_wrapper. More... | |
size_t | anonymous_namespace{json_dom.cc}::opaque_index (enum_field_types field_type) |
Compute an index into json_type_string_map to be applied to certain sub-types of J_OPAQUE. More... | |
string_view | json_type_name (const Json_wrapper &doc) |
Returns the name of the type of the JSON document contained in "doc". More... | |
#define DUMP_CALLBACK | ( | name, | |
state | |||
) |
#define MAX_NUMBER_SORT_PAD (std::max(DBL_DIG, DECIMAL_MAX_POSSIBLE_PRECISION) + VARLEN_PREFIX + 3) |
using Sorted_index_array = Prealloced_array<size_t, 16> |
|
static |
Add a value to a vector if it isn't already there.
This is used for removing duplicate matches for daisy-chained ellipsis tokens in find_child_doms(). The problem with daisy-chained ellipses is that the candidate set may contain the same Json_dom object multiple times at different nesting levels after matching the first ellipsis. That is, the candidate set may contain a Json_dom and its parent, grandparent and so on. When matching the next ellipsis in the path, each value in the candidate set and all its children will be inspected, so the nested Json_dom will be seen multiple times, as its grandparent, parent and finally itself are inspected. We want it to appear only once in the result.
The same problem occurs if a possibly auto-wrapping array path leg comes after an ellipsis. If the candidate set contains both an array element and its parent array due to the ellipsis, the auto-wrapping path leg may match the array element twice, and we only want it once in the result.
[in] | candidate | value to add |
[in,out] | duplicates | set of values added, or nullptr if duplicate checking is not needed |
[in,out] | result | vector |
|
static |
Append a comma to separate elements in JSON arrays and objects.
buffer | the string buffer |
pretty | true if pretty printing is enabled |
|
static |
Common implementation of move-assignment and copy-assignment for Json_wrapper.
If from is an rvalue, its contents are moved into to, otherwise the contents are copied over.
|
static |
Map the JSON type used by the binary representation to the type used by Json_dom and Json_wrapper.
Note: Does not look into opaque values to determine if they represent decimal or date/time values. For that, look into the Value and retrieve field_type.
[in] | bintype | type of json_binary |
|
static |
Compare a decimal value to a double by converting the double to a decimal.
a | the decimal value |
b | the double value |
|
static |
Compare a decimal value to a signed integer by converting the integer to a decimal.
a | the decimal value |
b | the signed integer value |
|
static |
Compare a decimal value to an unsigned integer by converting the integer to a decimal.
a | the decimal value |
b | the unsigned integer value |
|
static |
Compare a JSON double to a JSON signed integer.
a | the double value |
b | the integer value |
|
static |
Compare a JSON double to a JSON unsigned integer.
a | the double value |
b | the unsigned integer value |
Compare a JSON signed integer to a JSON unsigned integer.
a | the signed integer |
b | the unsigned integer |
|
static |
Compare the contents of two strings in a JSON value.
The strings could be either JSON string scalars encoded in utf8mb4, or binary strings from JSON opaque scalars. In either case they are compared byte by byte.
str1 | the first string |
str2 | the second string |
cs | If given, this charset will be used for comparison |
-1 | if str1 is less than str2, |
0 | if str1 is equal to str2, |
1 | if str1 is greater than str2 |
bool double_quote | ( | const char * | cptr, |
size_t | length, | ||
String * | buf | ||
) |
Perform quoting on a JSON string to make an external representation of it.
It wraps double quotes (text quotes) around the string (cptr) and also performs escaping according to the following table:
Common name C-style Original unescaped Transformed to escape UTF-8 bytes escape sequence notation in UTF-8 bytes --------------------------------------------------------------- quote \" %x22 %x5C %x22 backslash \\ %x5C %x5C %x5C backspace \b %x08 %x5C %x62 formfeed \f %x0C %x5C %x66 linefeed \n %x0A %x5C %x6E carriage-return \r %x0D %x5C %x72 tab \t %x09 %x5C %x74 unicode \uXXXX A hex number in the %x5C %x75 range of 00-1F, followed by except for the ones 4 hex digits handled above (backspace, formfeed, linefeed, carriage-return, and tab). ---------------------------------------------------------------
[in] | cptr | pointer to string data |
[in] | length | the length of the string |
[in,out] | buf | the destination buffer |
true | on error |
|
static |
Escape a special character in a JSON string, as described in double_quote(), and append it to a buffer.
c | the special character to escape |
buf | the destination buffer |
false | on success |
true | on memory allocation failure |
|
static |
Find the child Json_dom objects identified by the given path.
The child doms are added to a vector.
See the header comment for Json_wrapper::seek() for a discussion of complexities involving path expressions with more than one ellipsis (**) token, or a combination of ellipsis and auto-wrapping path legs.
[in] | dom | the DOM to search |
[in] | current_leg | iterator to the path leg to look at |
[in] | last_leg | iterator to the last path leg (exclusive) |
[in] | auto_wrap | if true, auto-wrap non-arrays when matching against array path legs |
[in] | only_need_one | true if we can stop after finding one match |
[in,out] | duplicates | set of values collected, which helps to identify duplicate arrays and objects introduced by daisy-chained tokens or auto-wrapping, or nullptr if duplicate elimination is not needed for this path leg |
[in,out] | result | the vector of qualifying children |
|
static |
Get which helper function of seek_no_dup_elimination() should be used for this path leg.
|
static |
Get string data as std::string from a json_binary::Value.
|
inlinestatic |
Check if a seek operation performed by find_child_doms() or Json_dom::seek() is done.
|
static |
Create a DOM template for the provided json_binary::Value.
If the binary value represents a scalar, create a Json_dom object that represents the scalar and return a pointer to it.
If the binary value represents an object or an array, create an empty Json_object or Json_array object and return a pointer to it.
v | the binary value to convert to DOM |
string_view json_type_name | ( | const Json_wrapper & | doc | ) |
Returns the name of the type of the JSON document contained in "doc".
bool json_wrapper_contains | ( | const Json_wrapper & | doc_wrapper, |
const Json_wrapper & | containee_wr, | ||
bool * | result | ||
) |
Check if one Json_wrapper contains all the elements of another Json_wrapper.
[in] | doc_wrapper | the containing document |
[in] | containee_wr | the possibly contained document |
[out] | result | true if doc_wrapper contains containee_wr, false otherwise |
false | on success |
true | on failure |
|
static |
Make a sort key for a JSON numeric value from its string representation.
The input string could be either on scientific format (such as 1.234e2) or on plain format (such as 12.34).
The sort key will have the following parts:
1) One byte that is JSON_KEY_NUMBER_NEG, JSON_KEY_NUMBER_ZERO or JSON_KEY_NUMBER_POS if the number is positive, zero or negative, respectively.
2) Two bytes that represent the decimal exponent of the number (log10 of the number, truncated to an integer).
3) All the digits of the number, without leading zeros.
4) Padding to ensure that equal numbers sort equal even if they have a different number of trailing zeros.
If the number is zero, parts 2, 3 and 4 are skipped.
For negative numbers, the values in parts 2, 3 and 4 need to be inverted so that bigger negative numbers sort before smaller negative numbers.
[in] | from | the string representation of the number |
[in] | len | the length of the input string |
[in] | negative | true if the number is negative, false otherwise |
[in,out] | to | the target sort key |
Json_dom_ptr merge_doms | ( | Json_dom_ptr | left, |
Json_dom_ptr | right | ||
) |
Merge two doms.
The right dom is either subsumed into the left dom or the contents of the right dom are transferred to the left dom and the right dom is deleted. After calling this function, the caller should not reference the right dom again. It has been deleted.
Returns NULL if there is a memory allocation failure. In this case both doms are deleted.
scalars - If any of the documents that are being merged is a scalar, each scalar document is autowrapped as a single value array before merging.
arrays - When merging a left array with a right array, then the result is the left array concatenated with the right array. For instance, [ 1, 2 ] merged with [ 3, 4 ] is [ 1, 2, 3, 4 ].
array and object - When merging an array with an object, the object is autowrapped as an array and then the rule above is applied. So [ 1, 2 ] merged with { "a" : true } is [ 1, 2, { "a": true } ].
objects - When merging two objects, the two objects are concatenated into a single, larger object. So { "a" : "foo" } merged with { "b" : 5 } is { "a" : "foo", "b" : 5 }.
duplicates - When two objects are merged and they share a key, the values associated with the shared key are merged.
[in,out] | left | The recipient dom. |
[in,out] | right | The dom to be consumed |
|
static |
Helper function for wrapper_to_string() which adds a newline and indentation up to the specified level.
[in,out] | buffer | the buffer to write to |
[in] | level | how many nesting levels to add indentation for |
false | on success |
true | on error |
|
static |
Does a search on this path, using Json_dom::seek() or Json_wrapper::seek(), need duplicate elimination?
Duplicate elimination is needed if the path contains multiple ellipses, or if it contains an auto-wrapping array path leg after an ellipses. See Json_wrapper::seek() for more details.
begin | the beginning of the path |
end | the end of the path (exclusive) |
auto_wrap | true if array auto-wrapping is used |
true | if duplicate elimination is needed |
false | if the path won't produce duplicates |
|
static |
Pretty-print a string to an evolving buffer, double-quoting if requested.
[in] | buffer | the buffer to print to |
[in] | json_quoted | true if we should double-quote |
[in] | data | the string to print |
|
static |
Reserve space in a string buffer.
If reallocation is needed, increase the size of the buffer exponentially.
buffer | the string buffer |
needed | the number of bytes needed |
|
static |
Helper function for seek_no_dup_elimination which handles jpl_array_cell path legs.
|
static |
Helper function for seek_no_dup_elimination which handles jpl_array_cell_wildcard and jpl_array_range path legs.
|
static |
Helper function for seek_no_dup_elimination which handles jpl_ellipsis path legs.
|
static |
Helper function for seek_no_dup_elimination which handles the end of the path.
|
static |
Helper function for seek_no_dup_elimination which handles jpl_member path legs.
|
static |
Helper function for seek_no_dup_elimination which handles jpl_member_wildcard path legs.
|
static |
Finds all of the JSON sub-documents which match the path expression.
Puts the matches on an evolving vector of results. This is a fast-track method for paths which don't need duplicate elimination due to multiple ellipses or the combination of ellipses and auto-wrapping. Those paths can take advantage of the efficient positioning logic of json_binary::Value.
[in] | value | the JSON value to search |
[in] | current_leg | iterator to the first path leg to look at. Usually called on the root document with an iterator pointing to the beginning of the path, and then incremented in recursive calls within this function. |
[in,out] | params | the seek parameters |
|
inlinestatic |
Possibly append a single quote to a buffer.
[in,out] | buffer | receiving buffer |
[in] | json_quoted | whether or not a quote should be appended |
|
static |
Sort the elements of a JSON array and remove duplicates.
[in] | orig | the original JSON array |
[out] | v | vector that will be filled with the indexes of the array elements in increasing order |
|
static |
Auto-wrap a dom in an array if it is not already an array.
Delete the dom if there is a memory allocation failure.
|
static |
Helper function which does all the heavy lifting for Json_wrapper::to_string().
It processes the Json_wrapper recursively. The depth parameter keeps track of the current nesting level. When it reaches JSON_DOCUMENT_MAX_DEPTH (see json_syntax_check.cc for definition), it gives up in order to avoid running out of stack space.
[in] | wr | the value to convert to a string |
[in,out] | buffer | the buffer to write to |
[in] | json_quoted | quote strings if true |
[in] | pretty | add newlines and indentation if true |
[in] | func_name | the name of the calling function |
[in] | depth | the nesting level of wr |
[in] | depth_handler | Pointer to a function that should handle error occurred when depth is exceeded. |
false | on success |
true | on error |
const size_t kMaxJsonTypeNameLength |
The maximum length of the type name returned from JSON_TYPE.
|
staticconstexpr |
The number of enumerators in the enum_json_type enum.
|
staticconstexpr |
The following matrix tells how two JSON values should be compared based on their types.
If type_comparison[type_of_a][type_of_b] is -1, it means that a is smaller than b. If it is 1, it means that a is greater than b. If it is 0, it means it cannot be determined which value is the greater one just by looking at the types.