mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-15 20:31:16 +08:00
Merge tag '0.49' into develop
Add get default transaction isolation level function (thanks volka)
This commit is contained in:
commit
8113a5f1fc
1
_config.yml
Normal file
1
_config.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
theme: jekyll-theme-minimal
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sqlpp11/connection.h>
|
#include <sqlpp11/connection.h>
|
||||||
|
#include <sqlpp11/transaction.h>
|
||||||
#include <sqlpp11/database/char_result.h> // You may use char result or bind result or both
|
#include <sqlpp11/database/char_result.h> // You may use char result or bind result or both
|
||||||
#include <sqlpp11/database/bind_result.h> // to represent results of select and prepared select
|
#include <sqlpp11/database/bind_result.h> // to represent results of select and prepared select
|
||||||
|
|
||||||
@ -129,9 +130,20 @@ namespace sqlpp
|
|||||||
return t._prepare(*this);
|
return t._prepare(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! set the transaction isolation level for the current connection
|
||||||
|
/// time of effect is connector-specific, for most is will only affect new transactions
|
||||||
|
void set_default_isolation_level(sqlpp::isolation_level);
|
||||||
|
|
||||||
|
//! read the default transaction isolation level for the current connection
|
||||||
|
sqlpp::isolation_level get_default_isolation_level();
|
||||||
|
|
||||||
//! start transaction
|
//! start transaction
|
||||||
void start_transaction();
|
void start_transaction();
|
||||||
|
|
||||||
|
//! start transaction with defined isolation level (optional only for connectors that support it)
|
||||||
|
void start_transaction(isolation_level isolation /* = isolation_level::undefined */);
|
||||||
|
|
||||||
//! commit transaction (or throw transaction if the transaction has been finished already)
|
//! commit transaction (or throw transaction if the transaction has been finished already)
|
||||||
void commit_transaction();
|
void commit_transaction();
|
||||||
|
|
||||||
|
192
include/sqlpp11/connection_pool.h
Normal file
192
include/sqlpp11/connection_pool.h
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 - 2017, Roland Bock, Frank Park
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SQLPP_CONNECTION_POOL_H
|
||||||
|
#define SQLPP_CONNECTION_POOL_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <stack>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <sqlpp11/exception.h>
|
||||||
|
#include <sqlpp11/pool_connection.h>
|
||||||
|
|
||||||
|
namespace sqlpp
|
||||||
|
{
|
||||||
|
namespace reconnect_policy
|
||||||
|
{
|
||||||
|
struct auto_reconnect {
|
||||||
|
template<typename Connection>
|
||||||
|
void operator()(Connection* connection)
|
||||||
|
{
|
||||||
|
if(!connection->is_valid())
|
||||||
|
connection->reconnect()
|
||||||
|
}
|
||||||
|
template<typename Connection>
|
||||||
|
void clean(Connection* connection) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
class periodic_reconnect
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::chrono::seconds revalidate_after;
|
||||||
|
std::unordered_map<void*,std::chrono::time_point<std::chrono::system_clock> > last_checked;
|
||||||
|
|
||||||
|
public:
|
||||||
|
periodic_reconnect(const std::chrono::seconds r = 28800s) //default wait_timeout in MySQL
|
||||||
|
: revalidate_after(r), last_checked() {}
|
||||||
|
|
||||||
|
template<typename Connection>
|
||||||
|
void operator()(Connection* con)
|
||||||
|
{
|
||||||
|
auto last = last_checked.find(con);
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
if(last == last_checked.end())
|
||||||
|
{
|
||||||
|
if (!con->is_valid())
|
||||||
|
{
|
||||||
|
con->reconnect();
|
||||||
|
}
|
||||||
|
last_checked.emplace_hint(last, con, now);
|
||||||
|
}
|
||||||
|
else if(now - last->second > revalidate_after)
|
||||||
|
{
|
||||||
|
if (!con->is_valid())
|
||||||
|
{
|
||||||
|
con->reconnect();
|
||||||
|
}
|
||||||
|
last = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename Connection>
|
||||||
|
void clean(Connection* con) {
|
||||||
|
auto itr = last_checked.find(con);
|
||||||
|
if(itr != last_checked.end())
|
||||||
|
{
|
||||||
|
last_checked.erase(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct never_reconnect {
|
||||||
|
template<typename Connection>
|
||||||
|
void operator()(Connection*) {}
|
||||||
|
template<typename Connection>
|
||||||
|
void clean(Connection*) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Connection_config,
|
||||||
|
typename Reconnect_policy = reconnect_policy::auto_reconnect,
|
||||||
|
typename Connection = typename std::enable_if<std::is_class<Connection_config::connection>::value, Connection_config::connection>::type>
|
||||||
|
class connection_pool
|
||||||
|
{
|
||||||
|
friend pool_connection<Connection_config, Reconnect_policy, Connection>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex connection_pool_mutex;
|
||||||
|
const std::shared_ptr<Connection_config> config;
|
||||||
|
size_t maximum_pool_size = 0;
|
||||||
|
std::stack<std::unique_ptr<Connection>> free_connections;
|
||||||
|
Reconnect_policy reconnect_policy;
|
||||||
|
|
||||||
|
void free_connection(std::unique_ptr<Connection>& connection)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(connection_pool_mutex);
|
||||||
|
if (free_connections.size() >= maximum_pool_size)
|
||||||
|
{
|
||||||
|
// Exceeds default size, do nothign and let connection self destroy.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (connection.get())
|
||||||
|
{
|
||||||
|
if (connection->is_valid())
|
||||||
|
{
|
||||||
|
free_connections.push(std::move(connection));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw sqlpp::exception("Trying to free a connection with incompatible config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw sqlpp::exception("Trying to free an empty connection.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
connection_pool(const std::shared_ptr<Connection_config>& config, size_t pool_size)
|
||||||
|
: config(config), maximum_pool_size(pool_size), reconnect_policy(Reconnect_policy()) {}
|
||||||
|
~connection_pool() = default;
|
||||||
|
connection_pool(const connection_pool&) = delete;
|
||||||
|
connection_pool(connection_pool&& other)
|
||||||
|
: config(std::move(other.config)), maximum_pool_size(std::move(other.maximum_pool_size)),
|
||||||
|
reconnect_policy(std::move(other.reconnect_policy)) {}
|
||||||
|
connection_pool& operator=(const connection_pool&) = delete;
|
||||||
|
connection_pool& operator=(connection_pool&&) = delete;
|
||||||
|
|
||||||
|
pool_connection<Connection_config, Reconnect_policy, Connection> get_connection()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(connection_pool_mutex);
|
||||||
|
if (!free_connections.empty())
|
||||||
|
{
|
||||||
|
auto connection = std::move(free_connections.top());
|
||||||
|
free_connections.pop();
|
||||||
|
return pool_connection<Connection_config, Reconnect_policy, Connection>(connection, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return pool_connection<Connection_config, Reconnect_policy, Connection>(std::move(std::make_unique<Connection>(config)), this);
|
||||||
|
}
|
||||||
|
catch (const sqlpp::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to spawn a new connection." << std::endl;
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Connection_config,
|
||||||
|
typename Reconnect_policy = reconnect_policy::auto_reconnect,
|
||||||
|
typename Connection = typename std::enable_if<std::is_class<Connection_config::connection>::value,Connection_config::connection>::type>
|
||||||
|
connection_pool<Connection_config, Reconnect_policy, Connection> make_connection_pool(
|
||||||
|
const std::shared_ptr<Connection_config>& config,
|
||||||
|
size_t max_pool_size)
|
||||||
|
{
|
||||||
|
return connection_pool<Connection_config, Reconnect_policy, Connection>(config, max_pool_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
179
include/sqlpp11/for_update.h
Normal file
179
include/sqlpp11/for_update.h
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Serge Robyns
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SQLPP_FOR_UPDATE_H
|
||||||
|
#define SQLPP_FOR_UPDATE_H
|
||||||
|
|
||||||
|
#include <sqlpp11/detail/type_set.h>
|
||||||
|
#include <sqlpp11/policy_update.h>
|
||||||
|
#include <sqlpp11/type_traits.h>
|
||||||
|
|
||||||
|
namespace sqlpp
|
||||||
|
{
|
||||||
|
// FOR_UPDATE DATA
|
||||||
|
struct for_update_data_t
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
// FOR_UPDATE
|
||||||
|
struct for_update_t
|
||||||
|
{
|
||||||
|
using _traits = make_traits<no_value_t, tag::is_for_update>;
|
||||||
|
using _nodes = detail::type_vector<>;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
using _data_t = for_update_data_t;
|
||||||
|
|
||||||
|
// Member implementation with data and methods
|
||||||
|
template <typename Policies>
|
||||||
|
struct _impl_t
|
||||||
|
{
|
||||||
|
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069
|
||||||
|
_impl_t() = default;
|
||||||
|
_impl_t(const _data_t& data) : _data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_data_t _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base template to be inherited by the statement
|
||||||
|
template <typename Policies>
|
||||||
|
struct _base_t
|
||||||
|
{
|
||||||
|
using _data_t = for_update_data_t;
|
||||||
|
|
||||||
|
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069
|
||||||
|
template <typename... Args>
|
||||||
|
_base_t(Args&&... args) : for_update{std::forward<Args>(args)...}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_impl_t<Policies> for_update;
|
||||||
|
_impl_t<Policies>& operator()()
|
||||||
|
{
|
||||||
|
return for_update;
|
||||||
|
}
|
||||||
|
const _impl_t<Policies>& operator()() const
|
||||||
|
{
|
||||||
|
return for_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static auto _get_member(T t) -> decltype(t.for_update)
|
||||||
|
{
|
||||||
|
return t.for_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
using _consistency_check = consistent_t;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct no_for_update_t
|
||||||
|
{
|
||||||
|
using _traits = make_traits<no_value_t, tag::is_noop>;
|
||||||
|
using _nodes = detail::type_vector<>;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
using _data_t = no_data_t;
|
||||||
|
|
||||||
|
// Member implementation with data and methods
|
||||||
|
template <typename Policies>
|
||||||
|
struct _impl_t
|
||||||
|
{
|
||||||
|
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069
|
||||||
|
_impl_t() = default;
|
||||||
|
_impl_t(const _data_t& data) : _data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_data_t _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base template to be inherited by the statement
|
||||||
|
template <typename Policies>
|
||||||
|
struct _base_t
|
||||||
|
{
|
||||||
|
using _data_t = no_data_t;
|
||||||
|
|
||||||
|
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069
|
||||||
|
template <typename... Args>
|
||||||
|
_base_t(Args&&... args) : no_for_update{std::forward<Args>(args)...}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_impl_t<Policies> no_for_update;
|
||||||
|
_impl_t<Policies>& operator()()
|
||||||
|
{
|
||||||
|
return no_for_update;
|
||||||
|
}
|
||||||
|
const _impl_t<Policies>& operator()() const
|
||||||
|
{
|
||||||
|
return no_for_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static auto _get_member(T t) -> decltype(t.no_for_update)
|
||||||
|
{
|
||||||
|
return t.no_for_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
using _database_t = typename Policies::_database_t;
|
||||||
|
|
||||||
|
template <typename Check, typename T>
|
||||||
|
using _new_statement_t = new_statement_t<Check, Policies, no_for_update_t, T>;
|
||||||
|
|
||||||
|
using _consistency_check = consistent_t;
|
||||||
|
|
||||||
|
auto for_update() const -> _new_statement_t<consistent_t, for_update_t>
|
||||||
|
{
|
||||||
|
return {static_cast<const derived_statement_t<Policies>&>(*this), for_update_data_t{}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interpreters
|
||||||
|
template <typename Context>
|
||||||
|
struct serializer_t<Context, for_update_data_t>
|
||||||
|
{
|
||||||
|
using _serialize_check = serialize_check_of<Context>;
|
||||||
|
using T = for_update_data_t;
|
||||||
|
|
||||||
|
static Context& _(const T& t, Context& context)
|
||||||
|
{
|
||||||
|
context << " FOR UPDATE ";
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto for_update(T&& t) -> decltype(statement_t<void, no_for_update_t>().for_update(std::forward<T>(t)))
|
||||||
|
{
|
||||||
|
return statement_t<void, no_for_update_t>().for_update(std::forward<T>(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
76
include/sqlpp11/pool_connection.h
Normal file
76
include/sqlpp11/pool_connection.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 - 2017, Roland Bock, Frank Park
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SQLPP_POOL_CONNECTION_H
|
||||||
|
#define SQLPP_POOL_CONNECTION_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace sqlpp
|
||||||
|
{
|
||||||
|
template <typename Connection_config, typename Reconnect_policy, typename Connection,
|
||||||
|
typename Connection_pool = connection_pool<Connection_config, Reconnect_policy, Connection>>
|
||||||
|
struct pool_connection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Connection> _impl;
|
||||||
|
Connection_pool* origin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
pool_connection(std::unique_ptr<Connection>& connection, Connection_pool* origin)
|
||||||
|
: _impl(std::move(connection)), origin(origin) {}
|
||||||
|
|
||||||
|
~pool_connection()
|
||||||
|
{
|
||||||
|
origin->free_connection(_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
auto operator()(Args&&... args) -> decltype(_impl->args(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return _impl->args(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto operator()(const T& t) -> decltype(_impl->run(t))
|
||||||
|
{
|
||||||
|
return _impl->run(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection* operator->()
|
||||||
|
{
|
||||||
|
return &_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_connection(const pool_connection&) = delete;
|
||||||
|
pool_connection(pool_connection&& other)
|
||||||
|
: _impl(std::move(other._impl)), origin(other.origin) {}
|
||||||
|
pool_connection& operator=(const pool_connection&) = delete;
|
||||||
|
pool_connection& operator=(pool_connection&&) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -40,6 +40,7 @@
|
|||||||
#include <sqlpp11/having.h>
|
#include <sqlpp11/having.h>
|
||||||
#include <sqlpp11/order_by.h>
|
#include <sqlpp11/order_by.h>
|
||||||
#include <sqlpp11/limit.h>
|
#include <sqlpp11/limit.h>
|
||||||
|
#include <sqlpp11/for_update.h>
|
||||||
#include <sqlpp11/offset.h>
|
#include <sqlpp11/offset.h>
|
||||||
#include <sqlpp11/union.h>
|
#include <sqlpp11/union.h>
|
||||||
#include <sqlpp11/expression.h>
|
#include <sqlpp11/expression.h>
|
||||||
@ -82,7 +83,8 @@ namespace sqlpp
|
|||||||
no_order_by_t,
|
no_order_by_t,
|
||||||
no_limit_t,
|
no_limit_t,
|
||||||
no_offset_t,
|
no_offset_t,
|
||||||
no_union_t>;
|
no_union_t,
|
||||||
|
no_for_update_t>;
|
||||||
|
|
||||||
inline blank_select_t<void> select() // FIXME: These should be constexpr
|
inline blank_select_t<void> select() // FIXME: These should be constexpr
|
||||||
{
|
{
|
||||||
|
@ -28,12 +28,21 @@
|
|||||||
#define SQLPP_TRANSACTION_H
|
#define SQLPP_TRANSACTION_H
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <ciso646>
|
||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
static constexpr bool quiet_auto_rollback = false;
|
static constexpr bool quiet_auto_rollback = false;
|
||||||
static constexpr bool report_auto_rollback = true;
|
static constexpr bool report_auto_rollback = true;
|
||||||
|
|
||||||
|
enum class isolation_level {
|
||||||
|
undefined, // use the current database default
|
||||||
|
serializable, // highest level, stronguest guarantee
|
||||||
|
repeatable_read, // DBMS holds read and write locks
|
||||||
|
read_committed, // DMBS holds read locks, non-repeatable reads can occur
|
||||||
|
read_uncommitted // lowest isolation level, dirty reads may occur
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Db>
|
template <typename Db>
|
||||||
class transaction_t
|
class transaction_t
|
||||||
{
|
{
|
||||||
@ -48,6 +57,12 @@ namespace sqlpp
|
|||||||
_db.start_transaction();
|
_db.start_transaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transaction_t(Db& db, bool report_unfinished_transaction, isolation_level isolation)
|
||||||
|
: _db(db), _report_unfinished_transaction(report_unfinished_transaction)
|
||||||
|
{
|
||||||
|
_db.start_transaction(isolation);
|
||||||
|
}
|
||||||
|
|
||||||
transaction_t(const transaction_t&) = delete;
|
transaction_t(const transaction_t&) = delete;
|
||||||
transaction_t(transaction_t&&) = default;
|
transaction_t(transaction_t&&) = default;
|
||||||
transaction_t& operator=(const transaction_t&) = delete;
|
transaction_t& operator=(const transaction_t&) = delete;
|
||||||
@ -88,7 +103,13 @@ namespace sqlpp
|
|||||||
template <typename Db>
|
template <typename Db>
|
||||||
transaction_t<Db> start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback)
|
transaction_t<Db> start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback)
|
||||||
{
|
{
|
||||||
return {db, report_unfinished_transaction};
|
return {db, report_unfinished_transaction};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Db>
|
||||||
|
transaction_t<Db> start_transaction(Db& db, isolation_level isolation, bool report_unfinished_transaction = report_auto_rollback)
|
||||||
|
{
|
||||||
|
return {db, report_unfinished_transaction, isolation};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +200,7 @@ namespace sqlpp
|
|||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_having)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_having)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_order_by)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_order_by)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_limit)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_limit)
|
||||||
|
SQLPP_VALUE_TRAIT_GENERATOR(is_for_update)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_offset)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_offset)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_using_)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_using_)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_column_list)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_column_list)
|
||||||
|
@ -204,6 +204,7 @@ types = {
|
|||||||
'integer': 'integer',
|
'integer': 'integer',
|
||||||
'int': 'integer',
|
'int': 'integer',
|
||||||
'serial': 'integer', # PostgreSQL
|
'serial': 'integer', # PostgreSQL
|
||||||
|
'mediumint' : 'integer',
|
||||||
'bigint': 'bigint',
|
'bigint': 'bigint',
|
||||||
'bigserial': 'bigint', # PostgreSQL
|
'bigserial': 'bigint', # PostgreSQL
|
||||||
'char': 'char_',
|
'char': 'char_',
|
||||||
|
@ -30,6 +30,7 @@ set(test_serializer_names
|
|||||||
Insert
|
Insert
|
||||||
TableAlias
|
TableAlias
|
||||||
Where
|
Where
|
||||||
|
ForUpdate
|
||||||
)
|
)
|
||||||
|
|
||||||
create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names})
|
create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names})
|
||||||
|
60
test_serializer/ForUpdate.cpp
Normal file
60
test_serializer/ForUpdate.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Serge Robyns
|
||||||
|
* 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 "compare.h"
|
||||||
|
#include "Sample.h"
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
auto getTrue() -> std::string
|
||||||
|
{
|
||||||
|
MockDb::_serializer_context_t printer = {};
|
||||||
|
return serialize(sqlpp::value(true), printer).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getFalse() -> std::string
|
||||||
|
{
|
||||||
|
MockDb::_serializer_context_t printer = {};
|
||||||
|
return serialize(sqlpp::value(false), printer).str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ForUpdate(int, char* [])
|
||||||
|
{
|
||||||
|
const auto foo = test::TabFoo{};
|
||||||
|
const auto bar = test::TabBar{};
|
||||||
|
|
||||||
|
// Unconditionally
|
||||||
|
compare(__LINE__, select(foo.omega).from(foo).unconditionally().for_update(), "SELECT tab_foo.omega FROM tab_foo FOR UPDATE ");
|
||||||
|
|
||||||
|
// Never
|
||||||
|
compare(__LINE__, where(sqlpp::value(false)), " WHERE " + getFalse());
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -28,12 +28,19 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sqlpp11/connection.h>
|
#include <sqlpp11/connection.h>
|
||||||
|
#include <sqlpp11/transaction.h>
|
||||||
#include <sqlpp11/data_types/no_value.h>
|
#include <sqlpp11/data_types/no_value.h>
|
||||||
#include <sqlpp11/schema.h>
|
#include <sqlpp11/schema.h>
|
||||||
#include <sqlpp11/serialize.h>
|
#include <sqlpp11/serialize.h>
|
||||||
#include <sqlpp11/serializer_context.h>
|
#include <sqlpp11/serializer_context.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
// an object to store internal Mock flags and values to validate in tests
|
||||||
|
struct InternalMockData {
|
||||||
|
sqlpp::isolation_level _last_isolation_level;
|
||||||
|
sqlpp::isolation_level _default_isolation_level;
|
||||||
|
};
|
||||||
|
|
||||||
template <bool enforceNullResultTreatment>
|
template <bool enforceNullResultTreatment>
|
||||||
struct MockDbT : public sqlpp::connection
|
struct MockDbT : public sqlpp::connection
|
||||||
{
|
{
|
||||||
@ -244,6 +251,38 @@ struct MockDbT : public sqlpp::connection
|
|||||||
{
|
{
|
||||||
return {name};
|
return {name};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void start_transaction()
|
||||||
|
{
|
||||||
|
_mock_data._last_isolation_level = _mock_data._default_isolation_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_transaction(sqlpp::isolation_level level)
|
||||||
|
{
|
||||||
|
_mock_data._last_isolation_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_default_isolation_level(sqlpp::isolation_level level)
|
||||||
|
{
|
||||||
|
_mock_data._default_isolation_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlpp::isolation_level get_default_isolation_level()
|
||||||
|
{
|
||||||
|
return _mock_data._default_isolation_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rollback_transaction(bool)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void commit_transaction()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void report_rollback_failure(std::string)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// temporary data store to verify the expected results were produced
|
||||||
|
InternalMockData _mock_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MockDb = MockDbT<false>;
|
using MockDb = MockDbT<false>;
|
||||||
|
@ -107,6 +107,14 @@ int Select(int, char* [])
|
|||||||
std::cout << a << ", " << b << ", " << g << std::endl;
|
std::cout << a << ", " << b << ", " << g << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& row : db(select(all_of(t).as(t), t.gamma).from(t).where(t.alpha > 7).for_update()))
|
||||||
|
{
|
||||||
|
int64_t a = row.tabBar.alpha;
|
||||||
|
const std::string b = row.tabBar.beta;
|
||||||
|
const bool g = row.gamma;
|
||||||
|
std::cout << a << ", " << b << ", " << g << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& row :
|
for (const auto& row :
|
||||||
db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).unconditionally()))
|
db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).unconditionally()))
|
||||||
{
|
{
|
||||||
@ -199,5 +207,22 @@ int Select(int, char* [])
|
|||||||
for_each_field(row, to_cerr{});
|
for_each_field(row, to_cerr{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction = start_transaction(db, sqlpp::isolation_level::read_committed);
|
||||||
|
if (db._mock_data._last_isolation_level != sqlpp::isolation_level::read_committed)
|
||||||
|
{
|
||||||
|
std::cout << "Error: transaction isolation level does not match expected level" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
db.set_default_isolation_level(sqlpp::isolation_level::read_uncommitted);
|
||||||
|
{
|
||||||
|
auto transaction = start_transaction(db);
|
||||||
|
if (db._mock_data._last_isolation_level != sqlpp::isolation_level::read_uncommitted)
|
||||||
|
{
|
||||||
|
std::cout << "Error: transaction isolation level does not match default level" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user