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

Moved mysql/mariadb connector over here.

This commit is contained in:
Roland Bock 2021-08-01 21:49:16 +02:00
parent 2e683a4b69
commit 5e16f32ed3
41 changed files with 4640 additions and 4 deletions

View File

@ -27,6 +27,10 @@
cmake_minimum_required(VERSION 3.14)
project(sqlpp11 VERSION 0.1 LANGUAGES CXX)
### Project Wide Setup
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
option(MARIADB_CONNECTOR "Build MariaDB Connector" OFF)
option(MYSQL_CONNECTOR "Build MySQL Connector" OFF)
option(POSTGRESQL_CONNECTOR "Build PostgreSQL Connector" OFF)
option(SQLITE3_CONNECTOR "Build SQLite3 Connector" OFF)
@ -38,6 +42,12 @@ else()
message(STATUS "Not building MYSQL_CONNECTOR")
endif()
if(MARIADB_CONNECTOR)
find_package(MariaDB REQUIRED)
else()
message(STATUS "Not building MARIAB_CONNECTOR")
endif()
if(POSTGRESQL_CONNECTOR)
find_package(PostgreSQL REQUIRED)
else()
@ -56,9 +66,6 @@ else()
message(STATUS "Not building SQLCIPHER_CONNECTOR")
endif()
### Project Wide Setup
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(CTest)
option(USE_SYSTEM_DATE "\
@ -70,7 +77,7 @@ if(USE_SYSTEM_DATE)
find_package(date REQUIRED)
endif()
### Dependencies
### Dependencies
add_subdirectory(dependencies)
### Core targets

35
cmake/FindMariaDB.cmake Normal file
View File

@ -0,0 +1,35 @@
# FindMySQL.cmake
if(DEFINED MSVC)
find_path(MySQL_INCLUDE_DIR
NAMES mariadb_version.h
PATH_SUFFIXES include
)
find_library(MySQL_LIBRARY
NAMES libmariadb
PATH_SUFFIXES lib
)
else()
find_path(MySQL_INCLUDE_DIR
NAMES mariadb_version.h
PATH_SUFFIXES mariadb mysql
)
find_library(MySQL_LIBRARY NAMES mariadb)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
MySQL
MySQL_INCLUDE_DIR
MySQL_LIBRARY
)
if(MySQL_FOUND AND NOT TARGET MySQL::MySQL)
add_library(MySQL::MySQL UNKNOWN IMPORTED)
target_include_directories(MySQL::MySQL INTERFACE "${MySQL_INCLUDE_DIR}")
set_target_properties(MySQL::MySQL PROPERTIES
IMPORTED_LOCATION "${MySQL_LIBRARY}"
IMPORTED_LINK_INTERFACE_LANGUAGES "C")
endif()
mark_as_advanced(MySQL_INCLUDE_DIR MySQL_LIBRARY)

45
cmake/FindMySQL.cmake Normal file
View File

@ -0,0 +1,45 @@
# FindMySQL.cmake
if(DEFINED MSVC)
set(SEARCH_PATHS
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.6"
"$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 8.0"
"$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 5.7"
"$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 5.6"
)
find_path(MySQL_INCLUDE_DIR
NAMES mysql_version.h
PATHS ${SEARCH_PATHS}
PATH_SUFFIXES include
)
find_library(MySQL_LIBRARY
NAMES libmysql
PATHS ${SEARCH_PATHS}
PATH_SUFFIXES lib
)
else()
find_path(MySQL_INCLUDE_DIR
NAMES mysql_version.h
PATH_SUFFIXES mysql
)
find_library(MySQL_LIBRARY NAMES mysqlclient mysqlclient_r)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
MySQL
MySQL_INCLUDE_DIR
MySQL_LIBRARY
)
if(MySQL_FOUND AND NOT TARGET MySQL::MySQL)
add_library(MySQL::MySQL UNKNOWN IMPORTED)
target_include_directories(MySQL::MySQL INTERFACE "${MySQL_INCLUDE_DIR}")
set_target_properties(MySQL::MySQL PROPERTIES
IMPORTED_LOCATION "${MySQL_LIBRARY}"
IMPORTED_LINK_INTERFACE_LANGUAGES "C")
endif()
mark_as_advanced(MySQL_INCLUDE_DIR MySQL_LIBRARY)

Binary file not shown.

View File

@ -0,0 +1,126 @@
/*
* 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_MYSQL_BIND_RESULT_H
#define SQLPP_MYSQL_BIND_RESULT_H
#include <memory>
#include <sqlpp11/chrono.h>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct prepared_statement_handle_t;
}
class bind_result_t
{
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
void* _result_row_address = nullptr;
public:
bind_result_t() = default;
bind_result_t(const std::shared_ptr<detail::prepared_statement_handle_t>& handle);
bind_result_t(const bind_result_t&) = delete;
bind_result_t(bind_result_t&& rhs) = default;
bind_result_t& operator=(const bind_result_t&) = delete;
bind_result_t& operator=(bind_result_t&&) = default;
~bind_result_t();
bool operator==(const bind_result_t& rhs) const
{
return _handle == rhs._handle;
}
template <typename ResultRow>
void next(ResultRow& result_row)
{
if (_invalid())
{
result_row._invalidate();
return;
}
if (&result_row != _result_row_address)
{
result_row._bind(*this); // sets row data to mysql bind data
bind_impl(); // binds mysql statement to data
_result_row_address = &result_row;
}
if (next_impl())
{
if (not result_row)
{
result_row._validate();
}
result_row._post_bind(*this); // translates bind_data to row data where required
}
else
{
if (result_row)
result_row._invalidate();
}
}
bool _invalid() const;
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_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null);
void _bind_text_result(size_t index, const char** text, size_t* len);
void _bind_blob_result(size_t index, const char** text, 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);
void _post_bind_boolean_result(size_t /* index */, signed char* /* value */, bool* /* is_null */)
{
}
void _post_bind_floating_point_result(size_t /* index */, double* /* value */, bool* /* is_null */)
{
}
void _post_bind_integral_result(size_t /* index */, int64_t* /* value */, bool* /* is_null */)
{
}
void _post_bind_unsigned_integral_result(size_t /* index */, uint64_t* /* value */, bool* /* is_null */)
{
}
void _post_bind_text_result(size_t /* index */, const char** /* text */, size_t* /* len */)
{
}
void _post_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null);
void _post_bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null);
private:
void bind_impl();
bool next_impl();
};
}
}
#endif

View File

