-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
json_dom.h
1953 lines (1612 loc) · 63 KB
/
json_dom.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef JSON_DOM_INCLUDED
#define JSON_DOM_INCLUDED
/* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <assert.h>
#include <stddef.h>
#include <iterator>
#include <map>
#include <memory> // unique_ptr
#include <new>
#include <string>
#include <type_traits> // is_base_of
#include <utility>
#include <vector>
#include "field_types.h" // enum_field_types
#include "my_compiler.h"
#include "my_inttypes.h"
#include "my_time.h" // my_time_flags_t
#include "mysql/mysql_lex_string.h"
#include "mysql_time.h" // MYSQL_TIME
#include "prealloced_array.h" // Prealloced_array
#include "sql/json_binary.h" // json_binary::Value
#include "sql/malloc_allocator.h" // Malloc_allocator
#include "sql/my_decimal.h" // my_decimal
class Field_json;
class Json_array;
class Json_container;
class Json_dom;
class Json_object;
class Json_path;
class Json_seekable_path;
class Json_wrapper;
class String;
class THD;
typedef Prealloced_array<Json_wrapper, 16> Json_wrapper_vector;
typedef Prealloced_array<Json_dom *, 16> Json_dom_vector;
using Json_dom_ptr = std::unique_ptr<Json_dom>;
using Json_array_ptr = std::unique_ptr<Json_array>;
using Json_object_ptr = std::unique_ptr<Json_object>;
/**
@file sql/json_dom.h
JSON DOM.
When a JSON value is retrieved from a column, a prior it exists in
a binary form, cf. Json_binary::Value class.
However, when we need to manipulate the JSON values we mostly convert them
from binary form to a structured in-memory from called DOM (from domain
object model) which uses a recursive tree representation of the JSON value
corresponding closely to a parse tree. This form is more suitable for
manipulation.
The JSON type is mostly represented internally as a Json_wrapper which hides
if the representation is a binary or DOM one. This makes is possible to avoid
building a DOM unless we really need one.
The file defines two sets of classes: a) The Json_dom hierarchy and
b) Json_wrapper and its companion classes Json_wrapper_object_iterator and
Json_object_wrapper. For both sets, arrays are traversed using an operator[].
*/
/**
Json values in MySQL comprises the stand set of JSON values plus a
MySQL specific set. A Json _number_ type is subdivided into _int_,
_uint_, _double_ and _decimal_.
MySQL also adds four built-in date/time values: _date_, _time_,
_datetime_ and _timestamp_. An additional _opaque_ value can
store any other MySQL type.
The enumeration is common to Json_dom and Json_wrapper.
The enumeration is also used by Json_wrapper::compare() to
determine the ordering when comparing values of different types,
so the order in which the values are defined in the enumeration,
is significant. The expected order is null < number < string <
object < array < boolean < date < time < datetime/timestamp <
opaque.
*/
enum class enum_json_type {
J_NULL,
J_DECIMAL,
J_INT,
J_UINT,
J_DOUBLE,
J_STRING,
J_OBJECT,
J_ARRAY,
J_BOOLEAN,
J_DATE,
J_TIME,
J_DATETIME,
J_TIMESTAMP,
J_OPAQUE,
J_ERROR
};
/**
Allocate a new Json_dom object and return a std::unique_ptr which points to
it.
@param args the arguments to pass to the constructor
@tparam T the type of Json_dom to create
@tparam Args the type of the arguments to pass to the constructor
@return a pointer to the allocated object
*/
template <typename T, typename... Args>
inline std::unique_ptr<T> create_dom_ptr(Args &&... args) {
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}
/**
JSON DOM abstract base class.
MySQL representation of in-memory JSON objects used by the JSON type
Supports access, deep cloning, and updates. See also Json_wrapper and
json_binary::Value.
Uses heap for space allocation for now. FIXME.
Class hierarchy:
<code><pre>
Json_dom (abstract)
Json_scalar (abstract)
Json_string
Json_number (abstract)
Json_decimal
Json_int
Json_uint
Json_double
Json_boolean
Json_null
Json_datetime
Json_opaque
Json_container (abstract)
Json_object
Json_array
</pre></code>
At the outset, object and array add/insert/append operations takes
a clone unless specified in the method, e.g. add_alias hands the
responsibility for the passed in object over to the object.
*/
class Json_dom {
// so that these classes can call set_parent()
friend class Json_object;
friend class Json_array;
private:
/**
Set the parent dom to which this dom is attached.
@param[in] parent the parent we're being attached to
*/
void set_parent(Json_container *parent) { m_parent = parent; }
public:
virtual ~Json_dom() {}
/**
Allocate space on the heap for a Json_dom object.
@return pointer to the allocated memory, or NULL if memory could
not be allocated (in which case my_error() will have been called
with the appropriate error message)
*/
void *operator new(size_t size, const std::nothrow_t &) noexcept;
/**
Deallocate the space used by a Json_dom object.
*/
void operator delete(void *ptr) noexcept;
/**
Nothrow delete.
*/
void operator delete(void *ptr, const std::nothrow_t &) noexcept;
/**
Get the parent dom to which this dom is attached.
@return the parent dom.
*/
Json_container *parent() const { return m_parent; }
/**
@return the type corresponding to the actual Json_dom subclass
*/
virtual enum_json_type json_type() const = 0;
/**
@return true if the object is a subclass of Json_scalar
*/
virtual bool is_scalar() const { return false; }
/**
@return true of the object is a subclass of Json_number
*/
virtual bool is_number() const { return false; }
#ifdef MYSQL_SERVER
/**
Compute the depth of a document. This is the value which would be
returned by the JSON_DEPTH() system function.
- for scalar values, empty array and empty object: 1
- for non-empty array: 1+ max(depth of array elements)
- for non-empty objects: 1+ max(depth of object values)
For example:
"abc", [] and {} have depth 1.
["abc", [3]] and {"a": "abc", "b": [3]} have depth 3.
@return the depth of the document
*/
virtual uint32 depth() const = 0;
#endif
/**
Make a deep clone. The ownership of the returned object is
henceforth with the caller.
@return a cloned Json_dom object.
*/
virtual Json_dom_ptr clone() const = 0;
/**
Parse Json text to DOM (using rapidjson). The text must be valid JSON.
The results when supplying an invalid document is undefined.
The ownership of the returned object is henceforth with the caller.
If the parsing fails because of a syntax error, the errmsg and
offset arguments will be given values that point to a detailed
error message and where the syntax error was located. The caller
will have to generate an error message with my_error() in this
case.
If the parsing fails because of some other error (such as out of
memory), errmsg will point to a location that holds the value
NULL. In this case, parse() will already have called my_error(),
and the caller doesn't need to generate an error message.
@param[in] text the JSON text
@param[in] length the length of the text
@param[out] errmsg any syntax error message (will be ignored if it is NULL)
@param[out] offset the position in the parsed string a syntax error was
found (will be ignored if it is NULL)
@result the built DOM if JSON text was parseable, else NULL
*/
static Json_dom_ptr parse(const char *text, size_t length,
const char **errmsg, size_t *offset);
/**
Construct a DOM object based on a binary JSON value. The ownership
of the returned object is henceforth with the caller.
@param thd current session
@param v the binary value to parse
@return a DOM representation of the binary value, or NULL on error
*/
static Json_dom_ptr parse(const THD *thd, const json_binary::Value &v);
/**
Get the path location of this dom, measured from the outermost
document it nests inside.
*/
Json_path get_location();
/**
Finds all of the json sub-documents which match the path expression.
Adds a vector element for each match.
See the header comment for Json_wrapper.seek() for a discussion
of complexities involving path expression with more than one
ellipsis (**) token.
@param[in] path the (possibly wildcarded) address of the sub-documents
@param[in] legs the number of legs to use from @a path
@param[out] hits one element per match
@param[in] auto_wrap
if true, match a tailing [0] to scalar at that position.
@param[in] only_need_one True if we can stop after finding one match
@return false on success, true on error
*/
bool seek(const Json_seekable_path &path, size_t legs, Json_dom_vector *hits,
bool auto_wrap, bool only_need_one);
private:
/** Parent pointer */
Json_container *m_parent{nullptr};
};
/**
Abstract base class of all JSON container types (Json_object and Json_array).
*/
class Json_container : public Json_dom {
public:
#ifdef MYSQL_SERVER
/**
Replace oldv contained inside this container array or object) with newv. If
this container does not contain oldv, calling the method is a no-op.
@param[in] oldv the value to be replaced
@param[in] newv the new value to put in the container
*/
virtual void replace_dom_in_container(const Json_dom *oldv,
Json_dom_ptr newv) = 0;
#endif // ifdef MYSQL_SERVER
};
/**
A comparator that is used for ordering keys in a Json_object. It
orders the keys on length, and lexicographically if the keys have
the same length. The ordering is ascending. This ordering was chosen
for speed of look-up. See usage in Json_object_map.
*/
struct Json_key_comparator {
bool operator()(const std::string &key1, const std::string &key2) const;
bool operator()(const MYSQL_LEX_CSTRING &key1, const std::string &key2) const;
bool operator()(const std::string &key1, const MYSQL_LEX_CSTRING &key2) const;
// is_transparent must be defined in order to make std::map::find() accept
// keys that are of a different type than the key_type of the map. In
// particular, this is needed to make it possible to call find() with
// MYSQL_LEX_CSTRING arguments and not only std::string arguments. It only has
// to be defined, it doesn't matter which type it is set to.
using is_transparent = void;
};
/**
A type used to hold JSON object elements in a map, see the
Json_object class.
*/
using Json_object_map =
std::map<std::string, Json_dom_ptr, Json_key_comparator,
Malloc_allocator<std::pair<const std::string, Json_dom_ptr>>>;
/**
Represents a JSON container value of type "object" (ECMA), type
J_OBJECT here.
*/
class Json_object final : public Json_container {
private:
/**
Map to hold the object elements.
*/
Json_object_map m_map;
public:
Json_object();
enum_json_type json_type() const override { return enum_json_type::J_OBJECT; }
/**
Insert a clone of the value into the object. If the key already
exists in the object, the existing value is replaced ("last value
wins").
@param[in] key the JSON element key of to be added
@param[in] value a JSON value: the element key's value
@retval false on success
@retval true on failure
*/
bool add_clone(const std::string &key, const Json_dom *value) {
return value == nullptr || add_alias(key, value->clone());
}
/**
Insert the value into the object. If the key already exists in the
object, the existing value is replaced ("last value wins").
Ownership of the value is effectively transferred to the
object and the value will be deallocated by the object so only add
values that can be deallocated safely (no stack variables please!)
New code should prefer #add_alias(const std::string&, Json_dom_ptr)
to this function, because that makes the transfer of ownership
more explicit. This function might be removed in the future.
@param[in] key the JSON key of to be added
@param[in] value a JSON value: the key's value
@retval false on success
@retval true on failure
*/
bool add_alias(const std::string &key, Json_dom *value) {
return add_alias(key, Json_dom_ptr(value));
}
/**
Insert the value into the object. If the key already exists in the
object, the existing value is replaced ("last value wins").
The ownership of the value is transferred to the object.
@param[in] key the key of the value to be added
@param[in] value the value to add
@return false on success, true on failure
*/
bool add_alias(const std::string &key, Json_dom_ptr value);
/**
Transfer all of the key/value pairs in the other object into this
object. The other object is deleted. If this object and the other
object share a key, then the two values of the key are merged.
@param [in] other a pointer to the object which will be consumed
@retval false on success
@retval true on failure
*/
bool consume(Json_object_ptr other);
/**
Return the value at key. The value is not cloned, so make
one if you need it. Do not delete the returned value, please!
If the key is not present, return a null pointer.
@param[in] key the key of the element whose value we want
@return the value associated with the key, or NULL if the key is not found
*/
Json_dom *get(const std::string &key) const;
Json_dom *get(const MYSQL_LEX_CSTRING &key) const;
/**
Remove the child element addressed by key. The removed child is deleted.
@param key the key of the element to remove
@retval true if an element was removed
@retval false if there was no element with that key
*/
bool remove(const std::string &key);
/**
@return The number of elements in the JSON object.
*/
size_t cardinality() const;
#ifdef MYSQL_SERVER
uint32 depth() const override;
#endif
Json_dom_ptr clone() const override;
#ifdef MYSQL_SERVER
void replace_dom_in_container(const Json_dom *oldv,
Json_dom_ptr newv) override;
#endif
/**
Remove all elements in the object.
*/
void clear() { m_map.clear(); }
/**
Constant iterator over the elements in the JSON object. Each
element is represented as a std::pair where first is a std::string
that represents the key name, and second is a pointer to a
Json_dom that represents the value.
*/
typedef Json_object_map::const_iterator const_iterator;
/// Returns a const_iterator that refers to the first element.
const_iterator begin() const { return m_map.begin(); }
/// Returns a const_iterator that refers past the last element.
const_iterator end() const { return m_map.end(); }
/**
Implementation of the MergePatch function specified in RFC 7396:
define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} # Ignore the contents and set it to an empty Object
for each Key/Value pair in Patch:
if Value is null:
if Key exists in Target:
remove the Key/Value pair from Target
else:
Target[Key] = MergePatch(Target[Key], Value)
return Target
else:
return Patch
@param patch the object that describes the patch
@retval false on success
@retval true on memory allocation error
*/
bool merge_patch(Json_object_ptr patch);
};
/**
Represents a JSON array container, i.e. type J_ARRAY here.
*/
class Json_array final : public Json_container {
private:
/// Holds the array values.
std::vector<Json_dom_ptr, Malloc_allocator<Json_dom_ptr>> m_v;
public:
Json_array();
enum_json_type json_type() const override { return enum_json_type::J_ARRAY; }
/**
Append a clone of the value to the end of the array.
@param[in] value a JSON value to be appended
@retval false on success
@retval true on failure
*/
bool append_clone(const Json_dom *value) {
return insert_clone(size(), value);
}
/**
Append the value to the end of the array.
Ownership of the value is effectively transferred to the array and
the value will be deallocated by the array so only append values
that can be deallocated safely (no stack variables please!)
New code should prefer #append_alias(Json_dom_ptr) to this
function, because that makes the transfer of ownership more
explicit. This function might be removed in the future.
@param[in] value a JSON value to be appended
@retval false on success
@retval true on failure
*/
bool append_alias(Json_dom *value) {
return append_alias(Json_dom_ptr(value));
}
/**
Append the value to the end of the array and take over the
ownership of the value.
@param value the JSON value to be appended
@return false on success, true on failure
*/
bool append_alias(Json_dom_ptr value) {
return insert_alias(size(), std::move(value));
}
/**
Moves all of the elements in the other array to the end of
this array. The other array is deleted.
@param [in] other a pointer to the array which will be consumed
@retval false on success
@retval true on failure
*/
bool consume(Json_array_ptr other);
/**
Insert a clone of the value at position index of the array. If beyond the
end, insert at the end.
@param[in] index the position at which to insert
@param[in] value a JSON value to be inserted
@retval false on success
@retval true on failure
*/
bool insert_clone(size_t index, const Json_dom *value) {
return value == nullptr || insert_alias(index, value->clone());
}
/**
Insert the value at position index of the array.
If beyond the end, insert at the end.
Ownership of the value is effectively transferred to the array and
the value will be deallocated by the array so only append values
that can be deallocated safely (no stack variables please!)
@param[in] index the position at which to insert
@param[in] value a JSON value to be inserted
@retval false on success
@retval true on failure
*/
bool insert_alias(size_t index, Json_dom_ptr value);
/**
Remove the value at this index. A no-op if index is larger than
size. Deletes the value.
@param[in] index the index of the value to remove
@return true if a value was removed, false otherwise.
*/
bool remove(size_t index);
/**
The cardinality of the array (number of values).
@return the size
*/
size_t size() const { return m_v.size(); }
#ifdef MYSQL_SERVER
uint32 depth() const override;
#endif
Json_dom_ptr clone() const override;
/**
Get the value at position index. The value has not been cloned so
it is the responsibility of the user to make a copy if needed. Do
not try to deallocate the returned value - it is owned by the array
and will be deallocated by it in time. It is admissible to modify
its contents (in place; without a clone being taken) if it is a
compound.
@param[in] index the array index
@return the value at index
*/
Json_dom *operator[](size_t index) const {
assert(m_v[index]->parent() == this);
return m_v[index].get();
}
/**
Remove the values in the array.
*/
void clear() { m_v.clear(); }
/// Constant iterator over the elements in the JSON array.
using const_iterator = decltype(m_v)::const_iterator;
/// Returns a const_iterator that refers to the first element.
const_iterator begin() const { return m_v.begin(); }
/// Returns a const_iterator that refers past the last element.
const_iterator end() const { return m_v.end(); }
#ifdef MYSQL_SERVER
void replace_dom_in_container(const Json_dom *oldv,
Json_dom_ptr newv) override;
#endif
/// Sort the array
void sort(const CHARSET_INFO *cs = nullptr);
/**
Check if the given value appears in the array
@param val value to look for
@returns
true value is found
false otherwise
*/
bool binary_search(Json_dom *val);
/**
Sort array and remove duplicate elements.
Used by multi-value index implementation.
*/
void remove_duplicates(const CHARSET_INFO *cs);
friend Json_dom;
};
/**
Abstract base class for all Json scalars.
*/
class Json_scalar : public Json_dom {
public:
#ifdef MYSQL_SERVER
uint32 depth() const final { return 1; }
#endif
bool is_scalar() const final { return true; }
};
/**
Represents a JSON string value (ECMA), of type J_STRING here.
*/
class Json_string final : public Json_scalar {
private:
std::string m_str; //!< holds the string
public:
/*
Construct a Json_string object.
@param args any arguments accepted by std::string's constructors
*/
template <typename... Args>
explicit Json_string(Args &&... args)
: Json_scalar(), m_str(std::forward<Args>(args)...) {}
enum_json_type json_type() const override { return enum_json_type::J_STRING; }
Json_dom_ptr clone() const override {
return create_dom_ptr<Json_string>(m_str);
}
/**
Get the reference to the value of the JSON string.
@return the string reference
*/
const std::string &value() const { return m_str; }
/**
Get the number of characters in the string.
@return the number of characters
*/
size_t size() const { return m_str.size(); }
};
/**
Abstract base class of all JSON number (ECMA) types (subclasses
represent MySQL extensions).
*/
class Json_number : public Json_scalar {
public:
bool is_number() const final { return true; }
};
/**
Represents a MySQL decimal number, type J_DECIMAL.
*/
class Json_decimal final : public Json_number {
private:
my_decimal m_dec; //!< holds the decimal number
public:
static const int MAX_BINARY_SIZE = DECIMAL_MAX_FIELD_SIZE + 2;
explicit Json_decimal(const my_decimal &value);
/**
Get the number of bytes needed to store this decimal in a Json_opaque.
@return the number of bytes.
*/
int binary_size() const;
/**
Get the binary representation of the wrapped my_decimal, so that this
value can be stored inside of a Json_opaque.
@param dest the destination buffer to which the binary representation
is written
@return false on success, true on error
*/
bool get_binary(char *dest) const;
enum_json_type json_type() const override {
return enum_json_type::J_DECIMAL;
}
/**
Get a pointer to the MySQL decimal held by this object. Ownership
is _not_ transferred.
@return the decimal
*/
const my_decimal *value() const { return &m_dec; }
Json_dom_ptr clone() const override {
return create_dom_ptr<Json_decimal>(m_dec);
}
/**
Convert a binary value produced by get_binary() back to a my_decimal.
@details
This and two next functions help storage engine to deal with
decimal value in a serialized JSON document. This funciton converts
serialized value to my_decimal. The later two functions extract the
decimal value from serialized JSON, so SE can index it in multi-valued
index.
@param[in] bin decimal value in binary format
@param[in] len length of the binary value
@param[out] dec my_decimal object to store the value to
@return false on success, true on failure
*/
static bool convert_from_binary(const char *bin, size_t len, my_decimal *dec);
/**
Returns stored DECIMAL binary
@param bin serialized Json_decimal object
@returns
pointer to the binary decimal value
@see #convert_from_binary
*/
static const char *get_encoded_binary(const char *bin) {
// Skip stored precision and scale
return bin + 2;
}
/**
Returns length of stored DECIMAL binary
@param length length of serialized Json_decimal object
@returns
length of the binary decimal value
@see #convert_from_binary
*/
static size_t get_encoded_binary_len(size_t length) {
// Skip stored precision and scale
return length - 2;
}
};
/**
Represents a MySQL double JSON scalar (an extension of the ECMA
number value), type J_DOUBLE.
*/
class Json_double final : public Json_number {
private:
double m_f; //!< holds the double value
public:
explicit Json_double(double value) : Json_number(), m_f(value) {}
enum_json_type json_type() const override { return enum_json_type::J_DOUBLE; }
Json_dom_ptr clone() const override {
return create_dom_ptr<Json_double>(m_f);
}
/**
Return the double value held by this object.
@return the value
*/
double value() const { return m_f; }
};
/**
Represents a MySQL integer (64 bits signed) JSON scalar (an extension
of the ECMA number value), type J_INT.
*/
class Json_int final : public Json_number {
private:
longlong m_i; //!< holds the value
public:
explicit Json_int(longlong value) : Json_number(), m_i(value) {}
enum_json_type json_type() const override { return enum_json_type::J_INT; }
/**
Return the signed int held by this object.
@return the value
*/
longlong value() const { return m_i; }
/**
@return true if the number can be held by a 16 bit signed integer
*/
bool is_16bit() const { return INT_MIN16 <= m_i && m_i <= INT_MAX16; }
/**
@return true if the number can be held by a 32 bit signed integer
*/
bool is_32bit() const { return INT_MIN32 <= m_i && m_i <= INT_MAX32; }
Json_dom_ptr clone() const override { return create_dom_ptr<Json_int>(m_i); }
};
/**
Represents a MySQL integer (64 bits unsigned) JSON scalar (an extension
of the ECMA number value), type J_UINT.
*/
class Json_uint final : public Json_number {
private:
ulonglong m_i; //!< holds the value
public:
explicit Json_uint(ulonglong value) : Json_number(), m_i(value) {}
enum_json_type json_type() const override { return enum_json_type::J_UINT; }
/**
Return the unsigned int held by this object.
@return the value
*/
ulonglong value() const { return m_i; }
/**
@return true if the number can be held by a 16 bit unsigned
integer.
*/
bool is_16bit() const { return m_i <= UINT_MAX16; }
/**
@return true if the number can be held by a 32 bit unsigned
integer.
*/
bool is_32bit() const { return m_i <= UINT_MAX32; }
Json_dom_ptr clone() const override { return create_dom_ptr<Json_uint>(m_i); }
};
/**
Represents a JSON null type (ECMA), type J_NULL here.
*/
class Json_null final : public Json_scalar {
public:
enum_json_type json_type() const override { return enum_json_type::J_NULL; }
Json_dom_ptr clone() const override { return create_dom_ptr<Json_null>(); }
};
/**
Represents a MySQL date/time value (DATE, TIME, DATETIME or
TIMESTAMP) - an extension to the ECMA set of JSON scalar types, types
J_DATE, J_TIME, J_DATETIME and J_TIMESTAMP respectively. The method
field_type identifies which of the four it is.
*/
class Json_datetime final : public Json_scalar {
private:
MYSQL_TIME m_t; //!< holds the date/time value
enum_field_types m_field_type; //!< identifies which type of date/time
public:
/**
Constructs a object to hold a MySQL date/time value.
@param[in] t the time/value
@param[in] ft the field type: must be one of MYSQL_TYPE_TIME,
MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME or
MYSQL_TYPE_TIMESTAMP.
*/
Json_datetime(const MYSQL_TIME &t, enum_field_types ft)
: Json_scalar(), m_t(t), m_field_type(ft) {}
enum_json_type json_type() const override;
Json_dom_ptr clone() const override;
/**
Return a pointer the date/time value. Ownership is _not_ transferred.
To identify which time time the value represents, use @c field_type.
@return the pointer
*/
const MYSQL_TIME *value() const { return &m_t; }
/**
Return what kind of date/time value this object holds.
@return One of MYSQL_TYPE_TIME, MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME
or MYSQL_TYPE_TIMESTAMP.
*/
enum_field_types field_type() const { return m_field_type; }
/**
Convert the datetime to the packed format used when storing
datetime values.
@param dest the destination buffer to write the packed datetime to
(must at least have size PACKED_SIZE)
*/
void to_packed(char *dest) const;
/**
Convert a packed datetime back to a MYSQL_TIME.
@param from the buffer to read from (must have at least PACKED_SIZE bytes)
@param ft the field type of the value
@param to the MYSQL_TIME to write the value to
*/
static void from_packed(const char *from, enum_field_types ft,
MYSQL_TIME *to);
#ifdef MYSQL_SERVER
/**
Convert a packed datetime to key string for indexing by SE
@param from the buffer to read from
@param ft the field type of the value
@param to the destination buffer
@param dec value's decimals
*/
static void from_packed_to_key(const char *from, enum_field_types ft,
uchar *to, uint8 dec);
#endif
/** Datetimes are packed in eight bytes. */
static const size_t PACKED_SIZE = 8;
};
/**