1 /*
2   Copyright (c) 2011, 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 02110-1301  USA
23 */
24 
25 #ifndef NDB_TYPES_UTIL_HPP
26 #define NDB_TYPES_UTIL_HPP
27 
28 #include <assert.h>
29 #include <string.h>
30 
31 #include "my_global.h"
32 
33 #include "ndb_constants.h"
34 #include "ndb_types.h"
35 
36 /*
37  * Traits and Helper classes for NDB data types.
38  */
39 
40 // ---------------------------------------------------------------------------
41 // Traits classes providing information on NDB (column) data types
42 // ---------------------------------------------------------------------------
43 
44 /*
45  * These Traits classes support code genericity by parametrizing over
46  * NDB (column) data types.  They provide compile-time information on
47  * - array types:               [long][var](binary|char)
48  * - numeric types:             [U]Int8..[U]Int64|float|double
49  *
50  * For instance, Traits functions
51  * - isFixedSized()             for array types
52  * - lowest(), highest()        for numeric types
53  * allow for the generic handling of arrays or numeric limits.
54  *
55  * Notes: the Traits classes
56  * - provide uniform access to type meta-data
57  * - are used as a type argument to a class or function template
58  * - have pure compile-time scope, lack instantiation at runtime
59  * - have _no_ link or library dependencies upon C++ stdlib code
60  *   (compare to the bounds definitions in std::numeric_limits)
61  * - are defined below as inline template specializations.
62  */
63 
64 /**
65  * Common Traits of NDB array types.
66  */
67 template< int TID > // the NDB type id as defined in ndb_constants.h
68 struct ArrayTypeTraits {
69   // whether this array type is a binary or character type
70   static bool isBinary();
71 
72   // whether this array type is fixed-or variable-sized
73   static bool isFixedSized();
74 
75   // the size of the length prefix in bytes, or zero if a fixed-sized array
76   static Uint32 lengthPrefixSize();
77 };
78 
79 // aliases for array type traits
80 typedef ArrayTypeTraits< NDB_TYPE_CHAR > Tchar;
81 typedef ArrayTypeTraits< NDB_TYPE_BINARY > Tbinary;
82 typedef ArrayTypeTraits< NDB_TYPE_VARCHAR > Tvarchar;
83 typedef ArrayTypeTraits< NDB_TYPE_VARBINARY > Tvarbinary;
84 typedef ArrayTypeTraits< NDB_TYPE_LONGVARCHAR > Tlongvarchar;
85 typedef ArrayTypeTraits< NDB_TYPE_LONGVARBINARY > Tlongvarbinary;
86 
87 // internal helper class
88 template< typename T >
89 struct NumTypeMap {};
90 
91 /**
92  * Common Traits of NDB numeric types.
93  *
94  * Notes: the C++ stdlib offers limits as part of std::numeric_limits;
95  * its bounds definitions result in a non-uniform usage over different
96  * data types, with min() referring to the smallest positive value for
97  * float and double, but lowest negative value for integral types.
98  * In contrast, this Traits class's functions lowest() and smallest()
99  * support a uniform usage.
100  */
101 template< typename T >
102 struct NumTypeTraits {
103   // the domain type T
104   typedef typename NumTypeMap< T >::DomainT DomainT;
105 
106   // if T is integral, the signed type of same width; otherwise T
107   typedef typename NumTypeMap< T >::SignedT SignedT;
108 
109   // if T is integral, the unsigned type of same width; otherwise T
110   typedef typename NumTypeMap< T >::UnsignedT UnsignedT;
111 
112   // whether the domain type is an integer type
isIntegralNumTypeTraits113   static bool isIntegral() { return NumTypeMap< T >::isIntegral(); };
114 
115   // whether the domain type is signed or unsigned
isSignedNumTypeTraits116   static bool isSigned() { return NumTypeMap< T >::isSigned(); };
117 
118   // the width of the type in bytes
119   static Uint32 size();
120 
121   // the minimum finite value
122   static T lowest();
123 
124   // the maximum finite value
125   static T highest();
126 
127   // the minimum positive normalized value, or 0 for integral types
128   static T smallest();
129 };
130 
131 // aliases for standard numeric type traits
132 typedef NumTypeTraits< Int8 > Tint8;
133 typedef NumTypeTraits< Int16 > Tint16;
134 typedef NumTypeTraits< Int32 > Tint32;
135 typedef NumTypeTraits< Int64 > Tint64;
136 typedef NumTypeTraits< Uint8 > Tuint8;
137 typedef NumTypeTraits< Uint16 > Tuint16;
138 typedef NumTypeTraits< Uint32 > Tuint32;
139 typedef NumTypeTraits< Uint64 > Tuint64;
140 // not implemented yet: float, double
141 // ansi C type 'long double' is not a supported numeric NDB type
142 
143 /**
144  * Common Traits of non-standard NDB numeric types.
145  *
146  * Unless distinct [U]Int24 value types are defined to represent these
147  * proper subsets of [U]Int32 numbers, the correspoding Traits classes
148  * need to be defined as separate types (not just mere specializations).
149  * Using a derived class does that and allows to partially override.
150  */
151 template< typename T >
152 struct NonStdNumTypeTraits : NumTypeTraits< T > {
153   // the minimum finite value
154   static T lowest();
155 
156   // the maximum finite value
157   static T highest();
158 };
159 
160 // aliases for standard numeric type traits
161 typedef NonStdNumTypeTraits< Int32 > Tint24;
162 typedef NonStdNumTypeTraits< Uint32 > Tuint24;
163 
164 // ---------------------------------------------------------------------------
165 // Helper classes providing common functions on NDB (column) data
166 // ---------------------------------------------------------------------------
167 
168 /*
169  * These Helper classes provide basic utility functions on NDB types.
170  *
171  * For example, Helper functions
172  * - read/writeLengthPrefix()   for array types
173  * - load(), store()            for numeric types
174  * allow to abstract from the details of writing an array's length prefix
175  * or from reading/writing a numeric value from/to an unaligned buffer.
176  *
177  * Notes: the Helper classes
178  * - extend Traits classes for convenience
179  * - only add basic utility functions that
180  * - have _no_ link or library dependencies upon MySQL code
181  *   (in contrast to other SQL utility code like ./NdbSqlUtil)
182  * - are defined below as inline template specializations.
183  */
184 
185 /**
186  * Basic Helper functions for NDB array types.
187  */
188 template< int ID >
189 struct ArrayTypeHelper : ArrayTypeTraits< ID > {
190   // read the length prefix (not available if a fixed-sized array)
191   static Uint32 readLengthPrefix(const void * a);
192 
193   // write the length prefix (not available if a fixed-sized array)
194   // the non-length-prefix bytes of 'l' must be zero
195   static void writeLengthPrefix(void * a, Uint32 l);
196 };
197 
198 // aliases for array type helpers
199 typedef ArrayTypeHelper< NDB_TYPE_CHAR > Hchar;
200 typedef ArrayTypeHelper< NDB_TYPE_BINARY > Hbinary;
201 typedef ArrayTypeHelper< NDB_TYPE_VARCHAR > Hvarchar;
202 typedef ArrayTypeHelper< NDB_TYPE_VARBINARY > Hvarbinary;
203 typedef ArrayTypeHelper< NDB_TYPE_LONGVARCHAR > Hlongvarchar;
204 typedef ArrayTypeHelper< NDB_TYPE_LONGVARBINARY > Hlongvarbinary;
205 
206 /**
207  * Basic Helper functions for numeric NDB types.
208  *
209  * As another design option, these helper functions could be defined as
210  * individual function templates, which'd allow for implicit function
211  * resolution based on the parameter type but, on the other hand, required
212  * distinct value types for all data (i.e., an Int24 value type).
213  */
214 template< typename T >
215 struct NumTypeHelper : NumTypeTraits< T > {
216   // convenience aliases
217   typedef typename NumTypeTraits< T >::SignedT SignedT;
218   typedef typename NumTypeTraits< T >::UnsignedT UnsignedT;
219 
220   // casts a value to the signed numerical type of same width
asSignedNumTypeHelper221   static SignedT asSigned(T t) { return static_cast< SignedT >(t); }
222 
223   // casts a value to the unsigned numerical type of same width
asUnsignedNumTypeHelper224   static UnsignedT asUnsigned(T t) { return static_cast< UnsignedT >(t); }
225 
226   // read a single value from an unaligned buffer; s, t must not overlap
227   static void load(T * t, const char * s);
228 
229   // write a single value to an unaligned buffer; s, t must not overlap
230   static void store(char * t, const T * s);
231 };
232 
233 // aliases for numeric type helpers
234 typedef NumTypeHelper< Int8 > Hint8;
235 typedef NumTypeHelper< Int16 > Hint16;
236 typedef NumTypeHelper< Int32 > Hint32;
237 typedef NumTypeHelper< Int64 > Hint64;
238 typedef NumTypeHelper< Uint8 > Huint8;
239 typedef NumTypeHelper< Uint16 > Huint16;
240 typedef NumTypeHelper< Uint32 > Huint32;
241 typedef NumTypeHelper< Uint64 > Huint64;
242 // not implemented yet: float, double
243 // ansi C type 'long double' is not a supported numeric NDB type
244 
245 /**
246  * Basic Helper functions of non-standard NDB numeric types.
247  *
248  * Unless distinct [U]Int24 value types are defined to represent these
249  * proper subsets of [U]Int32 numbers, the correspoding Helper classes
250  * need to be defined as separate types (not just mere specializations).
251  * This class only derives from the Traits class to avoid member access
252  * ambiguities resulting from multiple inheritance.
253  */
254 template< typename T >
255 struct NonStdNumTypeHelper : NonStdNumTypeTraits< T > {
256   // convenience alias
257   typedef typename NonStdNumTypeTraits< T >::SignedT SignedT;
258   typedef typename NonStdNumTypeTraits< T >::UnsignedT UnsignedT;
259 
260   // casts a value to the signed numerical type of same width
asSignedNonStdNumTypeHelper261   static SignedT asSigned(T t) { return static_cast< SignedT >(t); }
262 
263   // casts a value to the unsigned numerical type of same width
asUnsignedNonStdNumTypeHelper264   static UnsignedT asUnsigned(T t) { return static_cast< UnsignedT >(t); }
265 
266   // read a single value from an unaligned buffer; s, t must not overlap
267   static void load(T * t, const char * s);
268 
269   // write a single value to an unaligned buffer; s, t must not overlap
270   static void store(char * t, const T * s);
271 };
272 
273 // aliases for non-standard numeric type helpers
274 typedef NonStdNumTypeHelper< Int32 > Hint24;
275 typedef NonStdNumTypeHelper< Uint32 > Huint24;
276 
277 // ---------------------------------------------------------------------------
278 // Definitions/Specializations of Traits classes
279 // ---------------------------------------------------------------------------
280 
281 // specialize the Traits template members for array types
282 #define NDB_SPECIALIZE_ARRAY_TYPE_TRAITS( TR, B, FS, LPS )              \
283   template<> inline bool TR::isBinary() { return B; }                   \
284   template<> inline bool TR::isFixedSized() { return FS; }              \
285   template<> inline Uint32 TR::lengthPrefixSize() { return LPS; }
286 
287 // coincidentally, we could use ndb constants
288 //   NDB_ARRAYTYPE_FIXED, NDB_ARRAYTYPE_SHORT_VAR, NDB_ARRAYTYPE_MEDIUM_VAR
289 // instead of literals, but let's not confuse ordinal/cardinal numbers
290 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tchar, false, true, 0)
291 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tbinary, true, true, 0)
292 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tvarchar, false, false, 1)
293 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tvarbinary, true, false, 1)
294 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tlongvarchar, false, false, 2)
295 NDB_SPECIALIZE_ARRAY_TYPE_TRAITS(Tlongvarbinary, true, false, 2)
296 #undef NDB_SPECIALIZE_ARRAY_TYPE_TRAITS
297 
298 // specialize the TypeMap template for numeric types
299 #define NDB_SPECIALIZE_NUM_TYPE_MAP( DT, ST, UT, I, S )                 \
300   template<> struct NumTypeMap< DT > {                                  \
301     typedef DT DomainT;                                                 \
302     typedef ST SignedT;                                                 \
303     typedef UT UnsignedT;                                               \
304     static bool isIntegral() { return S; };                             \
305     static bool isSigned() { return S; };                               \
306   };
307 
308 NDB_SPECIALIZE_NUM_TYPE_MAP(Int8, Int8, Uint8, true, true)
309 NDB_SPECIALIZE_NUM_TYPE_MAP(Uint8, Int8, Uint8, true, false)
310 NDB_SPECIALIZE_NUM_TYPE_MAP(Int16, Int16, Uint16, true, true)
311 NDB_SPECIALIZE_NUM_TYPE_MAP(Uint16, Int16, Uint16, true, false)
312 NDB_SPECIALIZE_NUM_TYPE_MAP(Int32, Int32, Uint32, true, true)
313 NDB_SPECIALIZE_NUM_TYPE_MAP(Uint32, Int32, Uint32, true, false)
314 NDB_SPECIALIZE_NUM_TYPE_MAP(Int64, Int64, Uint64, true, true)
315 NDB_SPECIALIZE_NUM_TYPE_MAP(Uint64, Int64, Uint64, true, false)
316 
317 NDB_SPECIALIZE_NUM_TYPE_MAP(float, float, float, false, true)
318 NDB_SPECIALIZE_NUM_TYPE_MAP(double, double, double, false, true)
319 #undef NDB_SPECIALIZE_NUM_TYPE_MAP
320 
321 // specialize the Traits template members for numeric types
322 #define NDB_SPECIALIZE_NUM_TYPE_TRAITS( TR, T, SZ, LO, HI, SM )         \
323   template<> inline Uint32 TR::size() { return SZ; }                    \
324   template<> inline T TR::lowest() { return LO; }                       \
325   template<> inline T TR::highest() { return HI; }                      \
326   template<> inline T TR::smallest() { return SM; }
327 
328 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tint8, Int8, 1, INT_MIN8, INT_MAX8, 0)
329 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tint16, Int16, 2, INT_MIN16, INT_MAX16, 0)
330 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tint32, Int32, 4, INT_MIN32, INT_MAX32, 0)
331 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tint64, Int64, 8, INT_MIN64, INT_MAX64, 0)
332 
333 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tuint8, Uint8, 1, 0, UINT_MAX8, 0)
334 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tuint16, Uint16, 2, 0, UINT_MAX16, 0)
335 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tuint32, Uint32, 4, 0, UINT_MAX32, 0)
336 NDB_SPECIALIZE_NUM_TYPE_TRAITS(Tuint64, Uint64, 8, 0, UINT_MAX64, 0)
337 // not implemented yet: float, double
338 #undef NDB_SPECIALIZE_NUM_TYPE_TRAITS
339 
340 // specialize the Traits template members for non-standard numeric types
341 #define NDB_SPECIALIZE_NON_STD_NUM_TYPE_TRAITS( TR, T, LO, HI )         \
342   template<> inline T TR::lowest() { return LO; }                       \
343   template<> inline T TR::highest() { return HI; }
344 
345 NDB_SPECIALIZE_NON_STD_NUM_TYPE_TRAITS(Tint24, Int32, INT_MIN24, INT_MAX24)
346 NDB_SPECIALIZE_NON_STD_NUM_TYPE_TRAITS(Tuint24, Uint32, 0, UINT_MAX24)
347 #undef NDB_SPECIALIZE_NON_STD_NUM_TYPE_TRAITS
348 
349 // ---------------------------------------------------------------------------
350 // Definitions/Specializations of Helper classes
351 // ---------------------------------------------------------------------------
352 
353 // specialize the Helper template members for fixed-sized arrays
354 #define NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS0( H )                      \
355   template<> inline Uint32 H::readLengthPrefix(const void * a) {        \
356     assert(false);                                                      \
357     (void)a;                                                            \
358     return 0;                                                           \
359   };                                                                    \
360   template<> inline void H::writeLengthPrefix(void * a, Uint32 l) {     \
361     assert(false);                                                      \
362     (void)a; (void)l;                                                   \
363   }
364 
365 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS0(Hchar)
366 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS0(Hbinary)
367 #undef NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS0
368 
369 // specialize the Helper template members for short-var arrays
370 #define NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS1( H )                      \
371   template<> inline Uint32 H::readLengthPrefix(const void * a) {        \
372     assert(a);                                                          \
373     const Uint8 * s = static_cast<const Uint8 *>(a);                    \
374     return s[0];                                                        \
375   };                                                                    \
376   template<> inline void H::writeLengthPrefix(void * a, Uint32 l) {     \
377     assert(a);                                                          \
378     assert(l >> (lengthPrefixSize() * 8) == 0);                         \
379     Uint8 * t = static_cast<Uint8 *>(a);                                \
380     t[0] = l & 0x000000FF;                                              \
381   }
382 
383 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS1(Hvarchar)
384 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS1(Hvarbinary)
385 #undef NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS1
386 
387 // specialize the Helper template members for medium-var arrays
388 #define NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS2( H )                      \
389   template<> inline Uint32 H::readLengthPrefix(const void * a) {        \
390     assert(a);                                                          \
391     const Uint8 * s = static_cast<const Uint8 *>(a);                    \
392     return static_cast<Uint32>(s[0] + (s[1] << 8));                     \
393   };                                                                    \
394   template<> inline void H::writeLengthPrefix(void * a, Uint32 l) {     \
395     assert(a);                                                          \
396     assert(l >> (lengthPrefixSize() * 8) == 0);                         \
397     Uint8 * t = static_cast<Uint8 *>(a);                                \
398     t[0] = static_cast<Uint8>(l & 0x000000FF);                          \
399     t[1] = static_cast<Uint8>((l & 0x0000FF00) >> 8);                   \
400   }
401 
402 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS2(Hlongvarchar)
403 NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS2(Hlongvarbinary)
404 #undef NDB_SPECIALIZE_ARRAY_TYPE_HELPER_LPS2
405 
406 // specialize the Helper template members for single-byte types
407 #define NDB_SPECIALIZE_NUM_TYPE_HELPER_BYTE( H, T )                     \
408   template<> inline void H::load(T * t, const char * s) {               \
409     assert(t); assert(s); assert(t != (const T *)s);                    \
410     *t = static_cast<T>(*s);                                            \
411   }                                                                     \
412   template<> inline void H::store(char * t, const T * s) {              \
413     H::load(reinterpret_cast<T *>(t),                                   \
414             reinterpret_cast<const char *>(s));                         \
415   }
416 
417 NDB_SPECIALIZE_NUM_TYPE_HELPER_BYTE(Hint8, Int8);
418 NDB_SPECIALIZE_NUM_TYPE_HELPER_BYTE(Huint8, Uint8);
419 #undef NDB_SPECIALIZE_NUM_TYPE_HELPER_BYTE
420 
421 // specialize the Helper template members for numeric types
422 #define NDB_SPECIALIZE_NUM_TYPE_HELPER( H, T )                          \
423   template<> inline void H::load(T * t, const char * s) {               \
424     assert(t); assert(s); assert(t != (const T *)s);                    \
425     memcpy(t, s, H::size());                                            \
426   }                                                                     \
427   template<> inline void H::store(char * t, const T * s) {              \
428     H::load(reinterpret_cast<T *>(t),                                   \
429             reinterpret_cast<const char *>(s));                         \
430   }
431 
432 NDB_SPECIALIZE_NUM_TYPE_HELPER(Hint16, Int16);
433 NDB_SPECIALIZE_NUM_TYPE_HELPER(Hint32, Int32);
434 NDB_SPECIALIZE_NUM_TYPE_HELPER(Hint64, Int64);
435 
436 NDB_SPECIALIZE_NUM_TYPE_HELPER(Huint16, Uint16);
437 NDB_SPECIALIZE_NUM_TYPE_HELPER(Huint32, Uint32);
438 NDB_SPECIALIZE_NUM_TYPE_HELPER(Huint64, Uint64);
439 // not implemented yet: float, double
440 #undef NDB_SPECIALIZE_NUM_TYPE_HELPER
441 
442 // specialize the Helper template members for non-standard numeric types
443 #define NDB_SPECIALIZE_NON_STD_NUM_TYPE_HELPER( H, T, INT3KORR )        \
444   template<> inline void H::load(T * t, const char * s) {               \
445     assert(t); assert(s); assert(t != (const T *)s);                    \
446     *t = (INT3KORR(s));                                                 \
447   }                                                                     \
448   template<> inline void H::store(char * t, const T * s) {              \
449     assert(t); assert(s); assert((const T *)t != s);                    \
450     int3store(t, (*s));                                                 \
451   }
452 
453 NDB_SPECIALIZE_NON_STD_NUM_TYPE_HELPER(Hint24, Int32, sint3korr)
454 NDB_SPECIALIZE_NON_STD_NUM_TYPE_HELPER(Huint24, Uint32, uint3korr)
455 #undef NDB_SPECIALIZE_NON_STD_NUM_TYPE_HELPER
456 
457 #endif /* !NDB_TYPES_UTIL_HPP */
458