mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-15 20:31:16 +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) 2013-2015, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -37,6 +38,44 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace database
|
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
|
// The context is not a requirement, but if the database requires
|
||||||
// any deviations from the SQL standard, you should use your own
|
// any deviations from the SQL standard, you should use your own
|
||||||
// context in order to specialize the behaviour, see also interpreter.h
|
// context in order to specialize the behaviour, see also interpreter.h
|
||||||
@ -48,9 +87,25 @@ namespace sqlpp
|
|||||||
std::string escape(std::string arg);
|
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:
|
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<
|
using _traits = ::sqlpp::make_traits<
|
||||||
::sqlpp::no_value_t,
|
::sqlpp::no_value_t,
|
||||||
::sqlpp::tag::enforce_null_result_treatment // If that is what you really want, leave it out otherwise
|
::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
|
// serializer and interpreter are typically the same for string based connectors
|
||||||
// the types are required for dynamic statement components, see sqlpp11/interpretable.h
|
// 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
|
//! "direct" select
|
||||||
template <typename Select>
|
template <typename Select>
|
||||||
<< bind_result_t >>
|
<< 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)
|
//! 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;
|
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>
|
#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) 2013-2015, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -27,11 +28,133 @@
|
|||||||
#ifndef SQLPP11_CONNECTION_H
|
#ifndef SQLPP11_CONNECTION_H
|
||||||
#define SQLPP11_CONNECTION_H
|
#define SQLPP11_CONNECTION_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
struct connection
|
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
|
} // namespace sqlpp
|
||||||
|
|
||||||
#endif
|
#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,
|
template <typename Db,
|
||||||
typename Expr,
|
typename Expr,
|
||||||
typename std::enable_if<not std::is_convertible<Expr, std::string>::value, int>::type = 0>
|
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;
|
return db(select(expr.as(alias::a))).front().a;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 - 2017, Roland Bock
|
* Copyright (c) 2013 - 2017, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -104,11 +105,12 @@ namespace sqlpp
|
|||||||
|
|
||||||
struct connection_handle_t
|
struct connection_handle_t
|
||||||
{
|
{
|
||||||
std::shared_ptr<connection_config> config;
|
std::shared_ptr<const connection_config> config;
|
||||||
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
|
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
|
||||||
|
|
||||||
connection_handle_t(const std::shared_ptr<connection_config>& conf)
|
connection_handle_t(const std::shared_ptr<const connection_config>& conf) :
|
||||||
: config(conf), mysql(mysql_init(nullptr), handle_cleanup)
|
config(conf),
|
||||||
|
mysql(mysql_init(nullptr), handle_cleanup)
|
||||||
{
|
{
|
||||||
if (not mysql)
|
if (not mysql)
|
||||||
{
|
{
|
||||||
@ -118,43 +120,48 @@ namespace sqlpp
|
|||||||
if (config->auto_reconnect)
|
if (config->auto_reconnect)
|
||||||
{
|
{
|
||||||
my_bool my_true = true;
|
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");
|
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(const connection_handle_t&) = delete;
|
||||||
connection_handle_t(connection_handle_t&&) = default;
|
connection_handle_t(connection_handle_t&&) = default;
|
||||||
connection_handle_t& operator=(const connection_handle_t&) = delete;
|
connection_handle_t& operator=(const connection_handle_t&) = delete;
|
||||||
connection_handle_t& operator=(connection_handle_t&&) = default;
|
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()
|
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();
|
thread_init();
|
||||||
|
|
||||||
if (handle.config->debug)
|
if (handle->config->debug)
|
||||||
std::cerr << "MySQL debug: Executing: '" << statement << "'" << std::endl;
|
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(
|
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");
|
" (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,
|
const std::string& statement,
|
||||||
size_t no_of_parameters,
|
size_t no_of_parameters,
|
||||||
size_t no_of_columns)
|
size_t no_of_columns)
|
||||||
{
|
{
|
||||||
thread_init();
|
thread_init();
|
||||||
|
|
||||||
if (handle.config->debug)
|
if (handle->config->debug)
|
||||||
std::cerr << "MySQL debug: Preparing: '" << statement << "'" << std::endl;
|
std::cerr << "MySQL debug: Preparing: '" << statement << "'" << std::endl;
|
||||||
|
|
||||||
auto prepared_statement = std::make_shared<detail::prepared_statement_handle_t>(
|
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)
|
if (not prepared_statement)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception("MySQL error: Could not allocate prepared statement\n");
|
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()))
|
if (mysql_stmt_prepare(prepared_statement->mysql_stmt, statement.data(), statement.size()))
|
||||||
{
|
{
|
||||||
throw sqlpp::exception(
|
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");
|
" (statement was >>" + statement + "<<\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,13 +233,15 @@ namespace sqlpp
|
|||||||
static const auto global_init_and_end = scoped_library_initializer_t(argc, argv, groups);
|
static const auto global_init_and_end = scoped_library_initializer_t(argc, argv, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
class connection;
|
// Forward declaration
|
||||||
|
class connection_base;
|
||||||
|
|
||||||
struct serializer_t
|
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>
|
template <typename T>
|
||||||
std::ostream& operator<<(T t)
|
std::ostream& operator<<(T t)
|
||||||
@ -247,7 +256,7 @@ namespace sqlpp
|
|||||||
return _os.str();
|
return _os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection& _db;
|
const connection_base& _db;
|
||||||
sqlpp::detail::float_safe_ostringstream _os;
|
sqlpp::detail::float_safe_ostringstream _os;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,9 +264,9 @@ namespace sqlpp
|
|||||||
|
|
||||||
std::integral_constant<char, '`'> get_quote_right(const serializer_t&);
|
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;
|
bool _transaction_active = false;
|
||||||
|
|
||||||
// direct execution
|
// direct execution
|
||||||
@ -265,11 +274,11 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
execute_statement(_handle, statement);
|
execute_statement(_handle, statement);
|
||||||
std::unique_ptr<detail::result_handle> result_handle(
|
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)
|
if (!*result_handle)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception("MySQL error: Could not store result set: " +
|
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)};
|
return {std::move(result_handle)};
|
||||||
@ -279,19 +288,19 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
execute_statement(_handle, statement);
|
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)
|
size_t update_impl(const std::string& statement)
|
||||||
{
|
{
|
||||||
execute_statement(_handle, 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)
|
size_t remove_impl(const std::string& statement)
|
||||||
{
|
{
|
||||||
execute_statement(_handle, statement);
|
execute_statement(_handle, statement);
|
||||||
return mysql_affected_rows(_handle.mysql.get());
|
return mysql_affected_rows(_handle->native_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepared execution
|
// prepared execution
|
||||||
@ -325,6 +334,12 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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 _prepared_statement_t = ::sqlpp::mysql::prepared_statement_t;
|
||||||
using _context_t = serializer_t;
|
using _context_t = serializer_t;
|
||||||
using _serializer_context_t = _context_t;
|
using _serializer_context_t = _context_t;
|
||||||
@ -347,30 +362,19 @@ namespace sqlpp
|
|||||||
return serialize(t, context);
|
return serialize(t, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection(const std::shared_ptr<connection_config>& config) : _handle{config}
|
bool is_valid() const
|
||||||
{
|
{
|
||||||
}
|
return _handle->check_connection();
|
||||||
|
|
||||||
~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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconnect()
|
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()
|
bool is_transaction_active()
|
||||||
@ -483,7 +487,7 @@ namespace sqlpp
|
|||||||
std::string escape(const std::string& s) const
|
std::string escape(const std::string& s) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<char[]> dest(new char[s.size() * 2 + 1]);
|
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();
|
return dest.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,16 +573,35 @@ namespace sqlpp
|
|||||||
std::cerr << "MySQL message:" << message << std::endl;
|
std::cerr << "MySQL message:" << message << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MYSQL* native_handle()
|
||||||
|
{
|
||||||
|
return _handle->native_handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kept for compatibility with old code
|
||||||
MYSQL* get_handle()
|
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)
|
inline std::string serializer_t::escape(std::string arg)
|
||||||
{
|
{
|
||||||
return _db.escape(arg);
|
return _db.escape(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using connection = sqlpp::normal_connection<connection_base>;
|
||||||
|
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||||
} // namespace mysql
|
} // namespace mysql
|
||||||
} // namespace sqlpp
|
} // namespace sqlpp
|
||||||
|
|
||||||
|
@ -33,10 +33,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace mysql
|
namespace mysql
|
||||||
{
|
{
|
||||||
class connection;
|
|
||||||
struct connection_config
|
struct connection_config
|
||||||
{
|
{
|
||||||
typedef ::sqlpp::mysql::connection connection;
|
|
||||||
std::string host = "localhost";
|
std::string host = "localhost";
|
||||||
std::string user;
|
std::string user;
|
||||||
std::string password;
|
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) 2013 - 2015, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -28,6 +29,7 @@
|
|||||||
#define SQLPP_MYSQL_H
|
#define SQLPP_MYSQL_H
|
||||||
|
|
||||||
#include <sqlpp11/mysql/connection.h>
|
#include <sqlpp11/mysql/connection.h>
|
||||||
|
#include <sqlpp11/mysql/connection_pool.h>
|
||||||
#include <sqlpp11/mysql/char_result.h>
|
#include <sqlpp11/mysql/char_result.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,11 +41,11 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace mysql
|
namespace mysql
|
||||||
{
|
{
|
||||||
class connection;
|
class connection_base;
|
||||||
|
|
||||||
class prepared_statement_t
|
class prepared_statement_t
|
||||||
{
|
{
|
||||||
friend ::sqlpp::mysql::connection;
|
friend ::sqlpp::mysql::connection_base;
|
||||||
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright © 2014-2015, Matthijs Möhlmann
|
* Copyright © 2014-2015, Matthijs Möhlmann
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -63,39 +64,39 @@ namespace sqlpp
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
// Forward declaration
|
// 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 std::string& stmt,
|
||||||
const size_t& paramCount)
|
const size_t& paramCount)
|
||||||
{
|
{
|
||||||
if (handle.config->debug)
|
if (handle->config->debug)
|
||||||
{
|
{
|
||||||
std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
|
std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::unique_ptr<detail::prepared_statement_handle_t>(new detail::prepared_statement_handle_t
|
return std::unique_ptr<detail::prepared_statement_handle_t>(new detail::prepared_statement_handle_t
|
||||||
(handle, stmt, paramCount));
|
(*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
|
// Forward declaration
|
||||||
class connection;
|
class connection_base;
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
struct context_t
|
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>
|
template <typename T>
|
||||||
std::ostream& operator<<(T t)
|
std::ostream& operator<<(T t)
|
||||||
@ -108,7 +109,7 @@ namespace sqlpp
|
|||||||
return _os << (t ? "TRUE" : "FALSE");
|
return _os << (t ? "TRUE" : "FALSE");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string escape(const std::string& arg);
|
std::string escape(const std::string& arg) const;
|
||||||
|
|
||||||
std::string str() const
|
std::string str() const
|
||||||
{
|
{
|
||||||
@ -125,22 +126,22 @@ namespace sqlpp
|
|||||||
++_count;
|
++_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection& _db;
|
const connection_base& _db;
|
||||||
sqlpp::detail::float_safe_ostringstream _os;
|
sqlpp::detail::float_safe_ostringstream _os;
|
||||||
size_t _count{1};
|
size_t _count{1};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Connection
|
// Base connection class
|
||||||
class connection : public sqlpp::connection
|
class connection_base : public sqlpp::connection
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<detail::connection_handle> _handle;
|
|
||||||
bool _transaction_active{false};
|
bool _transaction_active{false};
|
||||||
|
|
||||||
void validate_connection_handle() const
|
void validate_connection_handle() const
|
||||||
{
|
{
|
||||||
if (!_handle)
|
if (!_handle) {
|
||||||
throw std::logic_error("connection handle used, but not initialized");
|
throw std::logic_error("connection handle used, but not initialized");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// direct execution
|
// direct execution
|
||||||
@ -158,6 +159,12 @@ namespace sqlpp
|
|||||||
size_t run_prepared_remove_impl(prepared_statement_t& prep);
|
size_t run_prepared_remove_impl(prepared_statement_t& prep);
|
||||||
|
|
||||||
public:
|
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 _prepared_statement_t = prepared_statement_t;
|
||||||
using _context_t = context_t;
|
using _context_t = context_t;
|
||||||
using _serializer_context_t = _context_t;
|
using _serializer_context_t = _context_t;
|
||||||
@ -180,18 +187,6 @@ namespace sqlpp
|
|||||||
return ::sqlpp::serialize(t, context);
|
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)
|
// Select stmt (returns a result)
|
||||||
template <typename Select>
|
template <typename Select>
|
||||||
bind_result_t select(const Select& s)
|
bind_result_t select(const Select& s)
|
||||||
@ -384,45 +379,19 @@ namespace sqlpp
|
|||||||
//! get the last inserted id for a certain table
|
//! get the last inserted id for a certain table
|
||||||
uint64_t last_insert_id(const std::string& table, const std::string& fieldname);
|
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 std::shared_ptr<detail::statement_handle_t> connection_base::execute(const std::string& stmt)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
validate_connection_handle();
|
validate_connection_handle();
|
||||||
if (_handle->config->debug)
|
if (_handle->config->debug)
|
||||||
@ -431,75 +400,76 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto result = std::make_shared<detail::statement_handle_t>(*_handle);
|
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;
|
result->valid = true;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// direct execution
|
// 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);
|
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());
|
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());
|
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());
|
return static_cast<size_t>(execute(stmt)->result.affected_rows());
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepared execution
|
// 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();
|
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();
|
validate_connection_handle();
|
||||||
execute_prepared_statement(*_handle, *prep._handle.get());
|
execute_prepared_statement(_handle, prep._handle);
|
||||||
return {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();
|
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());
|
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();
|
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());
|
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();
|
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());
|
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();
|
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());
|
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";
|
std::string level_str = "read uncommmitted";
|
||||||
switch (level)
|
switch (level)
|
||||||
@ -524,7 +494,8 @@ namespace sqlpp
|
|||||||
execute(cmd);
|
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 res = execute("SHOW default_transaction_isolation;");
|
||||||
auto status = res->result.status();
|
auto status = res->result.status();
|
||||||
@ -554,7 +525,7 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix escaping.
|
// 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();
|
validate_connection_handle();
|
||||||
// Escape strings
|
// Escape strings
|
||||||
@ -562,13 +533,13 @@ namespace sqlpp
|
|||||||
result.resize((s.size() * 2) + 1);
|
result.resize((s.size() * 2) + 1);
|
||||||
|
|
||||||
int err;
|
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);
|
result.resize(length);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! start transaction
|
//! start transaction
|
||||||
inline void connection::start_transaction(sqlpp::isolation_level level)
|
inline void connection_base::start_transaction(isolation_level level)
|
||||||
{
|
{
|
||||||
if (_transaction_active)
|
if (_transaction_active)
|
||||||
{
|
{
|
||||||
@ -606,28 +577,28 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! create savepoint
|
//! create savepoint
|
||||||
inline void connection::savepoint(const std::string& name)
|
inline void connection_base::savepoint(const std::string& name)
|
||||||
{
|
{
|
||||||
/// NOTE prevent from sql injection?
|
/// NOTE prevent from sql injection?
|
||||||
execute("SAVEPOINT " + name);
|
execute("SAVEPOINT " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! ROLLBACK TO SAVEPOINT
|
//! 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?
|
/// NOTE prevent from sql injection?
|
||||||
execute("ROLLBACK TO SAVEPOINT " + name);
|
execute("ROLLBACK TO SAVEPOINT " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! release_savepoint
|
//! 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?
|
/// NOTE prevent from sql injection?
|
||||||
execute("RELEASE SAVEPOINT " + name);
|
execute("RELEASE SAVEPOINT " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! commit transaction (or throw transaction if transaction has finished already)
|
//! commit transaction (or throw transaction if transaction has finished already)
|
||||||
inline void connection::commit_transaction()
|
inline void connection_base::commit_transaction()
|
||||||
{
|
{
|
||||||
if (!_transaction_active)
|
if (!_transaction_active)
|
||||||
{
|
{
|
||||||
@ -639,7 +610,7 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! rollback transaction
|
//! rollback transaction
|
||||||
inline void connection::rollback_transaction(bool report)
|
inline void connection_base::rollback_transaction(bool report)
|
||||||
{
|
{
|
||||||
if (!_transaction_active)
|
if (!_transaction_active)
|
||||||
{
|
{
|
||||||
@ -655,15 +626,15 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! report rollback failure
|
//! 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;
|
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')";
|
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)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
std::string err{PQresultErrorMessage(res)};
|
std::string err{PQresultErrorMessage(res)};
|
||||||
@ -677,17 +648,20 @@ namespace sqlpp
|
|||||||
return std::stoul(in);
|
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);
|
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>
|
#include <sqlpp11/postgresql/serializer.h>
|
||||||
|
|
||||||
|
@ -35,12 +35,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace postgresql
|
namespace postgresql
|
||||||
{
|
{
|
||||||
class connection;
|
|
||||||
struct DLL_PUBLIC connection_config
|
struct DLL_PUBLIC connection_config
|
||||||
{
|
{
|
||||||
// Needed for the connection pool
|
|
||||||
typedef ::sqlpp::postgresql::connection connection;
|
|
||||||
|
|
||||||
enum class sslmode_t
|
enum class sslmode_t
|
||||||
{
|
{
|
||||||
disable,
|
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 std::shared_ptr<const connection_config>& config);
|
||||||
connection_handle(const connection_handle&) = delete;
|
connection_handle(const connection_handle&) = delete;
|
||||||
connection_handle(connection_handle&&) = default;
|
connection_handle(connection_handle&&) = default;
|
||||||
|
~connection_handle();
|
||||||
connection_handle& operator=(const connection_handle&) = delete;
|
connection_handle& operator=(const connection_handle&) = delete;
|
||||||
connection_handle& operator=(connection_handle&&) = default;
|
connection_handle& operator=(connection_handle&&) = default;
|
||||||
~connection_handle();
|
|
||||||
|
|
||||||
PGconn* native() const
|
|
||||||
{
|
|
||||||
return postgres.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate_prepared_statement(const std::string& name);
|
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)
|
inline connection_handle::connection_handle(const std::shared_ptr<const connection_config>& conf)
|
||||||
@ -206,9 +203,9 @@ namespace sqlpp
|
|||||||
if (!postgres)
|
if (!postgres)
|
||||||
throw std::bad_alloc();
|
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));
|
throw broken_connection(std::move(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,10 +222,21 @@ namespace sqlpp
|
|||||||
inline void connection_handle::deallocate_prepared_statement(const std::string& name)
|
inline void connection_handle::deallocate_prepared_statement(const std::string& name)
|
||||||
{
|
{
|
||||||
std::string cmd = "DEALLOCATE \"" + name + "\"";
|
std::string cmd = "DEALLOCATE \"" + name + "\"";
|
||||||
PGresult* result = PQexec(postgres.get(), cmd.c_str());
|
PGresult* result = PQexec(native_handle(), cmd.c_str());
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
prepared_statement_names.erase(name);
|
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;
|
valid = false;
|
||||||
count = 0;
|
count = 0;
|
||||||
totalCount = 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
|
/// @todo validate result? is it really valid
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ namespace sqlpp
|
|||||||
inline void prepared_statement_handle_t::prepare(std::string stmt)
|
inline void prepared_statement_handle_t::prepare(std::string stmt)
|
||||||
{
|
{
|
||||||
// Create the prepared statement
|
// 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;
|
valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright © 2014-2015, Matthijs Möhlmann
|
* Copyright © 2014-2015, Matthijs Möhlmann
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -29,6 +30,7 @@
|
|||||||
#define SQLPP_POSTGRESQL_H
|
#define SQLPP_POSTGRESQL_H
|
||||||
|
|
||||||
#include <sqlpp11/postgresql/connection.h>
|
#include <sqlpp11/postgresql/connection.h>
|
||||||
|
#include <sqlpp11/postgresql/connection_pool.h>
|
||||||
#include <sqlpp11/postgresql/exception.h>
|
#include <sqlpp11/postgresql/exception.h>
|
||||||
#include <sqlpp11/postgresql/insert.h>
|
#include <sqlpp11/postgresql/insert.h>
|
||||||
#include <sqlpp11/postgresql/update.h>
|
#include <sqlpp11/postgresql/update.h>
|
||||||
|
@ -44,7 +44,7 @@ namespace sqlpp
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
class connection;
|
class connection_base;
|
||||||
|
|
||||||
// Detail namespace
|
// Detail namespace
|
||||||
namespace detail
|
namespace detail
|
||||||
@ -54,9 +54,9 @@ namespace sqlpp
|
|||||||
|
|
||||||
class prepared_statement_t
|
class prepared_statement_t
|
||||||
{
|
{
|
||||||
friend sqlpp::postgresql::connection;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class sqlpp::postgresql::connection_base;
|
||||||
|
|
||||||
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -40,7 +40,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace postgresql
|
namespace postgresql
|
||||||
{
|
{
|
||||||
class connection;
|
// Forward declaration
|
||||||
|
class connection_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@ -93,8 +94,8 @@ namespace sqlpp
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename NameType, bool CanBeNull>
|
template <typename NameType, bool CanBeNull>
|
||||||
struct result_field_t<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, field_spec_t<NameType, blob, CanBeNull>>
|
: public result_field_base<postgresql::connection_base, field_spec_t<NameType, blob, CanBeNull>>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const uint8_t* _blob{nullptr}; // Non-owning
|
const uint8_t* _blob{nullptr}; // Non-owning
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 - 2016, Roland Bock
|
* Copyright (c) 2013 - 2016, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -72,18 +73,20 @@ namespace sqlpp
|
|||||||
|
|
||||||
struct connection_handle
|
struct connection_handle
|
||||||
{
|
{
|
||||||
connection_config config;
|
std::shared_ptr<const connection_config> config;
|
||||||
std::unique_ptr<::sqlite3, void (*)(::sqlite3*)> sqlite;
|
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
|
#ifdef SQLPP_DYNAMIC_LOADING
|
||||||
init_sqlite("");
|
init_sqlite("");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
::sqlite3* sqlite_ptr;
|
::sqlite3* sqlite_ptr;
|
||||||
const auto rc = sqlite3_open_v2(conf.path_to_database.c_str(), &sqlite_ptr, conf.flags,
|
const auto rc = sqlite3_open_v2(conf->path_to_database.c_str(), &sqlite_ptr, conf->flags,
|
||||||
conf.vfs.empty() ? nullptr : conf.vfs.c_str());
|
conf->vfs.empty() ? nullptr : conf->vfs.c_str());
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
const std::string msg = sqlite3_errmsg(sqlite_ptr);
|
const std::string msg = sqlite3_errmsg(sqlite_ptr);
|
||||||
@ -94,13 +97,13 @@ namespace sqlpp
|
|||||||
sqlite.reset(sqlite_ptr);
|
sqlite.reset(sqlite_ptr);
|
||||||
|
|
||||||
#ifdef SQLITE_HAS_CODEC
|
#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)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
const std::string msg = sqlite3_errmsg(sqlite.get());
|
const std::string msg = sqlite3_errmsg(native_handle());
|
||||||
sqlite3_close(sqlite.get());
|
sqlite3_close(native_handle());
|
||||||
throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg);
|
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(connection_handle&&) = default;
|
||||||
connection_handle& operator=(const connection_handle&) = delete;
|
connection_handle& operator=(const connection_handle&) = delete;
|
||||||
connection_handle& operator=(connection_handle&&) = default;
|
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)
|
const std::string& statement)
|
||||||
{
|
{
|
||||||
if (handle.config.debug)
|
if (handle->config->debug)
|
||||||
std::cerr << "Sqlite3 debug: Preparing: '" << statement << "'" << std::endl;
|
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);
|
&result.sqlite_statement, nullptr);
|
||||||
|
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception(
|
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");
|
" (statement was >>" + (rc == SQLITE_TOOBIG ? statement.substr(0, 128) + "..." : statement) + "<<\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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);
|
auto rc = sqlite3_step(prepared.sqlite_statement);
|
||||||
switch (rc)
|
switch (rc)
|
||||||
@ -145,19 +157,20 @@ namespace sqlpp
|
|||||||
case SQLITE_DONE:
|
case SQLITE_DONE:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
if (handle.config.debug)
|
if (handle->config->debug)
|
||||||
std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl;
|
std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl;
|
||||||
throw sqlpp::exception("Sqlite3 error: Could not execute statement: " +
|
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
|
} // namespace detail
|
||||||
|
|
||||||
class connection;
|
// Forward declaration
|
||||||
|
class connection_base;
|
||||||
|
|
||||||
struct serializer_t
|
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;
|
++_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection& _db;
|
const connection_base& _db;
|
||||||
sqlpp::detail::float_safe_ostringstream _os;
|
sqlpp::detail::float_safe_ostringstream _os;
|
||||||
size_t _count;
|
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
|
enum class transaction_status_type
|
||||||
{
|
{
|
||||||
none,
|
none,
|
||||||
@ -219,21 +233,21 @@ namespace sqlpp
|
|||||||
auto prepared = prepare_statement(_handle, statement);
|
auto prepared = prepare_statement(_handle, statement);
|
||||||
execute_statement(_handle, prepared);
|
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)
|
size_t update_impl(const std::string& statement)
|
||||||
{
|
{
|
||||||
auto prepared = prepare_statement(_handle, statement);
|
auto prepared = prepare_statement(_handle, statement);
|
||||||
execute_statement(_handle, prepared);
|
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)
|
size_t remove_impl(const std::string& statement)
|
||||||
{
|
{
|
||||||
auto prepared = prepare_statement(_handle, statement);
|
auto prepared = prepare_statement(_handle, statement);
|
||||||
execute_statement(_handle, prepared);
|
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
|
// prepared execution
|
||||||
@ -252,31 +266,37 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
execute_statement(_handle, *prepared_statement._handle.get());
|
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)
|
size_t run_prepared_update_impl(prepared_statement_t& prepared_statement)
|
||||||
{
|
{
|
||||||
execute_statement(_handle, *prepared_statement._handle.get());
|
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)
|
size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement)
|
||||||
{
|
{
|
||||||
execute_statement(_handle, *prepared_statement._handle.get());
|
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)
|
size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement)
|
||||||
{
|
{
|
||||||
execute_statement(_handle, *prepared_statement._handle.get());
|
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:
|
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 _prepared_statement_t = prepared_statement_t;
|
||||||
using _context_t = serializer_t;
|
using _context_t = serializer_t;
|
||||||
using _serializer_context_t = _context_t;
|
using _serializer_context_t = _context_t;
|
||||||
@ -299,18 +319,6 @@ namespace sqlpp
|
|||||||
return ::sqlpp::serialize(t, context);
|
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)
|
//! select returns a result (which can be iterated row by row)
|
||||||
template <typename Select>
|
template <typename Select>
|
||||||
bind_result_t select(const Select& s)
|
bind_result_t select(const Select& s)
|
||||||
@ -416,7 +424,7 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
auto prepared = prepare_statement(_handle, statement);
|
auto prepared = prepare_statement(_handle, statement);
|
||||||
execute_statement(_handle, prepared);
|
execute_statement(_handle, prepared);
|
||||||
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
|
return static_cast<size_t>(sqlite3_changes(native_handle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@ -573,12 +581,12 @@ namespace sqlpp
|
|||||||
//! get the last inserted id
|
//! get the last inserted id
|
||||||
uint64_t last_insert_id() noexcept
|
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)
|
schema_t attach(const connection_config& config, const std::string name)
|
||||||
@ -589,12 +597,25 @@ namespace sqlpp
|
|||||||
|
|
||||||
return {name};
|
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)
|
inline std::string serializer_t::escape(std::string arg)
|
||||||
{
|
{
|
||||||
return _db.escape(arg);
|
return _db.escape(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using connection = sqlpp::normal_connection<connection_base>;
|
||||||
|
using pooled_connection = sqlpp::pooled_connection<connection_base>;
|
||||||
} // namespace sqlite3
|
} // namespace sqlite3
|
||||||
} // namespace sqlpp
|
} // 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
|
namespace sqlite3
|
||||||
{
|
{
|
||||||
|
// Forward declaration
|
||||||
|
class connection_base;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
inline void check_bind_result(int result, const char* const type)
|
inline void check_bind_result(int result, const char* const type)
|
||||||
@ -70,11 +73,9 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
class connection;
|
|
||||||
|
|
||||||
class SQLPP11_SQLITE3_EXPORT prepared_statement_t
|
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;
|
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -42,8 +42,6 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
namespace sqlite3
|
namespace sqlite3
|
||||||
{
|
{
|
||||||
class connection;
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
struct prepared_statement_handle_t
|
struct prepared_statement_handle_t
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 - 2015, Roland Bock
|
* Copyright (c) 2013 - 2015, Roland Bock
|
||||||
|
* Copyright (c) 2023, Vesselin Atanasov
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -28,6 +29,7 @@
|
|||||||
#define SQLPP_SQLITE3_H
|
#define SQLPP_SQLITE3_H
|
||||||
|
|
||||||
#include <sqlpp11/sqlite3/connection.h>
|
#include <sqlpp11/sqlite3/connection.h>
|
||||||
|
#include <sqlpp11/sqlite3/connection_pool.h>
|
||||||
#include <sqlpp11/sqlite3/insert_or.h>
|
#include <sqlpp11/sqlite3/insert_or.h>
|
||||||
|
|
||||||
#endif
|
#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
|
Truncated.cpp
|
||||||
Update.cpp
|
Update.cpp
|
||||||
Remove.cpp
|
Remove.cpp
|
||||||
|
ConnectionPool.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
||||||
|
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 <iostream>
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
#include <sqlpp11/custom_query.h>
|
#include <sqlpp11/custom_query.h>
|
||||||
@ -59,28 +60,13 @@ namespace
|
|||||||
|
|
||||||
const auto tab = TabSample{};
|
const auto tab = TabSample{};
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int CustomQuery(int, char*[])
|
int CustomQuery(int, char*[])
|
||||||
{
|
{
|
||||||
mysql::global_library_init();
|
sql::global_library_init();
|
||||||
|
|
||||||
auto config = std::make_shared<mysql::connection_config>();
|
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/mysql/mysql.h>
|
#include <sqlpp11/mysql/mysql.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
@ -68,32 +69,13 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int DateTime(int, char*[])
|
int DateTime(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<mysql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(SET time_zone = '+00:00')"); // To force MySQL's CURRENT_TIMESTAMP into the right timezone
|
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"(DROP TABLE IF EXISTS tab_date_time)");
|
||||||
db.execute(R"(CREATE TABLE tab_date_time (
|
db.execute(R"(CREATE TABLE tab_date_time (
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/alias_provider.h>
|
#include <sqlpp11/alias_provider.h>
|
||||||
#include <sqlpp11/functions.h>
|
#include <sqlpp11/functions.h>
|
||||||
@ -38,27 +39,13 @@
|
|||||||
|
|
||||||
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
|
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int DynamicSelect(int, char*[])
|
int DynamicSelect(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<mysql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) DEFAULT NULL,
|
alpha bigint(20) DEFAULT NULL,
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
|
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -52,28 +54,13 @@ namespace test
|
|||||||
SQLPP_ALIAS_PROVIDER(value)
|
SQLPP_ALIAS_PROVIDER(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int Json(int, char*[])
|
int Json(int, char*[])
|
||||||
{
|
{
|
||||||
mysql::global_library_init();
|
sql::global_library_init();
|
||||||
|
|
||||||
auto config = std::make_shared<mysql::connection_config>();
|
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_json)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_json)");
|
||||||
db.execute(R"(CREATE TABLE tab_json (
|
db.execute(R"(CREATE TABLE tab_json (
|
||||||
data JSON NOT NULL
|
data JSON NOT NULL
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/alias_provider.h>
|
#include <sqlpp11/alias_provider.h>
|
||||||
#include <sqlpp11/functions.h>
|
#include <sqlpp11/functions.h>
|
||||||
@ -37,29 +38,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int MoveConstructor(int, char*[])
|
int MoveConstructor(int, char*[])
|
||||||
{
|
{
|
||||||
mysql::global_library_init();
|
sql::global_library_init();
|
||||||
|
auto config = sql::make_test_config();
|
||||||
auto config = std::make_shared<mysql::connection_config>();
|
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
std::vector<sql::connection> connections;
|
||||||
}
|
connections.emplace_back(sql::connection(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));
|
|
||||||
|
|
||||||
connections.at(0).execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
connections.at(0).execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
connections.at(0).execute(R"(CREATE TABLE tab_sample (
|
connections.at(0).execute(R"(CREATE TABLE tab_sample (
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sqlpp11/alias_provider.h>
|
#include <sqlpp11/alias_provider.h>
|
||||||
@ -69,23 +70,10 @@ void testPreparedStatementResult(sql::connection& db)
|
|||||||
|
|
||||||
int Prepared(int, char*[])
|
int Prepared(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/mysql/mysql.h>
|
#include <sqlpp11/mysql/mysql.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
@ -36,23 +37,10 @@ namespace sql = sqlpp::mysql;
|
|||||||
|
|
||||||
int Remove(int, char*[])
|
int Remove(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/mysql/mysql.h>
|
#include <sqlpp11/mysql/mysql.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
@ -31,29 +32,13 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace mysql = sqlpp::mysql;
|
namespace sql = sqlpp::mysql;
|
||||||
int Sample(int, char*[])
|
int Sample(int, char*[])
|
||||||
{
|
{
|
||||||
sqlpp::mysql::global_library_init();
|
sql::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;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mysql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sqlpp11/alias_provider.h>
|
#include <sqlpp11/alias_provider.h>
|
||||||
@ -83,23 +84,9 @@ void testSelectAll(sql::connection& db, int expectedRowCount)
|
|||||||
|
|
||||||
int Select(int, char*[])
|
int Select(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sqlpp11/alias_provider.h>
|
#include <sqlpp11/alias_provider.h>
|
||||||
@ -44,24 +45,10 @@ const auto tab = TabSample{};
|
|||||||
|
|
||||||
int Truncated(int, char*[])
|
int Truncated(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
config->charset = "utf8";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/mysql/connection.h>
|
#include <sqlpp11/mysql/connection.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
@ -36,23 +37,10 @@ const auto tab = TabSample{};
|
|||||||
|
|
||||||
int Union(int, char*[])
|
int Union(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
alpha bigint(20) AUTO_INCREMENT,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "make_test_connection.h"
|
||||||
#include "TabSample.h"
|
#include "TabSample.h"
|
||||||
#include <sqlpp11/mysql/mysql.h>
|
#include <sqlpp11/mysql/mysql.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
@ -36,23 +37,10 @@ namespace sql = sqlpp::mysql;
|
|||||||
|
|
||||||
int Update(int, char*[])
|
int Update(int, char*[])
|
||||||
{
|
{
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
sql::global_library_init();
|
||||||
config->user = "root";
|
|
||||||
config->database = "sqlpp_mysql";
|
|
||||||
config->debug = true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sql::connection db(config);
|
auto db = sql::make_test_connection();
|
||||||
}
|
|
||||||
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);
|
|
||||||
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
|
||||||
db.execute(R"(CREATE TABLE tab_sample (
|
db.execute(R"(CREATE TABLE tab_sample (
|
||||||
alpha bigint(20) AUTO_INCREMENT,
|
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
|
Basic.cpp
|
||||||
BasicConstConfig.cpp
|
BasicConstConfig.cpp
|
||||||
Blob.cpp
|
Blob.cpp
|
||||||
|
ConnectionPool.cpp
|
||||||
Constructor.cpp
|
Constructor.cpp
|
||||||
Date.cpp
|
Date.cpp
|
||||||
DateTime.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
|
namespace postgresql
|
||||||
{
|
{
|
||||||
// Starts a connection and sets the time zone to UTC
|
// Get configuration for test connection
|
||||||
inline ::sqlpp::postgresql::connection make_test_connection()
|
inline std::shared_ptr<sqlpp::postgresql::connection_config> make_test_config()
|
||||||
{
|
{
|
||||||
namespace sql = sqlpp::postgresql;
|
auto config = std::make_shared<sqlpp::postgresql::connection_config>();
|
||||||
|
|
||||||
auto config = std::make_shared<sql::connection_config>();
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
config->dbname = "test";
|
config->dbname = "test";
|
||||||
@ -49,6 +47,15 @@ namespace sqlpp
|
|||||||
config->dbname = "sqlpp_postgresql";
|
config->dbname = "sqlpp_postgresql";
|
||||||
config->debug = true;
|
config->debug = true;
|
||||||
#endif
|
#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;
|
sql::connection db;
|
||||||
try
|
try
|
||||||
|
@ -38,6 +38,7 @@ set(test_files
|
|||||||
FloatingPoint.cpp
|
FloatingPoint.cpp
|
||||||
Integral.cpp
|
Integral.cpp
|
||||||
Blob.cpp
|
Blob.cpp
|
||||||
|
ConnectionPool.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
create_test_sourcelist(test_sources test_main.cpp ${test_files})
|
||||||
|
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