Skip to content

Commit 0dfe351

Browse files
Amith NagarajappaGeorgios Mappouras
Amith Nagarajappa
authored and
Georgios Mappouras
committed
WL#16345: DOM support for JSON Modify and JSON Merge functions
1. JSON_DOM support for JSON Modify and JSON Merge functions 2. Multi arg expression support for JSON MERGE functions and MODIFY functions Bug#36531320 - CREATE TABLE AS SELECT JSON_COL FROM TABLE produces wrong results if JSON column has NULL values Change-Id: I9e7c770acf1032861f0931890ef37bc289fc6fa2
1 parent 0074fc8 commit 0dfe351

File tree

4 files changed

+56
-58
lines changed

4 files changed

+56
-58
lines changed

sql-common/json_dom.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ static Json_dom *json_binary_to_dom_template(const json_binary::Value &v);
105105

106106
using Sorted_index_array = Prealloced_array<size_t, 16>;
107107

108-
#ifdef MYSQL_SERVER
109108
/**
110109
Auto-wrap a dom in an array if it is not already an array. Delete
111110
the dom if there is a memory allocation failure.
@@ -138,7 +137,6 @@ Json_dom_ptr merge_doms(Json_dom_ptr left, Json_dom_ptr right) {
138137

139138
return left_array;
140139
}
141-
#endif // ifdef MYSQL_SERVER
142140

143141
void *Json_dom::operator new(size_t size, const std::nothrow_t &) noexcept {
144142
/*
@@ -824,7 +822,6 @@ bool Json_object::add_alias(const std::string &key, Json_dom_ptr value) {
824822
return false;
825823
}
826824

827-
#ifdef MYSQL_SERVER
828825
bool Json_object::consume(Json_object_ptr other) {
829826
for (auto &other_member : other->m_map) {
830827
auto &key = other_member.first;
@@ -848,7 +845,6 @@ bool Json_object::consume(Json_object_ptr other) {
848845

849846
return false;
850847
}
851-
#endif // ifdef MYSQL_SERVER
852848

853849
template <typename Key>
854850
static Json_dom *json_object_get(const Json_dom *object [[maybe_unused]],

sql-common/json_path.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,3 +771,33 @@ static bool is_ecmascript_identifier(const std::string_view &name) {
771771

772772
return true;
773773
}
774+
775+
bool clone_without_autowrapping(const Json_path *source_path,
776+
Json_path_clone *target_path, Json_wrapper *doc,
777+
PSI_memory_key key) {
778+
Json_wrapper_vector hits(key);
779+
target_path->clear();
780+
for (const Json_path_leg *path_leg : *source_path) {
781+
if (path_leg->is_autowrap()) {
782+
/*
783+
We have a partial path of the form
784+
pathExpression[0]
785+
So see if pathExpression identifies a non-array value.
786+
*/
787+
hits.clear();
788+
if (doc->seek(*target_path, target_path->leg_count(), &hits, false, true))
789+
return true; /* purecov: inspected */
790+
if (!hits.empty() && hits[0].type() != enum_json_type::J_ARRAY) {
791+
/*
792+
pathExpression identifies a non-array value.
793+
We satisfy the conditions of the rule above.
794+
So we can throw away the [0] leg.
795+
*/
796+
continue;
797+
}
798+
}
799+
// The rule above is NOT satisfied. So add the leg.
800+
if (target_path->append(path_leg)) return true; /* purecov: inspected */
801+
}
802+
return false;
803+
}

sql-common/json_path.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "prealloced_array.h" // Prealloced_array
4545

4646
class String;
47+
class Json_wrapper;
4748

