mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-15 12:29:41 +08:00
Connection pools (#499)
Add support for connection pooling * Add support for connection pooling to the core code. * Add support for PostgreSQL connection pooling with tests. * Add support for SQLite3 connection pooling with tests. * Add support for MySQL connection pooling with tests.
This commit is contained in:
parent
a50d719364
commit
dff8c23b22
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -37,6 +38,44 @@ namespace sqlpp
|
||||
{
|
||||
namespace database
|
||||
{
|
||||
// Connection configuration that is used to create new database connections
|
||||
struct connection_config
|
||||
{
|
||||
// Put the configuration properties here, e.g.
|
||||
//
|
||||
// std::string host;
|
||||
// unsigned port;
|
||||
// std::string username;
|
||||
// std::string password;
|
||||
// std::string db_name;
|
||||
};
|
||||
|
||||
// The connection handle is a low-level representation of a database connection.
|
||||
// Pre-connected handles are stored in the connection pool and are used to create
|
||||
// full connection objects on request.
|
||||
class connection_handle
|
||||
{
|
||||
public:
|
||||
// Connection handles can be created from connection configurations
|
||||
connection_handle(const std::shared_ptr<const connection_config>& config);
|
||||
|
||||
// Connection handles cannot be copied
|
||||
connection_handle(const connection_handle&) = delete;
|
||||
connection_handle& operator=(const connection_handle&) = delete;
|
||||
|
||||
// Connection handles can be moved
|
||||
connection_handle(connection_handle&&);
|
||||
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();
|
||||
|
||||
// Optional method that returns a native (low-level) database handle.
|
||||
// Used by the test code to test the connection pool
|
||||
native_db_handle native_handle();
|
||||
};
|
||||
|
||||
// The context is not a requirement, but if the database requires
|
||||
// any deviations from the SQL standard, you should use your own
|
||||
// context in order to specialize the behaviour, see also interpreter.h
|
||||
@ -48,9 +87,25 @@ namespace sqlpp
|
||||
std::string escape(std::string arg);
|
||||
};
|
||||
|
||||
class connection : public sqlpp::connection // this inheritance helps with ADL for dynamic_select, for instance
|
||||
// The base database-specific connection class. Non-pooled and pooled connection classes derive from it
|
||||
class connection_base : public sqlpp::connection // this inheritance helps with ADL for dynamic_select, for instance
|
||||
{
|
||||
public:
|
||||
// Base configuration
|
||||
using _connection_base_t = connection_base;
|
||||
|
||||
// Type of configuration instances
|
||||
using _config_t = connection_config;
|
||||
|
||||
// Shared pointer wrapping a configuration instance
|
||||
using _config_ptr_t = std::shared_ptr<const _config_t>;
|
||||
|
||||
// Type of connection handles
|
||||
using _handle_t = connection_handle;
|
||||
|
||||
// Unique pointer wrapping a connection handle
|
||||
using _handle_ptr_t = std::unique_ptr<_handle_t>;
|
||||
|
||||
using _traits = ::sqlpp::make_traits<
|
||||
::sqlpp::no_value_t,
|
||||
::sqlpp::tag::enforce_null_result_treatment // If that is what you really want, leave it out otherwise
|
||||
@ -63,13 +118,6 @@ namespace sqlpp
|
||||
// serializer and interpreter are typically the same for string based connectors
|
||||
// the types are required for dynamic statement components, see sqlpp11/interpretable.h
|
||||
|
||||
connection(...);
|
||||
~connection();
|
||||
connection(const connection&) = delete;
|
||||
connection(connection&&) = delete;
|
||||
connection& operator=(const connection&) = delete;
|
||||
connection& operator=(connection&&) = delete;
|
||||
|
||||
//! "direct" select
|
||||
template <typename Select>
|
||||
<< bind_result_t >>
|
||||
@ -153,9 +201,26 @@ namespace sqlpp
|
||||
|
||||
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
||||
void report_rollback_failure(const std::string message) noexcept;
|
||||
|
||||
protected:
|
||||
// Low-level connection handle
|
||||
_handle_ptr_t _handle;
|
||||
|
||||
// The constructors are private because the base class instances are never created directly,
|
||||
// The constructors are called from the constructors of the derived classes
|
||||
connection_base() = default;
|
||||
connection_base(_handle_ptr_t&& handle) : _handle{std::move(handle)}
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Normal non-pooled connections.
|
||||
using connection = sqlpp::normal_connection<connection_base>;
|
||||
|
||||
// Pooled connections that are created by the thread pool
|
||||
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||
} // namespace database
|
||||
} // namespace sqlpp
|
||||
|
||||
#include <sqlpp11/database/interpreter.h>
|
||||
|
||||
|
39
connector_api/connection_pool.h
Normal file
39
connector_api/connection_pool.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/connection_pool.h>
|
||||
#include <sqlpp11/database/connection.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace database
|
||||
{
|
||||
using connection_pool = sqlpp::connection_pool<pooled_connection>;
|
||||
} // namespace database
|
||||
} // namespace sqlpp
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -27,11 +28,133 @@
|
||||
#ifndef SQLPP11_CONNECTION_H
|
||||
#define SQLPP11_CONNECTION_H
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
struct connection
|
||||
{
|
||||
};
|
||||
|
||||
// Normal (non-pooled) connection
|
||||
template<typename ConnectionBase>
|
||||
class normal_connection : public ConnectionBase
|
||||
{
|
||||
public:
|
||||
using _config_t = typename ConnectionBase::_config_t;
|
||||
using _config_ptr_t = typename ConnectionBase::_config_ptr_t;
|
||||
|
||||
// Constructors
|
||||
normal_connection() = default;
|
||||
normal_connection(const _config_t& config);
|
||||
normal_connection(const _config_ptr_t& config);
|
||||
normal_connection(const normal_connection&) = delete;
|
||||
normal_connection(normal_connection&&) = default;
|
||||
|
||||
// Assigment operators
|
||||
normal_connection& operator=(const normal_connection&) = delete;
|
||||
normal_connection& operator=(normal_connection&&) = default;
|
||||
|
||||
// creates a connection handle and connects to database
|
||||
void connectUsing(const _config_ptr_t& config) noexcept(false);
|
||||
|
||||
private:
|
||||
using _handle_t = typename ConnectionBase::_handle_t;
|
||||
};
|
||||
|
||||
template<typename ConnectionBase>
|
||||
normal_connection<ConnectionBase>::normal_connection(const _config_t& config) :
|
||||
normal_connection{std::make_shared<_config_t>(config)}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
normal_connection<ConnectionBase>::normal_connection(const _config_ptr_t& config) :
|
||||
ConnectionBase{std::make_unique<_handle_t>(config)}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
void normal_connection<ConnectionBase>::connectUsing(const _config_ptr_t& config) noexcept(false)
|
||||
{
|
||||
ConnectionBase::_handle = std::make_unique<_handle_t>(config);
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
template<typename ConnectionBase>
|
||||
class connection_pool;
|
||||
|
||||
// Pooled connection
|
||||
template<typename ConnectionBase>
|
||||
class pooled_connection : public ConnectionBase
|
||||
{
|
||||
friend class connection_pool<ConnectionBase>::pool_core;
|
||||
|
||||
public:
|
||||
using _config_ptr_t = typename ConnectionBase::_config_ptr_t;
|
||||
using _handle_t = typename ConnectionBase::_handle_t;
|
||||
using _handle_ptr_t = typename ConnectionBase::_handle_ptr_t;
|
||||
using _pool_core_ptr_t = std::shared_ptr<typename connection_pool<ConnectionBase>::pool_core>;
|
||||
|
||||
// Copy/Move constructors
|
||||
pooled_connection(const pooled_connection&) = delete;
|
||||
pooled_connection(pooled_connection&& other) = default;
|
||||
~pooled_connection();
|
||||
|
||||
// Assigment operators
|
||||
pooled_connection& operator=(const pooled_connection&) = delete;
|
||||
pooled_connection& operator=(pooled_connection&& other);
|
||||
|
||||
private:
|
||||
_pool_core_ptr_t _pool_core;
|
||||
|
||||
// Constructors used by the connection pool
|
||||
pooled_connection(_handle_ptr_t&& handle, _pool_core_ptr_t pool_core);
|
||||
pooled_connection(const _config_ptr_t& config, _pool_core_ptr_t pool_core);
|
||||
|
||||
void conn_release();
|
||||
};
|
||||
|
||||
template<typename ConnectionBase>
|
||||
pooled_connection<ConnectionBase>::~pooled_connection()
|
||||
{
|
||||
conn_release();
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
pooled_connection<ConnectionBase>& pooled_connection<ConnectionBase>::operator=(pooled_connection&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
conn_release();
|
||||
static_cast<ConnectionBase&>(*this) = std::move(static_cast<ConnectionBase&>(other));
|
||||
_pool_core = std::move(other._pool_core);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
pooled_connection<ConnectionBase>::pooled_connection(_handle_ptr_t&& handle, _pool_core_ptr_t pool_core) :
|
||||
ConnectionBase{std::move(handle)},
|
||||
_pool_core{pool_core}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
pooled_connection<ConnectionBase>::pooled_connection(const _config_ptr_t& config, _pool_core_ptr_t pool_core) :
|
||||
ConnectionBase{std::make_unique<_handle_t>(config)},
|
||||
_pool_core{pool_core}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
void pooled_connection<ConnectionBase>::conn_release()
|
||||
{
|
||||
if (_pool_core) {
|
||||
_pool_core->put(ConnectionBase::_handle);
|
||||
_pool_core = nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
151
include/sqlpp11/connection_pool.h
Normal file
151
include/sqlpp11/connection_pool.h
Normal file
@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <mutex>
|
||||
|
||||
#include <sqlpp11/detail/circular_buffer.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template<typename ConnectionBase>
|
||||
class connection_pool
|
||||
{
|
||||
public:
|
||||
using _config_ptr_t = typename ConnectionBase::_config_ptr_t;
|
||||
using _handle_ptr_t = typename ConnectionBase::_handle_ptr_t;
|
||||
using _pooled_connection_t = sqlpp::pooled_connection<ConnectionBase>;
|
||||
|
||||
class pool_core : public std::enable_shared_from_this<pool_core>
|
||||
{
|
||||
public:
|
||||
pool_core(const _config_ptr_t& connection_config, std::size_t capacity);
|
||||
pool_core() = delete;
|
||||
pool_core(const pool_core &) = delete;
|
||||
pool_core(pool_core &&) = delete;
|
||||
|
||||
pool_core& operator=(const pool_core&) = delete;
|
||||
pool_core& operator=(pool_core&&) = delete;
|
||||
|
||||
_pooled_connection_t get();
|
||||
void put(_handle_ptr_t& handle);
|
||||
// Returns number of connections available in the pool. Only used in tests.
|
||||
std::size_t available();
|
||||
|
||||
private:
|
||||
_config_ptr_t _connection_config;
|
||||
sqlpp::detail::circular_buffer<_handle_ptr_t> _handles;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
||||
connection_pool() = default;
|
||||
connection_pool(const _config_ptr_t& connection_config, std::size_t capacity);
|
||||
connection_pool(const connection_pool&) = delete;
|
||||
connection_pool(connection_pool&&) = default;
|
||||
|
||||
connection_pool& operator=(const connection_pool&) = delete;
|
||||
connection_pool& operator=(connection_pool&&) = default;
|
||||
|
||||
void initialize(const _config_ptr_t& connection_config, std::size_t capacity);
|
||||
_pooled_connection_t get();
|
||||
// Returns number of connections available in the pool. Only used in tests.
|
||||
std::size_t available();
|
||||
|
||||
private:
|
||||
std::shared_ptr<pool_core> _core;
|
||||
};
|
||||
|
||||
template<typename ConnectionBase>
|
||||
connection_pool<ConnectionBase>::pool_core::pool_core(const _config_ptr_t& connection_config, std::size_t capacity) :
|
||||
_connection_config{connection_config},
|
||||
_handles{capacity}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
typename connection_pool<ConnectionBase>::_pooled_connection_t connection_pool<ConnectionBase>::pool_core::get()
|
||||
{
|
||||
std::unique_lock lock{_mutex};
|
||||
if (_handles.empty()) {
|
||||
lock.unlock();
|
||||
return _pooled_connection_t{_connection_config, this->shared_from_this()};
|
||||
}
|
||||
auto handle = std::move(_handles.front());
|
||||
_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()};
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
void connection_pool<ConnectionBase>::pool_core::put(_handle_ptr_t& handle)
|
||||
{
|
||||
std::unique_lock lock{_mutex};
|
||||
if (_handles.full ()) {
|
||||
_handles.set_capacity (_handles.capacity () + 5);
|
||||
}
|
||||
_handles.push_back(std::move(handle));
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
std::size_t connection_pool<ConnectionBase>::pool_core::available()
|
||||
{
|
||||
std::unique_lock lock{_mutex};
|
||||
return _handles.size();
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
connection_pool<ConnectionBase>::connection_pool(const _config_ptr_t& connection_config, std::size_t capacity) :
|
||||
_core{std::make_shared<pool_core>(connection_config, capacity)}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
void connection_pool<ConnectionBase>::initialize(const _config_ptr_t& connection_config, std::size_t capacity)
|
||||
{
|
||||
if (_core) {
|
||||
throw std::runtime_error{"Connection pool already initialized"};
|
||||
}
|
||||
_core = std::make_shared<pool_core>(connection_config, capacity);
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
typename connection_pool<ConnectionBase>::_pooled_connection_t connection_pool<ConnectionBase>::get()
|
||||
{
|
||||
return _core->get();
|
||||
}
|
||||
|
||||
template<typename ConnectionBase>
|
||||
std::size_t connection_pool<ConnectionBase>::available()
|
||||
{
|
||||
return _core->available();
|
||||
}
|
||||
} // namespace sqlpp
|
162
include/sqlpp11/detail/circular_buffer.h
Normal file
162
include/sqlpp11/detail/circular_buffer.h
Normal file
@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// This class is modelled after boost::circular_buffer
|
||||
template <typename T>
|
||||
class circular_buffer
|
||||
{
|
||||
public:
|
||||
circular_buffer(std::size_t capacity);
|
||||
std::size_t capacity() const;
|
||||
void set_capacity(std::size_t capacity);
|
||||
std::size_t size() const;
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
T& front();
|
||||
void pop_front();
|
||||
void push_back(T&& t);
|
||||
|
||||
private:
|
||||
std::vector<T> _data;
|
||||
std::size_t _capacity;
|
||||
std::size_t _size;
|
||||
std::size_t _head;
|
||||
std::size_t _tail;
|
||||
|
||||
void increment(std::size_t& pos);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
circular_buffer<T>::circular_buffer(std::size_t capacity) :
|
||||
_data(capacity),
|
||||
_capacity{capacity},
|
||||
_size{0},
|
||||
_head{0},
|
||||
_tail{0}
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t circular_buffer<T>::capacity() const
|
||||
{
|
||||
return _capacity;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void circular_buffer<T>::set_capacity(std::size_t capacity)
|
||||
{
|
||||
if (capacity == _capacity) {
|
||||
return;
|
||||
}
|
||||
if (_tail >= _head) {
|
||||
if (empty () == false) {
|
||||
std::rotate(_data.begin(), _data.begin()+_tail, _data.end());
|
||||
}
|
||||
_head = (capacity > _size) ? _size : 0;
|
||||
_tail = 0;
|
||||
} else {
|
||||
if (capacity < _head) {
|
||||
std::rotate(_data.begin(), _data.begin()+_tail, _data.begin()+_head);
|
||||
_head = (capacity > _size) ? _size : 0;
|
||||
_tail = 0;
|
||||
} else if (capacity == _head) {
|
||||
_head = 0;
|
||||
}
|
||||
}
|
||||
_data.resize(capacity);
|
||||
_capacity = capacity;
|
||||
if (_size > capacity) {
|
||||
_size = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t circular_buffer<T>::size() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_buffer<T>::empty() const
|
||||
{
|
||||
return _size == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_buffer<T>::full() const
|
||||
{
|
||||
return _size == _capacity;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& circular_buffer<T>::front()
|
||||
{
|
||||
if (empty()) {
|
||||
throw std::runtime_error{"circular_buffer::front() called on empty buffer"};
|
||||
}
|
||||
return _data[_tail];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void circular_buffer<T>::pop_front()
|
||||
{
|
||||
if (empty()) {
|
||||
throw std::runtime_error{"circular_buffer::pop_front() called on empty buffer"};
|
||||
}
|
||||
_data[_tail] = {};
|
||||
increment(_tail);
|
||||
--_size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void circular_buffer<T>::push_back(T&& t)
|
||||
{
|
||||
if (full()) {
|
||||
throw std::runtime_error{"circular_buffer::push_back() called on full buffer"};
|
||||
}
|
||||
_data[_head] = std::move(t);
|
||||
increment(_head);
|
||||
++_size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void circular_buffer<T>::increment(std::size_t& pos)
|
||||
{
|
||||
pos = (pos + 1) % _capacity;
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace sqlpp
|
@ -51,7 +51,7 @@ namespace sqlpp
|
||||
template <typename Db,
|
||||
typename Expr,
|
||||
typename std::enable_if<not std::is_convertible<Expr, std::string>::value, int>::type = 0>
|
||||
auto eval(Db& db, Expr expr) -> typename eval_t<Db, Expr>::type
|
||||
auto eval(Db& db, Expr expr) -> typename eval_t<typename Db::_connection_base_t, Expr>::type
|
||||
{
|
||||
return db(select(expr.as(alias::a))).front().a;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2017, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -104,11 +105,12 @@ namespace sqlpp
|
||||
|
||||
struct connection_handle_t
|
||||
{
|
||||
std::shared_ptr<connection_config> config;
|
||||
std::shared_ptr<const connection_config> config;
|
||||
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
|
||||
|
||||
connection_handle_t(const std::shared_ptr<connection_config>& conf)
|
||||
: config(conf), mysql(mysql_init(nullptr), handle_cleanup)
|
||||
connection_handle_t(const std::shared_ptr<const connection_config>& conf) :
|
||||
config(conf),
|
||||
mysql(mysql_init(nullptr), handle_cleanup)
|
||||
{
|
||||
if (not mysql)
|
||||
{
|
||||
@ -118,43 +120,48 @@ namespace sqlpp
|
||||
if (config->auto_reconnect)
|
||||
{
|
||||
my_bool my_true = true;
|
||||
if (mysql_options(mysql.get(), MYSQL_OPT_RECONNECT, &my_true))
|
||||
if (mysql_options(native_handle(), MYSQL_OPT_RECONNECT, &my_true))
|
||||
{
|
||||
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_RECONNECT");
|
||||
}
|
||||
}
|
||||
|
||||
connect(mysql.get(), *config);
|
||||
connect(native_handle(), *config);
|
||||
}
|
||||
|
||||
~connection_handle_t() noexcept = default;
|
||||
connection_handle_t(const connection_handle_t&) = delete;
|
||||
connection_handle_t(connection_handle_t&&) = default;
|
||||
connection_handle_t& operator=(const connection_handle_t&) = delete;
|
||||
connection_handle_t& operator=(connection_handle_t&&) = default;
|
||||
|
||||
bool is_valid()
|
||||
MYSQL* native_handle() const
|
||||
{
|
||||
return mysql_ping(mysql.get()) == 0;
|
||||
return mysql.get();
|
||||
}
|
||||
|
||||
bool check_connection() const
|
||||
{
|
||||
auto nh = native_handle();
|
||||
return nh && (mysql_ping(nh) == 0);
|
||||
}
|
||||
|
||||
void reconnect()
|
||||
{
|
||||
connect(mysql.get(), *config);
|
||||
connect(native_handle(), *config);
|
||||
}
|
||||
};
|
||||
|
||||
inline void execute_statement(detail::connection_handle_t& handle, const std::string& statement)
|
||||
inline void execute_statement(std::unique_ptr<connection_handle_t>& handle, const std::string& statement)
|
||||
{
|
||||
thread_init();
|
||||
|
||||
if (handle.config->debug)
|
||||
if (handle->config->debug)
|
||||
std::cerr << "MySQL debug: Executing: '" << statement << "'" << std::endl;
|
||||
|
||||
if (mysql_query(handle.mysql.get(), statement.c_str()))
|
||||
if (mysql_query(handle->native_handle(), statement.c_str()))
|
||||
{
|
||||
throw sqlpp::exception(
|
||||
"MySQL error: Could not execute MySQL-statement: " + std::string(mysql_error(handle.mysql.get())) +
|
||||
"MySQL error: Could not execute MySQL-statement: " + std::string(mysql_error(handle->native_handle())) +
|
||||
" (statement was >>" + statement + "<<\n");
|
||||
}
|
||||
}
|
||||
@ -179,18 +186,18 @@ namespace sqlpp
|
||||
}
|
||||
}
|
||||
|
||||
inline std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle_t& handle,
|
||||
inline std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(std::unique_ptr<connection_handle_t>& handle,
|
||||
const std::string& statement,
|
||||
size_t no_of_parameters,
|
||||
size_t no_of_columns)
|
||||
{
|
||||
thread_init();
|
||||
|
||||
if (handle.config->debug)
|
||||
if (handle->config->debug)
|
||||
std::cerr << "MySQL debug: Preparing: '" << statement << "'" << std::endl;
|
||||
|
||||
auto prepared_statement = std::make_shared<detail::prepared_statement_handle_t>(
|
||||
mysql_stmt_init(handle.mysql.get()), no_of_parameters, no_of_columns, handle.config->debug);
|
||||
mysql_stmt_init(handle->native_handle()), no_of_parameters, no_of_columns, handle->config->debug);
|
||||
if (not prepared_statement)
|
||||
{
|
||||
throw sqlpp::exception("MySQL error: Could not allocate prepared statement\n");
|
||||
@ -198,7 +205,7 @@ namespace sqlpp
|
||||
if (mysql_stmt_prepare(prepared_statement->mysql_stmt, statement.data(), statement.size()))
|
||||
{
|
||||
throw sqlpp::exception(
|
||||
"MySQL error: Could not prepare statement: " + std::string(mysql_error(handle.mysql.get())) +
|
||||
"MySQL error: Could not prepare statement: " + std::string(mysql_error(handle->native_handle())) +
|
||||
" (statement was >>" + statement + "<<\n");
|
||||
}
|
||||
|
||||
@ -226,13 +233,15 @@ namespace sqlpp
|
||||
static const auto global_init_and_end = scoped_library_initializer_t(argc, argv, groups);
|
||||
}
|
||||
|
||||
class connection;
|
||||
// Forward declaration
|
||||
class connection_base;
|
||||
|
||||
struct serializer_t
|
||||
{
|
||||
serializer_t(const connection& db) : _db(db)
|
||||
serializer_t(const connection_base& db) : _db(db)
|
||||
{
|
||||
}
|
||||
serializer_t(const connection_base&&) = delete;
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(T t)
|
||||
@ -247,7 +256,7 @@ namespace sqlpp
|
||||
return _os.str();
|
||||
}
|
||||
|
||||
const connection& _db;
|
||||
const connection_base& _db;
|
||||
sqlpp::detail::float_safe_ostringstream _os;
|
||||
};
|
||||
|
||||
@ -255,9 +264,9 @@ namespace sqlpp
|
||||
|
||||
std::integral_constant<char, '`'> get_quote_right(const serializer_t&);
|
||||
|
||||
class connection : public sqlpp::connection
|
||||
class connection_base : public sqlpp::connection
|
||||
{
|
||||
detail::connection_handle_t _handle;
|
||||
private:
|
||||
bool _transaction_active = false;
|
||||
|
||||
// direct execution
|
||||
@ -265,11 +274,11 @@ namespace sqlpp
|
||||
{
|
||||
execute_statement(_handle, statement);
|
||||
std::unique_ptr<detail::result_handle> result_handle(
|
||||
new detail::result_handle(mysql_store_result(_handle.mysql.get()), _handle.config->debug));
|
||||
new detail::result_handle(mysql_store_result(_handle->native_handle()), _handle->config->debug));
|
||||
if (!*result_handle)
|
||||
{
|
||||
throw sqlpp::exception("MySQL error: Could not store result set: " +
|
||||
std::string(mysql_error(_handle.mysql.get())));
|
||||
std::string(mysql_error(_handle->native_handle())));
|
||||
}
|
||||
|
||||
return {std::move(result_handle)};
|
||||
@ -279,19 +288,19 @@ namespace sqlpp
|
||||
{
|
||||
execute_statement(_handle, statement);
|
||||
|
||||
return mysql_insert_id(_handle.mysql.get());
|
||||
return mysql_insert_id(_handle->native_handle());
|
||||
}
|
||||
|
||||
size_t update_impl(const std::string& statement)
|
||||
{
|
||||
execute_statement(_handle, statement);
|
||||
return mysql_affected_rows(_handle.mysql.get());
|
||||
return mysql_affected_rows(_handle->native_handle());
|
||||
}
|
||||
|
||||
size_t remove_impl(const std::string& statement)
|
||||
{
|
||||
execute_statement(_handle, statement);
|
||||
return mysql_affected_rows(_handle.mysql.get());
|
||||
return mysql_affected_rows(_handle->native_handle());
|
||||
}
|
||||
|
||||
// prepared execution
|
||||
@ -325,6 +334,12 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
public:
|
||||
using _connection_base_t = connection_base;
|
||||
using _config_t = connection_config;
|
||||
using _config_ptr_t = std::shared_ptr<const _config_t>;
|
||||
using _handle_t = detail::connection_handle_t;
|
||||
using _handle_ptr_t = std::unique_ptr<_handle_t>;
|
||||
|
||||
using _prepared_statement_t = ::sqlpp::mysql::prepared_statement_t;
|
||||
using _context_t = serializer_t;
|
||||
using _serializer_context_t = _context_t;
|
||||
@ -347,30 +362,19 @@ namespace sqlpp
|
||||
return serialize(t, context);
|
||||
}
|
||||
|
||||
connection(const std::shared_ptr<connection_config>& config) : _handle{config}
|
||||
bool is_valid() const
|
||||
{
|
||||
}
|
||||
|
||||
~connection() = default;
|
||||
|
||||
connection(const connection&) = delete;
|
||||
connection& operator=(const connection&) = delete;
|
||||
connection& operator=(connection&&) = default;
|
||||
connection(connection&& other) = default;
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
return _handle.is_valid();
|
||||
return _handle->check_connection();
|
||||
}
|
||||
|
||||
void reconnect()
|
||||
{
|
||||
return _handle.reconnect();
|
||||
return _handle->reconnect();
|
||||
}
|
||||
|
||||
const std::shared_ptr<connection_config>& get_config()
|
||||
const std::shared_ptr<const connection_config>& get_config()
|
||||
{
|
||||
return _handle.config;
|
||||
return _handle->config;
|
||||
}
|
||||
|
||||
bool is_transaction_active()
|
||||
@ -483,7 +487,7 @@ namespace sqlpp
|
||||
std::string escape(const std::string& s) const
|
||||
{
|
||||
std::unique_ptr<char[]> dest(new char[s.size() * 2 + 1]);
|
||||
mysql_real_escape_string(_handle.mysql.get(), dest.get(), s.c_str(), s.size());
|
||||
mysql_real_escape_string(_handle->native_handle(), dest.get(), s.c_str(), s.size());
|
||||
return dest.get();
|
||||
}
|
||||
|
||||
@ -569,16 +573,35 @@ namespace sqlpp
|
||||
std::cerr << "MySQL message:" << message << std::endl;
|
||||
}
|
||||
|
||||
MYSQL* native_handle()
|
||||
{
|
||||
return _handle->native_handle();
|
||||
}
|
||||
|
||||
// Kept for compatibility with old code
|
||||
MYSQL* get_handle()
|
||||
{
|
||||
return _handle.mysql.get();
|
||||
return native_handle();
|
||||
}
|
||||
|
||||
protected:
|
||||
_handle_ptr_t _handle;
|
||||
|
||||
// Constructors
|
||||
connection_base() = default;
|
||||
connection_base(_handle_ptr_t&& handle) : _handle{std::move(handle)}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Method definition moved outside of class because it needs connection_base
|
||||
inline std::string serializer_t::escape(std::string arg)
|
||||
{
|
||||
return _db.escape(arg);
|
||||
}
|
||||
|
||||
using connection = sqlpp::normal_connection<connection_base>;
|
||||
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||
} // namespace mysql
|
||||
} // namespace sqlpp
|
||||
|
||||
|
@ -33,10 +33,8 @@ namespace sqlpp
|
||||
{
|
||||
namespace mysql
|
||||
{
|
||||
class connection;
|
||||
struct connection_config
|
||||
{
|
||||
typedef ::sqlpp::mysql::connection connection;
|
||||
std::string host = "localhost";
|
||||
std::string user;
|
||||
std::string password;
|
||||
|
39
include/sqlpp11/mysql/connection_pool.h
Normal file
39
include/sqlpp11/mysql/connection_pool.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/connection_pool.h>
|
||||
#include <sqlpp11/mysql/connection.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace mysql
|
||||
{
|
||||
using connection_pool = sqlpp::connection_pool<connection_base>;
|
||||
} // namespace mysql
|
||||
} // namespace sqlpp
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2015, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -28,6 +29,7 @@
|
||||
#define SQLPP_MYSQL_H
|
||||
|
||||
#include <sqlpp11/mysql/connection.h>
|
||||
#include <sqlpp11/mysql/connection_pool.h>
|
||||
#include <sqlpp11/mysql/char_result.h>
|
||||
|
||||
#endif
|
||||
|
@ -41,11 +41,11 @@ namespace sqlpp
|
||||
{
|
||||
namespace mysql
|
||||
{
|
||||
class connection;
|
||||
class connection_base;
|
||||
|
||||
class prepared_statement_t
|
||||
{
|
||||
friend ::sqlpp::mysql::connection;
|
||||
friend ::sqlpp::mysql::connection_base;
|
||||
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||
|
||||
public:
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Copyright © 2014-2015, Matthijs Möhlmann
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -63,39 +64,39 @@ namespace sqlpp
|
||||
namespace detail
|
||||
{
|
||||
// Forward declaration
|
||||
inline std::unique_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle& handle,
|
||||
inline std::unique_ptr<detail::prepared_statement_handle_t> prepare_statement(std::unique_ptr<connection_handle>& handle,
|
||||
const std::string& stmt,
|
||||
const size_t& paramCount)
|
||||
{
|
||||
if (handle.config->debug)
|
||||
if (handle->config->debug)
|
||||
{
|
||||
std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
|
||||
}
|
||||
|
||||
return std::unique_ptr<detail::prepared_statement_handle_t>(new detail::prepared_statement_handle_t
|
||||
(handle, stmt, paramCount));
|
||||
return std::unique_ptr<detail::prepared_statement_handle_t>(new detail::prepared_statement_handle_t
|
||||
(*handle, stmt, paramCount));
|
||||
}
|
||||
|
||||
inline void execute_prepared_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared)
|
||||
inline void execute_prepared_statement(std::unique_ptr<connection_handle>& handle, std::shared_ptr<detail::prepared_statement_handle_t>& prepared)
|
||||
{
|
||||
if (handle.config->debug)
|
||||
if (handle->config->debug)
|
||||
{
|
||||
std::cerr << "PostgreSQL debug: executing: " << prepared.name() << std::endl;
|
||||
std::cerr << "PostgreSQL debug: executing: " << prepared->name() << std::endl;
|
||||
}
|
||||
prepared.execute();
|
||||
prepared->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
class connection;
|
||||
class connection_base;
|
||||
|
||||
// Context
|
||||
struct context_t
|
||||
{
|
||||
context_t(const connection& db) : _db(db)
|
||||
context_t(const connection_base& db) : _db(db)
|
||||
{
|
||||
}
|
||||
context_t(const connection&&) = delete;
|
||||
context_t(const connection_base&&) = delete;
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(T t)
|
||||
@ -108,7 +109,7 @@ namespace sqlpp
|
||||
return _os << (t ? "TRUE" : "FALSE");
|
||||
}
|
||||
|
||||
std::string escape(const std::string& arg);
|
||||
std::string escape(const std::string& arg) const;
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
@ -125,22 +126,22 @@ namespace sqlpp
|
||||
++_count;
|
||||
}
|
||||
|
||||
const connection& _db;
|
||||
const connection_base& _db;
|
||||
sqlpp::detail::float_safe_ostringstream _os;
|
||||
size_t _count{1};
|
||||
};
|
||||
|
||||
// Connection
|
||||
class connection : public sqlpp::connection
|
||||
// Base connection class
|
||||
class connection_base : public sqlpp::connection
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<detail::connection_handle> _handle;
|
||||
bool _transaction_active{false};
|
||||
|
||||
void validate_connection_handle() const
|
||||
{
|
||||
if (!_handle)
|
||||
if (!_handle) {
|
||||
throw std::logic_error("connection handle used, but not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
// direct execution
|
||||
@ -158,6 +159,12 @@ namespace sqlpp
|
||||
size_t run_prepared_remove_impl(prepared_statement_t& prep);
|
||||
|
||||
public:
|
||||
using _connection_base_t = connection_base;
|
||||
using _config_t = connection_config;
|
||||
using _config_ptr_t = std::shared_ptr<const _config_t>;
|
||||
using _handle_t = detail::connection_handle;
|
||||
using _handle_ptr_t = std::unique_ptr<_handle_t>;
|
||||
|
||||
using _prepared_statement_t = prepared_statement_t;
|
||||
using _context_t = context_t;
|
||||
using _serializer_context_t = _context_t;
|
||||
@ -180,18 +187,6 @@ namespace sqlpp
|
||||
return ::sqlpp::serialize(t, context);
|
||||
}
|
||||
|
||||
// ctor / dtor
|
||||
connection();
|
||||
connection(const std::shared_ptr<const connection_config>& config);
|
||||
~connection();
|
||||
connection(const connection&) = delete;
|
||||
connection(connection&&);
|
||||
connection& operator=(const connection&) = delete;
|
||||
connection& operator=(connection&&);
|
||||
|
||||
// creates a connection handle and connects to database
|
||||
void connectUsing(const std::shared_ptr<const connection_config>& config) noexcept(false);
|
||||
|
||||
// Select stmt (returns a result)
|
||||
template <typename Select>
|
||||
bind_result_t select(const Select& s)
|
||||
@ -384,45 +379,19 @@ namespace sqlpp
|
||||
//! get the last inserted id for a certain table
|
||||
uint64_t last_insert_id(const std::string& table, const std::string& fieldname);
|
||||
|
||||
::PGconn* native_handle();
|
||||
::PGconn* native_handle() const;
|
||||
|
||||
protected:
|
||||
_handle_ptr_t _handle;
|
||||
|
||||
// Constructors
|
||||
connection_base() = default;
|
||||
connection_base(_handle_ptr_t&& handle) : _handle{std::move(handle)}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline connection::connection() : _handle()
|
||||
{
|
||||
}
|
||||
|
||||
inline connection::connection(const std::shared_ptr<const connection_config>& config)
|
||||
: _handle(new detail::connection_handle(config))
|
||||
{
|
||||
}
|
||||
|
||||
inline connection::~connection()
|
||||
{
|
||||
}
|
||||
|
||||
inline connection::connection(connection&& other)
|
||||
{
|
||||
this->_transaction_active = other._transaction_active;
|
||||
this->_handle = std::move(other._handle);
|
||||
}
|
||||
|
||||
inline connection& connection::operator=(connection&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
// TODO: check this logic
|
||||
this->_transaction_active = other._transaction_active;
|
||||
this->_handle = std::move(other._handle);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void connection::connectUsing(const std::shared_ptr<const connection_config>& config) noexcept(false)
|
||||
{
|
||||
this->_handle.reset(new detail::connection_handle(config));
|
||||
}
|
||||
|
||||
inline std::shared_ptr<detail::statement_handle_t> connection::execute(const std::string& stmt)
|
||||
inline std::shared_ptr<detail::statement_handle_t> connection_base::execute(const std::string& stmt)
|
||||
{
|
||||
validate_connection_handle();
|
||||
if (_handle->config->debug)
|
||||
@ -431,75 +400,76 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
auto result = std::make_shared<detail::statement_handle_t>(*_handle);
|
||||
result->result = PQexec(_handle->native(), stmt.c_str());
|
||||
result->result = PQexec(native_handle(), stmt.c_str());
|
||||
result->valid = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// direct execution
|
||||
inline bind_result_t connection::select_impl(const std::string& stmt)
|
||||
inline bind_result_t connection_base::select_impl(const std::string& stmt)
|
||||
{
|
||||
return execute(stmt);
|
||||
}
|
||||
|
||||
inline size_t connection::insert_impl(const std::string& stmt)
|
||||
inline size_t connection_base::insert_impl(const std::string& stmt)
|
||||
{
|
||||
return static_cast<size_t>(execute(stmt)->result.affected_rows());
|
||||
}
|
||||
|
||||
inline size_t connection::update_impl(const std::string& stmt)
|
||||
inline size_t connection_base::update_impl(const std::string& stmt)
|
||||
{
|
||||
return static_cast<size_t>(execute(stmt)->result.affected_rows());
|
||||
}
|
||||
|
||||
inline size_t connection::remove_impl(const std::string& stmt)
|
||||
inline size_t connection_base::remove_impl(const std::string& stmt)
|
||||
{
|
||||
return static_cast<size_t>(execute(stmt)->result.affected_rows());
|
||||
}
|
||||
|
||||
// prepared execution
|
||||
inline prepared_statement_t connection::prepare_impl(const std::string& stmt, const size_t& paramCount)
|
||||
inline prepared_statement_t connection_base::prepare_impl(const std::string& stmt, const size_t& paramCount)
|
||||
{
|
||||
validate_connection_handle();
|
||||
return {prepare_statement(*_handle, stmt, paramCount)};
|
||||
return {prepare_statement(_handle, stmt, paramCount)};
|
||||
}
|
||||
|
||||
inline bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prep)
|
||||
inline bind_result_t connection_base::run_prepared_select_impl(prepared_statement_t& prep)
|
||||
{
|
||||
validate_connection_handle();
|
||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
||||
execute_prepared_statement(_handle, prep._handle);
|
||||
return {prep._handle};
|
||||
}
|
||||
|
||||
inline size_t connection::run_prepared_execute_impl(prepared_statement_t& prep)
|
||||
inline size_t connection_base::run_prepared_execute_impl(prepared_statement_t& prep)
|
||||
{
|
||||
validate_connection_handle();
|
||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
||||
execute_prepared_statement(_handle, prep._handle);
|
||||
return static_cast<size_t>(prep._handle->result.affected_rows());
|
||||
}
|
||||
|
||||
inline size_t connection::run_prepared_insert_impl(prepared_statement_t& prep)
|
||||
inline size_t connection_base::run_prepared_insert_impl(prepared_statement_t& prep)
|
||||
{
|
||||
validate_connection_handle();
|
||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
||||
execute_prepared_statement(_handle, prep._handle);
|
||||
return static_cast<size_t>(prep._handle->result.affected_rows());
|
||||
}
|
||||
|
||||
inline size_t connection::run_prepared_update_impl(prepared_statement_t& prep)
|
||||
inline size_t connection_base::run_prepared_update_impl(prepared_statement_t& prep)
|
||||
{
|
||||
validate_connection_handle();
|
||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
||||
execute_prepared_statement(_handle, prep._handle);
|
||||
return static_cast<size_t>(prep._handle->result.affected_rows());
|
||||
}
|
||||
|
||||
inline size_t connection::run_prepared_remove_impl(prepared_statement_t& prep)
|
||||
inline size_t connection_base::run_prepared_remove_impl(prepared_statement_t& prep)
|
||||
{
|
||||
validate_connection_handle();
|
||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
||||
execute_prepared_statement(_handle, prep._handle);
|
||||
return static_cast<size_t>(prep._handle->result.affected_rows());
|
||||
}
|
||||
|
||||
inline void connection::set_default_isolation_level(isolation_level level)
|
||||
inline void connection_base::set_default_isolation_level(isolation_level level)
|
||||
{
|
||||
std::string level_str = "read uncommmitted";
|
||||
switch (level)
|
||||
@ -524,7 +494,8 @@ namespace sqlpp
|
||||
execute(cmd);
|
||||
}
|
||||
|
||||
inline isolation_level connection::get_default_isolation_level()
|
||||
//! get the currently set default transaction isolation level
|
||||
inline isolation_level connection_base::get_default_isolation_level()
|
||||
{
|
||||
auto res = execute("SHOW default_transaction_isolation;");
|
||||
auto status = res->result.status();
|
||||
@ -554,7 +525,7 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
// TODO: Fix escaping.
|
||||
inline std::string connection::escape(const std::string& s) const
|
||||
inline std::string connection_base::escape(const std::string& s) const
|
||||
{
|
||||
validate_connection_handle();
|
||||
// Escape strings
|
||||
@ -562,13 +533,13 @@ namespace sqlpp
|
||||
result.resize((s.size() * 2) + 1);
|
||||
|
||||
int err;
|
||||
size_t length = PQescapeStringConn(_handle->native(), &result[0], s.c_str(), s.size(), &err);
|
||||
size_t length = PQescapeStringConn(native_handle(), &result[0], s.c_str(), s.size(), &err);
|
||||
result.resize(length);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! start transaction
|
||||
inline void connection::start_transaction(sqlpp::isolation_level level)
|
||||
inline void connection_base::start_transaction(isolation_level level)
|
||||
{
|
||||
if (_transaction_active)
|
||||
{
|
||||
@ -606,28 +577,28 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
//! create savepoint
|
||||
inline void connection::savepoint(const std::string& name)
|
||||
inline void connection_base::savepoint(const std::string& name)
|
||||
{
|
||||
/// NOTE prevent from sql injection?
|
||||
execute("SAVEPOINT " + name);
|
||||
}
|
||||
|
||||
//! ROLLBACK TO SAVEPOINT
|
||||
inline void connection::rollback_to_savepoint(const std::string& name)
|
||||
inline void connection_base::rollback_to_savepoint(const std::string& name)
|
||||
{
|
||||
/// NOTE prevent from sql injection?
|
||||
execute("ROLLBACK TO SAVEPOINT " + name);
|
||||
}
|
||||
|
||||
//! release_savepoint
|
||||
inline void connection::release_savepoint(const std::string& name)
|
||||
inline void connection_base::release_savepoint(const std::string& name)
|
||||
{
|
||||
/// NOTE prevent from sql injection?
|
||||
execute("RELEASE SAVEPOINT " + name);
|
||||
}
|
||||
|
||||
//! commit transaction (or throw transaction if transaction has finished already)
|
||||
inline void connection::commit_transaction()
|
||||
inline void connection_base::commit_transaction()
|
||||
{
|
||||
if (!_transaction_active)
|
||||
{
|
||||
@ -639,7 +610,7 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
//! rollback transaction
|
||||
inline void connection::rollback_transaction(bool report)
|
||||
inline void connection_base::rollback_transaction(bool report)
|
||||
{
|
||||
if (!_transaction_active)
|
||||
{
|
||||
@ -655,15 +626,15 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
//! report rollback failure
|
||||
inline void connection::report_rollback_failure(const std::string& message) noexcept
|
||||
inline void connection_base::report_rollback_failure(const std::string& message) noexcept
|
||||
{
|
||||
std::cerr << "PostgreSQL error: " << message << std::endl;
|
||||
}
|
||||
|
||||
inline uint64_t connection::last_insert_id(const std::string& table, const std::string& fieldname)
|
||||
inline uint64_t connection_base::last_insert_id(const std::string& table, const std::string& fieldname)
|
||||
{
|
||||
std::string sql = "SELECT currval('" + table + "_" + fieldname + "_seq')";
|
||||
PGresult* res = PQexec(_handle->native(), sql.c_str());
|
||||
PGresult* res = PQexec(native_handle(), sql.c_str());
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
std::string err{PQresultErrorMessage(res)};
|
||||
@ -677,17 +648,20 @@ namespace sqlpp
|
||||
return std::stoul(in);
|
||||
}
|
||||
|
||||
inline ::PGconn* connection::native_handle()
|
||||
inline ::PGconn* connection_base::native_handle() const
|
||||
{
|
||||
return _handle->native();
|
||||
return _handle->native_handle();
|
||||
}
|
||||
|
||||
inline std::string context_t::escape(const std::string& arg)
|
||||
inline std::string context_t::escape(const std::string& arg) const
|
||||
{
|
||||
return _db.escape(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using connection = sqlpp::normal_connection<connection_base>;
|
||||
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||
} // namespace postgresql
|
||||
} // namespace sqlpp
|
||||
|
||||
#include <sqlpp11/postgresql/serializer.h>
|
||||
|
||||
|
@ -35,12 +35,8 @@ namespace sqlpp
|
||||
{
|
||||
namespace postgresql
|
||||
{
|
||||
class connection;
|
||||
struct DLL_PUBLIC connection_config
|
||||
{
|
||||
// Needed for the connection pool
|
||||
typedef ::sqlpp::postgresql::connection connection;
|
||||
|
||||
enum class sslmode_t
|
||||
{
|
||||
disable,
|
||||
|
39
include/sqlpp11/postgresql/connection_pool.h
Normal file
39
include/sqlpp11/postgresql/connection_pool.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/connection_pool.h>
|
||||
#include <sqlpp11/postgresql/connection.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace postgresql
|
||||
{
|
||||
using connection_pool = sqlpp::connection_pool<connection_base>;
|
||||
} // namespace postgresql
|
||||
} // namespace sqlpp
|
@ -67,16 +67,13 @@ namespace sqlpp
|
||||
connection_handle(const std::shared_ptr<const connection_config>& config);
|
||||
connection_handle(const connection_handle&) = delete;
|
||||
connection_handle(connection_handle&&) = default;
|
||||
~connection_handle();
|
||||
connection_handle& operator=(const connection_handle&) = delete;
|
||||
connection_handle& operator=(connection_handle&&) = default;
|
||||
~connection_handle();
|
||||
|
||||
PGconn* native() const
|
||||
{
|
||||
return postgres.get();
|
||||
}
|
||||
|
||||
void deallocate_prepared_statement(const std::string& name);
|
||||
PGconn* native_handle() const;
|
||||
bool check_connection() const;
|
||||
};
|
||||
|
||||
inline connection_handle::connection_handle(const std::shared_ptr<const connection_config>& conf)
|
||||
@ -206,9 +203,9 @@ namespace sqlpp
|
||||
if (!postgres)
|
||||
throw std::bad_alloc();
|
||||
|
||||
if (PQstatus(postgres.get()) != CONNECTION_OK)
|
||||
if (check_connection() == false)
|
||||
{
|
||||
std::string msg(PQerrorMessage(postgres.get()));
|
||||
std::string msg(PQerrorMessage(native_handle()));
|
||||
throw broken_connection(std::move(msg));
|
||||
}
|
||||
}
|
||||
@ -225,10 +222,21 @@ namespace sqlpp
|
||||
inline void connection_handle::deallocate_prepared_statement(const std::string& name)
|
||||
{
|
||||
std::string cmd = "DEALLOCATE \"" + name + "\"";
|
||||
PGresult* result = PQexec(postgres.get(), cmd.c_str());
|
||||
PGresult* result = PQexec(native_handle(), cmd.c_str());
|
||||
PQclear(result);
|
||||
prepared_statement_names.erase(name);
|
||||
}
|
||||
|
||||
inline PGconn* connection_handle::native_handle() const
|
||||
{
|
||||
return postgres.get();
|
||||
}
|
||||
|
||||
inline bool connection_handle::check_connection() const
|
||||
{
|
||||
auto nh = native_handle();
|
||||
return nh && (PQstatus(nh) == CONNECTION_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ namespace sqlpp
|
||||
valid = false;
|
||||
count = 0;
|
||||
totalCount = 0;
|
||||
result = PQexecPrepared(connection.native(), _name.data(), static_cast<int>(size), values.data(), nullptr, nullptr, 0);
|
||||
result = PQexecPrepared(connection.native_handle(), _name.data(), static_cast<int>(size), values.data(), nullptr, nullptr, 0);
|
||||
/// @todo validate result? is it really valid
|
||||
valid = true;
|
||||
}
|
||||
@ -188,7 +188,7 @@ namespace sqlpp
|
||||
inline void prepared_statement_handle_t::prepare(std::string stmt)
|
||||
{
|
||||
// Create the prepared statement
|
||||
result = PQprepare(connection.native(), _name.c_str(), stmt.c_str(), 0, nullptr);
|
||||
result = PQprepare(connection.native_handle(), _name.c_str(), stmt.c_str(), 0, nullptr);
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Copyright © 2014-2015, Matthijs Möhlmann
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,6 +30,7 @@
|
||||
#define SQLPP_POSTGRESQL_H
|
||||
|
||||
#include <sqlpp11/postgresql/connection.h>
|
||||
#include <sqlpp11/postgresql/connection_pool.h>
|
||||
#include <sqlpp11/postgresql/exception.h>
|
||||
#include <sqlpp11/postgresql/insert.h>
|
||||
#include <sqlpp11/postgresql/update.h>
|
||||
|
@ -44,7 +44,7 @@ namespace sqlpp
|
||||
#endif
|
||||
|
||||
// Forward declaration
|
||||
class connection;
|
||||
class connection_base;
|
||||
|
||||
// Detail namespace
|
||||
namespace detail
|
||||
@ -54,9 +54,9 @@ namespace sqlpp
|
||||
|
||||
class prepared_statement_t
|
||||
{
|
||||
friend sqlpp::postgresql::connection;
|
||||
|
||||
private:
|
||||
friend class sqlpp::postgresql::connection_base;
|
||||
|
||||
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||
|
||||
public:
|
||||
|
@ -40,7 +40,8 @@ namespace sqlpp
|
||||
{
|
||||
namespace postgresql
|
||||
{
|
||||
class connection;
|
||||
// Forward declaration
|
||||
class connection_base;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@ -93,8 +94,8 @@ namespace sqlpp
|
||||
} // namespace detail
|
||||
|
||||
template <typename NameType, bool CanBeNull>
|
||||
struct result_field_t<postgresql::connection, field_spec_t<NameType, blob, CanBeNull>>
|
||||
: public result_field_base<postgresql::connection, field_spec_t<NameType, blob, CanBeNull>>
|
||||
struct result_field_t<postgresql::connection_base, field_spec_t<NameType, blob, CanBeNull>>
|
||||
: public result_field_base<postgresql::connection_base, field_spec_t<NameType, blob, CanBeNull>>
|
||||
{
|
||||
private:
|
||||
const uint8_t* _blob{nullptr}; // Non-owning
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2016, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -72,18 +73,20 @@ namespace sqlpp
|
||||
|
||||
struct connection_handle
|
||||
{
|
||||
connection_config config;
|
||||
std::shared_ptr<const connection_config> config;
|
||||
std::unique_ptr<::sqlite3, void (*)(::sqlite3*)> sqlite;
|
||||
|
||||
connection_handle(connection_config conf) : config(conf), sqlite(nullptr, handle_cleanup)
|
||||
connection_handle(const std::shared_ptr<const connection_config>& conf) :
|
||||
config(conf),
|
||||
sqlite(nullptr, handle_cleanup)
|
||||
{
|
||||
#ifdef SQLPP_DYNAMIC_LOADING
|
||||
init_sqlite("");
|
||||
#endif
|
||||
|
||||
::sqlite3* sqlite_ptr;
|
||||
const auto rc = sqlite3_open_v2(conf.path_to_database.c_str(), &sqlite_ptr, conf.flags,
|
||||
conf.vfs.empty() ? nullptr : conf.vfs.c_str());
|
||||
const auto rc = sqlite3_open_v2(conf->path_to_database.c_str(), &sqlite_ptr, conf->flags,
|
||||
conf->vfs.empty() ? nullptr : conf->vfs.c_str());
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
const std::string msg = sqlite3_errmsg(sqlite_ptr);
|
||||
@ -94,13 +97,13 @@ namespace sqlpp
|
||||
sqlite.reset(sqlite_ptr);
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if (conf.password.size() > 0)
|
||||
if (conf->password.size() > 0)
|
||||
{
|
||||
int ret = sqlite3_key(sqlite.get(), conf.password.data(), conf.password.size());
|
||||
int ret = sqlite3_key(native_handle(), conf->password.data(), conf->password.size());
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
const std::string msg = sqlite3_errmsg(sqlite.get());
|
||||
sqlite3_close(sqlite.get());
|
||||
const std::string msg = sqlite3_errmsg(native_handle());
|
||||
sqlite3_close(native_handle());
|
||||
throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg);
|
||||
}
|
||||
}
|
||||
@ -111,31 +114,40 @@ namespace sqlpp
|
||||
connection_handle(connection_handle&&) = default;
|
||||
connection_handle& operator=(const connection_handle&) = delete;
|
||||
connection_handle& operator=(connection_handle&&) = default;
|
||||
~connection_handle() = default;
|
||||
|
||||
::sqlite3* native_handle() const
|
||||
{
|
||||
return sqlite.get();
|
||||
}
|
||||
|
||||
bool check_connection() const
|
||||
{
|
||||
return native_handle() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle,
|
||||
inline detail::prepared_statement_handle_t prepare_statement(std::unique_ptr<connection_handle>& handle,
|
||||
const std::string& statement)
|
||||
{
|
||||
if (handle.config.debug)
|
||||
if (handle->config->debug)
|
||||
std::cerr << "Sqlite3 debug: Preparing: '" << statement << "'" << std::endl;
|
||||
|
||||
detail::prepared_statement_handle_t result(nullptr, handle.config.debug);
|
||||
detail::prepared_statement_handle_t result(nullptr, handle->config->debug);
|
||||
|
||||
auto rc = sqlite3_prepare_v2(handle.sqlite.get(), statement.c_str(), static_cast<int>(statement.size()),
|
||||
auto rc = sqlite3_prepare_v2(handle->native_handle(), statement.c_str(), static_cast<int>(statement.size()),
|
||||
&result.sqlite_statement, nullptr);
|
||||
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
throw sqlpp::exception(
|
||||
"Sqlite3 error: Could not prepare statement: " + std::string(sqlite3_errmsg(handle.sqlite.get())) +
|
||||
"Sqlite3 error: Could not prepare statement: " + std::string(sqlite3_errmsg(handle->native_handle())) +
|
||||
" (statement was >>" + (rc == SQLITE_TOOBIG ? statement.substr(0, 128) + "..." : statement) + "<<\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void execute_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared)
|
||||
inline void execute_statement(std::unique_ptr<connection_handle>& handle, detail::prepared_statement_handle_t& prepared)
|
||||
{
|
||||
auto rc = sqlite3_step(prepared.sqlite_statement);
|
||||
switch (rc)
|
||||
@ -145,19 +157,20 @@ namespace sqlpp
|
||||
case SQLITE_DONE:
|
||||
return;
|
||||
default:
|
||||
if (handle.config.debug)
|
||||
if (handle->config->debug)
|
||||
std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl;
|
||||
throw sqlpp::exception("Sqlite3 error: Could not execute statement: " +
|
||||
std::string(sqlite3_errmsg(handle.sqlite.get())));
|
||||
std::string(sqlite3_errmsg(handle->native_handle())));
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class connection;
|
||||
// Forward declaration
|
||||
class connection_base;
|
||||
|
||||
struct serializer_t
|
||||
{
|
||||
serializer_t(const connection& db) : _db(db), _count(1)
|
||||
serializer_t(const connection_base& db) : _db(db), _count(1)
|
||||
{
|
||||
}
|
||||
|
||||
@ -184,14 +197,15 @@ namespace sqlpp
|
||||
++_count;
|
||||
}
|
||||
|
||||
const connection& _db;
|
||||
const connection_base& _db;
|
||||
sqlpp::detail::float_safe_ostringstream _os;
|
||||
size_t _count;
|
||||
};
|
||||
|
||||
class SQLPP11_SQLITE3_EXPORT connection : public sqlpp::connection
|
||||
// Base connection class
|
||||
class SQLPP11_SQLITE3_EXPORT connection_base : public sqlpp::connection
|
||||
{
|
||||
detail::connection_handle _handle;
|
||||
private:
|
||||
enum class transaction_status_type
|
||||
{
|
||||
none,
|
||||
@ -219,21 +233,21 @@ namespace sqlpp
|
||||
auto prepared = prepare_statement(_handle, statement);
|
||||
execute_statement(_handle, prepared);
|
||||
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(native_handle()));
|
||||
}
|
||||
|
||||
size_t update_impl(const std::string& statement)
|
||||
{
|
||||
auto prepared = prepare_statement(_handle, statement);
|
||||
execute_statement(_handle, prepared);
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
size_t remove_impl(const std::string& statement)
|
||||
{
|
||||
auto prepared = prepare_statement(_handle, statement);
|
||||
execute_statement(_handle, prepared);
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
// prepared execution
|
||||
@ -252,31 +266,37 @@ namespace sqlpp
|
||||
{
|
||||
execute_statement(_handle, *prepared_statement._handle.get());
|
||||
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(native_handle()));
|
||||
}
|
||||
|
||||
size_t run_prepared_update_impl(prepared_statement_t& prepared_statement)
|
||||
{
|
||||
execute_statement(_handle, *prepared_statement._handle.get());
|
||||
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement)
|
||||
{
|
||||
execute_statement(_handle, *prepared_statement._handle.get());
|
||||
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement)
|
||||
{
|
||||
execute_statement(_handle, *prepared_statement._handle.get());
|
||||
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
public:
|
||||
using _connection_base_t = connection_base;
|
||||
using _config_t = connection_config;
|
||||
using _config_ptr_t = std::shared_ptr<const connection_config>;
|
||||
using _handle_t = detail::connection_handle;
|
||||
using _handle_ptr_t = std::unique_ptr<_handle_t>;
|
||||
|
||||
using _prepared_statement_t = prepared_statement_t;
|
||||
using _context_t = serializer_t;
|
||||
using _serializer_context_t = _context_t;
|
||||
@ -299,18 +319,6 @@ namespace sqlpp
|
||||
return ::sqlpp::serialize(t, context);
|
||||
}
|
||||
|
||||
connection(connection_config config) : _handle(std::move(config))
|
||||
{
|
||||
}
|
||||
|
||||
connection(connection&&) noexcept = default;
|
||||
connection& operator=(connection&&) noexcept = default;
|
||||
|
||||
~connection() = default;
|
||||
|
||||
connection(const connection&) = delete;
|
||||
connection& operator=(const connection&) = delete;
|
||||
|
||||
//! select returns a result (which can be iterated row by row)
|
||||
template <typename Select>
|
||||
bind_result_t select(const Select& s)
|
||||
@ -416,7 +424,7 @@ namespace sqlpp
|
||||
{
|
||||
auto prepared = prepare_statement(_handle, statement);
|
||||
execute_statement(_handle, prepared);
|
||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||
}
|
||||
|
||||
template <
|
||||
@ -573,12 +581,12 @@ namespace sqlpp
|
||||
//! get the last inserted id
|
||||
uint64_t last_insert_id() noexcept
|
||||
{
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
|
||||
return static_cast<size_t>(sqlite3_last_insert_rowid(native_handle()));
|
||||
}
|
||||
|
||||
::sqlite3* native_handle()
|
||||
::sqlite3* native_handle() const
|
||||
{
|
||||
return _handle.sqlite.get();
|
||||
return _handle->native_handle();
|
||||
}
|
||||
|
||||
schema_t attach(const connection_config& config, const std::string name)
|
||||
@ -589,12 +597,25 @@ namespace sqlpp
|
||||
|
||||
return {name};
|
||||
}
|
||||
|
||||
protected:
|
||||
_handle_ptr_t _handle;
|
||||
|
||||
// Constructors
|
||||
connection_base() = default;
|
||||
connection_base(_handle_ptr_t&& handle) : _handle{std::move(handle)}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Method definition moved outside of class because it needs connection_base
|
||||
inline std::string serializer_t::escape(std::string arg)
|
||||
{
|
||||
return _db.escape(arg);
|
||||
}
|
||||
|
||||
using connection = sqlpp::normal_connection<connection_base>;
|
||||
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||
} // namespace sqlite3
|
||||
} // namespace sqlpp
|
||||
|
||||
|
39
include/sqlpp11/sqlite3/connection_pool.h
Normal file
39
include/sqlpp11/sqlite3/connection_pool.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/connection_pool.h>
|
||||
#include <sqlpp11/sqlite3/connection.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace sqlite3
|
||||
{
|
||||
using connection_pool = sqlpp::connection_pool<connection_base>;
|
||||
} // namespace sqlite3
|
||||
} // namespace sqlpp
|
@ -49,6 +49,9 @@ namespace sqlpp
|
||||
{
|
||||
namespace sqlite3
|
||||
{
|
||||
// Forward declaration
|
||||
class connection_base;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline void check_bind_result(int result, const char* const type)
|
||||
@ -70,11 +73,9 @@ namespace sqlpp
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class connection;
|
||||
|
||||
class SQLPP11_SQLITE3_EXPORT prepared_statement_t
|
||||
{
|
||||
friend ::sqlpp::sqlite3::connection;
|
||||
friend class ::sqlpp::sqlite3::connection_base;
|
||||
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||
|
||||
public:
|
||||
|
@ -42,8 +42,6 @@ namespace sqlpp
|
||||
{
|
||||
namespace sqlite3
|
||||
{
|
||||
class connection;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct prepared_statement_handle_t
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2015, Roland Bock
|
||||
* Copyright (c) 2023, Vesselin Atanasov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -28,6 +29,7 @@
|
||||
#define SQLPP_SQLITE3_H
|
||||
|
||||
#include <sqlpp11/sqlite3/connection.h>
|
||||
#include <sqlpp11/sqlite3/connection_pool.h>
|
||||
#include <sqlpp11/sqlite3/insert_or.h>
|
||||
|
||||
#endif
|
||||
|
260
tests/include/ConnectionPoolTests.h
Normal file
260
tests/include/ConnectionPoolTests.h
Normal file
@ -0,0 +1,260 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <random>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "TabDepartment.h"
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<typename Pool>
|
||||
using native_type = std::decay_t<decltype(std::declval<Pool>().get().native_handle())>;
|
||||
|
||||
template<typename Pool>
|
||||
using native_set = std::unordered_set<native_type<Pool>>;
|
||||
|
||||
template<typename Pool>
|
||||
using pool_conn_type = std::decay_t<decltype(std::declval<Pool>().get())>;
|
||||
|
||||
template<typename Pool>
|
||||
native_set<Pool> get_native_handles(Pool& pool)
|
||||
{
|
||||
native_set<Pool> ns;
|
||||
if (pool.available() == 0) {
|
||||
return ns;
|
||||
}
|
||||
for (;;) {
|
||||
auto handle = pool.get().native_handle();
|
||||
auto insert_res = ns.insert(handle);
|
||||
if (insert_res.second == false) {
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_conn_move(Pool& pool)
|
||||
{
|
||||
auto nh_all = get_native_handles(pool);
|
||||
{
|
||||
// Get one connection from the pool
|
||||
auto conn_1 = pool.get();
|
||||
// If the native handles list was empty before getting a connection, then a new connection
|
||||
// was created, so we need to update the set of all native handles
|
||||
if (nh_all.empty()) {
|
||||
nh_all.insert(conn_1.native_handle());
|
||||
}
|
||||
auto nh_removed = nh_all;
|
||||
if (nh_removed.erase(conn_1.native_handle()) != 1) {
|
||||
throw std::logic_error{"Got an unknown native connection handle"};
|
||||
}
|
||||
if (get_native_handles(pool) != nh_removed) {
|
||||
throw std::logic_error{"Could not get correctly a connection from the pool"};
|
||||
}
|
||||
{
|
||||
// Move the pooled connection once
|
||||
auto conn_2 = std::move(conn_1);
|
||||
if (get_native_handles(pool) != nh_removed) {
|
||||
throw std::logic_error{"Moving a connection changes the pool"};
|
||||
}
|
||||
|
||||
// Move the pooled connection again
|
||||
conn_1 = std::move(conn_2);
|
||||
if (get_native_handles(pool) != nh_removed) {
|
||||
throw std::logic_error{"Moving a connection changes the pool"};
|
||||
}
|
||||
|
||||
// The empty connection conn_2 goes out of scope and gets destroyed
|
||||
}
|
||||
|
||||
// Check if destroying an empty connection changed the pool
|
||||
if (get_native_handles(pool) != nh_removed) {
|
||||
throw std::logic_error{"Destroying an empty connection changes the pool"};
|
||||
}
|
||||
|
||||
// The valid connection conn_1 goes out of scope and gets destroyed
|
||||
}
|
||||
|
||||
// Check if destroying a valid connection from the pool returned the handle to the pool
|
||||
if (get_native_handles(pool) != nh_all) {
|
||||
throw std::logic_error{"Destroying a valid connection does not return its handle to the pool"};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_basic(Pool& pool, const std::string& create_table)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto db = pool.get();
|
||||
db.execute("DROP TABLE IF EXISTS tab_department");
|
||||
db.execute(create_table);
|
||||
model::TabDepartment tabDept = {};
|
||||
db(insert_into(tabDept).default_values());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception in " << __func__ << "\n";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_single_connection(Pool& pool)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto* handle = [&pool]() {
|
||||
auto db = pool.get();
|
||||
return db.native_handle();
|
||||
}();
|
||||
|
||||
for (auto i = 0; i < 100; ++i)
|
||||
{
|
||||
auto db = pool.get();
|
||||
if (handle != db.native_handle())
|
||||
{
|
||||
std::cerr << "original connection: " << handle << std::endl;
|
||||
std::cerr << "received connection: " << db.native_handle() << std::endl;
|
||||
throw std::logic_error{"Pool acquired more than one connection"};
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception in " << __func__ << "\n";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_multiple_connections(Pool& pool)
|
||||
{
|
||||
try
|
||||
{
|
||||
model::TabDepartment tabDept = {};
|
||||
auto connections = std::vector<std::decay_t<decltype(pool.get())>>{};
|
||||
auto pointers = std::set<void*>{};
|
||||
for (auto i = 0; i < 50; ++i)
|
||||
{
|
||||
connections.push_back(pool.get());
|
||||
if (pointers.count(connections.back().native_handle()))
|
||||
{
|
||||
throw std::logic_error{"Pool yielded connection twice (without getting it back in between)"};
|
||||
}
|
||||
pointers.insert(connections.back().native_handle());
|
||||
connections.back()(insert_into(tabDept).default_values());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception in " << __func__ << "\n";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_multithreaded(Pool& pool)
|
||||
{
|
||||
std::random_device r;
|
||||
std::default_random_engine random_engine(r());
|
||||
std::uniform_int_distribution<int> uniform_dist(1, 20);
|
||||
|
||||
std::clog << "Run a random number [1,20] of threads\n";
|
||||
std::clog << "Each with a random number [1,20] of {pool.get() & insert}\n";
|
||||
|
||||
try
|
||||
{
|
||||
model::TabDepartment tabDept = {};
|
||||
auto threads = std::vector<std::thread>{};
|
||||
const auto thread_count = uniform_dist(random_engine);
|
||||
|
||||
for (auto i = 0; i < thread_count; ++i)
|
||||
{
|
||||
threads.push_back(std::thread([func = __func__, call_count = uniform_dist(random_engine), &pool, &tabDept]() {
|
||||
try
|
||||
{
|
||||
for (auto k = 0; k < call_count; ++k)
|
||||
{
|
||||
auto connection = pool.get();
|
||||
connection(insert_into(tabDept).default_values());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << std::string(func) + ": In-thread exception: " + e.what() + "\n";
|
||||
std::abort();
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (auto&& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception in " << __func__ << "\n";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
void test_destruction_order(typename Pool::_config_ptr_t config)
|
||||
{
|
||||
// Create a pool, get a connection from it and then destroy the pool before the connection
|
||||
auto pool = std::make_unique<Pool>(config, 5);
|
||||
auto conn = pool->get();
|
||||
pool = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pool>
|
||||
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);
|
||||
if (test_mt)
|
||||
{
|
||||
sqlpp::test::test_multithreaded(pool);
|
||||
}
|
||||
sqlpp::test::test_destruction_order<Pool>(config);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace sqlpp
|
79
tests/include/TabDepartment.h
Normal file
79
tests/include/TabDepartment.h
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <sqlpp11/table.h>
|
||||
#include <sqlpp11/data_types.h>
|
||||
#include <sqlpp11/char_sequence.h>
|
||||
|
||||
namespace model
|
||||
{
|
||||
namespace TabDepartment_
|
||||
{
|
||||
struct Id
|
||||
{
|
||||
struct _alias_t
|
||||
{
|
||||
static constexpr const char _literal[] = "id";
|
||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||
template<typename T>
|
||||
struct _member_t
|
||||
{
|
||||
T id;
|
||||
T& operator()() { return id; }
|
||||
const T& operator()() const { return id; }
|
||||
};
|
||||
};
|
||||
using _traits = sqlpp::make_traits<sqlpp::integer, sqlpp::tag::must_not_insert, sqlpp::tag::must_not_update, sqlpp::tag::can_be_null>;
|
||||
};
|
||||
struct Name
|
||||
{
|
||||
struct _alias_t
|
||||
{
|
||||
static constexpr const char _literal[] = "name";
|
||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||
template<typename T>
|
||||
struct _member_t
|
||||
{
|
||||
T name;
|
||||
T& operator()() { return name; }
|
||||
const T& operator()() const { return name; }
|
||||
};
|
||||
};
|
||||
using _traits = sqlpp::make_traits<sqlpp::text, sqlpp::tag::can_be_null>;
|
||||
};
|
||||
struct Division
|
||||
{
|
||||
struct _alias_t
|
||||
{
|
||||
static constexpr const char _literal[] = "division";
|
||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||
template<typename T>
|
||||
struct _member_t
|
||||
{
|
||||
T division;
|
||||
T& operator()() { return division; }
|
||||
const T& operator()() const { return division; }
|
||||
};
|
||||
};
|
||||
using _traits = sqlpp::make_traits<sqlpp::text>;
|
||||
};
|
||||
} // namespace TabDepartment_
|
||||
|
||||
struct TabDepartment: sqlpp::table_t<TabDepartment,
|
||||
TabDepartment_::Id,
|
||||
TabDepartment_::Name,
|
||||
TabDepartment_::Division>
|
||||
{
|
||||
struct _alias_t
|
||||
{
|
||||
static constexpr const char _literal[] = "tab_department";
|
||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||
template<typename T>
|
||||
struct _member_t
|
||||
{
|
||||
T tabDepartment;
|
||||
T& operator()() { return tabDepartment; }
|
||||
const T& operator()() const { return tabDepartment; }
|
||||
};
|
||||
};
|
||||
};
|
||||
} // namespace model
|
@ -40,6 +40,7 @@ set(test_files
|
||||
Truncated.cpp
|
||||
Update.cpp
|
||||
Remove.cpp
|
||||
ConnectionPool.cpp
|
||||
)
|
||||
|
||||
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
||||
@ -62,4 +63,4 @@ foreach(test_file IN LISTS test_files)
|
||||
add_test(NAME sqlpp11.mysql.usage.${test}
|
||||
COMMAND sqlpp11_mysql_tests ${test}
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
56
tests/mysql/usage/ConnectionPool.cpp
Normal file
56
tests/mysql/usage/ConnectionPool.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/mysql/mysql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
#include "../../include/ConnectionPoolTests.h"
|
||||
#include "make_test_connection.h"
|
||||
|
||||
namespace sql = ::sqlpp::mysql;
|
||||
|
||||
int ConnectionPool(int, char*[])
|
||||
{
|
||||
try
|
||||
{
|
||||
sqlpp::test::test_connection_pool<sql::connection_pool>(
|
||||
sql::make_test_config(),
|
||||
"CREATE TABLE tab_department ("
|
||||
"id INTEGER PRIMARY KEY AUTO_INCREMENT, "
|
||||
"name CHAR(100), "
|
||||
"division VARCHAR(255) NOT NULL DEFAULT 'engineering'"
|
||||
")",
|
||||
mysql_thread_safe()
|
||||
);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
#include <sqlpp11/custom_query.h>
|
||||
@ -59,28 +60,13 @@ namespace
|
||||
|
||||
const auto tab = TabSample{};
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int CustomQuery(int, char*[])
|
||||
{
|
||||
mysql::global_library_init();
|
||||
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/mysql/mysql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
@ -68,32 +69,13 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int DateTime(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown exception during connect" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(SET time_zone = '+00:00')"); // To force MySQL's CURRENT_TIMESTAMP into the right timezone
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_date_time)");
|
||||
db.execute(R"(CREATE TABLE tab_date_time (
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
#include <sqlpp11/functions.h>
|
||||
@ -38,27 +39,13 @@
|
||||
|
||||
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int DynamicSelect(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) DEFAULT NULL,
|
||||
|
@ -23,6 +23,8 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
|
||||
#include <mysql.h>
|
||||
#include <iostream>
|
||||
|
||||
@ -52,28 +54,13 @@ namespace test
|
||||
SQLPP_ALIAS_PROVIDER(value)
|
||||
}
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int Json(int, char*[])
|
||||
{
|
||||
mysql::global_library_init();
|
||||
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_json)");
|
||||
db.execute(R"(CREATE TABLE tab_json (
|
||||
data JSON NOT NULL
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
#include <sqlpp11/functions.h>
|
||||
@ -37,29 +38,15 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int MoveConstructor(int, char*[])
|
||||
{
|
||||
mysql::global_library_init();
|
||||
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
auto config = sql::make_test_config();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
std::vector<sqlpp::mysql::connection> connections;
|
||||
connections.emplace_back(sqlpp::mysql::connection(config));
|
||||
std::vector<sql::connection> connections;
|
||||
connections.emplace_back(sql::connection(config));
|
||||
|
||||
connections.at(0).execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
connections.at(0).execute(R"(CREATE TABLE tab_sample (
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <cassert>
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
@ -69,23 +70,10 @@ void testPreparedStatementResult(sql::connection& db)
|
||||
|
||||
int Prepared(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/mysql/mysql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
@ -36,23 +37,10 @@ namespace sql = sqlpp::mysql;
|
||||
|
||||
int Remove(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/mysql/mysql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
@ -31,29 +32,13 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace mysql = sqlpp::mysql;
|
||||
namespace sql = sqlpp::mysql;
|
||||
int Sample(int, char*[])
|
||||
{
|
||||
sqlpp::mysql::global_library_init();
|
||||
|
||||
auto config = std::make_shared<mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
config->connect_timeout_seconds = 5;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
mysql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <cassert>
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
@ -83,23 +84,9 @@ void testSelectAll(sql::connection& db, int expectedRowCount)
|
||||
|
||||
int Select(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <cassert>
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
@ -44,24 +45,10 @@ const auto tab = TabSample{};
|
||||
|
||||
int Truncated(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
config->charset = "utf8";
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/mysql/connection.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
@ -36,23 +37,10 @@ const auto tab = TabSample{};
|
||||
|
||||
int Union(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "make_test_connection.h"
|
||||
#include "TabSample.h"
|
||||
#include <sqlpp11/mysql/mysql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
@ -36,23 +37,10 @@ namespace sql = sqlpp::mysql;
|
||||
|
||||
int Update(int, char*[])
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
sql::global_library_init();
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
}
|
||||
catch (const sqlpp::exception& e)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
sql::connection db(config);
|
||||
auto db = sql::make_test_connection();
|
||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||
db.execute(R"(CREATE TABLE tab_sample (
|
||||
alpha bigint(20) AUTO_INCREMENT,
|
||||
|
65
tests/mysql/usage/make_test_connection.h
Normal file
65
tests/mysql/usage/make_test_connection.h
Normal file
@ -0,0 +1,65 @@
|
||||
#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:
|
||||
*
|
||||
* * 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 <sqlpp11/mysql/mysql.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace mysql
|
||||
{
|
||||
// Get configuration for test connection
|
||||
inline std::shared_ptr<sqlpp::mysql::connection_config> make_test_config()
|
||||
{
|
||||
auto config = std::make_shared<sqlpp::mysql::connection_config>();
|
||||
config->user = "root";
|
||||
config->database = "sqlpp_mysql";
|
||||
config->debug = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
// Starts a connection
|
||||
inline ::sqlpp::mysql::connection make_test_connection()
|
||||
{
|
||||
namespace sql = sqlpp::mysql;
|
||||
|
||||
auto config = make_test_config();
|
||||
sql::connection db;
|
||||
try
|
||||
{
|
||||
db.connectUsing(config);
|
||||
}
|
||||
catch (const sqlpp::exception&)
|
||||
{
|
||||
std::cerr << "For testing, you'll need to create a database called '" << config->database
|
||||
<< "', accessible by user '" << config->user << "' without a password." << std::endl;
|
||||
throw;
|
||||
}
|
||||
return db;
|
||||
}
|
||||
} // namespace mysql
|
||||
} // namespace sqlpp
|
@ -30,6 +30,7 @@ set(test_files
|
||||
Basic.cpp
|
||||
BasicConstConfig.cpp
|
||||
Blob.cpp
|
||||
ConnectionPool.cpp
|
||||
Constructor.cpp
|
||||
Date.cpp
|
||||
DateTime.cpp
|
||||
|
56
tests/postgresql/usage/ConnectionPool.cpp
Normal file
56
tests/postgresql/usage/ConnectionPool.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/postgresql/postgresql.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
#include "../../include/ConnectionPoolTests.h"
|
||||
#include "make_test_connection.h"
|
||||
|
||||
namespace sql = ::sqlpp::postgresql;
|
||||
|
||||
int ConnectionPool(int, char*[])
|
||||
{
|
||||
try
|
||||
{
|
||||
sqlpp::test::test_connection_pool<sql::connection_pool>(
|
||||
sql::make_test_config(),
|
||||
"CREATE TABLE tab_department ("
|
||||
"id SERIAL PRIMARY KEY, "
|
||||
"name CHAR(100), "
|
||||
"division VARCHAR(255) NOT NULL DEFAULT 'engineering'"
|
||||
")",
|
||||
PQisthreadsafe()
|
||||
);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -33,12 +33,10 @@ namespace sqlpp
|
||||
{
|
||||
namespace postgresql
|
||||
{
|
||||
// Starts a connection and sets the time zone to UTC
|
||||
inline ::sqlpp::postgresql::connection make_test_connection()
|
||||
// Get configuration for test connection
|
||||
inline std::shared_ptr<sqlpp::postgresql::connection_config> make_test_config()
|
||||
{
|
||||
namespace sql = sqlpp::postgresql;
|
||||
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
auto config = std::make_shared<sqlpp::postgresql::connection_config>();
|
||||
|
||||
#ifdef WIN32
|
||||
config->dbname = "test";
|
||||
@ -49,6 +47,15 @@ namespace sqlpp
|
||||
config->dbname = "sqlpp_postgresql";
|
||||
config->debug = true;
|
||||
#endif
|
||||
return config;
|
||||
}
|
||||
|
||||
// Starts a connection and sets the time zone to UTC
|
||||
inline ::sqlpp::postgresql::connection make_test_connection()
|
||||
{
|
||||
namespace sql = sqlpp::postgresql;
|
||||
|
||||
auto config = make_test_config();
|
||||
|
||||
sql::connection db;
|
||||
try
|
||||
|
@ -38,6 +38,7 @@ set(test_files
|
||||
FloatingPoint.cpp
|
||||
Integral.cpp
|
||||
Blob.cpp
|
||||
ConnectionPool.cpp
|
||||
)
|
||||
|
||||
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
||||
@ -76,4 +77,4 @@ if (SQLPP_DYNAMIC_LOADING)
|
||||
target_compile_options(Sqlpp11Sqlite3DynamicLoadingTest INTERFACE -Wall -Wextra -pedantic)
|
||||
endif ()
|
||||
add_test(NAME Sqlpp11Sqlite3DynamicLoadingTest COMMAND Sqlpp11Sqlite3DynamicLoadingTest)
|
||||
endif()
|
||||
endif()
|
||||
|
59
tests/sqlite3/usage/ConnectionPool.cpp
Normal file
59
tests/sqlite3/usage/ConnectionPool.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright (c) 2017 - 2018, Roland Bock
|
||||
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 <sqlpp11/sqlite3/sqlite3.h>
|
||||
#include <sqlpp11/sqlpp11.h>
|
||||
|
||||
#include "../../include/ConnectionPoolTests.h"
|
||||
|
||||
namespace sql = ::sqlpp::sqlite3;
|
||||
|
||||
int ConnectionPool(int, char*[])
|
||||
{
|
||||
try
|
||||
{
|
||||
auto config = std::make_shared<sql::connection_config>();
|
||||
config->path_to_database = "file:testpool?mode=memory&cache=shared";
|
||||
config->flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI;
|
||||
config->debug = true;
|
||||
sqlpp::test::test_connection_pool<sql::connection_pool>(
|
||||
config,
|
||||
"CREATE TABLE tab_department ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"name CHAR(100), "
|
||||
"division VARCHAR(255) NOT NULL DEFAULT 'engineering'"
|
||||
")",
|
||||
sqlite3_threadsafe()
|
||||
);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user