#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 "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; template inline void bind(Binder& binder, const T& v) { binder.bind(const_cast(v)); } template inline void bind(Binder& binder, T&& v) { binder.bind(v); } template inline void bind(Binder& binder, const char* str) { binder.bind((char*)str, (unsigned long)strlen(str)); } template inline void bind(Binder& binder, const std::string& str) { binder.bind((char*)str.data(), (unsigned long)str.size()); } template inline void bind(Binder& binder, std::string&& str) { binder.bind((char*)str.data(), (unsigned long)str.size()); } 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 data_type&() { return data; } }; template inline void bind_param(Command& command, size_t index, const T& param) { command.bind_param(index, param); } template inline void bind_field(Command& command, size_t index, T&& value) { command.bind_field(index, std::forward::type>(value)); } 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, char* value, size_t length) { command.bind_field(index, value, length); } namespace detail { template auto apply(F&& f, T&& v) -> decltype(f(v)) { return f(v); } template auto apply(F&& f, std::tuple&& v) -> decltype(apply_tuple(f, v)) { return apply_tuple(f, v); } template struct bind_helper { public: explicit bind_helper(Command& command) : m_command(command) { } void operator()(const std::tuple& params) const { m_command.bind_param(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 { m_command.bind_param(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 { } }; } 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(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 inline void bind_record(Command& command, T& value) { bind_record(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::make_tuple(params...), affected); } template void execute_direct(const char* query_text, uint64_t* affected, const Params&... params) { execute(query_text, std::make_tuple(params...), affected); } template void execute_direct(const std::string& query_text, uint64_t* affected, const Params&... params) { execute(query_text, std::make_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 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(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(proc, std::forward(values))) break; } command.close(); } template void query(const char* query_text, const Params& params, Values&& values, ValueProc proc) { query(query_text, strlen(query_text), params, std::forward(values), proc); } template void query(const std::string& query_text, const Params& params, Values&& values, ValueProc proc) { query(query_text.data(), query_text.size(), params, std::forward(values), proc); } template void query(const char* query_text, size_t text_length, Values&& values, ValueProc proc) { query(query_text, text_length, std::make_tuple(), std::forward(values), proc); } template void query(const char* query_text, Values&& values, ValueProc proc) { query(query_text, strlen(query_text), std::make_tuple(), std::forward(values), proc); } template void query(const std::string& query_text, Values&& values, ValueProc proc) { query(query_text, std::make_tuple(), std::forward(values), proc); } template void query_first(const char* query_text, size_t text_length, const Params& params, Values&& values) { query(query_text, text_length, params, std::forward(values), first_record()); } template void query_first(const char* query_text, const Params& params, Values&& values) { query(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(query_text, params, values, first_record()); } template void query_first(const char* query_text, size_t text_length, Values&& values) { query(query_text, text_length, std::make_tuple(), std::forward(values), first_record()); } template void query_first(const char* query_text, Values&& values) { query(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(query_text, std::make_tuple(), std::forward(values), first_record()); } 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_