Skip to content

Commit

Permalink
0.04 (#5)
Browse files Browse the repository at this point in the history
* use SQLExecDirect instead of prepare and execute

* Use SQL_ATTR_AUTOCOMMIT and SQLEndTran instead of executing BEGIN, COMMIT, and ROLLBACK
Added transaction tests to ODBCTest
Properly added MySQLTest for ctest

* Cmake install fixes; added version.h.
  • Loading branch information
Erroneous1 authored Mar 25, 2017
1 parent 600073e commit be4e6f6
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 128 deletions.
54 changes: 46 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,58 @@ if(NOT EXISTS ${DATE_INCLUDE_DIR}/date.h)
message(SEND_ERROR "Can't find date.h in ${DATE_INCLUDE_DIR}")
endif()

set(SQLPP11_ODBC_VERSION_MAJOR 0)
set(SQLPP11_ODBC_VERSION_MINOR 4)
set(SQLPP11_ODBC_VERSION_PATCH 0)

if(${SQLPP11_ODBC_VERSION_MINOR} LESS 10)
set(PROJECT_VERSION_MINOR "0${SQLPP11_ODBC_VERSION_MINOR}")
else()
set(PROJECT_VERSION_MINOR ${SQLPP11_ODBC_VERSION_MINOR})
endif()

set(PROJECT_VERSION "${SQLPP11_ODBC_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if(${SQLPP11_ODBC_VERSION_PATCH} GREATER 0)
if(${PROJECT_VERSION_PATCH} LESS 10)
set(PROJECT_VERSION_PATCH "0${SQLPP11_ODBC_VERSION_PATCH}")
else()
set(PROJECT_VERSION_PATCH ${SQLPP11_ODBC_VERSION_PATCH})
endif()

set(PROJECT_VERSION "${PROJECT_VERSION}.${PROJECT_VERSION_PATCH}")
set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_MINOR}${PROJECT_VERSION_PATCH}")
else()
set(SQLPP11_ODBC_VERSION_PATCH 0)
set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_MINOR}00")
endif()

if(${SQLPP11_ODBC_VERSION_MAJOR} GREATER 0)
if(${SQLPP11_ODBC_VERSION_MINOR} LESS 10)
set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_MAJOR}0${SQLPP11_ODBC_VERSION_INT}")
else()
set(SQLPP11_ODBC_VERSION_INT "${SQLPP11_ODBC_VERSION_MAJOR}${SQLPP11_ODBC_VERSION_INT}")
endif()
endif()

set(SQLPP11_ODBC_VERSION "${PROJECT_VERSION}")

configure_file(version.h.in version.h @ONLY)

message(SEND_MESSAGE "including sqlpp11 from ${SQLPP11_INCLUDE_DIR}")
include_directories("${SQLPP11_INCLUDE_DIR}")
include_directories("${DATE_INCLUDE_DIR}")
set(include_dir "${PROJECT_SOURCE_DIR}/sqlpp11")
# file(GLOB_RECURSE sqlpp_headers ${include_dir}/*.h ${SQLPP11_INCLUDE_DIR}/*.h)
include_directories(${include_dir})
include_directories(${PROJECT_SOURCE_DIR}/include/)

install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION include)
include_directories(
${SQLPP11_INCLUDE_DIR}
${DATE_INCLUDE_DIR}
${include_dir}
${PROJECT_SOURCE_DIR}/include/
)

install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION ${DESTDIR}/include)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/version.h" DESTINATION ${DESTDIR}/include/sqlpp11/odbc/)

add_subdirectory(src)

if(NOT ${CMAKE_SQLPP11_CONNECTOR_ODBC_TESTS_IGNORE})
if(NOT CMAKE_SQLPP11_CONNECTOR_ODBC_TESTS_IGNORE)
enable_testing()
add_subdirectory(tests)
endif()
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ if(NOT WIN32)
set_target_properties(sqlpp-odbc-static PROPERTIES OUTPUT_NAME sqlpp-odbc)
endif()

install(TARGETS sqlpp-odbc-static DESTINATION lib)
install(TARGETS sqlpp-odbc-shared DESTINATION lib)
install(TARGETS sqlpp-odbc-static DESTINATION ${DESTDIR}/lib)
install(TARGETS sqlpp-odbc-shared DESTINATION ${DESTDIR}/lib)
39 changes: 27 additions & 12 deletions src/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ namespace sqlpp {
}
return ret;
}

