znone
2017-01-26 39a95f6939417ebc5d8e716ca1664a1da1fc722c
根据回调函数参数推断绑定的数据类型。

回调函数可以无返回。
5 files modified
404 ■■■■ changed files
README.md 46 ●●●● patch | view | raw | blame | history
include/qtl_common.hpp 307 ●●●●● patch | view | raw | blame | history
include/qtl_mysql.hpp 3 ●●●● patch | view | raw | blame | history
test/TestMysql.cpp 25 ●●●●● patch | view | raw | blame | history
test/TestSqlite.cpp 23 ●●●●● patch | view | raw | blame | history
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&lt;char, N&gt;<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&lt;char, N&gt;<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指定的地址。
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_
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)
    {
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)
    {
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)
    {