519 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
| /* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
|    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 */
 | |
| 
 | |
| #ifndef DD_SERIALIZE_IMPL_H_INCLUDED
 | |
| #define DD_SERIALIZE_IMPL_H_INCLUDED
 | |
| 
 | |
| #include "my_rapidjson_size_t.h"  // IWYU pragma: keep
 | |
| 
 | |
| #include <rapidjson/document.h>      // rapidjson::GenericValue
 | |
| #include <rapidjson/prettywriter.h>  // rapidjson::PrettyWriter
 | |
| #include <memory>
 | |
| 
 | |
| #include "base64.h"    // base64_encode
 | |
| #include "m_string.h"  // STRING_WITH_LEN
 | |
| #include "my_dbug.h"
 | |
| #include "prealloced_array.h"  // Prealloced_array
 | |
| #include "sql/dd/object_id.h"  // Object_id typedef
 | |
| 
 | |
| /**
 | |
|   @file
 | |
|   @ingroup SDI
 | |
|   Internal (private) header file for the (de)serialization code. This
 | |
|   file is made up of 5 parts:
 | |
| 
 | |
|   @ref int_func_decl
 | |
|   @ref prealloced_typedefs
 | |
|   @ref value_overloads
 | |
|   @ref key_templates
 | |
|   @ref special_composite_templates
 | |
| */
 | |
| 
 | |
| /**
 | |
|   @defgroup int_func_decl Internal Sdi_context Functions
 | |
|   @ingroup sdi
 | |
| 
 | |
|   Declarations of internal functions which operate on Sdi_context
 | |
|   objects. Conceptually these are member functions of Sdi_context,
 | |
|   but declaring them as such would mean that the definition of
 | |
|   Sdi_context would have had to be made available in every
 | |
|   translation unit where these functions get called (most data
 | |
|   dictionary object implementation files).
 | |
| 
 | |
|   This is essentially a modification of the pimpl (Pointer to
 | |
|   IMPLementation) idiom where we avoid the need to create separate
 | |
|   api and implementation classes and avoid the extra indirection of
 | |
|   going through the pimpl pointer.
 | |
| 
 | |
|   @{
 | |
| */
 | |
| 
 | |
