0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Started to migrate postgresql connector into sqlpp11 repo.

Removed timezone handling in the process (needs to be documented).
Note: on_conflict does not check for constraints (needs to be documented).
Note: some of the constraints tests seem to be aiming for a different static_assert.
This commit is contained in:
Roland Bock 2021-11-13 17:54:54 +01:00
parent 13698d07c9
commit 4c942600bb
49 changed files with 6545 additions and 22 deletions

View File

@ -39,25 +39,31 @@ option(SQLCIPHER_CONNECTOR "Build SQLite3 Connector with SQLCipher" OFF)
if(MYSQL_CONNECTOR)
find_package(MySQL REQUIRED)
else()
message(STATUS "Not building MYSQL_CONNECTOR")
message(STATUS "Not building tests for MYSQL_CONNECTOR")
endif()
if(MARIADB_CONNECTOR)
find_package(MariaDB REQUIRED)
else()
message(STATUS "Not building MARIAB_CONNECTOR")
message(STATUS "Not building tests for MARIAB_CONNECTOR")
endif()
if(POSTGRESQL_CONNECTOR)
find_package(PostgreSQL REQUIRED)
else()
message(STATUS "Not building tests for POSTGRESQL_CONNECTOR")
endif()
if(SQLITE3_CONNECTOR)
find_package(SQLite3 REQUIRED)
else()
message(STATUS "Not building SQLITE3_CONNECTOR")
message(STATUS "Not building tests for SQLITE3_CONNECTOR")
endif()
if(SQLCIPHER_CONNECTOR)
find_package(SQLCipher REQUIRED)
else()
message(STATUS "Not building SQLCIPHER_CONNECTOR")
message(STATUS "Not building tests for SQLCIPHER_CONNECTOR")
endif()
include(CTest)

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2021-2021, Roland Bock
* 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 SQLPP11_COLUMN_TUPLE_MERGE_H
#define SQLPP11_COLUMN_TUPLE_MERGE_H
#include <tuple>
#include <sqlpp11/auto_alias.h>
namespace sqlpp
{
namespace detail
{
template <typename T>
std::tuple<auto_alias_t<T>> as_column_tuple(T t)
{
return std::tuple<auto_alias_t<T>>(auto_alias_t<T>{t});
}
template <typename... Args>
std::tuple<auto_alias_t<Args>...> as_column_tuple(std::tuple<Args...> t)
{
return t;
}
template <typename... Columns>
auto column_tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_column_tuple(columns)...))
{
return std::tuple_cat(as_column_tuple(columns)...);
}
}
} // namespace sqlpp
#endif

View File

