From 0d3e994e33aa85965616a064bbf635ec8d043c1a Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Fri, 02 Oct 2020 06:11:48 +0000
Subject: [PATCH] The database can be operated asynchronously through asio.
---
include/qtl_database_pool.hpp | 2
test/test_mariadb.mak | 2
include/qtl_mysql.hpp | 6
test/TestMariaDB.cpp | 462 +++++++----------------------------
include/qtl_asio.hpp | 306 +++++++++++++++++++++++
README_CN.md | 1
README.md | 1
7 files changed, 411 insertions(+), 369 deletions(-)
diff --git a/README.md b/README.md
index 635771a..9b39083 100644
--- a/README.md
+++ b/README.md
@@ -224,6 +224,7 @@
```
Database connections are usually not thread-safe. User code should guarantee that a connection can only be used by one thread at a time.
+For use this feature, GCC requires version 5 or higher.
## About MySQL
diff --git a/README_CN.md b/README_CN.md
index 87e108f..f516d4e 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -224,6 +224,7 @@
```
数据库连接通常不是线程安全的。用户代码应该保证,一个连接只能同时由一个线程使用。
+使用这项功能,GCC需要 5 或更高版本才行。
## 有关MySQL的说明
diff --git a/include/qtl_asio.hpp b/include/qtl_asio.hpp
new file mode 100644
index 0000000..cbf51c9
--- /dev/null
+++ b/include/qtl_asio.hpp
@@ -0,0 +1,306 @@
+#ifndef _QTL_ASIO_H_
+#define _QTL_ASIO_H_
+
+#include <qtl_async.hpp>
+#include <asio/version.hpp>
+#define ASIO_STANDALONE
+#if ASIO_VERSION < 101200
+#include <asio/io_service.hpp>
+#else
+#include <asio/io_context.hpp>
+#endif // ASIO_VERSION
+#include <asio/strand.hpp>
+#include <asio/ip/tcp.hpp>
+#include <asio/async_result.hpp>
+#include <asio/steady_timer.hpp>
+
+#if ASIO_VERSION < 100000
+#error The asio version required by QTL is at least 10.0
+#endif
+
+namespace qtl
+{
+
+namespace NS_ASIO = ::asio;
+
+namespace asio
+{
+
+class service
+{
+public:
+#if ASIO_VERSION < 101200
+ typedef NS_ASIO::io_service service_type;
+#else
+ typedef NS_ASIO::io_context service_type;
+#endif // ASIO_VERSION
+
+ service() { }
+ explicit service(int concurrency_hint) : _service(concurrency_hint) { }
+
+ void reset()
+ {
+ _service.reset();
+ }
+
+ void run()
+ {
+ _service.run();
+ }
+
+ void stop()
+ {
+ _service.stop();
+ }
+
+ service_type& context() { return _service; }
+
+private:
+
+ class event_item : public qtl::event
+ {
+ public:
+ event_item(service_type& service, qtl::socket_type fd)
+ : _strand(service), _socket(service, NS_ASIO::ip::tcp::v4(), fd), _timer(service), _busying(false)
+ {
+ }
+
+ NS_ASIO::ip::tcp::socket& next_layer() { return _socket; }
+
+ public: // qtl::event
+ virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) override
+ {
+ if (flags&qtl::event::ef_read)
+ {
+#if ASIO_VERSION < 101200
+ _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
+#else
+ _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
+#endif // ASIO_VERSION
+ if (!ec)
+ handler(qtl::event::ef_read);
+ else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
+ handler(qtl::event::ef_timeout);
+ else
+ handler(qtl::event::ef_exception);
+ _busying = false;
+ }));
+ _busying = true;
+ }
+ if (flags&qtl::event::ef_write)
+ {
+#if ASIO_VERSION < 101200
+ _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
+#else
+ _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
+#endif //ASIO_VERSION
+ if (!ec)
+ handler(qtl::event::ef_write);
+ else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
+ handler(qtl::event::ef_timeout);
+ else
+ handler(qtl::event::ef_exception);
+ _busying = false;
+ }));
+ _busying = true;
+ }
+ if (timeout > 0)
+ {
+#if ASIO_VERSION < 101200
+ _timer.expires_from_now(std::chrono::seconds(timeout));
+#else
+ _timer.expires_after(NS_ASIO::chrono::seconds(timeout));
+#endif // ASIO_VERSION
+ _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec) {
+ if (!ec)
+ {
+ _socket.cancel(ec);
+ }
+ }));
+ }
+ }
+
+ virtual void remove() override
+ {
+#if ASIO_VERSION < 101200 && (!defined(_WIN32) && _WIN32_WINNT >= 0x0603 )
+ _socket.release();
+#endif //Windows 8.1
+ }
+ virtual bool is_busying() override
+ {
+ return _busying;
+ }
+
+ private:
+ service_type::strand _strand;
+ NS_ASIO::ip::tcp::socket _socket;
+ NS_ASIO::steady_timer _timer;
+ bool _busying;
+ };
+
+public:
+
+ template<typename Connection>
+ event_item* add(Connection* connection)
+ {
+ event_item* item = new event_item(_service, connection->socket());
+ _events.push_back(std::unique_ptr<event_item>(item));
+ return item;
+ }
+
+private:
+ service_type _service;
+ std::vector<std::unique_ptr<event_item>> _events;
+};
+
+#if ASIO_VERSION < 101200
+
+template <typename Handler, typename Signature>
+using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>;
+
+template <typename Handler, typename Signature>
+inline typename NS_ASIO::handler_type<Handler, Signature>::type
+get_async_handler(async_init_type<Handler, Signature>& init)
+{
+ return init.handler;
+}
+
+#else
+
+template <typename Handler, typename Signature>
+using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
+
+template <typename Handler, typename Signature>
+inline typename async_init_type<Handler, Signature>::completion_handler_type
+get_async_handler(async_init_type<Handler, Signature>& init)
+{
+ return init.completion_handler;
+}
+
+#endif // ASIO_VERSION
+
+template<typename Connection, typename OpenHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
+async_open(service& service, Connection& db, OpenHandler&& handler, Args&&... args)
+{
+ async_init_type<OpenHandler,
+ void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler));
+ db.open(service, get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename CloseHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
+async_close(Connection& db, CloseHandler&& handler, Args&&... args)
+{
+ async_init_type<CloseHandler,
+ void()> init(std::forward<CloseHandler>(handler));
+ db.close(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename ExecuteHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+async_execute(Connection& db, ExecuteHandler&& handler, Args&&... args)
+{
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ db.execute(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename ExecuteHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+async_execute_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
+{
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename ExecuteHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_insert(Connection& db, ExecuteHandler&& handler, Args&&... args)
+{
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ db.insert(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename ExecuteHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_insert_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
+{
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename FinishHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query(Connection& db, FinishHandler&& handler, Args&&... args)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query(std::forward<Args>(args)..., get_async_handler(init));
+ return init.result.get();
+}
+
+template<typename Connection, typename FinishHandler, typename... Args>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+async_query_explicit(Connection& db, FinishHandler&& handler, Args&&... args)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
+ return init.result.get();
+}
+
+template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+async_query_multi_with_params(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+async_query_multi_with_params(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+async_query_multi(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+}
+
+template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
+inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+async_query_multi(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
+{
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+}
+
+}
+
+}
+
+#endif //_QTL_ASIO_H_
diff --git a/include/qtl_database_pool.hpp b/include/qtl_database_pool.hpp
index 81c5f28..4b53dfd 100644
--- a/include/qtl_database_pool.hpp
+++ b/include/qtl_database_pool.hpp
@@ -223,7 +223,7 @@
void test_alive()
{
if (m_connections.empty())
- return false;
+ return;
std::unique_lock<std::mutex> lock(m_pool_mutex);
auto it = m_connections.begin();
while (it != m_connections.end())
diff --git a/include/qtl_mysql.hpp b/include/qtl_mysql.hpp
index 8bb6e6d..179df88 100644
--- a/include/qtl_mysql.hpp
+++ b/include/qtl_mysql.hpp
@@ -1582,7 +1582,7 @@
int status = mysql_close_start(m_mysql);
if (status)
{
- wait_close(status, [this, handler]() {
+ wait_close(status, [this, handler]() mutable {
handler();
m_mysql = nullptr;
});
@@ -1781,7 +1781,7 @@
void wait_close(int status, CloseHandler&& handler) NOEXCEPT
{
m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, handler](int flags) {
+ [this, handler](int flags) mutable {
MYSQL* ret = nullptr;
int status = mysql_close_cont(m_mysql, mysql_status(flags));
if (status)
@@ -1809,7 +1809,7 @@
void wait_query(int status, int field_count, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT
{
m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, field_count, row_handler, result_handler](int flags) {
+ [this, field_count, row_handler, result_handler](int flags) mutable {
MYSQL_RES* result = 0;
int status = mysql_store_result_cont(&result, m_mysql, mysql_status(flags));
if (status)
diff --git a/test/TestMariaDB.cpp b/test/TestMariaDB.cpp
index 8435e6b..c78eda6 100644
--- a/test/TestMariaDB.cpp
+++ b/test/TestMariaDB.cpp
@@ -6,260 +6,11 @@
#include <time.h>
#include <limits.h>
#include "../include/qtl_mysql_pool.hpp"
+#include "../include/qtl_asio.hpp"
#if MARIADB_VERSION_ID < 0100000
#error "The program need mariadb version > 10.0"
#endif
-
-class simple_event_loop
-{
-public:
- simple_event_loop()
- {
- m_expired = 0;
- m_maxfd = 0;
- m_stoped = false;
- FD_ZERO(&m_readset);
- FD_ZERO(&m_writeset);
- FD_ZERO(&m_exceptset);
- }
-
- void reset()
- {
- m_stoped = false;
- }
-
- void run()
- {
- while (!m_stoped)
- do_once(nullptr);
- }
-
- void run_for(long seconds)
- {
- time_t expired, now;
- time(&now);
- expired = now + seconds;
- timeval tv = { seconds };
- do
- {
- do_once(&tv);
- time(&now);
- tv.tv_sec = expired - now;
- tv.tv_usec = 0;
- } while (!m_stoped && now < expired);
- }
-
- void stop()
- {
- m_stoped = true;
- }
-
-private:
- class event_item : public qtl::event
- {
- public:
- event_item(simple_event_loop* loop, qtl::socket_type fd)
- : m_loop(loop), m_fd(fd), m_expired(LONG_MAX)
- {
- }
-
- virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) NOEXCEPT override
- {
- if (timeout > 0)
- {
- time_t now;
- time(&now);
- if (m_expired > now + timeout)
- m_expired = now + timeout;
- m_loop->set(this, flags, m_expired);
- }
- else
- {
- m_expired = LONG_MAX;
- m_loop->set(this, flags, 0);
- }
- m_io_handler = std::forward<std::function<void(int)>>(handler);
- }
- virtual void remove() override
- {
- m_loop->remove(this);
- }
- virtual bool is_busying() override
- {
- return m_io_handler!=nullptr;
- }
-
- simple_event_loop* m_loop;
- qtl::socket_type m_fd;
- time_t m_expired;
- std::function<void(int)> m_io_handler;
- };
- std::vector<std::unique_ptr<event_item>> m_events;
-
- //implement for QTL
-public:
- template<typename Connection>
- event_item* add(Connection* connection)
- {
- qtl::socket_type fd = connection->socket();
- event_item* result = new event_item(this, fd);
- std::unique_ptr<event_item> item(result);
- m_events.emplace_back(std::move(item));
- return result;
- }
-
- template<typename Handler>
- event_item* set_timeout(const timeval& timeout, Handler&& handler)
- {
- event_item* result = new event_item(this, 0);
- std::unique_ptr<event_item> item(result);
- ::time(&result->m_expired);
- result->m_expired+=timeout.tv_sec;
- if(m_expired>result->m_expired)
- m_expired=result->m_expired;
- m_events.emplace_back(std::move(item));
- return result;
- }
-
-public:
- void set(event_item* item, int flags, time_t expired)
- {
- if (item->m_fd + 1 > m_maxfd)
- m_maxfd = item->m_fd + 1;
- if (flags&qtl::event::ef_read)
- FD_SET(item->m_fd, &m_readset);
- if (flags&qtl::event::ef_write)
- FD_SET(item->m_fd, &m_writeset);
- if (flags&qtl::event::ef_exception)
- FD_SET(item->m_fd, &m_exceptset);
- if (expired > 0 && m_expired > expired)
- m_expired = expired;
- }
-
- void remove(event_item* item)
- {
- auto it = m_events.begin();
- while (it != m_events.end())
- {
- if (it->get() == item)
- {
- m_events.erase(it);
- return;
- }
- ++it;
- }
- }
-
-private:
- fd_set m_readset, m_writeset, m_exceptset;
- qtl::socket_type m_maxfd;
- int do_once(timeval* timeout)
- {
- fd_set rs = m_readset, ws = m_writeset, es = m_exceptset;
- timeval tv = { INT_MAX, 0 };
- time_t now;
- time(&now);
- if (timeout)
- {
- tv = *timeout;
- timeout = &tv;
- }
-
- long d = m_expired - now;
- if (d > 0 && tv.tv_sec > d)
- {
- tv.tv_sec = d;
- timeout = &tv;
- }
-
- qtl::socket_type maxfd = m_maxfd;
- FD_ZERO(&m_readset);
- FD_ZERO(&m_writeset);
- FD_ZERO(&m_exceptset);
- m_maxfd = 0;
-
- if (maxfd == 0)
- {
- if (timeout)
- {
- std::this_thread::sleep_for(std::chrono::microseconds(timeout->tv_sec*std::micro::den + timeout->tv_usec));
- check_timeout();
- }
- else
- {
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }
- return 0;
- }
- else
- {
- int ret = select(maxfd, &rs, &ws, &es, timeout);
- if (ret > 0)
- {
- for (auto& item : m_events)
- {
- int flags = 0;
- if (FD_ISSET(item->m_fd, &rs))
- flags |= qtl::event::ef_read;
- if (FD_ISSET(item->m_fd, &ws))
- flags |= qtl::event::ef_write;
- if (FD_ISSET(item->m_fd, &es))
- flags |= qtl::event::ef_exception;
- if (flags && item->m_io_handler)
- {
- auto handler = std::move(item->m_io_handler);
- handler(flags);
- }
- }
- }
- else if (ret == 0)
- {
- time(&now);
- for (auto& item : m_events)
- {
- if (item->m_expired > 0 && item->m_io_handler && item->m_expired < now)
- {
- item->m_io_handler(qtl::event::ef_timeout);
- item->m_expired = 0;
- item->m_io_handler = nullptr;
- }
- }
- }
- else if (ret < 0)
- {
- int errc;
-#ifdef _WIN32
- errc = WSAGetLastError();
-#else
- errc = errno;
-#endif
- throw std::system_error(errc, std::system_category());
- }
- return ret;
- }
- }
-
- void check_timeout()
- {
- time_t now;
- time(&now);
- for (auto& item : m_events)
- {
- if (item->m_expired > 0 && item->m_io_handler && item->m_expired < now)
- {
- item->m_io_handler(qtl::event::ef_timeout);
- item->m_expired = 0;
- item->m_io_handler = nullptr;
- }
- }
- }
-
- time_t m_expired;
- bool m_stoped;
-};
-
-simple_event_loop ev;
using namespace qtl::mysql;
@@ -270,152 +21,135 @@
const char mysql_server[]="localhost";
const char mysql_user[]="root";
-const char mysql_password[]="";
+const char mysql_password[]="123456";
const char mysql_database[]="test";
-void SimpleTest()
+class MariaDBTest
{
- async_connection connection;
- ev.reset();
- connection.open(ev, [&connection](const error& e) {
- if (e)
- {
- LogError(e);
- ev.stop();
- }
- else
- {
- printf("Connect to mysql ok.\n");
- connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) {
- for (int i = 0; i != field_count; i++)
- printf("%s\t", row[i]);
- printf("\n");
- return true;
- }, [&connection](const error& e, size_t row_count) {
- if (e)
- LogError(e);
- else
- printf("Total %lu rows.\n", row_count);
+public:
+ MariaDBTest()
+ {
+ Open();
+ _service.run();
+ }
- connection.close([]() {
- printf("Close connection ok.\n");
- ev.stop();
- });
- });
- }
- }, mysql_server, mysql_user, mysql_password, mysql_database);
+private:
+ void Open();
+ void Close();
+ void SimpleQuery();
+ void Execute();
+ void Query();
+ void MultiQuery();
- ev.run();
-}
+private:
+ async_connection _connection;
+ qtl::asio::service _service;
-void ExecuteTest()
-{
- async_connection connection;
- ev.reset();
- connection.open(ev, [&connection](const error& e) {
- if (e)
- {
- LogError(e);
- ev.stop();
- }
- else
- {
- printf("Connect to mysql ok.\n");
- connection.execute([&connection](const error& e, uint64_t affected) mutable {
- if (e)
- LogError(e);
- else
- printf("Insert %llu records ok.\n", affected);
- connection.close([]() {
- printf("Close connection ok.\n");
- ev.stop();
- });
- }, "insert into test(name, createtime, company) values(?, now(), ?)", 0, std::make_tuple("test name", "test company"));
- }
- }, mysql_server, mysql_user, mysql_password, mysql_database);
-
- ev.run();
};
-void QueryTest()
+void MariaDBTest::Open()
{
- async_connection connection;
- ev.reset();
- connection.open(ev, [&connection](const error& e) {
+ _connection.open(_service, [this](const error& e) {
if (e)
{
LogError(e);
- ev.stop();
+ _service.stop();
}
else
{
printf("Connect to mysql ok.\n");
- connection.query("select id, name, CreateTime, Company from test", 0,
- [](int64_t id, const std::string& name, const qtl::mysql::time& create_time, const std::string& company) {
- char szTime[128] = { 0 };
- if (create_time.year != 0)
- {
- struct tm tm;
- create_time.as_tm(tm);
- strftime(szTime, 128, "%c", &tm);
- }
- printf("%lld\t%s\t%s\t%s\n", id, name.data(), szTime, company.data());
- }, [&connection](const error& e) {
- printf("query has completed.\n");
- if (e)
- LogError(e);
-
- connection.close([]() {
- printf("Close connection ok.\n");
- ev.stop();
- });
- });
+ SimpleQuery();
}
}, mysql_server, mysql_user, mysql_password, mysql_database);
-
- ev.run();
}
-void MultiQueryTest()
+void MariaDBTest::Close()
{
- async_connection connection;
- ev.reset();
- connection.open(ev, [&connection](const error& e) {
+ _connection.close([this]() {
+ printf("Connection is closed.\n");
+ _service.stop();
+ });
+}
+
+void MariaDBTest::SimpleQuery()
+{
+ _connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) {
+ for (int i = 0; i != field_count; i++)
+ printf("%s\t", row[i]);
+ printf("\n");
+ return true;
+ }, [this](const error& e, size_t row_count) {
if (e)
{
LogError(e);
- ev.stop();
}
else
{
- printf("Connect to mysql ok.\n");
- connection.query_multi("call test_proc",
- [&connection](const error& e) {
- if (e)
- LogError(e);
-
- connection.close([]() {
- printf("Close connection ok.\n");
- ev.stop();
- });
- }, [](uint32_t i, const std::string& str) {
- printf("0=\"%d\", 'hello world'=\"%s\"\n", i, str.data());
- }, [](const qtl::mysql::time& time) {
- struct tm tm;
- time.as_tm(tm);
- printf("current time is: %s\n", asctime(&tm));
- });
+ printf("Total %lu rows.\n", row_count);
+ Execute();
}
- }, mysql_server, mysql_user, mysql_password, mysql_database);
+ });
+}
- ev.run();
+void MariaDBTest::Execute()
+{
+ _connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) {
+ for (int i = 0; i != field_count; i++)
+ printf("%s\t", row[i]);
+ printf("\n");
+ return true;
+ }, [this](const error& e, size_t row_count) {
+ if (e)
+ LogError(e);
+ else
+ {
+ printf("Total %lu rows.\n", row_count);
+ Query();
+ }
+ });
+}
+
+void MariaDBTest::Query()
+{
+ _connection.query("select id, name, CreateTime, Company from test", 0,
+ [](int64_t id, const std::string& name, const qtl::mysql::time& create_time, const std::string& company) {
+ char szTime[128] = { 0 };
+ if (create_time.year != 0)
+ {
+ struct tm tm;
+ create_time.as_tm(tm);
+ strftime(szTime, 128, "%c", &tm);
+ }
+ printf("%lld\t%s\t%s\t%s\n", id, name.data(), szTime, company.data());
+ }, [this](const error& e) {
+ printf("query has completed.\n");
+ if (e)
+ LogError(e);
+ else
+ MultiQuery();
+ });
+}
+
+void MariaDBTest::MultiQuery()
+{
+ _connection.query_multi("call test_proc",
+ [this](const error& e) {
+ if (e)
+ LogError(e);
+ else
+ Close();
+
+ }, [](uint32_t i, const std::string& str) {
+ printf("0=\"%d\", 'hello world'=\"%s\"\n", i, str.data());
+ }, [](const qtl::mysql::time& time) {
+ struct tm tm;
+ time.as_tm(tm);
+ printf("current time is: %s\n", asctime(&tm));
+ });
}
int main(int argc, char* argv[])
{
- ExecuteTest();
- SimpleTest();
- QueryTest();
- MultiQueryTest();
+ MariaDBTest test;
return 0;
}
diff --git a/test/test_mariadb.mak b/test/test_mariadb.mak
index a0314d9..ee0f245 100644
--- a/test/test_mariadb.mak
+++ b/test/test_mariadb.mak
@@ -3,7 +3,7 @@
PCH_HEADER=stdafx.h
PCH=stdafx.h.gch
OBJ=TestMariaDB.o
-CFLAGS=-g -D_DEBUG -O2 -I/usr/include/mariadb -I/usr/local/include
+CFLAGS=-g -D_DEBUG -O2 -I/usr/include -I/usr/include/mariadb -I/usr/local/include -I/usr/local/include/mariadb
CXXFLAGS=-I../include -std=c++11
LDFLAGS= -L/usr/local/lib -L/usr/local/mariadb/lib -lmariadb
--
Gitblit v1.9.3