@ -0,0 +1,138 @@
/*
* 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_MYSQL_CHAR_RESULT_H
#define SQLPP_MYSQL_CHAR_RESULT_H
#include <ciso646>
#include <cstdlib>
#include <memory>
#include <sqlpp11/chrono.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/char_result_row.h>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_handle;
}
class char_result_t
{
std::unique_ptr<detail::result_handle> _handle;
char_result_row_t _char_result_row;
public:
char_result_t();
char_result_t(std::unique_ptr<detail::result_handle>&& handle);
char_result_t(const char_result_t&) = delete;
char_result_t(char_result_t&& rhs);
char_result_t& operator=(const char_result_t&) = delete;
char_result_t& operator=(char_result_t&&);
~char_result_t();
bool operator==(const char_result_t& rhs) const
{
return _handle == rhs._handle;
}
template <typename ResultRow>
void next(ResultRow& result_row)
{
if (_invalid())
{
result_row._invalidate();
return;
}
if (next_impl())
{
if (not result_row)
{
result_row._validate();
}
result_row._bind(*this);
}
else
{
if (result_row)
result_row._invalidate();
}
}
bool _invalid() const;
void _bind_boolean_result(size_t index, signed char* value, bool* is_null)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value =
(*is_null ? false : (_char_result_row.data[index][0] == 't' or _char_result_row.data[index][0] == '1'));
}
void _bind_floating_point_result(size_t index, double* value, bool* is_null)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtod(_char_result_row.data[index], nullptr));
}
void _bind_integral_result(size_t index, int64_t* value, bool* is_null)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtoll(_char_result_row.data[index], nullptr, 10));
}
void _bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtoull(_char_result_row.data[index], nullptr, 10));
}
void _bind_blob_result(size_t index, const uint8_t** value, size_t* len)
{
bool is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (uint8_t*)(is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _char_result_row.len[index]);
}
void _bind_text_result(size_t index, const char** value, size_t* len)
{
bool is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _char_result_row.len[index]);
}
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);
private:
bool next_impl();
};
}
}
#endif

View File

@ -0,0 +1,47 @@
/*
* 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_MYSQL_CHAR_RESULT_ROW_H
#define SQLPP_MYSQL_CHAR_RESULT_ROW_H
namespace sqlpp
{
namespace mysql
{
struct char_result_row_t
{
const char** data;
unsigned long* len;
bool operator==(const char_result_row_t& rhs) const
{
return data == rhs.data && len == rhs.len;
}
};
}
}
#endif

View File

@ -0,0 +1,316 @@
/*
* Copyright (c) 2013 - 2017, 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_MYSQL_CONNECTION_H
#define SQLPP_MYSQL_CONNECTION_H
#include <sqlpp11/connection.h>
#include <sqlpp11/mysql/bind_result.h>
#include <sqlpp11/mysql/char_result.h>
#include <sqlpp11/mysql/connection_config.h>
#include <sqlpp11/mysql/prepared_statement.h>
#include <sqlpp11/serialize.h>
#include <sstream>
#include <string>
#if LIBMYSQL_VERSION_ID < 80000
typedef struct st_mysql MYSQL;
#else
struct MYSQL;
#endif
namespace sqlpp
{
namespace mysql
{
struct scoped_library_initializer_t
{
// calls mysql_library_init
scoped_library_initializer_t(int argc = 0, char** argv = nullptr, char** groups = nullptr);
// calls mysql_library_end
~scoped_library_initializer_t();
};
// This will also cleanup when the program shuts down
void global_library_init(int argc = 0, char** argv = nullptr, char** groups = nullptr);
namespace detail
{
struct connection_handle_t;
}
class connection;
struct serializer_t
{
serializer_t(const connection& db) : _db(db)
{
}
template <typename T>
std::ostream& operator<<(T t)
{
return _os << t;
}
std::string escape(std::string arg);
std::string str() const
{
return _os.str();
}
const connection& _db;
std::stringstream _os;
};
std::integral_constant<char, '`'> get_quote_left(const serializer_t&);
std::integral_constant<char, '`'> get_quote_right(const serializer_t&);
class connection : public sqlpp::connection
{
std::unique_ptr<detail::connection_handle_t> _handle;
bool _transaction_active = false;
// direct execution
char_result_t select_impl(const std::string& statement);
size_t insert_impl(const std::string& statement);
size_t update_impl(const std::string& statement);
size_t remove_impl(const std::string& statement);
// prepared execution
prepared_statement_t prepare_impl(const std::string& statement, size_t no_of_parameters, size_t no_of_columns);
bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_update_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement);
public:
using _prepared_statement_t = ::sqlpp::mysql::prepared_statement_t;
using _context_t = serializer_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 serialize(t, context);
}
template <typename T>
static _context_t& _interpret_interpretable(const T& t, _context_t& context)
{
return serialize(t, context);
}
connection(const std::shared_ptr<connection_config>& config);
~connection();
connection(const connection&) = delete;
connection& operator=(const connection&) = delete;
connection& operator=(connection&&) = default;
connection(connection&& other);
bool is_valid();
void reconnect();
const std::shared_ptr<connection_config> get_config();
bool is_transaction_active()
{
return _transaction_active;
}
template <typename Select>
char_result_t select(const Select& s)
{
_context_t context(*this);
serialize(s, context);
return select_impl(context.str());
}
template <typename Select>
_prepared_statement_t prepare_select(Select& s)
{
_context_t context(*this);
serialize(s, context);
return prepare_impl(context.str(), s._get_no_of_parameters(), s.get_no_of_result_columns());
}
template <typename PreparedSelect>
bind_result_t run_prepared_select(const PreparedSelect& s)
{
s._bind_params();
return run_prepared_select_impl(s._prepared_statement);
}
//! insert returns the last auto_incremented id (or zero, if there is none)
template <typename Insert>
size_t insert(const Insert& i)
{
_context_t context(*this);
serialize(i, context);
return insert_impl(context.str());
}
template <typename Insert>
_prepared_statement_t prepare_insert(Insert& i)
{
_context_t context(*this);
serialize(i, context);
return prepare_impl(context.str(), i._get_no_of_parameters(), 0);
}
template <typename PreparedInsert>
size_t run_prepared_insert(const PreparedInsert& i)
{
i._bind_params();
return run_prepared_insert_impl(i._prepared_statement);
}
//! update returns the number of affected rows
template <typename Update>
size_t update(const Update& u)
{
_context_t context(*this);
serialize(u, context);
return update_impl(context.str());
}
template <typename Update>
_prepared_statement_t prepare_update(Update& u)
{
_context_t context(*this);
serialize(u, context);
return prepare_impl(context.str(), u._get_no_of_parameters(), 0);
}
template <typename PreparedUpdate>
size_t run_prepared_update(const PreparedUpdate& u)
{
u._bind_params();
return run_prepared_update_impl(u._prepared_statement);
}
//! remove returns the number of removed rows
template <typename Remove>
size_t remove(const Remove& r)
{
_context_t context(*this);
serialize(r, context);
return remove_impl(context.str());
}
template <typename Remove>
_prepared_statement_t prepare_remove(Remove& r)
{
_context_t context(*this);
serialize(r, context);
return prepare_impl(context.str(), r._get_no_of_parameters(), 0);
}
template <typename PreparedRemove>
size_t run_prepared_remove(const PreparedRemove& r)
{
r._bind_params();
return run_prepared_remove_impl(r._prepared_statement);
}
//! execute arbitrary command (e.g. create a table)
void execute(const std::string& command);
//! escape given string (does not quote, though)
std::string escape(const std::string& s) const;
//! call run on the argument
template <typename T>
auto run(const T& t) -> decltype(t._run(*this))
{
return t._run(*this);
}
//! 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>{});
}
//! start transaction
void start_transaction();
//! commit transaction (or throw if the transaction has been finished already)
void commit_transaction();
//! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished
// already)
void rollback_transaction(bool report);
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
void report_rollback_failure(const std::string message) noexcept;
MYSQL* get_handle();
};
inline std::string serializer_t::escape(std::string arg)
{
return _db.escape(arg);
}
}
}
#include <sqlpp11/mysql/serializer.h>
#endif

View File

@ -0,0 +1,320 @@
/*
* Copyright (c) 2013 - 2017, 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_MYSQL_CONNECTION_H
#define SQLPP_MYSQL_CONNECTION_H
#include <sqlpp11/connection.h>
#include <sqlpp11/mysql/bind_result.h>
#include <sqlpp11/mysql/char_result.h>
#include <sqlpp11/mysql/connection_config.h>
#include <sqlpp11/mysql/prepared_statement.h>
#include <sqlpp11/serialize.h>
#include <sstream>
#include <string>
<<<<<<< Updated upstream
#if LIBMYSQL_VERSION_ID < 80000
typedef struct st_mysql MYSQL;
#else
struct MYSQL;
#endif
=======
struct MYSQL;
>>>>>>> Stashed changes
namespace sqlpp
{
namespace mysql
{
struct scoped_library_initializer_t
{
// calls mysql_library_init
scoped_library_initializer_t(int argc = 0, char** argv = nullptr, char** groups = nullptr);
// calls mysql_library_end
~scoped_library_initializer_t();
};
// This will also cleanup when the program shuts down
void global_library_init(int argc = 0, char** argv = nullptr, char** groups = nullptr);
namespace detail
{
struct connection_handle_t;
}
class connection;
struct serializer_t
{
serializer_t(const connection& db) : _db(db)
{
}
template <typename T>
std::ostream& operator<<(T t)
{
return _os << t;
}
std::string escape(std::string arg);
std::string str() const
{
return _os.str();
}
const connection& _db;
std::stringstream _os;
};
std::integral_constant<char, '`'> get_quote_left(const serializer_t&);
std::integral_constant<char, '`'> get_quote_right(const serializer_t&);
class connection : public sqlpp::connection
{
std::unique_ptr<detail::connection_handle_t> _handle;
bool _transaction_active = false;
// direct execution
char_result_t select_impl(const std::string& statement);
size_t insert_impl(const std::string& statement);
size_t update_impl(const std::string& statement);
size_t remove_impl(const std::string& statement);
// prepared execution
prepared_statement_t prepare_impl(const std::string& statement, size_t no_of_parameters, size_t no_of_columns);
bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_update_impl(prepared_statement_t& prepared_statement);
size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement);
public:
using _prepared_statement_t = ::sqlpp::mysql::prepared_statement_t;
using _context_t = serializer_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);
}
connection(const std::shared_ptr<connection_config>& config);
~connection();
connection(const connection&) = delete;
connection& operator=(const connection&) = delete;
connection& operator=(connection&&) = default;
connection(connection&& other);
bool is_valid();
void reconnect();
const std::shared_ptr<connection_config> get_config();
bool is_transaction_active()
{
return _transaction_active;
}
template <typename Select>
char_result_t select(const Select& s)
{
_context_t context(*this);
serialize(s, context);
return select_impl(context.str());
}
template <typename Select>
_prepared_statement_t prepare_select(Select& s)
{
_context_t context(*this);
serialize(s, context);
return prepare_impl(context.str(), s._get_no_of_parameters(), s.get_no_of_result_columns());
}
template <typename PreparedSelect>
bind_result_t run_prepared_select(const PreparedSelect& s)
{
s._bind_params();
return run_prepared_select_impl(s._prepared_statement);
}
//! insert returns the last auto_incremented id (or zero, if there is none)
template <typename Insert>
size_t insert(const Insert& i)
{
_context_t context(*this);
serialize(i, context);
return insert_impl(context.str());
}
template <typename Insert>
_prepared_statement_t prepare_insert(Insert& i)
{
_context_t context(*this);
serialize(i, context);
return prepare_impl(context.str(), i._get_no_of_parameters(), 0);
}
template <typename PreparedInsert>
size_t run_prepared_insert(const PreparedInsert& i)
{
i._bind_params();
return run_prepared_insert_impl(i._prepared_statement);
}
//! update returns the number of affected rows
template <typename Update>
size_t update(const Update& u)
{
_context_t context(*this);
serialize(u, context);
return update_impl(context.str());
}
template <typename Update>
_prepared_statement_t prepare_update(Update& u)
{
_context_t context(*this);
serialize(u, context);
return prepare_impl(context.str(), u._get_no_of_parameters(), 0);
}
template <typename PreparedUpdate>
size_t run_prepared_update(const PreparedUpdate& u)
{
u._bind_params();
return run_prepared_update_impl(u._prepared_statement);
}
//! remove returns the number of removed rows
template <typename Remove>
size_t remove(const Remove& r)
{
_context_t context(*this);
serialize(r, context);
return remove_impl(context.str());
}
template <typename Remove>
_prepared_statement_t prepare_remove(Remove& r)
{
_context_t context(*this);
serialize(r, context);
return prepare_impl(context.str(), r._get_no_of_parameters(), 0);
}
template <typename PreparedRemove>
size_t run_prepared_remove(const PreparedRemove& r)
{
r._bind_params();
return run_prepared_remove_impl(r._prepared_statement);
}
//! execute arbitrary command (e.g. create a table)
void execute(const std::string& command);
//! escape given string (does not quote, though)
std::string escape(const std::string& s) const;
//! call run on the argument
template <typename T>
auto run(const T& t) -> decltype(t._run(*this))
{
return t._run(*this);
}
//! 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>{});
}
//! start transaction
void start_transaction();
//! commit transaction (or throw if the transaction has been finished already)
void commit_transaction();
//! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished
// already)
void rollback_transaction(bool report);
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
void report_rollback_failure(const std::string message) noexcept;
MYSQL* get_handle();
};
inline std::string serializer_t::escape(std::string arg)
{
return _db.escape(arg);
}
}
}
#include <sqlpp11/mysql/serializer.h>
#endif

View File

@ -0,0 +1,66 @@
/*
* 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_MYSQL_CONNECTION_CONFIG_H
#define SQLPP_MYSQL_CONNECTION_CONFIG_H
#include <string>
namespace sqlpp
{
namespace mysql
{
class connection;
struct connection_config
{
typedef ::sqlpp::mysql::connection connection;
std::string host = "localhost";
std::string user;
std::string password;
std::string database;
unsigned int port = 0;
std::string unix_socket;
unsigned long client_flag = 0;
std::string charset = "utf8";
bool auto_reconnect = true;
bool debug = false;
bool operator==(const connection_config& other) const
{
return (other.host == host and other.user == user and other.password == password and
other.database == database and other.charset == charset and other.auto_reconnect == auto_reconnect and
other.debug == debug);
}
bool operator!=(const connection_config& other) const
{
return !operator==(other);
}
};
}
}
#endif

View File

@ -0,0 +1,33 @@
/*
* 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_MYSQL_H
#define SQLPP_MYSQL_H
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/mysql/char_result.h>
#endif

View File

@ -0,0 +1,76 @@
/*
* 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_MYSQL_PREPARED_STATEMENT_H
#define SQLPP_MYSQL_PREPARED_STATEMENT_H
#include <memory>
#include <string>
#include <sqlpp11/chrono.h>
namespace sqlpp
{
namespace mysql
{
class connection;
namespace detail
{
struct prepared_statement_handle_t;
}
class prepared_statement_t
{
friend ::sqlpp::mysql::connection;
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
public:
prepared_statement_t() = delete;
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&& rhs) = 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) const
{
return _handle == rhs._handle;
}
void _pre_bind();
void _bind_boolean_parameter(size_t index, const signed char* value, bool is_null);
void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null);
void _bind_unsigned_integral_parameter(size_t index, const uint64_t* value, bool is_null);
void _bind_floating_point_parameter(size_t index, const double* 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);
};
}
}
#endif

View File

@ -0,0 +1,51 @@
/*
* 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_MYSQL_SERIALIZER_H
#define SQLPP_MYSQL_SERIALIZER_H
#include <sqlpp11/data_types/text/concat.h>
#include <sqlpp11/insert_value_list.h>
namespace sqlpp
{
template <typename First, typename... Args>
mysql::serializer_t& serialize(const concat_t<First, Args...>& t, mysql::serializer_t& context)
{
context << "CONCAT(";
interpret_tuple(t._args, ',', context);
context << ')';
return context;
}
inline mysql::serializer_t& serialize(const insert_default_values_data_t&, mysql::serializer_t& context)
{
context << " () VALUES()";
return context;
}
}
#endif

78
src/mysql/CMakeLists.txt Normal file
View File

@ -0,0 +1,78 @@
set(PUBLIC_HEADERS_DIR "${PROJECT_SOURCE_DIR}/include/")
add_library(sqlpp-mysql
bind_result.cpp
char_result.cpp
connection.cpp
prepared_statement.cpp
detail/connection_handle.cpp
)
target_include_directories(sqlpp-mysql PUBLIC
$<BUILD_INTERFACE:${PUBLIC_HEADERS_DIR}>
)
find_package(date REQUIRED)
find_package(Sqlpp11 REQUIRED)
target_link_libraries(sqlpp-mysql PUBLIC sqlpp11::sqlpp11)
target_link_libraries(sqlpp-mysql PRIVATE MySQL::MySQL)
target_link_libraries(sqlpp-mysql PRIVATE date::date)
# Installation
include(GNUInstallDirs)
add_library(sqlpp11::mysql ALIAS sqlpp-mysql)
set_target_properties(sqlpp-mysql PROPERTIES EXPORT_NAME sqlpp11::mysql)
install(
TARGETS sqlpp-mysql
EXPORT sqlpp-mysql-targets
COMPONENT sqlpp11::mysql
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
install(
DIRECTORY ${PUBLIC_HEADERS_DIR}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT sqlpp11::mysql
)
include(CMakePackageConfigHelpers)
set(cmake_config_path "${CMAKE_INSTALL_LIBDIR}/cmake/sqlpp-mysql")
configure_package_config_file(
sqlpp-mysql-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/sqlpp-mysql-config.cmake"
INSTALL_DESTINATION "${cmake_config_path}"
)
write_basic_package_version_file(
sqlpp-mysql-config-version.cmake
VERSION ${VERSION}
COMPATIBILITY SameMajorVersion
${extra_version_file_args}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/sqlpp-mysql-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/sqlpp-mysql-config-version.cmake"
DESTINATION "${cmake_config_path}"
COMPONENT sqlpp11::mysql
)
install(FILES
"${PROJECT_SOURCE_DIR}/cmake/FindMySQL.cmake"
DESTINATION "${cmake_config_path}"
COMPONENT sqlpp11::mysql
)
install(
EXPORT sqlpp-mysql-targets
FILE sqlpp-mysql-targets.cmake
DESTINATION "${cmake_config_path}"
COMPONENT sqlpp11::mysql
)

346
src/mysql/bind_result.cpp Normal file
View File

@ -0,0 +1,346 @@
/*
* 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.
*/
#include "detail/prepared_statement_handle.h"
#include <ciso646>
#include <date/date.h>
#include <iostream>
#include "sqlpp_mysql.h"
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/bind_result.h>
namespace sqlpp
{
namespace mysql
{
bind_result_t::bind_result_t(const std::shared_ptr<detail::prepared_statement_handle_t>& handle) : _handle(handle)
{
if (_handle and _handle->debug)
std::cerr << "MySQL debug: Constructing bind result, using handle at " << _handle.get() << std::endl;
}
bind_result_t::~bind_result_t()
{
if (_handle)
mysql_stmt_free_result(_handle->mysql_stmt);
}
bool bind_result_t::_invalid() const
{
return !_handle or !*_handle;
}
void bind_result_t::_bind_boolean_result(size_t index, signed char* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding boolean result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_TINY;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_integral_result(size_t index, int64_t* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding integral result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding unsigned integral result " << static_cast<void*>(value)
<< " at index: " << index << std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = true;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_floating_point_result(size_t index, double* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding floating point result " << static_cast<void*>(value)
<< " at index: " << index << std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_DOUBLE;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_text_result(size_t index, const char** value, size_t* len)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding text result " << static_cast<const void*>(*value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = len;
meta_data.is_null = nullptr;
meta_data.text_buffer = value;
if (meta_data.bound_text_buffer.empty())
meta_data.bound_text_buffer.resize(8);
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_STRING;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_blob_result(size_t index, const char** value, size_t* len)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding text result " << static_cast<const void*>(*value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = len;
meta_data.is_null = nullptr;
meta_data.text_buffer = value;
if (meta_data.bound_text_buffer.empty())
meta_data.bound_text_buffer.resize(8);
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_BLOB;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
meta_data.text_buffer = nullptr;
meta_data.bound_text_buffer.resize(sizeof(MYSQL_TIME));
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_DATE;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date time result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data = _handle->result_param_meta_data[index];
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
meta_data.text_buffer = nullptr;
meta_data.bound_text_buffer.resize(sizeof(MYSQL_TIME));
MYSQL_BIND& param = _handle->result_params[index];
param.buffer_type = MYSQL_TYPE_DATETIME;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
}
void bind_result_t::_post_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: post binding date result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
if (not *is_null)
{
const auto& dt =
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data());
*is_null = false;
*value = ::date::year(dt.year) / ::date::month(dt.month) / ::date::day(dt.day);
}
}
void bind_result_t::_post_bind_date_time_result(size_t index,
::sqlpp::chrono::microsecond_point* value,
bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date time result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
if (not *is_null)
{
const auto& dt =
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data());
*is_null = false;
*value = ::sqlpp::chrono::day_point(::date::year(dt.year) / ::date::month(dt.month) / ::date::day(dt.day)) +
std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
}
}
void bind_result_t::bind_impl()
{
if (_handle->debug)
std::cerr << "MySQL debug: Binding results for handle at " << _handle.get() << std::endl;
if (mysql_stmt_bind_result(_handle->mysql_stmt, _handle->result_params.data()))
{
throw sqlpp::exception(std::string("MySQL: mysql_stmt_bind_result: ") + mysql_stmt_error(_handle->mysql_stmt));
}
}
bool bind_result_t::next_impl()
{
if (_handle->debug)
std::cerr << "MySQL debug: Accessing next row of handle at " << _handle.get() << std::endl;
auto flag = mysql_stmt_fetch(_handle->mysql_stmt);
switch (flag)
{
case 0:
case MYSQL_DATA_TRUNCATED:
{
bool need_to_rebind = false;
for (auto& r : _handle->result_param_meta_data)
{
if (r.len)
{
if (r.bound_is_null)
{
*r.text_buffer = nullptr;
*r.len = 0;
}
else
{
if (r.bound_len > r.bound_text_buffer.size())
{
if (_handle->debug)
std::cerr << "MySQL debug: Need to reallocate buffer " << static_cast<const void*>(*r.text_buffer)
<< " at index " << r.index << " for handle at " << _handle.get() << std::endl;
need_to_rebind = true;
r.bound_text_buffer.resize(r.bound_len);
MYSQL_BIND& param = _handle->result_params[r.index];
param.buffer = r.bound_text_buffer.data();
param.buffer_length = r.bound_text_buffer.size();
auto err =
mysql_stmt_fetch_column(_handle->mysql_stmt, &param, r.index, 0);
if (err)
throw sqlpp::exception(std::string("MySQL: Fetch column after reallocate failed: ") +
"error-code: " + std::to_string(err) + ", stmt-error: " +
mysql_stmt_error(_handle->mysql_stmt) + ", stmt-errno: " +
std::to_string(mysql_stmt_errno(_handle->mysql_stmt)));
}
*r.text_buffer = r.bound_text_buffer.data();
if (_handle->debug)
std::cerr << "MySQL debug: New buffer " << static_cast<const void*>(*r.text_buffer) << " at index "
<< r.index << " for handle at " << _handle.get() << std::endl;
*r.len = r.bound_len;
}
}
if (r.is_null)
*r.is_null = r.bound_is_null;
}
if (need_to_rebind)
bind_impl();
}
return true;
case 1:
throw sqlpp::exception(std::string("MySQL: Could not fetch next result: ") +
mysql_stmt_error(_handle->mysql_stmt));
case MYSQL_NO_DATA:
return false;
default:
throw sqlpp::exception("MySQL: Unexpected return value for mysql_stmt_fetch()");
}
}
}
}

