* Refactored existing code and added doxygen comments for mostly every public typemaster
@@ -1,15 +1,57 @@ | |||
# Initialize CMake ################################################################################ | |||
CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) | |||
Include ( CTest ) | |||
If ( NOT CMAKE_BUILD_TYPE ) | |||
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||
EndIf ( NOT CMAKE_BUILD_TYPE ) | |||
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/" | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||
# Projects ######################################################################################## | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) | |||
# Set CMAKE_BUILD_TYPE | |||
If ( NOT CMAKE_BUILD_TYPE ) | |||
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||
EndIf ( NOT CMAKE_BUILD_TYPE ) | |||
Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) | |||
# Set CMAKE_MODULE_PATH | |||
If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
EndIf ( ) | |||
If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||
EndIf ( ) | |||
# Project ######################################################################################### | |||
Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmariadb-var.cmake ) | |||
Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmariadb-options.cmake ) | |||
Project ( cppmariadb | |||
DESCRIPTION "A simple library" | |||
VERSION "${CPPMARIADB_VERSION}" ) | |||
Include ( CTest ) | |||
Include ( GNUInstallDirs ) | |||
# Subdirectories | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
# Install | |||
Include ( CMakePackageConfigHelpers ) | |||
Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmariadb-config-version.cmake" | |||
VERSION ${CPPMARIADB_VERSION} | |||
COMPATIBILITY AnyNewerVersion ) | |||
Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmariadb-config.cmake" | |||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmariadb-config.cmake" | |||
@ONLY ) | |||
Set ( ConfigPackageLocation "${CPPMARIADB_INSTALL_DIR_SHARE}/cmake" ) | |||
Install ( EXPORT | |||
cppmariadb | |||
NAMESPACE | |||
cppmariadb:: | |||
DESTINATION | |||
${ConfigPackageLocation} ) | |||
Install ( FILES | |||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmariadb-config.cmake" | |||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmariadb-config-version.cmake" | |||
DESTINATION | |||
${ConfigPackageLocation} | |||
COMPONENT | |||
Devel ) |
@@ -1,46 +0,0 @@ | |||
Include ( ExternalProject ) | |||
Include ( FindPackageHandleStandardArgs ) | |||
Set ( CPPUTILS_PATH ${CMAKE_BINARY_DIR}/extern/cpputils ) | |||
If ( NOT TARGET cpputils_extern ) | |||
ExternalProject_Add ( cpputils_extern | |||
PREFIX ${CPPUTILS_PATH} | |||
TMP_DIR ${CPPUTILS_PATH}/tmp | |||
STAMP_DIR ${CPPUTILS_PATH}/stamp | |||
SOURCE_DIR ${CPPUTILS_PATH}/src | |||
BINARY_DIR ${CPPUTILS_PATH}/build | |||
INSTALL_DIR ${CPPUTILS_PATH}/install | |||
GIT_REPOSITORY "https://git.bergmann89.de/cpp/cpputils.git" | |||
GIT_TAG "master" | |||
TEST_COMMAND make test | |||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> | |||
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} | |||
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} | |||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} | |||
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}) | |||
EndIf ( ) | |||
Set ( CPPUTILS_LIBRARY ${CPPUTILS_PATH}/install/lib/libcpputils.so ) | |||
Set ( CPPUTILS_INCLUDE_DIR ${CPPUTILS_PATH}/install/include ) | |||
Set ( CPPUTILS_LIBRARIES ${CPPUTILS_LIBRARY} ) | |||
Set ( CPPUTILS_INCLUDE_DIRS ${CPPUTILS_INCLUDE_DIR} ) | |||
File ( MAKE_DIRECTORY ${CPPUTILS_INCLUDE_DIR} ) | |||
Find_Package_Handle_Standard_Args ( cpputils DEFAULT_MSG | |||
CPPUTILS_LIBRARY | |||
CPPUTILS_INCLUDE_DIR ) | |||
If ( NOT TARGET cpputils ) | |||
Add_Library ( cpputils SHARED IMPORTED ) | |||
Add_Dependencies ( cpputils cpputils_extern ) | |||
Set_Property ( TARGET cpputils | |||
PROPERTY IMPORTED_LOCATION ${CPPUTILS_LIBRARY} ) | |||
Set_Property ( TARGET cpputils | |||
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CPPUTILS_INCLUDE_DIRS} ) | |||
Install ( FILES ${CPPUTILS_LIBRARY} DESTINATION lib ) | |||
If ( CPPMARIADB_INSTALL_DEV_FILES ) | |||
Install ( DIRECTORY ${CPPUTILS_INCLUDE_DIR}/ DESTINATION include ) | |||
EndIf ( ) | |||
EndIf ( ) |
@@ -1,34 +0,0 @@ | |||
Find_Library ( MARIADB_LIBRARY | |||
NAMES mariadb mysql | |||
PATH_SUFFIXES mariadb ) | |||
Find_File ( MARIADB_INCLUDE_DIR | |||
NAMES mysql.h | |||
PATH_SUFFIXES mariadb ) | |||
Get_Filename_Component ( MARIADB_INCLUDE_DIR | |||
${MARIADB_INCLUDE_DIR} | |||
DIRECTORY ) | |||
Include ( FindPackageHandleStandardArgs ) | |||
Find_Package_Handle_Standard_Args ( mariadb DEFAULT_MSG | |||
MARIADB_LIBRARY | |||
MARIADB_INCLUDE_DIR ) | |||
Mark_As_Advanced ( MARIADB_LIBRARY | |||
MARIADB_LIBRARIES ) | |||
If ( MARIADB_FOUND ) | |||
Set ( MARIADB_LIBRARIES ${MARIADB_LIBRARY} ) | |||
Set ( MARIADB_INCLUDE_DIRS ${MARIADB_INCLUDE_DIR} ) | |||
If ( NOT TARGET mariadb ) | |||
Add_Library ( mariadb UNKNOWN IMPORTED ) | |||
Set_Property ( TARGET mariadb | |||
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MARIADB_INCLUDE_DIRS}" ) | |||
Set_Property ( TARGET mariadb | |||
APPEND | |||
PROPERTY IMPORTED_LOCATION "${MARIADB_LIBRARY}") | |||
EndIf ( ) | |||
EndIf ( ) |
@@ -0,0 +1,36 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <mariadb/mysql.h> | |||
#include <mariadb/errmsg.h> | |||
#include <mariadb/mysqld_error.h> | |||
#cmakedefine CPPMARIADB_HAS_CPPLOGGING | |||
#ifdef CPPMARIADB_HAS_CPPLOGGING | |||
#include <cpplogging/interface.h> | |||
#define cppmariadb_log(p_level) \ | |||
cpplogging_global_log(p_level) | |||
#else | |||
#include <iostream> | |||
#define cppmariadb_log(p_level) \ | |||
::std::cout << #p_level << ' ' << __FILE__ << ':' << __LINE__ << " - " | |||
#endif | |||
/* pre declarations */ | |||
namespace cppmariadb | |||
{ | |||
struct column; | |||
struct connection; | |||
struct database; | |||
struct field; | |||
struct result; | |||
struct result_stored; | |||
struct result_used; | |||
struct row; | |||
struct statement; | |||
struct transaction; | |||
using column_vector = std::vector<column>; | |||
} |
@@ -0,0 +1,10 @@ | |||
# cppmariadb-config.cmake - package configuration file | |||
Message ( WARNING "Please configure the dependencies of this package!" ) | |||
# Include ( CMakeFindDependencyMacro ) | |||
# Find_Dependency ( <dependency> ) | |||
Include ( FindPackageHandleStandardArgs ) | |||
Set ( ${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE} ) | |||
Find_Package_Handle_Standard_Args ( cppmariadb CONFIG_MODE ) | |||
Include ( "${CMAKE_CURRENT_LIST_DIR}/cppmariadb.cmake") |
@@ -0,0 +1,15 @@ | |||
Option ( CPPMARIADB_INSTALL_HEADER | |||
"Install headers of cppmariadb." | |||
ON ) | |||
Option ( CPPMARIADB_INSTALL_STATIC | |||
"Install static library of cppmariadb." | |||
ON ) | |||
Option ( CPPMARIADB_INSTALL_SHARED | |||
"Install shared library of cppmariadb." | |||
ON ) | |||
Option ( CPPMARIADB_INSTALL_DEBUG | |||
"Install the stripped debug informations of cppmariadb." | |||
OFF ) | |||
Option ( CPPMARIADB_NO_STRIP | |||
"Do not strip debug symbols from binary." | |||
OFF ) |
@@ -0,0 +1,31 @@ | |||
# Version | |||
Set ( CPPMARIADB_VERSION_MAJOR 1 ) | |||
Set ( CPPMARIADB_VERSION_MINOR 0 ) | |||
Set ( CPPMARIADB_VERSION_PATCH 0 ) | |||
Set ( CPPMARIADB_VERSION_BUILD 0 ) | |||
Set ( CPPMARIADB_VERSION_SHORT "${CPPMARIADB_VERSION_MAJOR}.${CPPMARIADB_VERSION_MINOR}" ) | |||
Set ( CPPMARIADB_VERSION "${CPPMARIADB_VERSION_SHORT}.${CPPMARIADB_VERSION_PATCH}.${CPPMARIADB_VERSION_BUILD}" ) | |||
Set ( CPPMARIADB_NAME "cppmariadb-${CPPMARIADB_VERSION_SHORT}" ) | |||
Set ( CPPMARIADB_OUTPUTNAME "cppmariadb" ) | |||
# Install directories | |||
Set ( CPPMARIADB_INSTALL_DIR_INCLUDE "include/${CPPMARIADB_NAME}" ) | |||
Set ( CPPMARIADB_INSTALL_DIR_LIB "lib" ) | |||
Set ( CPPMARIADB_INSTALL_DIR_SHARE "share/${CPPMARIADB_NAME}" ) | |||
# C Standard | |||
Set ( CMAKE_C_STANDARD 11 ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_C_STANDARD_REQUIRED ON ) | |||
Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) | |||
# Git Version | |||
Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) | |||
If ( HAS_GIT_HELPER ) | |||
GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. | |||
CPPMARIADB_VERSION_MAJOR | |||
CPPMARIADB_VERSION_MINOR | |||
CPPMARIADB_VERSION_PATCH | |||
CPPMARIADB_VERSION_BUILD | |||
CPPMARIADB_VERSION_HASH ) | |||
EndIf ( ) |
@@ -1,6 +0,0 @@ | |||
Option ( CPPMARIADB_BUILD_SHARED | |||
"Build cppmariadb shared library" | |||
ON ) | |||
Option ( CPPMARIADB_INSTALL_DEV_FILES | |||
"Install development files of cppmariadb" | |||
ON ) |
@@ -1,20 +1,23 @@ | |||
#pragma once | |||
#include <cppmariadb/column.h> | |||
#include <cppmariadb/connection.h> | |||
#include <cppmariadb/database.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/exception.h> | |||
#include <cppmariadb/field.h> | |||
#include <cppmariadb/result.h> | |||
#include <cppmariadb/row.h> | |||
#include <cppmariadb/statement.h> | |||
#include <cppmariadb/transaction.h> | |||
#include "cppmariadb/exception.h" | |||
#include "cppmariadb/column.h" | |||
#include "cppmariadb/enums.h" | |||
#include "cppmariadb/transaction.h" | |||
#include "cppmariadb/connection.h" | |||
#include "cppmariadb/result.h" | |||
#include "cppmariadb/config.h" | |||
#include "cppmariadb/impl/handle.h" | |||
#include "cppmariadb/row.h" | |||
#include "cppmariadb/field.h" | |||
#include "cppmariadb/statement.h" | |||
#include <cppmariadb/inline/connection.inl> | |||
#include <cppmariadb/inline/database.inl> | |||
#include <cppmariadb/inline/field.inl> | |||
#include <cppmariadb/inline/result.inl> | |||
#include <cppmariadb/inline/row.inl> | |||
#include <cppmariadb/inline/statement.inl> | |||
#include <cppmariadb/inline/transaction.inl> | |||
#include "cppmariadb/statement.inl" | |||
#include "cppmariadb/exception.inl" | |||
#include "cppmariadb/row.inl" | |||
#include "cppmariadb/column.inl" | |||
#include "cppmariadb/connection.inl" | |||
#include "cppmariadb/field.inl" | |||
#include "cppmariadb/impl/handle.inl" | |||
#include "cppmariadb/result.inl" | |||
#include "cppmariadb/transaction.inl" |
@@ -1,41 +1,31 @@ | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/forward/column.h> | |||
namespace cppmariadb | |||
{ | |||
struct column | |||
{ | |||
std::string name; | |||
std::string original_name; | |||
std::string table; | |||
std::string original_table; | |||
std::string database; | |||
unsigned long length; | |||
unsigned long max_length; | |||
column_flags flags; | |||
unsigned int decimals; | |||
unsigned int charset_number; | |||
column_type type; | |||
std::string name; //!< Name of the column. | |||
std::string original_name; //!< Original name of the column (if not renamed) | |||
std::string table; //!< Name of the table. | |||
std::string original_table; //!< Original name of the table (if not renamed) | |||
std::string database; //!< Name of the database. | |||
unsigned long length; //!< Length of the column. | |||
unsigned long max_length; //!< Maximal length of the column. | |||
column_flags flags; //!< Column flags. | |||
unsigned int decimals; //!< Decimals | |||
unsigned int charset_number; //!< Cahrset numbers. | |||
column_type type; //!< Column type. | |||
inline column(MYSQL_FIELD& f) | |||
: name (f.name, f.name_length) | |||
, original_name (f.org_name, f.org_name_length) | |||
, table (f.table, f.table_length) | |||
, original_table(f.org_table, f.org_table_length) | |||
, database (f.db, f.db_length) | |||
, length (f.length) | |||
, max_length (f.max_length) | |||
, flags (f.flags) | |||
, decimals (f.decimals) | |||
, charset_number(f.charsetnr) | |||
, type (static_cast<column_type>(f.type)) | |||
{ } | |||
/** | |||
* @brief Value constructor. Create a column object from the mariadb fields handle. | |||
*/ | |||
inline column(MYSQL_FIELD& f); | |||
}; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
#pragma once | |||
#include "column.h" | |||
namespace cppmariadb | |||
{ | |||
column::column(MYSQL_FIELD& f) | |||
: name (f.name, f.name_length) | |||
, original_name (f.org_name, f.org_name_length) | |||
, table (f.table, f.table_length) | |||
, original_table(f.org_table, f.org_table_length) | |||
, database (f.db, f.db_length) | |||
, length (f.length) | |||
, max_length (f.max_length) | |||
, flags (f.flags) | |||
, decimals (f.decimals) | |||
, charset_number(f.charsetnr) | |||
, type (static_cast<column_type>(f.type)) | |||
{ } | |||
} |
@@ -1,7 +0,0 @@ | |||
#pragma once | |||
#ifndef MARIADB_MOCK | |||
#include <mariadb/mysql.h> | |||
#include <mariadb/errmsg.h> | |||
#include <mariadb/mysqld_error.h> | |||
#endif |
@@ -1,50 +1,213 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/impl/mariadb_handle.h> | |||
#include <cppmariadb/forward/connection.h> | |||
#include <cppmariadb/forward/result.h> | |||
#include <cppmariadb/forward/statement.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/impl/handle.h> | |||
namespace cppmariadb | |||
{ | |||
/** | |||
* @brief MariaDB connection. | |||
*/ | |||
struct connection | |||
: public __impl::mariadb_handle<MYSQL*> | |||
: public __impl::handle<MYSQL*> | |||
{ | |||
private: | |||
using result_t = ::cppmariadb::result; | |||
std::unique_ptr<result_t> _result; | |||
using result_t = ::cppmariadb::result; | |||
using result_ptr_u = std::unique_ptr<result_t>; | |||
template<class T> | |||
typename T::result_type* execute_internal(const std::string& cmd); | |||
result_ptr_u _result; //!< REsult of the last query. | |||
public: | |||
inline void execute (const std::string& cmd); | |||
inline unsigned long long execute_id (const std::string& cmd); | |||
inline unsigned long long execute_rows (const std::string& cmd); | |||
inline result_stored* execute_stored (const std::string& cmd); | |||
inline result_used* execute_used (const std::string& cmd); | |||
inline void execute (const statement& s); | |||
inline unsigned long long execute_id (const statement& s); | |||
inline unsigned long long execute_rows (const statement& s); | |||
inline result_stored* execute_stored (const statement& s); | |||
inline result_used* execute_used (const statement& s); | |||
inline result_t* result () const; | |||
inline uint fieldcount () const; | |||
inline std::string escape (const std::string& value) const; | |||
inline void close (); | |||
inline connection& operator =(connection&& other); | |||
/** | |||
* @breif Default constructor. | |||
*/ | |||
inline connection(); | |||
/** | |||
* @brief Value constructor. Creates a new connection using the mariadb handle. | |||
*/ | |||
inline connection(MYSQL* h); | |||
/** | |||
* @brief Move constructor. | |||
*/ | |||
inline connection(connection&& other); | |||
/** | |||
* @brief Copy constructor. | |||
*/ | |||
inline connection(const connection& other) = delete; | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
inline ~connection(); | |||
/** | |||
* @brief Move assignment constructor. | |||
*/ | |||
inline connection& operator =(connection&& other); | |||
/** | |||
* @brief Copy assignment constructor. | |||
*/ | |||
inline connection& operator =(const connection& other) = delete; | |||
public: /* misc */ | |||
/** | |||
* @brief Connect to the database. | |||
* | |||
* @param[in] host Host to connect to. | |||
* @param[in] port Port to connect to. | |||
* @param[in] user User to use for authentication. | |||
* @param[in] password Password to use for authentication. | |||
* @param[in] database Default database to connect to. | |||
* @param[in] flags Connection flags. | |||
*/ | |||
inline void connect( | |||
const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags); | |||
/** | |||
* @brief Close this connection. | |||
*/ | |||
inline void close(); | |||
/** | |||
* @brief Get the result of the last executed query. | |||
*/ | |||
inline result_t* result() const; | |||
/** | |||
* @brief Get the field count of the last executed query. | |||
*/ | |||
inline uint fieldcount() const; | |||
/** | |||
* @brief Get the error code of the last executed operation. | |||
*/ | |||
inline error_code error_code() const; | |||
/** | |||
* @brief Get the error code of the last executed operation. | |||
*/ | |||
inline std::string error_msg() const; | |||
/** | |||
* @brief Escape the passed string. | |||
* | |||
* @param[in] value String to escape. | |||
* | |||
* @return Escaped string. | |||
*/ | |||
inline std::string escape(const std::string& value) const; | |||
public: /* execute query */ | |||
/** | |||
* @brief Execute the passed query. | |||
* | |||
* @param[in] cmd Query to execute. | |||
*/ | |||
inline void execute(const std::string& cmd); | |||
/** | |||
* @brief Execute the passed query. | |||
* | |||
* @param[in] cmd Query to execute. | |||
* | |||
* @return ID of the inserted/updated/effected row. | |||
*/ | |||
inline unsigned long long execute_id(const std::string& cmd); | |||
/** | |||
* @brief Execute the passed query. | |||
* | |||
* @param[in] cmd Query to execute. | |||
* | |||
* @return Number of affected rows. | |||
*/ | |||
inline unsigned long long execute_rows(const std::string& cmd); | |||
/** | |||
* @brief Execute the passed query. | |||
* | |||
* @param[in] cmd Query to execute. | |||
* | |||
* @return Stored result or nullptr if the query could not be executed. | |||
*/ | |||
inline result_stored* execute_stored(const std::string& cmd); | |||
/** | |||
* @brief Execute the passed query. | |||
* | |||
* @param[in] cmd Query to execute. | |||
* | |||
* @return Used result or nullptr if the query could not be executed. | |||
*/ | |||
inline result_used* execute_used(const std::string& cmd); | |||
public: /* execute statement */ | |||
/** | |||
* @brief Render and execute the passed statement. | |||
* | |||
* @param[in] s Statement to render and execute. | |||
*/ | |||
inline void execute(const statement& s); | |||
/** | |||
* @brief Render and execute the passed statement. | |||
* | |||
* @param[in] s Statement to render and execute. | |||
* | |||
* @return ID of the inserted/updated/effected row. | |||
*/ | |||
inline unsigned long long execute_id(const statement& s); | |||
/** | |||
* @brief Render and execute the passed statement. | |||
* | |||
* @param[in] s Statement to render and execute. | |||
* | |||
* @return Number of affected rows. | |||
*/ | |||
inline unsigned long long execute_rows(const statement& s); | |||
/** | |||
* @brief Render and execute the passed statement. | |||
* | |||
* @param[in] s Statement to render and execute. | |||
* | |||
* @return Stored result of nullptr if the query could not be executed. | |||
*/ | |||
inline result_stored* execute_stored(const statement& s); | |||
/** | |||
* @brief Render and execute the passed statement. | |||
* | |||
* @param[in] s Statement to render and execute. | |||
* | |||
* @return Used result of nullptr if the query could not be executed. | |||
*/ | |||
inline result_used* execute_used(const statement& s); | |||
private: | |||
/** | |||
* @brief Execute the passed query and return the suitable result type. | |||
* | |||
* @tparam T Traits type that is used to execute the query and contains the result type. | |||
* | |||
* @param[in] cmd Query to execute. | |||
*/ | |||
template<class T> | |||
typename T::result_type* execute_internal(const std::string& cmd); | |||
}; | |||
} | |||
} |
@@ -0,0 +1,185 @@ | |||
#pragma once | |||
#include "connection.h" | |||
namespace cppmariadb | |||
{ | |||
/* op_store_result ***************************************************************************/ | |||
struct op_store_result | |||
{ | |||
using result_type = result_stored; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_store_result(handle); } | |||
}; | |||
/* op_use_result *****************************************************************************/ | |||
struct op_use_result | |||
{ | |||
using result_type = result_used; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_use_result(handle); } | |||
}; | |||
/* connection ********************************************************************************/ | |||
connection::connection() | |||
: connection(nullptr) | |||
{ | |||
auto h = mysql_init(nullptr); | |||
if (!h) | |||
throw exception("unable to initialize connection handle", error_code::Unknown); | |||
set_handle(h); | |||
} | |||
connection::connection(MYSQL* h) | |||
: handle(h) | |||
{ } | |||
connection::connection(connection&& other) | |||
: handle(std::move(other)) | |||
, _result (std::move(other)._result) | |||
{ } | |||
connection::~connection() | |||
{ close(); } | |||
connection& connection::operator =(connection&& other) | |||
{ | |||
close(); | |||
set_handle(other.get_handle()); | |||
other.set_handle(nullptr); | |||
return *this; | |||
} | |||
void connection::connect( | |||
const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags) | |||
{ | |||
if (!mysql_real_connect( | |||
get_handle(), | |||
host.c_str(), | |||
user.c_str(), | |||
password.c_str(), | |||
database.empty() ? static_cast<const char*>(nullptr) : database.c_str(), | |||
port, | |||
nullptr, | |||
flags.value)) | |||
throw exception(error_msg(), error_code()); | |||
} | |||
void connection::close() | |||
{ | |||
_result.reset(); | |||
auto h = get_handle(); | |||
if (h) | |||
mysql_close(h); | |||
} | |||
result* connection::result() const | |||
{ return _result.get(); } | |||
uint connection::fieldcount() const | |||
{ return mysql_field_count(get_handle()); } | |||
error_code connection::error_code() const | |||
{ | |||
auto ret = mysql_errno(get_handle()); | |||
return static_cast<enum error_code>(ret); | |||
} | |||
std::string connection::error_msg() const | |||
{ | |||
auto ret = mysql_error(get_handle()); | |||
return (ret ? std::string(ret) : std::string()); | |||
} | |||
std::string connection::escape(const std::string& value) const | |||
{ | |||
if (get_handle()) | |||
{ | |||
std::string ret; | |||
ret.resize(2 * value.size() + 1); | |||
auto len = mysql_real_escape_string( | |||
get_handle(), | |||
const_cast<char*>(ret.data()), | |||
value.c_str(), | |||
value.size()); | |||
ret.resize(len); | |||
return ret; | |||
} | |||
return value; | |||
} | |||
template<class T> | |||
typename T::result_type* connection::execute_internal(const std::string& cmd) | |||
{ | |||
cppmariadb_log(debug) << "execute cppmariadb query: " << std::endl << cmd; | |||
if (!get_handle()) | |||
throw exception("invalid handle", error_code::Unknown, cmd); | |||
using result_type = typename T::result_type; | |||
_result.reset(); | |||
if (mysql_real_query(*this, cmd.data(), cmd.size()) != 0) | |||
throw exception(error_msg(), error_code(), cmd); | |||
auto ret = T()(*this); | |||
if (!ret) | |||
{ | |||
if (mysql_field_count(*this) > 0) | |||
throw exception(error_msg(), error_code(), cmd); | |||
return nullptr; | |||
} | |||
_result.reset(new result_type(ret)); | |||
return static_cast<result_type*>(_result.get()); | |||
} | |||
void connection::execute(const std::string& cmd) | |||
{ execute_internal<op_store_result>(cmd); } | |||
unsigned long long connection::execute_id(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto id = mysql_insert_id(*this); | |||
if (id == static_cast<unsigned long long>(-1)) | |||
throw exception(error_msg(), error_code(), cmd); | |||
return id; | |||
} | |||
unsigned long long connection::execute_rows(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto rows = mysql_affected_rows(*this); | |||
if (rows == static_cast<unsigned long long>(-1)) | |||
throw exception(error_msg(), error_code(), cmd); | |||
return rows; | |||
} | |||
result_stored* connection::execute_stored(const std::string& cmd) | |||
{ return execute_internal<op_store_result>(cmd); } | |||
result_used* connection::execute_used(const std::string& cmd) | |||
{ return execute_internal<op_use_result>(cmd); } | |||
void connection::execute(const statement& s) | |||
{ return execute(s.query(*this)); } | |||
unsigned long long connection::execute_id(const statement& s) | |||
{ return execute_id(s.query(*this)); } | |||
unsigned long long connection::execute_rows(const statement& s) | |||
{ return execute_rows(s.query(*this)); } | |||
result_stored* connection::execute_stored(const statement& s) | |||
{ return execute_stored(s.query(*this)); } | |||
result_used* connection::execute_used(const statement& s) | |||
{ return execute_used(s.query(*this)); } | |||
} |
@@ -1,25 +0,0 @@ | |||
#pragma once | |||
#include <string> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/forward/connection.h> | |||
namespace cppmariadb | |||
{ | |||
struct database | |||
{ | |||
using error_code_t = ::cppmariadb::error_code; | |||
static inline connection connect (const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags); | |||
static inline error_code_t error_code (MYSQL* handle); | |||
static inline std::string error_msg (MYSQL* handle); | |||
}; | |||
} |
@@ -1,8 +1,8 @@ | |||
#pragma once | |||
#include <limits> | |||
#include <cppcore/misc/flags.h> | |||
#include <cppmariadb/config.h> | |||
#include <cpputils/misc/flags.h> | |||
namespace cppmariadb | |||
{ | |||
@@ -63,7 +63,7 @@ namespace cppmariadb | |||
Group = GROUP_FLAG, /* Intern: Group field */ | |||
Unique = UNIQUE_FLAG, /* Intern: Used by sql_yacc */ | |||
}; | |||
using column_flags = utl::simple_flags<column_flag>; | |||
using column_flags = ::cppcore::simple_flags<column_flag>; | |||
enum class client_flag : uint | |||
{ | |||
@@ -92,7 +92,7 @@ namespace cppmariadb | |||
SessionTracking = CLIENT_SESSION_TRACKING, | |||
ConnectAttrs = CLIENT_CONNECT_ATTRS, | |||
}; | |||
using client_flags = utl::simple_flags<client_flag>; | |||
using client_flags = ::cppcore::simple_flags<client_flag>; | |||
enum class error_code : uint | |||
{ | |||
@@ -1227,4 +1227,4 @@ namespace cppmariadb | |||
ClientBulkWithoutParameters = /* 5006 */ CR_BULK_WITHOUT_PARAMETERS, | |||
}; | |||
} | |||
} |
@@ -1,26 +1,45 @@ | |||
#pragma once | |||
#include <cppcore/misc/exception.h> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cpputils/misc/exception.h> | |||
namespace cppmariadb | |||
{ | |||
struct exception : public utl::exception | |||
/** | |||
* @brief Exception class used for all mariadb errors. | |||
*/ | |||
struct exception | |||
: public ::cppcore::exception | |||
{ | |||
protected: | |||
void print_message(std::ostream& os) const override; | |||
public: | |||
error_code error; //!< Error code. | |||
std::string query; //!< Erroneous query. | |||
public: | |||
error_code error; | |||
std::string query; | |||
inline exception(const std::string& msg, error_code err, const std::string& q = std::string()) | |||
: utl::exception(msg) | |||
, error (err) | |||
, query (q) | |||
{ } | |||
/** | |||
* @brief Constructor. Create an exception object. | |||
* | |||
* @param[in] msg Exception message. | |||
* @param[in] err Error code. | |||
* @param[in] q Erroneous query. | |||
*/ | |||
inline exception( | |||
const std::string& msg, | |||
error_code err, | |||
const std::string& q = std::string()); | |||
protected: | |||
/** | |||
* @brief Print the message of the exception to the passed stream. | |||
* | |||
* @param[in] os Stream to print message of the exception to. | |||
*/ | |||
void print_message(std::ostream& os) const override; | |||
}; | |||
} | |||
} | |||
#include "exception.inl" |
@@ -0,0 +1,17 @@ | |||
#pragma once | |||
#include "exception.h" | |||
namespace cppmariadb | |||
{ | |||
exception::exception( | |||
const std::string& msg, | |||
error_code err, | |||
const std::string& q) | |||
: cppcore::exception(msg) | |||
, error (err) | |||
, query (q) | |||
{ } | |||
} |
@@ -1,36 +1,86 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/forward/column.h> | |||
#include <cppmariadb/forward/field.h> | |||
#include <cppmariadb/forward/row.h> | |||
#include <cppmariadb/impl/handle.h> | |||
namespace cppmariadb | |||
{ | |||
/** | |||
* @brief Represents a field from a row of a result. | |||
* The filed contains the requested data. | |||
*/ | |||
struct field | |||
{ | |||
private: | |||
using column_t = ::cppmariadb::column; | |||
const row& _row; | |||
const size_t _index; | |||
const char* _data; | |||
size_t _size; | |||
const row& _row; //!< Row this field belongs to. | |||
const size_t _index; //!< Index of the field inside the row. | |||
const char* _data; //!< Data stored in this field. | |||
size_t _size; //!< Number of bytes stored in _data. | |||
public: | |||
inline size_t index () const; | |||
inline const column_t& column () const; | |||
inline bool is_null () const; | |||
inline bool is_empty() const; | |||
inline const char* data () const; | |||
inline size_t size () const; | |||
inline operator bool () const; | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_row Row this field belongs to. | |||
* @param[in] p_index Index of this field inside the row. | |||
* @param[in] p_data Data of this field. | |||
* @param[in] p_size Number of bytes stored in p_data. | |||
*/ | |||
inline field( | |||
const row& p_row, | |||
size_t p_index, | |||
const char* p_data, | |||
size_t p_size); | |||
/** | |||
* @brief Return the index of the filed inside the row. | |||
*/ | |||
inline size_t index() const; | |||
/** | |||
* @brief Returns the column this field represents. | |||
*/ | |||
inline const column_t& column() const; | |||
/** | |||
* @brief Check if the field is null. | |||
* | |||
* @retval true If the value is null. | |||
* @retval false If the value is not null. | |||
*/ | |||
inline bool is_null() const; | |||
/** | |||
* @brief Check if the fiel is empty. | |||
* | |||
* @retval true If the value is null. | |||
* @retval false If the value is not null. | |||
*/ | |||
inline bool is_empty() const; | |||
/** | |||
* @brief Get the data stored in this field. | |||
*/ | |||
inline const char* data() const; | |||
/** | |||
* @brief Return the number of bytes stored in data(). | |||
*/ | |||
inline size_t size() const; | |||
/** | |||
* @brief Imlicit cast to bool (is not null and not empty). | |||
*/ | |||
inline operator bool() const; | |||
/** | |||
* @brief Convert the stored data of this field to the requested type. | |||
*/ | |||
template <class T> | |||
inline T get() const; | |||
inline field(const row& r, size_t i, const char* d, size_t s); | |||
}; | |||
} | |||
} |
@@ -1,9 +1,12 @@ | |||
#pragma once | |||
#include <cppmariadb/row.h> | |||
#include <cppmariadb/field.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
#include <cppcore/conversion/string.h> | |||
#include "enums.h" | |||
#include "field.h" | |||
#include "exception.h" | |||
#include "column.inl" | |||
namespace cppmariadb | |||
{ | |||
@@ -20,7 +23,7 @@ namespace cppmariadb | |||
{ | |||
T tmp; | |||
std::string data(c, s); | |||
if (!utl::try_from_string(data, tmp)) | |||
if (!cppcore::try_from_string(data, tmp)) | |||
throw exception(std::string("unable to convert field data (data=") + data + ")", error_code::UnknownError); | |||
return tmp; | |||
} | |||
@@ -42,40 +45,44 @@ namespace cppmariadb | |||
/* field *************************************************************************************/ | |||
inline size_t field::index() const | |||
field::field( | |||
const row& p_row, | |||
size_t p_index, | |||
const char* p_data, | |||
size_t p_size) | |||
: _row (p_row) | |||
, _index(p_index) | |||
, _data (p_data) | |||
, _size (p_size) | |||
{ } | |||
size_t field::index() const | |||
{ return _index; } | |||
inline const column& field::column() const | |||
const column& field::column() const | |||
{ return _row.columns().at(_index); } | |||
inline bool field::is_null() const | |||
bool field::is_null() const | |||
{ return (_data == nullptr); } | |||
inline bool field::is_empty() const | |||
bool field::is_empty() const | |||
{ return (_size == 0); } | |||
inline const char* field::data() const | |||
const char* field::data() const | |||
{ return _data; } | |||
inline size_t field::size() const | |||
size_t field::size() const | |||
{ return _size; } | |||
template <class T> | |||
inline T field::get() const | |||
T field::get() const | |||
{ | |||
if (is_null()) | |||
throw exception("field is null", error_code::UnknownError); | |||
return op_field_converter<T>()(_data, _size); | |||
} | |||
inline field::operator bool() const | |||
field::operator bool() const | |||
{ return !is_null() && !is_empty(); } | |||
inline field::field(const row& r, size_t i, const char* d, size_t s) | |||
: _row (r) | |||
, _index(i) | |||
, _data (d) | |||
, _size (s) | |||
{ } | |||
} | |||
} |
@@ -1,13 +0,0 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct column; | |||
using column_vector = std::vector<column>; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct connection; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct database; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct field; | |||
} |
@@ -1,14 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct result; | |||
struct result_used; | |||
struct result_stored; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct row; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct statement; | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb | |||
{ | |||
struct transaction; | |||
} |
@@ -0,0 +1,48 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb { | |||
namespace __impl { | |||
/** | |||
* @brief Wrap any mariadb library handle. | |||
* | |||
* @tparam T Handle to wrap. | |||
*/ | |||
template<class T> | |||
struct handle | |||
{ | |||
private: | |||
T _handle; //!< Handle of mariadb library. | |||
public: | |||
/** | |||
* @brief Value constructor. Initialize the object with the given mariadb handle. | |||
*/ | |||
inline handle(T h); | |||
/** | |||
* @brief Move constructor. Move the handle stored in the other object to this object. | |||
*/ | |||
inline handle(handle&& other); | |||
public: | |||
/** | |||
* @brief Operator to implicit convert the handle object to its underlying mariadb handle. | |||
*/ | |||
inline operator T() const; | |||
/** | |||
* @brief Get the handle stored in this object. | |||
*/ | |||
inline const T& get_handle() const; | |||
protected: | |||
/** | |||
* @brief Set the handle. | |||
*/ | |||
inline void set_handle(T h); | |||
}; | |||
} } |
@@ -0,0 +1,30 @@ | |||
#pragma once | |||
#include "handle.h" | |||
namespace cppmariadb { | |||
namespace __impl { | |||
template<typename T> | |||
handle<T>::handle(T h) | |||
: _handle(h) | |||
{ }; | |||
template<typename T> | |||
handle<T>::handle(handle&& other) | |||
: _handle(other._handle) | |||
{ other._handle = nullptr; } | |||
template<typename T> | |||
handle<T>::operator T() const | |||
{ return _handle; } | |||
template<typename T> | |||
const T& handle<T>::get_handle() const | |||
{ return _handle; } | |||
template<typename T> | |||
void handle<T>::set_handle(T h) | |||
{ _handle = h; } | |||
} } |
@@ -1,38 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
namespace cppmariadb { | |||
namespace __impl | |||
{ | |||
template<class T> | |||
struct mariadb_handle | |||
{ | |||
private: | |||
T _handle; | |||
protected: | |||
inline void handle(T h) | |||
{ _handle = h; } | |||
public: | |||
inline operator T() const | |||
{ return _handle; } | |||
inline const T& handle() const | |||
{ return _handle; } | |||
mariadb_handle(T h) : | |||
_handle(h) | |||
{ }; | |||
mariadb_handle(mariadb_handle&& other) : | |||
_handle(other._handle) | |||
{ other._handle = nullptr; } | |||
private: | |||
mariadb_handle(const mariadb_handle&) = delete; | |||
}; | |||
} } |
@@ -1,152 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/result.h> | |||
#include <cppmariadb/connection.h> | |||
#include <cppmariadb/inline/result.inl> | |||
#include <cppmariadb/inline/database.inl> | |||
#include <cppmariadb/inline/statement.inl> | |||
namespace cppmariadb | |||
{ | |||
/* op_store_result ***************************************************************************/ | |||
struct op_store_result | |||
{ | |||
using result_type = result_stored; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_store_result(handle); } | |||
}; | |||
/* op_use_result *****************************************************************************/ | |||
struct op_use_result | |||
{ | |||
using result_type = result_used; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_use_result(handle); } | |||
}; | |||
/* connection ********************************************************************************/ | |||
template<class T> | |||
typename T::result_type* connection::execute_internal(const std::string& cmd) | |||
{ | |||
#ifdef MARIADB_DEBUG | |||
log_global_message(debug) << "execute cppmariadb query: " << std::endl << cmd; | |||
#endif | |||
if (!handle()) | |||
throw exception("invalid handle", error_code::Unknown, cmd); | |||
using result_type = typename T::result_type; | |||
_result.reset(); | |||
if (mysql_real_query(*this, cmd.data(), cmd.size()) != 0) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
auto ret = T()(*this); | |||
if (!ret) | |||
{ | |||
if (mysql_field_count(*this) > 0) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return nullptr; | |||
} | |||
_result.reset(new result_type(ret)); | |||
return static_cast<result_type*>(_result.get()); | |||
} | |||
inline void connection::execute(const std::string& cmd) | |||
{ execute_internal<op_store_result>(cmd); } | |||
inline unsigned long long connection::execute_id(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto id = mysql_insert_id(*this); | |||
if (id == static_cast<unsigned long long>(-1)) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return id; | |||
} | |||
inline unsigned long long connection::execute_rows(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto rows = mysql_affected_rows(*this); | |||
if (rows == static_cast<unsigned long long>(-1)) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return rows; | |||
} | |||
inline result_stored* connection::execute_stored(const std::string& cmd) | |||
{ return execute_internal<op_store_result>(cmd); } | |||
inline result_used* connection::execute_used(const std::string& cmd) | |||
{ return execute_internal<op_use_result>(cmd); } | |||
inline void connection::execute(const statement& s) | |||
{ return execute(s.query(*this)); } | |||
inline unsigned long long connection::execute_id(const statement& s) | |||
{ return execute_id(s.query(*this)); } | |||
inline unsigned long long connection::execute_rows(const statement& s) | |||
{ return execute_rows(s.query(*this)); } | |||
inline result_stored* connection::execute_stored(const statement& s) | |||
{ return execute_stored(s.query(*this)); } | |||
inline result_used* connection::execute_used(const statement& s) | |||
{ return execute_used(s.query(*this)); } | |||
inline result* connection::result() const | |||
{ return _result.get(); } | |||
inline uint connection::fieldcount() const | |||
{ return mysql_field_count(handle()); } | |||
inline std::string connection::escape(const std::string& value) const | |||
{ | |||
if (handle()) | |||
{ | |||
std::string ret; | |||
ret.resize(2 * value.size() + 1); | |||
auto len = mysql_real_escape_string(handle(), const_cast<char*>(ret.data()), value.c_str(), value.size()); | |||
ret.resize(len); | |||
return ret; | |||
} | |||
return value; | |||
} | |||
inline void connection::close() | |||
{ | |||
_result.reset(); | |||
auto h = handle(); | |||
handle(nullptr); | |||
if (h) | |||
mysql_close(h); | |||
} | |||
inline connection& connection::operator =(connection&& other) | |||
{ | |||
close(); | |||
handle(other.handle()); | |||
other.handle(nullptr); | |||
return *this; | |||
} | |||
inline connection::connection() | |||
: connection(nullptr) | |||
{ } | |||
inline connection::connection(MYSQL* h) | |||
: mariadb_handle(h) | |||
{ } | |||
inline connection::connection(connection&& other) | |||
: mariadb_handle(std::move(other)) | |||
, _result (std::move(other)._result) | |||
{ } | |||
inline connection::~connection() | |||
{ close(); } | |||
} |
@@ -1,48 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/database.h> | |||
namespace cppmariadb | |||
{ | |||
/* database ***********************************************************************************/ | |||
inline connection database::connect( | |||
const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags) | |||
{ | |||
auto handle = mysql_init(nullptr); | |||
if (!handle) | |||
throw exception("unable to initialize connection handle", error_code::Unknown); | |||
if (!mysql_real_connect( | |||
handle, | |||
host.c_str(), | |||
user.c_str(), | |||
password.c_str(), | |||
database.empty() ? static_cast<const char*>(nullptr) : database.c_str(), | |||
port, | |||
nullptr, | |||
flags.value)) | |||
throw exception(database::error_msg(handle), database::error_code(handle)); | |||
return connection(handle); | |||
} | |||
inline error_code database::error_code(MYSQL* handle) | |||
{ | |||
auto ret = mysql_errno(handle); | |||
return static_cast<enum error_code>(ret); | |||
} | |||
inline std::string database::error_msg(MYSQL* handle) | |||
{ | |||
auto ret = mysql_error(handle); | |||
return (ret ? std::string(ret) : std::string()); | |||
} | |||
} |
@@ -1,72 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/result.h> | |||
namespace cppmariadb | |||
{ | |||
/* result ************************************************************************************/ | |||
inline void result::rowindex(unsigned long long value) | |||
{ _rowindex = value; } | |||
inline unsigned int result::columncount() const | |||
{ return mysql_num_fields(*this); } | |||
inline const column_vector& result::columns() const | |||
{ | |||
if (_columns.empty()) | |||
update_columns(); | |||
return _columns; | |||
} | |||
inline row* result::current() const | |||
{ return _row.get(); } | |||
inline unsigned long long result::rowindex() const | |||
{ return _rowindex; } | |||
inline void result::free() | |||
{ | |||
auto h = handle(); | |||
handle(nullptr); | |||
mysql_free_result(h); | |||
} | |||
inline result::result(MYSQL_RES* h) | |||
: mariadb_handle (h) | |||
, _is_initialized (false) | |||
, _rowindex (static_cast<unsigned long long>(-1)) | |||
{ } | |||
/* result_stored ******************************************************************************/ | |||
inline MYSQL_ROW_OFFSET result_stored::rowoffset() const | |||
{ return mysql_row_tell(*this); } | |||
inline void result_stored::rowoffset(MYSQL_ROW_OFFSET offset) | |||
{ mysql_row_seek(*this, offset); } | |||
inline void result_stored::rowindex(unsigned long long index) | |||
{ | |||
result::rowindex(index); | |||
mysql_data_seek(*this, result::rowindex()); | |||
} | |||
inline unsigned long long result_stored::rowindex() const | |||
{ return result::rowindex(); } | |||
inline unsigned long long result_stored::rowcount() const | |||
{ return mysql_num_rows(*this); } | |||
inline result_stored::result_stored(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
/* result_used *******************************************************************************/ | |||
inline result_used::result_used(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
} |
@@ -1,234 +0,0 @@ | |||
#pragma once | |||
#include <cppmariadb/row.h> | |||
#include <cppmariadb/field.h> | |||
#include <cppmariadb/result.h> | |||
namespace cppmariadb | |||
{ | |||
/* row::iterator_tpl *************************************************************************/ | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::compare_result | |||
row::iterator_tpl<T>::compare(const this_type& other) const | |||
{ | |||
if (_owner != other._owner) | |||
return compare_result::mismatch; | |||
else if (_index < other._index) | |||
return compare_result::lower; | |||
else if (_index > other._index) | |||
return compare_result::greater; | |||
else | |||
return compare_result::equals; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::reference | |||
row::iterator_tpl<T>::field() const | |||
{ | |||
if (!_cache) | |||
_cache.reset(new value_type(_owner->at(_index))); | |||
return *_cache; | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::assign(const this_type& other) | |||
{ | |||
_owner = other._owner; | |||
_index = other._index; | |||
_direction = other._direction; | |||
_cache.reset(); | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::next(difference_type i) | |||
{ | |||
_cache.reset(); | |||
_index = _index + _direction * i; | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::prev(difference_type i) | |||
{ | |||
_cache.reset(); | |||
_index = _index - _direction * i; | |||
} | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator==(const this_type& other) const | |||
{ return compare(other) == compare_result::equals; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator!=(const this_type& other) const | |||
{ return compare(other) != compare_result::equals; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator<(const this_type& other) const | |||
{ return compare(other) == compare_result::less; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator<=(const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::less || c == compare_result::equals); | |||
} | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator>(const this_type& other) const | |||
{ return compare(other) == compare_result::greater; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator>=(const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::greater || c == compare_result::equals); | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::reference | |||
row::iterator_tpl<T>::operator*() const | |||
{ return field(); } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::pointer | |||
row::iterator_tpl<T>::operator->() const | |||
{ return &field(); } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator++() | |||
{ | |||
next(); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator--() | |||
{ | |||
prev(); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator++(int) | |||
{ | |||
auto tmp(*this); | |||
next(); | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator--(int) | |||
{ | |||
auto tmp(*this); | |||
prev(); | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator+=(difference_type diff) | |||
{ | |||
next(diff); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator-=(difference_type diff) | |||
{ | |||
prev(diff); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator+(difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator-(difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp -= diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::difference_type | |||
row::iterator_tpl<T>::operator-(const this_type& other) const | |||
{ return (_index - other._index) * _direction; } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator[] (difference_type diff) | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline row::iterator_tpl<T>::iterator_tpl(const row& p_row, ssize_t index, ssize_t direction) | |||
: _owner (&p_row) | |||
, _index (index) | |||
, _direction(direction) | |||
{ } | |||
template<typename T> | |||
inline row::iterator_tpl<T>::iterator_tpl(const this_type& other) | |||
{ assign(other); } | |||
/* row ***************************************************************************************/ | |||
inline const column_vector& row::columns() const | |||
{ return _result.columns(); } | |||
inline unsigned int row::size() const | |||
{ return _result.columncount(); } | |||
inline row::iterator_type row::begin() const | |||
{ return iterator_type(*this, 0, 1); } | |||
inline row::iterator_type row::end() const | |||
{ return iterator_type(*this, size(), 1); } | |||
inline row::const_iterator_type row::cbegin() const | |||
{ return const_iterator_type(*this, 0, 1); } | |||
inline row::const_iterator_type row::cend() const | |||
{ return const_iterator_type(*this, size(), 1); } | |||
inline row::iterator_type row::rbegin() const | |||
{ return iterator_type(*this, size()-1, -1); } | |||
inline row::iterator_type row::rend() const | |||
{ return iterator_type(*this, -1, -1); } | |||
inline row::const_iterator_type row::crbegin() const | |||
{ return const_iterator_type(*this, size()-1, -1); } | |||
inline row::const_iterator_type row::crend() const | |||
{ return const_iterator_type(*this, -1, -1); } | |||
inline field row::operator[](size_t i) const | |||
{ return at(i); } | |||
inline field row::operator[](const std::string& name) const | |||
{ return at(name); } | |||
inline row::row(const result& p_result, MYSQL_ROW p_row) | |||
: mariadb_handle(p_row) | |||
, _result (p_result) | |||
, _lengths (nullptr) | |||
{ } | |||
} |
@@ -1,57 +1,121 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/impl/mariadb_handle.h> | |||
#include <cppmariadb/forward/column.h> | |||
#include <cppmariadb/forward/row.h> | |||
#include <cppmariadb/impl/handle.h> | |||
namespace cppmariadb | |||
{ | |||
/** | |||
* @brief Basic result type containing all rows and data from a query. | |||
*/ | |||
struct result : | |||
public __impl::mariadb_handle<MYSQL_RES*> | |||
public __impl::handle<MYSQL_RES*> | |||
{ | |||
private: | |||
bool _is_initialized; | |||
std::unique_ptr<row> _row; | |||
mutable column_vector _columns; | |||
unsigned long long _rowindex; | |||
bool _is_initialized; //!< Indicates if the result is initialized or not. | |||
std::unique_ptr<row> _row; //!< Current data row of the result. | |||
mutable column_vector _columns; //!< Column information that belongs to this result. | |||
unsigned long long _rowindex; //!< Index of the current row. | |||
void update_columns() const; | |||
public: | |||
/** | |||
* @brief Constructor. Create object from the mariadb handle. | |||
*/ | |||
inline result(MYSQL_RES* h); | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~result(); | |||
/** | |||
* @brief Get the number of columns. | |||
*/ | |||
inline unsigned int columncount() const; | |||
/** | |||
* @brief Get the columns that belong to this result. | |||
*/ | |||
inline const column_vector& columns() const; | |||
/** | |||
* @brief Get the next row of the result or nullptr | |||
* if no more rows are stored in the result. | |||
*/ | |||
row* next(); | |||
/** | |||
* @brief Get the current row. | |||
*/ | |||
inline row* current() const; | |||
/** | |||
* @brief Get the current row index. | |||
*/ | |||
inline unsigned long long rowindex() const; | |||
/** | |||
* @brief Free the result. | |||
*/ | |||
inline void free(); | |||
protected: | |||
/** | |||
* @brief Set the index of the current row. | |||
*/ | |||
inline void rowindex(unsigned long long value); | |||
public: | |||
inline unsigned int columncount () const; | |||
inline const column_vector& columns () const; | |||
row* next (); | |||
inline row* current () const; | |||
inline unsigned long long rowindex () const; | |||
inline void free (); | |||
inline result(MYSQL_RES* h); | |||
virtual ~result(); | |||
private: | |||
/** | |||
* @brief Fetch the column information from the database. | |||
*/ | |||
void update_columns() const; | |||
}; | |||
/** | |||
* @brief The stored result is a special kind of the result | |||
* that stores all result rows on the client. | |||
*/ | |||
struct result_stored | |||
: public result | |||
{ | |||
inline MYSQL_ROW_OFFSET rowoffset () const; | |||
inline void rowoffset (MYSQL_ROW_OFFSET offset); | |||
inline void rowindex (unsigned long long index); | |||
inline unsigned long long rowindex () const; | |||
inline unsigned long long rowcount () const; | |||
using result::rowindex; | |||
/** | |||
* @brief Constructor. Create a new object from the mariadb handle. | |||
*/ | |||
inline result_stored(MYSQL_RES* h); | |||
/** | |||
* @brief Set the index of the current row. | |||
*/ | |||
inline void rowindex(unsigned long long index); | |||
/** | |||
* @brief Get the number of rows soted in this result. | |||
*/ | |||
inline unsigned long long rowcount() const; | |||
}; | |||
/** | |||
* @brief The used result is a special kind of the result | |||
* that fetches only the needed rows from the database. | |||
*/ | |||
struct result_used | |||
: public result | |||
{ | |||
/** | |||
* @brief Constructor. Create a new object from the mariadb handle. | |||
*/ | |||
inline result_used(MYSQL_RES* h); | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~result_used() override; | |||
}; | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
#pragma once | |||
#include "result.h" | |||
namespace cppmariadb | |||
{ | |||
/* result ************************************************************************************/ | |||
result::result(MYSQL_RES* h) | |||
: handle (h) | |||
, _is_initialized (false) | |||
, _rowindex (static_cast<unsigned long long>(-1)) | |||
{ } | |||
unsigned int result::columncount() const | |||
{ return mysql_num_fields(*this); } | |||
const column_vector& result::columns() const | |||
{ | |||
if (_columns.empty()) | |||
update_columns(); | |||
return _columns; | |||
} | |||
row* result::current() const | |||
{ return _row.get(); } | |||
unsigned long long result::rowindex() const | |||
{ return _rowindex; } | |||
void result::free() | |||
{ | |||
auto h = get_handle(); | |||
handle(nullptr); | |||
mysql_free_result(h); | |||
} | |||
void result::rowindex(unsigned long long value) | |||
{ _rowindex = value; } | |||
/* result_stored ******************************************************************************/ | |||
result_stored::result_stored(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
void result_stored::rowindex(unsigned long long index) | |||
{ | |||
result::rowindex(index); | |||
mysql_data_seek(*this, result::rowindex()); | |||
} | |||
unsigned long long result_stored::rowcount() const | |||
{ return mysql_num_rows(*this); } | |||
/* result_used *******************************************************************************/ | |||
result_used::result_used(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
} |
@@ -3,106 +3,123 @@ | |||
#include <string> | |||
#include <limits> | |||
#include <memory> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/impl/mariadb_handle.h> | |||
#include <cppmariadb/forward/column.h> | |||
#include <cppmariadb/forward/field.h> | |||
#include <cppmariadb/forward/result.h> | |||
#include <cppmariadb/forward/row.h> | |||
#include <cppmariadb/impl/handle.h> | |||
namespace cppmariadb | |||
{ | |||
struct row | |||
: public __impl::mariadb_handle<MYSQL_ROW> | |||
namespace __impl | |||
{ | |||
private: | |||
template<typename T> | |||
struct iterator_tpl | |||
{ | |||
public: | |||
using this_type = iterator_tpl<T>; | |||
using iterator_category = std::random_access_iterator_tag; | |||
using value_type = T; | |||
using difference_type = ssize_t; | |||
using pointer = T*; | |||
using reference = T&; | |||
private: | |||
enum class compare_result : int | |||
{ | |||
lower = -1, | |||
equals = 0, | |||
greater = 1, | |||
mismatch = 2 | |||
}; | |||
using value_ptru_type = std::unique_ptr<value_type>; | |||
private: | |||
const row* _owner; | |||
ssize_t _index; | |||
ssize_t _direction; | |||
mutable value_ptru_type _cache; | |||
inline compare_result compare (const this_type& other) const; | |||
inline reference field () const; | |||
inline void assign (const this_type& other); | |||
inline void next (difference_type i = 1); | |||
inline void prev (difference_type i = 1); | |||
public: | |||
inline bool operator == (const this_type& other) const; | |||
inline bool operator != (const this_type& other) const; | |||
inline bool operator < (const this_type& other) const; | |||
inline bool operator <= (const this_type& other) const; | |||
inline bool operator > (const this_type& other) const; | |||
inline bool operator >= (const this_type& other) const; | |||
inline reference operator * () const; | |||
inline pointer operator -> () const; | |||
inline this_type& operator ++ (); | |||
inline this_type& operator -- (); | |||
inline this_type operator ++ (int); | |||
inline this_type operator -- (int); | |||
inline this_type& operator += (difference_type diff); | |||
inline this_type& operator -= (difference_type diff); | |||
inline this_type operator + (difference_type diff) const; | |||
inline this_type operator - (difference_type diff) const; | |||
inline difference_type operator - (const this_type& other) const; | |||
inline this_type operator [] (difference_type diff); | |||
inline iterator_tpl(const row& p_row, ssize_t index, ssize_t direction); | |||
inline iterator_tpl(const this_type& other); | |||
}; | |||
struct row_iterator; | |||
} | |||
/** | |||
* @brief Represents a row inside the result set. | |||
*/ | |||
struct row | |||
: public __impl::handle<MYSQL_ROW> | |||
{ | |||
public: | |||
using iterator_type = iterator_tpl<field>; | |||
using const_iterator_type = iterator_tpl<const field>; | |||
using iterator_type = __impl::row_iterator<field>; | |||
using const_iterator_type = __impl::row_iterator<const field>; | |||
static constexpr size_t npos = std::numeric_limits<size_t>::max(); | |||
private: | |||
const result& _result; | |||
mutable unsigned long* _lengths; | |||
const result& _result; //!< Result this row belongs to. | |||
mutable unsigned long* _lengths; //!< Number of fields stored in this row. | |||
public: | |||
inline const column_vector& columns () const; | |||
inline unsigned int size () const; | |||
inline iterator_type begin () const; | |||
inline iterator_type end () const; | |||
inline const_iterator_type cbegin () const; | |||
inline const_iterator_type cend () const; | |||
inline iterator_type rbegin () const; | |||
inline iterator_type rend () const; | |||
inline const_iterator_type crbegin () const; | |||
inline const_iterator_type crend () const; | |||
size_t find (const std::string& name) const; | |||
field at (size_t i) const; | |||
field at (const std::string name) const; | |||
inline field operator[] (size_t i) const; | |||
inline field operator[] (const std::string& name) const; | |||
/** | |||
* @brief Constructor to create a row from a mariadb handle. | |||
* | |||
* @param[in] p_result Result this row belongs to. | |||
* @param[in] p_row Row handle from mariadb. | |||
*/ | |||
inline row(const result& p_result, MYSQL_ROW p_row); | |||
public: | |||
/** | |||
* @brief Access operator to get the field at the given index. | |||
*/ | |||
inline field operator[](size_t i) const; | |||
/** | |||
* @brief Access operator to get the field with the given name. | |||
*/ | |||
inline field operator[](const std::string& name) const; | |||
public: | |||
/** | |||
* @brief Get the columns that belong to this rows. | |||
*/ | |||
inline const column_vector& columns() const; | |||
/** | |||
* @brief Get the number of fields stored in this row. | |||
*/ | |||
inline unsigned int size() const; | |||
/** | |||
* @brief Get the begin iterator. | |||
*/ | |||
inline iterator_type begin() const; | |||
/** | |||
* @brief Get the end iterator. | |||
*/ | |||
inline iterator_type end() const; | |||
/** | |||
* @brief Get the const begin iterator. | |||
*/ | |||
inline const_iterator_type cbegin() const; | |||
/** | |||
* @brief Get the const end iterator. | |||
*/ | |||
inline const_iterator_type cend() const; | |||
/** | |||
* @brief Get the reverse begin iterator. | |||
*/ | |||
inline iterator_type rbegin() const; | |||
/** | |||
* @brief Get the reverse end iterator. | |||
*/ | |||
inline iterator_type rend() const; | |||
/** | |||
* @brief Get the const reverse begin iterator. | |||
*/ | |||
inline const_iterator_type crbegin() const; | |||
/** | |||
* @brief Get the const reverse end iterator. | |||
*/ | |||
inline const_iterator_type crend() const; | |||
public: | |||
/** | |||
* @brief Get the index of a field by its name. | |||
*/ | |||
size_t find(const std::string& name) const; | |||
/** | |||
* @brief Get the field at the given index. | |||
*/ | |||
field at(size_t i) const; | |||
/** | |||
* @brief Get the field with the given name. | |||
*/ | |||
field at(const std::string name) const; | |||
}; | |||
} | |||
} |
@@ -0,0 +1,232 @@ | |||
#pragma once | |||
#include "row.h" | |||
#include "field.inl" | |||
#include "result.inl" | |||
namespace cppmariadb | |||
{ | |||
namespace __impl | |||
{ | |||
template<typename T> | |||
struct row_iterator | |||
{ | |||
public: | |||
using this_type = row_iterator<T>; | |||
using iterator_category = std::random_access_iterator_tag; | |||
using value_type = T; | |||
using difference_type = ssize_t; | |||
using pointer = T*; | |||
using reference = T&; | |||
private: | |||
enum class compare_result : int | |||
{ | |||
lower = -1, | |||
equals = 0, | |||
greater = 1, | |||
mismatch = 2 | |||
}; | |||
using value_ptru_type = std::unique_ptr<value_type>; | |||
private: | |||
const row* _owner; | |||
ssize_t _index; | |||
ssize_t _direction; | |||
mutable value_ptru_type _cache; | |||
public: | |||
inline row_iterator(const row& p_row, ssize_t index, ssize_t direction) | |||
: _owner (&p_row) | |||
, _index (index) | |||
, _direction(direction) | |||
{ } | |||
inline row_iterator(const this_type& other) | |||
{ assign(other); } | |||
public: | |||
inline bool operator == (const this_type& other) const | |||
{ return compare(other) == compare_result::equals; } | |||
inline bool operator != (const this_type& other) const | |||
{ return compare(other) != compare_result::equals; } | |||
inline bool operator < (const this_type& other) const | |||
{ return compare(other) == compare_result::less; } | |||
inline bool operator <= (const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::less || c == compare_result::equals); | |||
} | |||
inline bool operator > (const this_type& other) const | |||
{ return compare(other) == compare_result::greater; } | |||
inline bool operator >= (const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::greater || c == compare_result::equals); | |||
} | |||
inline reference operator * () const | |||
{ return field(); } | |||
inline pointer operator -> () const | |||
{ return &field(); } | |||
inline this_type& operator ++ () | |||
{ | |||
next(); | |||
return *this; | |||
} | |||
inline this_type& operator -- () | |||
{ | |||
prev(); | |||
return *this; | |||
} | |||
inline this_type operator ++ (int) | |||
{ | |||
auto tmp(*this); | |||
next(); | |||
return tmp; | |||
} | |||
inline this_type operator -- (int) | |||
{ | |||
auto tmp(*this); | |||
prev(); | |||
return tmp; | |||
} | |||
inline this_type& operator += (difference_type diff) | |||
{ | |||
next(diff); | |||
return *this; | |||
} | |||
inline this_type& operator -= (difference_type diff) | |||
{ | |||
prev(diff); | |||
return *this; | |||
} | |||
inline this_type operator + (difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
inline this_type operator - (difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp -= diff; | |||
return tmp; | |||
} | |||
inline difference_type operator - (const this_type& other) const | |||
{ return (_index - other._index) * _direction; } | |||
inline this_type operator [] (difference_type diff) | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
private: | |||
inline compare_result compare(const this_type& other) const | |||
{ | |||
if (_owner != other._owner) | |||
return compare_result::mismatch; | |||
else if (_index < other._index) | |||
return compare_result::lower; | |||
else if (_index > other._index) | |||
return compare_result::greater; | |||
else | |||
return compare_result::equals; | |||
} | |||
inline reference field() const | |||
{ | |||
if (!_cache) | |||
_cache.reset(new value_type(_owner->at(_index))); | |||
return *_cache; | |||
} | |||
inline void assign(const this_type& other) | |||
{ | |||
_owner = other._owner; | |||
_index = other._index; | |||
_direction = other._direction; | |||
_cache.reset(); | |||
} | |||
inline void next(difference_type i = 1) | |||
{ | |||
_cache.reset(); | |||
_index = _index + _direction * i; | |||
} | |||
inline void prev(difference_type i = 1) | |||
{ | |||
_cache.reset(); | |||
_index = _index - _direction * i; | |||
} | |||
}; | |||
} | |||
/* row */ | |||
row::row(const result& p_result, MYSQL_ROW p_row) | |||
: handle(p_row) | |||
, _result (p_result) | |||
, _lengths (nullptr) | |||
{ } | |||
field row::operator[](size_t i) const | |||
{ return at(i); } | |||
field row::operator[](const std::string& name) const | |||
{ return at(name); } | |||
const column_vector& row::columns() const | |||
{ return _result.columns(); } | |||
unsigned int row::size() const | |||
{ return _result.columncount(); } | |||
row::iterator_type row::begin() const | |||
{ return iterator_type(*this, 0, 1); } | |||
row::iterator_type row::end() const | |||
{ return iterator_type(*this, size(), 1); } | |||
row::const_iterator_type row::cbegin() const | |||
{ return const_iterator_type(*this, 0, 1); } | |||
row::const_iterator_type row::cend() const | |||
{ return const_iterator_type(*this, size(), 1); } | |||
row::iterator_type row::rbegin() const | |||
{ return iterator_type(*this, size()-1, -1); } | |||
row::iterator_type row::rend() const | |||
{ return iterator_type(*this, -1, -1); } | |||
row::const_iterator_type row::crbegin() const | |||
{ return const_iterator_type(*this, size()-1, -1); } | |||
row::const_iterator_type row::crend() const | |||
{ return const_iterator_type(*this, -1, -1); } | |||
} |
@@ -2,54 +2,137 @@ | |||
#include <string> | |||
#include <vector> | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/forward/connection.h> | |||
#include <cppmariadb/forward/statement.h> | |||
namespace cppmariadb | |||
{ | |||
/** | |||
* @brief Class to store a MYSQL statement. The variables | |||
* inside the statement are escaped automatically. | |||
*/ | |||
struct statement | |||
{ | |||
public: | |||
static constexpr size_t npos = std::numeric_limits<size_t>::max(); | |||
private: | |||
/** | |||
* @brief Parameter inside the statement. | |||
*/ | |||
struct parameter | |||
{ | |||
bool has_value { false }; | |||
bool unescaped { false }; | |||
std::string value; | |||
bool has_value { false }; //!< The parameter has a value assigned (is not null). | |||
bool unescaped { false }; //!< The parameter should not be escaped (is unescaped). | |||
std::string value; //!< Value of the parameter. | |||
}; | |||
private: | |||
mutable bool _changed; | |||
mutable std::string _query; | |||
mutable const connection* _connection; | |||
mutable bool _changed; //!< The statement has changed (_query need to be recompiled). | |||
mutable std::string _query; //!< The compiled query. | |||
mutable const connection* _connection; //!< Connection the query was compiled for. | |||
std::vector<std::string> _code; | |||
std::vector<std::pair<std::string, parameter>> _parameters; | |||
void parse(const std::string& query); | |||
void build(const connection& con) const; | |||
std::vector<std::string> _code; //!< Code pars of the statement | |||
std::vector<std::pair<std::string, parameter>> _parameters; //!< Parameters of the statement | |||
public: | |||
inline void assign (const std::string& query); | |||
inline const std::string& query (const connection& con) const; | |||
inline size_t find (const std::string& param); | |||
inline void set_null(const std::string& param); | |||
inline void set_null(size_t index); | |||
inline bool empty () const; | |||
inline void clear (); | |||
/** | |||
* @brief Default constructor. | |||
*/ | |||
inline statement(); | |||
/** | |||
* @brief Value constructor. Create a new statement of the passed query. | |||
* | |||
* @param[in] query Query to store in the new statement. | |||
*/ | |||
inline statement(const std::string& query); | |||
/** | |||
* @brief Assign a new query/statement to this object. | |||
*/ | |||
inline void assign(const std::string& query); | |||
/** | |||
* @brief Get the final query to pass to the server. | |||
* | |||
* @param[in] con Connection to use for escaping the values. | |||
* | |||
* @return Final query with escaped and filled values. | |||
*/ | |||
inline const std::string& query(const connection& con) const; | |||
/** | |||
* @brief Find a parameter by its name. | |||
* | |||
* @param[in] param Name of the parameter to find. | |||
* | |||
* @return Index of the parameter. | |||
*/ | |||
inline size_t find(const std::string& param); | |||
/** | |||
* @brief Set a parameter to null. | |||
* | |||
* @param[in] param Name of the parameter to set to null. | |||
*/ | |||
inline void set_null(const std::string& param); | |||
/** | |||
* @brief Set a parameter to null. | |||
* | |||
* @param[in] index Index of the parameter to set to null. | |||
*/ | |||
inline void set_null(size_t index); | |||
/** | |||
* @brief Check if the statement is empty. | |||
* | |||
* @retval true If this statement is empty. | |||
* @retval false If this statement has a query assigned. | |||
*/ | |||
inline bool empty() const; | |||
/** | |||
* @brief Set all variables of the statement to null. | |||
*/ | |||
inline void clear(); | |||
/** | |||
* @brief Set the value of a parameter. | |||
* | |||
* @param[in] param Name of the parameter to set the value for. | |||
* @param[in] value Value to set for the parameter. | |||
*/ | |||
template<class T> | |||
inline void set(const std::string& param, const T& value); | |||
/** | |||
* @brief Set the value of a parameter. | |||
* | |||
* @param[in] index Index of the parameter to set the value for. | |||
* @param[in] value Value to set for the parameter. | |||
*/ | |||
template<class T> | |||
inline void set(size_t index, const T& value); | |||
inline statement(); | |||
inline statement(const std::string& query); | |||
private: | |||
/** | |||
* @brief Parse the passed query and split it into its code and parameters parts. | |||
* | |||
* The parsed parts of the query are stored alternately in the _code and _parameters vector, | |||
* starting with a code element. | |||
* | |||
* @param[in] query Query to parse. | |||
*/ | |||
void parse(const std::string& query); | |||
/** | |||
* @brief Build the final query using the passed conection to escape the values. | |||
* The query is cached in the _query variable of the object. | |||
*/ | |||
void build(const connection& con) const; | |||
}; | |||
} | |||
} |
@@ -1,28 +1,39 @@ | |||
#pragma once | |||
#include <cppmariadb/statement.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
#include <cppcore/conversion/enum.h> | |||
#include <cppcore/conversion/string.h> | |||
#include "statement.h" | |||
namespace cppmariadb | |||
{ | |||
/* statement *********************************************************************************/ | |||
inline void statement::assign(const std::string& query) | |||
statement::statement() | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ } | |||
statement::statement(const std::string& query) | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ parse(query); } | |||
void statement::assign(const std::string& query) | |||
{ | |||
_changed = true; | |||
parse(query); | |||
} | |||
inline const std::string& statement::query(const connection& con) const | |||
const std::string& statement::query(const connection& con) const | |||
{ | |||
if (_changed || &con != _connection) | |||
build(con); | |||
return _query; | |||
} | |||
inline size_t statement::find(const std::string& param) | |||
size_t statement::find(const std::string& param) | |||
{ | |||
for (size_t i = 0; i < _parameters.size(); ++i) | |||
{ | |||
@@ -32,34 +43,34 @@ namespace cppmariadb | |||
return npos; | |||
} | |||
inline void statement::set_null(const std::string& param) | |||
void statement::set_null(const std::string& param) | |||
{ | |||
auto i = find(param); | |||
if (i == npos) | |||
throw exception(std::string("unknown parameter name in query: ") + param, error_code::Unknown); | |||
throw exception(std::string("unknown parameter name in statement: ") + param, error_code::Unknown); | |||
set_null(i); | |||
} | |||
inline void statement::set_null(size_t index) | |||
void statement::set_null(size_t index) | |||
{ | |||
if (index >= _parameters.size()) | |||
throw exception(std::string("unknown parameter index in query: ") + std::to_string(index), error_code::Unknown); | |||
throw exception(std::string("unknown parameter index in statement: ") + std::to_string(index), error_code::Unknown); | |||
auto& param = _parameters.at(index).second; | |||
param.has_value = false; | |||
_changed = true; | |||
} | |||
inline bool statement::empty() const | |||
bool statement::empty() const | |||
{ return _code.empty(); } | |||
inline void statement::clear() | |||
void statement::clear() | |||
{ | |||
for (auto& param : _parameters) | |||
param.second.has_value = false; | |||
} | |||
template<class T> | |||
inline void statement::set(const std::string& param, const T& value) | |||
void statement::set(const std::string& param, const T& value) | |||
{ | |||
auto i = find(param); | |||
if (i == npos) | |||
@@ -68,25 +79,14 @@ namespace cppmariadb | |||
} | |||
template<class T> | |||
inline void statement::set(size_t index, const T& value) | |||
void statement::set(size_t index, const T& value) | |||
{ | |||
if (index >= _parameters.size()) | |||
throw exception(std::string("unknown parameter index in query: ") + std::to_string(index), error_code::Unknown); | |||
auto& param = _parameters.at(index).second; | |||
param.has_value = true; | |||
param.value = utl::to_string(value); | |||
param.value = cppcore::to_string(value); | |||
_changed = true; | |||
} | |||
inline statement::statement() | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ } | |||
inline statement::statement(const std::string& query) | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ parse(query); } | |||
} | |||
} |
@@ -1,28 +1,51 @@ | |||
#pragma once | |||
#include <cppmariadb/config.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/forward/connection.h> | |||
#include <cppmariadb/forward/statement.h> | |||
#include <cppmariadb/forward/transaction.h> | |||
namespace cppmariadb | |||
{ | |||
/** | |||
* @brief Locks the queries executed at a connection. | |||
* | |||
* This will start an transaction if the object is created and | |||
* automatically execute the rollback in the destructor, if the | |||
* transaction ws not commited. | |||
*/ | |||
struct transaction | |||
{ | |||
private: | |||
connection& _connection; | |||
bool _closed; | |||
inline void begin(); | |||
connection& _connection; //!< Connection this transaction object protects | |||
bool _closed; //!< True if the transaction is closed/finished. | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] connection Connection to protect. | |||
*/ | |||
inline transaction(connection& connection); | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
inline ~transaction(); | |||
/** | |||
* @brief Commit the changes made on the connection. | |||
*/ | |||
inline void commit(); | |||
/** | |||
* @brief Rollback the changes made on the connection. | |||
*/ | |||
inline void rollback(); | |||
inline transaction(connection& connection); | |||
inline ~transaction(); | |||
private: | |||
/** | |||
* @brief Begin the transaction. | |||
*/ | |||
inline void begin(); | |||
}; | |||
} | |||
} |
@@ -1,19 +1,24 @@ | |||
#pragma once | |||
#include <cppmariadb/transaction.h> | |||
#include "transaction.h" | |||
namespace cppmariadb | |||
{ | |||
/* transaction *******************************************************************************/ | |||
/* transaction */ | |||
inline void transaction::begin() | |||
transaction::transaction(connection& connection) : | |||
_connection (connection), | |||
_closed (false) | |||
{ begin(); } | |||
transaction::~transaction() | |||
{ | |||
static const statement sCommit("START TRANSACTION"); | |||
_connection.execute(sCommit); | |||
if (!_closed) | |||
rollback(); | |||
} | |||
inline void transaction::commit() | |||
void transaction::commit() | |||
{ | |||
static const statement sCommit("COMMIT"); | |||
if (_closed) | |||
@@ -22,7 +27,7 @@ namespace cppmariadb | |||
_closed = true; | |||
} | |||
inline void transaction::rollback() | |||
void transaction::rollback() | |||
{ | |||
static const statement sRollback("ROLLBACK"); | |||
if (_closed) | |||
@@ -31,16 +36,10 @@ namespace cppmariadb | |||
_closed = true; | |||
} | |||
inline transaction::transaction(connection& connection) : | |||
_connection (connection), | |||
_closed (false) | |||
{ begin(); } | |||
inline transaction::~transaction() | |||
void transaction::begin() | |||
{ | |||
if (!_closed) | |||
rollback(); | |||
static const statement sCommit("START TRANSACTION"); | |||
_connection.execute(sCommit); | |||
} | |||
} | |||
} |
@@ -1,48 +1,126 @@ | |||
# Initialize ###################################################################################### | |||
Include ( cotire OPTIONAL ) | |||
Include ( pedantic OPTIONAL ) | |||
Include ( strip_symbols OPTIONAL ) | |||
Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||
Include ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/options.cmake ) | |||
FInd_Package ( cppcore REQUIRED ) | |||
Find_Package ( cpplogging ) | |||
If ( cpplogging_FOUND ) | |||
Set ( CPPMARIADB_HAS_CPPLOGGING true ) | |||
EndIf ( ) | |||
# Object Library ################################################################################## | |||
Set ( CMAKE_POSITION_INDEPENDENT_CODE ON ) | |||
Set ( CPPMARIADB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||
Set ( CPPMARIADB_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/include ) | |||
Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.h.in | |||
${CPPMARIADB_GENERATED_INCLUDE_DIR}/cppmariadb/config.h ) | |||
File ( GLOB_RECURSE CPPMARIADB_HEADER_FILES ${CPPMARIADB_INCLUDE_DIR}/*.h ) | |||
File ( GLOB_RECURSE CPPMARIADB_INLINE_FILES ${CPPMARIADB_INCLUDE_DIR}/*.inl ) | |||
File ( GLOB_RECURSE CPPMARIADB_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Library ( cppmariadb-objects | |||
OBJECT | |||
${CPPMARIADB_HEADER_FILES} | |||
${CPPMARIADB_INLINE_FILES} | |||
${CPPMARIADB_SOURCE_FILES} ) | |||
Target_Include_Directories ( cppmariadb-objects | |||
PUBLIC | |||
$<BUILD_INTERFACE:${CPPMARIADB_INCLUDE_DIR}> | |||
$<BUILD_INTERFACE:${CPPMARIADB_GENERATED_INCLUDE_DIR}> | |||
$<INSTALL_INTERFACE:${CPPMARIADB_INSTALL_DIR_INCLUDE}> ) | |||
Target_Link_Libraries ( cppmariadb-objects | |||
PUBLIC | |||
cppcore::cppcore ) | |||
If ( CPPMARIADB_HAS_CPPLOGGING ) | |||
Target_Link_Libraries ( cppmariadb-objects | |||
PUBLIC | |||
cpplogging::cpplogging-shared ) | |||
EndIf ( ) | |||
Set ( BUILD_SHARED_LIBS ${CPPMARIADB_BUILD_SHARED} ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||
# Static Library ################################################################################## | |||
# Dependencies #################################################################################### | |||
Add_Library ( cppmariadb-static STATIC $<TARGET_OBJECTS:cppmariadb-objects> ) | |||
Set_Target_Properties ( cppmariadb-static | |||
PROPERTIES | |||
OUTPUT_NAME "${CPPMARIADB_OUTPUTNAME}" | |||
VERSION ${CPPMARIADB_VERSION} ) | |||
Target_Include_Directories ( cppmariadb-static | |||
PUBLIC | |||
$<BUILD_INTERFACE:${CPPMARIADB_INCLUDE_DIR}> | |||
$<INSTALL_INTERFACE:${CPPMARIADB_INSTALL_DIR_INCLUDE}> ) | |||
If ( CPPMARIADB_HAS_CPPLOGGING ) | |||
Target_Link_Libraries ( cppmariadb-static | |||
PUBLIC | |||
cpplogging::cpplogging-static ) | |||
EndIf ( ) | |||
Find_Package ( cpputils REQUIRED ) | |||
Find_Package ( mariadb REQUIRED ) | |||
# Shared Library ################################################################################## | |||
# Project: cppmariadb ############################################################################# | |||
Add_Library ( cppmariadb-shared SHARED $<TARGET_OBJECTS:cppmariadb-objects> ) | |||
Set_Target_Properties ( cppmariadb-shared | |||
PROPERTIES | |||
OUTPUT_NAME "${CPPMARIADB_OUTPUTNAME}" | |||
VERSION ${CPPMARIADB_VERSION} | |||
SOVERSION ${CPPMARIADB_VERSION_SHORT} ) | |||
Target_Include_Directories ( cppmariadb-shared | |||
PUBLIC | |||
$<BUILD_INTERFACE:${CPPMARIADB_INCLUDE_DIR}> | |||
$<INSTALL_INTERFACE:${CPPMARIADB_INSTALL_DIR_INCLUDE}> ) | |||
If ( CPPMARIADB_HAS_CPPLOGGING ) | |||
Target_Link_Libraries ( cppmariadb-shared | |||
PUBLIC | |||
cpplogging::cpplogging-shared ) | |||
EndIf ( ) | |||
# Build | |||
Project ( cppmariadb VERSION 1.0.0.0 LANGUAGES CXX ) | |||
Set ( CPPMARIADB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Library ( cppmariadb ${SOURCE_FILES} ) | |||
Target_Include_Directories ( cppmariadb | |||
PUBLIC ${CPPMARIADB_INCLUDE_DIR} ) | |||
Target_Link_Libraries ( cppmariadb | |||
cpputils | |||
mariadb ) | |||
# Optimization #################################################################################### | |||
# pedantic | |||
If ( HAS_PEDANTIC ) | |||
Pedantic_Apply_Flags_Target ( cppmariadb-objects ALL ) | |||
Pedantic_Apply_Flags_Target ( cppmariadb-static ALL ) | |||
Pedantic_Apply_Flags_Target ( cppmariadb-shared ALL ) | |||
EndIf ( ) | |||
# cotire | |||
If ( HAS_COTIRE ) | |||
Cotire ( cppmariadb-objects ) | |||
Cotire ( cppmariadb-static ) | |||
Cotire ( cppmariadb-shared ) | |||
EndIf ( ) | |||
# Install ######################################################################################### | |||
# Header | |||
If ( CPPMARIADB_INSTALL_HEADER ) | |||
Install ( FILES ${CPPMARIADB_INCLUDE_DIR}/cppmariadb.h | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_INCLUDE} ) | |||
Install ( DIRECTORY ${CPPMARIADB_INCLUDE_DIR}/cppmariadb | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_INCLUDE} ) | |||
Install ( DIRECTORY ${CPPMARIADB_GENERATED_INCLUDE_DIR}/cppmariadb | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_INCLUDE} ) | |||
EndIf ( ) | |||
# Install | |||
If ( BUILD_SHARED_LIBS OR CPPMARIADB_INSTALL_DEV_FILES ) | |||
Install ( TARGETS cppmariadb DESTINATION lib ) | |||
# Static | |||
If ( CPPMARIADB_INSTALL_STATIC ) | |||
Install ( TARGETS cppmariadb-static | |||
EXPORT cppmariadb | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_LIB} ) | |||
EndIf ( ) | |||
If ( CPPMARIADB_INSTALL_DEV_FILES ) | |||
Install ( FILES ${CPPMARIADB_INCLUDE_DIR}/cppmariadb.h DESTINATION include ) | |||
Install ( DIRECTORY ${CPPMARIADB_INCLUDE_DIR}/cppmariadb DESTINATION include ) | |||
# Shared | |||
If ( CPPMARIADB_INSTALL_SHARED ) | |||
Install ( TARGETS cppmariadb-shared | |||
EXPORT cppmariadb | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_LIB} ) | |||
EndIf ( ) | |||
# Optimize | |||
If ( __COTIRE_INCLUDED ) | |||
Cotire ( cppmariadb ) | |||
# Debug | |||
If ( HAS_STRIP_SYMBOLS AND NOT CPPMARIADB_NO_STRIP ) | |||
Strip_Symbols ( cppmariadb-shared CPPMARIADB_DBG_FILE ) | |||
If ( CPPMARIADB_INSTALL_DEBUG ) | |||
Install ( FILES ${CPPMARIADB_DBG_FILE} | |||
DESTINATION ${CPPMARIADB_INSTALL_DIR_LIB} ) | |||
EndIf ( ) | |||
EndIf ( ) | |||
If ( __STRIP_SYMBOLS_INCLUDED AND BUILD_SHARED_LIBS ) | |||
Strip_Symbols ( cppmariadb DBG_FILE ) | |||
EndIf () |
@@ -1,6 +1,7 @@ | |||
#include <cppcore/conversion/enum.h> | |||
#include <cppcore/conversion/string.h> | |||
#include <cppmariadb/exception.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
using namespace ::cppmariadb; | |||
@@ -15,7 +16,7 @@ void exception::print_message(std::ostream& os) const | |||
if (error != error_code::NoError) | |||
{ | |||
os << "error_code="; | |||
utl::to_string(os, error); | |||
cppcore::to_string(os, error); | |||
first = false; | |||
} | |||
if (!query.empty()) | |||
@@ -26,4 +27,4 @@ void exception::print_message(std::ostream& os) const | |||
} | |||
os << ")"; | |||
} | |||
} | |||
} |
@@ -1,18 +1,23 @@ | |||
#include <cppmariadb/result.h> | |||
#include <cppmariadb/column.h> | |||
#include <cppmariadb/inline/row.inl> | |||
#include <cppmariadb/inline/result.inl> | |||
#include <cppmariadb/row.inl> | |||
#include <cppmariadb/result.inl> | |||
#include <cppmariadb/impl/handle.inl> | |||
using namespace ::cppmariadb; | |||
/* result */ | |||
result::~result() | |||
{ free(); } | |||
row* result::next() | |||
{ | |||
if (_is_initialized && !_row) | |||
return nullptr; | |||
_is_initialized = true; | |||
auto r = mysql_fetch_row(handle()); | |||
auto r = mysql_fetch_row(get_handle()); | |||
if (r) | |||
{ | |||
_row.reset(new row(*this, r)); | |||
@@ -26,16 +31,15 @@ row* result::next() | |||
void result::update_columns() const | |||
{ | |||
auto f = mysql_fetch_fields(handle()); | |||
auto c = mysql_num_fields (handle()); | |||
auto f = mysql_fetch_fields(get_handle()); | |||
auto c = mysql_num_fields (get_handle()); | |||
_columns.clear(); | |||
_columns.reserve(c); | |||
for (size_t i = 0; i < c; ++i) | |||
_columns.emplace_back(f[i]); | |||
} | |||
result::~result() | |||
{ free(); } | |||
/* result_used */ | |||
result_used::~result_used() | |||
{ while(next()); /* fetch rows until none is left */ } | |||
{ while(next()); /* fetch rows until none is left */ } |
@@ -1,10 +1,9 @@ | |||
#include <cppmariadb/row.h> | |||
#include <cppmariadb/column.h> | |||
#include <cppmariadb/exception.h> | |||
#include <cppmariadb/inline/row.inl> | |||
#include <cppmariadb/inline/field.inl> | |||
#include <cppmariadb/inline/result.inl> | |||
#include <cppmariadb/row.inl> | |||
#include <cppmariadb/field.inl> | |||
#include <cppmariadb/result.inl> | |||
#include <cppmariadb/impl/handle.inl> | |||
using namespace ::cppmariadb; | |||
@@ -30,11 +29,11 @@ field row::at(size_t i) const | |||
throw exception("row index out of range", error_code::UnknownError); | |||
if (!_lengths) | |||
{ | |||
_lengths = mysql_fetch_lengths(_result.handle()); | |||
_lengths = mysql_fetch_lengths(_result.get_handle()); | |||
if (!_lengths) | |||
throw exception("unble to fetch lenghts for row", error_code::UnknownError); | |||
} | |||
return field(*this, i, handle()[i], _lengths[i]); | |||
return field(*this, i, get_handle()[i], _lengths[i]); | |||
} | |||
field row::at(const std::string name) const | |||
@@ -1,10 +1,13 @@ | |||
#include <cppmariadb/row.h> | |||
#include <cppmariadb/enums.h> | |||
#include <cppmariadb/column.h> | |||
#include <cppmariadb/exception.h> | |||
#include <cppmariadb/statement.h> | |||
#include <cppmariadb/inline/statement.inl> | |||
#include <cppmariadb/inline/connection.inl> | |||
#include <cppmariadb/row.inl> | |||
#include <cppmariadb/column.inl> | |||
#include <cppmariadb/result.inl> | |||
#include <cppmariadb/statement.inl> | |||
#include <cppmariadb/connection.inl> | |||
#include <cppmariadb/impl/handle.inl> | |||
using namespace ::cppmariadb; | |||
@@ -81,4 +84,4 @@ void statement::build(const connection& con) const | |||
} | |||
_changed = false; | |||
_query = ss.str(); | |||
} | |||
} |
@@ -1,33 +1,43 @@ | |||
# Initialize ###################################################################################### | |||
Include ( cotire OPTIONAL ) | |||
Include ( pedantic OPTIONAL ) | |||
Include ( cmake_tests OPTIONAL ) | |||
Include ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/options.cmake ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||
Find_Package ( cpputils REQUIRED ) | |||
# Project: test_cppmariadb ######################################################################## | |||
Project ( test_cppmariadb ) | |||
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Executable ( test_cppmariadb EXCLUDE_FROM_ALL ${SOURCE_FILES} ) | |||
Target_Link_Libraries ( test_cppmariadb | |||
cppmariadb | |||
cpputils | |||
gmock_main | |||
gmock | |||
gtest | |||
pthread ) | |||
If ( __COTIRE_INCLUDED ) | |||
Cotire ( test_cppmariadb ) | |||
Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) | |||
# Test ############################################################################################ | |||
Find_Package ( GTest ) | |||
If ( NOT "${GTest_FOUND}" ) | |||
Return ( ) | |||
EndIf ( ) | |||
If ( __CMAKE_TESTS_INCLUDED ) | |||
Add_CMake_Test ( NAME tsoutils | |||
TARGET test_cppmariadb ) | |||
File ( GLOB_RECURSE CPPMARIADB_TEST_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) | |||
File ( GLOB_RECURSE CPPMARIADB_TEST_INLINE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) | |||
File ( GLOB_RECURSE CPPMARIADB_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Executable ( cppmariadb-test | |||
EXCLUDE_FROM_ALL | |||
${CPPMARIADB_TEST_HEADER_FILES} | |||
${CPPMARIADB_TEST_INLINE_FILES} | |||
${CPPMARIADB_TEST_SOURCE_FILES} ) | |||
Target_Link_Libraries ( cppmariadb-test | |||
PUBLIC | |||
cppmariadb-objects | |||
GMock::Main ) | |||
# pedantic | |||
If ( HAS_PEDANTIC ) | |||
Pedantic_Apply_Flags_Target ( cppmariadb-test ALL ) | |||
EndIf ( ) | |||
# optimization | |||
If ( HAS_COTIRE ) | |||
Cotire ( cppmariadb-test ) | |||
EndIf ( ) | |||
# test | |||
If ( HAS_CMAKE_TESTS ) | |||
Add_CMake_Test ( NAME cppmariadb TARGET cppmariadb-test ) | |||
Else ( ) | |||
Add_Test ( NAME cppmariadb COMMAND cppmariadb-test ) | |||
EndIf ( ) |
@@ -22,9 +22,10 @@ TEST(MariaDbTests, MariaDB_connect) | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))) | |||
.Times(1); | |||
auto con = database::connect("testhost", 3306, "testuser", "password", "database", client_flags::empty()); | |||
connection con; | |||
con.connect("testhost", 3306, "testuser", "password", "database", client_flags::empty()); | |||
EXPECT_EQ(reinterpret_cast<MYSQL*>(0x123), con.handle()); | |||
EXPECT_EQ(reinterpret_cast<MYSQL*>(0x123), con.get_handle()); | |||
} | |||
TEST(MariaDbTests, MariaDB_errorCode) | |||
@@ -32,7 +33,11 @@ TEST(MariaDbTests, MariaDB_errorCode) | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(1000)); | |||
auto ret = database::error_code(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))); | |||
connection con(reinterpret_cast<MYSQL*>(0x123)); | |||
auto ret = con.error_code(); | |||
EXPECT_EQ(error_code::ErrorFirst, ret); | |||
} | |||
@@ -43,7 +48,11 @@ TEST(MariaDbTests, MariaDB_errorMessage) | |||
std::string msg("test"); | |||
EXPECT_CALL(mock, mysql_error(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(msg.data())); | |||
auto ret = database::error_msg(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))); | |||
connection con(reinterpret_cast<MYSQL*>(0x123)); | |||
auto ret = con.error_msg(); | |||
EXPECT_EQ(msg, ret); | |||
} | |||
@@ -51,7 +60,11 @@ TEST(MariaDbTests, MariaDB_errorMessage) | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_error(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(nullptr)); | |||
auto ret = database::error_msg(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))); | |||
connection con(reinterpret_cast<MYSQL*>(0x123)); | |||
auto ret = con.error_msg(); | |||
EXPECT_EQ(std::string(), ret); | |||
} | |||
} | |||
@@ -166,7 +179,7 @@ TEST(MariaDbTests, Connection_execute_success) | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
con.execute("SELECT * FROM blubb"); | |||
ASSERT_TRUE(static_cast<bool>(con.result())); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), con.result()->handle()); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), con.result()->get_handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
@@ -247,7 +260,7 @@ TEST(MariaDbTests, Connection_executeStored_success) | |||
auto ret = con.execute_stored("SELECT * FROM blubb"); | |||
EXPECT_EQ (ret, con.result()); | |||
ASSERT_TRUE(static_cast<bool>(ret)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->handle()); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->get_handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
@@ -330,7 +343,7 @@ TEST(MariaDbTests, Connection_executeUsed_success) | |||
auto ret = con.execute_used("SELECT * FROM blubb"); | |||
EXPECT_EQ (ret, con.result()); | |||
ASSERT_TRUE(static_cast<bool>(ret)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->handle()); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->get_handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
@@ -399,12 +412,12 @@ TEST(MariaDbTests, Result_rowindex_next_current) | |||
EXPECT_EQ(-1, result.rowindex()); | |||
auto row = result.next(); | |||
ASSERT_TRUE(static_cast<bool>(row)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15160), row->handle()); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15160), row->get_handle()); | |||
EXPECT_EQ (0, result.rowindex()); | |||
row = result.next(); | |||
ASSERT_TRUE(static_cast<bool>(row)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15161), row->handle()); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15161), row->get_handle()); | |||
EXPECT_EQ (1, result.rowindex()); | |||
auto current = result.current(); | |||
@@ -555,24 +568,6 @@ TEST(MariaDbTests, Result_columns) | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, StoredResult_rowoffset) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_row_tell(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW_OFFSET>(0))); | |||
EXPECT_CALL(mock, mysql_row_seek(reinterpret_cast<MYSQL_RES*>(0x51651), reinterpret_cast<MYSQL_ROW_OFFSET>(4))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW_OFFSET>(0))); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
auto offset = result.rowoffset(); | |||
EXPECT_EQ(reinterpret_cast<MYSQL_ROW_OFFSET>(0), offset); | |||
result.rowoffset(reinterpret_cast<MYSQL_ROW_OFFSET>(4)); | |||
} | |||
TEST(MariaDbTests, StoredResult_rowcount) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
@@ -907,4 +902,4 @@ TEST(MariaDbTests, Field_get) | |||
EXPECT_EQ(123, field0.get<int>()); | |||
EXPECT_EQ(std::string("asd"), field1.get<std::string>()); | |||
} | |||
} |