| namespace dd {
 | |
| class Column;
 | |
| class Index;
 | |
| class Properties;
 | |
| template <typename T>
 | |
| class Collection;
 | |
| /**
 | |
|    Factory function for creating a Property object from String_type.
 | |
| 
 | |
|    @param str string representation of properties
 | |
|  */
 | |
| Properties *parse_properties(const String_type &str);
 | |
| 
 | |
| class Sdi_wcontext;
 | |
| 
 | |
| /**
 | |
|   Return a non-owning pointer to a char buffer which can be used
 | |
|   for e.g. base64 encoding.
 | |
|   @param wctx opaque context.
 | |
|   @param sz size of buffer.
 | |
| */
 | |
| char *buf_handle(Sdi_wcontext *wctx, size_t sz);
 | |
| 
 | |
| /**
 | |
|   Returns const reference to string holding schema name to use in SDI.
 | |
|   @param wctx opaque context.
 | |
|   @return schema name to use.
 | |
| */
 | |
| 
 | |
| const String_type &lookup_schema_name(Sdi_wcontext *wctx);
 | |
| 
 | |
| /**
 | |
|   Look up the tablespace name for a tablespace id. Returns a reference
 | |
|   to the name string inside an acquired tablespace object. The
 | |
|   lifetime of these tablespace objects are managed by the
 | |
|   Auto_releaser in the scope where the dd store is initiated.
 | |
| 
 | |
|   @param wctx opaque context
 | |
|   @param id tablespace id to look up
 | |
|   @return tablespace name ref
 | |
| */
 | |
| 
 | |
| const dd::String_type &lookup_tablespace_name(Sdi_wcontext *wctx,
 | |
|                                               dd::Object_id id);
 | |
| 
 | |
| class Sdi_rcontext;
 | |
| 
 | |
| /**
 | |
|   Register Column objects being deserialized so that it will be
 | |
|   possible to resolve references to it after deserialization has
 | |
|   finished.
 | |
| 
 | |
|   @param rctx opaque context
 | |
|   @param column_object object which may be referenced by other objects.
 | |
| */
 | |
| 
 | |
| void track_object(Sdi_rcontext *rctx, Column *column_object);
 | |
| 
 | |
| /**
 | |
|   Register Index objects being deserialized so that it will be
 | |
|   possible to resolve references to it after deserialization has
 | |
|   finished.
 | |
| 
 | |
|   @param rctx opaque context
 | |
|   @param index_object object which may be referenced by other objects.
 | |
| */
 | |
| 
 | |
| void track_object(Sdi_rcontext *rctx, Index *index_object);
 | |
| 
 | |
| /**
 | |
|   Return an non-owning raw pointer to the deserialized Index object
 | |
|   with ordinal postion index opx (ordinal position opx+1). The unused
 | |
|   const Index* argument is needed for overload resolution.
 | |
| 
 | |
|   @param rctx opaque context
 | |
|   @param opx ordinal position index
 | |
| */
 | |
| 
 | |
| Index *get_by_opx(Sdi_rcontext *rctx, const Index *, uint opx);
 | |
| 
 | |
| /**
 | |
|   Return an non-owning raw pointer to the deserialized Column object
 | |
|   with ordinal postion index opx (ordinal position opx+1). The unused
 | |
|   const Column* argument is needed for overload resolution.
 | |
| 
 | |
|   @param rctx opaque context
 | |
|   @param opx ordinal position index
 | |
| */
 | |
| 
 | |
| Column *get_by_opx(Sdi_rcontext *rctx, const Column *, uint opx);
 | |
| 
 | |
| /**
 | |
|   Return a non-owning pointer to a char buffer which can be used
 | |
|   for e.g. base64 encoding.
 | |
|   @param rctx opaque context
 | |
|   @param sz size of buffer
 | |
|   @return non-owning pointer to buffer
 | |
| */
 | |
| 
 | |
| char *buf_handle(Sdi_rcontext *rctx, size_t sz);
 | |
| 
 | |
| /**
 | |
|   Return the the Object_id of a schema name in the current data
 | |
|   dictionary. Used to recreate a reference to a schema during
 | |
|   deserialization.
 | |
| 
 | |
|   @param rctx opaque context.
 | |
|   @param name schema name used as reference.
 | |
|   @param idp [OUT] pointer to Object_id variable where result is stored.
 | |
|   @return MySQL error handling.
 | |
|   */
 | |
| 
 | |
| bool lookup_schema_ref(Sdi_rcontext *rctx, const String_type &name,
 | |
|                        Object_id *idp);
 | |
| 
 | |
| /**
 | |
|   Return the the Object_id of a tablespace name in the current data
 | |
|   dictionary. Used to recreate a reference to a tablespace during
 | |
|   deserialization.
 | |
| 
 | |
|   @param rctx opaque context.
 | |
|   @param name schema name used as reference.
 | |
|   @param idp [OUT] pointer to Object_id variable where result is stored.
 | |
|   @return MySQL error handling.
 | |
| 
 | |
|   */
 | |
| 
 | |
| bool lookup_tablespace_ref(Sdi_rcontext *rctx, const String_type &name,
 | |
|                            Object_id *idp);
 | |
| 
 | |
| }  // namespace dd
 | |
| 
 | |
| /** @} */  // int_func_decl
 | |
| 
 | |
| /**
 | |
|   @defgroup prealloced_typedefs Prealloced_array Typedefs
 | |
|   @ingroup sdi
 | |
| 
 | |
|   Defines a sub-class of Prealloced_array and some useful typedefs for use in
 | |
|   (de)serialization code.
 | |
|   @{
 | |
| */
 | |
| 
 | |
| typedef dd::String_type binary_t;
 | |
| template <typename T, size_t PREALLOC = 16>
 | |
| struct dd_vector : public Prealloced_array<T, PREALLOC> {
 | |
|   dd_vector(PSI_memory_key psi_key = 0)
 | |
|       : Prealloced_array<T, PREALLOC>(psi_key) {}
 | |
| };
 | |
| 
 | |
| typedef dd_vector<char, 32> Byte_buffer;
 | |
| 
 | |
| /** @} */  // prealloced_typedefs
 | |
| 
 | |
