summaryrefslogtreecommitdiff
path: root/libodbcpp
diff options
context:
space:
mode:
Diffstat (limited to 'libodbcpp')
-rw-r--r--libodbcpp/bind.h6
-rw-r--r--libodbcpp/command.cpp3
-rw-r--r--libodbcpp/command.h3
-rw-r--r--libodbcpp/connection.cpp88
-rw-r--r--libodbcpp/connection.h9
-rw-r--r--libodbcpp/modifycommand.cpp6
-rw-r--r--libodbcpp/param.cpp12
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());