Переглянути джерело

* Updated cmake project structure

* Refactored existing code and added doxygen comments for mostly every public type
master
bergmann 4 роки тому
джерело
коміт
406e80570b
52 змінених файлів з 1686 додано та 1196 видалено
  1. +55
    -13
      CMakeLists.txt
  2. +0
    -46
      cmake/Findcpputils.cmake
  3. +0
    -34
      cmake/Findmariadb.cmake
  4. +36
    -0
      cmake/config.h.in
  5. +10
    -0
      cmake/cppmariadb-config.cmake
  6. +15
    -0
      cmake/cppmariadb-options.cmake
  7. +31
    -0
      cmake/cppmariadb-var.cmake
  8. +0
    -6
      cmake/options.cmake
  9. +20
    -17
      include/cppmariadb.h
  10. +17
    -27
      include/cppmariadb/column.h
  11. +22
    -0
      include/cppmariadb/column.inl
  12. +0
    -7
      include/cppmariadb/config.h
  13. +193
    -30
      include/cppmariadb/connection.h
  14. +185
    -0
      include/cppmariadb/connection.inl
  15. +0
    -25
      include/cppmariadb/database.h
  16. +4
    -4
      include/cppmariadb/enums.h
  17. +32
    -13
      include/cppmariadb/exception.h
  18. +17
    -0
      include/cppmariadb/exception.inl
  19. +67
    -17
      include/cppmariadb/field.h
  20. +28
    -21
      include/cppmariadb/field.inl
  21. +0
    -13
      include/cppmariadb/forward/column.h
  22. +0
    -10
      include/cppmariadb/forward/connection.h
  23. +0
    -10
      include/cppmariadb/forward/database.h
  24. +0
    -10
      include/cppmariadb/forward/field.h
  25. +0
    -14
      include/cppmariadb/forward/result.h
  26. +0
    -10
      include/cppmariadb/forward/row.h
  27. +0
    -10
      include/cppmariadb/forward/statement.h
  28. +0
    -10
      include/cppmariadb/forward/transaction.h
  29. +48
    -0
      include/cppmariadb/impl/handle.h
  30. +30
    -0
      include/cppmariadb/impl/handle.inl
  31. +0
    -38
      include/cppmariadb/impl/mariadb_handle.h
  32. +0
    -152
      include/cppmariadb/inline/connection.inl
  33. +0
    -48
      include/cppmariadb/inline/database.inl
  34. +0
    -72
      include/cppmariadb/inline/result.inl
  35. +0
    -234
      include/cppmariadb/inline/row.inl
  36. +89
    -25
      include/cppmariadb/result.h
  37. +63
    -0
      include/cppmariadb/result.inl
  38. +102
    -85
      include/cppmariadb/row.h
  39. +232
    -0
      include/cppmariadb/row.inl
  40. +106
    -23
      include/cppmariadb/statement.h
  41. +27
    -27
      include/cppmariadb/statement.inl
  42. +34
    -11
      include/cppmariadb/transaction.h
  43. +16
    -17
      include/cppmariadb/transaction.inl
  44. +112
    -34
      src/CMakeLists.txt
  45. +5
    -4
      src/cppmariadb/exception.cpp
  46. +13
    -9
      src/cppmariadb/result.cpp
  47. +6
    -7
      src/cppmariadb/row.cpp
  48. +8
    -5
      src/cppmariadb/statement.cpp
  49. +39
    -29
      test/CMakeLists.txt
  50. +24
    -29
      test/cppmariadb/cppmariadb.cpp
  51. +0
    -0
      test/cppmariadb/mock.cpp
  52. +0
    -0
      test/cppmariadb/mock.h

+ 55
- 13
CMakeLists.txt Переглянути файл

@@ -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 )

+ 0
- 46
cmake/Findcpputils.cmake Переглянути файл

@@ -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 ( )

+ 0
- 34
cmake/Findmariadb.cmake Переглянути файл

@@ -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 ( )

+ 36
- 0
cmake/config.h.in Переглянути файл

@@ -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>;
}

+ 10
- 0
cmake/cppmariadb-config.cmake Переглянути файл

@@ -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")

+ 15
- 0
cmake/cppmariadb-options.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 )

+ 31
- 0
cmake/cppmariadb-var.cmake Переглянути файл

@@ -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 ( )

+ 0
- 6
cmake/options.cmake Переглянути файл

@@ -1,6 +0,0 @@
Option ( CPPMARIADB_BUILD_SHARED
"Build cppmariadb shared library"
ON )
Option ( CPPMARIADB_INSTALL_DEV_FILES
"Install development files of cppmariadb"
ON )

+ 20
- 17
include/cppmariadb.h Переглянути файл

@@ -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"

+ 17
- 27
include/cppmariadb/column.h Переглянути файл

@@ -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);
};

}
}

