1 /* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #ifndef DD_SERIALIZE_IMPL_H_INCLUDED
24 #define DD_SERIALIZE_IMPL_H_INCLUDED
25
26 #include "my_rapidjson_size_t.h" // IWYU pragma: keep
27
28 #include <rapidjson/document.h> // rapidjson::GenericValue
29 #include <rapidjson/prettywriter.h> // rapidjson::PrettyWriter
30 #include <memory>
31
32 #include "base64.h" // base64_encode
33 #include "m_string.h" // STRING_WITH_LEN
34 #include "my_dbug.h"
35 #include "prealloced_array.h" // Prealloced_array
36 #include "sql/dd/object_id.h" // Object_id typedef
37
38 /**
39 @file
40 @ingroup SDI
41 Internal (private) header file for the (de)serialization code. This
42 file is made up of 5 parts:
43
44 @ref int_func_decl
45 @ref prealloced_typedefs
46 @ref value_overloads
47 @ref key_templates
48 @ref special_composite_templates
49 */
50
51 /**
52 @defgroup int_func_decl Internal Sdi_context Functions
53 @ingroup sdi
54
55 Declarations of internal functions which operate on Sdi_context
56 objects. Conceptually these are member functions of Sdi_context,
57 but declaring them as such would mean that the definition of
58 Sdi_context would have had to be made available in every
59 translation unit where these functions get called (most data
60 dictionary object implementation files).
61
62 This is essentially a modification of the pimpl (Pointer to
63 IMPLementation) idiom where we avoid the need to create separate
64 api and implementation classes and avoid the extra indirection of
65 going through the pimpl pointer.
66
67 @{
68 */
69
70 namespace dd {
71 class Column;
72 class Index;
73 class Properties;
74 template <typename T>
75 class Collection;
76 /**
77 Factory function for creating a Property object from String_type.
78
79 @param str string representation of properties
80 */
81 Properties *parse_properties(const String_type &str);
82
83 class Sdi_wcontext;
84
85 /**
86 Return a non-owning pointer to a char buffer which can be used
87 for e.g. base64 encoding.
88 @param wctx opaque context.
89 @param sz size of buffer.
90 */
91 char *buf_handle(Sdi_wcontext *wctx, size_t sz);
92
93 /**
94 Returns const reference to string holding schema name to use in SDI.
95 @param wctx opaque context.
96 @return schema name to use.
97 */
98
99 const String_type &lookup_schema_name(Sdi_wcontext *wctx);
100
101 /**
102 Look up the tablespace name for a tablespace id. Returns a reference
103 to the name string inside an acquired tablespace object. The
104 lifetime of these tablespace objects are managed by the
105 Auto_releaser in the scope where the dd store is initiated.
106
107 @param wctx opaque context
108 @param id tablespace id to look up
109 @return tablespace name ref
110 */
111
112 const dd::String_type &lookup_tablespace_name(Sdi_wcontext *wctx,
113 dd::Object_id id);
114
115 class Sdi_rcontext;
116
117 /**
118 Register Column objects being deserialized so that it will be
119 possible to resolve references to it after deserialization has
120 finished.
121
122 @param rctx opaque context
123 @param column_object object which may be referenced by other objects.
124 */
125
126 void track_object(Sdi_rcontext *rctx, Column *column_object);
127
128 /**
129 Register Index objects being deserialized so that it will be
130 possible to resolve references to it after deserialization has
131 finished.
132
133 @param rctx opaque context
134 @param index_object object which may be referenced by other objects.
135 */
136
137 void track_object(Sdi_rcontext *rctx, Index *index_object);
138
139 /**
140 Return an non-owning raw pointer to the deserialized Index object
141 with ordinal postion index opx (ordinal position opx+1). The unused
142 const Index* argument is needed for overload resolution.
143
144 @param rctx opaque context
145 @param opx ordinal position index
146 */
147
148 Index *get_by_opx(Sdi_rcontext *rctx, const Index *, uint opx);
149
150 /**
151 Return an non-owning raw pointer to the deserialized Column object
152 with ordinal postion index opx (ordinal position opx+1). The unused
153 const Column* argument is needed for overload resolution.
154
155 @param rctx opaque context
156 @param opx ordinal position index
157 */
158
159 Column *get_by_opx(Sdi_rcontext *rctx, const Column *, uint opx);
160
161 /**
162 Return a non-owning pointer to a char buffer which can be used
163 for e.g. base64 encoding.
164 @param rctx opaque context
165 @param sz size of buffer
166 @return non-owning pointer to buffer
167 */
168
169 char *buf_handle(Sdi_rcontext *rctx, size_t sz);
170
171 /**
172 Return the the Object_id of a schema name in the current data
173 dictionary. Used to recreate a reference to a schema during
174 deserialization.
175
176 @param rctx opaque context.
177 @param name schema name used as reference.
178 @param idp [OUT] pointer to Object_id variable where result is stored.
179 @return MySQL error handling.
180 */
181
182 bool lookup_schema_ref(Sdi_rcontext *rctx, const String_type &name,
183 Object_id *idp);
184
185 /**
186 Return the the Object_id of a tablespace name in the current data
187 dictionary. Used to recreate a reference to a tablespace during
188 deserialization.
189
190 @param rctx opaque context.
191 @param name schema name used as reference.
192 @param idp [OUT] pointer to Object_id variable where result is stored.
193 @return MySQL error handling.
194
195 */
196
197 bool lookup_tablespace_ref(Sdi_rcontext *rctx, const String_type &name,
198 Object_id *idp);
199
200 } // namespace dd
201
202 /** @} */ // int_func_decl
203
204 /**
205 @defgroup prealloced_typedefs Prealloced_array Typedefs
206 @ingroup sdi
207
208 Defines a sub-class of Prealloced_array and some useful typedefs for use in
209 (de)serialization code.
210 @{
211 */
212
213 typedef dd::String_type binary_t;
214 template <typename T, size_t PREALLOC = 16>
215 struct dd_vector : public Prealloced_array<T, PREALLOC> {
216 dd_vector(PSI_memory_key psi_key = 0)
217 : Prealloced_array<T, PREALLOC>(psi_key) {}
218 };
219
220 typedef dd_vector<char, 32> Byte_buffer;
221
222 /** @} */ // prealloced_typedefs
223
224 /**
225 @defgroup value_overloads Value Function Overloads
226 @ingroup sdi
227
228 Defines function templates for writing a "bare" (without the key) json value.
229 Each definition is overloaded on the second argument (which isn't a template
230 argument) to handle each builtin type that has a corrsponding rapidjson type.
231 @{
232 */
233
234 template <typename W>
write_value(W * w,bool a)235 void write_value(W *w, bool a) {
236 w->Bool(a);
237 }
238
239 template <typename GV>
read_value(bool * ap,const GV & gv)240 bool read_value(bool *ap, const GV &gv) {
241 if (!gv.IsBool()) {
242 return true;
243 }
244 *ap = gv.GetBool();
245 return false;
246 }
247
248 template <typename W>
write_value(W * w,int a)249 void write_value(W *w, int a) {
250 w->Int(a);
251 }
252
253 template <typename GV>
read_value(int * ap,const GV & gv)254 bool read_value(int *ap, const GV &gv) {
255 if (!gv.IsInt()) {
256 return true;
257 }
258 *ap = gv.GetInt();
259 return false;
260 }
261
262 template <typename W>
write_value(W * w,uint a)263 void write_value(W *w, uint a) {
264 w->Uint(a);
265 }
266
267 template <typename GV>
read_value(uint * ap,const GV & gv)268 bool read_value(uint *ap, const GV &gv) {
269 if (!gv.IsUint()) {
270 return true;
271 }
272 *ap = gv.GetUint();
273 return false;
274 }
275
276 template <typename W>
write_value(W * w,ulong a)277 void write_value(W *w, ulong a) {
278 w->Uint64(a);
279 }
280
281 template <typename GV>
read_value(ulong * ap,const GV & gv)282 bool read_value(ulong *ap, const GV &gv) {
283 if (!gv.IsUint64()) {
284 return true;
285 }
286 *ap = gv.GetUint64();
287 return false;
288 }
289
290 template <typename W>
write_value(W * w,ulonglong a)291 void write_value(W *w, ulonglong a) {
292 w->Uint64(a);
293 }
294
295 template <typename GV>
read_value(ulonglong * ap,const GV & gv)296 bool read_value(ulonglong *ap, const GV &gv) {
297 if (!gv.IsUint64()) {
298 return true;
299 }
300 *ap = gv.GetUint64();
301 return false;
302 }
303
304 template <typename W>
write_value(W * w,const dd::String_type & a)305 void write_value(W *w, const dd::String_type &a) {
306 w->String(a.c_str(), a.size());
307 }
308
309 template <typename GV>
read_value(dd::String_type * ap,const GV & gv)310 bool read_value(dd::String_type *ap, const GV &gv) {
311 if (!gv.IsString()) {
312 return true;
313 }
314 *ap = dd::String_type(gv.GetString(), gv.GetStringLength());
315 return false;
316 }
317 /** @} */ // value_overloads
318
319 template <typename W>
320 void write_value(W *w, dd::String_type *a);
321
322 /**
323 @defgroup key_templates Key-related Function Templates
324 @ingroup sdi
325
326 Defines wrapper function templates which handles the key part when
327 writing and writing json.
328
329 @{
330 */
331
332 template <typename W, typename T>
write(W * w,const T & t,const char * key,size_t key_sz)333 void write(W *w, const T &t, const char *key, size_t key_sz) {
334 w->String(key, key_sz);
335 write_value(w, t);
336 }
337
338 template <typename T, typename GV>
read(T * ap,const GV & gv,const char * key)339 bool read(T *ap, const GV &gv, const char *key) {
340 if (!gv.HasMember(key)) {
341 return true;
342 }
343
344 return read_value(ap, gv[key]);
345 }
346
347 /** @} */ // key_templates
348
349 /**
350 @defgroup special_composite_templates Function Templates for Composite Types
351 @ingroup sdi
352
353 Defines function templates to handle types that do not map directly
354 to a rapidjson type, and require some amount of converson/adaptation.
355
356 @{
357 */
358
359 template <typename W, typename ENUM_T>
write_enum(W * w,ENUM_T enum_val,const char * key,size_t keysz)360 void write_enum(W *w, ENUM_T enum_val, const char *key, size_t keysz) {
361 write(w, static_cast<ulonglong>(enum_val), key, keysz);
362 }
363
364 template <typename ENUM_T, typename GV>
read_enum(ENUM_T * ep,const GV & gv,const char * key)365 bool read_enum(ENUM_T *ep, const GV &gv, const char *key) {
366 ulonglong v = 0;
367 if (read(&v, gv, key)) {
368 return true;
369 }
370 *ep = static_cast<ENUM_T>(v);
371 return false;
372 }
373
374 template <typename W>
write_binary(dd::Sdi_wcontext * wctx,W * w,const binary_t & b,const char * key,size_t keysz)375 void write_binary(dd::Sdi_wcontext *wctx, W *w, const binary_t &b,
376 const char *key, size_t keysz) {
377 int binsz = static_cast<int>(b.size());
378 int b64sz = base64_needed_encoded_length(binsz);
379
380 char *bp = dd::buf_handle(wctx, static_cast<size_t>(b64sz));
381 DBUG_ASSERT(bp);
382
383 base64_encode(b.c_str(), binsz, bp);
384 w->String(key, keysz);
385 w->String(bp);
386 }
387
388 template <typename GV>
read_binary(dd::Sdi_rcontext * rctx,binary_t * b,const GV & gv,const char * key)389 bool read_binary(dd::Sdi_rcontext *rctx, binary_t *b, const GV &gv,
390 const char *key) {
391 if (!gv.HasMember(key)) {
392 return true;
393 }
394
395 const GV &a_gv = gv[key];
396
397 if (!a_gv.IsString()) {
398 return true;
399 }
400
401 const char *b64 = a_gv.GetString();
402 size_t b64sz = a_gv.GetStringLength();
403 int binsz = base64_needed_decoded_length(b64sz);
404
405 char *bp = dd::buf_handle(rctx, static_cast<size_t>(binsz));
406 binsz = base64_decode(b64, b64sz, bp, nullptr, 0);
407 *b = binary_t(bp, binsz);
408 return false;
409 }
410
411 template <typename W, typename PP>
write_properties(W * w,const PP & p,const char * key,size_t keysz)412 void write_properties(W *w, const PP &p, const char *key, size_t keysz) {
413 write(w, p.raw_string(), key, keysz);
414 }
415
416 template <typename PP, typename GV>
read_properties(PP * p,const GV & gv,const char * key)417 bool read_properties(PP *p, const GV &gv, const char *key) {
418 dd::String_type raw_string;
419 if (read(&raw_string, gv, key)) {
420 return true;
421 }
422 p->insert_values(raw_string);
423 return false;
424 }
425
426 template <typename W, typename PP>
write_opx_reference(W * w,const PP & p,const char * key,size_t keysz)427 void write_opx_reference(W *w, const PP &p, const char *key, size_t keysz) {
428 uint opx = 0;
429 if (p) {
430 DBUG_ASSERT(p->ordinal_position() > 0);
431 opx = p->ordinal_position() - 1;
432 write(w, opx, key, keysz);
433 }
434 }
435
436 template <typename PP, typename GV>
read_opx_reference(dd::Sdi_rcontext * rctx,PP * p,const GV & gv,const char * key)437 bool read_opx_reference(dd::Sdi_rcontext *rctx, PP *p, const GV &gv,
438 const char *key) {
439 uint opx = 0;
440 if (read(&opx, gv, key)) {
441 return true;
442 }
443 *p = get_by_opx(rctx, *p, opx);
444 return false;
445 }
446
447 template <typename GV>
deserialize_schema_ref(dd::Sdi_rcontext * rctx,dd::Object_id * p,const GV & gv,const char * key)448 bool deserialize_schema_ref(dd::Sdi_rcontext *rctx, dd::Object_id *p,
449 const GV &gv, const char *key) {
450 dd::String_type schema_name;
451 return (read(&schema_name, gv, key) ||
452 lookup_schema_ref(rctx, schema_name, p));
453 }
454
455 template <typename W>
serialize_tablespace_ref(dd::Sdi_wcontext * wctx,W * w,dd::Object_id tablespace_id,const char * key,size_t keysz)456 void serialize_tablespace_ref(dd::Sdi_wcontext *wctx, W *w,
457 dd::Object_id tablespace_id, const char *key,
458 size_t keysz) {
459 if (tablespace_id == dd::INVALID_OBJECT_ID) {
460 // There is no name to look up (will be the case for SEs not using
461 // tablespaces
462 return;
463 }
464 const dd::String_type &tablespace_name =
465 lookup_tablespace_name(wctx, tablespace_id);
466
467 if (tablespace_name.empty()) {
468 return;
469 }
470 write(w, tablespace_name, key, keysz);
471 }
472
473 template <typename GV>
deserialize_tablespace_ref(dd::Sdi_rcontext * rctx,dd::Object_id * p,const GV & gv,const char * key)474 bool deserialize_tablespace_ref(dd::Sdi_rcontext *rctx, dd::Object_id *p,
475 const GV &gv, const char *key) {
476 dd::String_type tablespace_name;
477 if (read(&tablespace_name, gv, key)) {
478 return false; // Ok not to have this
479 }
480 return lookup_tablespace_ref(rctx, tablespace_name, p);
481 }
482
483 template <typename W, typename C>
serialize_each(dd::Sdi_wcontext * wctx,W * w,const dd::Collection<C * > & cp,const char * key,size_t keysz)484 void serialize_each(dd::Sdi_wcontext *wctx, W *w, const dd::Collection<C *> &cp,
485 const char *key, size_t keysz) {
486 w->String(key, keysz);
487 w->StartArray();
488 for (const C *vp : cp) {
489 vp->serialize(wctx, w);
490 }
491 w->EndArray(cp.size());
492 }
493
494 template <typename ADD_BINDER, typename GV>
deserialize_each(dd::Sdi_rcontext * rctx,ADD_BINDER add_binder,const GV & obj_gv,const char * key)495 bool deserialize_each(dd::Sdi_rcontext *rctx, ADD_BINDER add_binder,
496 const GV &obj_gv, const char *key) {
497 if (!obj_gv.HasMember(key)) {
498 return true;
499 }
500
501 const GV &array_gv = obj_gv[key];
502 if (!array_gv.IsArray()) {
503 return true;
504 }
505
506 const typename GV::ConstValueIterator end = array_gv.End();
507 for (typename GV::ConstValueIterator it = array_gv.Begin(); it != end; ++it) {
508 if (add_binder()->deserialize(rctx, *it)) {
509 return true;
510 }
511 }
512 return false;
513 }
514 /** @} */ // special_composite_templates
515
516 //} // namespace dd_sdi_impl
517
518 #endif /* DD_SERIALIZE_IMPL_H_INCLUDED */
519