#ifndef _MYDTL_DATABASE_H_ #define _MYDTL_DATABASE_H_ #if defined(_MSC_VER) #if _MSC_VER<1800 #error MYDTL need C++11 compiler #endif //MSC #elif __cplusplus<201103L #error MYDTL need C++11 compiler #endif //C++11 #include #include #include #include #include #include #include #include #include "apply_tuple.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 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)) { } 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); } // 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 inline void bind_field(Command& command, size_t index, BindType& value) { FieldType temp=FieldType(); bind_field(command, index, temp); value=static_cast(temp); } template inline void bind_field(Command& command, size_t index, BindType& value, CastFun&& fun) { FieldType temp=FieldType(); bind_field(command, index, temp); fun(value, temp); } namespace detail { template struct apply_impl { private: typedef typename std::result_of::type raw_result_type; 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; typedef typename std::result_of::type raw_result_type; template struct impl {}; template struct impl { typedef bool result_type; result_type operator()(F&& f, arg_type&& v) { 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 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, 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(!detail::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 { inline void operator()(Command& command, const T& param) const { qtl::bind_param(command, 0, param); } }; template struct params_binder> { void operator()(Command& command, const std::tuple& params) const { (detail::bind_helper>::value, Types...>(command))(params); } }; template struct params_binder> { 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, 0, std::forward::type>(value)); } }; 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, 0, std::forward(values.first)); bind_field(command, 1, std::forward(values.second)); } }; template inline void bind_record(Command& command, T&& value) { record_binder binder; binder(command, std::forward(value)); } template class query_iterator final : public std::iterator { public: 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.unique()) { 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 void 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(); } template void execute(const char* query_text, const Params& params, uint64_t* affected=NULL) { return execute(query_text, strlen(query_text), params, affected); } template void execute(const std::string& query_text, const Params& params, uint64_t* affected=NULL) { return execute(query_text.data(), query_text.length(), params, affected); } template void execute_direct(const char* query_text, size_t text_length, uint64_t* affected, const Params&... params) { execute(query_text, text_length, std::forward_as_tuple(params...), affected); } template void execute_direct(const char* query_text, uint64_t* affected, const Params&... params) { execute(query_text, std::forward_as_tuple(params...), affected); } template void execute_direct(const std::string& query_text, uint64_t* affected, const Params&... params) { 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 void 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(); } template void query_explicit(const char* query_text, const Params& params, Values&& values, ValueProc&& proc) { query_explicit(query_text, strlen(query_text), params, std::forward(values), std::forward(proc)); } template void query_explicit(const std::string& query_text, const Params& params, Values&& values, ValueProc&& proc) { query_explicit(query_text.data(), query_text.size(), params, std::forward(values), std::forward(proc)); } template void query_explicit(const char* query_text, size_t text_length, Values&& values, ValueProc&& proc) { query_explicit(query_text, text_length, std::make_tuple(), std::forward(values), std::forward(proc)); } template void query_explicit(const char* query_text, Values&& values, ValueProc&& proc) { query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward(values), std::forward(proc)); } template void query_explicit(const std::string& query_text, Values&& values, ValueProc&& proc) { query_explicit(query_text, std::make_tuple(), std::forward(values), std::forward(proc)); } template void query(const char* query_text, size_t text_length, const Params& params, ValueProc&& proc) { query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward(proc)); } template void query(const char* query_text, const Params& params, ValueProc&& proc) { query_explicit(query_text, params, detail::make_values(proc), std::forward(proc)); } template void query(const std::string& query_text, const Params& params, ValueProc&& proc) { query_explicit(query_text, params, detail::make_values(proc), std::forward(proc)); } template void query(const char* query_text, size_t text_length, ValueProc&& proc) { query_explicit(query_text, text_length, detail::make_values(proc), std::forward(proc)); } template void query(const char* query_text, ValueProc&& proc) { query_explicit(query_text, detail::make_values(proc), std::forward(proc)); } template void query(const std::string& query_text, ValueProc&& proc) { query_explicit(query_text, detail::make_values(proc), std::forward(proc)); } template void 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(); } template void query_multi_with_params(const char* query_text, const Params& params, ValueProc&&... proc) { query_multi_with_params(query_text, strlen(query_text), params, std::forward(proc)...); } template void query_multi_with_params(const std::string& query_text, const Params& params, ValueProc&&... proc) { query_multi_with_params(query_text.data(), query_text.size(), params, std::forward(proc)...); } template void query_multi(const char* query_text, size_t text_length, ValueProc&&... proc) { query_multi_with_params>(query_text, text_length, std::make_tuple(), std::forward(proc)...); } template void query_multi(const char* query_text, ValueProc&&... proc) { query_multi_with_params>(query_text, strlen(query_text), std::make_tuple(), std::forward(proc)...); } template void query_multi(const std::string& query_text, ValueProc&&... proc) { query_multi_with_params>(query_text.data(), query_text.size(), std::make_tuple(), std::forward(proc)...); } template void query_first(const char* query_text, size_t text_length, const Params& params, Values&& values) { query_explicit(query_text, text_length, params, std::forward(values), first_record()); } template void query_first(const char* query_text, const Params& params, Values&& values) { query_explicit(query_text, strlen(query_text), params, std::forward(values), first_record()); } template void query_first(const std::string& query_text, const Params& params, Values&& values) { query_explicit(query_text, params, values, first_record()); } template void query_first(const char* query_text, size_t text_length, Values&& values) { query_explicit(query_text, text_length, std::make_tuple(), std::forward(values), first_record()); } template void query_first(const char* query_text, Values&& values) { query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward(values), first_record()); } template void query_first(const std::string& query_text, Values&& values) { query_explicit(query_text, std::make_tuple(), std::forward(values), first_record()); } template void query_first_direct(const char* query_text, size_t text_length, Values&... values) { query_first(query_text, text_length, std::tie(values...)); } template void query_first_direct(const char* query_text, Values&... values) { query_first(query_text, std::tie(values...)); } template void query_first_direct(const std::string& query_text, Values&... values) { query_first(query_text, std::tie(values...)); } protected: struct nothing { template bool operator()(Values&&...) const { return true; } }; struct first_record { template bool operator()(Values&&...) const { return false; } }; }; 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 //_MYDTL_DATABASE_H_