mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-15 12:29:41 +08:00
Add connection methods is_connected() and ping_server() (#528)
* Replace connection handle method check_connection() with is_connected() and ping_server() * When a connections is fetched from a pool perform a validity check which can be one of none, passive or ping. * Add the methods is_connected() and ping_server() to the connection template class. * Remove unused #include and add mising #include. * Add tests for the connection methods is_connected() and ping_server().
This commit is contained in:
parent
8d92e7bb81
commit
623b5154d0
@ -67,8 +67,11 @@ namespace sqlpp
|
||||
connection_handle& operator=(connection_handle&&);
|
||||
|
||||
// Used by the connection pool to check if the connection handle is still
|
||||
// connected to the database server
|
||||
bool check_connection();
|
||||
// connected to the database server.
|
||||
bool is_connected();
|
||||
|
||||
// Send a dummy request to the server to check if the connection is still alive
|
||||
bool ping_server();
|
||||
|
||||
// Optional method that returns a native (low-level) database handle.
|
||||
// Used by the test code to test the connection pool
|
||||
|
@ -29,8 +29,8 @@
|
||||
|
||||
#include <sqlpp11/compat/make_unique.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
@ -38,9 +38,27 @@ namespace sqlpp
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ConnectionBase>
|
||||
class common_connection : public ConnectionBase
|
||||
{
|
||||
public:
|
||||
bool is_connected() const
|
||||
{
|
||||
return ConnectionBase::_handle ? ConnectionBase::_handle->is_connected() : false;
|
||||
}
|
||||
|
||||
bool ping_server() const
|
||||
{
|
||||
return ConnectionBase::_handle ? ConnectionBase::_handle->ping_server() : false;
|
||||
}
|
||||
|
||||
protected:
|
||||
using ConnectionBase::ConnectionBase;
|
||||
};
|
||||
|
||||
// Normal (non-pooled) connection
|
||||
template <typename ConnectionBase>
|
||||
class normal_connection : public ConnectionBase
|
||||
class normal_connection : public common_connection<ConnectionBase>
|
||||
{
|
||||
public:
|
||||
using _config_t = typename ConnectionBase::_config_t;
|
||||
@ -53,7 +71,8 @@ namespace sqlpp
|
||||
{
|
||||
}
|
||||
|
||||
normal_connection(const _config_ptr_t& config) : ConnectionBase{compat::make_unique<_handle_t>(config)}
|
||||
normal_connection(const _config_ptr_t& config)
|
||||
: common_connection<ConnectionBase>{compat::make_unique<_handle_t>(config)}
|
||||
{
|
||||
}
|
||||
|
||||
@ -80,7 +99,7 @@ namespace sqlpp
|
||||
|
||||
// Pooled connection
|
||||
template <typename ConnectionBase>
|
||||
class pooled_connection : public ConnectionBase
|
||||
class pooled_connection : public common_connection<ConnectionBase>
|
||||
{
|
||||
friend class connection_pool<ConnectionBase>::pool_core;
|
||||
|
||||
@ -118,12 +137,12 @@ namespace sqlpp
|
||||
|
||||
// Constructors used by the connection pool
|
||||
pooled_connection(_handle_ptr_t&& handle, _pool_core_ptr_t pool_core)
|
||||
: ConnectionBase{std::move(handle)}, _pool_core{pool_core}
|
||||
: common_connection<ConnectionBase>{std::move(handle)}, _pool_core{pool_core}
|
||||
{
|
||||
}
|
||||
|
||||
pooled_connection(const _config_ptr_t& config, _pool_core_ptr_t pool_core)
|
||||
: ConnectionBase{compat::make_unique<_handle_t>(config)}, _pool_core{pool_core}
|
||||
: common_connection<ConnectionBase>{compat::make_unique<_handle_t>(config)}, _pool_core{pool_core}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,20 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <sqlpp11/detail/circular_buffer.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
enum class connection_check
|
||||
{
|
||||
none,
|
||||
passive,
|
||||
ping
|
||||
};
|
||||
|
||||
template <typename ConnectionBase>
|
||||
class connection_pool
|
||||
{
|
||||
@ -56,7 +64,7 @@ namespace sqlpp
|
||||
pool_core& operator=(const pool_core&) = delete;
|
||||
pool_core& operator=(pool_core&&) = delete;
|
||||
|
||||
_pooled_connection_t get()
|
||||
_pooled_connection_t get(connection_check check)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{_mutex};
|
||||
if (_handles.empty())
|
||||
@ -68,8 +76,10 @@ namespace sqlpp
|
||||
_handles.pop_front();
|
||||
lock.unlock();
|
||||
// If the fetched connection is dead, drop it and create a new one on the fly
|
||||
return handle->check_connection() ? _pooled_connection_t{std::move(handle), this->shared_from_this()}
|
||||
: _pooled_connection_t{_connection_config, this->shared_from_this()};
|
||||
return
|
||||
check_connection(handle, check) ?
|
||||
_pooled_connection_t{std::move(handle), this->shared_from_this()} :
|
||||
_pooled_connection_t{_connection_config, this->shared_from_this()};
|
||||
}
|
||||
|
||||
void put(_handle_ptr_t& handle)
|
||||
@ -90,6 +100,21 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool check_connection(_handle_ptr_t& handle, connection_check check)
|
||||
{
|
||||
switch (check)
|
||||
{
|
||||
case connection_check::none:
|
||||
return true;
|
||||
case connection_check::passive:
|
||||
return handle->is_connected();
|
||||
case connection_check::ping:
|
||||
return handle->ping_server();
|
||||
default:
|
||||
throw std::invalid_argument{"Invalid connection check value"};
|
||||
}
|
||||
}
|
||||
|
||||
_config_ptr_t _connection_config;
|
||||
sqlpp::detail::circular_buffer<_handle_ptr_t> _handles;
|
||||
std::mutex _mutex;
|
||||
@ -117,9 +142,9 @@ namespace sqlpp
|
||||
_core = std::make_shared<pool_core>(connection_config, capacity);
|
||||
}
|
||||
|
||||
_pooled_connection_t get()
|
||||
_pooled_connection_t get(connection_check check = connection_check::passive)
|
||||
{
|
||||
return _core->get();
|
||||
return _core->get(check);
|
||||
}
|
||||
|
||||
// Returns number of connections available in the pool. Only used in tests.
|
||||
|
@ -281,9 +281,9 @@ namespace sqlpp
|
||||
return serialize(t, context);
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
[[deprecated("Use ping_server() instead")]] bool is_valid() const
|
||||
{
|
||||
return _handle->check_connection();
|
||||
return _handle->ping_server();
|
||||
}
|
||||
|
||||
void reconnect()
|
||||
|
@ -101,10 +101,17 @@ namespace sqlpp
|
||||
return mysql.get();
|
||||
}
|
||||
|
||||
bool check_connection() const
|
||||
bool is_connected() const
|
||||
{
|
||||
auto nh = native_handle();
|
||||
return nh && (mysql_ping(nh) == 0);
|
||||
// The connection is established in the constructor and the MySQL client
|
||||
// library doesn't seem to have a way to check passively if the connection
|
||||
// is still valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ping_server() const
|
||||
{
|
||||
return mysql_ping(native_handle()) == 0;
|
||||
}
|
||||
|
||||
void reconnect()
|
||||
|
@ -185,7 +185,7 @@ namespace sqlpp
|
||||
if (!postgres)
|
||||
throw std::bad_alloc{};
|
||||
|
||||
if (check_connection() == false)
|
||||
if (is_connected() == false)
|
||||
{
|
||||
std::string msg{PQerrorMessage(native_handle())};
|
||||
throw broken_connection{std::move(msg)};
|
||||
@ -220,11 +220,24 @@ namespace sqlpp
|
||||
return postgres.get();
|
||||
}
|
||||
|
||||
bool check_connection() const
|
||||
bool is_connected() const
|
||||
{
|
||||
auto nh = native_handle();
|
||||
return nh && (PQstatus(nh) == CONNECTION_OK);
|
||||
}
|
||||
|
||||
bool ping_server() const
|
||||
{
|
||||
// Loosely based on the implementation of PHP's pg_ping()
|
||||
if (is_connected() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto exec_res = PQexec(native_handle(), "SELECT 1");
|
||||
auto exec_ok = PQresultStatus(exec_res) == PGRES_TUPLES_OK;
|
||||
PQclear(exec_res);
|
||||
return exec_ok;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -96,9 +96,22 @@ namespace sqlpp
|
||||
return sqlite.get();
|
||||
}
|
||||
|
||||
bool check_connection() const
|
||||
bool is_connected() const
|
||||
{
|
||||
return native_handle() != nullptr;
|
||||
// The connection is established in the constructor and the SQLite3 client
|
||||
// library doesn't seem to have a way to check passively if the connection
|
||||
// is still valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ping_server() const
|
||||
{
|
||||
// Loosely based on the implementation of PHP's pg_ping()
|
||||
if (sqlite3_exec(native_handle(), "SELECT 1", nullptr, nullptr, nullptr) != SQLITE_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
@ -116,6 +116,24 @@ namespace sqlpp
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_conn_check(Pool& pool)
|
||||
{
|
||||
auto check_db = [] (typename Pool::_pooled_connection_t db) {
|
||||
if (db.is_connected() == false)
|
||||
{
|
||||
throw std::runtime_error{"is_connected() returned false"};
|
||||
}
|
||||
if (db.ping_server() == false)
|
||||
{
|
||||
throw std::runtime_error{"ping_server() returned false"};
|
||||
}
|
||||
};
|
||||
check_db(pool.get(connection_check::none));
|
||||
check_db(pool.get(connection_check::passive));
|
||||
check_db(pool.get(connection_check::ping));
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_basic(Pool& pool, const std::string& create_table)
|
||||
{
|
||||
@ -250,15 +268,16 @@ namespace sqlpp
|
||||
void test_connection_pool (typename Pool::_config_ptr_t config, const std::string& create_table, bool test_mt)
|
||||
{
|
||||
auto pool = Pool {config, 5};
|
||||
sqlpp::test::test_conn_move(pool);
|
||||
sqlpp::test::test_basic(pool, create_table);
|
||||
sqlpp::test::test_single_connection(pool);
|
||||
sqlpp::test::test_multiple_connections(pool);
|
||||
test_conn_move(pool);
|
||||
test_basic(pool, create_table);
|
||||
test_conn_check(pool);
|
||||
test_single_connection(pool);
|
||||
test_multiple_connections(pool);
|
||||
if (test_mt)
|
||||
{
|
||||
sqlpp::test::test_multithreaded(pool);
|
||||
test_multithreaded(pool);
|
||||
}
|
||||
sqlpp::test::test_destruction_order<Pool>(config);
|
||||
test_destruction_order<Pool>(config);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace sqlpp
|
||||
|
69
tests/include/ConnectionTests.h
Normal file
69
tests/include/ConnectionTests.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2023, Vesselin Atanasov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename Connection>
|
||||
void test_conn_empty()
|
||||
{
|
||||
Connection db;
|
||||
if (db.is_connected()) {
|
||||
throw std::runtime_error{"Unexpected is_connected() == true"};
|
||||
}
|
||||
if (db.ping_server()) {
|
||||
throw std::runtime_error{"Unexpected ping_server() == true"};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Connection, typename ConfigPtr>
|
||||
void test_conn_connected(const ConfigPtr& connection_config)
|
||||
{
|
||||
Connection db{connection_config};
|
||||
if (db.is_connected() == false) {
|
||||
throw std::runtime_error{"Unexpected is_connected() == false"};
|
||||
}
|
||||
if (db.ping_server() == false) {
|
||||
throw std::runtime_error{"Unexpected ping_server() == false"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Connection, typename ConfigPtr>
|
||||
void test_normal_connection(const ConfigPtr& connection_config)
|
||||
{
|
||||
test_conn_empty<Connection>();
|
||||
test_conn_connected<Connection>(connection_config);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace sqlpp
|
@ -40,6 +40,7 @@ set(test_files
|
||||
Truncated.cpp
|
||||
Update.cpp
|
||||
Remove.cpp
|
||||
Connection.cpp
|
||||
ConnectionPool.cpp
|
||||
)
|
||||
|
||||
|
39
tests/mysql/usage/Connection.cpp
Normal file
39
tests/mysql/usage/Connection.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../../include/ConnectionTests.h"
|
||||
#include "make_test_connection.h"
|
||||
|
||||
#include <sqlpp11/mysql/connection.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
int Connection(int, char*[])
|
||||
{
|
||||
namespace sql = sqlpp::mysql;
|
||||
namespace test = sqlpp::test;
|
||||
|
||||
test::test_normal_connection<sql::connection>(sql::make_test_config());
|
||||
return 0;
|
||||
}
|
@ -30,8 +30,8 @@ set(test_files
|
||||
Basic.cpp
|
||||
BasicConstConfig.cpp
|
||||
Blob.cpp
|
||||
Connection.cpp
|
||||
ConnectionPool.cpp
|
||||
Constructor.cpp
|
||||
Date.cpp
|
||||
DateTime.cpp
|
||||
Exceptions.cpp
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Serge Robyns
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -23,13 +24,17 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../../include/ConnectionTests.h"
|
||||
#include "make_test_connection.h"
|
||||
|
||||
#include <sqlpp11/postgresql/connection.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
namespace sql = sqlpp::postgresql;
|
||||
|
||||
int Constructor(int, char*[])
|
||||
int Connection(int, char*[])
|
||||
{
|
||||
sql::connection db;
|
||||
namespace sql = sqlpp::postgresql;
|
||||
namespace test = sqlpp::test;
|
||||
|
||||
test::test_normal_connection<sql::connection>(sql::make_test_config());
|
||||
return 0;
|
||||
}
|
@ -38,6 +38,7 @@ set(test_files
|
||||
FloatingPoint.cpp
|
||||
Integral.cpp
|
||||
Blob.cpp
|
||||
Connection.cpp
|
||||
ConnectionPool.cpp
|
||||
)
|
||||
|
||||
|
43
tests/sqlite3/usage/Connection.cpp
Normal file
43
tests/sqlite3/usage/Connection.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../../include/ConnectionTests.h"
|
||||
|
||||
#include <sqlpp11/sqlite3/connection.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
int Connection(int, char*[])
|
||||
{
|
||||
namespace sql = sqlpp::sqlite3;
|
||||
namespace test = sqlpp::test;
|
||||
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->path_to_database = ":memory:";
|
||||
config->flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
||||
config->debug = true;
|
||||
|
||||
test::test_normal_connection<sql::connection>(config);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user