184
src/mysql/char_result.cpp Normal file
View File

@ -0,0 +1,184 @@
/*
* 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 "detail/result_handle.h"
#include <cctype>
#include <ciso646>
#include <date/date.h>
#include <iostream>
#include <sqlpp11/mysql/char_result.h>
#include <vector>
namespace sqlpp
{
namespace mysql
{
char_result_t::char_result_t()
{
}
char_result_t::char_result_t(std::unique_ptr<detail::result_handle>&& handle) : _handle(std::move(handle))
{
if (_invalid())
throw sqlpp::exception("MySQL: Constructing char_result without valid handle");
if (_handle->debug)
std::cerr << "MySQL debug: Constructing result, using handle at " << _handle.get() << std::endl;
}
char_result_t::~char_result_t() = default;
char_result_t::char_result_t(char_result_t&& rhs) = default;
char_result_t& char_result_t::operator=(char_result_t&&) = default;
namespace
{
const auto date_digits = std::vector<char>{1, 1, 1, 1, 0, 1, 1, 0, 1, 1}; // 2015-10-28
const auto time_digits = std::vector<char>{0, 1, 1, 0, 1, 1, 0, 1, 1}; // T23:00:12
auto check_digits(const char* text, const std::vector<char>& digitFlags) -> bool
{
for (const auto digitFlag : digitFlags)
{
if (digitFlag)
{
if (not std::isdigit(*text))
{
return false;
}
}
else
{
if (std::isdigit(*text) or *text == '\0')
{
return false;
}
}
++text;
}
return true;
}
}
bool char_result_t::_invalid() const
{
return !_handle or !*_handle;
}
void char_result_t::_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl;
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
if (*is_null)
{
*value = {};
return;
}
const auto date_string = _char_result_row.data[index];
if (_handle->debug)
std::cerr << "MySQL debug: date string: " << date_string << std::endl;
if (check_digits(date_string, date_digits))
{
const auto ymd = ::date::year(std::atoi(date_string)) / atoi(date_string + 5) / atoi(date_string + 8);
*value = ::sqlpp::chrono::day_point(ymd);
}
else
{
if (_handle->debug)
std::cerr << "MySQL debug: invalid date result: " << date_string << std::endl;
*value = {};
}
}
void char_result_t::_bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl;
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
if (*is_null)
{
*value = {};
return;
}
const auto date_time_string = _char_result_row.data[index];
if (_handle->debug)
std::cerr << "MySQL debug: date_time string: " << date_time_string << std::endl;
if (check_digits(date_time_string, date_digits))
{
const auto ymd =
::date::year(std::atoi(date_time_string)) / atoi(date_time_string + 5) / atoi(date_time_string + 8);
*value = ::sqlpp::chrono::day_point(ymd);
}
else
{
if (_handle->debug)
std::cerr << "MySQL debug: invalid date_time result: " << date_time_string << std::endl;
*value = {};
return;
}
const auto time_string = date_time_string + 10;
if (check_digits(time_string, time_digits))
{
*value += ::std::chrono::hours(std::atoi(time_string + 1)) + std::chrono::minutes(std::atoi(time_string + 4)) +
std::chrono::seconds(std::atoi(time_string + 7));
}
else
{
return;
}
const auto mu_string = time_string + 9;
if (mu_string[0] == '\0')
{
return;
}
auto factor = 100 * 1000;
for (auto i = 1u; i <= 6u and std::isdigit(mu_string[i]); ++i, factor /= 10)
{
*value += ::std::chrono::microseconds(factor * (mu_string[i] - '0'));
}
}
bool char_result_t::next_impl()
{
if (_handle->debug)
std::cerr << "MySQL debug: Accessing next row of handle at " << _handle.get() << std::endl;
_char_result_row.data = const_cast<const char**>(mysql_fetch_row(_handle->mysql_res));
_char_result_row.len = mysql_fetch_lengths(_handle->mysql_res);
return _char_result_row.data;
}
}
}

288
src/mysql/connection.cpp Normal file
View File

@ -0,0 +1,288 @@
/*
* 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 <ciso646>
#include <iostream>
#include "detail/connection_handle.h"
#include "detail/prepared_statement_handle.h"
#include "detail/result_handle.h"
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/connection.h>
namespace sqlpp
{
namespace mysql
{
scoped_library_initializer_t::scoped_library_initializer_t(int argc, char** argv, char** groups)
{
mysql_library_init(argc, argv, groups);
}
scoped_library_initializer_t::~scoped_library_initializer_t()
{
mysql_library_end();
}
void global_library_init(int argc, char** argv, char** groups)
{
static const auto global_init_and_end = scoped_library_initializer_t(argc, argv, groups);
}
namespace
{
struct MySqlThreadInitializer
{
MySqlThreadInitializer()
{
if (!mysql_thread_safe())
{
throw sqlpp::exception("MySQL error: Operating on a non-threadsafe client");
}
mysql_thread_init();
}
~MySqlThreadInitializer()
{
mysql_thread_end();
}
};
void thread_init()
{
thread_local MySqlThreadInitializer threadInitializer;
}
void execute_statement(detail::connection_handle_t& handle, const std::string& statement)
{
thread_init();
if (handle.config->debug)
std::cerr << "MySQL debug: Executing: '" << statement << "'" << std::endl;
if (mysql_query(handle.mysql.get(), statement.c_str()))
{
throw sqlpp::exception("MySQL error: Could not execute MySQL-statement: " +
std::string(mysql_error(handle.mysql.get())) + " (statement was >>" + statement +
"<<\n");
}
}
void execute_prepared_statement(detail::prepared_statement_handle_t& prepared_statement)
{
thread_init();
if (prepared_statement.debug)
std::cerr << "MySQL debug: Executing prepared_statement" << std::endl;
if (mysql_stmt_bind_param(prepared_statement.mysql_stmt, prepared_statement.stmt_params.data()))
{
throw sqlpp::exception(std::string("MySQL error: Could not bind parameters to statement") +
mysql_stmt_error(prepared_statement.mysql_stmt));
}
if (mysql_stmt_execute(prepared_statement.mysql_stmt))
{
throw sqlpp::exception(std::string("MySQL error: Could not execute prepared statement: ") +
mysql_stmt_error(prepared_statement.mysql_stmt));
}
}
std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle_t& handle,
const std::string& statement,
size_t no_of_parameters,
size_t no_of_columns)
{
thread_init();
if (handle.config->debug)
std::cerr << "MySQL debug: Preparing: '" << statement << "'" << std::endl;
auto prepared_statement = std::make_shared<detail::prepared_statement_handle_t>(
mysql_stmt_init(handle.mysql.get()), no_of_parameters, no_of_columns, handle.config->debug);
if (not prepared_statement)
{
throw sqlpp::exception("MySQL error: Could not allocate prepared statement\n");
}
if (mysql_stmt_prepare(prepared_statement->mysql_stmt, statement.data(), statement.size()))
{
throw sqlpp::exception("MySQL error: Could not prepare statement: " +
std::string(mysql_error(handle.mysql.get())) + " (statement was >>" + statement +
"<<\n");
}
return prepared_statement;
}
}
connection::connection(const std::shared_ptr<connection_config>& config)
: _handle(new detail::connection_handle_t(config))
{
}
connection::~connection()
{
}
connection::connection(connection&& other)
{
this->_transaction_active = other._transaction_active;
this->_handle = std::move(other._handle);
}
bool connection::is_valid()
{
return _handle->is_valid();
}
void connection::reconnect()
{
return _handle->reconnect();
}
const std::shared_ptr<connection_config> connection::get_config()
{
return _handle->config;
}
char_result_t connection::select_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
std::unique_ptr<detail::result_handle> result_handle(
new detail::result_handle(mysql_store_result(_handle->mysql.get()), _handle->config->debug));
if (!*result_handle)
{
throw sqlpp::exception("MySQL error: Could not store result set: " +
std::string(mysql_error(_handle->mysql.get())));
}
return {std::move(result_handle)};
}
bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return prepared_statement._handle;
}
size_t connection::run_prepared_insert_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_insert_id(prepared_statement._handle->mysql_stmt);
}
size_t connection::run_prepared_update_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_affected_rows(prepared_statement._handle->mysql_stmt);
}
size_t connection::run_prepared_remove_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_affected_rows(prepared_statement._handle->mysql_stmt);
}
prepared_statement_t connection::prepare_impl(const std::string& statement,
size_t no_of_parameters,
size_t no_of_columns)
{
return prepare_statement(*_handle, statement, no_of_parameters, no_of_columns);
}
size_t connection::insert_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_insert_id(_handle->mysql.get());
}
void connection::execute(const std::string& command)
{
execute_statement(*_handle, command);
}
size_t connection::update_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_affected_rows(_handle->mysql.get());
}
size_t connection::remove_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_affected_rows(_handle->mysql.get());
}
std::string connection::escape(const std::string& s) const
{
std::unique_ptr<char[]> dest(new char[s.size() * 2 + 1]);
mysql_real_escape_string(_handle->mysql.get(), dest.get(), s.c_str(), s.size());
return dest.get();
}
void connection::start_transaction()
{
if (_transaction_active)
{
throw sqlpp::exception("MySQL: Cannot have more than one open transaction per connection");
}
execute_statement(*_handle, "START TRANSACTION");
_transaction_active = true;
}
void connection::commit_transaction()
{
if (not _transaction_active)
{
throw sqlpp::exception("MySQL: Cannot commit a finished or failed transaction");
}
_transaction_active = false;
execute_statement(*_handle, "COMMIT");
}
void connection::rollback_transaction(bool report)
{
if (not _transaction_active)
{
throw sqlpp::exception("MySQL: Cannot rollback a finished or failed transaction");
}
if (report)
{
std::cerr << "MySQL warning: Rolling back unfinished transaction" << std::endl;
}
_transaction_active = false;
execute_statement(*_handle, "ROLLBACK");
}
void connection::report_rollback_failure(const std::string message) noexcept
{
std::cerr << "MySQL message:" << message << std::endl;
}
MYSQL* connection::get_handle(){
return _handle->mysql.get();
}
}
}

View File

@ -0,0 +1,293 @@
/*
* 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 <ciso646>
#include <iostream>
#include "detail/connection_handle.h"
#include "detail/prepared_statement_handle.h"
#include "detail/result_handle.h"
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/connection.h>
namespace sqlpp
{
namespace mysql
{
scoped_library_initializer_t::scoped_library_initializer_t(int argc, char** argv, char** groups)
{
mysql_library_init(argc, argv, groups);
}
scoped_library_initializer_t::~scoped_library_initializer_t()
{
mysql_library_end();
}
void global_library_init(int argc, char** argv, char** groups)
{
static const auto global_init_and_end = scoped_library_initializer_t(argc, argv, groups);
}
namespace
{
struct MySqlThreadInitializer
{
MySqlThreadInitializer()
{
if (!mysql_thread_safe())
{
throw sqlpp::exception("MySQL error: Operating on a non-threadsafe client");
}
mysql_thread_init();
}
~MySqlThreadInitializer()
{
mysql_thread_end();
}
};
void thread_init()
{
thread_local MySqlThreadInitializer threadInitializer;
}
void execute_statement(detail::connection_handle_t& handle, const std::string& statement)
{
thread_init();
if (handle.config->debug)
std::cerr << "MySQL debug: Executing: '" << statement << "'" << std::endl;
if (mysql_query(handle.mysql.get(), statement.c_str()))
{
throw sqlpp::exception("MySQL error: Could not execute MySQL-statement: " +
std::string(mysql_error(handle.mysql.get())) + " (statement was >>" + statement +
"<<\n");
}
}
void execute_prepared_statement(detail::prepared_statement_handle_t& prepared_statement)
{
thread_init();
if (prepared_statement.debug)
std::cerr << "MySQL debug: Executing prepared_statement" << std::endl;
if (mysql_stmt_bind_param(prepared_statement.mysql_stmt, prepared_statement.stmt_params.data()))
{
throw sqlpp::exception(std::string("MySQL error: Could not bind parameters to statement") +
mysql_stmt_error(prepared_statement.mysql_stmt));
}
if (mysql_stmt_execute(prepared_statement.mysql_stmt))
{
throw sqlpp::exception(std::string("MySQL error: Could not execute prepared statement: ") +
mysql_stmt_error(prepared_statement.mysql_stmt));
}
}
std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle_t& handle,
const std::string& statement,
size_t no_of_parameters,
size_t no_of_columns)
{
thread_init();
if (handle.config->debug)
std::cerr << "MySQL debug: Preparing: '" << statement << "'" << std::endl;
auto prepared_statement = std::make_shared<detail::prepared_statement_handle_t>(
mysql_stmt_init(handle.mysql.get()), no_of_parameters, no_of_columns, handle.config->debug);
if (not prepared_statement)
{
throw sqlpp::exception("MySQL error: Could not allocate prepared statement\n");
}
if (mysql_stmt_prepare(prepared_statement->mysql_stmt, statement.data(), statement.size()))
{
throw sqlpp::exception("MySQL error: Could not prepare statement: " +
std::string(mysql_error(handle.mysql.get())) + " (statement was >>" + statement +
"<<\n");
}
return prepared_statement;
}
}
connection::connection(const std::shared_ptr<connection_config>& config)
: _handle(new detail::connection_handle_t(config))
{
}
connection::~connection()
{
}
connection::connection(connection&& other)
{
this->_transaction_active = other._transaction_active;
this->_handle = std::move(other._handle);
}
bool connection::is_valid()
{
return _handle->is_valid();
}
void connection::reconnect()
{
return _handle->reconnect();
}
const std::shared_ptr<connection_config> connection::get_config()
{
return _handle->config;
}
char_result_t connection::select_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
std::unique_ptr<detail::result_handle> result_handle(
new detail::result_handle(mysql_store_result(_handle->mysql.get()), _handle->config->debug));
if (!*result_handle)
{
throw sqlpp::exception("MySQL error: Could not store result set: " +
std::string(mysql_error(_handle->mysql.get())));
}
return {std::move(result_handle)};
}
bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return prepared_statement._handle;
}
size_t connection::run_prepared_insert_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_insert_id(prepared_statement._handle->mysql_stmt);
}
size_t connection::run_prepared_update_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_affected_rows(prepared_statement._handle->mysql_stmt);
}
size_t connection::run_prepared_remove_impl(prepared_statement_t& prepared_statement)
{
execute_prepared_statement(*prepared_statement._handle);
return mysql_stmt_affected_rows(prepared_statement._handle->mysql_stmt);
}
prepared_statement_t connection::prepare_impl(const std::string& statement,
size_t no_of_parameters,
size_t no_of_columns)
{
return prepare_statement(*_handle, statement, no_of_parameters, no_of_columns);
}
size_t connection::insert_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_insert_id(_handle->mysql.get());
}
void connection::execute(const std::string& command)
{
execute_statement(*_handle, command);
}
size_t connection::update_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_affected_rows(_handle->mysql.get());
}
size_t connection::remove_impl(const std::string& statement)
{
execute_statement(*_handle, statement);
return mysql_affected_rows(_handle->mysql.get());
}
std::string connection::escape(const std::string& s) const
{
std::unique_ptr<char[]> dest(new char[s.size() * 2 + 1]);
mysql_real_escape_string(_handle->mysql.get(), dest.get(), s.c_str(), s.size());
return dest.get();
}
void connection::start_transaction()
{
if (_transaction_active)
{
throw sqlpp::exception("MySQL: Cannot have more than one open transaction per connection");
}
execute_statement(*_handle, "START TRANSACTION");
_transaction_active = true;
}
void connection::commit_transaction()
{
if (not _transaction_active)
{
throw sqlpp::exception("MySQL: Cannot commit a finished or failed transaction");
}
_transaction_active = false;
execute_statement(*_handle, "COMMIT");
}
void connection::rollback_transaction(bool report)
{
if (not _transaction_active)
{
throw sqlpp::exception("MySQL: Cannot rollback a finished or failed transaction");
}
if (report)
{
std::cerr << "MySQL warning: Rolling back unfinished transaction" << std::endl;
}
_transaction_active = false;
execute_statement(*_handle, "ROLLBACK");
}
void connection::report_rollback_failure(const std::string message) noexcept
{
std::cerr << "MySQL message:" << message << std::endl;
}
<<<<<<< Updated upstream
MYSQL* connection::get_handle(){
=======
MYSQL* connection::get_handle()
{
>>>>>>> Stashed changes
return _handle->mysql.get();
}
}
}

View File

@ -0,0 +1,99 @@
/*
* 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 "connection_handle.h"
#include <ciso646>
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/connection_config.h>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
void connect(MYSQL* mysql, const connection_config& config)
{
if (!mysql_real_connect(mysql, config.host.empty() ? nullptr : config.host.c_str(),
config.user.empty() ? nullptr : config.user.c_str(),
config.password.empty() ? nullptr : config.password.c_str(), nullptr, config.port,
config.unix_socket.empty() ? nullptr : config.unix_socket.c_str(), config.client_flag))
{
throw sqlpp::exception("MySQL: could not connect to server: " + std::string(mysql_error(mysql)));
}
if (mysql_set_character_set(mysql, config.charset.c_str()))
{
throw sqlpp::exception("MySQL error: can't set character set " + config.charset);
}
if (not config.database.empty() and mysql_select_db(mysql, config.database.c_str()))
{
throw sqlpp::exception("MySQL error: can't select database '" + config.database + "'");
}
}
void handle_cleanup(MYSQL* mysql)
{
mysql_close(mysql);
}
connection_handle_t::connection_handle_t(const std::shared_ptr<connection_config>& conf)
: config(conf), mysql(mysql_init(nullptr), handle_cleanup)
{
if (not mysql)
{
throw sqlpp::exception("MySQL: could not init mysql data structure");
}
if (config->auto_reconnect)
{
my_bool my_true = true;
if (mysql_options(mysql.get(), MYSQL_OPT_RECONNECT, &my_true))
{
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_RECONNECT");
}
}
connect(mysql.get(), *config);
}
connection_handle_t::~connection_handle_t()
{
}
bool connection_handle_t::is_valid()
{
return mysql_ping(mysql.get()) == 0;
}
void connection_handle_t::reconnect()
{
connect(mysql.get(), *config);
}
}
}
}

View File

@ -0,0 +1,62 @@
/*
* 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_MYSQL_CONNECTION_HANDLE_H
#define SQLPP_MYSQL_CONNECTION_HANDLE_H
#include <memory>
#include "../sqlpp_mysql.h"
namespace sqlpp
{
namespace mysql
{
struct connection_config;
namespace detail
{
void handle_cleanup(MYSQL* mysql);
struct connection_handle_t
{
const std::shared_ptr<connection_config> config;
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
connection_handle_t(const std::shared_ptr<connection_config>& config);
~connection_handle_t();
connection_handle_t(const connection_handle_t&) = delete;
connection_handle_t(connection_handle_t&&) = delete;
connection_handle_t& operator=(const connection_handle_t&) = delete;
connection_handle_t& operator=(connection_handle_t&&) = delete;
bool is_valid();
void reconnect();
};
}
}
}
#endif

View File

@ -0,0 +1,109 @@
/*
* 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_MYSQL_DETAIL_PREPARED_STATEMENT_HANDLE_H
#define SQLPP_MYSQL_DETAIL_PREPARED_STATEMENT_HANDLE_H
#include "../sqlpp_mysql.h"
#include <vector>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_meta_data_t
{
size_t index;
unsigned long bound_len;
my_bool bound_is_null;
my_bool bound_error;
std::vector<char> bound_text_buffer; // also for blobs
const char** text_buffer;
size_t* len;
bool* is_null;
};
struct prepared_statement_handle_t
{
struct wrapped_bool
{
my_bool value;
wrapped_bool() : value(false)
{
}
wrapped_bool(bool v) : value(v)
{
}
wrapped_bool(const wrapped_bool&) = default;
wrapped_bool(wrapped_bool&&) = default;
wrapped_bool& operator=(const wrapped_bool&) = default;
wrapped_bool& operator=(wrapped_bool&&) = default;
~wrapped_bool() = default;
};
MYSQL_STMT* mysql_stmt;
std::vector<MYSQL_BIND> stmt_params;
std::vector<MYSQL_TIME> stmt_date_time_param_buffer;
std::vector<wrapped_bool> stmt_param_is_null; // my_bool is bool after 8.0, and vector<bool> is bad
std::vector<MYSQL_BIND> result_params;
std::vector<result_meta_data_t> result_param_meta_data;
bool debug;
prepared_statement_handle_t(MYSQL_STMT* stmt, size_t no_of_parameters, size_t no_of_columns, bool debug_)
: mysql_stmt(stmt),
stmt_params(no_of_parameters, MYSQL_BIND{}),
stmt_date_time_param_buffer(no_of_parameters, MYSQL_TIME{}),
stmt_param_is_null(no_of_parameters, false),
result_params(no_of_columns, MYSQL_BIND{}),
result_param_meta_data(no_of_columns, result_meta_data_t{}),
debug(debug_)
{
}
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;
~prepared_statement_handle_t()
{
if (mysql_stmt)
mysql_stmt_close(mysql_stmt);
}
bool operator!() const
{
return !mysql_stmt;
}
};
}
}
}
#endif

View File

@ -0,0 +1,67 @@
/*
* 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_MYSQL_DETAIL_RESULT_HANDLE_H
#define SQLPP_MYSQL_DETAIL_RESULT_HANDLE_H
#include "../sqlpp_mysql.h"
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_handle
{
MYSQL_RES* mysql_res;
bool debug;
result_handle(MYSQL_RES* res, bool debug_) : mysql_res(res), debug(debug_)
{
}
result_handle(const result_handle&) = delete;
result_handle(result_handle&&) = default;
result_handle& operator=(const result_handle&) = delete;
result_handle& operator=(result_handle&&) = default;
~result_handle()
{
if (mysql_res)
mysql_free_result(mysql_res);
}
bool operator!() const
{
return !mysql_res;
}
};
}
}
}
#endif

View File

@ -0,0 +1,204 @@
/*
* 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.
*/
#ifdef _WIN32
// It seems that Windows.h will be included directly and indirectly.
// These defines prevent min/max macros and a bunch of other stuff
// to be defined in that header.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif // _WIN32
#include "detail/prepared_statement_handle.h"
#include <ciso646>
#include <date/date.h>
#include <iostream>
#include <sqlpp11/mysql/prepared_statement.h>
#include <string>
namespace sqlpp
{
namespace mysql
{
prepared_statement_t::prepared_statement_t(std::shared_ptr<detail::prepared_statement_handle_t>&& handle)
: _handle(std::move(handle))
{
if (_handle and _handle->debug)
std::cerr << "MySQL debug: Constructing prepared_statement, using handle at " << _handle.get() << std::endl;
}
void prepared_statement_t::_bind_boolean_parameter(size_t index, const signed char* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding boolean parameter " << (*value ? "true" : "false") << " at index: " << index
<< ", being " << (is_null ? "" : "not ") << "null" << std::endl;
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_TINY;
param.buffer = const_cast<signed char*>(value);
param.buffer_length = sizeof(*value);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
void prepared_statement_t::_bind_integral_parameter(size_t index, const int64_t* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding integral parameter " << *value << " at index: " << index << ", being "
<< (is_null ? "" : "not ") << "null" << std::endl;
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = const_cast<int64_t*>(value);
param.buffer_length = sizeof(*value);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
void prepared_statement_t::_bind_unsigned_integral_parameter(size_t index, const uint64_t* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding unsigned integral parameter " << *value << " at index: " << index
<< ", being " << (is_null ? "" : "not ") << "null" << std::endl;
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = const_cast<uint64_t*>(value);
param.buffer_length = sizeof(*value);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = true;
param.error = nullptr;
}
void prepared_statement_t::_bind_floating_point_parameter(size_t index, const double* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding floating_point parameter " << *value << " at index: " << index << ", being "
<< (is_null ? "" : "not ") << "null" << std::endl;
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_DOUBLE;
param.buffer = const_cast<double*>(value);
param.buffer_length = sizeof(*value);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
void prepared_statement_t::_bind_text_parameter(size_t index, const std::string* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding text parameter " << *value << " at index: " << index << ", being "
<< (is_null ? "" : "not ") << "null" << std::endl;
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_STRING;
param.buffer = const_cast<char*>(value->data());
param.buffer_length = value->size();
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
void prepared_statement_t::_bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date parameter "
<< " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
auto& bound_time = _handle->stmt_date_time_param_buffer[index];
if (not is_null)
{
const auto ymd = ::date::year_month_day{*value};
bound_time.year = static_cast<int>(ymd.year());
bound_time.month = static_cast<unsigned>(ymd.month());
bound_time.day = static_cast<unsigned>(ymd.day());
if (_handle->debug)
std::cerr << "bound values: " << bound_time.year << '-' << bound_time.month << '-' << bound_time.day << 'T'
<< bound_time.hour << ':' << bound_time.minute << ':' << bound_time.second << std::endl;
}
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_DATE;
param.buffer = &bound_time;
param.buffer_length = sizeof(MYSQL_TIME);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
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 << "MySQL debug: binding date_time parameter "
<< " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
auto& bound_time = _handle->stmt_date_time_param_buffer[index];
if (not is_null)
{
const auto dp = ::sqlpp::chrono::floor<::date::days>(*value);
const auto time = date::make_time(*value - dp);
const auto ymd = ::date::year_month_day{dp};
bound_time.year = static_cast<int>(ymd.year());
bound_time.month = static_cast<unsigned>(ymd.month());
bound_time.day = static_cast<unsigned>(ymd.day());
bound_time.hour = time.hours().count();
bound_time.minute = time.minutes().count();
bound_time.second = time.seconds().count();
bound_time.second_part = time.subseconds().count();
if (_handle->debug)
std::cerr << "bound values: " << bound_time.year << '-' << bound_time.month << '-' << bound_time.day << 'T'
<< bound_time.hour << ':' << bound_time.minute << ':' << bound_time.second << std::endl;
}
_handle->stmt_param_is_null[index] = is_null;
MYSQL_BIND& param = _handle->stmt_params[index];
param.buffer_type = MYSQL_TYPE_DATETIME;
param.buffer = &bound_time;
param.buffer_length = sizeof(MYSQL_TIME);
param.length = &param.buffer_length;
param.is_null = &_handle->stmt_param_is_null[index].value;
param.is_unsigned = false;
param.error = nullptr;
}
}
}

View File

@ -0,0 +1,12 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_dependency(Sqlpp11 REQUIRED)
find_dependency(MySQL REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/sqlpp-mysql-targets.cmake")
check_required_components(sqlpp-mysql)

42
src/mysql/sqlpp_mysql.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2018 - 2018, 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_MYSQL_MYSQL_H
#define SQLPP_MYSQL_MYSQL_H
#include <mysql.h>
namespace sqlpp
{
namespace mysql
{
#if LIBMYSQL_VERSION_ID >= 80000
using my_bool = bool;
#endif
}
}
#endif

View File

@ -0,0 +1,26 @@
# 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(usage)

View File

@ -0,0 +1,25 @@
find_package(Threads REQUIRED)
macro(build_and_run arg)
add_executable(Sqlpp11MySQL${arg} ${arg}.cpp)
target_link_libraries(Sqlpp11MySQL${arg} PRIVATE sqlpp-mysql)
target_link_libraries(Sqlpp11MySQL${arg} PRIVATE Threads::Threads)
if(${arg} STREQUAL "JsonTest")
target_link_libraries(Sqlpp11MySQL${arg} PRIVATE MySQL::MySQL)
endif()
if(NOT MSVC)
target_compile_options(Sqlpp11MySQL${arg} PRIVATE -Wall -Wextra -pedantic)
endif()
add_test(${arg} Sqlpp11MySQL${arg})
endmacro()
build_and_run(JsonTest)
build_and_run(CustomQuery)
build_and_run(DateTimeTest)
build_and_run(SampleTest)
build_and_run(SelectTest)
build_and_run(UnionTest)
build_and_run(DynamicSelectTest)
build_and_run(MoveConstructorTest)
build_and_run(PreparedTest)
build_and_run(TruncatedTest)

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2013-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.
*/
#include <iostream>
#include "TabSample.h"
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/custom_query.h>
#include <sqlpp11/mysql/mysql.h>
SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right)
namespace
{
struct on_duplicate_key_update
{
std::string _serialized;
template <typename Db, typename Assignment>
on_duplicate_key_update(Db& db, Assignment assignment)
{
typename Db::_serializer_context_t context{db};
_serialized = " ON DUPLICATE KEY UPDATE " + serialize(assignment, context).str();
}
template <typename Db, typename Assignment>
auto operator()(Db& db, Assignment assignment) -> on_duplicate_key_update&
{
typename Db::_serializer_context_t context{db};
_serialized += ", " + serialize(assignment, context).str();
return *this;
}
auto get() const -> sqlpp::verbatim_t<::sqlpp::no_value_t>
{
return ::sqlpp::verbatim(_serialized);
}
};
} // namespace
const auto tab = TabSample{};
namespace mysql = sqlpp::mysql;
int main()
{
mysql::global_library_init();
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
mysql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
))");
// Create a MYSQL style custom "insert on duplicate update"
db(custom_query(sqlpp::insert_into(tab).set(tab.beta = "sample", tab.gamma = true),
on_duplicate_key_update(db, tab.beta = "sample")(db, tab.gamma = false).get()));
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,153 @@
/*
* 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.
*/
#include "TabSample.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>
#include <cassert>
#include <iostream>
#include <vector>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
namespace
{
const auto now = ::sqlpp::chrono::floor<::std::chrono::milliseconds>(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>
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 mysql = sqlpp::mysql;
int main()
{
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const std::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
catch (...)
{
std::cerr << "Unknown exception during connect" << std::endl;
return 1;
}
try
{
using days_type = std::chrono::duration<int, std::ratio<60*60*24>>;
mysql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_date_time)");
db.execute(R"(CREATE TABLE tab_date_time (
col_day_point date,
col_time_point datetime(3),
col_date_time_point datetime DEFAULT CURRENT_TIMESTAMP
))");
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{});
require_equal(__LINE__, std::chrono::time_point_cast<days_type>(row.colDateTimePoint.value()), std::chrono::time_point_cast<days_type>(std::chrono::system_clock::now()));
}
auto statement = db.prepare(select(tab.colDateTimePoint).from(tab).unconditionally());
for (const auto& row : db(statement))
{
require_equal(__LINE__, row.colDateTimePoint.is_null(), false);
require_equal(__LINE__, std::chrono::time_point_cast<days_type>(row.colDateTimePoint.value()), std::chrono::time_point_cast<days_type>(std::chrono::system_clock::now()));
}
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 x = update(tab)
.set(tab.colDayPoint = parameter(tab.colDayPoint), tab.colTimePoint = parameter(tab.colTimePoint))
.unconditionally();
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 (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
catch (...)
{
std::cerr << "Unkown exception" << std::endl;
}
}

View File

@ -0,0 +1,90 @@
/*
* 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.
*/
#include "TabSample.h"
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/remove.h>
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include <iostream>
#include <vector>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
namespace mysql = sqlpp::mysql;
int main()
{
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
mysql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
))");
const auto tab = TabSample{};
db(insert_into(tab).set(tab.gamma = true));
auto i = insert_into(tab).columns(tab.beta, tab.gamma);
i.values.add(tab.beta = "rhabarbertorte", tab.gamma = false);
i.values.add(tab.beta = "cheesecake", tab.gamma = false);
i.values.add(tab.beta = "kaesekuchen", tab.gamma = true);
db(i);
auto s = dynamic_select(db).dynamic_columns(tab.alpha).from(tab).unconditionally();
s.selected_columns.add(tab.beta);
for (const auto& row : db(s))
{
std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.at("beta") << std::endl;
};
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2019 - 2019, 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 <mysql.h>
#include <iostream>
// JSON support only in MYSQL 5.7.8 and later
#if !USE_MARIADB && (LIBMYSQL_VERSION_ID < 50708)
int main()
{
std::cerr << "Warning: not testing Json, because the MySQL version id is less than 50708" << std::endl;
}
#else
// JSON support only in MariaDB 10.2.7 and later
#if USE_MARIADB && (MARIADB_VERSION_ID < 100207)
int main()
{
std::cerr << "Warning: not testing Json, because the MariaDB version id is less than 100207" << std::endl;
}
#else
#include "TabJson.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>
namespace test
{
SQLPP_ALIAS_PROVIDER(value)
}
namespace mysql = sqlpp::mysql;
int main()
{
mysql::global_library_init();
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
mysql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_json)");
db.execute(R"(CREATE TABLE tab_json (
data JSON NOT NULL
))");
const auto tab = test::TabJson{};
db(insert_into(tab).set(tab.data = R"--({"key" : "value"})--"));
const auto query =
select(sqlpp::verbatim<sqlpp::text>(R"--(JSON_UNQUOTE(JSON_EXTRACT(data, "$.key")))--").as(test::value))
.from(tab)
.unconditionally();
auto result = db(query);
if (result.empty())
throw std::runtime_error{"selection result is empty"};
const std::string value = result.front().value;
if (value != "value")
throw std::runtime_error{std::string{"unexpected value: "} + value};
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}
#endif
#endif

