X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=odbc-store%2Fodbc-store.cpp;h=4c1ac8915b809a26be894a05d10c0d385beb528d;hb=1ef6f26a463a31a371547f91d3b5766e1d852558;hp=5eb2a2bdf6d2f0610bf29c98b7bec70b369baab1;hpb=f6780464860ab732ee0925760caccf284fde07cc;p=shibboleth%2Fsp.git diff --git a/odbc-store/odbc-store.cpp b/odbc-store/odbc-store.cpp index 5eb2a2b..4c1ac89 100644 --- a/odbc-store/odbc-store.cpp +++ b/odbc-store/odbc-store.cpp @@ -37,8 +37,8 @@ # define ODBCSTORE_EXPORTS #endif -#include #include +#include #include #include #include @@ -48,9 +48,9 @@ #include #include +using namespace xmltooling::logging; using namespace xmltooling; using namespace xercesc; -using namespace log4cpp; using namespace std; #define PLUGIN_VER_MAJOR 1 @@ -65,7 +65,7 @@ using namespace std; #define STRING_TABLE "strings" #define TEXT_TABLE "texts" -/* tables definitions +/* table definitions CREATE TABLE version ( major tinyint NOT NULL, minor tinyint NOT NULL @@ -96,23 +96,19 @@ namespace { // RAII for ODBC handles struct ODBCConn { - ODBCConn(SQLHDBC conn) : handle(conn) {} + ODBCConn(SQLHDBC conn) : handle(conn), autoCommit(true) {} ~ODBCConn() { - SQLRETURN sr = SQLEndTran(SQL_HANDLE_DBC, handle, SQL_COMMIT); + SQLRETURN sr = SQL_SUCCESS; + if (!autoCommit) + sr = SQLSetConnectAttr(handle, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, NULL); SQLDisconnect(handle); SQLFreeHandle(SQL_HANDLE_DBC,handle); if (!SQL_SUCCEEDED(sr)) - throw IOException("Failed to commit connection."); + throw IOException("Failed to commit connection and return to auto-commit mode."); } operator SQLHDBC() {return handle;} SQLHDBC handle; - }; - - struct ODBCStatement { - ODBCStatement(SQLHSTMT statement) : handle(statement) {} - ~ODBCStatement() {SQLFreeHandle(SQL_HANDLE_STMT,handle);} - operator SQLHSTMT() {return handle;} - SQLHSTMT handle; + bool autoCommit; }; class ODBCStorageService : public StorageService @@ -314,7 +310,8 @@ ODBCStorageService::~ODBCStorageService() shutdown_wait->signal(); cleanup_thread->join(NULL); delete shutdown_wait; - SQLFreeHandle(SQL_HANDLE_ENV, m_henv); + if (m_henv != SQL_NULL_HANDLE) + SQLFreeHandle(SQL_HANDLE_ENV, m_henv); } bool ODBCStorageService::log_error(SQLHANDLE handle, SQLSMALLINT htype, const char* checkfor) @@ -360,9 +357,6 @@ SQLHDBC ODBCStorageService::getHDBC() throw IOException("ODBC StorageService failed to connect to database."); } - sr = SQLSetConnectAttr(handle, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, NULL); - if (!SQL_SUCCEEDED(sr)) - throw IOException("ODBC StorageService failed to disable auto-commit mode."); sr = SQLSetConnectAttr(handle, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)SQL_TXN_SERIALIZABLE, NULL); if (!SQL_SUCCEEDED(sr)) throw IOException("ODBC StorageService failed to enable transaction isolation."); @@ -385,7 +379,7 @@ SQLHSTMT ODBCStorageService::getHSTMT(SQLHDBC conn) pair ODBCStorageService::getVersion(SQLHDBC conn) { // Grab the version number from the database. - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); SQLRETURN sr=SQLExecDirect(stmt, (SQLCHAR*)"SELECT major,minor FROM version", SQL_NTS); if (!SQL_SUCCEEDED(sr)) { @@ -406,7 +400,7 @@ pair ODBCStorageService::getVersion(SQLHDBC conn) throw IOException("ODBC StorageService failed to read version from database."); } -bool ODBCStorageService::createRow(const char *table, const char* context, const char* key, const char* value, time_t expiration) +bool ODBCStorageService::createRow(const char* table, const char* context, const char* key, const char* value, time_t expiration) { #ifdef _DEBUG xmltooling::NDC ndc("createRow"); @@ -417,25 +411,64 @@ bool ODBCStorageService::createRow(const char *table, const char* context, const // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); // Prepare and exectute insert statement. - char *scontext = makeSafeSQL(context); - char *skey = makeSafeSQL(key); - char *svalue = makeSafeSQL(value); - string q = string("INSERT ") + table + " VALUES ('" + scontext + "','" + skey + "'," + timebuf + ",1,'" + svalue + "')"; - freeSafeSQL(scontext, context); - freeSafeSQL(skey, key); - freeSafeSQL(svalue, value); - m_log.debug("SQL: %s", q.c_str()); + //char *scontext = makeSafeSQL(context); + //char *skey = makeSafeSQL(key); + //char *svalue = makeSafeSQL(value); + string q = string("INSERT INTO ") + table + " VALUES (?,?," + timebuf + ",1,?)"; - SQLRETURN sr=SQLExecDirect(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); + SQLRETURN sr = SQLPrepare(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("SQLPrepare failed (t=%s, c=%s, k=%s)", table, context, key); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to insert record."); + } + m_log.debug("SQLPrepare succeded. SQL: %s", q.c_str()); + + SQLINTEGER b_ind = SQL_NTS; + sr = SQLBindParam(stmt, 1, SQL_C_CHAR, SQL_VARCHAR, 255, 0, const_cast(context), &b_ind); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("SQLBindParam failed (context = %s)", context); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to insert record."); + } + m_log.debug("SQLBindParam succeded (context = %s)", context); + + sr = SQLBindParam(stmt, 2, SQL_C_CHAR, SQL_VARCHAR, 255, 0, const_cast(key), &b_ind); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("SQLBindParam failed (key = %s)", key); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to insert record."); + } + m_log.debug("SQLBindParam succeded (key = %s)", key); + + if (strcmp(table, TEXT_TABLE)==0) + sr = SQLBindParam(stmt, 3, SQL_C_CHAR, SQL_LONGVARCHAR, strlen(value), 0, const_cast(value), &b_ind); + else + sr = SQLBindParam(stmt, 3, SQL_C_CHAR, SQL_VARCHAR, 255, 0, const_cast(value), &b_ind); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("SQLBindParam failed (value = %s)", value); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to insert record."); + } + m_log.debug("SQLBindParam succeded (value = %s)", value); + + //freeSafeSQL(scontext, context); + //freeSafeSQL(skey, key); + //freeSafeSQL(svalue, value); + //m_log.debug("SQL: %s", q.c_str()); + + sr=SQLExecute(stmt); if (!SQL_SUCCEEDED(sr)) { m_log.error("insert record failed (t=%s, c=%s, k=%s)", table, context, key); if (log_error(stmt, SQL_HANDLE_STMT, "23000")) return false; // supposedly integrity violation? throw IOException("ODBC StorageService failed to insert record."); } + + m_log.debug("SQLExecute of insert succeeded"); return true; } @@ -449,7 +482,7 @@ int ODBCStorageService::readRow( // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); // Prepare and exectute select statement. char timebuf[32]; @@ -516,9 +549,13 @@ int ODBCStorageService::updateRow(const char *table, const char* context, const if (!value && !expiration) throw IOException("ODBC StorageService given invalid update instructions."); - // Get statement handle. + // Get statement handle. Disable auto-commit mode to wrap select + update. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLRETURN sr = SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, NULL); + if (!SQL_SUCCEEDED(sr)) + throw IOException("ODBC StorageService failed to disable auto-commit mode."); + conn.autoCommit = false; + SQLHSTMT stmt = getHSTMT(conn); // First, fetch the current version for later, which also ensures the record still exists. char timebuf[32]; @@ -526,11 +563,11 @@ int ODBCStorageService::updateRow(const char *table, const char* context, const char *scontext = makeSafeSQL(context); char *skey = makeSafeSQL(key); string q("SELECT version FROM "); - q = q + table + " WHERE context='" + scontext + "' AND id='" + key + "' AND expires > " + timebuf; + q = q + table + " WHERE context='" + scontext + "' AND id='" + skey + "' AND expires > " + timebuf; m_log.debug("SQL: %s", q.c_str()); - SQLRETURN sr=SQLExecDirect(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); + sr=SQLExecDirect(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); if (!SQL_SUCCEEDED(sr)) { freeSafeSQL(scontext, context); freeSafeSQL(skey, key); @@ -554,14 +591,14 @@ int ODBCStorageService::updateRow(const char *table, const char* context, const return -1; } + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = getHSTMT(conn); + // Prepare and exectute update statement. q = string("UPDATE ") + table + " SET "; - if (value) { - char *svalue = makeSafeSQL(value); - q = q + "value='" + svalue + "'" + ",version=version+1"; - freeSafeSQL(svalue, value); - } + if (value) + q = q + "value=?, version=version+1"; if (expiration) { timestampFromTime(expiration, timebuf); @@ -570,12 +607,33 @@ int ODBCStorageService::updateRow(const char *table, const char* context, const q = q + "expires = " + timebuf; } - q = q + " WHERE context='" + scontext + "' AND id='" + key + "'"; + q = q + " WHERE context='" + scontext + "' AND id='" + skey + "'"; freeSafeSQL(scontext, context); freeSafeSQL(skey, key); - m_log.debug("SQL: %s", q.c_str()); - sr=SQLExecDirect(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); + sr = SQLPrepare(stmt, (SQLCHAR*)q.c_str(), SQL_NTS); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("update of record failed (t=%s, c=%s, k=%s", table, context, key); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to update record."); + } + m_log.debug("SQLPrepare succeded. SQL: %s", q.c_str()); + + SQLINTEGER b_ind = SQL_NTS; + if (value) { + if (strcmp(table, TEXT_TABLE)==0) + sr = SQLBindParam(stmt, 1, SQL_C_CHAR, SQL_LONGVARCHAR, strlen(value), 0, const_cast(value), &b_ind); + else + sr = SQLBindParam(stmt, 1, SQL_C_CHAR, SQL_VARCHAR, 255, 0, const_cast(value), &b_ind); + if (!SQL_SUCCEEDED(sr)) { + m_log.error("SQLBindParam failed (context = %s)", context); + log_error(stmt, SQL_HANDLE_STMT); + throw IOException("ODBC StorageService failed to update record."); + } + m_log.debug("SQLBindParam succeded (context = %s)", context); + } + + sr=SQLExecute(stmt); if (sr==SQL_NO_DATA) return 0; // went missing? else if (!SQL_SUCCEEDED(sr)) { @@ -584,6 +642,7 @@ int ODBCStorageService::updateRow(const char *table, const char* context, const throw IOException("ODBC StorageService failed to update record."); } + m_log.debug("SQLExecute of update succeeded"); return ver + 1; } @@ -595,7 +654,7 @@ bool ODBCStorageService::deleteRow(const char *table, const char *context, const // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); // Prepare and execute delete statement. char *scontext = makeSafeSQL(context); @@ -671,7 +730,7 @@ void ODBCStorageService::updateContext(const char *table, const char* context, t // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); char timebuf[32]; timestampFromTime(expiration, timebuf); @@ -702,7 +761,7 @@ void ODBCStorageService::reap(const char *table, const char* context) // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); // Prepare and execute delete statement. char nowbuf[32]; @@ -734,7 +793,7 @@ void ODBCStorageService::deleteContext(const char *table, const char* context) // Get statement handle. ODBCConn conn(getHDBC()); - ODBCStatement stmt(getHSTMT(conn)); + SQLHSTMT stmt = getHSTMT(conn); // Prepare and execute delete statement. char *scontext = makeSafeSQL(context);