MySQL 9.0.0
Source Code Documentation
json_path.h
Go to the documentation of this file.
1#ifndef SQL_JSON_PATH_INCLUDED
2#define SQL_JSON_PATH_INCLUDED
3
4/* Copyright (c) 2015, 2024, Oracle and/or its affiliates.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is designed to work with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have either included with
16 the program or referenced in the documentation.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License, version 2.0, for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
26
27/**
28 @file json_path.h
29
30 This file contains interface support for the JSON path abstraction.
31 The path abstraction is described by the functional spec
32 attached to WL#7909.
33*/
34
35#include <assert.h>
36#include <stddef.h>
37#include <algorithm>
38#include <new>
39#include <string>
40#include <utility>
41
42#include "my_alloc.h" // MEM_ROOT
44#include "prealloced_array.h" // Prealloced_array
45
46class String;
47
48/** The type of a Json_path_leg. */
50 /**
51 A path leg that represents a JSON object member (such as `.name`).
52 This path leg matches a single member in a JSON object.
53 */
55
56 /**
57 A path leg that represents a JSON array cell (such as `[10]`).
58 This path leg matches a single element in a JSON object.
59 */
61
62 /**
63 A path leg that represents a range in a JSON array
64 (such as `[2 to 7]`).
65 */
67
68 /**
69 @brief A path leg that represents the member wildcard.
70
71 A path leg that represents the member wildcard (`.*`), which
72 matches all the members of a JSON object.
73 */
75
76 /**
77 A path leg that represents the array wildcard (`[*]`), which
78 matches all the elements of a JSON array.
79 */
81
82 /**
83 A path leg that represents the ellipsis (`**`), which matches any
84 JSON value and recursively all the JSON values nested within it if
85 it is an object or an array.
86 */
88};
89
90/**
91 A class that represents the index of an element in a JSON array. The
92 index is 0-based and relative to the beginning of the array.
93*/
94class Json_array_index final {
95 /**
96 The array index. It is 0 if the specified index was before the
97 first element of the array, or equal to the array length if the
98 specified index was after the last element of the array.
99 */
100 size_t m_index;
101
102 /** True if the array index is within the bounds of the array. */
104
105 public:
106 /**
107 Construct a new Json_array_index object representing the specified
108 position in an array of the given length.
109
110 @param index the array index
111 @param from_end true if @a index is relative to the end of the array
112 @param array_length the length of the array
113 */
114 Json_array_index(size_t index, bool from_end, size_t array_length)
115 : m_index(from_end ? (index < array_length ? array_length - index - 1 : 0)
116 : std::min(index, array_length)),
117 m_within_bounds(index < array_length) {}
118
119 /**
120 Is the array index within the bounds of the array?
121
122 @retval true if the array index is within bounds
123 @retval false otherwise
124 */
125 bool within_bounds() const { return m_within_bounds; }
126
127 /**
128 Get the position in the array pointed to by this array index.
129
130 If the index is out of bounds, 0 will be returned if the array
131 index is before the first element in the array, or a value equal
132 to the length of the array if the index is after the last element.
133
134 @return the position in the array (0-based index relative to the
135 start of the array)
136 */
137 size_t position() const { return m_index; }
138};
139
140/**
141 One path leg in a JSON path expression.
142
143 A path leg describes either a key/value pair in an object
144 or a 0-based index into an array.
145*/
146class Json_path_leg final {
147 /// The type of this path leg.
149
150 /// The index of an array cell, or the start of an array range.
152
153 /// Is #m_first_array_index relative to the end of the array?
155
156 /// The end (inclusive) of an array range.
158
159 /// Is #m_last_array_index relative to the end of the array?
161
162 /// The member name of a member path leg.
163 std::string m_member_name;
164
165 public:
166 /**
167 Construct a wildcard or ellipsis path leg.
168
169 @param leg_type the type of wildcard (#jpl_ellipsis,
170 #jpl_member_wildcard or #jpl_array_cell_wildcard)
171 */
173 : m_leg_type(leg_type) {
174 assert(leg_type == jpl_ellipsis || leg_type == jpl_member_wildcard ||
175 leg_type == jpl_array_cell_wildcard);
176 }
177
178 /**
179 Construct an array cell path leg.
180
181 @param index the 0-based index in the array,
182 relative to the beginning of the array
183 */
184 explicit Json_path_leg(size_t index) : Json_path_leg(index, false) {}
185
186 /**
187 Construct an array cell path leg.
188
189 @param index the 0-based index in the array
190 @param from_end true if @a index is relative to the end of the array
191 */
192 Json_path_leg(size_t index, bool from_end)
194 m_first_array_index(index),
196
197 /**
198 Construct an array range path leg.
199
200 @param idx1 the start index of the range, inclusive
201 @param idx1_from_end true if the start index is relative
202 to the end of the array
203 @param idx2 the last index of the range, inclusive
204 @param idx2_from_end true if the last index is relative
205 to the end of the array
206 */
207 Json_path_leg(size_t idx1, bool idx1_from_end, size_t idx2,
208 bool idx2_from_end)
211 m_first_array_index_from_end(idx1_from_end),
212 m_last_array_index(idx2),
213 m_last_array_index_from_end(idx2_from_end) {}
214
215 /**
216 Construct an object member path leg.
217
218 @param member_name the name of the object member
219 @param length the length of the member name
220 */
221 Json_path_leg(const char *member_name, size_t length)
222 : m_leg_type(jpl_member), m_member_name(member_name, length) {}
223
224 /** Construct an object member path leg. */
225 Json_path_leg(const std::string &member_name)
226 : Json_path_leg(member_name.c_str(), member_name.length()) {}
227
228 /** Get the type of the path leg. */
230
231 /** Get the member name of a ::jpl_member path leg. */
232 const std::string &get_member_name() const { return m_member_name; }
233
234 /** Turn into a human-readable string. */
235 bool to_string(String *buf) const;
236
237 /**
238 Is this path leg an auto-wrapping array accessor?
239
240 An auto-wrapping array accessor is an array accessor that matches
241 non-arrays by auto-wrapping them in a single-element array before doing
242 the matching.
243
244 This function returns true for any ::jpl_array_cell or ::jpl_array_range
245 path leg that would match the element contained in a single-element
246 array, and which therefore would also match non-arrays that have been
247 auto-wrapped in single-element arrays.
248 */
249 bool is_autowrap() const;
250
251 /**
252 Get the first array cell pointed to by an array range, or the
253 array cell pointed to by an array cell index.
254
255 @param array_length the length of the array
256 */
257 Json_array_index first_array_index(size_t array_length) const {
260 array_length);
261 }
262
263 /**
264 Get the last array cell pointed to by an array range. The range
265 includes this cell.
266
267 @param array_length the length of the array
268 */
269 Json_array_index last_array_index(size_t array_length) const {
270 assert(m_leg_type == jpl_array_range);
272 array_length);
273 }
274
275 /**
276 A structure that represents an array range.
277 */
278 struct Array_range {
279 size_t m_begin; ///< Beginning of the range, inclusive.
280 size_t m_end; ///< End of the range, exclusive.
281 };
282
283 /**
284 Get the array range pointed to by a path leg of type
285 ::jpl_array_range or ::jpl_array_cell_wildcard.
286 @param array_length the length of the array
287 */
288 Array_range get_array_range(size_t array_length) const;
289};
290
293
294/**
295 A path expression which can be used to seek to
296 a position inside a JSON value.
297*/
299 protected:
300 /** An array of pointers to the legs of the JSON path. */
302
304
305 public:
306 /** Return the number of legs in this searchable path */
307 size_t leg_count() const { return m_path_legs.size(); }
308
309 /** Get an iterator pointing to the first path leg. */
311
312 /** Get an iterator pointing just past the last path leg. */
313 Json_path_iterator end() const { return m_path_legs.end(); }
314
315 /** Get a pointer to the last path leg. The path must not be empty. */
316 const Json_path_leg *last_leg() const { return m_path_legs.back(); }
317};
318
319/**
320 A JSON path expression.
321
322 From the user's point of view, a path expression is a string literal
323 with the following structure. We parse this structure into a
324 Json_path object:
325
326 pathExpression ::= scope pathLeg (pathLeg)*
327
328 scope ::= dollarSign
329
330 pathLeg ::= member | arrayLocation | doubleAsterisk
331
332 member ::= period (keyName | asterisk)
333
334 arrayLocation ::=
335 leftBracket
336 (arrayIndex | arrayRange | asterisk)
337 rightBracket
338
339 arrayIndex ::=
340 non-negative-integer |
341 last [ minus non-negative-integer ]
342
343 arrayRange ::= arrayIndex to arrayIndex
344
345 keyName ::= ECMAScript-identifier | ECMAScript-string-literal
346
347 doubleAsterisk ::= **
348
349 to ::= "to"
350
351 last ::= "last"
352*/
353class Json_path final : public Json_seekable_path {
354 private:
355 /**
356 A MEM_ROOT in which the Json_path_leg objects pointed to by
357 #Json_seekable_path::m_path_legs are allocated.
358 */
360 /**
361 Key used to instrument memory usage.
362 */
364
365 public:
366 explicit Json_path(PSI_memory_key key);
367
369 for (const auto ptr : m_path_legs) ptr->~Json_path_leg();
370 }
371
372 /** Move constructor. */
375 m_mem_root(std::move(other.m_mem_root)),
376 m_psi_key(other.m_psi_key) {
377 // Move the contents of m_path_legs from other into this.
378 m_path_legs = std::move(other.m_path_legs);
379
380 /*
381 Must also make sure that other.m_path_legs is empty, so that we
382 don't end up destroying the same objects twice; once from this's
383 destructor and once from other's destructor.
384
385 Move-constructing a vector would usually leave "other" empty,
386 but it is not guaranteed. Furthermore, m_path_legs is a
387 Prealloced_array, not a std::vector, so often moving will mean
388 copying from one prealloced area to another instead of simply
389 swapping pointers to the backing array. (And at the time of
390 writing Prealloced_array doesn't even have a move-assignment
391 operator, so the above assignment will always copy and leave
392 "other" unchanged.)
393 */
394 other.m_path_legs.clear();
395 }
396
397 /** Move assignment. */
399 if (&other != this) {
400 this->~Json_path();
401 new (this) Json_path(std::move(other));
402 }
403 return *this;
404 }
405
406 /**
407 Add a path leg to the end of this path.
408 @param[in] leg the leg to add
409 @return false on success, true on error
410 */
411 bool append(const Json_path_leg &leg) {
412 auto ptr = new (&m_mem_root) Json_path_leg(leg);
413 return ptr == nullptr || m_path_legs.push_back(ptr);
414 }
415
416 /**
417 Resets this to an empty path with no legs.
418 */
419 void clear() {
420 // Destruct all the Json_path_leg objects, and clear the pointers to them.
421 for (const auto ptr : m_path_legs) ptr->~Json_path_leg();
423 // Mark the memory as ready for reuse.
425 }
426
427 /**
428 Return true if the path can match more than one value in a JSON document.
429
430 @retval true if the path contains a path leg which is a wildcard,
431 ellipsis or array range
432 @retval false otherwise
433 */
434 bool can_match_many() const;
435
436 /** Turn into a human-readable string. */
437 bool to_string(String *buf) const;
438};
439
440/**
441 A lightweight path expression. This exists so that paths can be cloned
442 from the path legs of other paths without allocating heap memory
443 to copy those legs into. This class does not own the memory of the
444 Json_path_leg objects pointed to by #Json_seekable_path::m_path_legs, it
445 just points to Json_path_leg objects that belong to a Json_path instance.
446*/
448 public:
450 /**
451 Add a path leg to the end of this cloned path.
452 @param[in] leg the leg to add
453 @return false on success, true on error
454 */
455 bool append(const Json_path_leg *leg) { return m_path_legs.push_back(leg); }
456
457 /**
458 Resets this to an empty path with no legs.
459 */
460 void clear() { m_path_legs.clear(); }
461};
462
463/**
464 Initialize a Json_path from a path expression.
465
466 Stops parsing on the first error. It initializes the Json_path and
467 returns false if the path is parsed successfully. Otherwise, it
468 returns false. In that case, the output bad_index argument will
469 contain an index into the path expression. The parsing failed near
470 that index.
471
472 @param[in] path_length The length of the path expression.
473 @param[in] path_expression The string form of the path expression.
474 @param[out] path The Json_path object to be initialized.
475 @param[out] bad_index If null is returned, the parsing failed around here.
476 @return false on success, true on error
477*/
478bool parse_path(size_t path_length, const char *path_expression,
479 Json_path *path, size_t *bad_index);
480
481/**
482 A helper function that uses the above one as workhorse. Entry point for
483 for JSON_TABLE (Table_function_json class) and Json_path_cache. Raises an
484 error if the path expression is syntactically incorrect. Raises an
485 error if the path expression contains wildcard tokens but is not
486 supposed to. Otherwise updates the supplied Json_path object with
487 the parsed path.
488
489 @param[in] path_value A String to be interpreted as a path.
490 @param[in] forbid_wildcards True if the path shouldn't contain * or **
491 @param[out] json_path The object that will hold the parsed path
492
493 @returns false on success (valid path or NULL), true on error
494*/
495bool parse_path(const String &path_value, bool forbid_wildcards,
496 Json_path *json_path);
497#endif /* SQL_JSON_PATH_INCLUDED */
A class that represents the index of an element in a JSON array.
Definition: json_path.h:94
size_t m_index
The array index.
Definition: json_path.h:100
size_t position() const
Get the position in the array pointed to by this array index.
Definition: json_path.h:137
Json_array_index(size_t index, bool from_end, size_t array_length)
Construct a new Json_array_index object representing the specified position in an array of the given ...
Definition: json_path.h:114
bool m_within_bounds
True if the array index is within the bounds of the array.
Definition: json_path.h:103
bool within_bounds() const
Is the array index within the bounds of the array?
Definition: json_path.h:125
A lightweight path expression.
Definition: json_path.h:447
bool append(const Json_path_leg *leg)
Add a path leg to the end of this cloned path.
Definition: json_path.h:455
void clear()
Resets this to an empty path with no legs.
Definition: json_path.h:460
Json_path_clone(PSI_memory_key key)
Definition: json_path.h:449
One path leg in a JSON path expression.
Definition: json_path.h:146
size_t m_first_array_index
The index of an array cell, or the start of an array range.
Definition: json_path.h:151
size_t m_last_array_index
The end (inclusive) of an array range.
Definition: json_path.h:157
Json_path_leg(enum_json_path_leg_type leg_type)
Construct a wildcard or ellipsis path leg.
Definition: json_path.h:172
Json_array_index first_array_index(size_t array_length) const
Get the first array cell pointed to by an array range, or the array cell pointed to by an array cell ...
Definition: json_path.h:257
Array_range get_array_range(size_t array_length) const
Get the array range pointed to by a path leg of type jpl_array_range or jpl_array_cell_wildcard.
Definition: json_path.cc:148
bool m_last_array_index_from_end
Is m_last_array_index relative to the end of the array?
Definition: json_path.h:160
std::string m_member_name
The member name of a member path leg.
Definition: json_path.h:163
enum_json_path_leg_type m_leg_type
The type of this path leg.
Definition: json_path.h:148
bool is_autowrap() const
Is this path leg an auto-wrapping array accessor?
Definition: json_path.cc:125
bool m_first_array_index_from_end
Is m_first_array_index relative to the end of the array?
Definition: json_path.h:154
Json_path_leg(const char *member_name, size_t length)
Construct an object member path leg.
Definition: json_path.h:221
Json_path_leg(size_t index)
Construct an array cell path leg.
Definition: json_path.h:184
Json_path_leg(const std::string &member_name)
Construct an object member path leg.
Definition: json_path.h:225
Json_path_leg(size_t index, bool from_end)
Construct an array cell path leg.
Definition: json_path.h:192
enum_json_path_leg_type get_type() const
Get the type of the path leg.
Definition: json_path.h:229
const std::string & get_member_name() const
Get the member name of a jpl_member path leg.
Definition: json_path.h:232
Json_path_leg(size_t idx1, bool idx1_from_end, size_t idx2, bool idx2_from_end)
Construct an array range path leg.
Definition: json_path.h:207
bool to_string(String *buf) const
Turn into a human-readable string.
Definition: json_path.cc:90
Json_array_index last_array_index(size_t array_length) const
Get the last array cell pointed to by an array range.
Definition: json_path.h:269
A JSON path expression.
Definition: json_path.h:353
Json_path(Json_path &&other)
Move constructor.
Definition: json_path.h:373
~Json_path()
Definition: json_path.h:368
Json_path(PSI_memory_key key)
Definition: json_path.cc:168
bool append(const Json_path_leg &leg)
Add a path leg to the end of this path.
Definition: json_path.h:411
void clear()
Resets this to an empty path with no legs.
Definition: json_path.h:419
bool to_string(String *buf) const
Turn into a human-readable string.
Definition: json_path.cc:171
PSI_memory_key m_psi_key
Key used to instrument memory usage.
Definition: json_path.h:363
Json_path & operator=(Json_path &&other)
Move assignment.
Definition: json_path.h:398
bool can_match_many() const
Return true if the path can match more than one value in a JSON document.
Definition: json_path.cc:181
MEM_ROOT m_mem_root
A MEM_ROOT in which the Json_path_leg objects pointed to by Json_seekable_path::m_path_legs are alloc...
Definition: json_path.h:359
A path expression which can be used to seek to a position inside a JSON value.
Definition: json_path.h:298
Json_path_iterator end() const
Get an iterator pointing just past the last path leg.
Definition: json_path.h:313
Json_seekable_path(PSI_memory_key key)
Definition: json_path.cc:165
size_t leg_count() const
Return the number of legs in this searchable path.
Definition: json_path.h:307
const Json_path_leg * last_leg() const
Get a pointer to the last path leg.
Definition: json_path.h:316
Json_path_iterator begin() const
Get an iterator pointing to the first path leg.
Definition: json_path.h:310
Json_path_leg_pointers m_path_legs
An array of pointers to the legs of the JSON path.
Definition: json_path.h:301
bool push_back(const Element_type &element)
Copies an element into the back of the array.
Definition: prealloced_array.h:318
void clear()
Removes (and destroys) all elements.
Definition: prealloced_array.h:601
size_t size() const
Definition: prealloced_array.h:227
iterator begin()
begin : Returns a pointer to the first element in the array.
Definition: prealloced_array.h:254
Element_type & back()
Definition: prealloced_array.h:244
iterator end()
Definition: prealloced_array.h:255
const const Json_path_leg * * const_iterator
Definition: prealloced_array.h:117
Using this class is fraught with peril, and you need to be very careful when doing so.
Definition: sql_string.h:167
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:49
enum_json_path_leg_type
The type of a Json_path_leg.
Definition: json_path.h:49
@ jpl_array_range
A path leg that represents a range in a JSON array (such as [2 to 7]).
Definition: json_path.h:66
@ jpl_array_cell_wildcard
A path leg that represents the array wildcard ([*]), which matches all the elements of a JSON array.
Definition: json_path.h:80
@ jpl_ellipsis
A path leg that represents the ellipsis (**), which matches any JSON value and recursively all the JS...
Definition: json_path.h:87
@ jpl_member
A path leg that represents a JSON object member (such as .name).
Definition: json_path.h:54
@ jpl_array_cell
A path leg that represents a JSON array cell (such as [10]).
Definition: json_path.h:60
@ jpl_member_wildcard
A path leg that represents the member wildcard.
Definition: json_path.h:74
Json_path_leg_pointers::const_iterator Json_path_iterator
Definition: json_path.h:292
bool parse_path(size_t path_length, const char *path_expression, Json_path *path, size_t *bad_index)
Initialize a Json_path from a path expression.
Definition: json_path.cc:258
This file follows Google coding style, except for the name MEM_ROOT (which is kept for historical rea...
static char * path
Definition: mysqldump.cc:149
Definition: buf0block_hint.cc:30
bool length(const dd::Spatial_reference_system *srs, const Geometry *g1, double *length, bool *null) noexcept
Computes the length of linestrings and multilinestrings.
Definition: length.cc:76
Definition: gcs_xcom_synode.h:64
Performance schema instrumentation interface.
required string key
Definition: replication_asynchronous_connection_failover.proto:60
A structure that represents an array range.
Definition: json_path.h:278
size_t m_end
End of the range, exclusive.
Definition: json_path.h:280
size_t m_begin
Beginning of the range, inclusive.
Definition: json_path.h:279
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:83
void ClearForReuse()
Similar to Clear(), but anticipates that the block will be reused for further allocations.
Definition: my_alloc.cc:190