View File

@ -0,0 +1,96 @@
/*
* 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 "TabSample.h"
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/remove.h>
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include <cassert>
#include <iostream>
#include <vector>
namespace mysql = sqlpp::mysql;
int main()
{
mysql::global_library_init();
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
std::vector<sqlpp::mysql::connection> connections;
connections.emplace_back(sqlpp::mysql::connection(config));
connections.at(0).execute(R"(DROP TABLE IF EXISTS tab_sample)");
connections.at(0).execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
))");
connections.at(0).start_transaction();
auto db = std::move(connections.at(0));
assert(db.is_transaction_active());
const auto tab = TabSample{};
db(insert_into(tab).set(tab.gamma = true));
auto i = insert_into(tab).columns(tab.beta, tab.gamma);
i.values.add(tab.beta = "rhabarbertorte", tab.gamma = false);
i.values.add(tab.beta = "cheesecake", tab.gamma = false);
i.values.add(tab.beta = "kaesekuchen", tab.gamma = true);
db(i);
auto s = dynamic_select(db).dynamic_columns(tab.alpha).from(tab).unconditionally();
s.selected_columns.add(tab.beta);
for (const auto& row : db(s))
{
std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.at("beta") << std::endl;
};
db.commit_transaction();
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,101 @@
/*
* 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.
*/
#include "TabSample.h"
#include <cassert>
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/remove.h>
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include <iostream>
#include <vector>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{0, nullptr, nullptr};
SQLPP_ALIAS_PROVIDER(left)
namespace sql = sqlpp::mysql;
const auto tab = TabSample{};
void testPreparedStatementResult (sql::connection& db)
{
auto preparedSelectAll = db.prepare(sqlpp::select(count(tab.alpha)).from(tab).unconditionally());
auto preparedUpdateAll = db.prepare(sqlpp::update(tab).set(tab.gamma = false).unconditionally());
uint32_t count = 0;
{
// explicit result scope
// if results are released update should execute without exception
auto result = db(preparedSelectAll);
count = result.front().count;
}
db(preparedUpdateAll);
}
int main()
{
auto config = std::make_shared<sql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
sql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
sql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
))");
testPreparedStatementResult(db);
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,207 @@
/*
* 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.
*/
#include "TabSample.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>
#include <cassert>
#include <iostream>
#include <vector>
SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right)
namespace mysql = sqlpp::mysql;
int main()
{
mysql::global_library_init();
auto config = std::make_shared<mysql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
mysql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
mysql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
))");
assert(not db(select(sqlpp::value(false).as(sqlpp::alias::a))).front().a);
const auto tab = TabSample{};
// clear the table
db(remove_from(tab).unconditionally());
// Several ways of ensuring that tab is empty
assert(not db(select(exists(select(tab.alpha).from(tab).unconditionally())))
.front()
.exists); // this is probably the fastest
assert(not db(select(count(tab.alpha)).from(tab).unconditionally()).front().count);
assert(db(select(tab.alpha).from(tab).unconditionally()).empty());
// explicit all_of(tab)
std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
select(all_of(tab)).from(tab);
std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
db(select(all_of(tab)).from(tab).unconditionally());
std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< std::endl;
};
// insert
db(insert_into(tab).default_values());
const auto x = select(all_of(tab)).from(tab).unconditionally();
const auto y = db.prepare(x);
for (const auto& row : db(db.prepare(select(all_of(tab)).from(tab).unconditionally())))
{
std::cerr << "alpha: " << row.alpha.is_null() << std::endl;
std::cerr << "beta: " << row.beta.is_null() << std::endl;
std::cerr << "gamma: " << row.gamma.is_null() << std::endl;
}
db(insert_into(tab).set(tab.beta = "kaesekuchen", tab.gamma = true));
db(insert_into(tab).default_values());
db(insert_into(tab).set(tab.beta = "", tab.gamma = true));
// update
db(update(tab).set(tab.gamma = false).where(tab.alpha.in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
db(update(tab).set(tab.gamma = true).where(tab.alpha.in(1)));
// remove
db(remove_from(tab).where(tab.alpha == tab.alpha + 3));
std::cerr << "+++++++++++++++++++++++++++" << std::endl;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
std::cerr << __LINE__ << " row.beta: " << row.beta << std::endl;
}
std::cerr << "+++++++++++++++++++++++++++" << std::endl;
decltype(db(select(all_of(tab)).from(tab).unconditionally())) result;
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())
{
int a = row.alpha;
int m = row.max;
std::cerr << __LINE__ << " row.alpha: " << a << ", row.max: " << m << std::endl;
}
tx.commit();
TabFoo foo;
for (const auto& row : db(select(tab.alpha).from(tab.join(foo).on(tab.alpha == foo.omega)).unconditionally()))
{
std::cerr << row.alpha << std::endl;
}
for (const auto& row :
db(select(tab.alpha).from(tab.left_outer_join(foo).on(tab.alpha == foo.omega)).unconditionally()))
{
std::cerr << row.alpha << std::endl;
}
auto ps = db.prepare(select(all_of(tab))
.from(tab)
.where(tab.alpha != parameter(tab.alpha) and tab.beta != parameter(tab.beta) and
tab.gamma != parameter(tab.gamma)));
ps.params.alpha = 7;
ps.params.beta = "wurzelbrunft";
ps.params.gamma = true;
for (const auto& row : db(ps))
{
std::cerr << "bound result: alpha: " << row.alpha << std::endl;
std::cerr << "bound result: beta: " << row.beta << std::endl;
std::cerr << "bound result: gamma: " << row.gamma << std::endl;
}
std::cerr << "--------" << std::endl;
ps.params.gamma = "false";
for (const auto& row : db(ps))
{
std::cerr << "bound result: alpha: " << row.alpha << std::endl;
std::cerr << "bound result: beta: " << row.beta << std::endl;
std::cerr << "bound result: gamma: " << row.gamma << std::endl;
}
std::cerr << "--------" << std::endl;
ps.params.beta = "kaesekuchen";
for (const auto& row : db(ps))
{
std::cerr << "bound result: alpha: " << row.alpha << std::endl;
std::cerr << "bound result: beta: " << row.beta << std::endl;
std::cerr << "bound result: gamma: " << row.gamma << std::endl;
}
auto pi = db.prepare(insert_into(tab).set(tab.beta = parameter(tab.beta), tab.gamma = true));
pi.params.beta = "prepared cake";
std::cerr << "Inserted: " << db(pi) << std::endl;
auto pu = db.prepare(update(tab).set(tab.gamma = parameter(tab.gamma)).where(tab.beta == "prepared cake"));
pu.params.gamma = false;
std::cerr << "Updated: " << db(pu) << std::endl;
auto pr = db.prepare(remove_from(tab).where(tab.beta != parameter(tab.beta)));
pr.params.beta = "prepared cake";
std::cerr << "Deleted lines: " << db(pr) << std::endl;
for (const auto& row : db(select(case_when(tab.gamma).then(tab.alpha).else_(foo.omega).as(tab.alpha))
.from(tab.cross_join(foo))
.unconditionally()))
{
std::cerr << row.alpha << std::endl;
}
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,174 @@
/*
* 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.
*/
#include "TabSample.h"
#include <cassert>
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/remove.h>
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include <iostream>
#include <vector>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{0, nullptr, nullptr};
SQLPP_ALIAS_PROVIDER(left)
namespace sql = sqlpp::mysql;
const auto tab = TabSample{};
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());
std::cerr << "--------------------------------------" << std::endl;
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);
// Try running the same prepared statement again
std::cerr << "--------------------------------------" << std::endl;
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 main()
{
auto config = std::make_shared<sql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
sql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
sql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
))");
testSelectAll(db, 0);
db(insert_into(tab).default_values());
testSelectAll(db, 1);
db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheesecake"));
testSelectAll(db, 2);
db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheesecake"));
testSelectAll(db, 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.beta + tab.beta) == ""));
db(select(all_of(tab)).from(tab).where((tab.beta + tab.beta).like("%'\"%")));
// insert
db(insert_into(tab).set(tab.gamma = true));
// update
db(update(tab).set(tab.gamma = false).where(tab.alpha.in(1)));
db(update(tab).set(tab.gamma = 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())
{
int a = row.alpha;
int m = row.max;
std::cerr << "-----------------------------" << a << ", " << m << std::endl;
}
tx.commit();
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,48 @@
// generated by ../../sqlpp11/scripts/ddl2cpp ../tests/TabJson.sql ../tests/TabJson test
#ifndef TEST_TABJSON_H
#define TEST_TABJSON_H
#include <sqlpp11/table.h>
#include <sqlpp11/data_types.h>
#include <sqlpp11/char_sequence.h>
namespace test
{
namespace TabJson_
{
struct Data
{
struct _alias_t
{
static constexpr const char _literal[] = "data";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template<typename T>
struct _member_t
{
T data;
T& operator()() { return data; }
const T& operator()() const { return data; }
};
};
using _traits = sqlpp::make_traits<sqlpp::text, sqlpp::tag::require_insert>;
};
} // namespace TabJson_
struct TabJson: sqlpp::table_t<TabJson,
TabJson_::Data>
{
struct _alias_t
{
static constexpr const char _literal[] = "tab_json";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template<typename T>
struct _member_t
{
T tabJson;
T& operator()() { return tabJson; }
const T& operator()() const { return tabJson; }
};
};
};
} // namespace test
#endif

View File

@ -0,0 +1,3 @@
CREATE TABLE tab_json (
data JSON NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,263 @@
/*
* 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::must_not_insert, ::sqlpp::tag::must_not_update>;
};
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::must_not_update, ::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 ColDateTimePoint
{
struct _alias_t
{
static constexpr const char _literal[] = "col_date_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template<typename T>
struct _member_t
{
T colDateTimePoint;
T& operator()() { return colDateTimePoint; }
const T& operator()() const { return colDateTimePoint; }
};
};
using _traits = sqlpp::make_traits<sqlpp::time_point>;
};
}
struct TabDateTime : sqlpp::table_t<TabDateTime, TabDateTime_::ColDayPoint, TabDateTime_::ColTimePoint, TabDateTime_::ColDateTimePoint>
{
struct _alias_t
{
static constexpr const char _literal[] = "tab_date_time";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabDateTime;
T& operator()()
{
return tabDateTime;
}
const T& operator()() const
{
return tabDateTime;
}
};
};
};
#endif

View File

@ -0,0 +1,5 @@
CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL AUTO_INCREMENT,
beta tinyint(1) DEFAULT NULL,
gamma varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View File

@ -0,0 +1,108 @@
/*
* 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.
*/
#include "TabSample.h"
#include <cassert>
#include <sqlpp11/alias_provider.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/remove.h>
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include <iostream>
#include <vector>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{0, nullptr, nullptr};
namespace sql = sqlpp::mysql;
const auto tab = TabSample{};
int main()
{
auto config = std::make_shared<sql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
config->charset = "utf8";
try
{
sql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
sql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
))");
db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheese"));
db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheesecake"));
{
for (const auto& row : db(db.prepare(sqlpp::select(all_of(tab)).from(tab).unconditionally())))
{
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma << std::endl;
}
}
{
auto result = db(db.prepare(sqlpp::select(all_of(tab)).from(tab).where(tab.alpha == 1).limit(1u)));
auto& row = result.front();
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma << std::endl;
assert(row.beta == "cheese");
}
{
auto result = db(db.prepare(sqlpp::select(all_of(tab)).from(tab).where(tab.alpha == 2).limit(1u)));
auto& row = result.front();
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma << std::endl;
assert(row.beta == "cheesecake");
}
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.
*/
#include "TabSample.h"
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/sqlpp11.h>
#include <iostream>
const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{0, nullptr, nullptr};
namespace sql = sqlpp::mysql;
const auto tab = TabSample{};
int main()
{
auto config = std::make_shared<sql::connection_config>();
config->user = "root";
config->database = "sqlpp_mysql";
config->debug = true;
try
{
sql::connection db(config);
}
catch (const sqlpp::exception& e)
{
std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
std::cerr << e.what() << std::endl;
return 1;
}
try
{
sql::connection db(config);
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta bool DEFAULT NULL,
gamma varchar(255) DEFAULT NULL,
PRIMARY KEY (alpha)
))");
auto u = select(all_of(tab)).from(tab).unconditionally().union_all(select(all_of(tab)).from(tab).unconditionally());
for (const auto& row : db(u))
{
std::cout << row.alpha << row.beta << row.gamma << std::endl;
}
for (const auto& row : db(u.union_distinct(select(all_of(tab)).from(tab).unconditionally())))
{
std::cout << row.alpha << row.beta << row.gamma << std::endl;
}
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
}