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