+ 22
- 0
include/cppmariadb/column.inl Переглянути файл

@@ -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))
{ }

}

+ 0
- 7
include/cppmariadb/config.h Переглянути файл

@@ -1,7 +0,0 @@
#pragma once

#ifndef MARIADB_MOCK
#include <mariadb/mysql.h>
#include <mariadb/errmsg.h>
#include <mariadb/mysqld_error.h>
#endif

+ 193
- 30
include/cppmariadb/connection.h Переглянути файл

@@ -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);
};

}
}

+ 185
- 0
include/cppmariadb/connection.inl Переглянути файл

@@ -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)); }

}

+ 0
- 25
include/cppmariadb/database.h Переглянути файл

@@ -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);
};

}

+ 4
- 4
include/cppmariadb/enums.h Переглянути файл

@@ -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,
};

}
}

+ 32
- 13
include/cppmariadb/exception.h Переглянути файл

@@ -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"

+ 17
- 0
include/cppmariadb/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)
{ }

}

+ 67
- 17
include/cppmariadb/field.h Переглянути файл

@@ -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);
};

}
}

include/cppmariadb/inline/field.inl → include/cppmariadb/field.inl Переглянути файл

@@ -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)
{ }

}
}

+ 0
- 13
include/cppmariadb/forward/column.h Переглянути файл

@@ -1,13 +0,0 @@
#pragma once

#include <vector>
#include <cppmariadb/config.h>

namespace cppmariadb
{

struct column;

using column_vector = std::vector<column>;

}

+ 0
- 10
include/cppmariadb/forward/connection.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct connection;

}

+ 0
- 10
include/cppmariadb/forward/database.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct database;

}

+ 0
- 10
include/cppmariadb/forward/field.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct field;

}

+ 0
- 14
include/cppmariadb/forward/result.h Переглянути файл

@@ -1,14 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct result;

struct result_used;

struct result_stored;

}

+ 0
- 10
include/cppmariadb/forward/row.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct row;

}

+ 0
- 10
include/cppmariadb/forward/statement.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct statement;

}

+ 0
- 10
include/cppmariadb/forward/transaction.h Переглянути файл

@@ -1,10 +0,0 @@
#pragma once

#include <cppmariadb/config.h>

namespace cppmariadb
{

struct transaction;

}

+ 48
- 0
include/cppmariadb/impl/handle.h Переглянути файл

@@ -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);
};

} }

+ 30
- 0
include/cppmariadb/impl/handle.inl Переглянути файл

@@ -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; }

} }

+ 0
- 38
include/cppmariadb/impl/mariadb_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;
};

} }

+ 0
- 152
include/cppmariadb/inline/connection.inl Переглянути файл

@@ -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(); }

}

+ 0
- 48
include/cppmariadb/inline/database.inl Переглянути файл

@@ -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());
}
}

+ 0
- 72
include/cppmariadb/inline/result.inl Переглянути файл

@@ -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)
{ }

}

+ 0
- 234
include/cppmariadb/inline/row.inl Переглянути файл

@@ -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)
{ }
}

+ 89
- 25
include/cppmariadb/result.h Переглянути файл

@@ -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;
};

}
}

+ 63
- 0
include/cppmariadb/result.inl Переглянути файл

@@ -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)
{ }

}

+ 102
- 85
include/cppmariadb/row.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;
};

}
}

+ 232
- 0
include/cppmariadb/row.inl Переглянути файл

@@ -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); }

}

+ 106
- 23
include/cppmariadb/statement.h Переглянути файл

@@ -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;
};

}
}

include/cppmariadb/inline/statement.inl → include/cppmariadb/statement.inl Переглянути файл

@@ -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); }


}
}

+ 34
- 11
include/cppmariadb/transaction.h Переглянути файл

@@ -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();
};

}
}

include/cppmariadb/inline/transaction.inl → include/cppmariadb/transaction.inl Переглянути файл

@@ -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);
}


}
}

+ 112
- 34
src/CMakeLists.txt Переглянути файл

@@ -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 ()

+ 5
- 4
src/cppmariadb/exception.cpp Переглянути файл

@@ -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 << ")";
}
}
}

+ 13
- 9
src/cppmariadb/result.cpp Переглянути файл

@@ -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 */ }

+ 6
- 7
src/cppmariadb/row.cpp Переглянути файл

@@ -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


+ 8
- 5
src/cppmariadb/statement.cpp Переглянути файл

@@ -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();
}
}

+ 39
- 29
test/CMakeLists.txt Переглянути файл

@@ -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 ( )

test/cppmariadb.cpp → test/cppmariadb/cppmariadb.cpp Переглянути файл

@@ -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>());
}
}

test/mock.cpp → test/cppmariadb/mock.cpp Переглянути файл


test/mock.h → test/cppmariadb/mock.h Переглянути файл


Завантаження…
Відмінити
Зберегти