#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& param) { command.bind_param(index, param.data(), param.size()); } template inline void bind_param(Command& command, size_t index, std::istream& param) { command.bind_param(index, param); } template inline void bind_param(Command& command, size_t index, const T& param) { command.bind_param(index, param); } #ifdef _QTL_ENABLE_CPP17 template inline void bind_param(Command& command, size_t index, const std::optional& param) { 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& params) const { bind_param(m_command, N-1, std::get(params)); (bind_helper(m_command))(params); } void operator()(std::tuple&& params) 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& params) const { bind_param(m_command, 0, std::get<0>(params)); } void operator()(std::tuple&& params) 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& params) const { } void operator()(std::tuple&& params) 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& param) const { qtl::bind_param(command, 0, param); } }; template struct params_binder> { enum { size = sizeof...(Types) }; void operator()(Command& command, const std::tuple& params) 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& param) { 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& params) { 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& params, 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& params, uint64_t* affected=NULL) { return execute(query_text, strlen(query_text), params, affected); } template 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 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& params) { 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& params) { return insert(query_text, strlen(query_text), params); } template uint64_t insert(const std::string& query_text, const Params& params) { 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& params) { 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& params) { return result(query_text, strlen(query_text), params); } template query_result result(const std::string& query_text, const Params& params) { 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params, 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& params) { command.reset(); command.execute(params); if(affected) *affected+=command.affetced_rows(); } template inline void execute(Command& command, uint64_t* affected, const Params& params, const Others&... others) { execute(command, affected, params); execute(command, affected, others...); } } #endif //_QTL_COMMON_H_