MySQL Connector/C++
MySQL connector library for C and C++ applications
common.h
1/*
2 * Copyright (c) 2015, 2024, 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, as
6 * published by the Free Software Foundation.
7 *
8 * This program is designed to work with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms, as
10 * 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 either included with
14 * the program or referenced in the documentation.
15 *
16 * Without limiting anything contained in the foregoing, this file,
17 * which is part of Connector/C++, is also subject to the
18 * Universal FOSS Exception, version 1.0, a copy of which can be found at
19 * https://oss.oracle.com/licenses/universal-foss-exception.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 * See the GNU General Public License, version 2.0, for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31#ifndef MYSQLX_COMMON_H
32#define MYSQLX_COMMON_H
33
34
35#include "../common.h"
36
37PUSH_SYS_WARNINGS
38#include <string>
39#include <stdexcept>
40#include <ostream>
41#include <memory>
42#include <forward_list>
43#include <string.h> // for memcpy
44#include <utility> // std::move etc
45POP_SYS_WARNINGS
46
47
48#define CATCH_AND_WRAP \
49 catch (const ::mysqlx::Error&) { throw; } \
50 catch (const std::out_of_range&) { throw; } \
51 catch (const std::exception &e) \
52 { throw ::mysqlx::Error(e.what()); } \
53 catch (const char *e) \
54 { throw ::mysqlx::Error(e); } \
55 catch (...) \
56 { throw ::mysqlx::Error("Unknown exception"); } \
57
58
59namespace mysqlx {
60MYSQLX_ABI_BEGIN(2,0)
61
62using std::out_of_range;
63
64using common::byte;
65class Value;
66
67
79// TODO: Make it header-only class somehow...
80
81DLL_WARNINGS_PUSH
82
83class PUBLIC_API Error : public common::Error
84{
85
86 DLL_WARNINGS_POP
87
88public:
89
90 Error(const char *msg)
91 : common::Error(msg)
92 {}
93};
94
95
96inline
97void throw_error(const char *msg)
98{
99 throw Error(msg);
100}
101
102
113class string : public std::u16string
114{
115
116 struct Impl
117 {
118 PUBLIC_API static std::string to_utf8(const string&);
119 PUBLIC_API static void from_utf8(string&, const std::string&);
120
121 PUBLIC_API static std::u32string to_ucs4(const string&);
122 PUBLIC_API static void from_ucs4(string&, const std::u32string&);
123
124 PUBLIC_API static std::wstring to_wide(const string&);
125 PUBLIC_API static void from_wide(string&, const std::wstring&);
126 };
127
128 template <typename T>
129 struct traits
130 {};
131
132
133public:
134
135 string() {}
136 string(const string&) = default;
137 string(string&&) = default;
138
139 string& operator=(const string&) = default;
140 string& operator=(string&&) = default;
141
142 using std::u16string::basic_string;
143
144 string(const std::u16string &other) : std::u16string(other) {}
145 string(std::u16string &&other) : std::u16string(std::move(other)) {}
146
147 template <typename C>
148 string(const C *other)
149 {
150 try {
151 if (!other)
152 return;
153 std::basic_string<C> str(other);
154 traits<C>::from_str(*this, str);
155 }
156 CATCH_AND_WRAP
157 }
158
159 template <typename C>
160 string(const std::basic_string<C> &other)
161 {
162 try {
163 traits<C>::from_str(*this, other);
164 }
165 CATCH_AND_WRAP
166 }
167
168 template <typename C>
169 operator std::basic_string<C>() const
170 {
171 try {
172 return traits<C>::to_str(*this);
173 }
174 CATCH_AND_WRAP
175 }
176
177
178 friend bool operator==(const string&lhs, const string&rhs)
179 {
180 return operator==((const std::u16string&)lhs, (const std::u16string&)rhs);
181 }
182
183 friend bool operator!=(const string&lhs, const string&rhs)
184 {
185 return !(lhs == rhs);
186 }
187
188 // Note: These are needed to help overload resolution :/
189
190 friend bool operator==(const string &lhs, const char16_t *rhs)
191 {
192 return lhs == string(rhs);
193 }
194
195 friend bool operator==(const char16_t *lhs, const string &rhs)
196 {
197 return string(lhs) == rhs;
198 }
199
200 friend bool operator!=(const string &lhs, const char16_t *rhs)
201 {
202 return !(lhs == rhs);
203 }
204
205 friend bool operator!=(const char16_t *lhs, const string &rhs)
206 {
207 return !(lhs == rhs);
208 }
209
210};
211
212
213template<>
214struct string::traits<char>
215{
216 using string = std::string;
217
218 static void from_str(mysqlx::string &to, const string &from)
219 {
220 Impl::from_utf8(to, from);
221 }
222
223 static string to_str(const mysqlx::string &from)
224 {
225 return Impl::to_utf8(from);
226 }
227};
228
229template<>
230struct string::traits<wchar_t>
231{
232 using string = std::wstring;
233
234 static void from_str(mysqlx::string &to, const string &from)
235 {
236 Impl::from_wide(to, from);
237 }
238
239 static string to_str(const mysqlx::string &from)
240 {
241 return Impl::to_wide(from);
242 }
243};
244
245template<>
246struct string::traits<char32_t>
247{
248 using string = std::u32string;
249
250 static void from_str(mysqlx::string &to, const string &from)
251 {
252 Impl::from_ucs4(to, from);
253 }
254
255 static string to_str(const mysqlx::string &from)
256 {
257 return Impl::to_ucs4(from);
258 }
259};
260
261
262inline
263std::ostream& operator<<(std::ostream &out, const string &str)
264{
265 const std::string utf8(str);
266 out << utf8;
267 return out;
268}
269
270
271typedef unsigned long col_count_t;
272typedef unsigned long row_count_t;
273
274
297class bytes : public std::pair<const byte*, size_t>
298{
299
300public:
301
302 bytes(const byte *beg_, const byte *end_)
303 : pair(beg_, end_ - beg_)
304 {}
305
306 bytes(const byte *beg, size_t len) : pair(beg, len)
307 {}
308
309 bytes(const char *str) : pair((const byte*)str, 0)
310 {
311 if (nullptr != str)
312 second = strlen(str);
313 }
314
315 bytes(std::pair<const byte*, size_t> buf) : pair(buf)
316 {}
317
318 bytes() : pair(nullptr, 0)
319 {}
320
321 bytes(const bytes &) = default;
322
323 virtual const byte* begin() const { return first; }
324 virtual const byte* end() const { return first + second; }
325
326 size_t length() const { return second; }
327 size_t size() const { return length(); }
328
329 class Access;
330 friend Access;
331};
332
333
334/*
335 Infrastructure for type-agnostic handling of lists
336 ==================================================
337
338 Template internal::List_initializer<> defined below is used to return lists
339 of values from public API method so that user can store this list in
340 a container of his choice. The only requirement is that the container instance
341 should be constructible from two iterators defining a range of elements
342 (such constructors exists for standard STL containers, for example).
343
344 Thus, given a public API method foo() which returns a List_initializer<> for
345 lists of elements of type X, user can do the following:
346
347 My_container cont = foo();
348
349 The container will be constructed as if this code was executed:
350
351 My_container cont = My_container(begin, end);
352
353 where begin and end are STL iterators defining a range of elements of type X.
354 This is implemented by defining templated conversion operator.
355
356 Apart from initializing containers, values of List_initializer<> type can
357 be iterated using a range loop:
358
359 for(X &el : foo()) { ... }
360
361 Otherwise, user should not be able to use List_initializer<> values directly.
362*/
363
364namespace internal {
365
366/*
367 Iterator template.
368
369 It defines an STL input iterator which is implemented using an
370 implementation object of some type Impl. It is assumed that Impl
371 has the following methods:
372
373 void iterator_start() - puts iterator in "before begin" position;
374 bool iterator_next() - moves iterator to next position, returns
375 false if it was not possible;
376 Value_type iterator_get() - gets current value.
377
378 An implementation object must be passed to iterator constructor. Iterator
379 stores only a pointer to this implementation (so it must exist as long as
380 iterator is used).
381*/
382
383template<
384 typename Impl,
385 typename T = typename std::iterator_traits<Impl>::value_type,
386 typename Distance = typename std::iterator_traits<T*>::difference_type,
387 typename Pointer = typename std::iterator_traits<T*>::pointer,
388 typename Reference = typename std::iterator_traits<T*>::reference
389>
390struct Iterator
391{
392 public:
393 using iterator_category = std::input_iterator_tag;
394 using value_type = T;
395 using difference_type = Distance;
396 using pointer = Pointer;
397 using reference = Reference;
398
399 protected:
400 typename std::remove_reference<Impl>::type *m_impl = NULL;
401 bool m_at_end = false;
402
403 public:
404 Iterator(Impl &impl) : m_impl(&impl) {
405 m_impl->iterator_start();
406 m_at_end = !m_impl->iterator_next();
407 }
408
409 Iterator()
410 : m_at_end(true)
411 {}
412
413 bool operator==(const Iterator &other) const
414 {
415 return (m_at_end && other.m_at_end);
416 }
417
418 bool operator !=(const Iterator &other) const
419 {
420 /*
421 Compares only if both iterators are at the end
422 of the sequence.
423 */
424 return !(m_at_end && other.m_at_end);
425 }
426
427 Iterator& operator++()
428 {
429 try {
430 if (m_impl && !m_at_end)
431 m_at_end = !m_impl->iterator_next();
432 return *this;
433 }
434 CATCH_AND_WRAP
435 }
436
437 T operator*() const
438 {
439 if (!m_impl || m_at_end)
440 THROW("Attempt to dereference null iterator");
441
442 try {
443 return m_impl->iterator_get();
444 }
445 CATCH_AND_WRAP
446 }
447
448 friend Impl;
449};
450
451
452/*
453 List_initializer object can be used to initialize a container of
454 arbitrary type U with list of items taken from a source object.
455
456 It is assumed that the source object type Source defines iterator
457 type and that std::begin/end() return iterators to the beginning
458 and end of the sequence. The container type U is assumed to have
459 a constructor from begin/end iterator.
460
461 List_iterator defines begin/end() methods, so it is possible to
462 iterate over the sequence without storing it in any container.
463*/
464
465template <class Source>
466class List_initializer
467{
468protected:
469
470 Source m_src;
471
472 friend Source;
473
474public:
475
476
477 /*
478 Arguments given to the constructor are passed to the internal
479 m_src object.
480 */
481
482 template <typename... Ty>
483 List_initializer(Ty&&... args)
484 : m_src(std::forward<Ty>(args)...)
485 {}
486
487 /*
488 Narrow the set of types for which this template is instantiated
489 to avoid ambiguous conversion errors. It is important to disallow
490 conversion to std::initializer_list<> because this conversion path
491 is considered when assigning to STL containers.
492 */
493
494 template <
495 typename U
496 , typename std::enable_if<
497 !std::is_same< U, std::initializer_list<typename U::value_type> >::value
498 >::type* = nullptr
499 >
500 operator U()
501 {
502 try {
503 return U(std::begin(m_src), std::end(m_src));
504 }
505 CATCH_AND_WRAP
506 }
507
508 auto begin() -> decltype(std::begin(m_src))
509 {
510 try {
511 return std::begin(m_src);
512 }
513 CATCH_AND_WRAP
514 }
515
516 auto end() const -> decltype(std::end(m_src))
517 {
518 try {
519 return std::end(m_src);
520 }
521 CATCH_AND_WRAP
522 }
523};
524
525
526template <typename T>
527struct iterator_traits
528{
529 using value_type = typename std::remove_reference<T>::type;
530 using difference_type
531 = typename std::iterator_traits<value_type*>::difference_type;
532 using pointer
533 = typename std::iterator_traits<value_type*>::pointer;
534 using reference
535 = typename std::iterator_traits<value_type*>::reference;
536};
537
538
539/*
540 This helper template adapts class Impl to be used as a source for
541 List_initializer<> template.
542
543 Class Impl should be suitable for the Iterator<> template which is used to
544 build iterators required by List_initializer<>. That is, Impl should
545 implement iterator_start(), iteratore_next() etc (see Iterator<>).
546*/
547
548template<
549 typename Impl,
550 typename Value_type = typename Impl::Value,
551 typename Distance = typename iterator_traits<Value_type>::difference_type,
552 typename Pointer = typename iterator_traits<Value_type>::pointer,
553 typename Reference = typename iterator_traits<Value_type>::reference
554>
555class List_source
556{
557protected:
558
559 Impl m_impl;
560
561public:
562
563 template <typename... Ty>
564 List_source(Ty&&... args)
565 : m_impl(std::forward<Ty>(args)...)
566 {}
567
568 using iterator = Iterator<Impl, Value_type, Distance, Pointer, Reference>;
569
570 iterator begin()
571 {
572 return iterator(m_impl);
573 }
574
575 iterator end() const
576 {
577 return iterator();
578 }
579};
580
581
582/*
583 A template used to adapt an object of class Impl that represents an array of
584 values accessed via operator[] to be used as source for List_initializer<>
585 template. This template uses instance of Impl to implement the iterator
586 methods iterator_start(), so that it can be used with Iterator<> template.
587*/
588
589template <typename Impl, typename Value_type = typename Impl::Value>
590class Array_src_impl
591{
592protected:
593
594 Impl m_impl;
595 size_t m_pos = 0;
596 bool m_at_begin = true;
597
598public:
599
600 template <typename... Ty>
601 Array_src_impl(Ty&&... args)
602 : m_impl(std::forward<Ty>(args)...)
603 {}
604
605 void iterator_start()
606 {
607 m_pos = 0;
608 m_at_begin = true;
609 }
610
611 bool iterator_next()
612 {
613 if (m_at_begin)
614 m_at_begin = false;
615 else
616 m_pos++;
617 return m_pos < size();
618 }
619
620 Value_type iterator_get()
621 {
622 return operator[](m_pos);
623 }
624
625 Value_type operator[](size_t pos)
626 {
627 return m_impl[pos];
628 }
629
630 size_t size() const
631 {
632 return m_impl.size();
633 }
634};
635
636
637/*
638 This template adapts an object of type Impl holding an array of values as
639 a source for List_initializer<> template. It combines List_source<> and
640 Array_src_impl<> adapters.
641*/
642
643template<
644 typename Impl,
645 typename Value_type = typename Impl::Value,
646 typename Distance = typename iterator_traits<Value_type>::difference_type,
647 typename Pointer = typename iterator_traits<Value_type>::pointer,
648 typename Reference = typename iterator_traits<Value_type>::reference
649>
650class Array_source
651 : public List_source<
652 Array_src_impl<Impl, Value_type>,
653 Value_type,
654 Distance,
655 Pointer,
656 Reference
657 >
658{
659 using Base = List_source<
660 Array_src_impl<Impl, Value_type>,
661 Value_type,
662 Distance,
663 Pointer,
664 Reference
665 >;
666
667 using Base::m_impl;
668
669public:
670
671 using
672 List_source<
673 Array_src_impl<Impl, Value_type>,
674 Value_type,
675 Distance,
676 Pointer,
677 Reference
678 >::List_source;
679
680 Value_type operator[](size_t pos)
681 {
682 return m_impl[pos];
683 }
684
685 size_t size() const
686 {
687 return m_impl.size();
688 }
689};
690
691} // internal
692
693
694/*
695 Infrastructure for handling variable argument lists
696 ===================================================
697
698 See documentation of Args_processor<> template.
699*/
700
701namespace internal {
702
703/*
704 Type trait which checks if std::begin()/end() work on objects of given
705 class C, so that it can be used as a range to iterate over.
706
707 TODO: Make it work also with user-defined begin()/end() functions.
708 TODO: Make it work with plain C arrays. For example:
709
710 int vals[] = { 1, 2, 3 }
711 process_args(data, vals)
712*/
713
714template <class C>
715class is_range
716{
717 /*
718 Note: This overload is taken into account only if std::begin(X) and
719 std::end(X) expressions are valid.
720 */
721 template <class X>
722 static std::true_type
723 test(
724 decltype(std::begin(*((X*)nullptr)))*,
725 decltype(std::end(*((X*)nullptr)))*
726 );
727
728 template <class X>
729 static std::false_type test(...);
730
731public:
732
733 static const bool value = std::is_same<
734 std::true_type,
735 decltype(test<C>(nullptr, nullptr))
736 >::value;
737};
738
739
740/*
741 Class template to be used for uniform processing of variable argument lists
742 in public API methods. This template handles the cases where arguments
743 are specified directly as a list:
744
745 method(arg1, arg2, ..., argN)
746
747 or they are taken from a container such as std::list:
748
749 method(container)
750
751 or they are taken from a range of items described by two iterators:
752
753 method(begin, end)
754
755 A class B that is using this template to define a varargs method 'foo'
756 should define it as follows:
757
758 template <typename... T>
759 X foo(T... args)
760 {
761 Args_processor<B>::process_args(m_impl, args...);
762 return ...;
763 }
764
765 Process_args() is a static method of Args_processor<> and therefore
766 additional context data is passed to it as the first argument. By default
767 this context is a pointer to internal implementation object, as defined
768 by the base class B. The process_args() methods does all the necessary
769 processing of the variable argument list, passing the resulting items
770 one-by-one to B::process_one() method. Base class B must define this
771 static method, which takes the context and one data item as arguments.
772 B::process_one() method can have overloads that handle different types
773 of data items.
774
775 See devapi/detail/crud.h for usage examples.
776*/
777
778template <class Base, class D = typename Base::Impl*>
779class Args_processor
780{
781public:
782
783 /*
784 Check if item of type T can be passed to Base::process_one()
785 */
786
787 template <typename T>
788 class can_process
789 {
790 template <typename X>
791 static std::true_type
792 test(decltype(Base::process_one(*(D*)nullptr, *(X*)nullptr))*);
793
794 template <typename X>
795 static std::false_type test(...);
796
797 public:
798
799 static const bool value
800 = std::is_same< std::true_type, decltype(test<T>(nullptr)) >::value;
801 };
802
803public:
804
805 /*
806 Process items from a container.
807 */
808
809 template <
810 typename C,
811 typename std::enable_if<is_range<C>::value>::type* = nullptr,
812 typename std::enable_if<!can_process<C>::value>::type* = nullptr
813 >
814 static void process_args(D data, C container)
815 {
816 // TODO: use (const) reference to avoid copying instances?
817 for (auto el : container)
818 {
819 Base::process_one(data, el);
820 }
821 }
822
823 /*
824 If process_args(data, a, b) is called and a,b are of the same type It
825 which can not be passed to Base::process_one() then we assume that a and
826 b are iterators that describe a range of elements to process.
827 */
828
829 template <
830 typename It,
831 typename std::enable_if<!can_process<It>::value>::type* = nullptr
832 >
833 static void process_args(D data, const It &begin, const It &end)
834 {
835 for (It it = begin; it != end; ++it)
836 {
837 Base::process_one(data, *it);
838 }
839 }
840
841 /*
842 Process elements given as a varargs list.
843 */
844
845 template <
846 typename T,
847 typename... R,
848 typename std::enable_if<can_process<T>::value>::type* = nullptr
849 >
850 static void process_args(D data, T first, R&&... rest)
851 {
852 process_args1(data, first, std::forward<R>(rest)...);
853 }
854
855private:
856
857 template <
858 typename T,
859 typename... R,
860 typename std::enable_if<can_process<T>::value>::type* = nullptr
861 >
862 static void process_args1(D data, T first, R&&... rest)
863 {
864 Base::process_one(data, first);
865 process_args1(data, std::forward<R>(rest)...);
866 }
867
868 static void process_args1(D)
869 {}
870
871};
872
873} // internal namespace
874
875MYSQLX_ABI_END(2,0)
876} // mysqlx
877
878
879#endif
Base class for connector errors.
Definition: common.h:84
Class representing a region of memory holding raw bytes.
Definition: common.h:298
A wrapper around std::wstring that can perform conversions from/to different character encodings used...
Definition: common.h:114