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