4849
/** The type of a Json_path_leg. */
4950
enum enum_json_path_leg_type {
@@ -494,4 +495,26 @@ bool parse_path(size_t path_length, const char *path_expression,
494495
*/
495496
bool parse_path(const String &path_value, bool forbid_wildcards,
496497
Json_path *json_path);
498+
499+
/**
500+
Clone a source path to a target path, stripping out legs which are made
501+
redundant by the auto-wrapping rule from the WL#7909 spec and further
502+
extended in the WL#9831 spec:
503+
504+
"If an array cell path leg or an array range path leg is evaluated against a
505+
non-array value, the result of the evaluation is the same as if the non-array
506+
value had been wrapped in a single-element array."
507+
508+
@see Json_path_leg::is_autowrap
509+
510+
@param[in] source_path The original path.
511+
@param[in,out] target_path The clone to be filled in.
512+
@param[in] doc The document to seek through.
513+
@param[in] key Instrumented memory key
514+
@returns True if an error occurred. False otherwise.
515+
*/
516+
bool clone_without_autowrapping(const Json_path *source_path,
517+
Json_path_clone *target_path, Json_wrapper *doc,
518+
PSI_memory_key key);
519+
497520
#endif /* SQL_JSON_PATH_INCLUDED */

sql/item_json_func.cc

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,58 +2080,6 @@ bool Item_func_json_array_insert::val_json(Json_wrapper *wr) {
20802080
return false;
20812081
}
20822082

2083-
/**
2084-
Clone a source path to a target path, stripping out legs which are made
2085-
redundant by the auto-wrapping rule from the WL#7909 spec and further
2086-
extended in the WL#9831 spec:
2087-
2088-
"If an array cell path leg or an array range path leg is evaluated against a
2089-
non-array value, the result of the evaluation is the same as if the non-array
2090-
value had been wrapped in a single-element array."
2091-
2092-
@see Json_path_leg::is_autowrap
2093-
2094-
@param[in] source_path The original path.
2095-
@param[in,out] target_path The clone to be filled in.
2096-
@param[in] doc The document to seek through.
2097-
2098-
@returns True if an error occurred. False otherwise.
2099-
*/
2100-
static bool clone_without_autowrapping(const Json_path *source_path,
2101-
Json_path_clone *target_path,
2102-
Json_wrapper *doc) {
2103-
Json_wrapper_vector hits(key_memory_JSON);
2104-
2105-
target_path->clear();
2106-
for (const Json_path_leg *path_leg : *source_path) {
2107-
if (path_leg->is_autowrap()) {
2108-
/*
2109-
We have a partial path of the form
2110-
2111-
pathExpression[0]
2112-
2113-
So see if pathExpression identifies a non-array value.
2114-
*/
2115-
hits.clear();
2116-
if (doc->seek(*target_path, target_path->leg_count(), &hits, false, true))
2117-
return true; /* purecov: inspected */
2118-
2119-
if (!hits.empty() && hits[0].type() != enum_json_type::J_ARRAY) {
2120-
/*
2121-
pathExpression identifies a non-array value.
2122-
We satisfy the conditions of the rule above.
2123-
So we can throw away the [0] leg.
2124-
*/
2125-
continue;
2126-
}
2127-
}
2128-
// The rule above is NOT satisfied. So add the leg.
2129-
if (target_path->append(path_leg)) return true; /* purecov: inspected */
2130-
}
2131-
2132-
return false;
2133-
}
2134-
21352083
void Item_json_func::mark_for_partial_update(const Field_json *field) {
21362084
assert(supports_partial_update(field));
21372085
m_partial_update_column = field;
@@ -2231,7 +2179,8 @@ bool Item_func_json_set_replace::val_json(Json_wrapper *wr) {
22312179
if (current_path == nullptr) goto return_null;
22322180

22332181
// Clone the path, stripping off redundant auto-wrapping.
2234-
if (clone_without_autowrapping(current_path, &m_path, &docw)) {
2182+
if (clone_without_autowrapping(current_path, &m_path, &docw,
2183+
key_memory_JSON)) {
22352184
return error_json();
22362185
}
22372186

@@ -2895,7 +2844,7 @@ bool Item_func_json_remove::val_json(Json_wrapper *wr) {
28952844
Json_path_clone path(key_memory_JSON);
28962845
for (uint path_idx = 0; path_idx < path_count; ++path_idx) {
28972846
if (clone_without_autowrapping(m_path_cache.get_path(path_idx + 1), &path,
2898-
&wrapper))
2847+
&wrapper, key_memory_JSON))
28992848
return error_json(); /* purecov: inspected */
29002849

29012850
// Cannot remove the root of the document.

0 commit comments

Comments
 (0)