@ -0,0 +1,397 @@
/**
* Copyright © 2014-2020, Matthijs Möhlmann
* 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_POSTGRESQL_BIND_RESULT_H
#define SQLPP_POSTGRESQL_BIND_RESULT_H
#include <memory>
#include <sqlpp11/chrono.h>
#include <sqlpp11/data_types.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "detail/prepared_statement_handle.h"
#if defined(_WIN32) || defined(_WIN64)
#pragma warning(disable : 4800) // int to bool
#endif
namespace sqlpp
{
namespace postgresql
{
namespace detail
{
struct statement_handle_t;
}
class bind_result_t
{
private:
std::shared_ptr<detail::statement_handle_t> _handle;
bool next_impl();
public:
bind_result_t() = default;
bind_result_t(const std::shared_ptr<detail::statement_handle_t>& handle);
bind_result_t(const bind_result_t&) = delete;
bind_result_t(bind_result_t&&) = default;
bind_result_t& operator=(const bind_result_t&) = delete;
bind_result_t& operator=(bind_result_t&&) = default;
~bind_result_t() = default;
bool operator==(const bind_result_t& rhs) const
{
return (this->_handle == rhs._handle);
}
template <typename ResultRow>
void next(ResultRow& result_row)
{
if (!this->_handle)
{
result_row._invalidate();
return;
}
if (this->next_impl())
{
if (!result_row)
{
result_row._validate();
}
result_row._bind(*this);
}
else
{
if (result_row)
{
result_row._invalidate();
}
}
}
void _bind_boolean_result(size_t index, signed char* value, bool* is_null);
void _bind_floating_point_result(size_t index, double* value, bool* is_null);
void _bind_integral_result(size_t index, int64_t* value, bool* is_null);
void _bind_text_result(size_t index, const char** value, size_t* len);
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null);
void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null);
int size() const;
};
inline bind_result_t::bind_result_t(const std::shared_ptr<detail::statement_handle_t>& handle) : _handle(handle)
{
if (this->_handle && this->_handle->debug())
{
// cerr
std::cerr << "PostgreSQL debug: constructing bind result, using handle at: " << this->_handle.get()
<< std::endl;
}
}
inline bool bind_result_t::next_impl()
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: accessing next row of handle at " << _handle.get() << std::endl;
}
// Fetch total amount
if (_handle->totalCount == 0U)
{
_handle->totalCount = _handle->result.records_size();
if (_handle->totalCount == 0U)
return false;
}
else
{
// Next row
if (_handle->count < (_handle->totalCount - 1))
{
_handle->count++;
}
else
{
return false;
}
}
// Really needed?
if (_handle->fields == 0U)
{
_handle->fields = _handle->result.field_count();
}
return true;
}
inline void bind_result_t::_bind_boolean_result(size_t _index, signed char* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding boolean result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
*value = _handle->result.getValue<bool>(_handle->count, index);
}
inline void bind_result_t::_bind_floating_point_result(size_t _index, double* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding floating_point result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
*value = _handle->result.getValue<double>(_handle->count, index);
}
inline void bind_result_t::_bind_integral_result(size_t _index, int64_t* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding integral result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
*value = _handle->result.getValue<unsigned long long>(_handle->count, index);
}
inline void bind_result_t::_bind_text_result(size_t _index, const char** value, size_t* len)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding text result at index: " << index << std::endl;
}
if (_handle->result.isNull(_handle->count, index))
{
*value = nullptr;
*len = 0;
}
else
{
*value = _handle->result.getValue<const char*>(_handle->count, index);
*len = _handle->result.length(_handle->count, index);
}
}
// same parsing logic as SQLite connector
// PostgreSQL will return one of those (using the default ISO client):
//
// 2010-10-11 01:02:03 - ISO timestamp without timezone
// 2011-11-12 01:02:03.123456 - ISO timesapt with sub-second (microsecond) precision
// 1997-12-17 07:37:16-08 - ISO timestamp with timezone
// 1992-10-10 01:02:03-06:30 - for some timezones with non-hour offset
// 1900-01-01 - date only
// we do not support time-only values !
namespace detail
{
inline auto check_first_digit(const char* text, bool digitFlag) -> bool
{
if (digitFlag)
{
if (not std::isdigit(*text))
{
return false;
}
}
else
{
if (std::isdigit(*text) or *text == '\0')
{
return false;
}
}
return true;
}
inline auto check_date_digits(const char* text) -> bool
{
for (const auto digitFlag : {true, true, true, true, false, true, true, false, true, true}) // YYYY-MM-DD
{
if (not check_first_digit(text, digitFlag))
return false;
++text;
}
return true;
}
inline auto check_time_digits(const char* text) -> bool
{
for (const auto digitFlag : {true, true, false, true, true, false, true, true}) // hh:mm:ss
{
if (not check_first_digit(text, digitFlag))
return false;
++text;
}
return true;
}
inline auto check_us_digits(const char* text) -> bool
{
for (const auto digitFlag : {true, true, true, true, true, true})
{
if (not check_first_digit(text, digitFlag))
return false;
++text;
}
return true;
}
inline auto check_tz_digits(const char* text) -> bool
{
for (const auto digitFlag : {false, true, true, false, true, true})
{
if (not check_first_digit(text, digitFlag))
return false;
++text;
}
return true;
}
} // namespace
inline void bind_result_t::_bind_date_result(size_t _index, ::sqlpp::chrono::day_point* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
if (!(*is_null))
{
const auto date_string = _handle->result.getValue<const char*>(_handle->count, index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: date string: " << date_string << std::endl;
}
if (detail::check_date_digits(date_string))
{
const auto ymd =
::date::year(std::atoi(date_string)) / std::atoi(date_string + 5) / std::atoi(date_string + 8);
*value = ::sqlpp::chrono::day_point(ymd);
}
else
{
if (_handle->debug())
std::cerr << "PostgreSQL debug: got invalid date '" << date_string << "'" << std::endl;
*value = {};
}
}
else
{
*value = {};
}
}
// always returns local time for timestamp with time zone
inline void bind_result_t::_bind_date_time_result(size_t _index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date_time result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
if (!(*is_null))
{
const auto date_string = _handle->result.getValue(_handle->count, index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: got date_time string: " << date_string << std::endl;
}
if (detail::check_date_digits(date_string))
{
const auto ymd =
::date::year(std::atoi(date_string)) / std::atoi(date_string + 5) / std::atoi(date_string + 8);
*value = ::sqlpp::chrono::day_point(ymd);
}
else
{
if (_handle->debug())
std::cerr << "PostgreSQL debug: got invalid date_time" << std::endl;
*value = {};
return;
}
if (std::strlen(date_string) <= 11)
return;
const auto time_string = date_string + 11; // YYYY-MM-DDT
if (detail::check_time_digits(time_string))
{
*value += std::chrono::hours(std::atoi(time_string)) + std::chrono::minutes(std::atoi(time_string + 3)) +
std::chrono::seconds(std::atoi(time_string + 6));
}
else
{
return;
}
if (std::strlen(time_string) <= 9)
return;
auto us_string = time_string + 9; // hh:mm:ss.
unsigned usec = 0;
for (int i = 0; i < 6; ++i)
{
if (std::isdigit(us_string[0]))
{
usec = 10 * usec + (us_string[0] - '0');
++us_string;
}
else
usec *= 10;
}
*value += ::std::chrono::microseconds(usec);
}
}
inline int bind_result_t::size() const
{
return _handle->result.records_size();
}
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,692 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_CONNECTION_H
#define SQLPP_POSTGRESQL_CONNECTION_H
#include <algorithm>
#include <iostream>
#include <sstream>
#include <sqlpp11/connection.h>
#include <sqlpp11/postgresql/bind_result.h>
#include <sqlpp11/postgresql/connection_config.h>
#include <sqlpp11/postgresql/prepared_statement.h>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/postgresql/result.h>
#include <sqlpp11/postgresql/detail/connection_handle.h>
#include <sqlpp11/postgresql/detail/prepared_statement_handle.h>
#include <sqlpp11/serialize.h>
#include <sqlpp11/transaction.h>
#ifdef SQLPP_DYNAMIC_LOADING
#include <sqlpp11/postgresql/dynamic_libpq.h>
#endif
struct pg_conn;
typedef struct pg_conn PGconn;
namespace sqlpp
{
namespace postgresql
{
#ifdef SQLPP_DYNAMIC_LOADING
using namespace dynamic;
#endif
namespace detail
{
// Forward declaration
inline std::unique_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle& handle,
const std::string& stmt,
const size_t& paramCount)
{
if (handle.config->debug)
{
std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
}
return std::unique_ptr<detail::prepared_statement_handle_t>(new detail::prepared_statement_handle_t
(handle, stmt, paramCount));
}
inline void execute_prepared_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared)
{
if (handle.config->debug)
{
std::cerr << "PostgreSQL debug: executing: " << prepared.name() << std::endl;
}
prepared.execute();
}
}
// Forward declaration
class connection;
// Context
struct context_t
{
context_t(const connection& db) : _db(db)
{
}
context_t(const connection&&) = delete;
template <typename T>
std::ostream& operator<<(T t)
{
return _os << t;
}
std::ostream& operator<<(bool t)
{
return _os << (t ? "TRUE" : "FALSE");
}
std::string escape(const std::string& arg);
std::string str() const
{
return _os.str();
}
size_t count() const
{
return _count;
}
void pop_count()
{
++_count;
}
const connection& _db;
std::ostringstream _os;
size_t _count{1};
};
// Connection
class connection : public sqlpp::connection
{
private:
std::unique_ptr<detail::connection_handle> _handle;
bool _transaction_active{false};
void validate_connection_handle() const
{
if (!_handle)
throw std::logic_error("connection handle used, but not initialized");
}
// direct execution
bind_result_t select_impl(const std::string& stmt);
size_t insert_impl(const std::string& stmt);
size_t update_impl(const std::string& stmt);
size_t remove_impl(const std::string& stmt);
// prepared execution
prepared_statement_t prepare_impl(const std::string& stmt, const size_t& paramCount);
bind_result_t run_prepared_select_impl(prepared_statement_t& prep);
size_t run_prepared_execute_impl(prepared_statement_t& prep);
size_t run_prepared_insert_impl(prepared_statement_t& prep);
size_t run_prepared_update_impl(prepared_statement_t& prep);
size_t run_prepared_remove_impl(prepared_statement_t& prep);
public:
using _prepared_statement_t = prepared_statement_t;
using _context_t = context_t;
using _serializer_context_t = _context_t;
using _interpreter_context_t = _context_t;
struct _tags
{
using _null_result_is_trivial_value = std::true_type;
};
template <typename T>
static _context_t& _serialize_interpretable(const T& t, _context_t& context)
{
return ::sqlpp::serialize(t, context);
}
template <typename T>
static _context_t& _interpret_interpretable(const T& t, _context_t& context)
{
return ::sqlpp::serialize(t, context);
}
// ctor / dtor
connection();
connection(const std::shared_ptr<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<connection_config>& config) noexcept(false);
// Select stmt (returns a result)
template <typename Select>
bind_result_t select(const Select& s)
{
_context_t ctx(*this);
serialize(s, ctx);
return select_impl(ctx.str());
}
// Prepared select
template <typename Select>
_prepared_statement_t prepare_select(Select& s)
{
_context_t ctx(*this);
serialize(s, ctx);
return prepare_impl(ctx.str(), ctx.count() - 1);
}
template <typename PreparedSelect>
bind_result_t run_prepared_select(const PreparedSelect& s)
{
s._bind_params();
return run_prepared_select_impl(s._prepared_statement);
}
// Insert
template <typename Insert>
size_t insert(const Insert& i)
{
_context_t ctx(*this);
serialize(i, ctx);
return insert_impl(ctx.str());
}
template <typename Insert>
prepared_statement_t prepare_insert(Insert& i)
{
_context_t ctx(*this);
serialize(i, ctx);
return prepare_impl(ctx.str(), ctx.count() - 1);
}
template <typename PreparedInsert>
size_t run_prepared_insert(const PreparedInsert& i)
{
i._bind_params();
return run_prepared_insert_impl(i._prepared_statement);
}
// Update
template <typename Update>
size_t update(const Update& u)
{
_context_t ctx(*this);
serialize(u, ctx);
return update_impl(ctx.str());
}
template <typename Update>
prepared_statement_t prepare_update(Update& u)
{
_context_t ctx(*this);
serialize(u, ctx);
return prepare_impl(ctx.str(), ctx.count() - 1);
}
template <typename PreparedUpdate>
size_t run_prepared_update(const PreparedUpdate& u)
{
u._bind_params();
return run_prepared_update_impl(u._prepared_statement);
}
// Remove
template <typename Remove>
size_t remove(const Remove& r)
{
_context_t ctx(*this);
serialize(r, ctx);
return remove_impl(ctx.str());
}
template <typename Remove>
prepared_statement_t prepare_remove(Remove& r)
{
_context_t ctx(*this);
serialize(r, ctx);
return prepare_impl(ctx.str(), ctx.count() - 1);
}
template <typename PreparedRemove>
size_t run_prepared_remove(const PreparedRemove& r)
{
r._bind_params();
return run_prepared_remove_impl(r._prepared_statement);
}
// Execute
std::shared_ptr<detail::statement_handle_t> execute(const std::string& command);
template <
typename Execute,
typename Enable = typename std::enable_if<not std::is_convertible<Execute, std::string>::value, void>::type>
std::shared_ptr<detail::statement_handle_t> execute(const Execute& x)
{
_context_t ctx(*this);
serialize(x, ctx);
return execute(ctx.str());
}
template <typename Execute>
_prepared_statement_t prepare_execute(Execute& x)
{
_context_t ctx(*this);
serialize(x, ctx);
return prepare_impl(ctx.str(), ctx.count() - 1);
}
template <typename PreparedExecute>
size_t run_prepared_execute(const PreparedExecute& x)
{
x._prepared_statement._reset();
x._bind_params();
return run_prepared_execute_impl(x._prepared_statement);
}
// escape argument
std::string escape(const std::string& s) const;
//! call run on the argument
template <typename T>
auto _run(const T& t, sqlpp::consistent_t) -> decltype(t._run(*this))
{
return t._run(*this);
}
template <typename Check, typename T>
auto _run(const T& t, Check) -> Check;
template <typename T>
auto operator()(const T& t) -> decltype(this->_run(t, sqlpp::run_check_t<_serializer_context_t, T>{}))
{
return _run(t, sqlpp::run_check_t<_serializer_context_t, T>{});
}
//! call prepare on the argument
template <typename T>
auto _prepare(const T& t, ::sqlpp::consistent_t) -> decltype(t._prepare(*this))
{
return t._prepare(*this);
}
template <typename Check, typename T>
auto _prepare(const T& t, Check) -> Check;
template <typename T>
auto prepare(const T& t) -> decltype(this->_prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{}))
{
return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{});
}
//! set the default transaction isolation level to use for new transactions
void set_default_isolation_level(isolation_level level);
//! get the currently set default transaction isolation level
isolation_level get_default_isolation_level();
//! create savepoint
void savepoint(const std::string& name);
//! ROLLBACK TO SAVEPOINT
void rollback_to_savepoint(const std::string& name);
//! release_savepoint
void release_savepoint(const std::string& name);
//! start transaction
void start_transaction(isolation_level level = isolation_level::undefined);
//! commit transaction (or throw transaction if transaction has
// finished already)
void commit_transaction();
//! rollback transaction
void rollback_transaction(bool report);
//! report rollback failure
void report_rollback_failure(const std::string& message) noexcept;
//! get the last inserted id for a certain table
uint64_t last_insert_id(const std::string& table, const std::string& fieldname);
::PGconn* native_handle();
};
inline connection::connection() : _handle()
{
}
inline connection::connection(const std::shared_ptr<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<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();
if (_handle->config->debug)
{
std::cerr << "PostgreSQL debug: executing: " << stmt << std::endl;
}
auto result = std::make_shared<detail::statement_handle_t>(*_handle);
result->result = PQexec(_handle->native(), stmt.c_str());
result->valid = true;
return result;
}
// direct execution
inline bind_result_t connection::select_impl(const std::string& stmt)
{
return execute(stmt);
}
inline size_t connection::insert_impl(const std::string& stmt)
{
return execute(stmt)->result.affected_rows();
}
inline size_t connection::update_impl(const std::string& stmt)
{
return execute(stmt)->result.affected_rows();
}
inline size_t connection::remove_impl(const std::string& stmt)
{
return execute(stmt)->result.affected_rows();
}
// prepared execution
inline prepared_statement_t connection::prepare_impl(const std::string& stmt, const size_t& paramCount)
{
validate_connection_handle();
return {prepare_statement(*_handle, stmt, paramCount)};
}
inline bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prep)
{
validate_connection_handle();
execute_prepared_statement(*_handle, *prep._handle.get());
return {prep._handle};
}
inline size_t connection::run_prepared_execute_impl(prepared_statement_t& prep)
{
validate_connection_handle();
execute_prepared_statement(*_handle, *prep._handle.get());
return prep._handle->result.affected_rows();
}
inline size_t connection::run_prepared_insert_impl(prepared_statement_t& prep)
{
validate_connection_handle();
execute_prepared_statement(*_handle, *prep._handle.get());
return prep._handle->result.affected_rows();
}
inline size_t connection::run_prepared_update_impl(prepared_statement_t& prep)
{
validate_connection_handle();
execute_prepared_statement(*_handle, *prep._handle.get());
return prep._handle->result.affected_rows();
}
inline size_t connection::run_prepared_remove_impl(prepared_statement_t& prep)
{
validate_connection_handle();
execute_prepared_statement(*_handle, *prep._handle.get());
return prep._handle->result.affected_rows();
}
inline void connection::set_default_isolation_level(isolation_level level)
{
std::string level_str = "read uncommmitted";
switch (level)
{
/// @todo what about undefined ?
case isolation_level::read_committed:
level_str = "read committed";
break;
case isolation_level::read_uncommitted:
level_str = "read uncommitted";
break;
case isolation_level::repeatable_read:
level_str = "repeatable read";
break;
case isolation_level::serializable:
level_str = "serializable";
break;
default:
throw sqlpp::exception("Invalid isolation level");
}
std::string cmd = "SET default_transaction_isolation to '" + level_str + "'";
execute(cmd);
}
inline isolation_level connection::get_default_isolation_level()
{
auto res = execute("SHOW default_transaction_isolation;");
auto status = res->result.status();
if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK))
{
throw sqlpp::exception("PostgreSQL error: could not read default_transaction_isolation");
}
auto in = res->result.getValue<std::string>(0, 0);
if (in == "read committed")
{
return isolation_level::read_committed;
}
else if (in == "read uncommitted")
{
return isolation_level::read_uncommitted;
}
else if (in == "repeatable read")
{
return isolation_level::repeatable_read;
}
else if (in == "serializable")
{
return isolation_level::serializable;
}
return isolation_level::undefined;
}
// TODO: Fix escaping.
inline std::string connection::escape(const std::string& s) const
{
validate_connection_handle();
// Escape strings
std::string result;
result.resize((s.size() * 2) + 1);
int err;
size_t length = PQescapeStringConn(_handle->postgres, &result[0], s.c_str(), s.size(), &err);
result.resize(length);
return result;
}
//! start transaction
inline void connection::start_transaction(sqlpp::isolation_level level)
{
if (_transaction_active)
{
throw sqlpp::exception("PostgreSQL error: transaction already open");
}
switch (level)
{
case isolation_level::serializable:
{
execute("BEGIN ISOLATION LEVEL SERIALIZABLE");
break;
}
case isolation_level::repeatable_read:
{
execute("BEGIN ISOLATION LEVEL REPEATABLE READ");
break;
}
case isolation_level::read_committed:
{
execute("BEGIN ISOLATION LEVEL READ COMMITTED");
break;
}
case isolation_level::read_uncommitted:
{
execute("BEGIN ISOLATION LEVEL READ UNCOMMITTED");
break;
}
case isolation_level::undefined:
{
execute("BEGIN");
break;
}
}
_transaction_active = true;
}
//! create savepoint
inline void connection::savepoint(const std::string& name)
{
/// NOTE prevent from sql injection?
execute("SAVEPOINT " + name);
}
//! ROLLBACK TO SAVEPOINT
inline void connection::rollback_to_savepoint(const std::string& name)
{
/// NOTE prevent from sql injection?
execute("ROLLBACK TO SAVEPOINT " + name);
}
//! release_savepoint
inline void connection::release_savepoint(const std::string& name)
{
/// NOTE prevent from sql injection?
execute("RELEASE SAVEPOINT " + name);
}
//! commit transaction (or throw transaction if transaction has finished already)
inline void connection::commit_transaction()
{
if (!_transaction_active)
{
throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
}
_transaction_active = false;
execute("COMMIT");
}
//! rollback transaction
inline void connection::rollback_transaction(bool report)
{
if (!_transaction_active)
{
throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
}
execute("ROLLBACK");
if (report)
{
std::cerr << "PostgreSQL warning: rolling back unfinished transaction" << std::endl;
}
_transaction_active = false;
}
//! report rollback failure
inline void connection::report_rollback_failure(const std::string& message) noexcept
{
std::cerr << "PostgreSQL error: " << message << std::endl;
}
inline uint64_t connection::last_insert_id(const std::string& table, const std::string& fieldname)
{
std::string sql = "SELECT currval('" + table + "_" + fieldname + "_seq')";
PGresult* res = PQexec(_handle->postgres, sql.c_str());
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
std::string err{PQresultErrorMessage(res)};
PQclear(res);
throw sqlpp::postgresql::undefined_table(err, sql);
}
// Parse the number and return.
std::string in{PQgetvalue(res, 0, 0)};
PQclear(res);
return std::stoi(in);
}
inline ::PGconn* connection::native_handle()
{
return _handle->postgres;
}
inline std::string context_t::escape(const std::string& arg)
{
return _db.escape(arg);
}
}
}
#include <sqlpp11/postgresql/serializer.h>
#endif

View File

@ -0,0 +1,100 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_CONNECTION_CONFIG_H
#define SQLPP_POSTGRESQL_CONNECTION_CONFIG_H
#include <sqlpp11/postgresql/visibility.h>
#include <string>
namespace sqlpp
{
namespace postgresql
{
class connection;
struct DLL_PUBLIC connection_config
{
// Needed for the connection pool
typedef ::sqlpp::postgresql::connection connection;
enum class sslmode_t
{
disable,
allow,
prefer,
require,
verify_ca,
verify_full
};
std::string host;
std::string hostaddr;
uint32_t port{5432};
std::string dbname;
std::string user;
std::string password;
uint32_t connect_timeout{0};
std::string client_encoding;
std::string options;
std::string application_name;
std::string fallback_application_name;
bool keepalives{true};
uint32_t keepalives_idle{0};
uint32_t keepalives_interval{0};
uint32_t keepalives_count{0};
sslmode_t sslmode{sslmode_t::prefer};
bool sslcompression{true};
std::string sslcert;
std::string sslkey;
std::string sslrootcert;
std::string sslcrl;
std::string requirepeer;
std::string krbsrvname;
std::string service;
// bool auto_reconnect {true};
bool debug{false};
bool operator==(const connection_config& other)
{
return (other.host == host && other.hostaddr == hostaddr && other.port == port && other.dbname == dbname &&
other.user == user && other.password == password && other.connect_timeout == connect_timeout &&
other.client_encoding == client_encoding && other.options == options &&
other.application_name == application_name && other.keepalives == keepalives &&
other.keepalives_idle == keepalives_idle && other.keepalives_interval == keepalives_interval &&
other.keepalives_count == keepalives_count && other.sslmode == sslmode &&
other.sslcompression == sslcompression && other.sslcert == sslcert && other.sslkey == sslkey &&
other.sslrootcert == sslrootcert && other.sslcrl == sslcrl && other.requirepeer == requirepeer &&
other.krbsrvname == krbsrvname && other.service == service && other.debug == debug);
}
bool operator!=(const connection_config& other)
{
return !operator==(other);
}
};
}
}
#endif

View File

@ -0,0 +1,239 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_CONNECTION_HANDLE_H
#define SQLPP_POSTGRESQL_CONNECTION_HANDLE_H
#include <memory>
#include <set>
#include <string>
#include <libpq-fe.h>
#include <sqlpp11/postgresql/connection_config.h>
#include <sqlpp11/postgresql/visibility.h>
#ifdef SQLPP_DYNAMIC_LOADING
#include <sqlpp11/postgresql/dynamic_libpq.h>
#endif
namespace sqlpp
{
namespace postgresql
{
// Forward declaration
struct connection_config;
#ifdef SQLPP_DYNAMIC_LOADING
using namespace dynamic;
#endif
namespace detail
{
struct DLL_LOCAL connection_handle
{
const std::shared_ptr<connection_config> config;
PGconn* postgres{nullptr};
std::set<std::string> prepared_statement_names;
connection_handle(const std::shared_ptr<connection_config>& config);
~connection_handle();
connection_handle(const connection_handle&) = delete;
connection_handle(connection_handle&&) = delete;
connection_handle& operator=(const connection_handle&) = delete;
connection_handle& operator=(connection_handle&&) = delete;
PGconn* native() const
{
return postgres;
}
void deallocate_prepared_statement(const std::string& name);
};
inline connection_handle::connection_handle(const std::shared_ptr<connection_config>& conf) : config(conf)
{
#ifdef SQLPP_DYNAMIC_LOADING
init_pg("");
#endif
if (config->debug)
{
std::cerr << "PostgreSQL debug: connecting to the database server." << std::endl;
}
// Open connection
std::string conninfo = "";
if (!config->host.empty())
{
conninfo.append("host=" + config->host);
}
if (!config->hostaddr.empty())
{
conninfo.append(" hostaddr=" + config->hostaddr);
}
if (config->port != 5432)
{
conninfo.append(" port=" + std::to_string(config->port));
}
if (!config->dbname.empty())
{
conninfo.append(" dbname=" + config->dbname);
}
if (!config->user.empty())
{
conninfo.append(" user=" + config->user);
}
if (!config->password.empty())
{
conninfo.append(" password=" + config->password);
}
if (config->connect_timeout != 0)
{
conninfo.append(" connect_timeout=" + std::to_string(config->connect_timeout));
}
if (!config->client_encoding.empty())
{
conninfo.append(" client_encoding=" + config->client_encoding);
}
if (!config->options.empty())
{
conninfo.append(" options=" + config->options);
}
if (!config->application_name.empty())
{
conninfo.append(" application_name=" + config->application_name);
}
if (!config->fallback_application_name.empty())
{
conninfo.append(" fallback_application_name=" + config->fallback_application_name);
}
if (!config->keepalives)
{
conninfo.append(" keepalives=0");
}
if (config->keepalives_idle != 0)
{
conninfo.append(" keepalives_idle=" + std::to_string(config->keepalives_idle));
}
if (config->keepalives_interval != 0)
{
conninfo.append(" keepalives_interval=" + std::to_string(config->keepalives_interval));
}
if (config->keepalives_count != 0)
{
conninfo.append(" keepalives_count=" + std::to_string(config->keepalives_count));
}
switch (config->sslmode)
{
case connection_config::sslmode_t::disable:
conninfo.append(" sslmode=disable");
break;
case connection_config::sslmode_t::allow:
conninfo.append(" sslmode=allow");
break;
case connection_config::sslmode_t::require:
conninfo.append(" sslmode=require");
break;
case connection_config::sslmode_t::verify_ca:
conninfo.append(" sslmode=verify-ca");
break;
case connection_config::sslmode_t::verify_full:
conninfo.append(" sslmode=verify-full");
break;
case connection_config::sslmode_t::prefer:
break;
}
if (!config->sslcompression)
{
conninfo.append(" sslcompression=0");
}
if (!config->sslcert.empty())
{
conninfo.append(" sslcert=" + config->sslcert);
}
if (!config->sslkey.empty())
{
conninfo.append(" sslkey=" + config->sslkey);
}
if (!config->sslrootcert.empty())
{
conninfo.append(" sslrootcert=" + config->sslrootcert);
}
if (!config->requirepeer.empty())
{
conninfo.append(" requirepeer=" + config->requirepeer);
}
if (!config->krbsrvname.empty())
{
conninfo.append(" krbsrvname=" + config->krbsrvname);
}
if (!config->service.empty())
{
conninfo.append(" service=" + config->service);
}
if (this->postgres)
return;
this->postgres = PQconnectdb(conninfo.c_str());
if (!this->postgres)
throw std::bad_alloc();
if (PQstatus(this->postgres) != CONNECTION_OK)
{
std::string msg(PQerrorMessage(this->postgres));
PQfinish(this->postgres);
throw broken_connection(std::move(msg));
}
}
inline connection_handle::~connection_handle()
{
// Debug
if (config->debug)
{
std::cerr << "PostgreSQL debug: closing database connection." << std::endl;
}
// Close connection
if (this->postgres)
{
PQfinish(this->postgres);
}
}
inline void connection_handle::deallocate_prepared_statement(const std::string& name)
{
std::string cmd = "DEALLOCATE \"" + name + "\"";
PGresult* result = PQexec(postgres, cmd.c_str());
PQclear(result);
prepared_statement_names.erase(name);
}
}
}
}
#endif

View File

@ -0,0 +1,198 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* Copyright © 2015-2016, Bartosz Wieczorek
* 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_POSTGRESQL_PREPARED_STATEMENT_HANDLE_H
#define SQLPP_POSTGRESQL_PREPARED_STATEMENT_HANDLE_H
#include <iostream>
#include <random>
#include <string>
#include <vector>
#include <libpq-fe.h>
#include <sqlpp11/postgresql/result.h>
#include <sqlpp11/postgresql/visibility.h>
#include "connection_handle.h"
#ifdef SQLPP_DYNAMIC_LOADING
#include <sqlpp11/postgresql/dynamic_libpq.h>
#endif
namespace sqlpp
{
namespace postgresql
{
#ifdef SQLPP_DYNAMIC_LOADING
using namespace dynamic;
#endif
namespace detail
{
struct DLL_PUBLIC statement_handle_t
{
detail::connection_handle& connection;
Result result;
bool valid{false};
uint32_t count{0};
uint32_t totalCount = {0};
uint32_t fields = {0};
// ctor
statement_handle_t(detail::connection_handle& _connection);
statement_handle_t(const statement_handle_t&) = delete;
statement_handle_t(statement_handle_t&&) = default;
statement_handle_t& operator=(const statement_handle_t&) = delete;
statement_handle_t& operator=(statement_handle_t&&) = default;
virtual ~statement_handle_t();
bool operator!() const;
void clearResult();
bool debug() const;
};
struct prepared_statement_handle_t : public statement_handle_t
{
private:
std::string _name{"xxxxxx"};
public:
// Store prepared statement arguments
std::vector<bool> nullValues;
std::vector<std::string> paramValues;
// ctor
prepared_statement_handle_t(detail::connection_handle& _connection, std::string stmt, const size_t& paramCount);
prepared_statement_handle_t(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t(prepared_statement_handle_t&&) = default;
prepared_statement_handle_t& operator=(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t& operator=(prepared_statement_handle_t&&) = default;
virtual ~prepared_statement_handle_t();
void execute();
std::string name() const
{
return _name;
}
private:
void generate_name();
void prepare(std::string stmt);
};
inline statement_handle_t::statement_handle_t(connection_handle& _connection) : connection(_connection)
{
}
inline statement_handle_t::~statement_handle_t()
{
clearResult();
}
inline bool statement_handle_t::operator!() const
{
return !valid;
}
inline void statement_handle_t::clearResult()
{
if (result)
{
result.clear();
}
}
inline bool statement_handle_t::debug() const
{
return connection.config->debug;
}
inline prepared_statement_handle_t::prepared_statement_handle_t(connection_handle& _connection,
std::string stmt,
const size_t& paramCount)
: statement_handle_t(_connection), nullValues(paramCount), paramValues(paramCount)
{
generate_name();
prepare(std::move(stmt));
}
inline prepared_statement_handle_t::~prepared_statement_handle_t()
{
if (valid && !_name.empty())
{
connection.deallocate_prepared_statement(_name);
}
}
inline void prepared_statement_handle_t::execute()
{
int size = static_cast<int>(paramValues.size());
std::vector<const char*> values;
for (int i = 0; i < size; i++)
values.push_back(nullValues[i] ? nullptr : const_cast<char*>(paramValues[i].c_str()));
// Execute prepared statement with the parameters.
clearResult();
valid = false;
count = 0;
totalCount = 0;
result = PQexecPrepared(connection.postgres, _name.data(), size, values.data(), nullptr, nullptr, 0);
/// @todo validate result? is it really valid
valid = true;
}
inline void prepared_statement_handle_t::generate_name()
{
// Generate a random name for the prepared statement
while (connection.prepared_statement_names.find(_name) != connection.prepared_statement_names.end())
{
std::generate_n(_name.begin(), 6, []() {
constexpr static auto charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
constexpr size_t max = (sizeof(charset) - 1);
std::random_device rd;
return charset[rd() % max];
});
}
connection.prepared_statement_names.insert(_name);
}
inline void prepared_statement_handle_t::prepare(std::string stmt)
{
// Create the prepared statement
result = PQprepare(connection.postgres, _name.c_str(), stmt.c_str(), 0, nullptr);
valid = true;
}
}
}
}
#endif

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2015, Volker Assmann
* 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 DYNAMIC_LIBPQ_H
#define DYNAMIC_LIBPQ_H
#include <stdexcept>
#include <libpq-fe.h>
#ifdef SQLPP_DYNAMIC_LOADING
// Copied from PostgreSQL Internal include (internal/libpq-int.h) to enable linking
#define CMDSTATUS_LEN 64
struct PGresAttValue;
struct PGresParamDesc;
struct PGEvent;
struct PGMessageField;
struct PGresult_data;
typedef struct
{
PQnoticeReceiver noticeRec; /* notice message receiver */
void *noticeRecArg;
PQnoticeProcessor noticeProc; /* notice message processor */
void *noticeProcArg;
} PGNoticeHooks;
struct pg_result
{
int ntups;
int numAttributes;
PGresAttDesc *attDescs;
PGresAttValue **tuples; /* each PGresTuple is an array of
* PGresAttValue's */
int tupArrSize; /* allocated size of tuples array */
int numParameters;
PGresParamDesc *paramDescs;
ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the query */
int binary; /* binary tuple values if binary == 1,
* otherwise text */
/*
* These fields are copied from the originating PGconn, so that operations
* on the PGresult don't have to reference the PGconn.
*/
PGNoticeHooks noticeHooks;
PGEvent *events;
int nEvents;
int client_encoding; /* encoding id */
/*
* Error information (all NULL if not an error result). errMsg is the
* "overall" error message returned by PQresultErrorMessage. If we have
* per-field info then it is stored in a linked list.
*/
char *errMsg; /* error message, or NULL if no error */
PGMessageField *errFields; /* message broken into fields */
/* All NULL attributes in the query result point to this null string */
char null_field[1];
/*
* Space management information. Note that attDescs and error stuff, if
* not null, point into allocated blocks. But tuples points to a
* separately malloc'd block, so that we can realloc it.
*/
PGresult_data *curBlock; /* most recently allocated block */
int curOffset; /* start offset of free space in block */
int spaceLeft; /* number of free bytes remaining in block */
};
#endif
// namespace for internal PQ function wrappers - when using this instead of libpq direct linking
// do this:
// using namespace sqlpp::postgresql::dyn_pg;
// to override the libpq functions with these function pointers
namespace sqlpp
{
namespace postgresql
{
namespace dynamic
{
#define DYNDEFINE(NAME) extern decltype( ::NAME ) * NAME
DYNDEFINE(PQescapeStringConn);
DYNDEFINE(PQescapeString);
DYNDEFINE(PQescapeByteaConn);
DYNDEFINE(PQescapeBytea);
DYNDEFINE(PQfreemem);
DYNDEFINE(PQexec);
DYNDEFINE(PQprepare);
DYNDEFINE(PQexecPrepared);
DYNDEFINE(PQexecParams);
DYNDEFINE(PQresultStatus);
DYNDEFINE(PQresStatus);
DYNDEFINE(PQresultErrorMessage);
DYNDEFINE(PQresultErrorField);
DYNDEFINE(PQcmdTuples);
DYNDEFINE(PQcmdStatus);
DYNDEFINE(PQgetvalue);
DYNDEFINE(PQgetlength);
DYNDEFINE(PQgetisnull);
DYNDEFINE(PQoidValue);
DYNDEFINE(PQoidStatus);
DYNDEFINE(PQfformat);
DYNDEFINE(PQntuples);
DYNDEFINE(PQnfields);
DYNDEFINE(PQnparams);
DYNDEFINE(PQclear);
DYNDEFINE(PQfinish);
DYNDEFINE(PQstatus);
DYNDEFINE(PQconnectdb);
DYNDEFINE(PQerrorMessage);
#undef DYNDEFINE
/// load the PostgreSQL libraries, optionally providing the filename (leave empty for default)
void init_pg(std::string libname);
}
}
}
#endif // DYNAMIC_LIBPQ_H

