From 39a95f6939417ebc5d8e716ca1664a1da1fc722c Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Thu, 09 Feb 2017 12:04:19 +0000
Subject: [PATCH] 根据回调函数参数推断绑定的数据类型。
---
test/TestSqlite.cpp | 23 +-
test/TestMysql.cpp | 25 ++-
include/qtl_common.hpp | 307 ++++++++++++++++++++++++++++++++++++++++---
include/qtl_mysql.hpp | 3
README.md | 46 ++++-
5 files changed, 343 insertions(+), 61 deletions(-)
diff --git a/README.md b/README.md
index 60e813a..e19e54c 100644
--- a/README.md
+++ b/README.md
@@ -33,18 +33,22 @@
qtl::execute(stmt, &affected, "second_user", "third_user");
```
+或者
+```C++
+stmt<<"second_user"<<"third_user";
+
+```
#### 4. 查询数据,以回调函数方式处理数据
-当回调函数返回false时,中止遍历数据。
+程序会一直遍历数据集,直到当回调函数返回false为止。如果回调函数无返回值,相当于返回true。
```C++
-db.query("select * from test where id=?",
- id, std::tuple<uint32_t, std::string, qtl::mysql::time>(),
- [](uint32_t id, const std::string& name, qtl::mysql::time& create_time) {
+db.query("select * from test where id=?", id,
+ [](uint32_t id, const std::string& name, const qtl::mysql::time& create_time) {
printf("ID=\"%d\", Name=\"%s\"\n", id, name.data());
- return true;
});
```
+当无法根据回调函数的参数推断字段类型时,请使用query_explicit代替query,手动指定数据类型进行查询。
#### 5. 也可以把数据绑定到结构上
@@ -72,14 +76,24 @@
}
}
-db.query("select * from test where id=?",
- id, TestMysqlRecord(),
- [](TestMysqlRecord& record) {
+db.query("select * from test where id=?", id,
+ [](const TestMysqlRecord& record) {
printf("ID=\"%d\", Name=\"%s\"\n", record.id, record.name);
- return true;
});
```
-#### 6. 以迭代器方式访问数据
+#### 6. 用成员函数做为查询的回调函数
+当记录类有不带参数的成员函数时,可以直接用作查询的回调函数
+```C++
+struct TestMysqlRecord
+{
+ void print();
+};
+
+db.query("select * from test where id=?", id,
+ &TestMysqlRecord::print);
+```
+
+#### 7. 以迭代器方式访问数据
```C++
for(auto& record : db.result<TestMysqlRecord>("select * from test"))
@@ -87,6 +101,12 @@
printf("ID=\"%d\", Name=\"%s\"\n", record.id, record.name);
}
```
+#### 8. 指示器
+可以用指示器获取查询结果的更多信息。指示器包含以下成员:
+- data 存储字段的数据
+- is_null 字段是否为空
+- length 数据的实际长度
+- is_truncated 数据是否被截断
## 有关MySQL的说明
@@ -116,7 +136,7 @@
| bigint | int64_t<br/>uint64_t |
| float | float |
| double | double |
-| char<br>varchar | char[N]<br>std::array<char, N><br>std::string |
+| char<br>varchar | char[N]<br>std::array<char, N><br>std::string |
| blob<br>binary<br>text | qtl::blob_data<br>std::ostream |
| date<br>time<br>datetime<br>timestamp | qtl::mysql::time |
@@ -152,8 +172,8 @@
| ------- | ------ |
| integer | int</br>int64_t |
| real | double |
-| text | char[N]<br>std::array<char, N><br>std::string<br>std::wstring |
-| blob | qtl::const_blob_data<br>qtl::blob_data<br>ios::ostream |
+| text | char[N]<br>std::array<char, N><br>std::string<br>std::wstring |
+| blob | qtl::const_blob_data<br>qtl::blob_data<br>std::ostream |
当以qtl::const_blob_data接收blob数据时,直接返回SQLite给出的数据地址;当以qtl::blob_data接收blob数据时,数据被复制到qtl::blob_data指定的地址。
diff --git a/include/qtl_common.hpp b/include/qtl_common.hpp
index caf6c3e..e630599 100644
--- a/include/qtl_common.hpp
+++ b/include/qtl_common.hpp
@@ -14,6 +14,7 @@
#include <type_traits>
#include <tuple>
#include <memory>
+#include <functional>
#include "apply_tuple.h"
namespace qtl
@@ -88,7 +89,9 @@
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<typename Command, typename T>
@@ -119,15 +122,153 @@
{
template<typename F, typename T>
-auto apply(F&& f, T&& v) -> decltype(f(v))
+struct apply_impl
{
- return f(v);
-}
+private:
+ typedef typename std::result_of<F(T)>::type raw_result_type;
+ template<typename Ret, bool>
+ struct impl {};
+ template<typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(F&& f, T&& v)
+ {
+ f(std::forward<T>(v));
+ return true;
+ }
+ };
+ template<typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(F&& f, T&& v)
+ {
+ return f(std::forward<T>(v));
+ }
+ };
+
+public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(F&& f, T&& v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v));
+ }
+};
template<typename F, typename... Types>
-auto apply(F&& f, std::tuple<Types...>&& v) -> decltype(apply_tuple(f, v))
+struct apply_impl<F, std::tuple<Types...>>
{
- return apply_tuple(f, v);
+private:
+ typedef typename std::remove_reference<F>::type fun_type;
+ typedef std::tuple<Types...> arg_type;
+ typedef typename std::result_of<F(Types...)>::type raw_result_type;
+ template<typename Ret, bool>
+ struct impl {};
+ template<typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(F&& f, arg_type&& v)
+ {
+ apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
+ return true;
+ }
+ };
+ template<typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(F&& f, arg_type&& v)
+ {
+ return apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
+ }
+ };
+
+public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(F&& f, arg_type&& v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v));
+ }
+};
+
+template<typename Type, typename R>
+struct apply_impl<R (Type::*)(), Type>
+{
+private:
+ typedef R (Type::*fun_type)();
+ typedef R raw_result_type;
+ template<typename Ret, bool>
+ struct impl {};
+ template<typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(fun_type f, Type&& v)
+ {
+ (v.*f)();
+ return true;
+ }
+ };
+ template<typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(fun_type f, Type&& v)
+ {
+ return (v.*f)();
+ }
+ };
+
+public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(R (Type::*f)(), Type&& v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
+ }
+};
+
+template<typename Type, typename R>
+struct apply_impl<R (Type::*)() const, Type>
+{
+private:
+ typedef R (Type::*fun_type)() const;
+ typedef R raw_result_type;
+ template<typename Ret, bool>
+ struct impl {};
+ template<typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(fun_type f, Type&& v)
+ {
+ (v.*f)();
+ return true;
+ }
+ };
+ template<typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(fun_type f, Type&& v)
+ {
+ return (v.*f)();
+ }
+ };
+
+public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(fun_type f, Type&& v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
+ }
+};
+
+template<typename F, typename T>
+typename apply_impl<F, T>::result_type apply(F&& f, T&& v)
+{
+ return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v));
}
template<typename Command, size_t N, typename... Types>
@@ -182,6 +323,72 @@
{
}
};
+
+#define QTL_ARGS_TUPLE(Arg, Others) \
+ typename std::tuple<typename std::decay<Arg>::type, typename std::decay<Others>::type...>
+
+template<typename Ret, typename Arg>
+inline typename std::decay<Arg>::type make_values(Ret (*)(Arg))
+{
+ return typename std::decay<Arg>::type();
+};
+
+template<typename Ret, typename Arg, typename... Others>
+inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
+{
+ return QTL_ARGS_TUPLE(Arg, Others)();
+};
+
+template<typename Type, typename Ret>
+inline Type make_values(Ret (Type::*)())
+{
+ return Type();
+};
+template<typename Type, typename Ret>
+inline Type make_values(Ret (Type::*)() const)
+{
+ return Type();
+};
+
+template<typename Type, typename Ret, typename... Args>
+inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args)
+{
+ return QTL_ARGS_TUPLE(Type, Args)();
+};
+template<typename Type, typename Ret, typename... Args>
+inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args)
+{
+ return QTL_ARGS_TUPLE(Type, Args)();
+};
+
+template<typename Type, typename Ret, typename Arg>
+inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg))
+{
+ return typename std::decay<Arg>::type();
+};
+template<typename Type, typename Ret, typename Arg>
+inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const)
+{
+ return typename std::decay<Arg>::type();
+};
+
+template<typename Type, typename Ret, typename Arg, typename... Others>
+inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
+{
+ return QTL_ARGS_TUPLE(Arg, Others)();
+};
+template<typename Type, typename Ret, typename Arg, typename... Others>
+inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others)
+{
+ return QTL_ARGS_TUPLE(Arg, Others)();
+};
+
+template<typename Functor, typename=typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type>
+inline auto make_values(const Functor&)
+-> decltype(make_values_noclass(&Functor::operator()))
+{
+ return make_values_noclass(&Functor::operator());
+}
}
@@ -452,88 +659,137 @@
}
template<typename Params, typename Values, typename ValueProc>
- void query(const char* query_text, size_t text_length, const Params& params, Values&& values, ValueProc proc)
+ void query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, ValueProc&& proc)
{
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
while(command.fetch(std::forward<Values>(values)))
{
- if(!detail::apply(proc, std::forward<Values>(values))) break;
+ if(!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) break;
}
command.close();
}
template<typename Params, typename Values, typename ValueProc>
- void query(const char* query_text, const Params& params, Values&& values, ValueProc proc)
+ void query_explicit(const char* query_text, const Params& params, Values&& values, ValueProc&& proc)
{
- query(query_text, strlen(query_text), params, std::forward<Values>(values), proc);
+ query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Params, typename Values, typename ValueProc>
- void query(const std::string& query_text, const Params& params, Values&& values, ValueProc proc)
+ void query_explicit(const std::string& query_text, const Params& params, Values&& values, ValueProc&& proc)
{
- query(query_text.data(), query_text.size(), params, std::forward<Values>(values), proc);
+ query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
- void query(const char* query_text, size_t text_length, Values&& values, ValueProc proc)
+ void query_explicit(const char* query_text, size_t text_length, Values&& values, ValueProc&& proc)
{
- query(query_text, text_length, std::make_tuple(), std::forward<Values>(values), proc);
+ query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
- void query(const char* query_text, Values&& values, ValueProc proc)
+ void query_explicit(const char* query_text, Values&& values, ValueProc&& proc)
{
- query(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), proc);
+ query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
- void query(const std::string& query_text, Values&& values, ValueProc proc)
+ void query_explicit(const std::string& query_text, Values&& values, ValueProc&& proc)
{
- query(query_text, std::make_tuple(), std::forward<Values>(values), proc);
+ query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+
+ template<typename Params, typename ValueProc>
+ 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<ValueProc>(proc));
+ }
+ template<typename Params, typename ValueProc>
+ void query(const char* query_text, const Params& params, ValueProc&& proc)
+ {
+ query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template<typename Params, typename ValueProc>
+ void query(const std::string& query_text, const Params& params, ValueProc&& proc)
+ {
+ query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template<typename ValueProc>
+ void query(const char* query_text, size_t text_length, ValueProc&& proc)
+ {
+ query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template<typename ValueProc>
+ void query(const char* query_text, ValueProc&& proc)
+ {
+ query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template<typename ValueProc>
+ void query(const std::string& query_text, ValueProc&& proc)
+ {
+ query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename Params, typename Values>
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>(values), first_record());
+ query_explicit(query_text, text_length, params, std::forward<Values>(values), first_record());
}
template<typename Params, typename Values>
void query_first(const char* query_text, const Params& params, Values&& values)
{
- query(query_text, strlen(query_text), params, std::forward<Values>(values), first_record());
+ query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), first_record());
}
template<typename Params, typename Values>
void query_first(const std::string& query_text, const Params& params, Values&& values)
{
- query(query_text, params, values, first_record());
+ query_explicit(query_text, params, values, first_record());
}
template<typename Values>
void query_first(const char* query_text, size_t text_length, Values&& values)
{
- query(query_text, text_length, std::make_tuple(), std::forward<Values>(values), first_record());
+ query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), first_record());
}
template<typename Values>
void query_first(const char* query_text, Values&& values)
{
- query(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), first_record());
+ query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), first_record());
}
template<typename Values>
void query_first(const std::string& query_text, Values&& values)
{
- query(query_text, std::make_tuple(), std::forward<Values>(values), first_record());
+ query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), first_record());
+ }
+
+ template<typename... Values>
+ void query_first_direct(const char* query_text, size_t text_length, Values&... values)
+ {
+ query_first(query_text, text_length, std::tie(values...));
+ }
+
+ template<typename... Values>
+ void query_first_direct(const char* query_text, Values&... values)
+ {
+ query_first(query_text, std::tie(values...));
+ }
+
+ template<typename... Values>
+ void query_first_direct(const std::string& query_text, Values&... values)
+ {
+ query_first(query_text, std::tie(values...));
}
protected:
struct nothing
{
- template<typename... Values> bool operator()(Values&...) const { return true; }
+ template<typename... Values> bool operator()(Values&&...) const { return true; }
};
struct first_record
{
- template<typename... Values> bool operator()(Values&...) const { return false; }
+ template<typename... Values> bool operator()(Values&&...) const { return false; }
};
};
@@ -593,6 +849,5 @@
}
}
-
#endif //_MYDTL_DATABASE_H_
diff --git a/include/qtl_mysql.hpp b/include/qtl_mysql.hpp
index 1c9cf5d..60c552b 100644
--- a/include/qtl_mysql.hpp
+++ b/include/qtl_mysql.hpp
@@ -563,12 +563,13 @@
bool open(const char *host, const char *user, const char *passwd, const char *db,
unsigned long clientflag=0, unsigned int port=0, const char *unix_socket=NULL)
{
+ if(m_mysql==NULL) m_mysql=mysql_init(NULL);
return mysql_real_connect(m_mysql, host, user, passwd, db, port, unix_socket, clientflag)!=NULL;
}
void close()
{
mysql_close(m_mysql);
- m_mysql=mysql_init(NULL);
+ m_mysql=NULL;
}
void refresh(unsigned int options)
{
diff --git a/test/TestMysql.cpp b/test/TestMysql.cpp
index 68dcb6f..53330c1 100644
--- a/test/TestMysql.cpp
+++ b/test/TestMysql.cpp
@@ -17,6 +17,12 @@
{
memset(this, 0, sizeof(TestMysqlRecord));
}
+
+ void print() const
+ {
+ printf("ID=\"%d\", Name=\"%s\"\n",
+ id, name);
+ }
};
namespace qtl
@@ -57,11 +63,9 @@
try
{
db.query("select 0, 'hello world' from dual",
- std::tuple<uint32_t, std::string>(),
[](uint32_t i, const std::string& str) {
printf("0=\"%d\", 'hello world'=\"%s\"\n",
i, str.data());
- return true;
});
}
catch(qtl::mysql::error& e)
@@ -77,21 +81,20 @@
try
{
- db.query("select * from test where id=?", 0,
- id, std::tuple<uint32_t, std::string, qtl::mysql::time>(),
- [](uint32_t id, const std::string& name, qtl::mysql::time& create_time) {
+ db.query("select * from test where id=?", id,
+ [](const qtl::indicator<uint32_t>& id, const std::string& name, const qtl::mysql::time& create_time) {
printf("ID=\"%d\", Name=\"%s\"\n",
- id, name.data());
- return true;
+ id.data, name.data());
});
- db.query("select * from test where id=?", 0,
- id, TestMysqlRecord(),
- [](TestMysqlRecord& record) {
+ db.query("select * from test where id=?", id,
+ [](const TestMysqlRecord& record) {
printf("ID=\"%d\", Name=\"%s\"\n",
record.id, record.name);
- return true;
});
+
+ db.query("select * from test where id=?", id,
+ &TestMysqlRecord::print);
}
catch(qtl::mysql::error& e)
{
diff --git a/test/TestSqlite.cpp b/test/TestSqlite.cpp
index 04417ba..7ac4ad6 100644
--- a/test/TestSqlite.cpp
+++ b/test/TestSqlite.cpp
@@ -19,6 +19,12 @@
{
memset(this, 0, sizeof(TestSqliteRecord));
}
+
+ void print() const
+ {
+ printf("ID=\"%d\", Name=\"%s\"\n",
+ id, name);
+ }
};
namespace qtl
@@ -66,11 +72,9 @@
try
{
db.query("select 0, 'hello world'",
- std::tuple<int32_t, std::string>(),
[](int32_t i, const std::string& str) {
printf("0=\"%d\", 'hello world'=\"%s\"\n",
i, str.data());
- return true;
});
}
catch(qtl::sqlite::error& e)
@@ -153,22 +157,21 @@
try
{
- db.query("select * from test where id=?",
- id, std::tuple<int, std::string, std::string>(),
- [](int id, const std::string& name, std::string& create_time) {
+ db.query("select * from test where id=?", id,
+ [](int id, const std::string& name, const std::string& create_time) {
printf("ID=\"%d\", Name=\"%s\", CrateTime=\"%s\"\n",
id, name.data(), create_time.data());
- return true;
});
- db.query("select ID, Name, strftime('%s', CreateTime) from test where id=?",
- id, TestSqliteRecord(),
- [](TestSqliteRecord& record) {
+ db.query("select ID, Name, strftime('%s', CreateTime) from test where id=?", id,
+ [](const TestSqliteRecord& record) {
time_t t=record.create_time;
printf("ID=\"%d\", Name=\"%s\", CrateTime=\"%s\"\n",
record.id, record.name, asctime(localtime(&t)));
- return true;
});
+
+ db.query("select * from test where id=?", id,
+ &TestSqliteRecord::print);
}
catch(qtl::sqlite::error& e)
{
--
Gitblit v1.9.3