├── .gitignore ├── CMake ├── Modules │ └── FindODBC.cmake ├── SetVersion.cmake └── Sqlpp11ConnectorODBCConfig.cmake ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── sqlpp11 │ └── odbc │ ├── bind_result.h │ ├── connection.h │ ├── connection_config.h │ ├── insert_or.h │ ├── odbc.h │ ├── prepared_statement.h │ └── serializer.h ├── sqlpp11-connector-odbc.kdev4 ├── src ├── CMakeLists.txt ├── bind_result.cpp ├── connection.cpp ├── detail │ ├── connection_handle.cpp │ ├── connection_handle.h │ └── prepared_statement_handle.h └── prepared_statement.cpp ├── tests ├── CMakeLists.txt ├── ODBCTest.cpp └── TabSample.h └── version.h.in /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | build/ 3 | external/ 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | -------------------------------------------------------------------------------- /CMake/Modules/FindODBC.cmake: -------------------------------------------------------------------------------- 1 | # Find the ODBC driver manager includes and library. 2 | # Modified from POCO C++ FindODBC.cmake 3 | # https://github.com/pocoproject/poco 4 | # 5 | # This module defines 6 | # ODBC_INCLUDE_DIRECTORIES, where to find sql.h 7 | # ODBC_LIBRARIES, the libraries to link against to use ODBC 8 | 9 | set(ODBC_INCLUDE_DIR "${ODBC_INCLUDE_DIR}" CACHE PATH "Directory to include for ODBC headers") 10 | set(ODBC_LIBRARY_DIR "${ODBC_LIBRARY_DIR}" CACHE PATH "Directory containing ODBC library") 11 | 12 | set(SQL_HEADERS sql.h sqlext.h sqltypes.h) 13 | 14 | if(WIN32) 15 | 16 | set(ODBC_WIN_ARCH "${ODBC_WIN_ARCH}" CACHE PATH "ODBC Target Architecture Directory Name (x86*|x64|arm|arm64)") 17 | if(NOT ODBC_WIN_ARCH) 18 | if("${CMAKE_GENERATOR}" MATCHES "Win64") 19 | set(ODBC_WIN_ARCH "x64") 20 | elseif("${CMAKE_GENERATOR}" MATCHES "ARM64") 21 | set(ODBC_WIN_ARCH "arm64") 22 | elseif("${CMAKE_GENERATOR}" MATCHES "ARM") 23 | set(ODBC_WIN_ARCH "arm") 24 | else() 25 | set(ODBC_WIN_ARCH "x86") 26 | endif() 27 | endif() 28 | 29 | set(PROGENV "ProgramFiles(x86)") 30 | set(PROG32 $ENV{${PROGENV}}) 31 | if(NOT PROG32) 32 | set(PROG32 $ENV{PROGRAMFILES}) 33 | endif(NOT PROG32) 34 | find_path(ODBC_INCLUDE_DIRECTORIES 35 | NAMES ${SQL_HEADERS} 36 | HINTS ${ODBC_INCLUDE_DIR} 37 | "${PROG32}/Windows Kits/10/Include/10.0.16299.0/um" 38 | "${PROG32}/Windows Kits/10/Include/10.0.15063.0/um" 39 | "${PROG32}/Windows Kits/8.1/Include/um" 40 | "${PROG32}/Microsoft SDKs/Windows/v7.0/include" 41 | "${PROG32}/Microsoft SDKs/Windows/v6.0a/include" 42 | "C:/Program Files/ODBC/include" 43 | "C:/ODBC/include" 44 | DOC "Specify the directory containing sql.h." 45 | ) 46 | 47 | find_library(ODBC_LIBRARY 48 | NAMES odbc odbc32 49 | HINTS ${ODBC_LIBRARY_DIR} 50 | "${PROG32}/Windows Kits/10/Lib/10.0.16299.0/um/${ODBC_WIN_ARCH}" 51 | "${PROG32}/Windows Kits/10/Lib/10.0.15063.0/um/${ODBC_WIN_ARCH}" 52 | "${PROG32}/Windows Kits/8.1/Lib/winv6.3/um/${ODBC_WIN_ARCH}" 53 | "${PROG32}/Microsoft SDKs/Windows/v7.0/Lib" 54 | "${PROG32}/Microsoft SDKs/Windows/v6.0a/Lib" 55 | "C:/Program Files/ODBC/lib" 56 | "C:/ODBC/lib/debug" 57 | DOC "Specify the ODBC driver manager library here." 58 | ) 59 | else() 60 | find_path(ODBC_INCLUDE_DIRECTORIES 61 | NAMES ${SQL_HEADERS} 62 | HINTS ${ODBC_INCLUDE_DIR} 63 | /usr/include 64 | /usr/include/odbc 65 | /usr/local/include 66 | /usr/local/include/odbc 67 | /usr/local/odbc/include 68 | ) 69 | 70 | find_library(ODBC_LIBRARY 71 | NAMES iodbc unixodbc 72 | HINTS ${ODBC_LIBRARY_DIR} 73 | /usr/lib 74 | /usr/lib/odbc 75 | /usr/local/lib 76 | /usr/local/lib/odbc 77 | /usr/local/odbc/lib 78 | DOC "Specify the ODBC driver manager library here." 79 | ) 80 | endif(WIN32) 81 | 82 | if(ODBC_LIBRARY AND ODBC_INCLUDE_DIRECTORIES) 83 | set(ODBC_LIBRARIES ${ODBC_LIBRARY}) 84 | endif(ODBC_LIBRARY AND ODBC_INCLUDE_DIRECTORIES) 85 | 86 | 87 | include(FindPackageHandleStandardArgs) 88 | find_package_handle_standard_args(ODBC 89 | REQUIRED_VARS ODBC_INCLUDE_DIRECTORIES ODBC_LIBRARIES 90 | FAIL_MESSAGE "Could not find ODBC directories" 91 | ) 92 | 93 | -------------------------------------------------------------------------------- /CMake/SetVersion.cmake: -------------------------------------------------------------------------------- 1 | # Original work Copyright (c) 2017, Aaron Bishop 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # Redistributions in binary form must reproduce the above copyright notice, this 11 | # list of conditions and the following disclaimer in the documentation and/or 12 | # other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | set(PROJECT_VERSION "${SQLPP11_ODBC_VERSION_MAJOR}.${SQLPP11_ODBC_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") 26 | set(PROJECT_VERSION_MAJOR "${SQLPP11_ODBC_VERSION_MAJOR}") 27 | set(PROJECT_VERSION_MINOR "${SQLPP11_ODBC_VERSION_MAJOR}") 28 | set(PROJECT_VERSION_PATCH "${SQLPP11_ODBC_VERSION_MAJOR}") 29 | 30 | set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_MAJOR}") 31 | 32 | if(${SQLPP11_ODBC_VERSION_MINOR} LESS 10) 33 | set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_INT}0${SQLPP11_ODBC_VERSION_MINOR}") 34 | else() 35 | set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_INT}${SQLPP11_ODBC_VERSION_MINOR}") 36 | endif() 37 | 38 | if(${SQLPP11_ODBC_VERSION_PATCH} LESS 10) 39 | set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_INT}0${SQLPP11_ODBC_VERSION_PATCH}") 40 | else() 41 | set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_INT}${SQLPP11_ODBC_VERSION_PATCH}") 42 | endif() 43 | 44 | string(REGEX REPLACE "^0+" "" SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_INT}") 45 | 46 | set(SQLPP11_ODBC_VERSION "${PROJECT_VERSION}") 47 | 48 | configure_file(version.h.in version.h @ONLY) -------------------------------------------------------------------------------- /CMake/Sqlpp11ConnectorODBCConfig.cmake: -------------------------------------------------------------------------------- 1 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") 2 | 3 | include(CMakeFindDependencyMacro) 4 | find_dependency(Sqlpp11 REQUIRED) 5 | find_dependency(ODBC REQUIRED) 6 | 7 | include("${CMAKE_CURRENT_LIST_DIR}/Sqlpp11ConnectorODBCTargets.cmake") -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Original work Copyright (c) 2013-2015, Roland Bock 2 | # Modified work Copyright (c) 2016, Aaron Bishop 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | cmake_minimum_required(VERSION 3.2 FATAL_ERROR) 27 | 28 | project (sqlpp11-connector-odbc VERSION 0.6.0 LANGUAGES CXX) 29 | 30 | set(SQLPP11_ODBC_VERSION_MAJOR 0) 31 | set(SQLPP11_ODBC_VERSION_MINOR 6) 32 | set(SQLPP11_ODBC_VERSION_PATCH 0) 33 | include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/SetVersion.cmake") 34 | 35 | option(SQLPP11_ODBC_DISABLE_SHARED "Disable making sqlpp11-connector-odbc shared library" Off) 36 | option(SQLPP11_ODBC_DISABLE_STATIC "Disable making sqlpp11-connector-odbc static library" Off) 37 | 38 | find_package(Sqlpp11 REQUIRED) 39 | include_directories(${HinnantDate_INCLUDE_DIR} $) 40 | 41 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake/Modules/") 42 | find_package(ODBC REQUIRED) 43 | 44 | include_directories(${ODBC_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR}/include) 45 | 46 | enable_testing() 47 | 48 | if(NOT CMAKE_SQLPP11_CONNECTOR_ODBC_TESTS_IGNORE) 49 | add_subdirectory(tests) 50 | endif() 51 | 52 | add_library(sqlpp11-odbc INTERFACE) 53 | 54 | target_link_libraries(sqlpp11-odbc INTERFACE sqlpp11 ${ODBC_LIBRARIES}) 55 | 56 | install(TARGETS sqlpp11-odbc EXPORT Sqlpp11ConnectorODBCTargets) 57 | 58 | install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION include) 59 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/version.h" DESTINATION include/sqlpp11/odbc/) 60 | 61 | if(NOT SQLPP11_ODBC_DISABLE_SHARED) 62 | add_library(sqlpp11-odbc-shared SHARED 63 | src/connection.cpp 64 | src/bind_result.cpp 65 | src/prepared_statement.cpp 66 | src/detail/connection_handle.cpp) 67 | target_include_directories(sqlpp11-odbc-shared INTERFACE 68 | $ 69 | $ 70 | ) 71 | target_link_libraries(sqlpp11-odbc-shared sqlpp11-odbc) 72 | set_target_properties(sqlpp11-odbc-shared PROPERTIES OUTPUT_NAME sqlpp11-odbc) 73 | install(TARGETS sqlpp11-odbc-shared EXPORT Sqlpp11ConnectorODBCTargets DESTINATION lib) 74 | endif() 75 | if(NOT SQLPP11_ODBC_DISABLE_STATIC) 76 | add_library(sqlpp11-odbc-static STATIC 77 | src/connection.cpp 78 | src/bind_result.cpp 79 | src/prepared_statement.cpp 80 | src/detail/connection_handle.cpp) 81 | target_include_directories(sqlpp11-odbc-static INTERFACE 82 | $ 83 | $ 84 | ) 85 | target_link_libraries(sqlpp11-odbc-static sqlpp11-odbc) 86 | set_target_properties(sqlpp11-odbc-static PROPERTIES OUTPUT_NAME sqlpp11-odbc) 87 | install(TARGETS sqlpp11-odbc-static EXPORT Sqlpp11ConnectorODBCTargets DESTINATION lib) 88 | endif() 89 | 90 | include(CMakePackageConfigHelpers) 91 | 92 | write_basic_package_version_file( 93 | "${CMAKE_CURRENT_BINARY_DIR}/CMake/Sqlpp11ConnectorODBCConfigVersion.cmake" 94 | VERSION ${PROJECT_VERSION} 95 | COMPATIBILITY AnyNewerVersion 96 | ) 97 | 98 | export(EXPORT Sqlpp11ConnectorODBCTargets 99 | FILE "${CMAKE_CURRENT_BINARY_DIR}/CMake/Sqlpp11ConnectorODBCTargets.cmake" 100 | ) 101 | 102 | configure_file(CMake/Sqlpp11ConnectorODBCConfig.cmake 103 | "${CMAKE_CURRENT_BINARY_DIR}/CMake/Sqlpp11ConnectorODBCConfig.cmake" 104 | COPYONLY 105 | ) 106 | 107 | set(ConfigPackageLocation lib/CMake/Sqlpp11ConnectorODBC) 108 | install(EXPORT Sqlpp11ConnectorODBCTargets 109 | FILE 110 | Sqlpp11ConnectorODBCTargets.cmake 111 | DESTINATION 112 | ${ConfigPackageLocation} 113 | ) 114 | 115 | install( 116 | FILES 117 | "CMake/Sqlpp11ConnectorODBCConfig.cmake" 118 | "${CMAKE_CURRENT_BINARY_DIR}/CMake/Sqlpp11ConnectorODBCConfigVersion.cmake" 119 | "CMake/Modules/FindODBC.cmake" 120 | DESTINATION 121 | ${ConfigPackageLocation} 122 | ) 123 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Original work Copyright (c) 2013-2015, Roland Bock 2 | Modified work Copyright (c) 2016, Aaron Bishop 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sqlpp11-connector-odbc 2 | ====================== 3 | ODBC connector for sqlpp11 4 | 5 | Sample Code: 6 | ------------ 7 | ```C++ 8 | namespace odbc = sqlpp::odbc; 9 | int main() { 10 | odbc::connection_config config; 11 | //DSN between [ ] in odbc.ini for unixodbc 12 | config.data_source_name = "MyDSN"; 13 | //Database to use. Leave empty to execute your own USE statement 14 | config.database = "my_schema"; 15 | //Username for data source 16 | config.username = "user"; 17 | //Authentication for data source 18 | config.password = "password"; 19 | 20 | //Valid types currently include MySQL, PostgreSQL, SQLite3, or TSQL 21 | //This is used to get the last insert ID, used by insert function 22 | config.type = odbc::connection_config::ODBC_Type::MySQL; 23 | config.debug = true; 24 | odbc::connection db(config); 25 | ... 26 | } 27 | ``` 28 | 29 | Requirements: 30 | ------------- 31 | __Compiler:__ 32 | sqlpp11-connector-odbc makes use of C++11 and requires a recent compiler and STL. The following compilers are known to compile the test programs: 33 | * g++-7.2.0 on Arch Linux as of 2017-10-25 34 | * Visual Studio on Windows 7 using LLVM toolset as of 2017-10-29 35 | 36 | __C++ SQL Layer:__ 37 | sqlpp11-connector-odbc depends on sqlpp11 (https://github.com/rbock/sqlpp11). 38 | 39 | __ODBC:__ 40 | Appropriate ODBC library (like unixodbc or Windows's ODBC library), and ODBC connector capable of ODBC 3.0 or higher. Tested with unixodbc 2.3.4. 41 | 42 | __Threading:__ 43 | Using the same `sqlpp::odbc::connection` object on multiple threads is not safe. Instead, pass the `sqlpp::odbc::connection_config` to create a new connection (which may be safe depending on your ODBC connector) or use mutexes. 44 | 45 | __Wide Strings:__ 46 | While sqlpp11-connector-odbc should compile on Windows (possibly with some modifications), sqlpp11 uses std::string and std::ostream. 47 | 48 | __Windows:__ 49 | To build on Windows for 64 bit, first build and install sqlpp11: 50 | ```sh 51 | mkdir sqlpp11/build 52 | cd sqlpp11/build 53 | cmake .. -G"Visual Studio 15 2017 Win64" -T"LLVM-vs2014" -DHinnantDate_ROOT_DIR="C:/Users/myuser/source/repos/date/include" 54 | # Use VS 2017 to build INSTALL project 55 | # As admin, run the Post Build script for INSTALL project 56 | ``` 57 | Then you can build sqlpp11-connector-odbc the same way. -------------------------------------------------------------------------------- /include/sqlpp11/odbc/bind_result.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_BIND_RESULT_H 29 | #define SQLPP11_ODBC_BIND_RESULT_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #ifdef _WIN32 38 | # ifndef WIN32_LEAN_AND_MEAN 39 | # define WIN32_LEAN_AND_MEAN 40 | # endif 41 | # ifndef NOMINMAX 42 | # define NOMINMAX 43 | # endif 44 | # include 45 | #endif 46 | 47 | #include 48 | 49 | namespace sqlpp { 50 | namespace odbc { 51 | class connection; 52 | namespace detail { 53 | struct prepared_statement_handle_t; 54 | } 55 | 56 | class bind_result_t { 57 | friend connection; 58 | std::shared_ptr _handle; 59 | 60 | public: 61 | bind_result_t() = default; 62 | bind_result_t(const std::shared_ptr& handle); 63 | bind_result_t(const bind_result_t&) = delete; 64 | bind_result_t(bind_result_t&& rhs) = default; 65 | bind_result_t& operator=(const bind_result_t&) = delete; 66 | bind_result_t& operator=(bind_result_t&&) = default; 67 | ~bind_result_t() = default; 68 | 69 | bool operator==(const bind_result_t& rhs) const { 70 | return _handle == rhs._handle; 71 | } 72 | 73 | template 74 | void next(ResultRow& result_row) { 75 | if (!_handle) { 76 | result_row._invalidate(); 77 | return; 78 | } 79 | if (next_impl()) { 80 | if (not result_row) { 81 | result_row._validate(); 82 | } 83 | std::cerr << "Calling _bind" << std::endl; 84 | result_row._bind(*this); 85 | } else { 86 | if (result_row) { 87 | result_row._invalidate(); 88 | } 89 | } 90 | } 91 | 92 | void _bind_boolean_result(size_t index, signed char* value, bool* is_null); 93 | void _bind_floating_point_result(size_t index, double* value, bool* is_null); 94 | void _bind_integral_result(size_t index, int64_t* value, bool* is_null); 95 | void _bind_text_result(size_t index, const char** text, size_t* len); 96 | void _bind_date_result(size_t index, ::sqlpp::day_point::_cpp_value_type* value, bool* is_null); 97 | void _bind_date_time_result(size_t index, ::sqlpp::time_point::_cpp_value_type* value, bool* is_null); 98 | void _bind_time_of_day_result(size_t index, ::sqlpp::time_of_day::_cpp_value_type* value, bool* is_null); 99 | void _bind_timestamp_result(size_t index, SQL_TIMESTAMP_STRUCT* value, bool* is_null); 100 | 101 | size_t size() const; 102 | private: 103 | bool next_impl(); 104 | }; 105 | } 106 | } 107 | 108 | #endif //SQLPP11_ODBC_BIND_RESULT_H 109 | -------------------------------------------------------------------------------- /include/sqlpp11/odbc/connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_CONNECTION_H 29 | #define SQLPP11_ODBC_CONNECTION_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #ifdef _WIN32 43 | # ifndef WIN32_LEAN_AND_MEAN 44 | # define WIN32_LEAN_AND_MEAN 45 | # endif 46 | # ifndef NOMINMAX 47 | # define NOMINMAX 48 | # endif 49 | # include 50 | #endif 51 | 52 | #include 53 | 54 | namespace sqlpp { 55 | namespace odbc { 56 | namespace detail { 57 | struct connection_handle_t; 58 | } 59 | 60 | class connection : public sqlpp::connection 61 | { 62 | std::unique_ptr _handle; 63 | bool _transaction_active = false; 64 | 65 | // direct execution 66 | bind_result_t select_impl(const std::string& statement); 67 | size_t insert_impl(const std::string& statement); 68 | size_t update_impl(const std::string& statement); 69 | size_t remove_impl(const std::string& statement); 70 | 71 | // prepared execution 72 | prepared_statement_t prepare_impl(const std::string& statement); 73 | bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement); 74 | size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement); 75 | size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement); 76 | size_t run_prepared_update_impl(prepared_statement_t& prepared_statement); 77 | size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement); 78 | 79 | public: 80 | using _prepared_statement_t = prepared_statement_t; 81 | using _context_t = serializer_t; 82 | using _serializer_context_t = _context_t; 83 | using _interpreter_context_t = _context_t; 84 | 85 | struct _tags { 86 | using _null_result_is_trivial_value = std::true_type; 87 | }; 88 | 89 | template 90 | static _context_t& _serialize_interpretable(const T& t, _context_t& context) { 91 | return ::sqlpp::serialize(t, context); 92 | } 93 | 94 | template 95 | static _context_t& _interpret_interpretable(const T& t, _context_t& context) { 96 | return ::sqlpp::serialize(t, context); 97 | } 98 | 99 | connection(const connection_config& config); 100 | connection(const driver_connection_config& config); 101 | connection(const driver_connection_config& config, std::string& out_connection, size_t out_max = 255); 102 | 103 | ~connection(); 104 | connection(const connection&) = delete; 105 | connection(connection&&) = delete; 106 | connection& operator=(const connection&) = delete; 107 | connection& operator=(connection&&) = delete; 108 | 109 | //! select returns a result (which can be iterated row by row) 110 | template 111 | bind_result_t select(const Select& s) { 112 | _context_t context(*this); 113 | serialize(s, context); 114 | return select_impl(context.str()); 115 | } 116 | 117 | template 118 | _prepared_statement_t prepare_select(Select& s) { 119 | _context_t context(*this); 120 | serialize(s, context); 121 | return prepare_impl(context.str()); 122 | } 123 | 124 | template 125 | bind_result_t run_prepared_select(const PreparedSelect& s) { 126 | s._prepared_statement._reset(); 127 | s._bind_params(); 128 | return run_prepared_select_impl(s._prepared_statement); 129 | } 130 | 131 | //! insert returns the last auto_incremented id (or zero, if there is none) 132 | template 133 | size_t insert(const Insert& i) { 134 | _context_t context(*this); 135 | serialize(i, context); 136 | return insert_impl(context.str()); 137 | } 138 | 139 | template 140 | _prepared_statement_t prepare_insert(Insert& i) { 141 | _context_t context(*this); 142 | serialize(i, context); 143 | return prepare_impl(context.str()); 144 | } 145 | 146 | template 147 | size_t run_prepared_insert(const PreparedInsert& i) { 148 | i._prepared_statement._reset(); 149 | i._bind_params(); 150 | return run_prepared_insert_impl(i._prepared_statement); 151 | } 152 | 153 | //! update returns the number of affected rows 154 | template 155 | size_t update(const Update& u) { 156 | _context_t context(*this); 157 | serialize(u, context); 158 | return update_impl(context.str()); 159 | } 160 | 161 | template 162 | _prepared_statement_t prepare_update(Update& u) { 163 | _context_t context(*this); 164 | serialize(u, context); 165 | return prepare_impl(context.str()); 166 | } 167 | 168 | template 169 | size_t run_prepared_update(const PreparedUpdate& u) { 170 | u._prepared_statement._reset(); 171 | u._bind_params(); 172 | return run_prepared_update_impl(u._prepared_statement); 173 | } 174 | 175 | //! remove returns the number of removed rows 176 | template 177 | size_t remove(const Remove& r) { 178 | _context_t context(*this); 179 | serialize(r, context); 180 | return remove_impl(context.str()); 181 | } 182 | 183 | template 184 | _prepared_statement_t prepare_remove(Remove& r) { 185 | _context_t context(*this); 186 | serialize(r, context); 187 | return prepare_impl(context.str()); 188 | } 189 | 190 | template 191 | size_t run_prepared_remove(const PreparedRemove& r) { 192 | r._prepared_statement._reset(); 193 | r._bind_params(); 194 | return run_prepared_remove_impl(r._prepared_statement); 195 | } 196 | 197 | //! execute arbitrary command (e.g. create a table) 198 | size_t execute(const std::string& command); 199 | 200 | template < 201 | typename Execute, 202 | typename Enable = typename std::enable_if::value, void>::type> 203 | size_t execute(const Execute& x) { 204 | _context_t context(*this); 205 | serialize(x, context); 206 | return execute(context.str()); 207 | } 208 | 209 | template 210 | _prepared_statement_t prepare_execute(Execute& x) { 211 | _context_t context(*this); 212 | serialize(x, context); 213 | return prepare_impl(context.str()); 214 | } 215 | 216 | template 217 | void run_prepared_execute(const PreparedInsert& x) { 218 | x._prepared_statement._reset(); 219 | x._bind_params(); 220 | return run_prepared_execute_impl(x._prepared_statement); 221 | } 222 | 223 | //! escape given string (does not quote, though) 224 | std::string escape(const std::string& s) const; 225 | 226 | //! call run on the argument 227 | template 228 | auto _run(const T& t, const ::sqlpp::consistent_t&) -> decltype(t._run(*this)) { 229 | return t._run(*this); 230 | } 231 | 232 | template 233 | auto _run(const T& t, Check) -> Check; 234 | 235 | template 236 | auto operator()(const T& t) 237 | -> decltype(this->_run(t, sqlpp::run_check_t<_serializer_context_t, T>{})) { 238 | return _run(t, sqlpp::run_check_t<_serializer_context_t, T>{}); 239 | } 240 | 241 | //! call prepare on the argument 242 | template 243 | auto _prepare(const T& t, const std::true_type&) -> decltype(t._prepare(*this)) { 244 | return t._prepare(*this); 245 | } 246 | 247 | template 248 | auto _prepare(const T& t, const std::false_type&) -> void; 249 | 250 | template 251 | auto prepare(const T& t) 252 | -> decltype(this->_prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{})) { 253 | sqlpp::prepare_check_t<_serializer_context_t, T>::_(); 254 | return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{}); 255 | } 256 | 257 | //! start transaction 258 | void start_transaction(); 259 | 260 | //! commit transaction (or throw if the transaction has been finished already) 261 | void commit_transaction(); 262 | 263 | //! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished 264 | // already) 265 | void rollback_transaction(bool report); 266 | 267 | //! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor) 268 | void report_rollback_failure(const std::string message) noexcept; 269 | 270 | ::SQLHENV* native_handle(); 271 | 272 | size_t last_insert_id(); 273 | }; 274 | 275 | inline std::string serializer_t::escape(std::string arg) { 276 | return _db.escape(arg); 277 | } 278 | } 279 | } 280 | 281 | #endif 282 | 283 | -------------------------------------------------------------------------------- /include/sqlpp11/odbc/connection_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_CONNECTION_CONFIG_H 29 | #define SQLPP11_ODBC_CONNECTION_CONFIG_H 30 | 31 | #include 32 | #include 33 | 34 | namespace sqlpp { 35 | namespace odbc { 36 | enum class ODBC_Type 37 | { 38 | MySQL, 39 | PostgreSQL, 40 | SQLite3, 41 | TSQL 42 | }; 43 | 44 | enum class driver_completion : unsigned short 45 | { 46 | no_prompt = 0, 47 | complete = 1, 48 | prompt = 2, 49 | complete_required = 3 50 | }; 51 | 52 | struct connection_config { 53 | connection_config() : data_source_name(), username(), password(), type(ODBC_Type::TSQL), debug(false) {} 54 | connection_config(const connection_config&) = default; 55 | connection_config(connection_config&&) = default; 56 | 57 | connection_config(std::string dsn, ODBC_Type t=ODBC_Type::TSQL, std::string vf = {}, bool dbg = false) 58 | : data_source_name(std::forward(dsn)), username(), password(), type(t), debug(dbg) {} 59 | 60 | std::string data_source_name; 61 | std::string username; 62 | std::string password; 63 | ODBC_Type type; 64 | bool debug; 65 | }; 66 | 67 | inline bool operator==(const connection_config& a, const connection_config& b) 68 | { 69 | return 70 | a.data_source_name == b.data_source_name && 71 | a.username == b.username && 72 | a.password == b.password && 73 | a.type == b.type && 74 | a.debug == b.debug; 75 | } 76 | 77 | inline bool operator!=(const connection_config& a, const connection_config& b) 78 | { 79 | return !(a == b); 80 | } 81 | 82 | struct driver_connection_config { 83 | driver_connection_config() : window{nullptr}, connection(), completion(driver_completion::no_prompt), type(ODBC_Type::TSQL), debug(false) {} 84 | driver_connection_config(const driver_connection_config& ) = default; 85 | driver_connection_config(driver_connection_config&& ) = default; 86 | 87 | void* window; 88 | std::string connection; 89 | driver_completion completion; 90 | ODBC_Type type; 91 | bool debug; 92 | }; 93 | 94 | inline bool operator==(const driver_connection_config& a, const driver_connection_config& b) 95 | { 96 | return 97 | a.connection == b.connection && 98 | a.window == b.window && 99 | a.completion == b.completion && 100 | a.type == b.type && 101 | a.debug == b.debug; 102 | } 103 | 104 | inline bool operator!=(const driver_connection_config& a, const driver_connection_config& b) 105 | { 106 | return !(a == b); 107 | } 108 | } 109 | } 110 | 111 | #endif //SQLPP11_ODBC_CONNECTION_CONFIG_H 112 | -------------------------------------------------------------------------------- /include/sqlpp11/odbc/insert_or.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_INSERT_OR_H 29 | #define SQLPP11_ODBC_INSERT_OR_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace sqlpp { 41 | namespace odbc { 42 | struct insert_or_replace_name_t {}; 43 | struct insert_or_ignore_name_t {}; 44 | 45 | template 46 | struct insert_or_t : public statement_name_t { 47 | using _traits = make_traits; 48 | struct _alias_t { 49 | static constexpr const char _literal[] = "insert_or"; 50 | using _name_t = sqlpp::make_char_sequence; 51 | }; 52 | 53 | template 54 | struct _result_methods_t { 55 | using _statement_t = Statement; 56 | 57 | const _statement_t& _get_statement() const { 58 | return static_cast(*this); 59 | } 60 | 61 | template 62 | auto _run(Db& db) const -> decltype(db.insert(this->_get_statement())) { 63 | return db.insert(_get_statement()); 64 | } 65 | 66 | template 67 | auto _prepare(Db& db) const -> prepared_insert_t { 68 | return {{}, db.prepare_insert(_get_statement())}; 69 | } 70 | }; 71 | }; 72 | 73 | template 74 | using blank_insert_or_t = 75 | statement_t, no_into_t, no_insert_value_list_t>; 76 | 77 | template 78 | using blank_insert_or_replace_t = blank_insert_or_t; 79 | 80 | template 81 | using blank_insert_or_ignore_t = blank_insert_or_t; 82 | 83 | inline auto insert_or_replace() -> blank_insert_or_replace_t { 84 | return {blank_insert_or_replace_t()}; 85 | } 86 | 87 | template 88 | constexpr auto insert_or_replace_into(Table table) -> decltype(blank_insert_or_replace_t().into(table)) { 89 | return {blank_insert_or_replace_t().into(table)}; 90 | } 91 | 92 | template 93 | constexpr auto dynamic_insert_or_replace(const Database&) -> decltype(blank_insert_or_replace_t()) { 94 | return {blank_insert_or_replace_t()}; 95 | } 96 | 97 | template 98 | constexpr auto dynamic_insert_or_replace_into(const Database&, Table table) 99 | -> decltype(blank_insert_or_replace_t().into(table)) { 100 | return {blank_insert_or_replace_t().into(table)}; 101 | } 102 | 103 | inline auto insert_or_ignore() -> blank_insert_or_ignore_t { 104 | return {blank_insert_or_ignore_t()}; 105 | } 106 | 107 | template 108 | constexpr auto insert_or_ignore_into(Table table) -> decltype(blank_insert_or_ignore_t().into(table)) { 109 | return {blank_insert_or_ignore_t().into(table)}; 110 | } 111 | 112 | template 113 | constexpr auto dynamic_insert_or_ignore(const Database&) -> decltype(blank_insert_or_ignore_t()) { 114 | return {blank_insert_or_ignore_t()}; 115 | } 116 | 117 | template 118 | constexpr auto dynamic_insert_or_ignore_into(const Database&, Table table) 119 | -> decltype(blank_insert_or_ignore_t().into(table)) { 120 | return {blank_insert_or_ignore_t().into(table)}; 121 | } 122 | } 123 | 124 | template 125 | struct serializer_t { 126 | using _serialize_check = consistent_t; 127 | using T = odbc::insert_or_replace_name_t; 128 | 129 | static Context& _(const T& t, Context& context) { 130 | context << "INSERT OR REPLACE "; 131 | return context; 132 | } 133 | }; 134 | 135 | template 136 | struct serializer_t 137 | { 138 | using _serialize_check = consistent_t; 139 | using T = odbc::insert_or_ignore_name_t; 140 | 141 | static Context& _(const T& t, Context& context) { 142 | context << "INSERT OR IGNORE "; 143 | return context; 144 | } 145 | }; 146 | } 147 | 148 | #endif //SQLPP11_ODBC_INSERT_OR_H -------------------------------------------------------------------------------- /include/sqlpp11/odbc/odbc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_ODBC_H 29 | #define SQLPP11_ODBC_ODBC_H 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #endif //SQLPP11_ODBC_ODBC_H 36 | -------------------------------------------------------------------------------- /include/sqlpp11/odbc/prepared_statement.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_PREPARED_STATEMENT_H 29 | #define SQLPP11_ODBC_PREPARED_STATEMENT_H 30 | 31 | #ifdef _WIN32 32 | # ifndef WIN32_LEAN_AND_MEAN 33 | # define WIN32_LEAN_AND_MEAN 34 | # endif 35 | # ifndef NOMINMAX 36 | # define NOMINMAX 37 | # endif 38 | # include 39 | #endif 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | namespace sqlpp { 47 | namespace odbc { 48 | class connection; 49 | 50 | namespace detail { 51 | struct prepared_statement_handle_t; 52 | } 53 | 54 | class prepared_statement_t { 55 | friend ::sqlpp::odbc::connection; 56 | std::shared_ptr _handle; 57 | 58 | public: 59 | prepared_statement_t() = default; 60 | prepared_statement_t(std::shared_ptr&& handle); 61 | prepared_statement_t(const prepared_statement_t&) = delete; 62 | prepared_statement_t(prepared_statement_t&& rhs) = default; 63 | prepared_statement_t& operator=(const prepared_statement_t&) = delete; 64 | prepared_statement_t& operator=(prepared_statement_t&&) = default; 65 | ~prepared_statement_t() = default; 66 | 67 | SQLHSTMT native_handle(); 68 | 69 | bool operator==(const prepared_statement_t& rhs) const { 70 | return _handle == rhs._handle; 71 | } 72 | void _reset(); 73 | void _bind_boolean_parameter(size_t index, const signed char* value, bool is_null); 74 | void _bind_floating_point_parameter(size_t index, const double* value, bool is_null); 75 | void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null); 76 | void _bind_text_parameter(size_t index, const std::string* value, bool is_null); 77 | void _bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null); 78 | void _bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null); 79 | void _bind_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null); 80 | void _bind_timestamp_parameter(size_t index, const SQL_TIMESTAMP_STRUCT* value, bool is_null); 81 | 82 | }; 83 | 84 | } 85 | } 86 | 87 | #endif //SQLPP11_ODBC_PREPARED_STATEMENT_H -------------------------------------------------------------------------------- /include/sqlpp11/odbc/serializer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_SERIALIZER_H 29 | #define SQLPP11_ODBC_SERIALIZER_H 30 | 31 | #ifdef _WIN32 32 | # ifndef WIN32_LEAN_AND_MEAN 33 | # define WIN32_LEAN_AND_MEAN 34 | # endif 35 | # ifndef NOMINMAX 36 | # define NOMINMAX 37 | # endif 38 | # include 39 | #endif 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | namespace sqlpp 47 | { 48 | namespace odbc { 49 | struct serializer_t; 50 | } 51 | #if ODBCVER < 0x0300 52 | struct assert_no_with_t 53 | { 54 | using type = std::false_type; 55 | 56 | template 57 | static void _() 58 | { 59 | static_assert(wrong_t::value, "ODBC versions prior to 3.0 unsupported"); 60 | } 61 | }; 62 | #endif 63 | namespace odbc { 64 | struct serializer_t { 65 | serializer_t(const connection& db) : _db(db), _count(1) {} 66 | 67 | template 68 | std::ostream& operator<<(T t) { 69 | return _os << t; 70 | } 71 | 72 | std::string escape(std::string arg); 73 | 74 | std::string str() const { 75 | return _os.str(); 76 | } 77 | 78 | size_t count() const { 79 | return _count; 80 | } 81 | 82 | void pop_count() { 83 | ++_count; 84 | } 85 | 86 | const connection& _db; 87 | std::stringstream _os; 88 | size_t _count; 89 | }; 90 | } 91 | template 92 | struct serializer_t> 93 | { 94 | using _serialize_check = consistent_t; 95 | using T = concat_t; 96 | 97 | static odbc::serializer_t& _(const T& t, odbc::serializer_t& context) 98 | { 99 | context << "{fn CONCAT("; 100 | interpret_tuple(t._args, ',', context); 101 | context << ")}"; 102 | return context; 103 | } 104 | }; 105 | template <> 106 | struct serializer_t 107 | { 108 | using _serialize_check = consistent_t; 109 | using T = insert_default_values_data_t; 110 | 111 | static odbc::serializer_t& _(const T& t, odbc::serializer_t& context) 112 | { 113 | context << " () VALUES()"; 114 | return context; 115 | } 116 | }; 117 | } 118 | 119 | #endif //SQLPP11_ODBC_SERIALIZER_H -------------------------------------------------------------------------------- /sqlpp11-connector-odbc.kdev4: -------------------------------------------------------------------------------- 1 | [Project] 2 | CreatedFrom=CMakeLists.txt 3 | Manager=KDevCMakeManager 4 | Name=sqlpp11-connector-odbc 5 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Original work Copyright (c) 2013-2015, Roland Bock 2 | # Modified work Copyright (c) 2016, Aaron Bishop 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | add_library(sqlpp-odbc-static STATIC 27 | connection.cpp 28 | bind_result.cpp 29 | prepared_statement.cpp 30 | detail/connection_handle.cpp) 31 | add_library(sqlpp-odbc-shared SHARED 32 | connection.cpp 33 | bind_result.cpp 34 | prepared_statement.cpp 35 | detail/connection_handle.cpp) 36 | 37 | target_link_libraries(sqlpp-odbc-static ${ODBC_LIBRARIES}) 38 | target_link_libraries(sqlpp-odbc-shared ${ODBC_LIBRARIES}) 39 | 40 | set_target_properties(sqlpp-odbc-shared PROPERTIES OUTPUT_NAME sqlpp-odbc) 41 | set_target_properties(sqlpp-odbc-static PROPERTIES OUTPUT_NAME sqlpp-odbc) 42 | 43 | install(TARGETS sqlpp-odbc-static DESTINATION ${DESTDIR}/lib) 44 | install(TARGETS sqlpp-odbc-shared DESTINATION ${DESTDIR}/lib) 45 | -------------------------------------------------------------------------------- /src/bind_result.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #ifdef _WIN32 34 | # ifndef WIN32_LEAN_AND_MEAN 35 | # define WIN32_LEAN_AND_MEAN 36 | # endif 37 | # ifndef NOMINMAX 38 | # define NOMINMAX 39 | # endif 40 | # include 41 | #endif 42 | 43 | #include 44 | #include 45 | #include "detail/prepared_statement_handle.h" 46 | #include "detail/connection_handle.h" 47 | #include 48 | #include 49 | 50 | namespace sqlpp { 51 | namespace odbc { 52 | bind_result_t::bind_result_t(const std::shared_ptr& handle) : _handle(handle){ 53 | if(_handle and _handle->debug){ 54 | std::cerr << "ODBC debug: Constructing bind result, using handle at " << _handle.get() << std::endl; 55 | } 56 | } 57 | 58 | void bind_result_t::_bind_boolean_result(size_t index, signed char* value, bool* is_null) { 59 | if(_handle->debug) { 60 | std::cerr << "ODBC debug: binding boolean result " << *value << " at index " << index << std::endl; 61 | } 62 | SQLLEN ind(0); 63 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_BIT, value, sizeof(signed char), &ind))) { 64 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_BIT): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 65 | } 66 | if(is_null) { 67 | *is_null = (ind == SQL_NULL_DATA); 68 | } 69 | } 70 | 71 | void bind_result_t::_bind_floating_point_result(size_t index, double* value, bool* is_null) { 72 | if(_handle->debug) { 73 | std::cerr << "ODBC debug: binding floating_point result " << *value << " at index " << index << std::endl; 74 | } 75 | SQLLEN ind(0); 76 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_DOUBLE, value, sizeof(double), &ind))) { 77 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_DOUBLE): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 78 | } 79 | if(is_null) { 80 | *is_null = (ind == SQL_NULL_DATA); 81 | } 82 | } 83 | 84 | void bind_result_t::_bind_integral_result(size_t index, int64_t* value, bool* is_null) { 85 | if(_handle->debug) { 86 | std::cerr << "ODBC debug: binding integral result " << *value << " at index " << index << std::endl; 87 | } 88 | SQLLEN ind(0); 89 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_SBIGINT, value, sizeof(int64_t), &ind))) { 90 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_SBIGINT): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 91 | } 92 | if(is_null) { 93 | *is_null = (ind == SQL_NULL_DATA); 94 | } 95 | } 96 | 97 | void bind_result_t::_bind_text_result(size_t index, const char** value, size_t* len) { 98 | if(_handle->debug) { 99 | std::cerr << "ODBC debug: binding text result at index " << index << std::endl; 100 | } 101 | assert(len); 102 | SQLLEN ind(0); 103 | *value = new char[256]; 104 | 105 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_CHAR,(SQLPOINTER) *value, 256, &ind))) { 106 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_CHAR): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 107 | } 108 | if(ind == SQL_NULL_DATA || ind == SQL_NO_TOTAL || ind < 0) { 109 | *len = 0; 110 | } else { 111 | *len = ind; 112 | } 113 | if(ind > 256) { 114 | delete[] *value; 115 | *value = new char[ind]; 116 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_CHAR,(SQLPOINTER) *value, ind, &ind))) { 117 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_CHAR): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 118 | } 119 | } 120 | } 121 | 122 | void bind_result_t::_bind_date_result(size_t index, ::sqlpp::day_point::_cpp_value_type* value, bool* is_null) { 123 | if(_handle->debug) { 124 | std::cerr << "ODBC debug: binding date result at index " << index << std::endl; 125 | } 126 | SQL_DATE_STRUCT date_struct = {0}; 127 | SQLLEN ind(0); 128 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_TYPE_DATE, &date_struct, sizeof(SQL_DATE_STRUCT), &ind))) { 129 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_TYPE_DATE): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 130 | } 131 | *is_null = (ind == SQL_NULL_DATA); 132 | if(!*is_null) { 133 | *value = ::sqlpp::day_point::_cpp_value_type( ::date::year(date_struct.year) / date_struct.month / date_struct.day ); 134 | } 135 | } 136 | 137 | void bind_result_t::_bind_date_time_result(size_t index, ::sqlpp::time_point::_cpp_value_type* value, bool* is_null) { 138 | if(_handle->debug) { 139 | std::cerr << "ODBC debug: binding date_time result at index " << index << std::endl; 140 | } 141 | 142 | SQL_TIMESTAMP_STRUCT timestamp_struct = {0}; 143 | SQLLEN ind(0); 144 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_TYPE_TIMESTAMP, ×tamp_struct, /*std::max(*/sizeof(SQL_TIMESTAMP_STRUCT)/*,22)*/, nullptr))) { 145 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_TYPE_TIMESTAMP): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 146 | } 147 | *is_null = (ind == SQL_NULL_DATA); 148 | if(!*is_null) { 149 | *value = ::sqlpp::day_point::_cpp_value_type(::date::year(timestamp_struct.year) / timestamp_struct.month / timestamp_struct.day); 150 | *value += 151 | std::chrono::hours(timestamp_struct.hour) + 152 | std::chrono::minutes(timestamp_struct.minute) + 153 | std::chrono::seconds(timestamp_struct.second) + 154 | std::chrono::duration_cast(std::chrono::nanoseconds(timestamp_struct.fraction)); 155 | } 156 | } 157 | void bind_result_t::_bind_timestamp_result(size_t index, SQL_TIMESTAMP_STRUCT* value, bool* is_null) { 158 | if(_handle->debug) { 159 | std::cerr << "ODBC debug: binding date_time result at index " << index << std::endl; 160 | } 161 | 162 | SQLLEN ind(0); 163 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_TYPE_TIMESTAMP, value, /*std::max(*/sizeof(SQL_TIMESTAMP_STRUCT)/*,22)*/, nullptr))) { 164 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_TYPE_TIMESTAMP): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 165 | } 166 | *is_null = (ind == SQL_NULL_DATA); 167 | } 168 | void bind_result_t::_bind_time_of_day_result(size_t index, ::sqlpp::time_of_day::_cpp_value_type* value, bool* is_null) { 169 | if(_handle->debug) { 170 | std::cerr << "ODBC debug: binding date_time result at index " << index << std::endl; 171 | } 172 | 173 | SQL_TIME_STRUCT time_struct = {0}; 174 | SQLLEN ind(0); 175 | if(!SQL_SUCCEEDED(SQLGetData(_handle->stmt, index+1, SQL_C_TYPE_TIME, &time_struct, sizeof(SQL_TIME_STRUCT), nullptr))) { 176 | throw sqlpp::exception("ODBC error: couldn't SQLGetData("+std::to_string(index+1)+",SQL_C_TYPE_TIME): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 177 | } 178 | *is_null = (ind == SQL_NULL_DATA); 179 | if(!*is_null) { 180 | *value = 181 | std::chrono::hours{time_struct.hour} + 182 | std::chrono::minutes{time_struct.minute} + 183 | std::chrono::seconds{time_struct.second}; 184 | } 185 | } 186 | 187 | bool bind_result_t::next_impl() { 188 | if(_handle->debug) { 189 | std::cerr << "ODBC debug: accessing next row handle at " << _handle.get() << std::endl; 190 | } 191 | SQLRETURN rc; 192 | while((rc = SQLFetch(_handle->stmt)) == SQL_STILL_EXECUTING){} 193 | switch(rc) { 194 | case SQL_NO_DATA: 195 | return false; 196 | case SQL_SUCCESS_WITH_INFO: 197 | std::cerr << "ODBC warning: SQLFetch returned info "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT) << std::endl; 198 | case SQL_SUCCESS: 199 | return true; 200 | case SQL_ERROR: 201 | throw sqlpp::exception("ODBC error: couldn't SQLFetch(returned SQL_ERROR): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 202 | case SQL_INVALID_HANDLE: 203 | throw sqlpp::exception("ODBC error: couldn't SQLFetch(returned SQL_INVALID_HANDLE): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 204 | default: 205 | throw sqlpp::exception("ODBC error: couldn't SQLFetch(returned "+std::to_string(rc)+"): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 206 | } 207 | } 208 | 209 | size_t bind_result_t::size() const { 210 | SQLLEN ret = 0; 211 | if(!SQL_SUCCEEDED(SQLRowCount(_handle->stmt, &ret))) { 212 | throw sqlpp::exception("ODBC error: couldn't SQLRowCount(SQLLEN*): "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 213 | } 214 | if(ret < 0) { 215 | throw sqlpp::exception("ODBC error: bind_result_t.size() returned negative number!"); 216 | } 217 | return ret; 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/connection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "detail/prepared_statement_handle.h" 34 | #include "detail/connection_handle.h" 35 | 36 | #ifdef _WIN32 37 | # ifndef WIN32_LEAN_AND_MEAN 38 | # define WIN32_LEAN_AND_MEAN 39 | # endif 40 | # include 41 | #endif 42 | 43 | #include 44 | #include 45 | 46 | namespace sqlpp { 47 | namespace odbc { 48 | namespace { 49 | void execute_statement(SQLHSTMT stmt) { 50 | if(!SQL_SUCCEEDED(SQLExecute(stmt))) { 51 | throw sqlpp::exception("ODBC error: couldn't SQLExecute: "+detail::odbc_error(stmt, SQL_HANDLE_STMT)); 52 | } 53 | } 54 | size_t odbc_affected(SQLHSTMT stmt) { 55 | SQLLEN ret; 56 | if(!SQL_SUCCEEDED(SQLRowCount(stmt, &ret))) { 57 | throw sqlpp::exception("ODBC error: couldn't SQLRowCount: "+detail::odbc_error(stmt, SQL_HANDLE_STMT)); 58 | } 59 | return ret; 60 | } 61 | 62 | void set_autocommit(SQLHDBC dbc) { 63 | if(!SQL_SUCCEEDED(SQLSetConnectAttr(dbc, SQL_ATTR_AUTOCOMMIT, SQLPOINTER(SQL_TRUE), 0))) { 64 | throw sqlpp::exception("ODBC error: Could not set AUTOCOMMIT to TRUE ("+detail::odbc_error(dbc, SQL_HANDLE_DBC)+')'); 65 | } 66 | } 67 | } 68 | std::shared_ptr prepare_statement(detail::connection_handle_t& handle, const std::string& statement) { 69 | if(handle.debug) { 70 | std::cerr << "ODBC debug: Preparing: " << statement << std::endl; 71 | } 72 | SQLHSTMT stmt; 73 | SQLAllocHandle(SQL_HANDLE_STMT, handle.dbc, &stmt); 74 | std::shared_ptr ret = std::make_shared(stmt, handle.debug); 75 | if(SQL_SUCCEEDED(SQLPrepare(stmt, make_sqlchar(statement), statement.length()))){ 76 | return ret; 77 | } else { 78 | throw sqlpp::exception("ODBC error: couldn't SQLPrepare " + statement + ": "+detail::odbc_error(stmt, SQL_HANDLE_STMT)); 79 | } 80 | } 81 | 82 | connection::connection(const connection_config& config) 83 | : _handle(new detail::connection_handle_t(config.debug, config.type)) 84 | { 85 | if(_handle->debug) { 86 | std::cerr << "ODBC debug: connecting to DSN: " << config.data_source_name << std::endl; 87 | } 88 | if(!SQL_SUCCEEDED(SQLConnect(_handle->dbc, 89 | make_sqlchar(config.data_source_name), config.data_source_name.length(), 90 | config.username.empty() ? nullptr : make_sqlchar(config.username), config.username.length(), 91 | config.password.empty() ? nullptr : make_sqlchar(config.password), config.password.length()))) 92 | { 93 | std::string err = detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC); 94 | //Free and nullify so we don't try to disconnect 95 | if(_handle->dbc) { 96 | auto d = _handle->dbc; 97 | _handle->dbc = nullptr; 98 | SQLFreeHandle(SQL_HANDLE_DBC, d); 99 | } 100 | throw sqlpp::exception("ODBC error: couldn't SQLConnect("+config.data_source_name+"): "+err); 101 | } 102 | } 103 | 104 | connection::~connection() {} 105 | 106 | 107 | inline SQLUSMALLINT from_completion(const driver_completion c) 108 | { 109 | //Just in case the values are different on your system 110 | //Otherwise we could just cast. Optimizer might do that anyway. 111 | switch(c) { 112 | case driver_completion::prompt: 113 | return SQL_DRIVER_PROMPT; 114 | case driver_completion::complete: 115 | return SQL_DRIVER_COMPLETE; 116 | case driver_completion::complete_required: 117 | return SQL_DRIVER_COMPLETE_REQUIRED; 118 | case driver_completion::no_prompt: 119 | return SQL_DRIVER_NOPROMPT; 120 | default: 121 | return static_cast(c); 122 | } 123 | } 124 | 125 | static SQLSMALLINT connect_driver(detail::connection_handle_t& handle, const driver_connection_config& config, SQLCHAR* out_connection, size_t out_max) 126 | { 127 | if(handle.debug) { 128 | std::cerr << "ODBC debug: connecting to " << config.connection << std::endl; 129 | } 130 | SQLSMALLINT out_size = std::min(out_max, std::numeric_limits::max()); 131 | const bool success = SQL_SUCCEEDED( 132 | SQLDriverConnect(handle.dbc, 133 | (SQLHWND)config.window, 134 | make_sqlchar(config.connection), config.connection.length(), 135 | out_connection, out_size, 136 | &out_size, from_completion(config.completion))); 137 | if(!success) { 138 | std::string err = detail::odbc_error(handle.dbc, SQL_HANDLE_DBC); 139 | //Free and nullify so we don't try to disconnect 140 | if(handle.dbc) { 141 | auto dbc = handle.dbc; 142 | handle.dbc = nullptr; 143 | SQLFreeHandle(SQL_HANDLE_DBC, dbc); 144 | } 145 | throw sqlpp::exception("ODBC error: couldn't SQLDriverConnect("+config.connection+"): "+err); 146 | } 147 | return out_size; 148 | } 149 | connection::connection(const driver_connection_config& config) 150 | : _handle(new detail::connection_handle_t(config.debug, config.type)) 151 | { 152 | connect_driver(*_handle, config, nullptr, 0); 153 | } 154 | connection::connection(const driver_connection_config& config, std::string& out_connection, size_t out_max) 155 | : _handle(new detail::connection_handle_t(config.debug, config.type)) 156 | { 157 | out_connection.resize(out_max, '\0'); 158 | out_connection.resize(connect_driver(*_handle, config, make_sqlchar(out_connection), out_max), '\0'); 159 | } 160 | 161 | bind_result_t connection::select_impl(const std::string& statement) { 162 | auto prepared = prepare_statement(*_handle, statement); 163 | if(!prepared || !*prepared) { 164 | throw sqlpp::exception("ODBC error: Could not store result set"); 165 | } 166 | execute_statement(prepared->stmt); 167 | return bind_result_t(prepared); 168 | } 169 | 170 | bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prepared_statement) { 171 | return {prepared_statement._handle}; 172 | } 173 | namespace last_insert_id_ { 174 | SQLPP_ALIAS_PROVIDER(id); 175 | } 176 | size_t connection::last_insert_id(){ 177 | std::string statement; 178 | switch(_handle->type){ 179 | case ODBC_Type::MySQL: 180 | statement = "SELECT LAST_INSERT_ID()"; break; 181 | case ODBC_Type::TSQL: 182 | statement = "SELECT SCOPE_IDENTITY"; break; 183 | case ODBC_Type::SQLite3: 184 | statement = "SELECT last_insert_rowid()"; break; 185 | case ODBC_Type::PostgreSQL: 186 | statement = "SELECT LASTVAL()"; break; 187 | default: 188 | throw sqlpp::exception("Can't get last insert id for ODBC_Type "+std::to_string(static_cast(_handle->type))); 189 | } 190 | auto prepared_statement = prepare_statement(*_handle, statement); 191 | execute_statement(prepared_statement->stmt); 192 | int64_t ret; 193 | bool is_null; 194 | bind_result_t result(prepared_statement); 195 | if(!result.next_impl()){ 196 | std::cerr << "ODBC warning: next_impl failed!" << std::endl; 197 | return 0; 198 | } 199 | result._bind_integral_result(0, &ret, &is_null); 200 | if(is_null) { 201 | std::cerr << "ODBC warning: NULL returned from " << statement << std::endl; 202 | return 0; 203 | } 204 | return ret; 205 | } 206 | 207 | 208 | size_t connection::insert_impl(const std::string& statement) { 209 | auto prepared = prepare_statement(*_handle, statement); 210 | execute_statement(prepared->stmt); 211 | 212 | return last_insert_id(); 213 | } 214 | 215 | prepared_statement_t connection::prepare_impl(const std::string& statement) { 216 | return prepared_statement_t(prepare_statement(*_handle, statement)); 217 | } 218 | 219 | size_t connection::run_prepared_insert_impl(prepared_statement_t& prepared_statement) { 220 | execute_statement(prepared_statement.native_handle()); 221 | return last_insert_id(); 222 | } 223 | 224 | size_t connection::run_prepared_execute_impl(prepared_statement_t& prepared_statement) { 225 | execute_statement(prepared_statement.native_handle()); 226 | return odbc_affected(prepared_statement.native_handle()); 227 | } 228 | 229 | size_t connection::execute(const std::string& statement) { 230 | return _handle->exec_direct(statement); 231 | } 232 | 233 | size_t connection::update_impl(const std::string& statement) { 234 | auto prepared = prepare_statement(*_handle, statement); 235 | execute_statement(prepared->stmt); 236 | return odbc_affected(prepared->stmt); 237 | } 238 | 239 | size_t connection::run_prepared_update_impl(prepared_statement_t& prepared_statement) { 240 | execute_statement(prepared_statement.native_handle()); 241 | return odbc_affected(prepared_statement.native_handle()); 242 | } 243 | 244 | size_t connection::remove_impl(const std::string& statement) { 245 | auto prepared = prepare_statement(*_handle, statement); 246 | execute_statement(prepared->stmt); 247 | return odbc_affected(prepared->stmt); 248 | } 249 | 250 | size_t connection::run_prepared_remove_impl(prepared_statement_t& prepared_statement) { 251 | execute_statement(prepared_statement.native_handle()); 252 | return odbc_affected(prepared_statement.native_handle()); 253 | } 254 | 255 | std::string connection::escape(const std::string& s) const { 256 | std::string t; 257 | size_t count(s.size()); 258 | for(auto c : s){ 259 | if(c == '\''){ 260 | count++; 261 | } 262 | } 263 | t.reserve(count); 264 | for(auto c : s){ 265 | if(c == '\''){ 266 | t.push_back(c); 267 | } 268 | t.push_back(c); 269 | } 270 | return t; 271 | } 272 | 273 | void connection::start_transaction() { 274 | if(_transaction_active) { 275 | throw sqlpp::exception("ODBC error: Cannot have more than one open transaction per connection"); 276 | } 277 | if(_handle->debug) { 278 | std::cerr << "ODBC debug: Beginning Transaction\n"; 279 | } 280 | if(!SQL_SUCCEEDED(SQLSetConnectAttr(_handle->dbc, SQL_ATTR_AUTOCOMMIT, SQLPOINTER(SQL_FALSE), 0))) { 281 | throw sqlpp::exception("ODBC error: Could not set AUTOCOMMIT to FALSE ("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')'); 282 | } 283 | _transaction_active = true; 284 | } 285 | 286 | void connection::commit_transaction() { 287 | if(not _transaction_active) { 288 | throw sqlpp::exception("ODBC error: Cannot commit a finished or failed transaction"); 289 | } 290 | if(_handle->debug) { 291 | std::cerr << "ODBC debug: Committing Transaction\n"; 292 | } 293 | if(!SQL_SUCCEEDED(SQLEndTran(SQL_HANDLE_DBC, _handle->dbc, SQL_COMMIT))) { 294 | throw sqlpp::exception("ODBC error: Could not SQLEndTran COMMIT("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')'); 295 | } 296 | set_autocommit(_handle->dbc); 297 | _transaction_active = false; 298 | } 299 | 300 | void connection::rollback_transaction(bool report) { 301 | if(not _transaction_active) { 302 | throw sqlpp::exception("ODBC error: Cannot rollback a finished or failed transaction"); 303 | } 304 | if(report || _handle->debug) { 305 | std::cerr << "ODBC warning: Rolling back unfinished transaction" << std::endl; 306 | } 307 | if(!SQL_SUCCEEDED(SQLEndTran(SQL_HANDLE_DBC, _handle->dbc, SQL_ROLLBACK))) { 308 | throw sqlpp::exception("ODBC error: Could not SQLEndTran ROLLBACK("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')'); 309 | } 310 | set_autocommit(_handle->dbc); 311 | _transaction_active = false; 312 | } 313 | 314 | void connection::report_rollback_failure(const std::string message) noexcept { 315 | std::cerr << "ODBC message: " << message << std::endl; 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/detail/connection_handle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "connection_handle.h" 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | namespace sqlpp { 37 | namespace odbc { 38 | namespace detail { 39 | std::string return_code_string(SQLRETURN rc) { 40 | switch(rc) { 41 | case 0: return "SQL_SUCCESS"; 42 | case 1: return "SQL_SUCCESS_WITH_INFO"; 43 | case 2: return "SQL_STILL_EXECUTING"; 44 | case -1: return "SQL_NULL_DATA/SQL_ERROR"; 45 | case -2: return "SQL_DATA_AT_EXEC/SQL_INVALID_HANDLE"; 46 | case 99: return "SQL_NEED_DATA"; 47 | case 100: return "SQL_NO_DATA"; 48 | case 101: return "SQL_PARAM_DATA_AVAILABLE"; 49 | default: return "Unknown return code "+std::to_string(rc); 50 | } 51 | } 52 | 53 | std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type, SQLRETURN return_code){ 54 | return "Returned "+return_code_string(return_code)+' '+odbc_error(handle, handle_type); 55 | } 56 | 57 | std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type){ 58 | std::vector errors; 59 | errors.reserve(1); 60 | std::unique_ptr buffer(new SQLCHAR[1024]); 61 | std::vector state(6, '\0'); 62 | SQLINTEGER native_error; 63 | SQLSMALLINT buffer_len; 64 | bool get_more(true); 65 | SQLRETURN rc; 66 | std::ostringstream oss; 67 | for(SQLSMALLINT rec_number(1); get_more; rec_number++){ 68 | rc = SQLGetDiagRec(handle_type, handle, rec_number++, state.data(), &native_error, buffer.get(), 1024, &buffer_len); 69 | oss << "ODBC error STATE: " << reinterpret_cast(state.data()) << ", Native Error: " << native_error << '\n'; 70 | switch(rc){ 71 | case SQL_SUCCESS: 72 | case SQL_SUCCESS_WITH_INFO: 73 | oss << "Error: "; 74 | oss.write(reinterpret_cast(buffer.get()), static_cast(buffer_len)); 75 | oss << '\n'; 76 | case SQL_NO_DATA: 77 | get_more = false; break; 78 | case SQL_INVALID_HANDLE: 79 | std::cerr << "ODBC error: SQLGetDiagRec returned SQL_INVALID_HANDLE (" << handle << ", " << handle_type << ')' << std::endl; 80 | get_more = false; break; 81 | case SQL_ERROR: 82 | std::cerr << "ODBC error: SQLGetDiagRec returned SQL_ERROR" << std::endl; 83 | get_more = false; break; 84 | default: 85 | std::cerr << "ODBC error: SQLGetDiagRec returned " << rc << std::endl; 86 | get_more = false; break; 87 | } 88 | } 89 | auto ret = oss.str(); 90 | if(ret.empty()) 91 | return "Could not retrieve diagnostic information!"; 92 | if(*ret.rbegin() == '\n') 93 | ret.erase(--ret.end()); 94 | return ret; 95 | } 96 | 97 | connection_handle_t::connection_handle_t(bool _debug, ODBC_Type _type) 98 | : env(nullptr) 99 | , dbc(nullptr) 100 | , debug(_debug) 101 | , type(_type) 102 | { 103 | if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env)) || env == nullptr) { 104 | throw sqlpp::exception("ODBC error: couldn't SQLAllocHandle(SQL_HANDLE_ENV)"); 105 | }else if(!SQL_SUCCEEDED(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))) { 106 | throw sqlpp::exception("ODBC error: couldn't SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION, SQL_0V_ODBC3): "+odbc_error(env, SQL_HANDLE_ENV)); 107 | }else if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc)) || dbc == nullptr) { 108 | throw sqlpp::exception("ODBC error: couldn't SQLAllocHandle(SQL_HANDLE_DBC): "+odbc_error(env, SQL_HANDLE_ENV)); 109 | } 110 | } 111 | 112 | sqlpp::odbc::detail::connection_handle_t::~connection_handle_t() { 113 | if(dbc) { 114 | SQLDisconnect(dbc); 115 | SQLFreeHandle(SQL_HANDLE_DBC, dbc); 116 | } 117 | if(env) { 118 | SQLFreeHandle(SQL_HANDLE_ENV, env); 119 | } 120 | } 121 | 122 | size_t connection_handle_t::exec_direct(const std::string& statement) { 123 | SQLHSTMT stmt; 124 | if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))) { 125 | throw sqlpp::exception("ODBC error: could SQLAllocHandle(SQL_HANDLE_STMT): "+odbc_error(stmt, SQL_HANDLE_STMT)); 126 | } 127 | auto rc = SQLExecDirect(stmt, make_sqlchar(statement), statement.length()); 128 | std::string err; 129 | SQLLEN ret = 0; 130 | if(!(SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA)){ 131 | err = "ODBC error: couldn't SQLExecDirect("+statement+"): "+odbc_error(stmt, SQL_HANDLE_STMT, rc); 132 | } else { 133 | rc = SQLRowCount(stmt, &ret); 134 | if(!SQL_SUCCEEDED(rc)) { 135 | err = "ODBC error: couldn't SQLRowCount: "+odbc_error(stmt, SQL_HANDLE_STMT); 136 | } 137 | } 138 | if(!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_STMT, stmt))) { 139 | throw sqlpp::exception("ODBC error: couldn't SQLFreeHandle(HSTMT): "+odbc_error(dbc, SQL_HANDLE_DBC)); 140 | } 141 | stmt = nullptr; 142 | if(!SQL_SUCCEEDED(rc)) { 143 | throw sqlpp::exception(err); 144 | } 145 | return ret; 146 | } 147 | 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/detail/connection_handle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_CONNECTION_HANDLE_H 29 | #define SQLPP11_ODBC_CONNECTION_HANDLE_H 30 | 31 | #ifdef _WIN32 32 | # ifndef WIN32_LEAN_AND_MEAN 33 | # define WIN32_LEAN_AND_MEAN 34 | # endif 35 | # ifndef NOMINMAX 36 | # define NOMINMAX 37 | # endif 38 | # include 39 | #endif 40 | 41 | #include 42 | #include 43 | 44 | //I wish ODBC used const SQLCHAR* when it won't be modified 45 | inline SQLCHAR* make_sqlchar(const std::string& str) 46 | { 47 | return const_cast(reinterpret_cast(str.c_str())); 48 | } 49 | inline SQLCHAR* make_sqlchar(std::string& str) 50 | { 51 | return reinterpret_cast(&str[0]); 52 | } 53 | 54 | namespace sqlpp { 55 | namespace odbc { 56 | 57 | namespace detail { 58 | struct connection_handle_t { 59 | SQLHENV env; 60 | SQLHDBC dbc; 61 | bool debug; 62 | ODBC_Type type; 63 | 64 | connection_handle_t(bool _debug, ODBC_Type _type); 65 | ~connection_handle_t(); 66 | connection_handle_t(const connection_handle_t&) = delete; 67 | connection_handle_t(connection_handle_t&&) = delete; 68 | connection_handle_t& operator=(const connection_handle_t&) = delete; 69 | connection_handle_t& operator=(connection_handle_t&&) = delete; 70 | 71 | size_t exec_direct(const std::string& statement); 72 | }; 73 | 74 | std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type); 75 | std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type, SQLRETURN return_code); 76 | } 77 | } 78 | } 79 | 80 | #endif //SQLPP11_ODBC_CONNECTION_HANDLE_H 81 | -------------------------------------------------------------------------------- /src/detail/prepared_statement_handle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SQLPP11_ODBC_PREPARED_STATEMENT_HANDLE_H 29 | #define SQLPP11_ODBC_PREPARED_STATEMENT_HANDLE_H 30 | 31 | #ifdef _WIN32 32 | # ifndef WIN32_LEAN_AND_MEAN 33 | # define WIN32_LEAN_AND_MEAN 34 | # endif 35 | # ifndef NOMINMAX 36 | # define NOMINMAX 37 | # endif 38 | # include 39 | #endif 40 | 41 | #include 42 | 43 | namespace sqlpp { 44 | namespace odbc { 45 | namespace detail { 46 | struct prepared_statement_handle_t { 47 | SQLHSTMT stmt; 48 | bool debug; 49 | prepared_statement_handle_t(SQLHSTMT statement, bool debug_) : stmt(statement), debug(debug_) {} 50 | 51 | prepared_statement_handle_t(const prepared_statement_handle_t&) = delete; 52 | prepared_statement_handle_t(prepared_statement_handle_t&&) = default; 53 | prepared_statement_handle_t& operator=(const prepared_statement_handle_t&) = delete; 54 | prepared_statement_handle_t& operator=(prepared_statement_handle_t&&) = default; 55 | 56 | ~prepared_statement_handle_t() { 57 | if(stmt) { 58 | SQLFreeHandle(SQL_HANDLE_STMT, stmt); 59 | } 60 | } 61 | 62 | bool operator!() const { return !stmt; } 63 | }; 64 | } 65 | } 66 | } 67 | 68 | #endif //SQLPP11_ODBC_PREPARED_STATEMENT_HANDLE_H -------------------------------------------------------------------------------- /src/prepared_statement.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "detail/prepared_statement_handle.h" 36 | #include "detail/connection_handle.h" 37 | 38 | #ifdef _WIN32 39 | # ifndef WIN32_LEAN_AND_MEAN 40 | # define WIN32_LEAN_AND_MEAN 41 | # endif 42 | # ifndef NOMINMAX 43 | # define NOMINMAX 44 | # endif 45 | # include 46 | #endif 47 | 48 | #include 49 | #include 50 | 51 | #if defined(__CYGWIN__) 52 | #include 53 | 54 | // Workaround because cygwin gcc does not define to_string 55 | namespace std 56 | { 57 | std::string to_string(int i) 58 | { 59 | std::unique_ptr buffer(new char[12]); 60 | snprintf(buffer.get(), 12, "%i", i); 61 | return std::string(buffer.get()); 62 | } 63 | } 64 | #endif 65 | 66 | namespace sqlpp { 67 | namespace odbc { 68 | void check_bind_result(int result, const char* const type, SQLHSTMT* stmt, detail::prepared_statement_handle_t& handle) { 69 | switch(result) { 70 | case SQL_ERROR: 71 | throw sqlpp::exception("ODBC error: "+std::string(type)+" couldn't bind: "+detail::odbc_error(stmt, SQL_HANDLE_STMT)); 72 | case SQL_INVALID_HANDLE: 73 | throw sqlpp::exception("ODBC error: "+std::string(type)+" couldn't bind to invalid handle"); 74 | case SQL_SUCCESS: 75 | case SQL_SUCCESS_WITH_INFO: 76 | return; 77 | default: 78 | throw sqlpp::exception("ODBC error: "+std::string(type)+" unexpected return code: "+std::to_string(result)); 79 | } 80 | } 81 | 82 | prepared_statement_t::prepared_statement_t(std::shared_ptr&& handle) 83 | : _handle(std::move(handle)) { 84 | if(_handle && _handle->debug) { 85 | std::cerr << "ODBC debug: Constructing prepared_statement, using handle at " << _handle.get() << std::endl; 86 | } 87 | } 88 | 89 | void prepared_statement_t::_reset() { 90 | if(_handle->debug) { 91 | std::cerr << "ODBC debug: resetting prepared_statement" << std::endl; 92 | } 93 | auto rc = SQLFreeStmt(_handle->stmt, SQL_RESET_PARAMS); 94 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){ 95 | throw sqlpp::exception("ODBC error: couldn't reset parameters on prepared_statement: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 96 | } 97 | } 98 | 99 | void prepared_statement_t::_bind_boolean_parameter(size_t index, const signed char* value, bool is_null) { 100 | if(_handle->debug) { 101 | std::cerr << "ODBC debug: binding boolean parameter " << (*value ? "true" : "false") 102 | << " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 103 | } 104 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 105 | auto rc = SQLBindParameter(_handle->stmt, 106 | index, 107 | SQL_PARAM_INPUT, 108 | SQL_C_CHAR, 109 | SQL_BIT, 110 | 1, 111 | 0, 112 | (SQLPOINTER)value, 113 | sizeof(signed char), 114 | &indPtr); 115 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 116 | throw sqlpp::exception("ODBC error: couldn't bind boolean parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 117 | } 118 | } 119 | 120 | void prepared_statement_t::_bind_floating_point_parameter(size_t index, const double* value, bool is_null) { 121 | if(_handle->debug) { 122 | std::cerr << "ODBC debug: binding floating_point parameter " << *value 123 | << " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 124 | } 125 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 126 | auto rc = SQLBindParameter(_handle->stmt, 127 | index, 128 | SQL_PARAM_INPUT, 129 | SQL_C_DOUBLE, 130 | SQL_DOUBLE, 131 | 15, 132 | DBL_DIG, 133 | (SQLPOINTER)value, 134 | sizeof(double), 135 | &indPtr); 136 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 137 | throw sqlpp::exception("ODBC error: couldn't bind floating_point parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 138 | } 139 | } 140 | 141 | void prepared_statement_t::_bind_integral_parameter(size_t index, const int64_t* value, bool is_null) { 142 | if(_handle->debug) { 143 | std::cerr << "ODBC debug: binding integral parameter " << *value 144 | << " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 145 | } 146 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 147 | auto rc = SQLBindParameter(_handle->stmt, 148 | index, 149 | SQL_PARAM_INPUT, 150 | SQL_C_SBIGINT, 151 | SQL_BIGINT, 152 | 19, 153 | 0, 154 | (SQLPOINTER)value, 155 | sizeof(int64_t), 156 | &indPtr); 157 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 158 | throw sqlpp::exception("ODBC error: couldn't bind integral parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 159 | } 160 | } 161 | 162 | void prepared_statement_t::_bind_text_parameter(size_t index, const std::string* value, bool is_null) { 163 | if(_handle->debug) { 164 | std::cerr << "ODBC debug: binding text parameter " << *value 165 | << " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 166 | } 167 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 168 | auto rc = SQLBindParameter(_handle->stmt, 169 | index, 170 | SQL_PARAM_INPUT, 171 | SQL_C_CHAR, 172 | SQL_CHAR, 173 | value->length(), 174 | 0, 175 | (SQLPOINTER)value, 176 | value->size(), 177 | &indPtr); 178 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 179 | throw sqlpp::exception("ODBC error: couldn't bind text parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 180 | } 181 | } 182 | 183 | void prepared_statement_t::_bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null) { 184 | if(_handle->debug) { 185 | std::cerr << "ODBC debug: binding date parameter" 186 | " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 187 | } 188 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 189 | SQL_DATE_STRUCT ymd_value = {0}; 190 | if(!is_null) { 191 | const auto ymd = ::date::year_month_day{*value}; 192 | ymd_value.year = static_cast(ymd.year()); 193 | ymd_value.month = static_cast(ymd.month()); 194 | ymd_value.day = static_cast(ymd.day()); 195 | } 196 | 197 | auto rc = SQLBindParameter(_handle->stmt, 198 | index, 199 | SQL_PARAM_INPUT, 200 | SQL_C_TYPE_DATE, 201 | SQL_TYPE_DATE, 202 | 10, 203 | 0, 204 | (SQLPOINTER)&ymd_value, 205 | sizeof(SQL_DATE_STRUCT), 206 | &indPtr); 207 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 208 | throw sqlpp::exception("ODBC error: couldn't bind date parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 209 | } 210 | } 211 | 212 | void prepared_statement_t::_bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null) { 213 | if(_handle->debug) { 214 | std::cerr << "ODBC debug: binding date_time parameter" 215 | " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 216 | } 217 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 218 | SQL_TIMESTAMP_STRUCT ts_value = {0}; 219 | if(!is_null) { 220 | const auto dp = ::date::floor<::date::days>(*value); 221 | const auto time = date::make_time(*value - dp); 222 | const auto ymd = ::date::year_month_day{dp}; 223 | ts_value.year = static_cast(ymd.year()); 224 | ts_value.month = static_cast(ymd.month()); 225 | ts_value.day = static_cast(ymd.day()); 226 | ts_value.hour = time.hours().count(); 227 | ts_value.minute = time.minutes().count(); 228 | ts_value.second = time.seconds().count(); 229 | ts_value.fraction = time.subseconds().count(); 230 | } 231 | 232 | auto rc = SQLBindParameter(_handle->stmt, 233 | index, 234 | SQL_PARAM_INPUT, 235 | SQL_C_TYPE_TIMESTAMP, 236 | SQL_TYPE_TIMESTAMP, 237 | sizeof(SQL_TIMESTAMP_STRUCT), 238 | 0, 239 | (SQLPOINTER)&ts_value, 240 | sizeof(SQL_DATE_STRUCT), 241 | &indPtr); 242 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 243 | throw sqlpp::exception("ODBC error: couldn't bind date parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 244 | } 245 | } 246 | 247 | void prepared_statement_t::_bind_timestamp_parameter(size_t index, const SQL_TIMESTAMP_STRUCT* value, bool is_null) { 248 | if(_handle->debug) { 249 | std::cerr << "ODBC debug: binding date_time parameter" 250 | " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 251 | } 252 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 253 | auto rc = SQLBindParameter(_handle->stmt, 254 | index, 255 | SQL_PARAM_INPUT, 256 | SQL_C_TYPE_TIMESTAMP, 257 | SQL_TYPE_TIMESTAMP, 258 | 29, 259 | 0, 260 | (SQLPOINTER)value, 261 | sizeof(SQL_DATE_STRUCT), 262 | &indPtr); 263 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 264 | throw sqlpp::exception("ODBC error: couldn't bind date parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 265 | } 266 | } 267 | 268 | void prepared_statement_t::_bind_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null) { 269 | if(_handle->debug) { 270 | std::cerr << "ODBC debug: binding date_time parameter" 271 | " at index: " << index << ", being " << (is_null ? std::string() : "not") << " null" << std::endl; 272 | } 273 | SQLLEN indPtr(is_null ? SQL_NULL_DATA : 0); 274 | SQL_TIME_STRUCT t_value = {0}; 275 | if(!is_null) { 276 | const auto time = date::make_time(value->time_since_epoch()); 277 | t_value.hour = time.hours().count(); 278 | t_value.minute = time.minutes().count(); 279 | t_value.second = time.seconds().count(); 280 | } 281 | 282 | auto rc = SQLBindParameter(_handle->stmt, 283 | index, 284 | SQL_PARAM_INPUT, 285 | SQL_C_TYPE_TIME, 286 | SQL_TYPE_TIME, 287 | 8, 288 | 0, 289 | (SQLPOINTER)&t_value, 290 | sizeof(SQL_DATE_STRUCT), 291 | &indPtr); 292 | if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 293 | throw sqlpp::exception("ODBC error: couldn't bind date parameter: "+detail::odbc_error(_handle->stmt, SQL_HANDLE_STMT)); 294 | } 295 | } 296 | SQLHSTMT prepared_statement_t::native_handle() { 297 | return _handle->stmt; 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Original work Copyright (c) 2013-2015, Roland Bock 2 | # Modified work Copyright (c) 2016-2017, Aaron Bishop 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | include_directories(include) 27 | # Add headers to sources to enable file browsing in IDEs 28 | add_executable("ODBCTest" "ODBCTest.cpp" ${sqlpp_headers}) 29 | if(SQLPP11_ODBC_DISABLE_STATIC) 30 | target_link_libraries("ODBCTest" ${ODBC_LIBRARIES} sqlpp11-odbc-shared) 31 | else() 32 | target_link_libraries("ODBCTest" ${ODBC_LIBRARIES} sqlpp11-odbc-static) 33 | endif() 34 | add_test("MySQLTest" "ODBCTest" "MySQLTest" "test" "test" "test" "MySQL") 35 | -------------------------------------------------------------------------------- /tests/ODBCTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "TabSample.h" 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | template 39 | void printResultsSample(const ResultRow& row) { 40 | std::cout << "alpha:\t"; 41 | if(row.alpha.is_null()) 42 | std::cout << "NULL"; 43 | else 44 | std::cout << row.alpha; 45 | std::cout << ", beta:\t"; 46 | if(row.beta.is_null()) 47 | std::cout << "NULL"; 48 | else 49 | std::cout << row.beta; 50 | std::cout << ", gamma:\t"; 51 | if(row.gamma.is_null()) 52 | std::cout << "NULL"; 53 | else 54 | std::cout << row.gamma; 55 | std::cout << std::endl; 56 | } 57 | 58 | template 59 | void printResultsBar(const ResultRow& row) { 60 | std::cout << "delta:\t"; 61 | if(row.delta.is_null()) 62 | std::cout << "NULL"; 63 | else 64 | std::cout << row.delta; 65 | std::cout << ", epsilon:\t"; 66 | if(row.epsilon.is_null()) 67 | std::cout << "NULL"; 68 | else 69 | std::cout << row.epsilon; 70 | std::cout << ", zeta:\t"; 71 | if(row.zeta.is_null()) 72 | std::cout << "NULL"; 73 | else 74 | std::cout << row.zeta; 75 | std::cout << ", eta:\t"; 76 | if(row.eta.is_null()) 77 | std::cout << "NULL"; 78 | else 79 | std::cout << row.eta; 80 | std::cout << std::endl; 81 | } 82 | 83 | namespace odbc = sqlpp::odbc; 84 | int main(int argc, const char **argv) 85 | { 86 | if(argc != 6 && argc != 4) 87 | { 88 | std::cout << "Usage:\n\tODBCTest data_source_name database username password type\n" 89 | "\tODBCTest connection database type" << std::endl; 90 | return 1; 91 | } 92 | try { 93 | std::map> odbc_types({ 94 | {"MySQL",{odbc::ODBC_Type::MySQL,"BIGINT NOT NULL AUTO_INCREMENT"}}, 95 | {"PostgreSQL",{odbc::ODBC_Type::PostgreSQL,"SERIAL"}}, 96 | {"SQLite3",{odbc::ODBC_Type::SQLite3,"BIGINT NOT NULL AUTOINCREMENT"}}, 97 | {"TSQL",{odbc::ODBC_Type::TSQL, "BIGINT NOT NULL AUTO_INCREMENT"}} 98 | }); 99 | auto mType = odbc_types.find(argv[argc-1]); 100 | if(mType == odbc_types.end()) 101 | { 102 | std::cout << "Unknown type: " << argv[5] << ", valid types are:" << std::endl; 103 | for(auto t : odbc_types) 104 | { 105 | std::cout << '\t' << t.first << std::endl; 106 | } 107 | } 108 | if(mType->second.first == odbc::ODBC_Type::SQLite3) { 109 | std::cout << "SQLite3 does not allow for proper DATE and TIMESTAMP datatypes. Testing cancelled\n"; 110 | return 1; 111 | } 112 | std::unique_ptr db; 113 | const std::string database = argv[2]; 114 | std::string auto_increment_column = mType->second.second; 115 | if(argc == 6) { 116 | odbc::connection_config config; 117 | config.data_source_name = argv[1]; 118 | config.username = argv[3]; 119 | config.password = argv[4]; 120 | config.type = mType->second.first; 121 | config.debug = true; 122 | db.reset(new odbc::connection(config)); 123 | } else { 124 | odbc::driver_connection_config config; 125 | config.connection = argv[1]; 126 | config.type = mType->second.first; 127 | config.debug = true; 128 | db.reset(new odbc::connection(config)); 129 | } 130 | if(!database.empty()) 131 | db->execute("USE "+database); 132 | db->execute(R"(DROP TABLE IF EXISTS tab_sample)"); 133 | db->execute(R"(DROP TABLE IF EXISTS tab_foo)"); 134 | db->execute(R"(DROP TABLE IF EXISTS tab_bar)"); 135 | db->execute("CREATE TABLE tab_foo (\n\ 136 | omega "+auto_increment_column+",\n\ 137 | name VARCHAR(32),\n\ 138 | PRIMARY KEY (omega)\n\ 139 | )"); 140 | db->execute(R"(CREATE TABLE tab_sample ( 141 | alpha bigint(20) DEFAULT NULL, 142 | beta varchar(255) DEFAULT NULL, 143 | gamma bool DEFAULT NULL, 144 | FOREIGN KEY (alpha) REFERENCES tab_foo(omega) 145 | ))"); 146 | db->execute(R"(CREATE TABLE tab_bar ( 147 | delta date DEFAULT NULL, 148 | epsilon datetime DEFAULT NULL, 149 | zeta timestamp, 150 | eta time DEFAULT NULL 151 | ))"); 152 | 153 | TabFoo foo; 154 | TabSample tab; 155 | TabBar bar; 156 | // clear the table 157 | size_t omega = db->insert(insert_into(foo).set(foo.name = "test")); 158 | 159 | std::cout << "Inserted " << omega << std::endl; 160 | (*db)(insert_into(tab).set(tab.alpha = (int64_t)omega, tab.gamma = true, tab.beta = "cheesecake")); 161 | (*db)(insert_into(tab).set(tab.gamma = false, tab.beta = "blueberry muffin")); 162 | 163 | { 164 | auto result = (*db)(select(all_of(tab)).from(tab).unconditionally()); 165 | auto size = result.size(); 166 | std::cout << "Select returned " << size << " rows\n"; 167 | assert(size == 2); 168 | for(const auto& row : result) 169 | { 170 | printResultsSample(row); 171 | --size; 172 | }; 173 | assert(size == 0); 174 | } 175 | auto date_time = std::chrono::system_clock::time_point() 176 | + std::chrono::microseconds(3723123456); 177 | auto dp = date::floor(date_time); 178 | auto date = date::year_month_day{dp}; 179 | auto time = date::make_time(date_time-dp); 180 | std::cout << "Using today(" << date << ' ' << time << ')' << std::endl; 181 | 182 | db->start_transaction(); 183 | 184 | (*db)(insert_into(bar).set( 185 | bar.delta = dp, 186 | bar.epsilon = date_time, 187 | bar.zeta = date_time, 188 | bar.eta = date_time)); 189 | auto&& select_bar = (*db)(select(all_of(bar)).from(bar).unconditionally()); 190 | assert(!select_bar.empty()); 191 | for(const auto& row : select_bar) 192 | { 193 | printResultsBar(row); 194 | } 195 | 196 | db->rollback_transaction(true); 197 | 198 | select_bar = (*db)(select(all_of(bar)).from(bar).unconditionally()); 199 | assert(select_bar.empty()); 200 | } catch(const std::exception& e) { 201 | std::cerr << "Encountered error: " << e.what() << '\n'; 202 | return 2; 203 | } 204 | return 0; 205 | } 206 | -------------------------------------------------------------------------------- /tests/TabSample.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2013-2015, Roland Bock 3 | * Modified work Copyright (c) 2016, Aaron Bishop 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef TEST_SAMPLE_H 28 | #define TEST_SAMPLE_H 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | // clang-format off 35 | 36 | namespace TabFoo_ { 37 | struct Omega { 38 | struct _alias_t { 39 | static constexpr const char _literal[] = "omega"; 40 | using _name_t = sqlpp::make_char_sequence; 41 | 42 | template 43 | struct _member_t { 44 | T omega; 45 | T& operator()() { return omega; } 46 | const T& operator()() const { return omega; } 47 | }; 48 | }; 49 | using _traits = sqlpp::make_traits; 50 | }; 51 | struct Name { 52 | struct _alias_t { 53 | static constexpr const char _literal[] = "name"; 54 | using _name_t = sqlpp::make_char_sequence; 55 | 56 | template 57 | struct _member_t { 58 | T name; 59 | T& operator()() { return name; } 60 | const T& operator()() const { return name; } 61 | }; 62 | }; 63 | using _traits = sqlpp::make_traits; 64 | }; 65 | } 66 | 67 | struct TabFoo : sqlpp::table_t { 68 | struct _alias_t { 69 | static constexpr const char _literal[] = "tab_foo"; 70 | using _name_t = sqlpp::make_char_sequence; 71 | 72 | template 73 | struct _member_t { 74 | T tab_foo; 75 | T& operator()() { return tab_foo; } 76 | const T& operator()() const { return tab_foo; } 77 | }; 78 | }; 79 | }; 80 | namespace TabSample_ { 81 | struct Alpha { 82 | struct _alias_t { 83 | static constexpr const char _literal[] = "alpha"; 84 | using _name_t = sqlpp::make_char_sequence; 85 | 86 | template 87 | struct _member_t { 88 | T alpha; 89 | T& operator()() { return alpha; } 90 | const T& operator()() const { return alpha; } 91 | }; 92 | }; 93 | using _traits = sqlpp::make_traits; 94 | // using _foreign_key = decltype(TabFoo::omega); 95 | }; 96 | struct Beta { 97 | struct _alias_t { 98 | static constexpr const char _literal[] = "beta"; 99 | using _name_t = sqlpp::make_char_sequence; 100 | 101 | template 102 | struct _member_t { 103 | T beta; 104 | T& operator()() { return beta; } 105 | const T& operator()() const { return beta; } 106 | }; 107 | }; 108 | using _traits = sqlpp::make_traits; 109 | }; 110 | struct Gamma { 111 | struct _alias_t { 112 | static constexpr const char _literal[] = "gamma"; 113 | using _name_t = sqlpp::make_char_sequence; 114 | 115 | template 116 | struct _member_t { 117 | T gamma; 118 | T& operator()() { return gamma; } 119 | const T& operator()() const { return gamma; } 120 | }; 121 | }; 122 | using _traits = sqlpp::make_traits; 123 | }; 124 | } 125 | 126 | struct TabSample: sqlpp::table_t { 127 | struct _alias_t { 128 | static constexpr const char _literal[] = "tab_sample"; 129 | using _name_t = sqlpp::make_char_sequence; 130 | 131 | template 132 | struct _member_t { 133 | T tab_sample; 134 | T& operator()() { return tab_sample; } 135 | const T& operator()() const { return tab_sample; } 136 | }; 137 | }; 138 | }; 139 | 140 | namespace TabBar_ { 141 | struct Delta { 142 | struct _alias_t { 143 | static constexpr const char _literal[] = "delta"; 144 | using _name_t = sqlpp::make_char_sequence; 145 | 146 | template 147 | struct _member_t { 148 | T delta; 149 | T& operator()() { return delta; } 150 | const T& operator()() const { return delta; } 151 | }; 152 | }; 153 | using _traits = sqlpp::make_traits; 154 | }; 155 | 156 | struct Epsilon { 157 | struct _alias_t { 158 | static constexpr const char _literal[] = "epsilon"; 159 | using _name_t = sqlpp::make_char_sequence; 160 | 161 | template 162 | struct _member_t { 163 | T epsilon; 164 | T& operator()() { return epsilon; } 165 | const T& operator()() const { return epsilon; } 166 | }; 167 | }; 168 | using _traits = sqlpp::make_traits; 169 | }; 170 | 171 | struct Zeta { 172 | struct _alias_t { 173 | static constexpr const char _literal[] = "zeta"; 174 | using _name_t = sqlpp::make_char_sequence; 175 | 176 | template 177 | struct _member_t { 178 | T zeta; 179 | T& operator()() { return zeta; } 180 | const T& operator()() const { return zeta; } 181 | }; 182 | }; 183 | using _traits = sqlpp::make_traits; 184 | }; 185 | 186 | struct Eta { 187 | struct _alias_t { 188 | static constexpr const char _literal[] = "eta"; 189 | using _name_t = sqlpp::make_char_sequence; 190 | 191 | template 192 | struct _member_t { 193 | T eta; 194 | T& operator()() { return eta; } 195 | const T& operator()() const { return eta; } 196 | }; }; 197 | using _traits = sqlpp::make_traits; 198 | }; 199 | } 200 | 201 | struct TabBar: sqlpp::table_t { 202 | struct _alias_t { 203 | static constexpr const char _literal[] = "tab_bar"; 204 | using _name_t = sqlpp::make_char_sequence; 205 | 206 | template 207 | struct _member_t { 208 | T tab_bar; 209 | T& operator()() { return tab_bar; } 210 | const T& operator()() const { return tab_bar; } 211 | }; 212 | }; 213 | }; 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Original work Copyright (c) 2017, Aaron Bishop 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SQLPP11_ODBC_VERSION_H 28 | #define SQLPP11_ODBC_VERSION_H 29 | 30 | #define SQLPP11_ODBC_VERSION_MAJOR @SQLPP11_ODBC_VERSION_MAJOR@ 31 | #define SQLPP11_ODBC_VERSION_MINOR @SQLPP11_ODBC_VERSION_MINOR@ 32 | #define SQLPP11_ODBC_VERSION_PATCH @SQLPP11_ODBC_VERSION_PATCH@ 33 | 34 | #define SQLPP11_ODBC_VERSION "@SQLPP11_ODBC_VERSION@" 35 | #define SQLPP11_ODBC_VERSION_INT @SQLPP11_ODBC_VERSION_INT@ 36 | 37 | #endif //SQLPP11_ODBC_VERSION_H 38 | --------------------------------------------------------------------------------