View File

@ -0,0 +1,417 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_EXCEPTION_H
#define SQLPP_POSTGRESQL_EXCEPTION_H
/**
classes copied from http://pqxx.org/devprojects/libpqxx/doc/3.1/html/Reference/a00032.html
*/
#include "visibility.h"
#include <sqlpp11/exception.h>
#include <string>
namespace sqlpp
{
namespace postgresql
{
/**
* @addtogroup exception Exception classes
*
* These exception classes follow, roughly, the two-level hierarchy defined by
* the PostgreSQL error codes (see Appendix A of the PostgreSQL documentation
* corresponding to your server version). The hierarchy given here is, as yet,
* not a complete mirror of the error codes. There are some other differences
* as well, e.g. the error code statement_completion_unknown has a separate
* status in libpqxx as in_doubt_error, and too_many_connections is classified
* as a broken_connection rather than a subtype of insufficient_resources.
*
* @see http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
*
* @{
*/
/// Run-time failure encountered by sqlpp::postgresql connector, similar to std::runtime_error
class DLL_PUBLIC failure : public ::sqlpp::exception
{
virtual const std::exception& base() const noexcept
{
return *this;
}
public:
explicit failure(std::string whatarg) : sqlpp::exception(std::move(whatarg))
{
}
};
/// Exception class for lost or failed backend connection.
/**
* @warning When this happens on Unix-like systems, you may also get a SIGPIPE
* signal. That signal aborts the program by default, so if you wish to be able
* to continue after a connection breaks, be sure to disarm this signal.
*
* If you're working on a Unix-like system, see the manual page for
* @c signal (2) on how to deal with SIGPIPE. The easiest way to make this
* signal harmless is to make your program ignore it:
*
* @code
* #include <signal.h>
*
* int main()
* {
* signal(SIGPIPE, SIG_IGN);
* // ...
* @endcode
*/
class DLL_PUBLIC broken_connection : public failure
{
public:
broken_connection() : failure("Connection to database failed")
{
}
explicit broken_connection(std::string whatarg) : failure(std::move(whatarg))
{
}
};
/// Exception class for failed queries.
/** Carries a copy of the failed query in addition to a regular error message */
class DLL_PUBLIC sql_error : public failure
{
std::string m_Q;
public:
sql_error() : failure("Failed query"), m_Q()
{
}
explicit sql_error(std::string whatarg) : failure(std::move(whatarg)), m_Q()
{
}
sql_error(std::string whatarg, std::string Q) : failure(std::move(whatarg)), m_Q(std::move(Q))
{
}
/// The query whose execution triggered the exception
const std::string& query() const noexcept
{
return m_Q;
}
};
// TODO: should this be called statement_completion_unknown!?
/// "Help, I don't know whether transaction was committed successfully!"
/** Exception that might be thrown in rare cases where the connection to the
* database is lost while finishing a database transaction, and there's no way
* of telling whether it was actually executed by the backend. In this case
* the database is left in an indeterminate (but consistent) state, and only
* manual inspection will tell which is the case.
*/
class DLL_PUBLIC in_doubt_error : public failure
{
public:
explicit in_doubt_error(std::string whatarg) : failure(std::move(whatarg))
{
}
};
/// Database feature not supported in current setup
class DLL_PUBLIC feature_not_supported : public sql_error
{
public:
explicit feature_not_supported(std::string err) : sql_error(std::move(err))
{
}
feature_not_supported(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
/// Error in data provided to SQL statement
class DLL_PUBLIC data_exception : public sql_error
{
public:
explicit data_exception(std::string err) : sql_error(std::move(err))
{
}
data_exception(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC integrity_constraint_violation : public sql_error
{
public:
explicit integrity_constraint_violation(std::string err) : sql_error(std::move(err))
{
}
integrity_constraint_violation(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC restrict_violation : public integrity_constraint_violation
{
public:
explicit restrict_violation(std::string err) : integrity_constraint_violation(std::move(err))
{
}
restrict_violation(std::string err, std::string Q) : integrity_constraint_violation(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC not_null_violation : public integrity_constraint_violation
{
public:
explicit not_null_violation(std::string err) : integrity_constraint_violation(std::move(err))
{
}
not_null_violation(std::string err, std::string Q) : integrity_constraint_violation(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC foreign_key_violation : public integrity_constraint_violation
{
public:
explicit foreign_key_violation(std::string err) : integrity_constraint_violation(std::move(err))
{
}
foreign_key_violation(std::string err, std::string Q)
: integrity_constraint_violation(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC unique_violation : public integrity_constraint_violation
{
public:
explicit unique_violation(std::string err) : integrity_constraint_violation(std::move(err))
{
}
unique_violation(std::string err, std::string Q) : integrity_constraint_violation(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC check_violation : public integrity_constraint_violation
{
public:
explicit check_violation(std::string err) : integrity_constraint_violation(std::move(err))
{
}
check_violation(std::string err, std::string Q) : integrity_constraint_violation(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC invalid_cursor_state : public sql_error
{
public:
explicit invalid_cursor_state(std::string err) : sql_error(std::move(err))
{
}
invalid_cursor_state(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC invalid_sql_statement_name : public sql_error
{
public:
explicit invalid_sql_statement_name(std::string err) : sql_error(std::move(err))
{
}
invalid_sql_statement_name(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC invalid_cursor_name : public sql_error
{
public:
explicit invalid_cursor_name(std::string err) : sql_error(std::move(err))
{
}
invalid_cursor_name(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC syntax_error : public sql_error
{
public:
/// Approximate position in string where error occurred, or -1 if unknown.
const int error_position;
explicit syntax_error(std::string err, int pos = -1) : sql_error(std::move(err)), error_position(pos)
{
}
syntax_error(std::string err, std::string Q, int pos = -1) : sql_error(std::move(err), std::move(Q)), error_position(pos)
{
}
};
class DLL_PUBLIC undefined_column : public syntax_error
{
public:
explicit undefined_column(std::string err) : syntax_error(std::move(err))
{
}
undefined_column(std::string err, std::string Q) : syntax_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC undefined_function : public syntax_error
{
public:
explicit undefined_function(std::string err) : syntax_error(std::move(err))
{
}
undefined_function(std::string err, std::string Q) : syntax_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC undefined_table : public syntax_error
{
public:
explicit undefined_table(std::string err) : syntax_error(std::move(err))
{
}
undefined_table(std::string err, std::string Q) : syntax_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC insufficient_privilege : public sql_error
{
public:
explicit insufficient_privilege(std::string err) : sql_error(std::move(err))
{
}
insufficient_privilege(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
/// Resource shortage on the server
class DLL_PUBLIC insufficient_resources : public sql_error
{
public:
explicit insufficient_resources(std::string err) : sql_error(std::move(err))
{
}
insufficient_resources(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC disk_full : public insufficient_resources
{
public:
explicit disk_full(std::string err) : insufficient_resources(std::move(err))
{
}
disk_full(std::string err, std::string Q) : insufficient_resources(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC out_of_memory : public insufficient_resources
{
public:
explicit out_of_memory(std::string err) : insufficient_resources(std::move(err))
{
}
out_of_memory(std::string err, std::string Q) : insufficient_resources(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC too_many_connections : public broken_connection
{
public:
explicit too_many_connections(std::string err) : broken_connection(std::move(err))
{
}
};
/// PL/pgSQL error
/** Exceptions derived from this class are errors from PL/pgSQL procedures.*/
class DLL_PUBLIC plpgsql_error : public sql_error
{
public:
explicit plpgsql_error(std::string err) : sql_error(std::move(err))
{
}
plpgsql_error(std::string err, std::string Q) : sql_error(std::move(err), std::move(Q))
{
}
};
/// Exception raised in PL/pgSQL procedure
class DLL_PUBLIC plpgsql_raise : public plpgsql_error
{
public:
explicit plpgsql_raise(std::string err) : plpgsql_error(std::move(err))
{
}
plpgsql_raise(std::string err, std::string Q) : plpgsql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC plpgsql_no_data_found : public plpgsql_error
{
public:
explicit plpgsql_no_data_found(const std::string& err) : plpgsql_error(std::move(err))
{
}
plpgsql_no_data_found(const std::string& err, const std::string& Q) : plpgsql_error(std::move(err), std::move(Q))
{
}
};
class DLL_PUBLIC plpgsql_too_many_rows : public plpgsql_error
{
public:
explicit plpgsql_too_many_rows(std::string err) : plpgsql_error(std::move(err))
{
}
plpgsql_too_many_rows(std::string err, std::string Q) : plpgsql_error(std::move(err), std::move(Q))
{
}
};
}
}
#endif

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2013-2016, Roland Bock
* 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_POSTGRESQL_INSERT_H
#define SQLPP_POSTGRESQL_INSERT_H
#include <sqlpp11/insert.h>
#include <sqlpp11/postgresql/on_conflict.h>
#include <sqlpp11/postgresql/returning.h>
namespace sqlpp
{
namespace postgresql
{
template <typename Database>
using blank_insert_t =
statement_t<Database, insert_t, no_into_t, no_insert_value_list_t, no_on_conflict_t, no_returning_t>;
inline auto insert() -> blank_insert_t<void>
{
return {blank_insert_t<void>()};
}
template <typename Table>
constexpr auto insert_into(Table table) -> decltype(blank_insert_t<void>().into(table))
{
return {blank_insert_t<void>().into(table)};
}
template <typename Database>
constexpr auto dynamic_insert(const Database&) -> decltype(blank_insert_t<Database>())
{
static_assert(std::is_base_of<connection, Database>::value, "Invalid database parameter");
return {blank_insert_t<Database>()};
}
template <typename Database, typename Table>
constexpr auto dynamic_insert_into(const Database&, Table table) -> decltype(blank_insert_t<Database>().into(table))
{
static_assert(std::is_base_of<connection, Database>::value, "Invalid database parameter");
return {blank_insert_t<Database>().into(table)};
}
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,264 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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_POSTGRESQL_NO_CONFLICT_H
#define SQLPP_POSTGRESQL_NO_CONFLICT_H
#include <sqlpp11/postgresql/on_conflict_do_nothing.h>
#include <sqlpp11/postgresql/on_conflict_do_update.h>
#include <sqlpp11/statement.h>
namespace sqlpp
{
SQLPP_VALUE_TRAIT_GENERATOR(is_on_conflict);
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_action_t,
"either do_nothing() or do_update(...) is required with on_conflict");
namespace postgresql
{
template <typename ConflictTarget>
struct on_conflict_data_t
{
on_conflict_data_t(ConflictTarget column) : _column(column)
{
}
on_conflict_data_t(const on_conflict_data_t&) = default;
on_conflict_data_t(on_conflict_data_t&&) = default;
on_conflict_data_t& operator=(const on_conflict_data_t&) = default;
on_conflict_data_t& operator=(on_conflict_data_t&&) = default;
~on_conflict_data_t() = default;
ConflictTarget _column;
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_do_update_set_assignments_t,
"at least one argument is not an assignment in do_update()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_do_update_set_no_duplicates_t,
"at least one duplicate column detected in do_update()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_do_update_set_allowed_t,
"at least one assignment is prohibited by its column definition in do_update()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_do_update_set_single_table_t,
"do_update() contains assignments for columns from more than one table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_conflict_do_update_set_count_args_t,
"at least one assignment expression required in do_update()");
namespace detail
{
template <typename Assignment>
struct lhs_must_not_update
{
static constexpr auto value = sqlpp::detail::must_not_update_impl<typename lhs<Assignment>::type>::type::value;
};
} // namespace detail
template <typename... Assignments>
using check_on_conflict_do_update_set_t = static_combined_check_t<
static_check_t<logic::all_t<sqlpp::detail::is_assignment_impl<Assignments>::type::value...>::value,
assert_on_conflict_do_update_set_assignments_t>,
static_check_t<not sqlpp::detail::has_duplicates<typename lhs<Assignments>::type...>::value,
assert_on_conflict_do_update_set_no_duplicates_t>,
static_check_t<logic::none_t<detail::lhs_must_not_update<Assignments>::value...>::value,
assert_on_conflict_do_update_set_allowed_t>,
static_check_t<sizeof...(Assignments) == 0 or sqlpp::detail::make_joined_set_t<required_tables_of<
typename lhs<Assignments>::type>...>::size::value == 1,
assert_on_conflict_do_update_set_single_table_t>>;
template <typename... Assignments>
struct check_on_conflict_do_update_static_set
{
using type = static_combined_check_t<
check_on_conflict_do_update_set_t<Assignments...>,
static_check_t<sizeof...(Assignments) != 0, assert_on_conflict_do_update_set_count_args_t>>;
};
template <typename... Assignments>
using check_on_conflict_do_update_static_set_t =
typename check_on_conflict_do_update_static_set<Assignments...>::type;
template <typename ConflictTarget>
struct on_conflict_t
{
using _traits = make_traits<no_value_t, tag::is_noop>;
using _nodes = sqlpp::detail::type_vector<ConflictTarget>;
using _data_t = on_conflict_data_t<ConflictTarget>;
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;
};
template <typename Policies>
struct _base_t
{
using _data_t = on_conflict_data_t<ConflictTarget>;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069
template <typename... Args>
_base_t(Args&&... args) : on_conflict{std::forward<Args>(args)...}
{
}
_impl_t<Policies> on_conflict;
_impl_t<Policies>& operator()()
{
return on_conflict;
}
const _impl_t<Policies>& operator()() const
{
return on_conflict;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.on_conflict)
{
return t.on_conflict;
}
template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check, Policies, on_conflict_t, T>;
using _consistency_check = assert_on_conflict_action_t;
// DO NOTHING
auto do_nothing() const -> _new_statement_t<consistent_t, on_conflict_do_nothing_t<ConflictTarget>>
{
return {static_cast<const derived_statement_t<Policies>&>(*this),
on_conflict_do_nothing_data_t<ConflictTarget>{on_conflict._data}};
}
// DO UPDATE
template <typename... Assignments>
auto do_update(Assignments... assignments) const
-> _new_statement_t<check_on_conflict_do_update_static_set_t<Assignments...>,
on_conflict_do_update_t<void, ConflictTarget, Assignments...>>
{
static_assert(is_column_t<ConflictTarget>::value,
"conflict_target specification is required with do_update(...)");
return {static_cast<const derived_statement_t<Policies>&>(*this),
on_conflict_do_update_data_t<void, ConflictTarget, Assignments...>(on_conflict._data,
std::make_tuple(assignments...))};
}
};
};
struct no_on_conflict_t
{
using _traits = make_traits<no_value_t, tag::is_on_conflict>;
using _nodes = ::sqlpp::detail::type_vector<>;
using _data_t = no_data_t;
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_impl_t() = default;
_impl_t(const _data_t& data) : _data(data)
{
}
_data_t _data;
};
template <typename Policies>
struct _base_t
{
using _data_t = no_data_t;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : no_on_conflict{std::forward<Args>(args)...}
{
}
_impl_t<Policies> no_on_conflict;
_impl_t<Policies>& operator()()
{
return no_on_conflict;
}
const _impl_t<Policies>& operator()() const
{
return no_on_conflict;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.no_on_conflict)
{
return t.no_on_conflict;
}
using _database_t = typename Policies::_database_t;
template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check, Policies, no_on_conflict_t, T>;
using _consistency_check = consistent_t;
auto on_conflict() const -> _new_statement_t<consistent_t, on_conflict_t<no_data_t>>
{
return {static_cast<const derived_statement_t<Policies>&>(*this), on_conflict_data_t<no_data_t>{no_data_t{}}};
}
template <typename ConflictTarget>
auto on_conflict(ConflictTarget column) const -> _new_statement_t<consistent_t, on_conflict_t<ConflictTarget>>
{
static_assert(is_column_t<ConflictTarget>::value,
"only a column is supported as conflict_target specification");
return {static_cast<const derived_statement_t<Policies>&>(*this), on_conflict_data_t<ConflictTarget>{column}};
}
};
};
template <typename ConflictTarget>
postgresql::context_t& serialize(const postgresql::on_conflict_data_t<ConflictTarget>&,
postgresql::context_t& context)
{
context << " ON CONFLICT (";
context << name_of<ConflictTarget>::template char_ptr<postgresql::context_t>();
context << ") ";
return context;
}
inline postgresql::context_t& serialize(const postgresql::on_conflict_data_t<no_data_t>&, postgresql::context_t& context)
{
context << " ON CONFLICT ";
return context;
}
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,127 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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_POSTGRESQL_ON_CONFLICT_DO_NOTHING_H
#define SQLPP_POSTGRESQL_ON_CONFLICT_DO_NOTHING_H
#include <sqlpp11/detail/type_vector.h>
#include <sqlpp11/serialize.h>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
SQLPP_VALUE_TRAIT_GENERATOR(is_on_conflict_do_nothing)
namespace postgresql
{
// Forward declaration
template <typename ConflictTarget>
struct on_conflict_data_t;
template <typename ConflictTarget>
struct on_conflict_do_nothing_data_t
{
on_conflict_do_nothing_data_t(on_conflict_data_t<ConflictTarget> column) : _column(column)
{
}
on_conflict_do_nothing_data_t(const on_conflict_do_nothing_data_t&) = default;
on_conflict_do_nothing_data_t(on_conflict_do_nothing_data_t&&) = default;
on_conflict_do_nothing_data_t& operator=(const on_conflict_do_nothing_data_t&) = default;
on_conflict_do_nothing_data_t& operator=(on_conflict_do_nothing_data_t&&) = default;
~on_conflict_do_nothing_data_t() = default;
on_conflict_data_t<ConflictTarget> _column;
};
template <typename ConflictTarget>
struct on_conflict_do_nothing_t
{
using _traits = make_traits<no_value_t, tag::is_on_conflict_do_nothing>;
using _nodes = sqlpp::detail::type_vector<ConflictTarget>;
// Data
using _data_t = on_conflict_do_nothing_data_t<ConflictTarget>;
// Member implementation and methods
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_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 = on_conflict_do_nothing_data_t<ConflictTarget>;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : column{std::forward<Args>(args)...}
{
}
_impl_t<Policies> column;
_impl_t<Policies>& operator()()
{
return column;
}
const _impl_t<Policies>& operator()() const
{
return column;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.column)
{
return t.column;
}
// No consistency check needed, do nothing is just do nothing.
using _consistency_check = consistent_t;
};
};
template <typename ConflictTarget>
postgresql::context_t& serialize(const postgresql::on_conflict_do_nothing_data_t<ConflictTarget>& o,
postgresql::context_t& context)
{
serialize(o._column, context);
context << "DO NOTHING";
return context;
}
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,232 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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_POSTGRESQL_ON_CONFLICT_DO_UPDATE_H
#define SQLPP_POSTGRESQL_ON_CONFLICT_DO_UPDATE_H
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/interpretable_list.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/where.h>
namespace sqlpp
{
SQLPP_VALUE_TRAIT_GENERATOR(is_on_conflict_do_update)
namespace postgresql
{
// Assignments data
template <typename Database, typename ConflictTarget, typename... Assignments>
struct on_conflict_do_update_data_t
{
on_conflict_do_update_data_t(on_conflict_data_t<ConflictTarget> conflict_target,
std::tuple<Assignments...> assignments)
: _conflict_target(conflict_target), _assignments(assignments)
{
}
on_conflict_do_update_data_t(const on_conflict_do_update_data_t&) = default;
on_conflict_do_update_data_t(on_conflict_do_update_data_t&&) = default;
on_conflict_do_update_data_t& operator=(const on_conflict_do_update_data_t&) = default;
on_conflict_do_update_data_t& operator=(on_conflict_do_update_data_t&&) = default;
~on_conflict_do_update_data_t() = default;
on_conflict_data_t<ConflictTarget> _conflict_target;
std::tuple<Assignments...> _assignments;
// interpretable_list_t<Database> _dynamic_assignments;
};
// Where data
template <typename Database, typename ConflictTarget, typename Expression, typename... Assignments>
struct on_conflict_do_update_where_data_t
{
on_conflict_do_update_where_data_t(
Expression expression, on_conflict_do_update_data_t<Database, ConflictTarget, Assignments...> assignments)
: _expression(expression), _assignments(assignments)
{
}
on_conflict_do_update_where_data_t(const on_conflict_do_update_where_data_t&) = default;
on_conflict_do_update_where_data_t(on_conflict_do_update_where_data_t&&) = default;
on_conflict_do_update_where_data_t& operator=(const on_conflict_do_update_where_data_t&) = default;
on_conflict_do_update_where_data_t& operator=(on_conflict_do_update_where_data_t&&) = default;
Expression _expression;
on_conflict_do_update_data_t<Database, ConflictTarget, Assignments...> _assignments;
// interpretable_list_t<Database> _dynamic_expressions;
};
// extra where statement
template <typename Database, typename ConflictTarget, typename Expression, typename... Assignments>
struct on_conflict_do_update_where_t
{
using _traits = make_traits<no_value_t, tag::is_on_conflict_do_update>;
using _nodes = sqlpp::detail::type_vector<ConflictTarget, Expression, Assignments...>;
using _is_dynamic = is_database<Database>;
using _data_t = on_conflict_do_update_where_data_t<Database, ConflictTarget, Expression, Assignments...>;
// Member implementation and methods
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_impl_t() = default;
_impl_t(const _data_t& data) : _data(data)
{
}
_data_t _data;
};
template <typename Policies>
struct _base_t
{
using _data_t = on_conflict_do_update_where_data_t<Database, ConflictTarget, Expression, Assignments...>;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : where{std::forward<Args>(args)...}
{
}
_impl_t<Policies> where;
_impl_t<Policies>& operator()()
{
return where;
}
const _impl_t<Policies>& operator()() const
{
return where;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.where)
{
return t.where;
}
using _consistency_check = consistent_t;
};
};
// Use the update_list
template <typename Database, typename ConflictTarget, typename... Assignments>
struct on_conflict_do_update_t
{
using _traits = make_traits<no_value_t, tag::is_on_conflict_do_update>;
using _nodes = sqlpp::detail::type_vector<ConflictTarget, Assignments...>;
using _is_dynamic = is_database<Database>;
// Data
using _data_t = on_conflict_do_update_data_t<Database, ConflictTarget, Assignments...>;
// Member implementation with data and methods
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_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 = on_conflict_do_update_data_t<Database, ConflictTarget, Assignments...>;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : assignments{std::forward<Args>(args)...}
{
}
_impl_t<Policies> assignments;
_impl_t<Policies>& operator()()
{
return assignments;
}
const _impl_t<Policies>& operator()() const
{
return assignments;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.assignments)
{
return t.assignments;
}
using _consistency_check = consistent_t;
template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check, Policies, on_conflict_do_update_t, T>;
// WHERE
template <typename Expression>
auto where(Expression expression) const
-> _new_statement_t<check_where_static_t<Expression>,
on_conflict_do_update_where_t<void, ConflictTarget, Expression, Assignments...>>
{
return {static_cast<const derived_statement_t<Policies>&>(*this),
on_conflict_do_update_where_data_t<void, ConflictTarget, Expression, Assignments...>(
expression, assignments._data)};
}
};
};
template <typename Database, typename ConflictTarget, typename... Assignments>
postgresql::context_t& serialize(
const postgresql::on_conflict_do_update_data_t<Database, ConflictTarget, Assignments...>& o,
postgresql::context_t& context)
{
serialize(o._conflict_target, context);
context << "DO UPDATE SET ";
interpret_tuple(o._assignments, ",", context);
return context;
}
template <typename Database, typename ConflictTarget, typename Expression, typename... Assignments>
postgresql::context_t& serialize(
const postgresql::on_conflict_do_update_where_data_t<Database, ConflictTarget, Expression, Assignments...>& o,
postgresql::context_t& context)
{
serialize(o._assignments, context);
context << " WHERE ";
serialize(o._expression, context);
return context;
}
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,36 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_H
#define SQLPP_POSTGRESQL_H
#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/postgresql/insert.h>
#include <sqlpp11/postgresql/update.h>
#endif

View File

@ -0,0 +1,216 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_PREPARED_STATEMENT_H
#define SQLPP_POSTGRESQL_PREPARED_STATEMENT_H
#include <memory>
#include <string>
#include <sqlpp11/chrono.h>
#include <sqlpp11/postgresql/exception.h>
namespace sqlpp
{
namespace postgresql
{
#ifdef SQLPP_DYNAMIC_LOADING
using namespace dynamic;
#endif
// Forward declaration
class connection;
// Detail namespace
namespace detail
{
struct prepared_statement_handle_t;
}
class prepared_statement_t
{
friend sqlpp::postgresql::connection;
private:
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
public:
prepared_statement_t() = default;
prepared_statement_t(std::shared_ptr<detail::prepared_statement_handle_t>&& handle);
prepared_statement_t(const prepared_statement_t&) = delete;
prepared_statement_t(prepared_statement_t&&) = default;
prepared_statement_t& operator=(const prepared_statement_t&) = delete;
prepared_statement_t& operator=(prepared_statement_t&&) = default;
~prepared_statement_t() = default;
bool operator==(const prepared_statement_t& rhs)
{
return (this->_handle == rhs._handle);
}
void _bind_boolean_parameter(size_t index, const signed char* value, bool is_null);
void _bind_floating_point_parameter(size_t index, const double* value, bool is_null);
void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null);
void _bind_text_parameter(size_t index, const std::string* value, bool is_null);
void _bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null);
void _bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null);
};
// ctor
inline prepared_statement_t::prepared_statement_t(std::shared_ptr<detail::prepared_statement_handle_t>&& handle)
: _handle{handle}
{
if (_handle && _handle->debug())
{
std::cerr << "PostgreSQL debug: constructing prepared_statement, using handle at: " << _handle.get()
<< std::endl;
}
}
inline void prepared_statement_t::_bind_boolean_parameter(size_t index, const signed char* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding boolean parameter " << (*value ? "true" : "false")
<< " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
}
_handle->nullValues[index] = is_null;
if (!is_null)
{
if (*value)
{
_handle->paramValues[index] = "TRUE";
}
else
{
_handle->paramValues[index] = "FALSE";
}
}
}
inline void prepared_statement_t::_bind_floating_point_parameter(size_t index, const double* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding floating_point parameter " << *value << " at index: " << index
<< ", being " << (is_null ? "" : "not ") << "null" << std::endl;
}
_handle->nullValues[index] = is_null;
if (!is_null)
{
std::ostringstream out;
out.precision(std::numeric_limits<double>::digits10);
out << std::fixed << *value;
_handle->paramValues[index] = out.str();
}
}
inline void prepared_statement_t::_bind_integral_parameter(size_t index, const int64_t* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding integral parameter " << *value << " at index: " << index << ", being "
<< (is_null ? "" : "not ") << "null" << std::endl;
}
// Assign values
_handle->nullValues[index] = is_null;
if (!is_null)
{
_handle->paramValues[index] = std::to_string(*value);
}
}
inline void prepared_statement_t::_bind_text_parameter(size_t index, const std::string* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding text parameter " << *value << " at index: " << index << ", being "
<< (is_null ? "" : "not ") << "null" << std::endl;
}
// Assign values
_handle->nullValues[index] = is_null;
if (!is_null)
{
_handle->paramValues[index] = *value;
}
}
inline void prepared_statement_t::_bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date parameter at index "
<< index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
}
_handle->nullValues[index] = is_null;
if (not is_null)
{
const auto ymd = ::date::year_month_day{*value};
std::ostringstream os;
os << ymd;
_handle->paramValues[index] = os.str();
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date parameter string: " << _handle->paramValues[index] << std::endl;
}
}
}
inline void prepared_statement_t::_bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date_time parameter at index "
<< index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
}
_handle->nullValues[index] = is_null;
if (not is_null)
{
const auto dp = ::sqlpp::chrono::floor<::date::days>(*value);
const auto time = ::date::make_time(::sqlpp::chrono::floor<::std::chrono::microseconds>(*value - dp));
const auto ymd = ::date::year_month_day{dp};
// Timezone handling - always treat the value as UTC.
// It is assumed that the database timezone is set to UTC, too.
std::ostringstream os;
os << ymd << ' ' << time;
_handle->paramValues[index] = os.str();
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date_time parameter string: " << _handle->paramValues[index] << std::endl;
}
}
}
}
}
#endif

View File

@ -0,0 +1,346 @@
/**
* Copyright © 2015-2016, Bartosz Wieczorek
* 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_POSTGRESQL_RESULT_H
#define SQLPP_POSTGRESQL_RESULT_H
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <libpq-fe.h>
#include <sqlpp11/postgresql/visibility.h>
#include <sqlpp11/postgresql/exception.h>
#ifdef SQLPP_DYNAMIC_LOADING
#include <sqlpp11/postgresql/dynamic_libpq.h>
#endif
namespace sqlpp
{
namespace postgresql
{
#ifdef SQLPP_DYNAMIC_LOADING
using namespace dynamic;
#endif
class DLL_PUBLIC Result
{
public:
Result();
~Result();
ExecStatusType status();
void clear();
int affected_rows();
int records_size() const;
int field_count() const;
int length(int record, int field) const;
bool isNull(int record, int field) const;
void operator=(PGresult* res);
operator bool() const;
template <typename T = const char*>
inline T getValue(int record, int field) const
{
static_assert(std::is_arithmetic<T>::value, "Value must be numeric type");
checkIndex(record, field);
T t(0);
auto txt = std::string(getPqValue(m_result, record, field));
if(txt != "")
{
t = std::stold(txt);
}
return t;
}
const std::string& query() const
{
return m_query;
}
std::string& query()
{
return m_query;
}
private:
void CheckStatus() const;
[[noreturn]] void ThrowSQLError(const std::string& Err, const std::string& Query) const;
std::string StatusError() const;
int errorPosition() const noexcept;
bool hasError();
void checkIndex(int record, int field) const noexcept(false);
// move PQgetvalue to implementation so we don't depend on the libpq in the
// public interface
const char* getPqValue(PGresult* result, int record, int field) const;
PGresult* m_result;
std::string m_query;
};
template <>
inline const char* Result::getValue<const char*>(int record, int field) const
{
return const_cast<const char*>(getPqValue(m_result, record, field));
}
template <>
inline std::string Result::getValue<std::string>(int record, int field) const
{
return {getValue<const char*>(record, field)};
}
template <>
inline bool Result::getValue<bool>(int record, int field) const
{
checkIndex(record, field);
auto val = getPqValue(m_result, record, field);
if (*val == 't')
return true;
else if (*val == 'f')
return false;
return const_cast<const char*>(val);
}
inline Result::Result() : m_result(nullptr)
{
}
inline void Result::checkIndex(int record, int field) const noexcept(false)
{
if (record > records_size() || field > field_count())
throw std::out_of_range("PostgreSQL error: index out of range");
}
inline void Result::operator=(PGresult* res)
{
m_result = res;
CheckStatus();
}
inline void Result::CheckStatus() const
{
const std::string Err = StatusError();
if (!Err.empty())
ThrowSQLError(Err, query());
}
inline const char* Result::getPqValue(PGresult* result, int record, int field) const
{
return const_cast<const char*>(PQgetvalue(result, record, field));
}
[[noreturn]] inline void Result::ThrowSQLError(const std::string& Err, const std::string& Query) const
{
// Try to establish more precise error type, and throw corresponding exception
const char* const code = PQresultErrorField(m_result, PG_DIAG_SQLSTATE);
if (code)
switch (code[0])
{
case '0':
switch (code[1])
{
case '8':
throw broken_connection(Err);
case 'A':
throw feature_not_supported(Err, Query);
}
break;
case '2':
switch (code[1])
{
case '2':
throw data_exception(Err, Query);
case '3':
if (strcmp(code, "23001") == 0)
throw restrict_violation(Err, Query);
if (strcmp(code, "23502") == 0)
throw not_null_violation(Err, Query);
if (strcmp(code, "23503") == 0)
throw foreign_key_violation(Err, Query);
if (strcmp(code, "23505") == 0)
throw unique_violation(Err, Query);
if (strcmp(code, "23514") == 0)
throw check_violation(Err, Query);
throw integrity_constraint_violation(Err, Query);
case '4':
throw invalid_cursor_state(Err, Query);
case '6':
throw invalid_sql_statement_name(Err, Query);
}
break;
case '3':
switch (code[1])
{
case '4':
throw invalid_cursor_name(Err, Query);
}
break;
case '4':
switch (code[1])
{
case '2':
if (strcmp(code, "42501") == 0)
throw insufficient_privilege(Err, Query);
if (strcmp(code, "42601") == 0)
throw syntax_error(Err, Query, errorPosition());
if (strcmp(code, "42703") == 0)
throw undefined_column(Err, Query);
if (strcmp(code, "42883") == 0)
throw undefined_function(Err, Query);
if (strcmp(code, "42P01") == 0)
throw undefined_table(Err, Query);
}
break;
case '5':
switch (code[1])
{
case '3':
if (strcmp(code, "53100") == 0)
throw disk_full(Err, Query);
if (strcmp(code, "53200") == 0)
throw out_of_memory(Err, Query);
if (strcmp(code, "53300") == 0)
throw too_many_connections(Err);
throw insufficient_resources(Err, Query);
}
break;
case 'P':
if (strcmp(code, "P0001") == 0)
throw plpgsql_raise(Err, Query);
if (strcmp(code, "P0002") == 0)
throw plpgsql_no_data_found(Err, Query);
if (strcmp(code, "P0003") == 0)
throw plpgsql_too_many_rows(Err, Query);
throw plpgsql_error(Err, Query);
}
throw sql_error(Err, Query);
}
inline std::string Result::StatusError() const
{
if (!m_result)
throw failure("No result set given");
std::string Err;
switch (PQresultStatus(m_result))
{
case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
case PGRES_COMMAND_OK: // Successful completion of a command returning no data
case PGRES_TUPLES_OK: // The query successfully executed
break;
case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
case PGRES_COPY_IN: // Copy In (to server) data transfer started
break;
case PGRES_BAD_RESPONSE: // The server's response was not understood
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
Err = PQresultErrorMessage(m_result);
break;
case PGRES_COPY_BOTH:
case PGRES_SINGLE_TUPLE:
throw sqlpp::exception("pqxx::result: Unrecognized response code " +
std::to_string(PQresultStatus(m_result)));
}
return Err;
}
inline int Result::errorPosition() const noexcept
{
int pos = -1;
if (m_result)
{
const char* p = PQresultErrorField(m_result, PG_DIAG_STATEMENT_POSITION);
if (p)
pos = std::stoi(std::string(p));
}
return pos;
}
inline sqlpp::postgresql::Result::operator bool() const
{
return m_result != 0;
}
inline void Result::clear()
{
if (m_result)
PQclear(m_result);
m_result = nullptr;
}
inline int Result::affected_rows()
{
const char* const RowsStr = PQcmdTuples(m_result);
return RowsStr[0] ? std::stoi(std::string(RowsStr)) : 0;
}
inline int Result::records_size() const
{
return m_result ? PQntuples(m_result) : 0;
}
inline int Result::field_count() const
{
return m_result ? PQnfields(m_result) : 0;
}
inline bool Result::isNull(int record, int field) const
{
/// check index?
return PQgetisnull(m_result, record, field);
}
inline int Result::length(int record, int field) const
{
/// check index?
return PQgetlength(m_result, record, field);
}
inline Result::~Result()
{
clear();
}
inline ExecStatusType Result::status()
{
return PQresultStatus(m_result);
}
}
}
#endif

View File

@ -0,0 +1,176 @@
/**
* Copyright © 2014-2018, Matthijs Möhlmann
* 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_POSTGRESQL_RETURNING_H
#define SQLPP_POSTGRESQL_RETURNING_H
#include <sqlpp11/postgresql/returning_column_list.h>
#include <sqlpp11/select_column_list.h>
#include <sqlpp11/statement.h>
namespace sqlpp
{
SQLPP_VALUE_TRAIT_GENERATOR(is_returning)
namespace postgresql
{
struct return_name_t
{
};
struct returning_t : public statement_name_t<return_name_t, tag::is_returning>
{
};
template <typename Database>
using blank_returning_t = statement_t<Database, returning_t, no_returning_column_list_t>;
inline blank_returning_t<void> returning()
{
return {};
}
struct no_returning_t
{
using _traits = make_traits<no_value_t, tag::is_returning>;
using _nodes = ::sqlpp::detail::type_vector<>;
using _data_t = no_data_t;
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_impl_t() = default;
_impl_t(const _data_t& data) : _data(data)
{
}
_data_t _data;
};
template <typename Policies>
struct _base_t
{
using _data_t = no_data_t;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : no_returning{std::forward<Args>(args)...}
{
}
_impl_t<Policies> no_returning;
_impl_t<Policies>& operator()()
{
return no_returning;
}
const _impl_t<Policies>& operator()() const
{
return no_returning;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.no_returning)
{
return t.no_returning;
}
using _database_t = typename Policies::_database_t;
template <typename... T>
static constexpr auto _check_tuple(std::tuple<T...>) -> check_selected_columns_t<T...>
{
return {};
}
template <typename... T>
static constexpr auto _check_args(T... args)
-> decltype(_check_tuple(sqlpp::detail::column_tuple_merge(args...)))
{
return {};
}
template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check, Policies, no_returning_t, T>;
using _consistency_check = consistent_t;
template <typename... Columns>
auto returning(Columns... columns) const
-> _new_statement_t<decltype(_check_args(columns...)), returning_column_list_t<_database_t, Columns...>>
{
static_assert(sizeof...(Columns),
"at least one returnable expression (e.g. a column) is required in returning");
static_assert(decltype(_check_args(columns...))::value,
"at least one argument is not a returnable expression in returning()");
return {static_cast<const derived_statement_t<Policies>&>(*this),
typename returning_column_list_t<_database_t, Columns...>::_data_t{columns...}};
}
template <typename... Columns>
auto returning(std::tuple<Columns...> columns) const
-> _new_statement_t<decltype(_check_args(columns)), returning_column_list_t<_database_t, Columns...>>
{
static_assert(sizeof...(Columns),
"at least one returnable expression (e.g. a column) is required in returning");
static_assert(decltype(_check_args(columns))::value,
"at least one argument is not a returnable expression in returning()");
return {static_cast<const derived_statement_t<Policies>&>(*this),
typename returning_column_list_t<_database_t, Columns...>::_data_t{columns}};
}
template <typename... Columns>
auto dynamic_returning(Columns... columns) const
-> _new_statement_t<void, returning_column_list_t<_database_t, Columns...>>
{
static_assert(sizeof...(Columns),
"at least one returnable expression (e.g. a column) is required in returning");
static_assert(decltype(_check_args(columns...))::value,
"at least one argument is not a returnable expression in returning()");
return {static_cast<const derived_statement_t<Policies>&>(*this),
typename returning_column_list_t<_database_t, Columns...>::_data_t{columns...}};
}
template <typename Database, typename... Columns>
auto dynamic_returning(const Database&, Columns... columns)
-> decltype(blank_returning_t<Database>().columns(columns...))
{
static_assert(sizeof...(Columns),
"at least one returnable expression (e.g. a column) is required in returning");
static_assert(decltype(_check_args(columns...))::value,
"at least one argument is not a returnable expression in returning()");
static_assert(std::is_base_of<connection, Database>::value, "Invalid database parameter");
return {static_cast<const derived_statement_t<Policies>&>(*this),
typename dynamic_returning_column_list<_database_t>::_data_t{columns...}};
}
};
};
} // namespace postgresql
} // namespace sqlpp
#endif

View File

@ -0,0 +1,496 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_RETURNING_COLUMN_LIST_H
#define SQLPP_POSTGRESQL_RETURNING_COLUMN_LIST_H
#include <sqlpp11/data_types/no_value.h>
#include <sqlpp11/detail/column_tuple_merge.h>
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/expression_fwd.h>
#include <sqlpp11/field_spec.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/named_interpretable.h>
#include <sqlpp11/operand_check.h>
#include <sqlpp11/policy_update.h>
#include <sqlpp11/result_row.h>
#include <sqlpp11/select_pseudo_table.h>
#include <sqlpp11/table.h>
#include <tuple>
namespace sqlpp
{
SQLPP_VALUE_TRAIT_GENERATOR(is_returning_column_list)
namespace postgresql
{
namespace detail
{
template <typename... Columns>
struct returning_traits
{
using _traits = make_traits<no_value_t, tag::is_returning_column_list, tag::is_return_value>;
struct _alias_t
{
};
};
template <typename Column>
struct returning_traits<Column>
{
using _traits = make_traits<value_type_of<Column>,
tag::is_returning_column_list,
tag::is_return_value,
tag::is_expression,
tag::is_selectable>; // TODO: Is this correct?
using _alias_t = typename Column::_alias_t;
};
} // namespace detail
template <typename Db>
struct dynamic_returning_column_list
{
using _names_t = std::vector<std::string>;
std::vector<named_interpretable_t<Db>> _dynamic_columns;
_names_t _dynamic_expression_names;
template <typename Expr>
void emplace_back(Expr expr)
{
_dynamic_expression_names.push_back(name_of<Expr>::char_ptr());
_dynamic_columns.emplace_back(expr);
}
bool empty() const
{
return _dynamic_columns.empty();
}
};
template <>
struct dynamic_returning_column_list<void>
{
using _names_t = no_name_t;
_names_t _dynamic_expression_names;
static constexpr bool empty()
{
return true;
}
};
template <typename Db>
postgresql::context_t& serialize(const postgresql::dynamic_returning_column_list<Db>& t,
postgresql::context_t& context)
{
bool first{true};
for (const auto& column : t._dynamic_columns)
{
if (first)
{
first = false;
}
else
{
context << ',';
}
serialize(column, context);
}
return context;
}
inline postgresql::context_t& serialize(const postgresql::dynamic_returning_column_list<void>&,
postgresql::context_t& context)
{
return context;
}
template <typename Database, typename... Columns>
struct returning_column_list_data_t
{
returning_column_list_data_t(Columns... columns) : _columns(columns...)
{
}
returning_column_list_data_t(std::tuple<Columns...> columns) : _columns(columns)
{
}
returning_column_list_data_t(const returning_column_list_data_t&) = default;
returning_column_list_data_t(returning_column_list_data_t&&) = default;
returning_column_list_data_t& operator=(const returning_column_list_data_t&) = default;
returning_column_list_data_t& operator=(returning_column_list_data_t&&) = default;
std::tuple<Columns...> _columns;
dynamic_returning_column_list<Database> _dynamic_columns;
};
// static asserts...
SQLPP_PORTABLE_STATIC_ASSERT(
assert_no_unknown_tables_in_returning_columns_t,
"at least one returning column requires a table which is otherwise not known in the statement");
// Columns in returning list
template <typename Database, typename... Columns>
struct returning_column_list_t
{
using _traits = typename detail::returning_traits<Columns...>::_traits;
using _nodes = ::sqlpp::detail::type_vector<Columns...>;
using _alias_t = typename detail::returning_traits<Columns...>::_alias_t;
using _is_dynamic = is_database<Database>;
struct _column_type
{
};
// Data
using _data_t = returning_column_list_data_t<Database, Columns...>;
// Implementation
template <typename Policies>
struct _impl_t
{
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
_impl_t() = default;
_impl_t(const _data_t& data) : _data(data)
{
}
template <typename NamedExpression>
void add_ntc(NamedExpression namedExpression)
{
add<NamedExpression, std::false_type>(namedExpression);
}
template <typename NamedExpression, typename TableCheckRequired = std::true_type>
void add(NamedExpression namedExpression)
{
using named_expression = auto_alias_t<NamedExpression>;
static_assert(_is_dynamic::value, "selected_columns::add() can only be called for dynamic_column");
static_assert(is_selectable_t<named_expression>::value,
"invalid named expression argument in selected_columns::add()");
static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables<named_expression>::value,
"named expression uses tables unknown to this statement in selected_columns::add()");
using column_names = ::sqlpp::detail::make_type_set_t<typename Columns::_alias_t...>;
static_assert(not::sqlpp::detail::is_element_of<typename named_expression::_alias_t, column_names>::value,
"a column of this name is present in the select already");
using ok = logic::all_t<_is_dynamic::value, is_selectable_t<named_expression>::value>;
_add_impl(namedExpression, ok());
}
template <typename NamedExpression>
void _add_impl(NamedExpression namedExpression, const std::true_type&)
{
return _data._dynamic_columns.emplace_back(auto_alias_t<NamedExpression>{namedExpression});
}
template <typename NamedExpression>
void _add_impl(NamedExpression namedExpression, const std::false_type&);
_data_t _data;
};
// Base template to be inherited by statement
template <typename Policies>
struct _base_t
{
using _data_t = returning_column_list_data_t<Database, Columns...>;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&&... args) : returning_columns{std::forward<Args>(args)...}
{
}
_impl_t<Policies> returning_columns;
_impl_t<Policies>& operator()()
{
return returning_columns;
}
const _impl_t<Policies>& operator()() const
{
return returning_columns;
}
_impl_t<Policies>& get_selected_columns()
{
return returning_columns;
}
const _impl_t<Policies>& get_selected_columns() const
{
return returning_columns;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.returning_columms)
{
return t.returning_columns;
}
// Checks
using _table_check =
typename std::conditional<Policies::template _no_unknown_tables<returning_column_list_t>::value,
consistent_t,
assert_no_unknown_tables_in_returning_columns_t>::type;
using _consistency_check = ::sqlpp::detail::get_first_if<is_inconsistent_t, consistent_t, _table_check>;
};
// Result methods
template <typename Statement>
struct _result_methods_t
{
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
template <typename Db, typename Column>
struct _deferred_field_t
{
using type = make_field_spec_t<_statement_t, Column>;
};
template <typename Db, typename Column>
using _field_t = typename _deferred_field_t<Db, Column>::type;
template <typename Db>
using _result_row_t = typename std::conditional<_is_dynamic::value,
dynamic_result_row_t<Db, _field_t<Db, Columns>...>,
result_row_t<Db, _field_t<Db, Columns>...>>::type;
using _dynamic_names_t = typename dynamic_returning_column_list<Database>::_names_t;
template <typename AliasProvider>
struct _deferred_table_t
{
using table = select_pseudo_table_t<_statement_t, Columns...>;
using alias = typename table::template _alias_t<AliasProvider>;
};
template <typename AliasProvider>
using _table_t = typename _deferred_table_t<AliasProvider>::table;
template <typename AliasProvider>
using _alias_t = typename _deferred_table_t<AliasProvider>::alias;
template <typename AliasProvider>
_alias_t<AliasProvider> as(const AliasProvider& aliasProvider) const
{
consistency_check_t<_statement_t>::_();
static_assert(_statement_t::_can_be_used_as_table(),
"statement cannot be used as table, e.g. due to missing tables");
return _table_t<AliasProvider>(_get_statement()).as(aliasProvider);
}
const _dynamic_names_t& get_dynamic_names() const
{
return _get_statement().get_selected_columns()._data._dynamic_columns._dynamic_expression_names;
}
size_t get_no_of_result_columns() const
{
return sizeof...(Columns) + get_dynamic_names().size();
}
// auto ..
template <typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const
-> result_t<decltype(db.select(composite)), _result_row_t<Db>>
{
return {db.select(composite), get_dynamic_names()};
}
template <typename Db>
auto _run(Db& db) const -> result_t<decltype(db.select(std::declval<_statement_t>())), _result_row_t<Db>>
{
return {db.select(_get_statement()), get_dynamic_names()};
}
// Prepare
template <typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const -> prepared_select_t<Db, _statement_t, Composite>
{
return {make_parameter_list_t<Composite>{}, get_dynamic_names(), db.prepare_select(composite)};
}
template <typename Db>
auto _prepare(Db& db) const -> prepared_select_t<Db, _statement_t>
{
return {make_parameter_list_t<_statement_t>{}, get_dynamic_names(), db.prepare_select(_get_statement())};
}
};
};
namespace detail
{
template <typename Database, typename... Columns>
returning_column_list_t<Database, Columns...> make_returning_column_list(std::tuple<Columns...> columns);
}
struct no_returning_column_list_t
{
using _traits = make_traits<no_value_t, tag::is_noop, tag::is_missing>;
using _nodes = ::sqlpp::detail::type_vector<>;
struct _alias_t
{
};
// 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/2173269
_impl_t() = default;
_impl_t(const _data_t& data) : _data(data)
{
}
_data_t _data;
};
// Base template to be inherited
template <typename Policies>
struct _base_t
{
using _data_t = no_data_t;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
template <typename... Args>
_base_t(Args&... args) : no_returned_columns{std::forward<Args>(args)...}
{
}
_impl_t<Policies> no_returned_columns;
_impl_t<Policies>& operator()()
{
return no_returned_columns;
}
const _impl_t<Policies>& operator()() const
{
return no_returned_columns;
}
template <typename T>
static auto _get_member(T t) -> decltype(t.no_returned_columns)
{
return t.no_returned_columns;
}
using _database_t = typename Policies::_database_t;
template <typename... T>
struct _check : logic::all_t<is_selectable_t<T>::value...>
{
};
template <typename... T>
static constexpr auto _check_tuple(std::tuple<T...>) -> _check<T...>
{
return {};
}
template <typename... T>
static constexpr auto _check_args(T... args)
-> decltype(_check_tuple(sqlpp::detail::column_tuple_merge(args...)))
{
return _check_tuple(sqlpp::detail::column_tuple_merge(args...));
}
template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check, Policies, no_returning_column_list_t, T>;
using _consistency_check = consistent_t;
template <typename... Args>
auto returning(Args... args) const -> _new_statement_t<
decltype(_check_args(args...)),
decltype(detail::make_returning_column_list<void>(::sqlpp::detail::column_tuple_merge(args...)))>
{
static_assert(sizeof...(Args), "at least one selectable expression (e.g. a column) required in returning()");
static_assert(decltype(_check_args(args...))::value,
"at least one argument is not a selectable expression in returning()");
return _returning_impl<void>(decltype(_check_args(args...)){}, ::sqlpp::detail::column_tuple_merge(args...));
}
template <typename... Args>
auto dynamic_returning(Args... args) const
-> _new_statement_t<decltype(_check_args(args...)),
decltype(detail::make_returning_column_list<_database_t>(::sqlpp::detail::column_tuple_merge(args...)))>
{
static_assert(not std::is_same<_database_t, void>::value,
"dynamic_columns must not be called in a static statement");
static_assert(decltype(_check_args(args...))::value,
"at least one argument is not a selectable expression in returning()");
return _returning_impl<_database_t>(decltype(_check_args(args...)){},
::sqlpp::detail::column_tuple_merge(args...));
}
private:
template <typename Database, typename Check, typename... Args>
auto _returning_impl(const std::false_type&, std::tuple<Args...> args) const -> inconsistent<Check>;
template <typename Database, typename... Args>
auto _returning_impl(consistent_t, std::tuple<Args...> args) const
-> _new_statement_t<consistent_t, returning_column_list_t<Database, Args...>>
{
static_assert(not::sqlpp::detail::has_duplicates<Args...>::value, "at least one duplicate argument detected");
static_assert(not::sqlpp::detail::has_duplicates<typename Args::_alias_t...>::value,
"at least one duplicate name detected");
return {static_cast<const derived_statement_t<Policies>&>(*this),
typename returning_column_list_t<Database, Args...>::_data_t{args}};
}
};
};
// Serialization
template <typename Database, typename... Columns>
postgresql::context_t& serialize(const postgresql::returning_column_list_data_t<Database, Columns...>& t,
postgresql::context_t& context)
{
context << " RETURNING ";
interpret_tuple(t._columns, ',', context);
if (sizeof...(Columns) and not t._dynamic_columns.empty())
context << ',';
serialize(t._dynamic_columns, context);
return context;
}
}
} // namespace sqlpp
#endif

View File

@ -0,0 +1,46 @@
/**
* Copyright © 2014-2015, Matthijs Möhlmann
* 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_POSTGRESQL_SERIALIZER_H
#define SQLPP_POSTGRESQL_SERIALIZER_H
#include <sqlpp11/parameter.h>
#include <sqlpp11/wrap_operand.h>
namespace sqlpp
{
// Serialize parameters
template <typename ValueType, typename NameType>
postgresql::context_t& serialize(const parameter_t<ValueType, NameType>&, postgresql::context_t& context)
{
context << "$" << context.count();
context.pop_count();
return context;
}
}
#endif

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2016, Bartoszek
* 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_POSTGRESQL_UPDATE_H
#define SQLPP_POSTGRESQL_UPDATE_H
#include <sqlpp11/update.h>
#include <sqlpp11/postgresql/returning.h>
namespace sqlpp
{
namespace postgresql
{
template <typename Database>
using blank_update_t =
statement_t<Database, update_t, no_single_table_t, no_update_list_t, no_where_t<true>, no_returning_t>;
template <typename Table>
constexpr auto update(Table table) -> decltype(blank_update_t<void>().single_table(table))
{
return {blank_update_t<void>().single_table(table)};
}
template <typename Database, typename Table>
constexpr auto dynamic_update(const Database&, Table table)
-> decltype(blank_update_t<Database>().single_table(table))
{
static_assert(std::is_base_of<connection, Database>::value, "Invalid database parameter");
return {blank_update_t<Database>().single_table(table)};
}
}
}
#endif

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2015 cszawisza <cszawisza@gmail.com>
* 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 SQLPP11_POSTGRESQL_VISIBILITY_H
#define SQLPP11_POSTGRESQL_VISIBILITY_H
#ifdef SQLPP_DYNAMIC_LOADING
#if defined _WIN32 || defined __CYGWIN__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__((dllexport))
#else
#define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__((dllimport))
#else
#define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define DLL_LOCAL
#else
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__((visibility("default")))
#define DLL_LOCAL __attribute__((visibility("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif

View File

@ -29,6 +29,7 @@
#include <sqlpp11/data_types/no_value.h>
#include <sqlpp11/auto_alias.h>
#include <sqlpp11/detail/column_tuple_merge.h>
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/dynamic_select_column_list.h>
#include <sqlpp11/expression_fwd.h>
@ -291,24 +292,6 @@ namespace sqlpp
namespace detail
{
template <typename T>
std::tuple<auto_alias_t<T>> as_column_tuple(T t)
{
return std::tuple<auto_alias_t<T>>(auto_alias_t<T>{t});
}
template <typename... Args>
std::tuple<auto_alias_t<Args>...> as_column_tuple(std::tuple<Args...> t)
{
return t;
}
template <typename... Columns>
auto column_tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_column_tuple(columns)...))
{
return std::tuple_cat(as_column_tuple(columns)...);
}
template <typename Database, typename... Columns>
select_column_list_t<Database, Columns...> make_column_list(std::tuple<Columns...> columns);
} // namespace detail

View File

@ -0,0 +1,28 @@
# Copyright (c) 2021-2021, Roland Bock
# 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.
add_subdirectory(constraints)
add_subdirectory(usage)

View File

@ -0,0 +1,53 @@
# Copyright (c) 2013-2015, Roland Bock
# 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.
function(test_constraint name pattern)
set(test sqlpp11.postgresql.constraints.${name})
set(target sqlpp11_postgresql_${name})
add_executable(${target} EXCLUDE_FROM_ALL ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing)
target_link_libraries(${target} PRIVATE PostgreSQL::PostgreSQL)
add_test(NAME ${test}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target}
)
set_property(TEST ${test} PROPERTY PASS_REGULAR_EXPRESSION ${pattern})
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET ${target} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS no)
endif()
endfunction()
# Compiling these is required to fail (testing some static_assert)
test_constraint(OnConflictEmptyWhereDoUpdate "conflict_target specification is required with do_update")
test_constraint(OnConflictInvalidAssignmentsDoUpdate "conflict_target specification is required with do_update")
test_constraint(OnConflictInvalidParameter "only a column is supported as conflict_target specification")
test_constraint(OnConflictInvalidWhereDoUpdate "conflict_target specification is required with do_update")
test_constraint(OnConflictMissingAction "either do_nothing\\(\\) or do_update\\(...\\) is required with on_conflict")
test_constraint(OnConflictMissingAssignmentsDoUpdate "conflict_target specification is required with do_update")
test_constraint(OnConflictMissingParameterDoUpdate "conflict_target specification is required with do_update")
test_constraint(ReturningEmptyAssert "at least one returnable expression")
test_constraint(ReturningInvalidArgument "at least one returning column requires a table which is otherwise not known in the statement")

View File

@ -0,0 +1,47 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto insert1 = sql::insert_into(foo)
.default_values()
.on_conflict()
.do_update(foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true)
.where();
}

View File

@ -0,0 +1,48 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
model::TabBar bar = {};
auto insert1 = sql::insert_into(foo)
.default_values()
.on_conflict()
.do_update(foo.beta = 3, bar.c_int = 5)
.where(foo.beta == 2);
}

View File

@ -0,0 +1,44 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto insert1 = sql::insert_into(foo).default_values().on_conflict(foo).do_nothing();
}

View File

@ -0,0 +1,48 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto insert1 = sql::insert_into(foo)
.default_values()
.on_conflict()
.do_update(foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true)
.where(foo.beta = 3);
}

View File

@ -0,0 +1,46 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto sql = sql::insert_into(foo).default_values().on_conflict(foo.beta);
sql::connection dummydb;
const auto res = dummydb(sql);
}

View File

@ -0,0 +1,48 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto insert1 = sql::insert_into(foo)
.default_values()
.on_conflict()
.do_update()
.where(foo.beta == 2);
}

View File

@ -0,0 +1,48 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
model::TabFoo foo = {};
// model::TabBar bar = {};
auto insert1 = sql::insert_into(foo)
.default_values()
.on_conflict()
.do_update(foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true)
.where(foo.beta == 2);
}

View File

@ -0,0 +1,57 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
// Tables
model::TabFoo foo;
model::TabBar bar;
// Should not compile
auto sql = sqlpp::postgresql::insert_into(foo).set(foo.gamma = "bla").returning();
MockDb dummydb;
const auto res = dummydb(sql);
//auto sql = sqlpp::postgresql::insert_into(foo).set(foo.gamma = "bla").returning(all_of(foo));
//auto sql = sqlpp::postgresql::insert_into(foo).set(foo.gamma = "bla").returning(bar.c_int);
//MockDb dummydb;
//const auto res = dummydb(sql);
// Should not compile
//auto sql = sqlpp::postgresql::insert_into(foo).set(foo.gamma = "bla").returning();
return 0;
}

View File

@ -0,0 +1,48 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../usage/TabBar.h"
#include "../usage/TabFoo.h"
namespace sql = sqlpp::postgresql;
int main(int, char*[])
{
// Tables
model::TabFoo foo;
model::TabBar bar;
// Fail to compile
auto sql = sqlpp::postgresql::insert_into(foo).set(foo.gamma = "bla").returning(foo.gamma, bar.c_int);
sql::connection dummydb;
const auto res = dummydb(sql);
return 0;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2017, Volker Aßmann
* 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 <iostream>
#include <memory>
#include <stdexcept>
#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/sqlpp11.h>
namespace sql = sqlpp::postgresql;
int Basic(int, char*[])
{
auto config = std::make_shared<sql::connection_config>();
config->host = "localhost";
config->user = "unknown_user_must_fail";
try
{
sql::connection db(config);
throw std::logic_error("should never reach this point");
}
catch (const sqlpp::postgresql::broken_connection& ex)
{
std::cout << "Got exception: '" << ex.what() << "'";
return 0;
}
return 1;
}

View File

@ -0,0 +1,64 @@
# Copyright (c) 2015, Matthijs Möhlmann
# Copyright (c) 2021, Roland Bock
# 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.
add_library(sqlpp11_postgresql_testing INTERFACE)
target_include_directories(sqlpp11_postgresql_testing INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
set(test_names
Basic
Constructor
Date
DateTime
Exceptions
InsertOnConflict
Returning
Select
Transaction
Type
)
create_test_sourcelist(test_sources test_main.cpp ${test_names})
add_executable(sqlpp11_postgresql_tests ${test_sources})
target_link_libraries(sqlpp11_postgresql_tests PRIVATE sqlpp11 sqlpp11_testing sqlpp11_postgresql_testing)
target_link_libraries(sqlpp11_postgresql_tests PRIVATE sqlpp11::sqlpp11)
target_link_libraries(sqlpp11_postgresql_tests PRIVATE PostgreSQL::PostgreSQL)
target_link_libraries(sqlpp11_postgresql_tests PRIVATE date::date)
if(NOT MSVC)
target_compile_options(sqlpp11_postgresql_tests PRIVATE -Wall -Wextra -pedantic)
endif()
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET sqlpp11_postgresql_tests PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET sqlpp11_postgresql_tests PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET sqlpp11_postgresql_tests PROPERTY CXX_EXTENSIONS no)
endif()
foreach(test IN LISTS test_names)
add_test(NAME sqlpp11.postgresql.usage.${test}
COMMAND sqlpp11_postgresql_tests ${test}
)
endforeach()

View File

@ -0,0 +1,35 @@
/*
* 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 <sqlpp11/postgresql/connection.h>
#include <sqlpp11/sqlpp11.h>
namespace sql = sqlpp::postgresql;
int Constructor(int, char*[])
{
sql::connection db;
return 0;
}

View File

@ -0,0 +1,146 @@
/**
* Copyright © 2017 Volker Aßmann
* 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 <iostream>
#include <sqlpp11/custom_query.h>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabSample.h"
#include "make_test_connection.h"
namespace
{
const auto now = ::sqlpp::chrono::floor<::std::chrono::microseconds>(std::chrono::system_clock::now());
const auto today = ::sqlpp::chrono::floor<::sqlpp::chrono::days>(now);
const auto yesterday = today - ::sqlpp::chrono::days{1};
template <typename L, typename R>
void require_equal(int line, const L& l, const R& r)
{
if (l != r)
{
std::cerr << line << ": ";
serialize(::sqlpp::wrap_operand_t<L>{l}, std::cerr);
std::cerr << " != ";
serialize(::sqlpp::wrap_operand_t<R>{r}, std::cerr);
throw std::runtime_error("Unexpected result");
}
}
template <class Db>
void prepare_table(Db&& db, bool with_tz)
{
db.execute("DROP TABLE IF EXISTS tab_date_time");
if (with_tz)
{
// prepare test with timezone
db.execute("CREATE TABLE tab_date_time (col_day_point DATE, col_time_point TIMESTAMP WITH TIME ZONE)");
}
else
{
// prepare test without timezone
db.execute("CREATE TABLE tab_date_time (col_day_point DATE, col_time_point TIMESTAMP)");
}
}
} // namespace
int Date(int, char*[])
{
namespace sql = sqlpp::postgresql;
sql::connection db = sql::make_test_connection();
try
{
for (int i = 0; i <= 1; ++i)
{
if (i)
std::cerr << "Testing date/time WITH timezone\n";
else
std::cerr << "Testing date/time WITHOUT timezone\n";
prepare_table(db, i);
const auto tab = TabDateTime{};
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.is_null(), true);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
}
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.value(), today);
require_equal(__LINE__, row.colTimePoint.value(), now);
}
db(update(tab).set(tab.colDayPoint = yesterday, tab.colTimePoint = today).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.value(), yesterday);
require_equal(__LINE__, row.colTimePoint.value(), today);
}
auto prepared_update = db.prepare(
update(tab)
.set(tab.colDayPoint = parameter(tab.colDayPoint), tab.colTimePoint = parameter(tab.colTimePoint))
.unconditionally());
prepared_update.params.colDayPoint = today;
prepared_update.params.colTimePoint = now;
std::cout << "---- running prepared update ----" << std::endl;
db(prepared_update);
std::cout << "---- finished prepared update ----" << std::endl;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.value(), today);
require_equal(__LINE__, row.colTimePoint.value(), now);
}
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
catch (...)
{
std::cerr << "Unknown exception" << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2013 - 2015, Roland Bock
* 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 <cassert>
#include <iostream>
#include <vector>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabFoo.h"
#include "make_test_connection.h"
namespace
{
const auto now = ::date::floor<::std::chrono::microseconds>(std::chrono::system_clock::now());
const auto today = ::date::floor<::sqlpp::chrono::days>(now);
const auto yesterday = today - ::sqlpp::chrono::days{1};
template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void
{
if (l != r)
{
std::cerr << line << ": ";
serialize(::sqlpp::wrap_operand_t<L>{l}, std::cerr);
std::cerr << " != ";
serialize(::sqlpp::wrap_operand_t<R>{r}, std::cerr);
throw std::runtime_error("Unexpected result");
}
}
} // namespace
int DateTime(int, char*[])
{
namespace sql = sqlpp::postgresql;
sql::connection db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial NOT NULL,
beta smallint,
gamma text,
c_bool boolean,
c_timepoint timestamp with time zone,
c_day date
))");
model::TabFoo tab = {};
try
{
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.c_day.is_null(), true);
require_equal(__LINE__, row.c_day.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.c_timepoint.is_null(), true);
require_equal(__LINE__, row.c_timepoint.value(), ::sqlpp::chrono::microsecond_point{});
}
db(update(tab).set(tab.c_day = today, tab.c_timepoint = now).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.c_day.value(), today);
require_equal(__LINE__, row.c_timepoint.value(), now);
}
db(update(tab).set(tab.c_day = yesterday, tab.c_timepoint = today).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.c_day.value(), yesterday);
require_equal(__LINE__, row.c_timepoint.value(), today);
}
auto prepared_update =
db.prepare(update(tab)
.set(tab.c_day = parameter(tab.c_day), tab.c_timepoint = parameter(tab.c_timepoint))
.unconditionally());
prepared_update.params.c_day = today;
prepared_update.params.c_timepoint = now;
std::cout << "---- running prepared update ----" << std::endl;
db(prepared_update);
std::cout << "---- finished prepared update ----" << std::endl;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.c_day.value(), today);
require_equal(__LINE__, row.c_timepoint.value(), now);
}
}
catch (const sql::failure& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2014-2015, Matthijs Möhlmann
* 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/exception.h>
#include <sqlpp11/postgresql/postgresql.h>
#include "assertThrow.h"
#include "TabBar.h"
#include "TabFoo.h"
#include "make_test_connection.h"
namespace sql = sqlpp::postgresql;
int Exceptions(int, char*[])
{
{
// broken_connection exception on bad config
auto config = std::make_shared<sql::connection_config>();
config->host = "non-existing-host";
assert_throw(sql::connection db(config), sql::broken_connection);
}
model::TabFoo foo = {};
sql::connection db = sql::make_test_connection();
try
{
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial NOT NULL,
beta smallint UNIQUE,
gamma text CHECK( length(gamma) < 5 ),
c_bool boolean,
c_timepoint timestamp with time zone DEFAULT now(),
c_day date
))");
assert_throw(db(insert_into(foo).set(foo.beta = std::numeric_limits<int16_t>::max() + 1)), sql::data_exception);
assert_throw(db(insert_into(foo).set(foo.gamma = "123456")), sql::check_violation);
db(insert_into(foo).set(foo.beta = 5));
assert_throw(db(insert_into(foo).set(foo.beta = 5)), sql::integrity_constraint_violation);
assert_throw(db.last_insert_id("tabfoo", "no_such_column"), sqlpp::postgresql::undefined_table);
}
catch (const sql::failure& e)
{
std::cout << e.what();
return 1;
}
return 0;
}

View File

@ -0,0 +1,89 @@
/**
* Copyright © 2014-2019, Matthijs Möhlmann
* 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 <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabBar.h"
#include "TabFoo.h"
#include "make_test_connection.h"
namespace sql = sqlpp::postgresql;
int InsertOnConflict(int, char*[])
{
model::TabFoo foo = {};
sql::connection db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial PRIMARY KEY NOT NULL,
beta smallint,
gamma text,
c_bool boolean,
c_timepoint timestamp with time zone,
c_day date
))");
#warning: Need to add serialization tests
// Test on conflict
db(sql::insert_into(foo).default_values().on_conflict().do_nothing());
// Test on conflict (with conflict target)
db(sql::insert_into(foo).default_values().on_conflict(foo.alpha).do_nothing());
// Conflict target
db(sql::insert_into(foo).default_values().on_conflict(foo.alpha).do_update(
foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true));
// With where statement
for (const auto& row : db(sql::insert_into(foo)
.default_values()
.on_conflict(foo.alpha)
.do_update(foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true)
.where(foo.beta == 2)
.returning(foo.gamma)))
{
std::cout << row.gamma << std::endl;
}
// Returning
for (const auto& row : db(sql::insert_into(foo)
.default_values()
.on_conflict(foo.alpha)
.do_update(foo.beta = 5, foo.gamma = "test bla", foo.c_bool = true)
.returning(foo.beta)))
{
std::cout << row.beta << std::endl;
}
return 0;
}

View File

@ -0,0 +1,64 @@
#include <iostream>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabFoo.h"
#include "make_test_connection.h"
int Returning(int, char*[])
{
namespace sql = sqlpp::postgresql;
sql::connection db = sql::make_test_connection();
model::TabFoo foo = {};
try
{
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial NOT NULL,
beta smallint,
gamma text,
c_bool boolean,
c_timepoint timestamp with time zone DEFAULT now(),
c_day date
))");
std::cout
<< db(sqlpp::postgresql::insert_into(foo).set(foo.gamma = "dsa").returning(foo.c_timepoint)).front().c_timepoint
<< std::endl;
std::cout
<< db(sqlpp::postgresql::insert_into(foo).set(foo.gamma = "asd").returning(std::make_tuple(foo.c_timepoint))).front().c_timepoint
<< std::endl;
auto i = sqlpp::postgresql::dynamic_insert_into(db, foo).dynamic_set().returning(foo.c_timepoint);
i.insert_list.add(foo.gamma = "blah");
std::cout << db(i).front().c_timepoint << std::endl;
auto updated =
db(sqlpp::postgresql::update(foo).set(foo.beta = 0).unconditionally().returning(foo.gamma, foo.beta));
for (const auto& row : updated)
std::cout << "Gamma: " << row.gamma << " Beta: " << row.beta << std::endl;
auto multi_insert = sqlpp::postgresql::insert_into(foo).columns(foo.beta).returning(foo.alpha, foo.beta);
multi_insert.values.add(foo.beta = 1);
multi_insert.values.add(foo.beta = 2);
auto inserted = db(multi_insert);
for (const auto& row : inserted)
std::cout << row.beta << std::endl;
}
catch (const sql::failure&)
{
return 1;
}
return 0;
}

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2013 - 2015, Roland Bock
* 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 <cassert>
#include <iostream>
#include <vector>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabFoo.h"
#include "make_test_connection.h"
SQLPP_ALIAS_PROVIDER(left);
namespace sql = sqlpp::postgresql;
model::TabFoo tab = {};
void testSelectAll(sql::connection& db, int expectedRowCount)
{
std::cerr << "--------------------------------------" << std::endl;
int i = 0;
for (const auto& row : db(sqlpp::select(all_of(tab)).from(tab).unconditionally()))
{
++i;
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< std::endl;
assert(i == row.alpha);
};
assert(i == expectedRowCount);
auto preparedSelectAll = db.prepare(sqlpp::select(all_of(tab)).from(tab).unconditionally());
i = 0;
for (const auto& row : db(preparedSelectAll))
{
++i;
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< std::endl;
assert(i == row.alpha);
};
assert(i == expectedRowCount);
std::cerr << "--------------------------------------" << std::endl;
}
int Select(int, char*[])
{
sql::connection db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial NOT NULL,
beta smallint,
gamma text,
c_bool boolean,
c_timepoint timestamp with time zone,
c_day date
))");
testSelectAll(db, 0);
db(insert_into(tab).default_values());
testSelectAll(db, 1);
db(insert_into(tab).set(tab.c_bool = true, tab.gamma = "cheesecake"));
testSelectAll(db, 2);
db(insert_into(tab).set(tab.c_bool = true, tab.gamma = "cheesecake"));
testSelectAll(db, 3);
// Test size functionality
const auto test_size = db(select(all_of(tab)).from(tab).unconditionally());
assert(test_size.size() == 3);
// test functions and operators
db(select(all_of(tab)).from(tab).where(tab.alpha.is_null()));
db(select(all_of(tab)).from(tab).where(tab.alpha.is_not_null()));
db(select(all_of(tab)).from(tab).where(tab.alpha.in(1, 2, 3)));
db(select(all_of(tab)).from(tab).where(tab.alpha.in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
db(select(all_of(tab)).from(tab).where(tab.alpha.not_in(1, 2, 3)));
db(select(all_of(tab)).from(tab).where(tab.alpha.not_in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
db(select(count(tab.alpha)).from(tab).unconditionally());
db(select(avg(tab.alpha)).from(tab).unconditionally());
db(select(max(tab.alpha)).from(tab).unconditionally());
db(select(min(tab.alpha)).from(tab).unconditionally());
db(select(exists(select(tab.alpha).from(tab).where(tab.alpha > 7))).from(tab).unconditionally());
db(select(all_of(tab)).from(tab).where(tab.alpha == any(select(tab.alpha).from(tab).where(tab.alpha < 3))));
db(select(all_of(tab)).from(tab).where(tab.alpha == some(select(tab.alpha).from(tab).where(tab.alpha < 3))));
db(select(all_of(tab)).from(tab).where(tab.alpha + tab.alpha > 3));
db(select(all_of(tab)).from(tab).where((tab.gamma + tab.gamma) == ""));
db(select(all_of(tab)).from(tab).where((tab.gamma + tab.gamma).like("%'\"%")));
// test boolean value
db(insert_into(tab).set(tab.c_bool = true, tab.gamma = "asdf"));
db(insert_into(tab).set(tab.c_bool = false, tab.gamma = "asdfg"));
assert(db(select(tab.c_bool).from(tab).where(tab.gamma == "asdf")).front().c_bool);
assert(not db(select(tab.c_bool).from(tab).where(tab.gamma == "asdfg")).front().c_bool);
assert(not db(select(tab.c_bool).from(tab).where(tab.alpha == 1)).front().c_bool);
// test
// update
db(update(tab).set(tab.c_bool = false).where(tab.alpha.in(1)));
db(update(tab).set(tab.c_bool = false).where(tab.alpha.in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
// remove
db(remove_from(tab).where(tab.alpha == tab.alpha + 3));
auto result = db(select(all_of(tab)).from(tab).unconditionally());
std::cerr << "Accessing a field directly from the result (using the current row): " << result.begin()->alpha
<< std::endl;
std::cerr << "Can do that again, no problem: " << result.begin()->alpha << std::endl;
auto tx = start_transaction(db);
if (const auto& row = *db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally()).begin())
{
auto a = row.alpha;
auto m = row.max;
std::cerr << "-----------------------------" << a << ", " << m << std::endl;
}
tx.commit();
return 0;
}

View File

@ -0,0 +1,61 @@
#ifndef MODEL_TABBAR_H
#define MODEL_TABBAR_H
#include <sqlpp11/table.h>
#include <sqlpp11/char_sequence.h>
#include <sqlpp11/column_types.h>
namespace model
{
namespace TabBar_
{
struct C_int
{
struct _alias_t
{
static constexpr const char _literal[] = "c_int";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_int;
T& operator()()
{
return c_int;
}
const T& operator()() const
{
return c_int;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::bigint, sqlpp::tag::can_be_null>;
};
}
struct TabBar : sqlpp::table_t<TabBar, TabBar_::C_int>
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
{
static constexpr const char _literal[] = "TabBar";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T TabBar;
T& operator()()
{
return TabBar;
}
const T& operator()() const
{
return TabBar;
}
};
};
};
}
#endif

View File

@ -0,0 +1,187 @@
#ifndef MODEL_TABFOO_H
#define MODEL_TABFOO_H
#include <sqlpp11/table.h>
#include <sqlpp11/char_sequence.h>
#include <sqlpp11/column_types.h>
namespace model
{
namespace TabFoo_
{
struct Alpha
{
struct _alias_t
{
static constexpr const char _literal[] = "alpha";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T alpha;
T& operator()()
{
return alpha;
}
const T& operator()() const
{
return alpha;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::bigint, sqlpp::tag::can_be_null>;
};
struct Beta
{
struct _alias_t
{
static constexpr const char _literal[] = "beta";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T beta;
T& operator()()
{
return beta;
}
const T& operator()() const
{
return beta;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::smallint, sqlpp::tag::can_be_null>;
};
struct Gamma
{
struct _alias_t
{
static constexpr const char _literal[] = "gamma";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T gamma;
T& operator()()
{
return gamma;
}
const T& operator()() const
{
return gamma;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::text, sqlpp::tag::can_be_null>;
};
struct C_bool
{
struct _alias_t
{
static constexpr const char _literal[] = "c_bool";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_bool;
T& operator()()
{
return c_bool;
}
const T& operator()() const
{
return c_bool;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::boolean, sqlpp::tag::can_be_null>;
};
struct C_timepoint
{
struct _alias_t
{
static constexpr const char _literal[] = "c_timepoint";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_timepoint;
T& operator()()
{
return c_timepoint;
}
const T& operator()() const
{
return c_timepoint;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::time_point, sqlpp::tag::can_be_null>;
};
struct C_day
{
struct _alias_t
{
static constexpr const char _literal[] = "c_day";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_day;
T& operator()()
{
return c_day;
}
const T& operator()() const
{
return c_day;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::day_point, sqlpp::tag::can_be_null>;
};
}
struct TabFoo : sqlpp::table_t<TabFoo,
TabFoo_::Alpha,
TabFoo_::Beta,
TabFoo_::Gamma,
TabFoo_::C_bool,
TabFoo_::C_timepoint,
TabFoo_::C_day>
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
{
static constexpr const char _literal[] = "TabFoo";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T TabFoo;
T& operator()()
{
return TabFoo;
}
const T& operator()() const
{
return TabFoo;
}
};
};
};
}
#endif

View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 2013 - 2015, Roland Bock
* 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_TAB_SAMPLE_H
#define SQLPP_TAB_SAMPLE_H
#include <sqlpp11/table.h>
#include <sqlpp11/char_sequence.h>
#include <sqlpp11/column_types.h>
namespace TabFoo_
{
struct Omega
{
struct _alias_t
{
static constexpr const char _literal[] = "omega";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T omega;
T& operator()()
{
return omega;
}
const T& operator()() const
{
return omega;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::bigint>;
};
}
struct TabFoo : sqlpp::table_t<TabFoo, TabFoo_::Omega>
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
{
static constexpr const char _literal[] = "tab_foo";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabFoo;
T& operator()()
{
return tabFoo;
}
const T& operator()() const
{
return tabFoo;
}
};
};
};
namespace TabSample_
{
struct Alpha
{
struct _alias_t
{
static constexpr const char _literal[] = "alpha";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T alpha;
T& operator()()
{
return alpha;
}
const T& operator()() const
{
return alpha;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::bigint,
::sqlpp::tag::can_be_null>;
};
struct Beta
{
struct _alias_t
{
static constexpr const char _literal[] = "beta";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T beta;
T& operator()()
{
return beta;
}
const T& operator()() const
{
return beta;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::varchar, ::sqlpp::tag::can_be_null>;
};
struct Gamma
{
struct _alias_t
{
static constexpr const char _literal[] = "gamma";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T gamma;
T& operator()()
{
return gamma;
}
const T& operator()() const
{
return gamma;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::boolean>;
};
}
struct TabSample : sqlpp::table_t<TabSample, TabSample_::Alpha, TabSample_::Beta, TabSample_::Gamma>
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
{
static constexpr const char _literal[] = "tab_sample";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabSample;
T& operator()()
{
return tabSample;
}
const T& operator()() const
{
return tabSample;
}
};
};
};
namespace TabDateTime_
{
struct ColDayPoint
{
struct _alias_t
{
static constexpr const char _literal[] = "col_day_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T colDayPoint;
T& operator()()
{
return colDayPoint;
}
const T& operator()() const
{
return colDayPoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::day_point, sqlpp::tag::can_be_null>;
};
struct ColTimePoint
{
struct _alias_t
{
static constexpr const char _literal[] = "col_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T colTimePoint;
T& operator()()
{
return colTimePoint;
}
const T& operator()() const
{
return colTimePoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::time_point, sqlpp::tag::can_be_null>;
};
}
struct TabDateTime : sqlpp::table_t<TabDateTime, TabDateTime_::ColDayPoint, TabDateTime_::ColTimePoint>
{
struct _alias_t
{
static constexpr const char _literal[] = "tab_date_time";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabDateTime;
T& operator()()
{
return tabDateTime;
}
const T& operator()() const
{
return tabDateTime;
}
};
};
};
#endif

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2017, Volker Aßmann
* 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 <iostream>
#include <memory>
#include <stdexcept>
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/custom_query.h>
#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/transaction.h>
#include "make_test_connection.h"
namespace
{
std::ostream& operator<<(std::ostream& stream, const sqlpp::isolation_level& level)
{
switch (level)
{
case sqlpp::isolation_level::serializable:
{
stream << "SERIALIZABLE";
break;
}
case sqlpp::isolation_level::repeatable_read:
{
stream << "REPEATABLE READ";
break;
}
case sqlpp::isolation_level::read_committed:
{
stream << "READ COMMITTED";
break;
}
case sqlpp::isolation_level::read_uncommitted:
{
stream << "READ UNCOMMITTED";
break;
}
case sqlpp::isolation_level::undefined:
{
stream << "BEGIN";
break;
}
}
return stream;
}
template <typename L, typename R>
void require_equal(int line, const L& l, const R& r)
{
if (l != r)
{
std::cerr << line << ": " << l << " != " << r << std::endl;
throw std::runtime_error("Unexpected result");
}
}
}
namespace sql = sqlpp::postgresql;
SQLPP_ALIAS_PROVIDER(level);
int Transaction(int, char*[])
{
sql::connection db = sql::make_test_connection();
try
{
{
auto current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
.with_result_type_of(select(sqlpp::value("").as(level))))
.front()
.level;
require_equal(__LINE__, current_level, "read committed");
std::cerr << "isolation level outside transaction: " << current_level << "\n";
auto tx = start_transaction(db, sqlpp::isolation_level::serializable);
current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
.with_result_type_of(select(sqlpp::value("").as(level))))
.front()
.level;
require_equal(__LINE__, current_level, "serializable");
std::cerr << "isolation level in transaction(serializable) : " << current_level << "\n";
tx.commit();
}
require_equal(__LINE__, db.get_default_isolation_level(), sqlpp::isolation_level::read_committed);
db.set_default_isolation_level(sqlpp::isolation_level::serializable);
require_equal(__LINE__, db.get_default_isolation_level(), sqlpp::isolation_level::serializable);
}
catch (const sqlpp::exception& ex)
{
std::cerr << "Got exception: " << ex.what() << std::endl;
return 1;
}
catch (...)
{
std::cerr << "Got unknown exception" << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,130 @@
/**
* Copyright © 2017 Volker Aßmann
* 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 <iostream>
#include <sqlpp11/custom_query.h>
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "TabSample.h"
#include "make_test_connection.h"
namespace
{
template <typename L, typename R>
void require_equal(int line, const L& l, const R& r)
{
if (l != r)
{
std::cerr << line << ": --" << l << " != " << r << "--" << std::endl;
throw std::runtime_error("Unexpected result");
}
}
template <class Db>
void prepare_table(Db&& db)
{
// prepare test with timezone
db.execute("DROP TABLE IF EXISTS tab_sample");
db.execute("CREATE TABLE tab_sample (alpha bigint, beta text, gamma bool)");
}
}
namespace sql = sqlpp::postgresql;
int Type(int, char*[])
{
sql::connection db = sql::make_test_connection();
try
{
prepare_table(db);
const auto tab = TabSample{};
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.is_null(), true);
require_equal(__LINE__, row.alpha.value(), 0);
require_equal(__LINE__, row.beta.is_null(), true);
require_equal(__LINE__, row.beta.value(), "");
require_equal(__LINE__, row.gamma.is_null(), true);
require_equal(__LINE__, row.gamma.value(), false);
}
db(update(tab).set(tab.alpha = 10, tab.beta = "Cookies!", tab.gamma = true).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.is_null(), false);
require_equal(__LINE__, row.alpha.value(), 10);
require_equal(__LINE__, row.beta.is_null(), false);
require_equal(__LINE__, row.beta.value(), "Cookies!");
require_equal(__LINE__, row.gamma.is_null(), false);
require_equal(__LINE__, row.gamma.value(), true);
}
db(update(tab).set(tab.alpha = 20, tab.beta = "Monster", tab.gamma = false).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.value(), 20);
require_equal(__LINE__, row.beta.value(), "Monster");
require_equal(__LINE__, row.gamma.value(), false);
}
auto prepared_update = db.prepare(
update(tab)
.set(tab.alpha = parameter(tab.alpha), tab.beta = parameter(tab.beta), tab.gamma = parameter(tab.gamma))
.unconditionally());
prepared_update.params.alpha = 30;
prepared_update.params.beta = "IceCream";
prepared_update.params.gamma = true;
std::cout << "---- running prepared update ----" << std::endl;
db(prepared_update);
std::cout << "---- finished prepared update ----" << std::endl;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.value(), 30);
require_equal(__LINE__, row.beta.value(), "IceCream");
require_equal(__LINE__, row.gamma.value(), true);
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
catch (...)
{
std::cerr << "Unknown exception" << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,18 @@
#ifndef ASSERT_THROW_H
#define ASSERT_THROW_H
#define assert_throw(code, exception) \
{ \
bool exceptionThrown = false; \
try \
{ \
code; \
} \
catch (const exception&) \
{ \
exceptionThrown = true; \
} \
assert(exceptionThrown); \
}
#endif

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2021, Roland Bock
* 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 SQLPP11_TEST_POSTGRESQL_USAGE_CONNECT_H
#define SQLPP11_TEST_POSTGRESQL_USAGE_CONNECT_H
#include <sqlpp11/postgresql/postgresql.h>
namespace sqlpp
{
namespace postgresql
{
// Starts a connection and sets the time zone to UTC
inline ::sqlpp::postgresql::connection make_test_connection()
{
namespace sql = sqlpp::postgresql;
auto config = std::make_shared<sql::connection_config>();
#ifdef WIN32
config->dbname = "test";
config->user = "test";
config->debug = true;
#else
config->user = getenv("USER");
config->dbname = "sqlpp_postgresql";
config->debug = true;
#endif
sql::connection db;
try
{
db.connectUsing(config);
}
catch (const sqlpp::exception&)
{
std::cerr << "For testing, you'll need to create a database called '" << config->dbname
<< "', accessible by user '" << config->user << "' without a password." << std::endl;
throw;
}
db.execute(R"(SET TIME ZONE 'UTC';)");
return db;
}
} // namespace postgresql
} // namespace sqlpp
#endif