| /**
 | |
|   @defgroup value_overloads Value Function Overloads
 | |
|   @ingroup sdi
 | |
| 
 | |
|   Defines function templates for writing a "bare" (without the key) json value.
 | |
|   Each definition is overloaded on the second argument (which isn't a template
 | |
|   argument) to handle each builtin type that has a corrsponding rapidjson type.
 | |
|   @{
 | |
| */
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, bool a) {
 | |
|   w->Bool(a);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(bool *ap, const GV &gv) {
 | |
|   if (!gv.IsBool()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = gv.GetBool();
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, int a) {
 | |
|   w->Int(a);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(int *ap, const GV &gv) {
 | |
|   if (!gv.IsInt()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = gv.GetInt();
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, uint a) {
 | |
|   w->Uint(a);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(uint *ap, const GV &gv) {
 | |
|   if (!gv.IsUint()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = gv.GetUint();
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, ulong a) {
 | |
|   w->Uint64(a);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(ulong *ap, const GV &gv) {
 | |
|   if (!gv.IsUint64()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = gv.GetUint64();
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, ulonglong a) {
 | |
|   w->Uint64(a);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(ulonglong *ap, const GV &gv) {
 | |
|   if (!gv.IsUint64()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = gv.GetUint64();
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, const dd::String_type &a) {
 | |
|   w->String(a.c_str(), a.size());
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_value(dd::String_type *ap, const GV &gv) {
 | |
|   if (!gv.IsString()) {
 | |
|     return true;
 | |
|   }
 | |
|   *ap = dd::String_type(gv.GetString(), gv.GetStringLength());
 | |
|   return false;
 | |
| }
 | |
| /** @} */  // value_overloads
 | |
| 
 | |
| template <typename W>
 | |
| void write_value(W *w, dd::String_type *a);
 | |
| 
 | |
| /**
 | |
|   @defgroup key_templates Key-related Function Templates
 | |
|   @ingroup sdi
 | |
| 
 | |
|   Defines wrapper function templates which handles the key part when
 | |
|   writing and writing json.
 | |
| 
 | |
|   @{
 | |
| */
 | |
| 
 | |
| template <typename W, typename T>
 | |
| void write(W *w, const T &t, const char *key, size_t key_sz) {
 | |
|   w->String(key, key_sz);
 | |
|   write_value(w, t);
 | |
| }
 | |
| 
 | |
| template <typename T, typename GV>
 | |
| bool read(T *ap, const GV &gv, const char *key) {
 | |
|   if (!gv.HasMember(key)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return read_value(ap, gv[key]);
 | |
| }
 | |
| 
 | |
| /** @} */  // key_templates
 | |
| 
 | |
| /**
 | |
|   @defgroup special_composite_templates Function Templates for Composite Types
 | |
|   @ingroup sdi
 | |
| 
 | |
|   Defines function templates to handle types that do not map directly
 | |
|   to a rapidjson type, and require some amount of converson/adaptation.
 | |
| 
 | |
|   @{
 | |
| */
 | |
| 
 | |
| template <typename W, typename ENUM_T>
 | |
| void write_enum(W *w, ENUM_T enum_val, const char *key, size_t keysz) {
 | |
|   write(w, static_cast<ulonglong>(enum_val), key, keysz);
 | |
| }
 | |
| 
 | |
| template <typename ENUM_T, typename GV>
 | |
| bool read_enum(ENUM_T *ep, const GV &gv, const char *key) {
 | |
|   ulonglong v = 0;
 | |
|   if (read(&v, gv, key)) {
 | |
|     return true;
 | |
|   }
 | |
|   *ep = static_cast<ENUM_T>(v);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void write_binary(dd::Sdi_wcontext *wctx, W *w, const binary_t &b,
 | |
|                   const char *key, size_t keysz) {
 | |
|   int binsz = static_cast<int>(b.size());
 | |
|   int b64sz = base64_needed_encoded_length(binsz);
 | |
| 
 | |
|   char *bp = dd::buf_handle(wctx, static_cast<size_t>(b64sz));
 | |
|   DBUG_ASSERT(bp);
 | |
| 
 | |
|   base64_encode(b.c_str(), binsz, bp);
 | |
|   w->String(key, keysz);
 | |
|   w->String(bp);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool read_binary(dd::Sdi_rcontext *rctx, binary_t *b, const GV &gv,
 | |
|                  const char *key) {
 | |
|   if (!gv.HasMember(key)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   const GV &a_gv = gv[key];
 | |
| 
 | |
|   if (!a_gv.IsString()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   const char *b64 = a_gv.GetString();
 | |
|   size_t b64sz = a_gv.GetStringLength();
 | |
|   int binsz = base64_needed_decoded_length(b64sz);
 | |
| 
 | |
|   char *bp = dd::buf_handle(rctx, static_cast<size_t>(binsz));
 | |
|   binsz = base64_decode(b64, b64sz, bp, NULL, 0);
 | |
|   *b = binary_t(bp, binsz);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W, typename PP>
 | |
| void write_properties(W *w, const PP &p, const char *key, size_t keysz) {
 | |
|   write(w, p.raw_string(), key, keysz);
 | |
| }
 | |
| 
 | |
| template <typename PP, typename GV>
 | |
| bool read_properties(PP *p, const GV &gv, const char *key) {
 | |
|   dd::String_type raw_string;
 | |
|   if (read(&raw_string, gv, key)) {
 | |
|     return true;
 | |
|   }
 | |
|   p->insert_values(raw_string);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename W, typename PP>
 | |
| void write_opx_reference(W *w, const PP &p, const char *key, size_t keysz) {
 | |
|   uint opx = 0;
 | |
|   if (p) {
 | |
|     DBUG_ASSERT(p->ordinal_position() > 0);
 | |
|     opx = p->ordinal_position() - 1;
 | |
|     write(w, opx, key, keysz);
 | |
|   }
 | |
| }
 | |
| 
 | |
| template <typename PP, typename GV>
 | |
| bool read_opx_reference(dd::Sdi_rcontext *rctx, PP *p, const GV &gv,
 | |
|                         const char *key) {
 | |
|   uint opx = 0;
 | |
|   if (read(&opx, gv, key)) {
 | |
|     return true;
 | |
|   }
 | |
|   *p = get_by_opx(rctx, *p, opx);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool deserialize_schema_ref(dd::Sdi_rcontext *rctx, dd::Object_id *p,
 | |
|                             const GV &gv, const char *key) {
 | |
|   dd::String_type schema_name;
 | |
|   return (read(&schema_name, gv, key) ||
 | |
|           lookup_schema_ref(rctx, schema_name, p));
 | |
| }
 | |
| 
 | |
| template <typename W>
 | |
| void serialize_tablespace_ref(dd::Sdi_wcontext *wctx, W *w,
 | |
|                               dd::Object_id tablespace_id, const char *key,
 | |
|                               size_t keysz) {
 | |
|   if (tablespace_id == dd::INVALID_OBJECT_ID) {
 | |
|     // There is no name to look up (will be the case for SEs not using
 | |
|     // tablespaces
 | |
|     return;
 | |
|   }
 | |
|   const dd::String_type &tablespace_name =
 | |
|       lookup_tablespace_name(wctx, tablespace_id);
 | |
| 
 | |
|   if (tablespace_name.empty()) {
 | |
|     return;
 | |
|   }
 | |
|   write(w, tablespace_name, key, keysz);
 | |
| }
 | |
| 
 | |
| template <typename GV>
 | |
| bool deserialize_tablespace_ref(dd::Sdi_rcontext *rctx, dd::Object_id *p,
 | |
|                                 const GV &gv, const char *key) {
 | |
|   dd::String_type tablespace_name;
 | |
|   if (read(&tablespace_name, gv, key)) {
 | |
|     return false;  // Ok not to have this
 | |
|   }
 | |
|   return lookup_tablespace_ref(rctx, tablespace_name, p);
 | |
| }
 | |
| 
 | |
| template <typename W, typename C>
 | |
| void serialize_each(dd::Sdi_wcontext *wctx, W *w, const dd::Collection<C *> &cp,
 | |
|                     const char *key, size_t keysz) {
 | |
|   w->String(key, keysz);
 | |
|   w->StartArray();
 | |
|   for (const C *vp : cp) {
 | |
|     vp->serialize(wctx, w);
 | |
|   }
 | |
|   w->EndArray(cp.size());
 | |
| }
 | |
| 
 | |
| template <typename ADD_BINDER, typename GV>
 | |
| bool deserialize_each(dd::Sdi_rcontext *rctx, ADD_BINDER add_binder,
 | |
|                       const GV &obj_gv, const char *key) {
 | |
|   if (!obj_gv.HasMember(key)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   const GV &array_gv = obj_gv[key];
 | |
|   if (!array_gv.IsArray()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   const typename GV::ConstValueIterator end = array_gv.End();
 | |
|   for (typename GV::ConstValueIterator it = array_gv.Begin(); it != end; ++it) {
 | |
|     if (add_binder()->deserialize(rctx, *it)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| /** @} */  // special_composite_templates
 | |
| 
 | |
| //} // namespace dd_sdi_impl
 | |
| 
 | |
| #endif /* DD_SERIALIZE_IMPL_H_INCLUDED */
 |