void set_autocommit(SQLHDBC dbc) {
if(!SQL_SUCCEEDED(SQLSetConnectAttr(dbc, SQL_ATTR_AUTOCOMMIT, SQLPOINTER(SQL_TRUE), 0))) {
throw sqlpp::exception("ODBC error: Could not set AUTOCOMMIT to TRUE ("+detail::odbc_error(dbc, SQL_HANDLE_DBC)+')');
}
}
}
std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(detail::connection_handle_t& handle, const std::string& statement) {
if(handle.config.debug) {
Expand Down Expand Up @@ -137,9 +143,7 @@ namespace sqlpp {
}

size_t connection::execute(const std::string& statement) {
auto prepared = prepare_statement(*_handle, statement);
execute_statement(prepared->stmt);
return odbc_affected(prepared->stmt);
return _handle->exec_direct(statement);
}

size_t connection::update_impl(const std::string& statement) {
Expand Down Expand Up @@ -186,34 +190,45 @@ namespace sqlpp {
if(_transaction_active) {
throw sqlpp::exception("ODBC error: Cannot have more than one open transaction per connection");
}
auto prepared = prepare_statement(*_handle, "BEGIN");
execute_statement(prepared->stmt);
if(_handle->config.debug) {
std::cerr << "ODBC debug: Beginning Transaction\n";
}
if(!SQL_SUCCEEDED(SQLSetConnectAttr(_handle->dbc, SQL_ATTR_AUTOCOMMIT, SQLPOINTER(SQL_FALSE), 0))) {
throw sqlpp::exception("ODBC error: Could not set AUTOCOMMIT to FALSE ("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')');
}
_transaction_active = true;
}

void connection::commit_transaction() {
if(not _transaction_active) {
throw sqlpp::exception("ODBC error: Cannot commit a finished or failed transaction");
}
if(_handle->config.debug) {
std::cerr << "ODBC debug: Committing Transaction\n";
}
if(!SQL_SUCCEEDED(SQLEndTran(SQL_HANDLE_DBC, _handle->dbc, SQL_COMMIT))) {
throw sqlpp::exception("ODBC error: Could not SQLEndTran COMMIT("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')');
}
set_autocommit(_handle->dbc);
_transaction_active = false;
auto prepared = prepare_statement(*_handle, "COMMIT");
execute_statement(prepared->stmt);
}

void connection::rollback_transaction(bool report) {
if(not _transaction_active) {
throw sqlpp::exception("ODBC error: Cannot rollback a finished or failed transaction");
}
_transaction_active = false;
if(report) {
if(report || _handle->config.debug) {
std::cerr << "ODBC warning: Rolling back unfinished transaction" << std::endl;
}
auto prepared = prepare_statement(*_handle, "ROLLBACK");
execute_statement(prepared->stmt);
if(!SQL_SUCCEEDED(SQLEndTran(SQL_HANDLE_DBC, _handle->dbc, SQL_ROLLBACK))) {
throw sqlpp::exception("ODBC error: Could not SQLEndTran ROLLBACK("+detail::odbc_error(_handle->dbc, SQL_HANDLE_DBC)+')');
}
set_autocommit(_handle->dbc);
_transaction_active = false;
}

void connection::report_rollback_failure(const std::string message) noexcept {
std::cerr << "ODBC message: " << message << std::endl;
}
}
}
}
61 changes: 45 additions & 16 deletions src/detail/connection_handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,23 @@
namespace sqlpp {
namespace odbc {
namespace detail {
std::string return_code_string(SQLRETURN rc) {
switch(rc) {
case 0: return "SQL_SUCCESS";
case 1: return "SQL_SUCCESS_WITH_INFO";
case 2: return "SQL_STILL_EXECUTING";
case -1: return "SQL_NULL_DATA/SQL_ERROR";
case -2: return "SQL_DATA_AT_EXEC/SQL_INVALID_HANDLE";
case 99: return "SQL_NEED_DATA";
case 100: return "SQL_NO_DATA";
case 101: return "SQL_PARAM_DATA_AVAILABLE";
default: return "Unknown return code "+std::to_string(rc);
}
}

std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type, SQLRETURN return_code){
return "Returned "+return_code_string(return_code)+' '+odbc_error(handle, handle_type);
}

std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type){
std::vector<std::string> errors;
Expand Down Expand Up @@ -108,23 +125,10 @@ namespace sqlpp {
throw sqlpp::exception("ODBC error: couldn't SQLConnect("+config.data_source_name+"): "+err);
}
if(!config.database.empty()) {
SQLHSTMT stmt;
if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))) {
throw sqlpp::exception("ODBC error: could SQLAllocHandle(SQL_HANDLE_STMT): "+odbc_error(stmt, SQL_HANDLE_STMT));
}
if(config.debug) {
std::cerr << "ODBC debug: using " << config.database;
}
auto rc = SQLExecDirect(stmt, (SQLCHAR*)std::string("USE "+config.database).c_str(), config.database.length()+4);
std::string err;
if(!SQL_SUCCEEDED(rc)){
err = detail::odbc_error(stmt, SQL_HANDLE_STMT);
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
stmt = nullptr;
if(!SQL_SUCCEEDED(rc)) {
throw sqlpp::exception("ODBC error: couldn't SQLExecDirect(USE "+config.database+"): "+err);
std::cerr << "ODBC debug: using " << config.database << '\n';
}
exec_direct("USE "+config.database);
}
}

