1 /*
2  * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License, version 2.0,
6  * as published by the Free Software Foundation.
7  *
8  * This program is also distributed with certain software (including
9  * but not limited to OpenSSL) that is licensed under separate terms,
10  * as designated in a particular file or component or in included license
11  * documentation.  The authors of MySQL hereby grant you an additional
12  * permission to link the program and your derivative works with the
13  * separately licensed software that they have included with MySQL.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License, version 2.0, for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301  USA
24  */
25 
26 #ifndef _NGS_GETTER_ANY_H_
27 #define _NGS_GETTER_ANY_H_
28 
29 #include <string>
30 #include <vector>
31 #include <sstream>
32 
33 #include "ngs_common/protocol_protobuf.h"
34 #include "ngs/ngs_error.h"
35 #include "ngs/error_code.h"
36 
37 
38 namespace ngs
39 {
40 
41 
42 class Getter_any
43 {
44 public:
45   template <typename Value_type>
get_numeric_value(const::Mysqlx::Datatypes::Any & any)46   static Value_type get_numeric_value(const ::Mysqlx::Datatypes::Any &any)
47   {
48     using namespace ::Mysqlx::Datatypes;
49 
50     if (Any::SCALAR != any.type())
51       throw ngs::Error_code(ER_X_INVALID_PROTOCOL_DATA, "Invalid data, expecting scalar");
52 
53     const Scalar &scalar = any.scalar();
54 
55     switch (scalar.type())
56     {
57     case Scalar::V_BOOL:
58       return static_cast<Value_type>(scalar.v_bool());
59 
60     case Scalar::V_DOUBLE:
61       return static_cast<Value_type>(scalar.v_double());
62 
63     case Scalar::V_FLOAT:
64       return static_cast<Value_type>(scalar.v_float());
65 
66     case Scalar::V_SINT:
67       return static_cast<Value_type>(scalar.v_signed_int());
68 
69     case Scalar::V_UINT:
70       return static_cast<Value_type>(scalar.v_unsigned_int());
71 
72     default:
73       throw ngs::Error_code(ER_X_INVALID_PROTOCOL_DATA, "Invalid data, expected numeric type");
74     }
75   }
76 
77 
78   template <typename Value_type>
get_numeric_value_or_default(const::Mysqlx::Datatypes::Any & any,const Value_type & default_value)79   static Value_type get_numeric_value_or_default(const ::Mysqlx::Datatypes::Any &any, const Value_type & default_value)
80   {
81     try
82     {
83       return get_numeric_value<Value_type>(any);
84     }
85     catch (const ngs::Error_code&)
86     {
87     }
88 
89     return default_value;
90   }
91 
92 
93   template <typename Functor>
put_scalar_value_to_functor(const::Mysqlx::Datatypes::Any & any,Functor & functor)94   static void put_scalar_value_to_functor(const ::Mysqlx::Datatypes::Any &any, Functor & functor)
95   {
96     if (!any.has_type())
97       throw ngs::Error_code(ER_X_INVALID_PROTOCOL_DATA, "Invalid data, expecting type");
98 
99     if (::Mysqlx::Datatypes::Any::SCALAR != any.type())
100       throw ngs::Error_code(ER_X_INVALID_PROTOCOL_DATA, "Invalid data, expecting scalar");
101 
102     using ::Mysqlx::Datatypes::Scalar;
103     const Scalar &scalar = any.scalar();
104 
105     switch (scalar.type())
106     {
107     case Scalar::V_SINT:
108       throw_invalid_type_if_false(scalar, scalar.has_v_signed_int());
109       functor(scalar.v_signed_int());
110       break;
111 
112     case Scalar::V_UINT:
113       throw_invalid_type_if_false(scalar, scalar.has_v_unsigned_int());
114       functor(scalar.v_unsigned_int());
115       break;
116 
117     case Scalar::V_NULL:
118       functor();
119       break;
120 
121     case Scalar::V_OCTETS:
122       throw_invalid_type_if_false(scalar, scalar.has_v_octets() && scalar.v_octets().has_value());
123       functor(scalar.v_octets().value());
124       break;
125 
126     case Scalar::V_DOUBLE:
127       throw_invalid_type_if_false(scalar, scalar.has_v_double());
128       functor(scalar.v_double());
129       break;
130 
131     case Scalar::V_FLOAT:
132       throw_invalid_type_if_false(scalar, scalar.has_v_float());
133       functor(scalar.v_float());
134       break;
135 
136     case Scalar::V_BOOL:
137       throw_invalid_type_if_false(scalar, scalar.has_v_bool());
138       functor(scalar.v_bool());
139       break;
140 
141     case Scalar::V_STRING:
142       //XXX
143       // implement char-set handling
144       const bool is_valid = scalar.has_v_string() && scalar.v_string().has_value();
145 
146       throw_invalid_type_if_false(scalar, is_valid);
147       functor(scalar.v_string().value());
148       break;
149     }
150   }
151 
152 private:
throw_invalid_type_if_false(const::Mysqlx::Datatypes::Scalar & scalar,const bool is_valid)153   static void throw_invalid_type_if_false(const ::Mysqlx::Datatypes::Scalar &scalar, const bool is_valid)
154   {
155     if (!is_valid)
156       throw ngs::Error(ER_X_INVALID_PROTOCOL_DATA,
157                        "Missing field required for ScalarType: %d", scalar.type());
158   }
159 };
160 
161 
162 } // namespace ngs
163 
164 
165 #endif // _NGS_GETTER_ANY_H_
166