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