Expand All @@ -138,7 +142,32 @@ namespace sqlpp {
}
}

size_t connection_handle_t::exec_direct(const std::string& statement) {
SQLHSTMT stmt;
if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))) {
throw sqlpp::exception("ODBC error: could SQLAllocHandle(SQL_HANDLE_STMT): "+odbc_error(stmt, SQL_HANDLE_STMT));
}
auto rc = SQLExecDirect(stmt, (SQLCHAR*)statement.c_str(), statement.length());
std::string err;
SQLLEN ret = 0;
if(!(SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA)){
err = "ODBC error: couldn't SQLExecDirect("+statement+"): "+odbc_error(stmt, SQL_HANDLE_STMT, rc);
} else {
rc = SQLRowCount(stmt, &ret);
if(!SQL_SUCCEEDED(rc)) {
err = "ODBC error: couldn't SQLRowCount: "+odbc_error(stmt, SQL_HANDLE_STMT);
}
}
if(!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_STMT, stmt))) {
throw sqlpp::exception("ODBC error: couldn't SQLFreeHandle(HSTMT): "+odbc_error(dbc, SQL_HANDLE_DBC));
}
stmt = nullptr;
if(!SQL_SUCCEEDED(rc)) {
throw sqlpp::exception(err);
}
return ret;
}

}
}
}
}
5 changes: 4 additions & 1 deletion src/detail/connection_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,14 @@ namespace sqlpp {
connection_handle_t(connection_handle_t&&) = delete;
connection_handle_t& operator=(const connection_handle_t&) = delete;
connection_handle_t& operator=(connection_handle_t&&) = delete;

size_t exec_direct(const std::string& statement);
};

std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type);
std::string odbc_error(SQLHANDLE handle, SQLSMALLINT handle_type, SQLRETURN return_code);
}
}
}

#endif //SQLPP11_ODBC_CONNECTION_HANDLE_H
#endif //SQLPP11_ODBC_CONNECTION_HANDLE_H
17 changes: 6 additions & 11 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Original work Copyright (c) 2013-2015, Roland Bock
# Modified work Copyright (c) 2016, Aaron Bishop
# Modified work Copyright (c) 2016-2017, Aaron Bishop
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
Expand All @@ -23,13 +23,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

macro (build_and_run arg)
include_directories(include)
# Add headers to sources to enable file browsing in IDEs
add_executable("Sqlpp11ODBC${arg}" "${arg}.cpp" ${sqlpp_headers})
target_link_libraries("Sqlpp11ODBC${arg}" ${ODBC_LIBRARIES} sqlpp-odbc)
#target_link_libraries("Sqlpp11ODBC${arg}" nativeclient)
add_test("Sqlpp11ODBC${arg}" "${arg}")
endmacro ()

build_and_run(ODBCTest)
include_directories(include)
# Add headers to sources to enable file browsing in IDEs
add_executable("ODBCTest" "ODBCTest.cpp" ${sqlpp_headers})
target_link_libraries("ODBCTest" ${ODBC_LIBRARIES} sqlpp-odbc-shared)
add_test("MySQLTest" "ODBCTest" "MySQLTest" "test" "test" "test" "MySQL")
Loading

0 comments on commit be4e6f6

Please sign in to comment.