#ifndef _QTL_COMMON_H_ #define _QTL_COMMON_H_ #if __cplusplus < 201103L && _MSC_VER < 1800 #error QTL need C++11 compiler #endif // C++11 #if _MSC_VER >= 1800 && _MSC_VER < 1900 #define NOEXCEPT throw() #else #define NOEXCEPT noexcept #endif // NOEXCEPT #include #include #include #include #include #include #include #include #include #include "apply_tuple.h" #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) #define _QTL_ENABLE_CPP17 #include #include #endif // C++17 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 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 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(value)) {} bind_string_helper(const bind_string_helper &src) : m_value(std::forward(src.m_value)) { } bind_string_helper(bind_string_helper &&src) : m_value(std::forward(src.m_value)) { } bind_string_helper &operator=(const bind_string_helper &src) { if (this != &src) { m_value = std::forward(src.m_value); } return *this; } bind_string_helper &operator=(bind_string_helper &&src) { if (this != &src) { m_value = std::forward(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 inline bind_string_helper::type> bind_string(StringT &&value) { typedef typename std::decay::type string_type; return bind_string_helper(std::forward(value)); } template inline void bind_param(Command &command, size_t index, const std::string ¶m) { command.bind_param(index, param.data(), param.size()); } template inline void bind_param(Command &command, size_t index, std::istream ¶m) { command.bind_param(index, param); } template inline void bind_param(Command &command, size_t index, const T ¶m) { command.bind_param(index, param); } #ifdef _QTL_ENABLE_CPP17 template inline void bind_param(Command &command, size_t index, const std::optional ¶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 template inline void bind_field(Command &command, size_t index, char (&value)[N]) { command.bind_field(index, value, N); } template inline void bind_field(Command &command, size_t index, wchar_t (&value)[N]) { command.bind_field(index, value, N); } template inline void bind_field(Command &command, size_t index, char *value, size_t length) { command.bind_field(index, value, length); } template inline void bind_field(Command &command, size_t index, wchar_t *value, size_t length) { command.bind_field(index, value, length); } template inline void bind_field(Command &command, size_t index, std::string &&value) { command.bind_field(index, bind_string(std::forward(value))); } template inline void bind_field(Command &command, size_t index, std::wstring &&value) { command.bind_field(index, bind_string(std::forward(value))); } template inline void bind_field(Command &command, size_t index, std::vector &&value) { command.bind_field(index, bind_string(std::forward>(value))); } template inline void bind_field(Command &command, size_t index, std::vector &&value) { command.bind_field(index, bind_string(std::forward>(value))); } template ::value>::type> inline void bind_field(Command &command, size_t index, T &&value) { command.bind_field(index, std::forward(value)); } template inline void bind_field(Command &command, size_t index, T &value) { bind_field(command, index, std::forward(value)); } template ::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 command.bind_field(index, std::forward(value)); } template 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(value)); } template 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 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 inline void bind_field(Command &command, const char *name, std::reference_wrapper &&value) { return bind_field(command, value.get()); } #ifdef _QTL_ENABLE_CPP17 template inline void bind_field(Command &command, size_t index, std::optional &value) { value.emplace(); command.bind_field(index, std::forward(value)); } template inline void bind_field(Command &command, const char *name, std::optional &value) { size_t index = command.find_field(name); if (index == -1) value.reset(); else bind_field(command, index, value); } #endif // C++17 template inline size_t bind_fields(Command &command, size_t index, T &&value) { bind_field(command, index, std::forward(value)); return index + 1; } template inline size_t bind_fields(Command &command, size_t start, T &&value, Other &&...other) { bind_field(command, start, std::forward(value)); return bind_fields(command, start + 1, std::forward(other)...); } template inline size_t bind_fields(Command &command, Fields &&...fields) { return bind_fields(command, (size_t)0, std::forward(fields)...); } namespace detail { template struct apply_impl { private: #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L typedef typename std::invoke_result::type raw_result_type; #else typedef typename std::result_of::type raw_result_type; #endif template struct impl { }; template struct impl { typedef bool result_type; result_type operator()(F &&f, T &&v) { f(std::forward(v)); return true; } }; template struct impl { typedef Ret result_type; result_type operator()(F &&f, T &&v) { return f(std::forward(v)); } }; public: typedef typename impl::value>::result_type result_type; result_type operator()(F &&f, T &&v) { return impl::value>()(std::forward(f), std::forward(v)); } }; template struct apply_impl> { private: typedef typename std::remove_reference::type fun_type; typedef std::tuple arg_type; #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L typedef typename std::invoke_result::type raw_result_type; #else typedef typename std::result_of::type raw_result_type; #endif template struct impl { }; template struct impl { typedef bool result_type; result_type operator()(F &&f, arg_type &&v) { qtl::detail::apply_tuple(std::forward(f), std::forward(v)); return true; } }; template struct impl { typedef Ret result_type; result_type operator()(F &&f, arg_type &&v) { return qtl::detail::apply_tuple(std::forward(f), std::forward(v)); } }; public: typedef typename impl::value>::result_type result_type; result_type operator()(F &&f, arg_type &&v) { return impl::value>()(std::forward(f), std::forward(v)); } }; template struct apply_impl { private: typedef R (Type::*fun_type)(); typedef R raw_result_type; template struct impl { }; template struct impl { typedef bool result_type; result_type operator()(fun_type f, Type &&v) { (v.*f)(); return true; } }; template struct impl { typedef Ret result_type; result_type operator()(fun_type f, Type &&v) { return (v.*f)(); } }; public: typedef typename impl::value>::result_type result_type; result_type operator()(R (Type::*f)(), Type &&v) { return impl::value>()(f, std::forward(v)); } }; template struct apply_impl { private: typedef R (Type::*fun_type)() const; typedef R raw_result_type; template struct impl { }; template struct impl { typedef bool result_type; result_type operator()(fun_type f, Type &&v) { (v.*f)(); return true; } }; template struct impl { typedef Ret result_type; result_type operator()(fun_type f, Type &&v) { return (v.*f)(); } }; public: typedef typename impl::value>::result_type result_type; result_type operator()(fun_type f, Type &&v) { return impl::value>()(f, std::forward(v)); } }; template typename apply_impl::result_type apply(F &&f, T &&v) { return apply_impl()(std::forward(f), std::forward(v)); } template struct bind_helper { public: explicit bind_helper(Command &command) : m_command(command) {} void operator()(const std::tuple ¶ms) const { bind_param(m_command, N - 1, std::get(params)); (bind_helper(m_command))(params); } void operator()(std::tuple &¶ms) const { typedef typename std::remove_reference::type>::type param_type; bind_field(m_command, N - 1, std::forward(std::get(std::forward(params)))); (bind_helper(m_command))(std::forward(params)); } private: typedef std::tuple tuple_type; Command &m_command; }; template struct bind_helper { public: explicit bind_helper(Command &command) : m_command(command) {} void operator()(const std::tuple ¶ms) const { bind_param(m_command, 0, std::get<0>(params)); } void operator()(std::tuple &¶ms) const { typedef typename std::remove_reference::type>::type param_type; bind_field(m_command, static_cast(0), std::forward(std::get<0>(std::forward(params)))); } private: typedef std::tuple tuple_type; Command &m_command; }; template struct bind_helper { public: explicit bind_helper(Command &command) {} void operator()(const std::tuple ¶ms) const { } void operator()(std::tuple &¶ms) const { } }; #define QTL_ARGS_TUPLE(Arg, Others) \ typename std::tuple::type, typename std::decay::type...> template inline typename std::decay::type make_values(Ret (*)(Arg)) { return typename std::decay::type(); }; template inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) { return QTL_ARGS_TUPLE(Arg, Others)(); }; template inline Type make_values(Ret (Type::*)()) { return Type(); }; template inline Type make_values(Ret (Type::*)() const) { return Type(); }; template inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args) { return QTL_ARGS_TUPLE(Type, Args)(); }; template inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args) { return QTL_ARGS_TUPLE(Type, Args)(); }; template inline typename std::decay::type make_values_noclass(Ret (Type::*)(Arg)) { return typename std::decay::type(); }; template inline typename std::decay::type make_values_noclass(Ret (Type::*)(Arg) const) { return typename std::decay::type(); }; template inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others) { return QTL_ARGS_TUPLE(Arg, Others)(); }; template inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others) { return QTL_ARGS_TUPLE(Arg, Others)(); }; template ::value>::type> inline auto make_values(const Functor &) -> decltype(make_values_noclass(&Functor::operator())) { return make_values_noclass(&Functor::operator()); } template inline void fetch_command(Command &command, ValueProc &&proc) { auto values = make_values(proc); typedef decltype(values) values_type; while (command.fetch(std::forward(values))) { if (!apply(std::forward(proc), std::forward(values))) break; } } template inline void fetch_command(Command &command, ValueProc &&proc, OtherProc &&...other) { fetch_command(command, std::forward(proc)); if (command.next_result()) { fetch_command(command, std::forward(other)...); } } } template struct params_binder { enum { size = 1 }; inline void operator()(Command &command, const T ¶m) const { qtl::bind_param(command, 0, param); } }; template struct params_binder> { enum { size = sizeof...(Types) }; void operator()(Command &command, const std::tuple ¶ms) const { (detail::bind_helper>::value, Types...>(command))(params); } }; template struct params_binder> { enum { size = 2 }; void operator()(Command &command, std::pair &&values) const { qtl::bind_param(command, 0, std::forward(values.first)); qtl::bind_param(command, 1, std::forward(values.second)); } }; template inline void bind_params(Command &command, const T ¶m) { params_binder binder; binder(command, param); } template struct record_binder { inline void operator()(Command &command, T &&value) const { bind_field(command, static_cast(0), std::forward::type>(value)); } }; template struct record_binder> { inline void operator()(Command &command, std::reference_wrapper &&value) const { bind_field(command, static_cast(0), std::forward::type>(value.get())); } }; template struct record_binder> { void operator()(Command &command, std::tuple &&values) const { (detail::bind_helper>::value, Types...>(command))(std::forward>(values)); } }; template struct record_binder> { void operator()(Command &command, std::pair &&values) const { bind_field(command, static_cast(0), std::forward(values.first)); bind_field(command, static_cast(1), std::forward(values.second)); } }; template struct record_with_tag : public T { }; template 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(v)), m_pred(pred) { } template custom_binder_type(Pred pred, Args &&...args) : value_type(std::forward(args)...), m_pred(pred) { } template void bind(Command &command) { m_pred(std::forward(*this), command); // Pred maybe member function } private: Pred m_pred; }; template struct custom_binder_type, Pred> : public std::reference_wrapper { typedef std::reference_wrapper value_type; explicit custom_binder_type(Pred pred) : m_pred(pred) {} custom_binder_type(value_type &&v, Pred pred) : value_type(std::forward(v)), m_pred(pred) { } template custom_binder_type(Pred pred, Args &&...args) : T(std::forward(args)...), m_pred(pred) { } template void bind(Command &command) { m_pred(std::forward(*this), command); // Pred maybe member function } private: Pred m_pred; }; template inline custom_binder_type custom_bind(T &&v, Pred pred) { return custom_binder_type(std::forward(v), pred); } template struct record_binder> { void operator()(Command &command, custom_binder_type &&values) const { values.bind(command); } }; template inline void bind_record(Command &command, T &&value) { record_binder binder; binder(command, std::forward(value)); } template 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(); if (m_record.use_count() == 1) { if (!m_command.fetch(std::forward(*m_record))) m_record.reset(); } else { std::shared_ptr record = std::make_shared(); if (m_command.fetch(std::forward(*record))) m_record = record; else m_record.reset(); } return *this; } query_iterator operator++(int) { query_iterator temp = *this; m_record = std::make_shared(); if (!m_command.fetch(std::forward(*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 m_record; }; template class query_result final { public: typedef typename query_iterator::value_type value_type; typedef typename query_iterator::pointer pointer; typedef typename query_iterator::reference reference; typedef query_iterator 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 iterator begin(const Params ¶ms) { query_iterator it(m_command); ++it; return it; } iterator begin() { return begin(std::make_tuple()); } iterator end() { return query_iterator(m_command); } private: Command m_command; }; template class base_database { public: template base_database &execute(const char *query_text, size_t text_length, const Params ¶ms, uint64_t *affected = NULL) { T *pThis = static_cast(this); Command command = pThis->open_command(query_text, text_length); command.execute(params); if (affected) *affected = command.affetced_rows(); command.close(); return *this; } template base_database &execute(const char *query_text, const Params ¶ms, uint64_t *affected = NULL) { return execute(query_text, strlen(query_text), params, affected); } template 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 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 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 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 uint64_t insert(const char *query_text, size_t text_length, const Params ¶ms) { uint64_t id = 0; T *pThis = static_cast(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 uint64_t insert(const char *query_text, const Params ¶ms) { return insert(query_text, strlen(query_text), params); } template uint64_t insert(const std::string &query_text, const Params ¶ms) { return insert(query_text.data(), query_text.length(), params); } template 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 uint64_t insert_direct(const char *query_text, const Params &...params) { return insert(query_text, strlen(query_text), std::forward_as_tuple(params...)); } template 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 query_result result(const char *query_text, size_t text_length, const Params ¶ms) { T *pThis = static_cast(this); Command command = pThis->open_command(query_text, text_length); command.execute(params); return query_result(std::move(command)); } template query_result result(const char *query_text, const Params ¶ms) { return result(query_text, strlen(query_text), params); } template query_result result(const std::string &query_text, const Params ¶ms) { return result(query_text.data(), query_text.length(), params); } template query_result result(const char *query_text, size_t text_length) { return result(query_text, text_length, std::make_tuple()); } template query_result result(const char *query_text) { return result(query_text, strlen(query_text), std::make_tuple()); } template query_result result(const std::string &query_text) { return result(query_text.data(), query_text.length(), std::make_tuple()); } template base_database &query_explicit(const char *query_text, size_t text_length, const Params ¶ms, Values &&values, ValueProc &&proc) { T *pThis = static_cast(this); Command command = pThis->open_command(query_text, text_length); command.execute(params); while (command.fetch(std::forward(values))) { if (!detail::apply(std::forward(proc), std::forward(values))) break; } command.close(); return *this; } template 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), std::forward(proc)); } template 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), std::forward(proc)); } template 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), std::forward(proc)); } template 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), std::forward(proc)); } template base_database &query_explicit(const std::string &query_text, Values &&values, ValueProc &&proc) { return query_explicit(query_text, std::make_tuple(), std::forward(values), std::forward(proc)); } template 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(proc)); } template base_database &query(const char *query_text, const Params ¶ms, ValueProc &&proc) { return query_explicit(query_text, params, detail::make_values(proc), std::forward(proc)); } template 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(proc)); } template 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(proc)); } template base_database &query(const char *query_text, ValueProc &&proc) { return query_explicit(query_text, detail::make_values(proc), std::forward(proc)); } template base_database &query(const std::string &query_text, ValueProc &&proc) { return query_explicit(query_text, detail::make_values(proc), std::forward(proc)); } template base_database &query_multi_with_params(const char *query_text, size_t text_length, const Params ¶ms, ValueProc &&...proc) { T *pThis = static_cast(this); Command command = pThis->open_command(query_text, text_length); command.execute(params); detail::fetch_command(command, std::forward(proc)...); command.close(); return *this; } template 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(proc)...); } template 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(proc)...); } template base_database &query_multi(const char *query_text, size_t text_length, ValueProc &&...proc) { return query_multi_with_params, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward(proc)...); } template base_database &query_multi(const char *query_text, ValueProc &&...proc) { return query_multi_with_params, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward(proc)...); } template base_database &query_multi(const std::string &query_text, ValueProc &&...proc) { return query_multi_with_params, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward(proc)...); } template 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), std::ref(fetcher)); return fetcher; } template 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), std::ref(fetcher)); return fetcher; } template 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 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), std::ref(fetcher)); return fetcher; } template 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), std::ref(fetcher)); return fetcher; } template bool query_first(const std::string &query_text, Values &&values) { first_record fetcher; return query_explicit(query_text, std::make_tuple(), std::forward(values), std::ref(fetcher)); return fetcher; } template 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 bool query_first_direct(const char *query_text, Values &...values) { return query_first(query_text, std::tie(values...)); } template bool query_first_direct(const std::string &query_text, Values &...values) { return query_first(query_text, std::tie(values...)); } protected: struct nothing { template bool operator()(Values &&...) const { return true; } }; struct first_record { first_record() : _found(false) {} template 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(); } } virtual int_type overflow(int_type ch = traits_type::eof()) override { 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; } 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 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(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 blob_writer; template 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 inline void execute(Command &command, uint64_t *affected, const Params ¶ms) { command.reset(); command.execute(params); if (affected) *affected += command.affetced_rows(); } template inline void execute(Command &command, uint64_t *affected, const Params ¶ms, const Others &...others) { execute(command, affected, params); execute(command, affected, others...); } } #endif //_QTL_COMMON_H_