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:
parent
13698d07c9
commit
4c942600bb
@ -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)
|
||||
|
58
include/sqlpp11/detail/column_tuple_merge.h
Normal file
58
include/sqlpp11/detail/column_tuple_merge.h
Normal 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
|
397
include/sqlpp11/postgresql/bind_result.h
Normal file
397
include/sqlpp11/postgresql/bind_result.h
Normal 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
|
692
include/sqlpp11/postgresql/connection.h
Normal file
692
include/sqlpp11/postgresql/connection.h
Normal 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
|
100
include/sqlpp11/postgresql/connection_config.h
Normal file
100
include/sqlpp11/postgresql/connection_config.h
Normal 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
|
239
include/sqlpp11/postgresql/detail/connection_handle.h
Normal file
239
include/sqlpp11/postgresql/detail/connection_handle.h
Normal 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
|
198
include/sqlpp11/postgresql/detail/prepared_statement_handle.h
Normal file
198
include/sqlpp11/postgresql/detail/prepared_statement_handle.h
Normal 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
|
154
include/sqlpp11/postgresql/dynamic_libpq.h
Normal file
154
include/sqlpp11/postgresql/dynamic_libpq.h
Normal 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
|
||||
|
417
include/sqlpp11/postgresql/exception.h
Normal file
417
include/sqlpp11/postgresql/exception.h
Normal 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
|
69
include/sqlpp11/postgresql/insert.h
Normal file
69
include/sqlpp11/postgresql/insert.h
Normal 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
|
264
include/sqlpp11/postgresql/on_conflict.h
Normal file
264
include/sqlpp11/postgresql/on_conflict.h
Normal 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
|
127
include/sqlpp11/postgresql/on_conflict_do_nothing.h
Normal file
127
include/sqlpp11/postgresql/on_conflict_do_nothing.h
Normal 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
|
232
include/sqlpp11/postgresql/on_conflict_do_update.h
Normal file
232
include/sqlpp11/postgresql/on_conflict_do_update.h
Normal 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
|
36
include/sqlpp11/postgresql/postgresql.h
Normal file
36
include/sqlpp11/postgresql/postgresql.h
Normal 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
|
216
include/sqlpp11/postgresql/prepared_statement.h
Normal file
216
include/sqlpp11/postgresql/prepared_statement.h
Normal 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
|
346
include/sqlpp11/postgresql/result.h
Normal file
346
include/sqlpp11/postgresql/result.h
Normal 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
|
176
include/sqlpp11/postgresql/returning.h
Normal file
176
include/sqlpp11/postgresql/returning.h
Normal 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
|
496
include/sqlpp11/postgresql/returning_column_list.h
Normal file
496
include/sqlpp11/postgresql/returning_column_list.h
Normal 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
|
46
include/sqlpp11/postgresql/serializer.h
Normal file
46
include/sqlpp11/postgresql/serializer.h
Normal 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
|
57
include/sqlpp11/postgresql/update.h
Normal file
57
include/sqlpp11/postgresql/update.h
Normal 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
|
60
include/sqlpp11/postgresql/visibility.h
Normal file
60
include/sqlpp11/postgresql/visibility.h
Normal 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
|
@ -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
|
||||
|
28
tests/postgresql/CMakeLists.txt
Normal file
28
tests/postgresql/CMakeLists.txt
Normal 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)
|
||||
|
||||
|
53
tests/postgresql/constraints/CMakeLists.txt
Normal file
53
tests/postgresql/constraints/CMakeLists.txt
Normal 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")
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
44
tests/postgresql/constraints/OnConflictInvalidParameter.cpp
Normal file
44
tests/postgresql/constraints/OnConflictInvalidParameter.cpp
Normal 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();
|
||||
}
|
@ -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);
|
||||
}
|
46
tests/postgresql/constraints/OnConflictMissingAction.cpp
Normal file
46
tests/postgresql/constraints/OnConflictMissingAction.cpp
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
57
tests/postgresql/constraints/ReturningEmptyAssert.cpp
Normal file
57
tests/postgresql/constraints/ReturningEmptyAssert.cpp
Normal 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;
|
||||
}
|
48
tests/postgresql/constraints/ReturningInvalidArgument.cpp
Normal file
48
tests/postgresql/constraints/ReturningInvalidArgument.cpp
Normal 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;
|
||||
}
|
53
tests/postgresql/usage/Basic.cpp
Normal file
53
tests/postgresql/usage/Basic.cpp
Normal 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;
|
||||
}
|
64
tests/postgresql/usage/CMakeLists.txt
Normal file
64
tests/postgresql/usage/CMakeLists.txt
Normal 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()
|
||||
|
35
tests/postgresql/usage/Constructor.cpp
Normal file
35
tests/postgresql/usage/Constructor.cpp
Normal 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;
|
||||
}
|
146
tests/postgresql/usage/Date.cpp
Normal file
146
tests/postgresql/usage/Date.cpp
Normal 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;
|
||||
}
|
124
tests/postgresql/usage/DateTime.cpp
Normal file
124
tests/postgresql/usage/DateTime.cpp
Normal 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;
|
||||
}
|
74
tests/postgresql/usage/Exceptions.cpp
Normal file
74
tests/postgresql/usage/Exceptions.cpp
Normal 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;
|
||||
}
|
89
tests/postgresql/usage/InsertOnConflict.cpp
Normal file
89
tests/postgresql/usage/InsertOnConflict.cpp
Normal 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;
|
||||
}
|
64
tests/postgresql/usage/Returning.cpp
Normal file
64
tests/postgresql/usage/Returning.cpp
Normal 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;
|
||||
}
|
144
tests/postgresql/usage/Select.cpp
Normal file
144
tests/postgresql/usage/Select.cpp
Normal 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;
|
||||
}
|
61
tests/postgresql/usage/TabBar.h
Normal file
61
tests/postgresql/usage/TabBar.h
Normal 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
|
187
tests/postgresql/usage/TabFoo.h
Normal file
187
tests/postgresql/usage/TabFoo.h
Normal 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
|
248
tests/postgresql/usage/TabSample.h
Normal file
248
tests/postgresql/usage/TabSample.h
Normal 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
|
130
tests/postgresql/usage/Transaction.cpp
Normal file
130
tests/postgresql/usage/Transaction.cpp
Normal 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;
|
||||
}
|
130
tests/postgresql/usage/Type.cpp
Normal file
130
tests/postgresql/usage/Type.cpp
Normal 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;
|
||||
}
|
18
tests/postgresql/usage/assertThrow.h
Normal file
18
tests/postgresql/usage/assertThrow.h
Normal 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
|
72
tests/postgresql/usage/make_test_connection.h
Normal file
72
tests/postgresql/usage/make_test_connection.h
Normal 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
|
Loading…
Reference in New Issue
Block a user