diff options
-rw-r--r-- | libodbcpp/bind.h | 6 | ||||
-rw-r--r-- | libodbcpp/command.cpp | 3 | ||||
-rw-r--r-- | libodbcpp/command.h | 3 | ||||
-rw-r--r-- | libodbcpp/connection.cpp | 88 | ||||
-rw-r--r-- | libodbcpp/connection.h | 9 | ||||
-rw-r--r-- | libodbcpp/modifycommand.cpp | 6 | ||||
-rw-r--r-- | libodbcpp/param.cpp | 12 |
7 files changed, 119 insertions, 8 deletions
diff --git a/libodbcpp/bind.h b/libodbcpp/bind.h index 36c7584..d06dcb2 100644 --- a/libodbcpp/bind.h +++ b/libodbcpp/bind.h @@ -23,6 +23,12 @@ namespace ODBC { virtual ~Bind() {} t value; }; + template <> + class Bind<unsigned char*> { + public: + virtual ~Bind(); + unsigned char * value; + }; } #endif diff --git a/libodbcpp/command.cpp b/libodbcpp/command.cpp index 6c8bf3c..217954e 100644 --- a/libodbcpp/command.cpp +++ b/libodbcpp/command.cpp @@ -4,7 +4,8 @@ #include <sqlext.h> ODBC::Command::Command(const Connection& c, String s) : - sql(s) + sql(s), + connection(c) { RETCODE rc = SQLAllocHandle(SQL_HANDLE_STMT, c.conn, &hStmt); if (rc != SQL_SUCCESS) { diff --git a/libodbcpp/command.h b/libodbcpp/command.h index 8e59c76..55e6703 100644 --- a/libodbcpp/command.h +++ b/libodbcpp/command.h @@ -15,6 +15,8 @@ namespace ODBC { void bindParamI(unsigned int i, int val); void bindParamI(unsigned int i, unsigned int val); + void bindParamI(unsigned int i, long unsigned int val); + void bindParamI(unsigned int i, long long unsigned int val); void bindParamF(unsigned int i, double val); void bindParamF(unsigned int i, float val); void bindParamS(unsigned int i, const char *); @@ -28,6 +30,7 @@ namespace ODBC { const String sql; protected: SQLHSTMT hStmt; + const Connection& connection; private: Params params; }; diff --git a/libodbcpp/connection.cpp b/libodbcpp/connection.cpp index 4130f08..7fa32fd 100644 --- a/libodbcpp/connection.cpp +++ b/libodbcpp/connection.cpp @@ -6,32 +6,39 @@ ODBC::Connection::Connection(const DSN& d) : DSN(d), env(0), - conn(0) + conn(0), + txDepth(0), + txAborted(false) { SQLRETURN dberr = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); - if ((dberr != SQL_SUCCESS) && (dberr != SQL_SUCCESS_WITH_INFO)) { + if ((dberr != SQL_SUCCESS)) { throw Error(dberr, SQL_HANDLE_ENV, env, "Allocate handle"); } dberr = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - if ((dberr != SQL_SUCCESS) && (dberr != SQL_SUCCESS_WITH_INFO)) { + if ((dberr != SQL_SUCCESS)) { throw Error(dberr, SQL_HANDLE_ENV, env, "Set ODBC version"); } dberr = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); - if ((dberr != SQL_SUCCESS) && (dberr != SQL_SUCCESS_WITH_INFO)) { + if ((dberr != SQL_SUCCESS)) { throw Error(dberr, SQL_HANDLE_ENV, env, "Allocate DBC handle"); } dberr = SQLSetConnectAttr(conn, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0); - if ((dberr != SQL_SUCCESS) && (dberr != SQL_SUCCESS_WITH_INFO)) { + if ((dberr != SQL_SUCCESS)) { throw Error(dberr, SQL_HANDLE_ENV, env, "Set connection attributes"); } dberr = SQLConnect(conn, dsn, SQL_NTS, username, SQL_NTS, password, SQL_NTS); - if ((dberr != SQL_SUCCESS) && (dberr != SQL_SUCCESS_WITH_INFO)) { + if ((dberr != SQL_SUCCESS)) { throw Error(dberr, SQL_HANDLE_DBC, conn, "Connect"); } + + dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); + } } ODBC::Connection::~Connection() @@ -50,3 +57,72 @@ ODBC::Connection::~Connection() } } } + +int +ODBC::Connection::beginTx() +{ + SQLRETURN dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); + } + txDepth += 1; + return txDepth; +} + +int +ODBC::Connection::commitTx() +{ + if (txDepth > 0) { + if (txAborted) { + return rollbackTx(); + } + txDepth -= 1; + if (txDepth == 0) { + SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_COMMIT)"); + } + dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); + } + txAborted = false; + } + return txDepth; + } + throw Error("Attempt to commit none existant transaction"); +} + +int +ODBC::Connection::rollbackTx() +{ + if (txDepth > 0) { + txDepth -= 1; + if (txDepth == 0) { + SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_ROLLBACK); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_ROLLBACK)"); + } + dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if ((dberr != SQL_SUCCESS)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); + } + txAborted = false; + } + return txDepth; + } + throw Error("Attempt to rollback none existant transaction"); +} + +void +ODBC::Connection::abortTx() const +{ + txAborted = true; +} + +bool +ODBC::Connection::txIsAborted() const +{ + return txAborted; +} + diff --git a/libodbcpp/connection.h b/libodbcpp/connection.h index d5adb31..8593e82 100644 --- a/libodbcpp/connection.h +++ b/libodbcpp/connection.h @@ -11,6 +11,15 @@ namespace ODBC { ~Connection(); SQLHENV env; SQLHDBC conn; + + int beginTx(); + int commitTx(); + int rollbackTx(); + void abortTx() const; + bool txIsAborted() const; + private: + mutable unsigned int txDepth; + mutable bool txAborted; }; } diff --git a/libodbcpp/modifycommand.cpp b/libodbcpp/modifycommand.cpp index 706b3fd..5e614b7 100644 --- a/libodbcpp/modifycommand.cpp +++ b/libodbcpp/modifycommand.cpp @@ -13,21 +13,27 @@ ODBC::ModifyCommand::~ModifyCommand() unsigned int ODBC::ModifyCommand::execute(bool anc) { + if (connection.txIsAborted()) { + throw Error("Transaction has been aborted, not issuing any more commands"); + } RETCODE rc = SQLExecute(hStmt); if (rc != SQL_SUCCESS) { if (rc != SQL_NO_DATA || !anc) { + connection.abortTx(); throw Error(rc, SQL_HANDLE_STMT, hStmt, "%s: SQLExecute", __FUNCTION__); } } SQLINTEGER rows; if ((rc = SQLRowCount(hStmt, &rows)) != SQL_SUCCESS) { + connection.abortTx(); throw Error(rc, SQL_HANDLE_STMT, hStmt, "%s: SQLRowCount", __FUNCTION__); } if (rows > 0 || anc) { return rows; } + connection.abortTx(); throw Error("%s: No rows affected", __FUNCTION__); } diff --git a/libodbcpp/param.cpp b/libodbcpp/param.cpp index 7657ef4..0e49067 100644 --- a/libodbcpp/param.cpp +++ b/libodbcpp/param.cpp @@ -68,7 +68,7 @@ ODBC::Command::bindParamI(unsigned int i, int val) throw Error("%s: Bind out of bounds", __FUNCTION__); } void -ODBC::Command::bindParamI(unsigned int i, unsigned int val) +ODBC::Command::bindParamI(unsigned int i, long long unsigned int val) { if (i < params.size()) { _Param<SQLUINTEGER>* p = Param::makeParam<SQLUINTEGER>(params[i]); @@ -129,6 +129,16 @@ ODBC::Command::bindParamT(unsigned int i, struct tm * val) // Wrappers for all the roughly compatable types void +ODBC::Command::bindParamI(unsigned int i, long unsigned int val) +{ + bindParamI(i, (long long unsigned int)val); +} +void +ODBC::Command::bindParamI(unsigned int i, unsigned int val) +{ + bindParamI(i, (long long unsigned int)val); +} +void ODBC::Command::bindParamS(unsigned int i, String val) { bindParamS(i, val.c_str(), val.size()); |