允许用字段名绑定数据(会影响性能)
允许对同一个数据结构进行不同的绑定
| | |
| | | fun(value, temp); |
| | | } |
| | | |
| | | template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type> |
| | | inline void bind_field(Command& command, const char* name, T&& value) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=T(); |
| | | else |
| | | command.bind_field(index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_field(Command& command, const char* name, T& value) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=T(); |
| | | else |
| | | bind_field(command, index, std::forward<T>(value)); |
| | | } |
| | | |
| | | template<typename FieldType, typename Command, typename BindType> |
| | | inline void bind_field(Command& command, const char* name, BindType& value) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=BindType(); |
| | | else |
| | | bind_field<FieldType>(command, index, value); |
| | | } |
| | | |
| | | template<typename FieldType, typename Command, typename BindType, typename CastFun> |
| | | inline void bind_field(Command& command, const char* name, BindType& value, CastFun&& fun) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value=BindType(); |
| | | else |
| | | bind_field<FieldType>(command, index, value, fun); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, const char* name, char* value, size_t length) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value[0]='\0'; |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | template<typename Command> |
| | | inline void bind_field(Command& command, const char* name, wchar_t* value, size_t length) |
| | | { |
| | | size_t index=command.find_field(name); |
| | | if(index==-1) |
| | | value[0]='\0'; |
| | | else |
| | | command.bind_field(index, value, length); |
| | | } |
| | | |
| | | namespace detail |
| | | { |
| | | |
| | |
| | | void operator()(std::tuple<Types...>&& params) const |
| | | { |
| | | typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, 0, std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params)))); |
| | | bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params)))); |
| | | } |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | |
| | | { |
| | | inline void operator()(Command& command, T&& value) const |
| | | { |
| | | bind_field(command, 0, std::forward<typename std::remove_reference<T>::type>(value)); |
| | | bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value)); |
| | | } |
| | | }; |
| | | |
| | |
| | | { |
| | | void operator()(Command& command, std::pair<Type1, Type2>&& values) const |
| | | { |
| | | bind_field(command, 0, std::forward<Type1>(values.first)); |
| | | bind_field(command, 1, std::forward<Type2>(values.second)); |
| | | bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first)); |
| | | bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second)); |
| | | } |
| | | }; |
| | | |
| | | template<typename T, typename Tag> |
| | | struct record_with_tag : public T |
| | | { |
| | | }; |
| | | |
| | | template<typename Command, typename T> |
| | | inline void bind_record(Command& command, T&& value) |
| | | { |
| | |
| | | { |
| | | public: |
| | | error() : m_error(0) { } |
| | | error(int err, const char* errmsg) : m_error(err), m_errmsg(errmsg) { } |
| | | explicit error(int err) : m_error(err), m_errmsg(ER(err)) { } |
| | | error(unsigned int err, const char* errmsg) : m_error(err), m_errmsg(errmsg) { } |
| | | explicit error(unsigned int err) : m_error(err), m_errmsg(ER(err)) { } |
| | | explicit error(statement& stmt); |
| | | explicit error(database& db); |
| | | error(const error& src) = default; |
| | |
| | | int code() const throw() { return m_error; } |
| | | virtual const char* what() const throw() override { return m_errmsg.data(); } |
| | | private: |
| | | int m_error; |
| | | unsigned int m_error; |
| | | std::string m_errmsg; |
| | | }; |
| | | |
| | |
| | | return m_binderAddins[index].m_isNull!=0; |
| | | } |
| | | |
| | | size_t find_field(const char* name) const |
| | | { |
| | | if(m_result) |
| | | { |
| | | for(size_t i=0; i!=m_result->field_count; i++) |
| | | { |
| | | if(strncmp(m_result->fields[i].name, name, m_result->fields[i].name_length)==0) |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | void close() |
| | | { |
| | | if(m_result) |
| | |
| | | return &m_binders[index]; |
| | | } |
| | | |
| | | unsigned int error() |
| | | unsigned int error() const |
| | | { |
| | | return mysql_stmt_errno(m_stmt); |
| | | } |
| | | const char* errmsg() |
| | | const char* errmsg() const |
| | | { |
| | | return mysql_stmt_error(m_stmt); |
| | | } |
| | |
| | | class database final : public qtl::base_database<database, statement> |
| | | { |
| | | public: |
| | | typedef error exception_type; |
| | | typedef mysql::error exception_type; |
| | | |
| | | database() |
| | | { |
| | |
| | | return m_mysql->db; |
| | | } |
| | | |
| | | unsigned int error() |
| | | unsigned int error() const |
| | | { |
| | | return mysql_errno(m_mysql); |
| | | } |
| | | const char* errmsg() |
| | | const char* errmsg() const |
| | | { |
| | | return mysql_error(m_mysql); |
| | | } |
| | |
| | | return count; |
| | | } |
| | | |
| | | size_t find_field(const char* name) const |
| | | { |
| | | SQLSMALLINT count=0; |
| | | verify_error(SQLNumResultCols(m_handle, &count)); |
| | | for(SQLSMALLINT i=0; i!=count; i++) |
| | | { |
| | | SQLCHAR field_name[256]={0}; |
| | | SQLSMALLINT name_length=0; |
| | | SQLSMALLINT data_type; |
| | | SQLULEN column_size; |
| | | SQLSMALLINT digits; |
| | | SQLSMALLINT nullable; |
| | | verify_error(SQLDescribeCol(m_handle, i, field_name, sizeof(field_name), &name_length, |
| | | &data_type, &column_size, &digits, &nullable)); |
| | | if(strncmp((char*)field_name, name, name_length)==0) |
| | | return i; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | /* |
| | | ODBC do not support this function, but you can use query to instead it: |
| | | For MS SQL Server: SELECT @@IDENTITY; |
| | |
| | | class database : public object<SQL_HANDLE_DBC>, public qtl::base_database<database, statement> |
| | | { |
| | | public: |
| | | typedef odbc::error exception_type; |
| | | |
| | | explicit database(environment& env) : object(env.handle()), m_opened(false) |
| | | { |
| | | } |
| | |
| | | bind_field(index, value.data(), value.size()); |
| | | } |
| | | |
| | | size_t find_field(const char* name) const |
| | | { |
| | | size_t count=get_column_count(); |
| | | for(size_t i=0; i!=count; i++) |
| | | { |
| | | if(strcmp(get_column_name(i), name)==0) |
| | | return i; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | bool fetch() |
| | | { |
| | | m_fetch_result=sqlite3_step(m_stmt); |
| | |
| | | class database final : public qtl::base_database<database, statement> |
| | | { |
| | | public: |
| | | typedef sqlite::error exception_type; |
| | | |
| | | database() : m_db(NULL) { } |
| | | ~database() { close(); } |
| | | database(const database&) = delete; |