| | |
| | | #ifndef _QTL_COMMON_H_ |
| | | #define _QTL_COMMON_H_ |
| | | |
| | | #if __cplusplus<201103L && _MSC_VER<1800 |
| | | #if __cplusplus < 201103L && _MSC_VER < 1800 |
| | | #error QTL need C++11 compiler |
| | | #endif //C++11 |
| | | #endif // C++11 |
| | | |
| | | #if _MSC_VER>=1800 && _MSC_VER<1900 |
| | | #if _MSC_VER >= 1800 && _MSC_VER < 1900 |
| | | #define NOEXCEPT throw() |
| | | #else |
| | | #define NOEXCEPT noexcept |
| | | #endif //NOEXCEPT |
| | | #endif // NOEXCEPT |
| | | |
| | | #include <stdint.h> |
| | | #include <string.h> |
| | |
| | | namespace qtl |
| | | { |
| | | |
| | | struct null { }; |
| | | |
| | | struct blob_data |
| | | { |
| | | void* data; |
| | | size_t size; |
| | | |
| | | blob_data() : data(NULL), size(0) { } |
| | | blob_data(void* d, size_t n) : data(d), size(n) { } |
| | | }; |
| | | |
| | | struct const_blob_data |
| | | { |
| | | const void* data; |
| | | size_t size; |
| | | |
| | | const_blob_data() : data(NULL), size(0) { } |
| | | const_blob_data(const void* d, size_t n) : data(d), size(n) { } |
| | | }; |
| | | |
| | | const size_t blob_buffer_size=64*1024; |
| | | |
| | | inline std::string& trim_string(std::string& str, const char* target) |
| | | { |
| | | str.erase(0, str.find_first_not_of(target)); |
| | | str.erase(str.find_last_not_of(target)+1); |
| | | return str; |
| | | } |
| | | |
| | | template<typename T> |
| | | struct indicator |
| | | { |
| | | typedef T data_type; |
| | | |
| | | data_type data; |
| | | size_t length; |
| | | bool is_null; |
| | | bool is_truncated; |
| | | |
| | | indicator() |
| | | : is_null(false), is_truncated(false), length(0) { } |
| | | explicit indicator(const data_type& src) |
| | | : is_null(false), is_truncated(false), length(0), data(src) { } |
| | | explicit indicator(data_type&& src) |
| | | : is_null(false), is_truncated(false), length(0), data(std::move(src)) { } |
| | | |
| | | operator bool() const { return is_null; } |
| | | operator data_type&() { return data; } |
| | | operator const data_type&() const { return data; } |
| | | }; |
| | | |
| | | template<typename StringT> |
| | | struct bind_string_helper |
| | | { |
| | | typedef StringT string_type; |
| | | typedef typename string_type::value_type char_type; |
| | | bind_string_helper(string_type&& value) : m_value(std::forward<string_type>(value)) { } |
| | | bind_string_helper(const bind_string_helper& src) |
| | | : m_value(std::forward<StringT>(src.m_value)) |
| | | struct null |
| | | { |
| | | }; |
| | | |
| | | struct blob_data |
| | | { |
| | | void *data; |
| | | size_t size; |
| | | |
| | | blob_data() : data(NULL), size(0) {} |
| | | blob_data(void *d, size_t n) : data(d), size(n) {} |
| | | }; |
| | | |
| | | struct const_blob_data |
| | | { |
| | | const void *data; |
| | | size_t size; |
| | | |
| | | const_blob_data() : data(NULL), size(0) {} |
| | | const_blob_data(const void *d, size_t n) : data(d), size(n) {} |
| | | }; |
| | | |
| | | const size_t blob_buffer_size = 64 * 1024; |
| | | |
| | | inline std::string &trim_string(std::string &str, const char *target) |
| | | { |
| | | str.erase(0, str.find_first_not_of(target)); |
| | | str.erase(str.find_last_not_of(target) + 1); |
| | | return str; |
| | | } |
| | | bind_string_helper(bind_string_helper&& src) |
| | | : m_value(std::forward<StringT>(src.m_value)) |
| | | |
| | | template <typename T> |
| | | struct indicator |
| | | { |
| | | } |
| | | bind_string_helper& operator=(const bind_string_helper& src) |
| | | typedef T data_type; |
| | | |
| | | data_type data; |
| | | size_t length; |
| | | bool is_null; |
| | | bool is_truncated; |
| | | |
| | | indicator() |
| | | : is_null(false), is_truncated(false), length(0) {} |
| | | explicit indicator(const data_type &src) |
| | | : is_null(false), is_truncated(false), length(0), data(src) {} |
| | | explicit indicator(data_type &&src) |
| | | : is_null(false), is_truncated(false), length(0), data(std::move(src)) {} |
| | | |
| | | operator bool() const { return is_null; } |
| | | operator data_type &() { return data; } |
| | | operator const data_type &() const { return data; } |
| | | }; |
| | | |
| | | template <typename StringT> |
| | | struct bind_string_helper |
| | | { |
| | | if (this != &src) |
| | | typedef StringT string_type; |
| | | typedef typename string_type::value_type char_type; |
| | | bind_string_helper(string_type &&value) : m_value(std::forward<string_type>(value)) {} |
| | | bind_string_helper(const bind_string_helper &src) |
| | | : m_value(std::forward<StringT>(src.m_value)) |
| | | { |
| | | m_value = std::forward<StringT>(src.m_value); |
| | | } |
| | | return *this; |
| | | } |
| | | bind_string_helper& operator=(bind_string_helper&& src) |
| | | { |
| | | if (this != &src) |
| | | bind_string_helper(bind_string_helper &&src) |
| | | : m_value(std::forward<StringT>(src.m_value)) |
| | | { |
| | | m_value = std::forward<StringT>(src.m_value); |
| | | } |
| | | return *this; |
| | | bind_string_helper &operator=(const bind_string_helper &src) |
| | | { |
| | | if (this != &src) |
| | | { |
| | | m_value = std::forward<StringT>(src.m_value); |
| | | } |
| | | return *this; |
| | | } |
| | | bind_string_helper &operator=(bind_string_helper &&src) |
| | | { |
| | | if (this != &src) |
| | | { |
| | | m_value = std::forward<StringT>(src.m_value); |
| | | } |
| | | return *this; |
| | | } |
| | | |
| | | void clear() { m_value.clear(); } |
| | | char_type *alloc(size_t n) |
| | | { |
| | | m_value.resize(n); |
| | | return (char_type *)m_value.data(); |
| | | } |
| | | void truncate(size_t n) { m_value.resize(n); } |
| | | void assign(const char_type *str, size_t n) { m_value.assign(str, n); } |
| | | const char_type *data() const { return m_value.data(); } |
| | | size_t size() const { return m_value.size(); } |
| | | |
| | | private: |
| | | string_type &&m_value; |
| | | }; |
| | | |
| | | template <typename StringT> |
| | | inline bind_string_helper<typename std::decay<StringT>::type> bind_string(StringT &&value) |
| | | { |
| | | typedef typename std::decay<StringT>::type string_type; |
| | | return bind_string_helper<string_type>(std::forward<string_type>(value)); |
| | | } |
| | | |
| | | void clear() { m_value.clear(); } |
| | | char_type* alloc(size_t n) { m_value.resize(n); return (char_type*)m_value.data(); } |
| | | void truncate(size_t n) { m_value.resize(n); } |
| | | void assign(const char_type* str, size_t n) { m_value.assign(str, n); } |
| | | const char_type* data() const { return m_value.data(); } |
| | | size_t size() const { return m_value.size(); } |
| | | private: |
| | | string_type&& m_value; |
| | | }; |
| | | template <typename Command> |
| | | inline void bind_param(Command &command, size_t index, const std::string ¶m) |
| | | { |
| | | command.bind_param(index, param.data(), param.size()); |
| | | } |
| | | |
| | | template<typename StringT> |
| | | inline bind_string_helper<typename std::decay<StringT>::type> bind_string(StringT&& value) |
| | | { |
| | | typedef typename std::decay<StringT>::type string_type; |
| | | return bind_string_helper<string_type>(std::forward<string_type>(value)); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_param(Command &command, size_t index, std::istream ¶m) |
| | | { |
| | | command.bind_param(index, param); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_param(Command& command, size_t index, const std::string& param) |
| | | { |
| | | command.bind_param(index, param.data(), param.size()); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_param(Command& command, size_t index, std::istream& param) |
| | | { |
| | | command.bind_param(index, param); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_param(Command& command, size_t index, const T& param) |
| | | { |
| | | command.bind_param(index, param); |
| | | } |
| | | template <typename Command, typename T> |
| | | inline void bind_param(Command &command, size_t index, const T ¶m) |
| | | { |
| | | command.bind_param(index, param); |
| | | } |
| | | |
| | | #ifdef _QTL_ENABLE_CPP17 |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_param(Command& command, size_t index, const std::optional<T>& param) |
| | | { |
| | | if(param) |
| | | command.bind_param(index, *param); |
| | | else |
| | | command.bind_param(index, nullptr); |
| | | } |
| | | template <typename Command, typename T> |
| | | inline void bind_param(Command &command, size_t index, const std::optional<T> ¶m) |
| | | { |
| | | if (param) |
| | | command.bind_param(index, *param); |
| | | else |
| | | command.bind_param(index, nullptr); |
| | | } |
| | | |
| | | #endif // C++17 |
| | | |
| | | // The order of the overloaded functions 'bind_field' is very important |
| | | // The version with the most generic parameters is at the end |
| | | // The order of the overloaded functions 'bind_field' is very important |
| | | // The version with the most generic parameters is at the end |
| | | |
| | | template<typename Command, size_t N> |
| | | inline void bind_field(Command& command, size_t index, char (&value)[N]) |
| | | { |
| | | command.bind_field(index, value, N); |
| | | } |
| | | template <typename Command, size_t N> |
| | | inline void bind_field(Command &command, size_t index, char (&value)[N]) |
| | | { |
| | | command.bind_field(index, value, N); |
| | | } |
| | | |
| | | template<typename Command, size_t N> |
| | | inline void bind_field(Command& command, size_t index, wchar_t (&value)[N]) |
| | | { |
| | | command.bind_field(index, value, N); |
| | | } |
| | | template <typename Command, size_t N> |
| | | inline void bind_field(Command &command, size_t index, wchar_t (&value)[N]) |
| | | { |
| | | command.bind_field(index, value, N); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, char* value, size_t length) |
| | | { |
| | | command.bind_field(index, value, length); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, char *value, size_t length) |
| | | { |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, wchar_t* value, size_t length) |
| | | { |
| | | command.bind_field(index, value, length); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, wchar_t *value, size_t length) |
| | | { |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, std::string&& value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::string>(value))); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, std::string &&value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::string>(value))); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, std::wstring&& value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::wstring>(value))); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, std::wstring &&value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::wstring>(value))); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, std::vector<char>&& value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::vector<char>>(value))); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, std::vector<char> &&value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::vector<char>>(value))); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, size_t index, std::vector<wchar_t>&& value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::vector<wchar_t>>(value))); |
| | | } |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, size_t index, std::vector<wchar_t> &&value) |
| | | { |
| | | command.bind_field(index, bind_string(std::forward<std::vector<wchar_t>>(value))); |
| | | } |
| | | |
| | | template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type> |
| | | inline void bind_field(Command& command, size_t index, T&& value) |
| | | { |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, size_t index, T& value) |
| | | { |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type> |
| | | inline void bind_field(Command& command, const char* name, T&& value) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=T(); |
| | | else |
| | | template <typename Command, typename T, typename = typename std::enable_if<!std::is_reference<T>::value>::type> |
| | | inline void bind_field(Command &command, size_t index, T &&value) |
| | | { |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, const char* name, T& value) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=T(); |
| | | else |
| | | template <typename Command, typename T> |
| | | inline void bind_field(Command &command, size_t index, T &value) |
| | | { |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, const char* name, char* value, size_t length) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if (index == -1) |
| | | { |
| | | if (length > 0) value[0] = '\0'; |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, const char* name, wchar_t* value, size_t length) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if (index == -1) |
| | | template <typename Command, typename T, typename = typename std::enable_if<!std::is_reference<T>::value>::type> |
| | | inline void bind_field(Command &command, const char *name, T &&value) |
| | | { |
| | | if (length > 0) value[0] = '\0'; |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | value = T(); |
| | | else |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, const char* name, std::reference_wrapper<T>&& value) |
| | | { |
| | | return bind_field(command, value.get()); |
| | | } |
| | | template <typename Command, typename T> |
| | | inline void bind_field(Command &command, const char *name, T &value) |
| | | { |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | value = T(); |
| | | else |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, const char *name, char *value, size_t length) |
| | | { |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | { |
| | | if (length > 0) |
| | | value[0] = '\0'; |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template <typename Command> |
| | | inline void bind_field(Command &command, const char *name, wchar_t *value, size_t length) |
| | | { |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | { |
| | | if (length > 0) |
| | | value[0] = '\0'; |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template <typename Command, typename T> |
| | | inline void bind_field(Command &command, const char *name, std::reference_wrapper<T> &&value) |
| | | { |
| | | return bind_field(command, value.get()); |
| | | } |
| | | |
| | | #ifdef _QTL_ENABLE_CPP17 |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, size_t index, std::optional<T>& value) |
| | | { |
| | | value.emplace(); |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | template <typename Command, typename T> |
| | | inline void bind_field(Command &command, size_t index, std::optional<T> &value) |
| | | { |
| | | value.emplace(); |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, const char* name, std::optional<T>& value) |
| | | { |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | value.reset(); |
| | | else |
| | | bind_field(command, index, value); |
| | | } |
| | | template <typename Command, typename T> |
| | | inline void bind_field(Command &command, const char *name, std::optional<T> &value) |
| | | { |
| | | size_t index = command.find_field(name); |
| | | if (index == -1) |
| | | value.reset(); |
| | | else |
| | | bind_field(command, index, value); |
| | | } |
| | | |
| | | #endif // C++17 |
| | | |
| | | template<typename Command, typename T> |
| | | inline size_t bind_fields(Command& command, size_t index, T&& value) |
| | | { |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | return index+1; |
| | | } |
| | | template <typename Command, typename T> |
| | | inline size_t bind_fields(Command &command, size_t index, T &&value) |
| | | { |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | return index + 1; |
| | | } |
| | | |
| | | template<typename Command, typename T, typename... Other> |
| | | inline size_t bind_fields(Command& command, size_t start, T&& value, Other&&... other) |
| | | { |
| | | bind_field(command, start, std::forward<T>(value)); |
| | | return bind_fields(command, start+1, std::forward<Other>(other)...); |
| | | } |
| | | template <typename Command, typename T, typename... Other> |
| | | inline size_t bind_fields(Command &command, size_t start, T &&value, Other &&...other) |
| | | { |
| | | bind_field(command, start, std::forward<T>(value)); |
| | | return bind_fields(command, start + 1, std::forward<Other>(other)...); |
| | | } |
| | | |
| | | template<typename Command, typename... Fields> |
| | | inline size_t bind_fields(Command& command, Fields&&... fields) |
| | | { |
| | | return bind_fields(command, (size_t)0, std::forward<Fields>(fields)...); |
| | | } |
| | | template <typename Command, typename... Fields> |
| | | inline size_t bind_fields(Command &command, Fields &&...fields) |
| | | { |
| | | return bind_fields(command, (size_t)0, std::forward<Fields>(fields)...); |
| | | } |
| | | |
| | | namespace detail |
| | | { |
| | | namespace detail |
| | | { |
| | | |
| | | template<typename F, typename T> |
| | | struct apply_impl |
| | | { |
| | | private: |
| | | template <typename F, typename T> |
| | | struct apply_impl |
| | | { |
| | | private: |
| | | #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L |
| | | typedef typename std::invoke_result<F, T>::type raw_result_type; |
| | | typedef typename std::invoke_result<F, T>::type raw_result_type; |
| | | #else |
| | | typedef typename std::result_of<F(T)>::type raw_result_type; |
| | | typedef typename std::result_of<F(T)>::type raw_result_type; |
| | | #endif |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(F&& f, T&& v) |
| | | { |
| | | f(std::forward<T>(v)); |
| | | return true; |
| | | } |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(F&& f, T&& v) |
| | | { |
| | | return f(std::forward<T>(v)); |
| | | } |
| | | }; |
| | | template <typename Ret, bool> |
| | | struct impl |
| | | { |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(F &&f, T &&v) |
| | | { |
| | | f(std::forward<T>(v)); |
| | | return true; |
| | | } |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(F &&f, T &&v) |
| | | { |
| | | return f(std::forward<T>(v)); |
| | | } |
| | | }; |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(F&& f, T&& v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v)); |
| | | } |
| | | }; |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(F &&f, T &&v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v)); |
| | | } |
| | | }; |
| | | |
| | | template<typename F, typename... Types> |
| | | struct apply_impl<F, std::tuple<Types...>> |
| | | { |
| | | private: |
| | | typedef typename std::remove_reference<F>::type fun_type; |
| | | typedef std::tuple<Types...> arg_type; |
| | | template <typename F, typename... Types> |
| | | struct apply_impl<F, std::tuple<Types...>> |
| | | { |
| | | private: |
| | | typedef typename std::remove_reference<F>::type fun_type; |
| | | typedef std::tuple<Types...> arg_type; |
| | | #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L |
| | | typedef typename std::invoke_result<F, Types...>::type raw_result_type; |
| | | typedef typename std::invoke_result<F, Types...>::type raw_result_type; |
| | | #else |
| | | typedef typename std::result_of<F(Types...)>::type raw_result_type; |
| | | typedef typename std::result_of<F(Types...)>::type raw_result_type; |
| | | #endif |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(F&& f, arg_type&& v) |
| | | template <typename Ret, bool> |
| | | struct impl |
| | | { |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(F &&f, arg_type &&v) |
| | | { |
| | | qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | return true; |
| | | } |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(F &&f, arg_type &&v) |
| | | { |
| | | return qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | } |
| | | }; |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(F &&f, arg_type &&v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | } |
| | | }; |
| | | |
| | | template <typename Type, typename R> |
| | | struct apply_impl<R (Type::*)(), Type> |
| | | { |
| | | qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | return true; |
| | | } |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(F&& f, arg_type&& v) |
| | | private: |
| | | typedef R (Type::*fun_type)(); |
| | | typedef R raw_result_type; |
| | | template <typename Ret, bool> |
| | | struct impl |
| | | { |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(fun_type f, Type &&v) |
| | | { |
| | | (v.*f)(); |
| | | return true; |
| | | } |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(fun_type f, Type &&v) |
| | | { |
| | | return (v.*f)(); |
| | | } |
| | | }; |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(R (Type::*f)(), Type &&v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v)); |
| | | } |
| | | }; |
| | | |
| | | template <typename Type, typename R> |
| | | struct apply_impl<R (Type::*)() const, Type> |
| | | { |
| | | return qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | } |
| | | }; |
| | | private: |
| | | typedef R (Type::*fun_type)() const; |
| | | typedef R raw_result_type; |
| | | template <typename Ret, bool> |
| | | struct impl |
| | | { |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(fun_type f, Type &&v) |
| | | { |
| | | (v.*f)(); |
| | | return true; |
| | | } |
| | | }; |
| | | template <typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(fun_type f, Type &&v) |
| | | { |
| | | return (v.*f)(); |
| | | } |
| | | }; |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(F&& f, arg_type&& v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v)); |
| | | } |
| | | }; |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(fun_type f, Type &&v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v)); |
| | | } |
| | | }; |
| | | |
| | | template<typename Type, typename R> |
| | | struct apply_impl<R (Type::*)(), Type> |
| | | { |
| | | private: |
| | | typedef R (Type::*fun_type)(); |
| | | typedef R raw_result_type; |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(fun_type f, Type&& v) |
| | | template <typename F, typename T> |
| | | typename apply_impl<F, T>::result_type apply(F &&f, T &&v) |
| | | { |
| | | (v.*f)(); |
| | | return true; |
| | | return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v)); |
| | | } |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(fun_type f, Type&& v) |
| | | |
| | | template <typename Command, size_t N, typename... Types> |
| | | struct bind_helper |
| | | { |
| | | return (v.*f)(); |
| | | } |
| | | }; |
| | | public: |
| | | explicit bind_helper(Command &command) : m_command(command) {} |
| | | void operator()(const std::tuple<Types...> ¶ms) const |
| | | { |
| | | bind_param(m_command, N - 1, std::get<N - 1>(params)); |
| | | (bind_helper<Command, N - 1, Types...>(m_command))(params); |
| | | } |
| | | void operator()(std::tuple<Types...> &¶ms) const |
| | | { |
| | | typedef typename std::remove_reference<typename std::tuple_element<N - 1, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, N - 1, std::forward<param_type>(std::get<N - 1>(std::forward<tuple_type>(params)))); |
| | | (bind_helper<Command, N - 1, Types...>(m_command))(std::forward<tuple_type>(params)); |
| | | } |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(R (Type::*f)(), Type&& v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v)); |
| | | } |
| | | }; |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command &m_command; |
| | | }; |
| | | |
| | | template<typename Type, typename R> |
| | | struct apply_impl<R (Type::*)() const, Type> |
| | | { |
| | | private: |
| | | typedef R (Type::*fun_type)() const; |
| | | typedef R raw_result_type; |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | | typedef bool result_type; |
| | | result_type operator()(fun_type f, Type&& v) |
| | | template <typename Command, typename... Types> |
| | | struct bind_helper<Command, 1, Types...> |
| | | { |
| | | (v.*f)(); |
| | | return true; |
| | | } |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, false> |
| | | { |
| | | typedef Ret result_type; |
| | | result_type operator()(fun_type f, Type&& v) |
| | | public: |
| | | explicit bind_helper(Command &command) : m_command(command) {} |
| | | void operator()(const std::tuple<Types...> ¶ms) const |
| | | { |
| | | bind_param(m_command, 0, std::get<0>(params)); |
| | | } |
| | | void operator()(std::tuple<Types...> &¶ms) const |
| | | { |
| | | typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params)))); |
| | | } |
| | | |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command &m_command; |
| | | }; |
| | | |
| | | template <typename Command, typename... Types> |
| | | struct bind_helper<Command, 0, Types...> |
| | | { |
| | | return (v.*f)(); |
| | | } |
| | | }; |
| | | |
| | | public: |
| | | typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type; |
| | | result_type operator()(fun_type f, Type&& v) |
| | | { |
| | | return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v)); |
| | | } |
| | | }; |
| | | |
| | | template<typename F, typename T> |
| | | typename apply_impl<F, T>::result_type apply(F&& f, T&& v) |
| | | { |
| | | return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v)); |
| | | } |
| | | |
| | | template<typename Command, size_t N, typename... Types> |
| | | struct bind_helper |
| | | { |
| | | public: |
| | | explicit bind_helper(Command& command) : m_command(command) { } |
| | | void operator()(const std::tuple<Types...>& params) const |
| | | { |
| | | bind_param(m_command, N-1, std::get<N-1>(params)); |
| | | (bind_helper<Command, N-1, Types...>(m_command))(params); |
| | | } |
| | | void operator()(std::tuple<Types...>&& params) const |
| | | { |
| | | typedef typename std::remove_reference<typename std::tuple_element<N-1, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, N-1, std::forward<param_type>(std::get<N-1>(std::forward<tuple_type>(params)))); |
| | | (bind_helper<Command, N-1, Types...>(m_command))(std::forward<tuple_type>(params)); |
| | | } |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command& m_command; |
| | | }; |
| | | |
| | | template<typename Command, typename... Types> |
| | | struct bind_helper<Command, 1, Types...> |
| | | { |
| | | public: |
| | | explicit bind_helper(Command& command) : m_command(command) { } |
| | | void operator()(const std::tuple<Types...>& params) const |
| | | { |
| | | bind_param(m_command, 0, std::get<0>(params)); |
| | | } |
| | | void operator()(std::tuple<Types...>&& params) const |
| | | { |
| | | typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params)))); |
| | | } |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command& m_command; |
| | | }; |
| | | |
| | | template<typename Command, typename... Types> |
| | | struct bind_helper<Command, 0, Types...> |
| | | { |
| | | public: |
| | | explicit bind_helper(Command& command) { } |
| | | void operator()(const std::tuple<Types...>& params) const |
| | | { |
| | | } |
| | | void operator()(std::tuple<Types...>&& params) const |
| | | { |
| | | } |
| | | }; |
| | | public: |
| | | explicit bind_helper(Command &command) {} |
| | | void operator()(const std::tuple<Types...> ¶ms) const |
| | | { |
| | | } |
| | | void operator()(std::tuple<Types...> &¶ms) const |
| | | { |
| | | } |
| | | }; |
| | | |
| | | #define QTL_ARGS_TUPLE(Arg, Others) \ |
| | | typename std::tuple<typename std::decay<Arg>::type, typename std::decay<Others>::type...> |
| | | |
| | | template<typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values(Ret (*)(Arg)) |
| | | { |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | |
| | | template<typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | |
| | | template<typename Type, typename Ret> |
| | | inline Type make_values(Ret (Type::*)()) |
| | | { |
| | | return Type(); |
| | | }; |
| | | template<typename Type, typename Ret> |
| | | inline Type make_values(Ret (Type::*)() const) |
| | | { |
| | | return Type(); |
| | | }; |
| | | |
| | | template<typename Type, typename Ret, typename... Args> |
| | | inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args) |
| | | { |
| | | return QTL_ARGS_TUPLE(Type, Args)(); |
| | | }; |
| | | template<typename Type, typename Ret, typename... Args> |
| | | inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args) |
| | | { |
| | | return QTL_ARGS_TUPLE(Type, Args)(); |
| | | }; |
| | | |
| | | template<typename Type, typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg)) |
| | | { |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | template<typename Type, typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const) |
| | | { |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | |
| | | template<typename Type, typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | template<typename Type, typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | |
| | | template<typename Functor, typename=typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type> |
| | | inline auto make_values(const Functor&) |
| | | -> decltype(make_values_noclass(&Functor::operator())) |
| | | { |
| | | return make_values_noclass(&Functor::operator()); |
| | | } |
| | | |
| | | template<typename Command, typename ValueProc> |
| | | inline void fetch_command(Command& command, ValueProc&& proc) |
| | | { |
| | | auto values=make_values(proc); |
| | | typedef decltype(values) values_type; |
| | | while(command.fetch(std::forward<values_type>(values))) |
| | | { |
| | | if(!apply(std::forward<ValueProc>(proc), std::forward<values_type>(values))) |
| | | break; |
| | | } |
| | | } |
| | | |
| | | template<typename Command, typename ValueProc, typename... OtherProc> |
| | | inline void fetch_command(Command& command, ValueProc&& proc, OtherProc&&... other) |
| | | { |
| | | fetch_command(command, std::forward<ValueProc>(proc)); |
| | | if(command.next_result()) |
| | | { |
| | | fetch_command(command, std::forward<OtherProc>(other)...); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | struct params_binder |
| | | { |
| | | enum { size = 1 }; |
| | | inline void operator()(Command& command, const T& param) const |
| | | { |
| | | qtl::bind_param(command, 0, param); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename... Types> |
| | | struct params_binder<Command, std::tuple<Types...>> |
| | | { |
| | | enum { size = sizeof...(Types) }; |
| | | void operator()(Command& command, const std::tuple<Types...>& params) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename Type1, typename Type2> |
| | | struct params_binder<Command, std::pair<Type1, Type2>> |
| | | { |
| | | enum { size = 2 }; |
| | | void operator()(Command& command, std::pair<Type1, Type2>&& values) const |
| | | { |
| | | qtl::bind_param(command, 0, std::forward<Type1>(values.first)); |
| | | qtl::bind_param(command, 1, std::forward<Type2>(values.second)); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_params(Command& command, const T& param) |
| | | { |
| | | params_binder<Command, T> binder; |
| | | binder(command, param); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | struct record_binder |
| | | { |
| | | inline void operator()(Command& command, T&& value) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value)); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename T> |
| | | struct record_binder<Command, std::reference_wrapper<T>> |
| | | { |
| | | inline void operator()(Command& command, std::reference_wrapper<T>&& value) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value.get())); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename... Types> |
| | | struct record_binder<Command, std::tuple<Types...>> |
| | | { |
| | | void operator()(Command& command, std::tuple<Types...>&& values) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command)) |
| | | (std::forward<std::tuple<Types...>>(values)); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename Type1, typename Type2> |
| | | struct record_binder<Command, std::pair<Type1, Type2>> |
| | | { |
| | | void operator()(Command& command, std::pair<Type1, Type2>&& values) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first)); |
| | | bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second)); |
| | | } |
| | | }; |
| | | |
| | | template<typename T, typename Tag> |
| | | struct record_with_tag : public T |
| | | { |
| | | }; |
| | | |
| | | template<typename T, typename Pred> |
| | | struct custom_binder_type : public T |
| | | { |
| | | typedef T value_type; |
| | | |
| | | explicit custom_binder_type(Pred pred) : m_pred(pred) { } |
| | | custom_binder_type(value_type&& v, Pred pred) |
| | | : value_type(std::forward<value_type>(v)), m_pred(pred) |
| | | { |
| | | } |
| | | template<typename... Args> |
| | | custom_binder_type(Pred pred, Args&&... args) |
| | | : value_type(std::forward<Args>(args)...), m_pred(pred) |
| | | { |
| | | } |
| | | |
| | | template<typename Command> |
| | | void bind(Command& command) |
| | | { |
| | | m_pred(std::forward<T>(*this), command); // Pred maybe member function |
| | | } |
| | | |
| | | private: |
| | | Pred m_pred; |
| | | }; |
| | | |
| | | template<typename T, typename Pred> |
| | | struct custom_binder_type<std::reference_wrapper<T>, Pred> : public std::reference_wrapper<T> |
| | | { |
| | | typedef std::reference_wrapper<T> value_type; |
| | | |
| | | explicit custom_binder_type(Pred pred) : m_pred(pred) { } |
| | | custom_binder_type(value_type&& v, Pred pred) |
| | | : value_type(std::forward<value_type>(v)), m_pred(pred) |
| | | { |
| | | } |
| | | template<typename... Args> |
| | | custom_binder_type(Pred pred, Args&&... args) |
| | | : T(std::forward<Args>(args)...), m_pred(pred) |
| | | { |
| | | } |
| | | |
| | | template<typename Command> |
| | | void bind(Command& command) |
| | | { |
| | | m_pred(std::forward<T>(*this), command); // Pred maybe member function |
| | | } |
| | | |
| | | private: |
| | | Pred m_pred; |
| | | }; |
| | | |
| | | |
| | | template<typename T, typename Pred> |
| | | inline custom_binder_type<T, Pred> custom_bind(T&& v, Pred pred) |
| | | { |
| | | return custom_binder_type<T, Pred>(std::forward<T>(v), pred); |
| | | } |
| | | |
| | | template<typename Command, typename T, typename Pred> |
| | | struct record_binder<Command, custom_binder_type<T, Pred>> |
| | | { |
| | | void operator()(Command& command, custom_binder_type<T, Pred>&& values) const |
| | | { |
| | | values.bind(command); |
| | | } |
| | | }; |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_record(Command& command, T&& value) |
| | | { |
| | | record_binder<Command, T> binder; |
| | | binder(command, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command, typename Record> |
| | | class query_iterator final |
| | | { |
| | | public: |
| | | using iterator_category = std::forward_iterator_tag; |
| | | using value_type = Record; |
| | | using difference_type = ptrdiff_t; |
| | | using pointer = Record*; |
| | | using reference = Record&; |
| | | |
| | | explicit query_iterator(Command& command) |
| | | : m_command(command) { } |
| | | Record* operator->() const { return m_record.get(); } |
| | | Record& operator*() const { return *m_record; } |
| | | |
| | | query_iterator& operator++() |
| | | { |
| | | if(!m_record) |
| | | m_record=std::make_shared<Record>(); |
| | | if(m_record.use_count()==1) |
| | | template <typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values(Ret (*)(Arg)) |
| | | { |
| | | if(!m_command.fetch(std::forward<Record>(*m_record))) |
| | | m_record.reset(); |
| | | } |
| | | else |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | |
| | | template <typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | std::shared_ptr<Record> record=std::make_shared<Record>(); |
| | | if(m_command.fetch(std::forward<Record>(*record))) |
| | | m_record=record; |
| | | else |
| | | m_record.reset(); |
| | | } |
| | | return *this; |
| | | } |
| | | query_iterator operator++(int) |
| | | { |
| | | query_iterator temp=*this; |
| | | m_record=std::make_shared<Record>(); |
| | | if(!m_command.fetch(std::forward<Record>(*m_record))) |
| | | m_record.reset(); |
| | | return temp; |
| | | } |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | |
| | | bool operator ==(const query_iterator& rhs) |
| | | { |
| | | return &this->m_command==&rhs.m_command && |
| | | this->m_record==rhs.m_record; |
| | | } |
| | | bool operator !=(const query_iterator& rhs) |
| | | { |
| | | return !(*this==rhs); |
| | | } |
| | | |
| | | private: |
| | | Command& m_command; |
| | | std::shared_ptr<Record> m_record; |
| | | }; |
| | | |
| | | template<typename Command, typename Record> |
| | | class query_result final |
| | | { |
| | | public: |
| | | typedef typename query_iterator<Command, Record>::value_type value_type; |
| | | typedef typename query_iterator<Command, Record>::pointer pointer; |
| | | typedef typename query_iterator<Command, Record>::reference reference; |
| | | typedef query_iterator<Command, Record> iterator; |
| | | |
| | | explicit query_result(Command&& command) : m_command(std::move(command)) { } |
| | | query_result(query_result&& src) : m_command(std::move(src.m_command)) { } |
| | | query_result& operator=(query_result&& src) |
| | | { |
| | | if(this!=&src) |
| | | m_command=std::move(src.m_command); |
| | | return *this; |
| | | } |
| | | |
| | | template<typename Params> |
| | | iterator begin(const Params& params) |
| | | { |
| | | query_iterator<Command, Record> it(m_command); |
| | | ++it; |
| | | return it; |
| | | } |
| | | iterator begin() |
| | | { |
| | | return begin(std::make_tuple()); |
| | | } |
| | | |
| | | iterator end() |
| | | { |
| | | return query_iterator<Command, Record>(m_command); |
| | | } |
| | | |
| | | private: |
| | | Command m_command; |
| | | }; |
| | | |
| | | template<typename T, class Command> |
| | | class base_database |
| | | { |
| | | public: |
| | | template<typename Params> |
| | | base_database& execute(const char* query_text, size_t text_length, const Params& params, uint64_t* affected=NULL) |
| | | { |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | if(affected) *affected=command.affetced_rows(); |
| | | command.close(); |
| | | return *this; |
| | | } |
| | | template<typename Params> |
| | | base_database& execute(const char* query_text, const Params& params, uint64_t* affected=NULL) |
| | | { |
| | | return execute(query_text, strlen(query_text), params, affected); |
| | | } |
| | | template<typename Params> |
| | | base_database& execute(const std::string& query_text, const Params& params, uint64_t* affected=NULL) |
| | | { |
| | | return execute(query_text.data(), query_text.length(), params, affected); |
| | | } |
| | | |
| | | template<typename... Params> |
| | | base_database& execute_direct(const char* query_text, size_t text_length, uint64_t* affected, const Params&... params) |
| | | { |
| | | return execute(query_text, text_length, std::forward_as_tuple(params...), affected); |
| | | } |
| | | template<typename... Params> |
| | | base_database& execute_direct(const char* query_text, uint64_t* affected, const Params&... params) |
| | | { |
| | | return execute(query_text, std::forward_as_tuple(params...), affected); |
| | | } |
| | | template<typename... Params> |
| | | base_database& execute_direct(const std::string& query_text, uint64_t* affected, const Params&... params) |
| | | { |
| | | return execute(query_text, std::forward_as_tuple(params...), affected); |
| | | } |
| | | |
| | | template<typename Params> |
| | | uint64_t insert(const char* query_text, size_t text_length, const Params& params) |
| | | { |
| | | uint64_t id=0; |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | if(command.affetced_rows()>0) |
| | | id=command.insert_id(); |
| | | return id; |
| | | } |
| | | |
| | | template<typename Params> |
| | | uint64_t insert(const char* query_text, const Params& params) |
| | | { |
| | | return insert(query_text, strlen(query_text), params); |
| | | } |
| | | |
| | | template<typename Params> |
| | | uint64_t insert(const std::string& query_text, const Params& params) |
| | | { |
| | | return insert(query_text.data(), query_text.length(), params); |
| | | } |
| | | |
| | | template<typename... Params> |
| | | uint64_t insert_direct(const char* query_text, size_t text_length, const Params&... params) |
| | | { |
| | | return insert(query_text, text_length, std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template<typename... Params> |
| | | uint64_t insert_direct(const char* query_text, const Params&... params) |
| | | { |
| | | return insert(query_text, strlen(query_text), std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template<typename... Params> |
| | | uint64_t insert_direct(const std::string& query_text, const Params&... params) |
| | | { |
| | | return insert(query_text.data(), query_text.length(), std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template<typename Record, typename Params> |
| | | query_result<Command, Record> result(const char* query_text, size_t text_length, const Params& params) |
| | | { |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | return query_result<Command, Record>(std::move(command)); |
| | | } |
| | | template<typename Record, typename Params> |
| | | query_result<Command, Record> result(const char* query_text, const Params& params) |
| | | { |
| | | return result<Record, Params>(query_text, strlen(query_text), params); |
| | | } |
| | | template<typename Record, typename Params> |
| | | query_result<Command, Record> result(const std::string& query_text, const Params& params) |
| | | { |
| | | return result<Record, Params>(query_text.data(), query_text.length(), params); |
| | | } |
| | | template<typename Record> |
| | | query_result<Command, Record> result(const char* query_text, size_t text_length) |
| | | { |
| | | return result<Record>(query_text, text_length, std::make_tuple()); |
| | | } |
| | | template<typename Record> |
| | | query_result<Command, Record> result(const char* query_text) |
| | | { |
| | | return result<Record>(query_text, strlen(query_text), std::make_tuple()); |
| | | } |
| | | template<typename Record> |
| | | query_result<Command, Record> result(const std::string& query_text) |
| | | { |
| | | return result<Record>(query_text.data(), query_text.length(), std::make_tuple()); |
| | | } |
| | | |
| | | template<typename Params, typename Values, typename ValueProc> |
| | | base_database& query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, ValueProc&& proc) |
| | | { |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | while(command.fetch(std::forward<Values>(values))) |
| | | template <typename Type, typename Ret> |
| | | inline Type make_values(Ret (Type::*)()) |
| | | { |
| | | if(!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) break; |
| | | return Type(); |
| | | }; |
| | | template <typename Type, typename Ret> |
| | | inline Type make_values(Ret (Type::*)() const) |
| | | { |
| | | return Type(); |
| | | }; |
| | | |
| | | template <typename Type, typename Ret, typename... Args> |
| | | inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args) |
| | | { |
| | | return QTL_ARGS_TUPLE(Type, Args)(); |
| | | }; |
| | | template <typename Type, typename Ret, typename... Args> |
| | | inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args) |
| | | { |
| | | return QTL_ARGS_TUPLE(Type, Args)(); |
| | | }; |
| | | |
| | | template <typename Type, typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg)) |
| | | { |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | template <typename Type, typename Ret, typename Arg> |
| | | inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const) |
| | | { |
| | | return typename std::decay<Arg>::type(); |
| | | }; |
| | | |
| | | template <typename Type, typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | template <typename Type, typename Ret, typename Arg, typename... Others> |
| | | inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others) |
| | | { |
| | | return QTL_ARGS_TUPLE(Arg, Others)(); |
| | | }; |
| | | |
| | | template <typename Functor, typename = typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type> |
| | | inline auto make_values(const Functor &) |
| | | -> decltype(make_values_noclass(&Functor::operator())) |
| | | { |
| | | return make_values_noclass(&Functor::operator()); |
| | | } |
| | | command.close(); |
| | | return *this; |
| | | |
| | | template <typename Command, typename ValueProc> |
| | | inline void fetch_command(Command &command, ValueProc &&proc) |
| | | { |
| | | auto values = make_values(proc); |
| | | typedef decltype(values) values_type; |
| | | while (command.fetch(std::forward<values_type>(values))) |
| | | { |
| | | if (!apply(std::forward<ValueProc>(proc), std::forward<values_type>(values))) |
| | | break; |
| | | } |
| | | } |
| | | |
| | | template <typename Command, typename ValueProc, typename... OtherProc> |
| | | inline void fetch_command(Command &command, ValueProc &&proc, OtherProc &&...other) |
| | | { |
| | | fetch_command(command, std::forward<ValueProc>(proc)); |
| | | if (command.next_result()) |
| | | { |
| | | fetch_command(command, std::forward<OtherProc>(other)...); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | template<typename Params, typename Values, typename ValueProc> |
| | | base_database& query_explicit(const char* query_text, const Params& params, Values&& values, ValueProc&& proc) |
| | | template <typename Command, typename T> |
| | | struct params_binder |
| | | { |
| | | return query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Params, typename Values, typename ValueProc> |
| | | base_database& query_explicit(const std::string& query_text, const Params& params, Values&& values, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Values, typename ValueProc> |
| | | base_database& query_explicit(const char* query_text, size_t text_length, Values&& values, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Values, typename ValueProc> |
| | | base_database& query_explicit(const char* query_text, Values&& values, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Values, typename ValueProc> |
| | | base_database& query_explicit(const std::string& query_text, Values&& values, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | |
| | | template<typename Params, typename ValueProc> |
| | | base_database& query(const char* query_text, size_t text_length, const Params& params, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Params, typename ValueProc> |
| | | base_database& query(const char* query_text, const Params& params, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename Params, typename ValueProc> |
| | | base_database& query(const std::string& query_text, const Params& params, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename ValueProc> |
| | | base_database& query(const char* query_text, size_t text_length, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename ValueProc> |
| | | base_database& query(const char* query_text, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template<typename ValueProc> |
| | | base_database& query(const std::string& query_text, ValueProc&& proc) |
| | | { |
| | | return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | |
| | | template<typename Params, typename... ValueProc> |
| | | base_database& query_multi_with_params(const char* query_text, size_t text_length, const Params& params, ValueProc&&... proc) |
| | | { |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | detail::fetch_command(command, std::forward<ValueProc>(proc)...); |
| | | command.close(); |
| | | return *this; |
| | | } |
| | | template<typename Params, typename... ValueProc> |
| | | base_database& query_multi_with_params(const char* query_text, const Params& params, ValueProc&&... proc) |
| | | { |
| | | return query_multi_with_params(query_text, strlen(query_text), params, std::forward<ValueProc>(proc)...); |
| | | } |
| | | template<typename Params, typename... ValueProc> |
| | | base_database& query_multi_with_params(const std::string& query_text, const Params& params, ValueProc&&... proc) |
| | | { |
| | | return query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<ValueProc>(proc)...); |
| | | } |
| | | template<typename... ValueProc> |
| | | base_database& query_multi(const char* query_text, size_t text_length, ValueProc&&... proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | template<typename... ValueProc> |
| | | base_database& query_multi(const char* query_text, ValueProc&&... proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | template<typename... ValueProc> |
| | | base_database& query_multi(const std::string& query_text, ValueProc&&... proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | |
| | | template<typename Params, typename Values> |
| | | bool query_first(const char* query_text, size_t text_length, const Params& params, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, text_length, params, std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename Params, typename Values> |
| | | bool query_first(const char* query_text, const Params& params, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename Params, typename Values> |
| | | bool query_first(const std::string& query_text, const Params& params, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, params, values, std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename Values> |
| | | bool query_first(const char* query_text, size_t text_length, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename Values> |
| | | bool query_first(const char* query_text, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename Values> |
| | | bool query_first(const std::string& query_text, Values&& values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template<typename... Values> |
| | | bool query_first_direct(const char* query_text, size_t text_length, Values&... values) |
| | | { |
| | | return query_first(query_text, text_length, std::tie(values...)); |
| | | } |
| | | |
| | | template<typename... Values> |
| | | bool query_first_direct(const char* query_text, Values&... values) |
| | | { |
| | | return query_first(query_text, std::tie(values...)); |
| | | } |
| | | |
| | | template<typename... Values> |
| | | bool query_first_direct(const std::string& query_text, Values&... values) |
| | | { |
| | | return query_first(query_text, std::tie(values...)); |
| | | } |
| | | |
| | | protected: |
| | | struct nothing |
| | | { |
| | | template<typename... Values> bool operator()(Values&&...) const { return true; } |
| | | enum |
| | | { |
| | | size = 1 |
| | | }; |
| | | inline void operator()(Command &command, const T ¶m) const |
| | | { |
| | | qtl::bind_param(command, 0, param); |
| | | } |
| | | }; |
| | | struct first_record |
| | | |
| | | template <typename Command, typename... Types> |
| | | struct params_binder<Command, std::tuple<Types...>> |
| | | { |
| | | first_record() : _found(false) { } |
| | | template<typename... Values> bool operator()(Values&&...) { _found = true; return false; } |
| | | operator bool() const { return _found; } |
| | | enum |
| | | { |
| | | size = sizeof...(Types) |
| | | }; |
| | | void operator()(Command &command, const std::tuple<Types...> ¶ms) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename Type1, typename Type2> |
| | | struct params_binder<Command, std::pair<Type1, Type2>> |
| | | { |
| | | enum |
| | | { |
| | | size = 2 |
| | | }; |
| | | void operator()(Command &command, std::pair<Type1, Type2> &&values) const |
| | | { |
| | | qtl::bind_param(command, 0, std::forward<Type1>(values.first)); |
| | | qtl::bind_param(command, 1, std::forward<Type2>(values.second)); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename T> |
| | | inline void bind_params(Command &command, const T ¶m) |
| | | { |
| | | params_binder<Command, T> binder; |
| | | binder(command, param); |
| | | } |
| | | |
| | | template <typename Command, typename T> |
| | | struct record_binder |
| | | { |
| | | inline void operator()(Command &command, T &&value) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value)); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename T> |
| | | struct record_binder<Command, std::reference_wrapper<T>> |
| | | { |
| | | inline void operator()(Command &command, std::reference_wrapper<T> &&value) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value.get())); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename... Types> |
| | | struct record_binder<Command, std::tuple<Types...>> |
| | | { |
| | | void operator()(Command &command, std::tuple<Types...> &&values) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(std::forward<std::tuple<Types...>>(values)); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename Type1, typename Type2> |
| | | struct record_binder<Command, std::pair<Type1, Type2>> |
| | | { |
| | | void operator()(Command &command, std::pair<Type1, Type2> &&values) const |
| | | { |
| | | bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first)); |
| | | bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second)); |
| | | } |
| | | }; |
| | | |
| | | template <typename T, typename Tag> |
| | | struct record_with_tag : public T |
| | | { |
| | | }; |
| | | |
| | | template <typename T, typename Pred> |
| | | struct custom_binder_type : public T |
| | | { |
| | | typedef T value_type; |
| | | |
| | | explicit custom_binder_type(Pred pred) : m_pred(pred) {} |
| | | custom_binder_type(value_type &&v, Pred pred) |
| | | : value_type(std::forward<value_type>(v)), m_pred(pred) |
| | | { |
| | | } |
| | | template <typename... Args> |
| | | custom_binder_type(Pred pred, Args &&...args) |
| | | : value_type(std::forward<Args>(args)...), m_pred(pred) |
| | | { |
| | | } |
| | | |
| | | template <typename Command> |
| | | void bind(Command &command) |
| | | { |
| | | m_pred(std::forward<T>(*this), command); // Pred maybe member function |
| | | } |
| | | |
| | | private: |
| | | bool _found; |
| | | Pred m_pred; |
| | | }; |
| | | }; |
| | | |
| | | class blobbuf : public std::streambuf |
| | | { |
| | | public: |
| | | blobbuf() = default; |
| | | blobbuf(const blobbuf&) = default; |
| | | blobbuf& operator=(const blobbuf&) = default; |
| | | virtual ~blobbuf() |
| | | template <typename T, typename Pred> |
| | | struct custom_binder_type<std::reference_wrapper<T>, Pred> : public std::reference_wrapper<T> |
| | | { |
| | | overflow(); |
| | | } |
| | | typedef std::reference_wrapper<T> value_type; |
| | | |
| | | void swap(blobbuf& other) |
| | | { |
| | | std::swap(m_buf, other.m_buf); |
| | | std::swap(m_size, other.m_size); |
| | | std::swap(m_pos, other.m_pos); |
| | | |
| | | std::streambuf::swap(other); |
| | | } |
| | | |
| | | protected: |
| | | virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, |
| | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
| | | { |
| | | if (which&std::ios_base::in) |
| | | explicit custom_binder_type(Pred pred) : m_pred(pred) {} |
| | | custom_binder_type(value_type &&v, Pred pred) |
| | | : value_type(std::forward<value_type>(v)), m_pred(pred) |
| | | { |
| | | pos_type pos = 0; |
| | | pos = seekoff(m_pos, off, dir); |
| | | return seekpos(pos, which); |
| | | } |
| | | return std::streambuf::seekoff(off, dir, which); |
| | | template <typename... Args> |
| | | custom_binder_type(Pred pred, Args &&...args) |
| | | : T(std::forward<Args>(args)...), m_pred(pred) |
| | | { |
| | | } |
| | | |
| | | template <typename Command> |
| | | void bind(Command &command) |
| | | { |
| | | m_pred(std::forward<T>(*this), command); // Pred maybe member function |
| | | } |
| | | |
| | | private: |
| | | Pred m_pred; |
| | | }; |
| | | |
| | | template <typename T, typename Pred> |
| | | inline custom_binder_type<T, Pred> custom_bind(T &&v, Pred pred) |
| | | { |
| | | return custom_binder_type<T, Pred>(std::forward<T>(v), pred); |
| | | } |
| | | |
| | | virtual pos_type seekpos(pos_type pos, |
| | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
| | | template <typename Command, typename T, typename Pred> |
| | | struct record_binder<Command, custom_binder_type<T, Pred>> |
| | | { |
| | | if (pos >= m_size) |
| | | return pos_type(off_type(-1)); |
| | | |
| | | if (which&std::ios_base::out) |
| | | void operator()(Command &command, custom_binder_type<T, Pred> &&values) const |
| | | { |
| | | if (pos < m_pos || pos >= m_pos + off_type(egptr() - pbase())) |
| | | values.bind(command); |
| | | } |
| | | }; |
| | | |
| | | template <typename Command, typename T> |
| | | inline void bind_record(Command &command, T &&value) |
| | | { |
| | | record_binder<Command, T> binder; |
| | | binder(command, std::forward<T>(value)); |
| | | } |
| | | |
| | | template <typename Command, typename Record> |
| | | class query_iterator final |
| | | { |
| | | public: |
| | | using iterator_category = std::forward_iterator_tag; |
| | | using value_type = Record; |
| | | using difference_type = ptrdiff_t; |
| | | using pointer = Record *; |
| | | using reference = Record &; |
| | | |
| | | explicit query_iterator(Command &command) |
| | | : m_command(command) {} |
| | | Record *operator->() const { return m_record.get(); } |
| | | Record &operator*() const { return *m_record; } |
| | | |
| | | query_iterator &operator++() |
| | | { |
| | | if (!m_record) |
| | | m_record = std::make_shared<Record>(); |
| | | if (m_record.use_count() == 1) |
| | | { |
| | | overflow(); |
| | | m_pos = pos; |
| | | setp(m_buf.data(), m_buf.data() + m_buf.size()); |
| | | if (!m_command.fetch(std::forward<Record>(*m_record))) |
| | | m_record.reset(); |
| | | } |
| | | else |
| | | { |
| | | pbump(off_type(pos - pabs())); |
| | | std::shared_ptr<Record> record = std::make_shared<Record>(); |
| | | if (m_command.fetch(std::forward<Record>(*record))) |
| | | m_record = record; |
| | | else |
| | | m_record.reset(); |
| | | } |
| | | return *this; |
| | | } |
| | | query_iterator operator++(int) |
| | | { |
| | | query_iterator temp = *this; |
| | | m_record = std::make_shared<Record>(); |
| | | if (!m_command.fetch(std::forward<Record>(*m_record))) |
| | | m_record.reset(); |
| | | return temp; |
| | | } |
| | | |
| | | bool operator==(const query_iterator &rhs) |
| | | { |
| | | return &this->m_command == &rhs.m_command && |
| | | this->m_record == rhs.m_record; |
| | | } |
| | | bool operator!=(const query_iterator &rhs) |
| | | { |
| | | return !(*this == rhs); |
| | | } |
| | | |
| | | private: |
| | | Command &m_command; |
| | | std::shared_ptr<Record> m_record; |
| | | }; |
| | | |
| | | template <typename Command, typename Record> |
| | | class query_result final |
| | | { |
| | | public: |
| | | typedef typename query_iterator<Command, Record>::value_type value_type; |
| | | typedef typename query_iterator<Command, Record>::pointer pointer; |
| | | typedef typename query_iterator<Command, Record>::reference reference; |
| | | typedef query_iterator<Command, Record> iterator; |
| | | |
| | | explicit query_result(Command &&command) : m_command(std::move(command)) {} |
| | | query_result(query_result &&src) : m_command(std::move(src.m_command)) {} |
| | | query_result &operator=(query_result &&src) |
| | | { |
| | | if (this != &src) |
| | | m_command = std::move(src.m_command); |
| | | return *this; |
| | | } |
| | | |
| | | template <typename Params> |
| | | iterator begin(const Params ¶ms) |
| | | { |
| | | query_iterator<Command, Record> it(m_command); |
| | | ++it; |
| | | return it; |
| | | } |
| | | iterator begin() |
| | | { |
| | | return begin(std::make_tuple()); |
| | | } |
| | | |
| | | iterator end() |
| | | { |
| | | return query_iterator<Command, Record>(m_command); |
| | | } |
| | | |
| | | private: |
| | | Command m_command; |
| | | }; |
| | | |
| | | template <typename T, class Command> |
| | | class base_database |
| | | { |
| | | public: |
| | | template <typename Params> |
| | | base_database &execute(const char *query_text, size_t text_length, const Params ¶ms, uint64_t *affected = NULL) |
| | | { |
| | | T *pThis = static_cast<T *>(this); |
| | | Command command = pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | if (affected) |
| | | *affected = command.affetced_rows(); |
| | | command.close(); |
| | | return *this; |
| | | } |
| | | template <typename Params> |
| | | base_database &execute(const char *query_text, const Params ¶ms, uint64_t *affected = NULL) |
| | | { |
| | | return execute(query_text, strlen(query_text), params, affected); |
| | | } |
| | | template <typename Params> |
| | | base_database &execute(const std::string &query_text, const Params ¶ms, uint64_t *affected = NULL) |
| | | { |
| | | return execute(query_text.data(), query_text.length(), params, affected); |
| | | } |
| | | |
| | | template <typename... Params> |
| | | base_database &execute_direct(const char *query_text, size_t text_length, uint64_t *affected, const Params &...params) |
| | | { |
| | | return execute(query_text, text_length, std::forward_as_tuple(params...), affected); |
| | | } |
| | | template <typename... Params> |
| | | base_database &execute_direct(const char *query_text, uint64_t *affected, const Params &...params) |
| | | { |
| | | return execute(query_text, std::forward_as_tuple(params...), affected); |
| | | } |
| | | template <typename... Params> |
| | | base_database &execute_direct(const std::string &query_text, uint64_t *affected, const Params &...params) |
| | | { |
| | | return execute(query_text, std::forward_as_tuple(params...), affected); |
| | | } |
| | | |
| | | template <typename Params> |
| | | uint64_t insert(const char *query_text, size_t text_length, const Params ¶ms) |
| | | { |
| | | uint64_t id = 0; |
| | | T *pThis = static_cast<T *>(this); |
| | | Command command = pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | if (command.affetced_rows() > 0) |
| | | id = command.insert_id(); |
| | | return id; |
| | | } |
| | | |
| | | template <typename Params> |
| | | uint64_t insert(const char *query_text, const Params ¶ms) |
| | | { |
| | | return insert(query_text, strlen(query_text), params); |
| | | } |
| | | |
| | | template <typename Params> |
| | | uint64_t insert(const std::string &query_text, const Params ¶ms) |
| | | { |
| | | return insert(query_text.data(), query_text.length(), params); |
| | | } |
| | | |
| | | template <typename... Params> |
| | | uint64_t insert_direct(const char *query_text, size_t text_length, const Params &...params) |
| | | { |
| | | return insert(query_text, text_length, std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template <typename... Params> |
| | | uint64_t insert_direct(const char *query_text, const Params &...params) |
| | | { |
| | | return insert(query_text, strlen(query_text), std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template <typename... Params> |
| | | uint64_t insert_direct(const std::string &query_text, const Params &...params) |
| | | { |
| | | return insert(query_text.data(), query_text.length(), std::forward_as_tuple(params...)); |
| | | } |
| | | |
| | | template <typename Record, typename Params> |
| | | query_result<Command, Record> result(const char *query_text, size_t text_length, const Params ¶ms) |
| | | { |
| | | T *pThis = static_cast<T *>(this); |
| | | Command command = pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | return query_result<Command, Record>(std::move(command)); |
| | | } |
| | | template <typename Record, typename Params> |
| | | query_result<Command, Record> result(const char *query_text, const Params ¶ms) |
| | | { |
| | | return result<Record, Params>(query_text, strlen(query_text), params); |
| | | } |
| | | template <typename Record, typename Params> |
| | | query_result<Command, Record> result(const std::string &query_text, const Params ¶ms) |
| | | { |
| | | return result<Record, Params>(query_text.data(), query_text.length(), params); |
| | | } |
| | | template <typename Record> |
| | | query_result<Command, Record> result(const char *query_text, size_t text_length) |
| | | { |
| | | return result<Record>(query_text, text_length, std::make_tuple()); |
| | | } |
| | | template <typename Record> |
| | | query_result<Command, Record> result(const char *query_text) |
| | | { |
| | | return result<Record>(query_text, strlen(query_text), std::make_tuple()); |
| | | } |
| | | template <typename Record> |
| | | query_result<Command, Record> result(const std::string &query_text) |
| | | { |
| | | return result<Record>(query_text.data(), query_text.length(), std::make_tuple()); |
| | | } |
| | | |
| | | template <typename Params, typename Values, typename ValueProc> |
| | | base_database &query_explicit(const char *query_text, size_t text_length, const Params ¶ms, Values &&values, ValueProc &&proc) |
| | | { |
| | | T *pThis = static_cast<T *>(this); |
| | | Command command = pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | while (command.fetch(std::forward<Values>(values))) |
| | | { |
| | | if (!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) |
| | | break; |
| | | } |
| | | command.close(); |
| | | return *this; |
| | | } |
| | | |
| | | template <typename Params, typename Values, typename ValueProc> |
| | | base_database &query_explicit(const char *query_text, const Params ¶ms, Values &&values, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Params, typename Values, typename ValueProc> |
| | | base_database &query_explicit(const std::string &query_text, const Params ¶ms, Values &&values, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Values, typename ValueProc> |
| | | base_database &query_explicit(const char *query_text, size_t text_length, Values &&values, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Values, typename ValueProc> |
| | | base_database &query_explicit(const char *query_text, Values &&values, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Values, typename ValueProc> |
| | | base_database &query_explicit(const std::string &query_text, Values &&values, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc)); |
| | | } |
| | | |
| | | template <typename Params, typename ValueProc> |
| | | base_database &query(const char *query_text, size_t text_length, const Params ¶ms, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Params, typename ValueProc> |
| | | base_database &query(const char *query_text, const Params ¶ms, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename Params, typename ValueProc> |
| | | base_database &query(const std::string &query_text, const Params ¶ms, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename ValueProc> |
| | | base_database &query(const char *query_text, size_t text_length, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename ValueProc> |
| | | base_database &query(const char *query_text, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | template <typename ValueProc> |
| | | base_database &query(const std::string &query_text, ValueProc &&proc) |
| | | { |
| | | return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc)); |
| | | } |
| | | |
| | | template <typename Params, typename... ValueProc> |
| | | base_database &query_multi_with_params(const char *query_text, size_t text_length, const Params ¶ms, ValueProc &&...proc) |
| | | { |
| | | T *pThis = static_cast<T *>(this); |
| | | Command command = pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | detail::fetch_command(command, std::forward<ValueProc>(proc)...); |
| | | command.close(); |
| | | return *this; |
| | | } |
| | | template <typename Params, typename... ValueProc> |
| | | base_database &query_multi_with_params(const char *query_text, const Params ¶ms, ValueProc &&...proc) |
| | | { |
| | | return query_multi_with_params(query_text, strlen(query_text), params, std::forward<ValueProc>(proc)...); |
| | | } |
| | | template <typename Params, typename... ValueProc> |
| | | base_database &query_multi_with_params(const std::string &query_text, const Params ¶ms, ValueProc &&...proc) |
| | | { |
| | | return query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<ValueProc>(proc)...); |
| | | } |
| | | template <typename... ValueProc> |
| | | base_database &query_multi(const char *query_text, size_t text_length, ValueProc &&...proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | template <typename... ValueProc> |
| | | base_database &query_multi(const char *query_text, ValueProc &&...proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | template <typename... ValueProc> |
| | | base_database &query_multi(const std::string &query_text, ValueProc &&...proc) |
| | | { |
| | | return query_multi_with_params<std::tuple<>, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<ValueProc>(proc)...); |
| | | } |
| | | |
| | | template <typename Params, typename Values> |
| | | bool query_first(const char *query_text, size_t text_length, const Params ¶ms, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, text_length, params, std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename Params, typename Values> |
| | | bool query_first(const char *query_text, const Params ¶ms, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename Params, typename Values> |
| | | bool query_first(const std::string &query_text, const Params ¶ms, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, params, values, std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename Values> |
| | | bool query_first(const char *query_text, size_t text_length, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename Values> |
| | | bool query_first(const char *query_text, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename Values> |
| | | bool query_first(const std::string &query_text, Values &&values) |
| | | { |
| | | first_record fetcher; |
| | | return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher)); |
| | | return fetcher; |
| | | } |
| | | |
| | | template <typename... Values> |
| | | bool query_first_direct(const char *query_text, size_t text_length, Values &...values) |
| | | { |
| | | return query_first(query_text, text_length, std::tie(values...)); |
| | | } |
| | | |
| | | template <typename... Values> |
| | | bool query_first_direct(const char *query_text, Values &...values) |
| | | { |
| | | return query_first(query_text, std::tie(values...)); |
| | | } |
| | | |
| | | template <typename... Values> |
| | | bool query_first_direct(const std::string &query_text, Values &...values) |
| | | { |
| | | return query_first(query_text, std::tie(values...)); |
| | | } |
| | | |
| | | protected: |
| | | struct nothing |
| | | { |
| | | template <typename... Values> |
| | | bool operator()(Values &&...) const { return true; } |
| | | }; |
| | | struct first_record |
| | | { |
| | | first_record() : _found(false) {} |
| | | template <typename... Values> |
| | | bool operator()(Values &&...) |
| | | { |
| | | _found = true; |
| | | return false; |
| | | } |
| | | operator bool() const { return _found; } |
| | | |
| | | private: |
| | | bool _found; |
| | | }; |
| | | }; |
| | | |
| | | class blobbuf : public std::streambuf |
| | | { |
| | | public: |
| | | blobbuf() = default; |
| | | blobbuf(const blobbuf &) = default; |
| | | blobbuf &operator=(const blobbuf &) = default; |
| | | virtual ~blobbuf() |
| | | { |
| | | overflow(); |
| | | } |
| | | |
| | | void swap(blobbuf &other) |
| | | { |
| | | std::swap(m_buf, other.m_buf); |
| | | std::swap(m_size, other.m_size); |
| | | std::swap(m_pos, other.m_pos); |
| | | |
| | | std::streambuf::swap(other); |
| | | } |
| | | |
| | | protected: |
| | | virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, |
| | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
| | | { |
| | | if (which & std::ios_base::in) |
| | | { |
| | | pos_type pos = 0; |
| | | pos = seekoff(m_pos, off, dir); |
| | | return seekpos(pos, which); |
| | | } |
| | | return std::streambuf::seekoff(off, dir, which); |
| | | } |
| | | |
| | | virtual pos_type seekpos(pos_type pos, |
| | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
| | | { |
| | | if (pos >= m_size) |
| | | return pos_type(off_type(-1)); |
| | | |
| | | if (which & std::ios_base::out) |
| | | { |
| | | if (pos < m_pos || pos >= m_pos + off_type(egptr() - pbase())) |
| | | { |
| | | overflow(); |
| | | m_pos = pos; |
| | | setp(m_buf.data(), m_buf.data() + m_buf.size()); |
| | | } |
| | | else |
| | | { |
| | | pbump(off_type(pos - pabs())); |
| | | } |
| | | } |
| | | else if (which & std::ios_base::in) |
| | | { |
| | | if (pos < m_pos || pos >= m_pos + off_type(epptr() - eback())) |
| | | { |
| | | m_pos = pos; |
| | | setg(m_buf.data(), m_buf.data(), m_buf.data()); |
| | | } |
| | | else |
| | | { |
| | | gbump(off_type(pos - gabs())); |
| | | } |
| | | } |
| | | return pos; |
| | | } |
| | | |
| | | virtual std::streamsize showmanyc() override |
| | | { |
| | | return m_size - pabs(); |
| | | } |
| | | |
| | | virtual int_type underflow() override |
| | | { |
| | | if (pptr() > pbase()) |
| | | overflow(); |
| | | |
| | | off_type count = egptr() - eback(); |
| | | pos_type next_pos = 0; |
| | | if (count == 0 && eback() == m_buf.data()) |
| | | { |
| | | setg(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size()); |
| | | count = m_buf.size(); |
| | | } |
| | | else |
| | | { |
| | | next_pos = m_pos + pos_type(count); |
| | | } |
| | | if (next_pos >= m_size) |
| | | return traits_type::eof(); |
| | | |
| | | count = std::min(count, m_size - next_pos); |
| | | m_pos = next_pos; |
| | | if (read_blob(m_buf.data(), count, m_pos)) |
| | | { |
| | | setg(eback(), eback(), eback() + count); |
| | | return traits_type::to_int_type(*gptr()); |
| | | } |
| | | else |
| | | { |
| | | return traits_type::eof(); |
| | | } |
| | | } |
| | | else if (which&std::ios_base::in) |
| | | |
| | | virtual int_type overflow(int_type ch = traits_type::eof()) override |
| | | { |
| | | if (pos < m_pos || pos >= m_pos + off_type(epptr() - eback())) |
| | | if (pptr() != pbase()) |
| | | { |
| | | m_pos = pos; |
| | | size_t count = pptr() - pbase(); |
| | | write_blob(pbase(), count); |
| | | |
| | | // auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, epptr() - pbase()); |
| | | // if (intersection.first != intersection.second) |
| | | //{ |
| | | // commit(intersection.first, intersection.second); |
| | | // } |
| | | |
| | | m_pos += count; |
| | | setp(pbase(), epptr()); |
| | | } |
| | | if (!traits_type::eq_int_type(ch, traits_type::eof())) |
| | | { |
| | | char_type c = traits_type::to_char_type(ch); |
| | | if (m_pos >= m_size) |
| | | return traits_type::eof(); |
| | | write_blob(&c, 1); |
| | | |
| | | // auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, 1); |
| | | // if (intersection.first != intersection.second) |
| | | //{ |
| | | // eback()[intersection.first - m_pos] = c; |
| | | // } |
| | | m_pos += 1; |
| | | } |
| | | return ch; |
| | | } |
| | | |
| | | virtual int_type pbackfail(int_type c = traits_type::eof()) override |
| | | { |
| | | if (gptr() == 0 || gptr() <= eback() || (!traits_type::eq_int_type(traits_type::eof(), c) && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | { |
| | | return (traits_type::eof()); // can't put back, fail |
| | | } |
| | | else |
| | | { // back up one position and store put-back character |
| | | gbump(-1); |
| | | if (!traits_type::eq_int_type(traits_type::eof(), c)) |
| | | *gptr() = traits_type::to_char_type(c); |
| | | return (traits_type::not_eof(c)); |
| | | } |
| | | } |
| | | |
| | | private: |
| | | off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir) |
| | | { |
| | | off_type result = 0; |
| | | switch (dir) |
| | | { |
| | | case std::ios_base::beg: |
| | | result = off; |
| | | break; |
| | | case std::ios_base::cur: |
| | | result = position + off; |
| | | break; |
| | | case std::ios_base::end: |
| | | result = m_size - off; |
| | | } |
| | | if (result > m_size) |
| | | result = m_size; |
| | | return result; |
| | | } |
| | | |
| | | pos_type gabs() const // absolute offset of input pointer in blob field |
| | | { |
| | | return m_pos + off_type(gptr() - eback()); |
| | | } |
| | | |
| | | pos_type pabs() const // absolute offset of output pointer in blob field |
| | | { |
| | | return m_pos + off_type(pptr() - pbase()); |
| | | } |
| | | |
| | | protected: |
| | | std::vector<char> m_buf; |
| | | pos_type m_size; |
| | | pos_type m_pos; // position in the input sequence |
| | | |
| | | virtual bool read_blob(char *buffer, off_type &count, pos_type position) = 0; |
| | | virtual void write_blob(const char *buffer, size_t count) = 0; |
| | | |
| | | void init_buffer(std::ios_base::openmode mode) |
| | | { |
| | | size_t bufsize; |
| | | if (m_size > 0) |
| | | bufsize = std::min<size_t>(blob_buffer_size, m_size); |
| | | else |
| | | bufsize = blob_buffer_size; |
| | | if (mode & std::ios_base::in) |
| | | { |
| | | m_buf.resize(bufsize); |
| | | m_pos = 0; |
| | | setg(m_buf.data(), m_buf.data(), m_buf.data()); |
| | | } |
| | | else |
| | | else if (mode & std::ios_base::out) |
| | | { |
| | | gbump(off_type(pos - gabs())); |
| | | m_buf.resize(bufsize); |
| | | m_pos = 0; |
| | | setp(m_buf.data(), m_buf.data() + bufsize); |
| | | } |
| | | } |
| | | return pos; |
| | | } |
| | | }; |
| | | |
| | | virtual std::streamsize showmanyc() override |
| | | typedef std::function<void(std::ostream &)> blob_writer; |
| | | |
| | | template <typename Database> |
| | | struct transaction |
| | | { |
| | | return m_size - pabs(); |
| | | } |
| | | transaction(Database &db) : m_db(db), m_commited(true) |
| | | { |
| | | begin(); |
| | | } |
| | | ~transaction() |
| | | { |
| | | rollback(); |
| | | } |
| | | void begin() |
| | | { |
| | | if (m_commited) |
| | | { |
| | | m_db.begin_transaction(); |
| | | m_commited = false; |
| | | } |
| | | } |
| | | void rollback() |
| | | { |
| | | if (!m_commited) |
| | | { |
| | | m_db.rollback(); |
| | | m_commited = true; |
| | | } |
| | | } |
| | | void commit() |
| | | { |
| | | if (!m_commited) |
| | | { |
| | | m_db.commit(); |
| | | m_commited = true; |
| | | } |
| | | } |
| | | |
| | | virtual int_type underflow() override |
| | | private: |
| | | bool m_commited; |
| | | Database &m_db; |
| | | }; |
| | | |
| | | template <typename Command, typename Params, typename... Others> |
| | | inline void execute(Command &command, uint64_t *affected, const Params ¶ms) |
| | | { |
| | | if (pptr() > pbase()) |
| | | overflow(); |
| | | |
| | | off_type count = egptr() - eback(); |
| | | pos_type next_pos = 0; |
| | | if (count == 0 && eback() == m_buf.data()) |
| | | { |
| | | setg(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size()); |
| | | count = m_buf.size(); |
| | | } |
| | | else |
| | | { |
| | | next_pos = m_pos + pos_type(count); |
| | | } |
| | | if (next_pos >= m_size) |
| | | return traits_type::eof(); |
| | | |
| | | count = std::min(count, m_size - next_pos); |
| | | m_pos = next_pos; |
| | | if (read_blob(m_buf.data(), count, m_pos)) |
| | | { |
| | | setg(eback(), eback(), eback() + count); |
| | | return traits_type::to_int_type(*gptr()); |
| | | } |
| | | else |
| | | { |
| | | return traits_type::eof(); |
| | | } |
| | | command.reset(); |
| | | command.execute(params); |
| | | if (affected) |
| | | *affected += command.affetced_rows(); |
| | | } |
| | | |
| | | virtual int_type overflow(int_type ch = traits_type::eof()) override |
| | | template <typename Command, typename Params, typename... Others> |
| | | inline void execute(Command &command, uint64_t *affected, const Params ¶ms, const Others &...others) |
| | | { |
| | | if (pptr() != pbase()) |
| | | { |
| | | size_t count = pptr() - pbase(); |
| | | write_blob(pbase(), count); |
| | | |
| | | //auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, epptr() - pbase()); |
| | | //if (intersection.first != intersection.second) |
| | | //{ |
| | | // commit(intersection.first, intersection.second); |
| | | //} |
| | | |
| | | m_pos += count; |
| | | setp(pbase(), epptr()); |
| | | } |
| | | if (!traits_type::eq_int_type(ch, traits_type::eof())) |
| | | { |
| | | char_type c = traits_type::to_char_type(ch); |
| | | if (m_pos >= m_size) |
| | | return traits_type::eof(); |
| | | write_blob(&c, 1); |
| | | |
| | | //auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, 1); |
| | | //if (intersection.first != intersection.second) |
| | | //{ |
| | | // eback()[intersection.first - m_pos] = c; |
| | | //} |
| | | m_pos += 1; |
| | | |
| | | } |
| | | return ch; |
| | | execute(command, affected, params); |
| | | execute(command, affected, others...); |
| | | } |
| | | |
| | | virtual int_type pbackfail(int_type c = traits_type::eof()) override |
| | | { |
| | | if (gptr() == 0 |
| | | || gptr() <= eback() |
| | | || (!traits_type::eq_int_type(traits_type::eof(), c) |
| | | && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | { |
| | | return (traits_type::eof()); // can't put back, fail |
| | | } |
| | | else |
| | | { // back up one position and store put-back character |
| | | gbump(-1); |
| | | if (!traits_type::eq_int_type(traits_type::eof(), c)) |
| | | *gptr() = traits_type::to_char_type(c); |
| | | return (traits_type::not_eof(c)); |
| | | } |
| | | } |
| | | |
| | | private: |
| | | |
| | | off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir) |
| | | { |
| | | off_type result = 0; |
| | | switch (dir) |
| | | { |
| | | case std::ios_base::beg: |
| | | result = off; |
| | | break; |
| | | case std::ios_base::cur: |
| | | result = position + off; |
| | | break; |
| | | case std::ios_base::end: |
| | | result = m_size - off; |
| | | } |
| | | if (result > m_size) |
| | | result = m_size; |
| | | return result; |
| | | } |
| | | |
| | | pos_type gabs() const // absolute offset of input pointer in blob field |
| | | { |
| | | return m_pos + off_type(gptr() - eback()); |
| | | } |
| | | |
| | | pos_type pabs() const // absolute offset of output pointer in blob field |
| | | { |
| | | return m_pos + off_type(pptr() - pbase()); |
| | | } |
| | | |
| | | protected: |
| | | std::vector<char> m_buf; |
| | | pos_type m_size; |
| | | pos_type m_pos; //position in the input sequence |
| | | |
| | | virtual bool read_blob(char* buffer, off_type& count, pos_type position) = 0; |
| | | virtual void write_blob(const char* buffer, size_t count) = 0; |
| | | |
| | | void init_buffer(std::ios_base::openmode mode) |
| | | { |
| | | size_t bufsize; |
| | | if (m_size > 0) |
| | | bufsize = std::min<size_t>(blob_buffer_size, m_size); |
| | | else |
| | | bufsize = blob_buffer_size; |
| | | if (mode&std::ios_base::in) |
| | | { |
| | | m_buf.resize(bufsize); |
| | | m_pos = 0; |
| | | setg(m_buf.data(), m_buf.data(), m_buf.data()); |
| | | } |
| | | else if (mode&std::ios_base::out) |
| | | { |
| | | m_buf.resize(bufsize); |
| | | m_pos = 0; |
| | | setp(m_buf.data(), m_buf.data() + bufsize); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | typedef std::function<void(std::ostream&)> blob_writer; |
| | | |
| | | template<typename Database> |
| | | struct transaction |
| | | { |
| | | transaction(Database& db) : m_db(db), m_commited(true) |
| | | { |
| | | begin(); |
| | | } |
| | | ~transaction() |
| | | { |
| | | rollback(); |
| | | } |
| | | void begin() |
| | | { |
| | | if(m_commited) |
| | | { |
| | | m_db.begin_transaction(); |
| | | m_commited=false; |
| | | } |
| | | } |
| | | void rollback() |
| | | { |
| | | if(!m_commited) |
| | | { |
| | | m_db.rollback(); |
| | | m_commited=true; |
| | | } |
| | | } |
| | | void commit() |
| | | { |
| | | if(!m_commited) |
| | | { |
| | | m_db.commit(); |
| | | m_commited=true; |
| | | } |
| | | } |
| | | private: |
| | | bool m_commited; |
| | | Database& m_db; |
| | | }; |
| | | |
| | | template<typename Command, typename Params, typename... Others> |
| | | inline void execute(Command& command, uint64_t* affected, const Params& params) |
| | | { |
| | | command.reset(); |
| | | command.execute(params); |
| | | if(affected) *affected+=command.affetced_rows(); |
| | | } |
| | | |
| | | template<typename Command, typename Params, typename... Others> |
| | | inline void execute(Command& command, uint64_t* affected, const Params& params, const Others&... others) |
| | | { |
| | | execute(command, affected, params); |
| | | execute(command, affected, others...); |
| | | } |
| | | |
| | | } |
| | | |