/* * DB2Query object defines the needed query functions for the dbConnect IBM DB2 driver * Copyright (C) 2003 Johnathan Ingram, jingram@rogueware.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 US * */ #include "ibmDB2Query.h" // ----------------------------------------------------------------------------- // PRIVATE: // ----------------------------------------------------------------------------- //------------------------------------------------------------------------------ // DB2Query::_db2GetFieldsInformation //------------------------------------------------------------------------------ void DB2Query::_db2GetFieldsInformation() { // Clear any previouse field information just incase. _freeCollection(FIELD_INFORMATION); // Internal method used to build the field information. // Allocate the information pointers _numFieldInformation = _fieldCount; _fieldInformation = (DB2FieldDescription**)malloc(_numFieldInformation * sizeof(DB2FieldDescription*)); // Assign the data to the corresponding fields. for (int i=0; i<_numFieldInformation; i++) { // Get the field information SQLRETURN cliRC; SQLCHAR colName[256]; SQLSMALLINT colNameLen; SQLSMALLINT colType; SQLUINTEGER colSize; SQLSMALLINT colScale; SQLSMALLINT colPrecision; SQLSMALLINT colNullable; SQLSMALLINT colAutoUnique; // Obtain the required information cliRC = SQLDescribeCol(_hstmt, (SQLSMALLINT)i+1, colName, sizeof(colName)-1, &colNameLen, &colType, &colSize, &colScale, &colNullable); if (cliRC == SQL_SUCCESS) cliRC = SQLColAttribute(_hstmt, (SQLSMALLINT)i+1, SQL_DESC_PRECISION, NULL, 0, NULL, &colPrecision); if (cliRC == SQL_SUCCESS) cliRC = SQLColAttribute(_hstmt, (SQLSMALLINT)i+1, SQL_DESC_AUTO_UNIQUE_VALUE, NULL, 0, NULL, &colAutoUnique); // Finally bail on an error if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "_db2GetFieldsInformation(): "; err += (const char*)message; throw ErrorQuerying(err); } // Work out the field type. FieldType _type = _db2ResolveFieldType(colType); // Field Properties. string fName = (const char*)colName; long int _scale = colScale; long int _precision = 0; if (colType == SQL_DECIMAL || colType == SQL_NUMERIC || colType == SQL_DOUBLE || colType == SQL_FLOAT || colType == SQL_INTEGER || colType == SQL_REAL || colType == SQL_SMALLINT) _precision = colPrecision; bool _isIncrement = (colAutoUnique == SQL_FALSE ? false : true); // Will always return false. Future versions of CLI will support this. bool _isPriKey = false; // Not supported bool _isUnique = false; // Not supported bool _isNotNull = (colNullable == SQL_NULLABLE ? false : true); // Add the field properties to the vector. _fieldInformation[i] = new DB2FieldDescription(fName, i, _type, _isIncrement, _isPriKey, _isUnique, _isNotNull, _precision, _scale, colType, colSize); } } // DB2Query::_db2GetFieldsInformation //------------------------------------------------------------------------------ // DB2Query::_db2GetResultSetRow //------------------------------------------------------------------------------ void DB2Query::_db2GetResultSetRow() { // NOTE: This function always assumes fetchNext has been called before the start // Clear any previouse field information just incase. _freeCollection(FIELD_VALUES); // Allocate the value pointers _numRecordValues = _fieldCount; _recordValues = (DB2Value**)malloc(_numRecordValues * sizeof(DB2Value*)); // Get the data :) SQLRETURN cliRC; for (int i=0; i<_fieldCount; i++) { // Allocate the field _recordValues[i] = new DB2Value(_fieldInformation[i]->name().c_str()); // Get the field value according to the field type SQLINTEGER strlen_indptr, tmp_strlen_indptr; void *buffer = NULL; long bufferSize = 0; void *bufferOffset = NULL; JDate dVal(0.0); // Epoch switch(_fieldInformation[i]->db2FieldType()) { // Obtain the data as an 64bit integer value case SQL_BIGINT: case SQL_TINYINT: case SQL_INTEGER: case SQL_SMALLINT: bufferSize = sizeof(DBLONG); buffer = malloc(bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_SBIGINT, buffer, bufferSize, &strlen_indptr); if (cliRC == SQL_SUCCESS) { if (strlen_indptr == SQL_NULL_DATA) _recordValues[i]->setNULL(); else _recordValues[i]->setLong(*(DBLONG*)buffer); } break; // Obtain the data as an double floating point value case SQL_DECIMAL: case SQL_DOUBLE: case SQL_FLOAT: case SQL_NUMERIC: case SQL_REAL: bufferSize = sizeof(double); buffer = malloc(bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_DOUBLE, buffer, bufferSize, &strlen_indptr); if (cliRC == SQL_SUCCESS) { if (strlen_indptr == SQL_NULL_DATA) _recordValues[i]->setNULL(); else _recordValues[i]->setFloat(*(double*)buffer); } break; // Obtain the data as character data (Allocate enough for field size) case SQL_CHAR: case SQL_CLOB: case SQL_VARCHAR: case SQL_GRAPHIC: case SQL_VARGRAPHIC: bufferSize = _fieldInformation[i]->db2FieldSize() + 1; // +1 for NULL terminating char buffer = malloc(bufferSize); memset(buffer, 0, bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_CHAR, buffer, bufferSize, &strlen_indptr); if (cliRC == SQL_SUCCESS) { if (strlen_indptr == SQL_NULL_DATA) _recordValues[i]->setNULL(); else _recordValues[i]->setString((char*)buffer); } break; // Obtain the data as timstamp value case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TYPE_TIMESTAMP: bufferSize = sizeof(TIMESTAMP_STRUCT); buffer = malloc(bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_TYPE_TIMESTAMP, buffer, bufferSize, &strlen_indptr); if (cliRC == SQL_SUCCESS) { if (strlen_indptr == SQL_NULL_DATA) _recordValues[i]->setNULL(); else { // Build a JDate from the components dVal.setDate(((TIMESTAMP_STRUCT*)buffer)->year, ((TIMESTAMP_STRUCT*)buffer)->month, ((TIMESTAMP_STRUCT*)buffer)->day, ((TIMESTAMP_STRUCT*)buffer)->hour, ((TIMESTAMP_STRUCT*)buffer)->minute, ((TIMESTAMP_STRUCT*)buffer)->second ); _recordValues[i]->setDateTime(dVal); } } break; // Obtain the data as binary value (Obtain the data block by block) case SQL_BLOB: case SQL_BINARY: bufferSize = FETCH_BLOCK_SIZE; buffer = malloc(bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_BINARY, buffer, bufferSize, &strlen_indptr); if (cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) { if (strlen_indptr == SQL_NULL_DATA) _recordValues[i]->setNULL(); else { // Get any left over data in a single query. Result is set to SQL_SUCCESS_WITH_INFO // if there is still data left to be read if (cliRC == SQL_SUCCESS_WITH_INFO) { // strlen_indptr now has the total size of the data in the column tmp_strlen_indptr = strlen_indptr; buffer = realloc(buffer, tmp_strlen_indptr); bufferOffset = (void*)((unsigned int)buffer + bufferSize); cliRC = SQLGetData(_hstmt, i+1, SQL_C_BINARY, bufferOffset, tmp_strlen_indptr - bufferSize, &strlen_indptr); if (cliRC != SQL_SUCCESS) break; // Now finally set the buffer size bufferSize = tmp_strlen_indptr; } else { // The buffer size is the number of bytes read bufferSize = strlen_indptr; } if (cliRC == SQL_SUCCESS) _recordValues[i]->setBinary(buffer, bufferSize); } } break; default: char buf[20]; memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf)-1, "%d", _fieldInformation[i]->db2FieldType()); string err = "_db2GetResultSetRow(): Unknown DB2 SQL field type "; err += buf; throw ResultSetError(err); break; } // Free the buffer if (buffer) { free(buffer); buffer = NULL; } // Make sure fetching the field data was ok. if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "_db2GetResultSetRow(): Unable to obtain field data, "; err += (const char*)message; throw ResultSetError(err); } } // Pre-fetch the next row cliRC = SQLFetch(_hstmt); // Check if the previouse fetchNext fetched the last row if (cliRC == SQL_NO_DATA_FOUND) { _eof = true; } else if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "_db2GetResultSetRow(): "; err += (const char*)message; throw ResultSetError(err); } } // DB2Query::_db2GetResultSetRow //------------------------------------------------------------------------------ // DB2Query::_db2ResolveFieldType //------------------------------------------------------------------------------ FieldType DB2Query::_db2ResolveFieldType( SQLSMALLINT type) { FieldType res; // LONG types are not supported as they should be replaced by LOB types according to the DB2 documentation // TODO: Research and support the following types // SQL_BIT, SQL_DATALINK // SQL_DB_CLOB, SQL_DB_LOCATOR, SQL_WCHAR // TODO: Support VARBINARY //case SQL_VARBINARY: // res = FT_BLOB; // break; switch(type) { case SQL_BIGINT: res = FT_LONG; break; case SQL_BLOB: res = FT_BLOB; break; case SQL_CHAR: res = FT_STRING; break; case SQL_TINYINT: res = FT_LONG; break; case SQL_BINARY: res = FT_BLOB; break; case SQL_CLOB: res = FT_STRING; break; case SQL_TYPE_DATE: res = FT_DATETIME; break; case SQL_DECIMAL: res = FT_DOUBLE; break; case SQL_DOUBLE: res = FT_DOUBLE; break; case SQL_FLOAT: res = FT_DOUBLE; break; case SQL_INTEGER: res = FT_LONG; break; case SQL_NUMERIC: res = FT_DOUBLE; break; case SQL_REAL: res = FT_DOUBLE; break; case SQL_SMALLINT: res = FT_SHORT; break; case SQL_TYPE_TIME: res = FT_DATETIME; break; case SQL_TYPE_TIMESTAMP: res = FT_DATETIME; break; case SQL_VARCHAR: res = FT_STRING; break; case SQL_GRAPHIC: res = FT_STRING; break; case SQL_VARGRAPHIC: res = FT_STRING; break; default: res = FT_UNKNOWN; break; } return res; } // DB2Query::_db2ResolveFieldType //------------------------------------------------------------------------------ // DB2Query::_db2ParseBindParameters //------------------------------------------------------------------------------ string DB2Query::_db2ParseBindParameters( const string& originalSqlStatement, vector &bindParameters) { // Replace the ":name" parameters with a ? from left to right building the bindParameter vector to point to the correct values // Try and substitute the parameters checking to make sure they exist. string res = originalSqlStatement; int pos, endPos; char paramName[1024]; pos = res.find(":"); while (pos != string::npos) { memset(paramName, 0, sizeof(paramName)); // Get the position at the end of the parameter name and determine the parameter name endPos = pos +1; char tstChar = res.c_str()[endPos]; while ((tstChar >= '0' && tstChar <= '9') || // 0 - 9 (tstChar >= 'A' && tstChar <= 'Z') || // A - Z (tstChar >= 'a' && tstChar <= 'z')|| // a - z (tstChar == '_') ) // _ { endPos++; if (endPos > res.length()) throw BindParameterError("_db2ParseBindParameters(): Unable to properly parse the bind parameters"); tstChar = res.c_str()[endPos]; } char *paramNameStart = (char*)((int)res.c_str() + pos+1); // Jump the : in the param name strncpy(paramName, paramNameStart, endPos - pos-1); // Replace the parameter with a ? res.replace(pos, endPos-pos, "?"); // Make sure the parameter name exists and add the value to the parameter vector bool found = false; for (int i =0; i<_numParameters; i++) { if (strcasecmp(_parameters[i]->name().c_str(), paramName) == 0) { found = true; bindParameters.push_back(_parameters[i]); break; } } if (!found) { string err = "_db2ParseBindParameters(): The bind parameter, "; err += paramName; err += ", in the SQL statement: "; err += originalSqlStatement; err += " has not been set."; throw BindParameterNotSet(err); } // Find the next parameter and continue pos = res.find(":"); } return res; } // DB2Query::_db2ParseBindParameters //------------------------------------------------------------------------------ // DB2Query::_db2BindParameters //------------------------------------------------------------------------------ void DB2Query::_db2BindParameters( const string& resolvedSqlStatement, vector &bindParameters) { SQLRETURN cliRC = SQL_SUCCESS; // Iterate through the pointer list and bind the parameter values according to type from left to right for (int i=0; igetDB2CType(), paramSQLType, columnSize, decDigits, bindParameters[i]->getDB2DataPointer(), bindParameters[i]->getDB2DataPointerLength(), bindParameters[i]->getDB2StrLenIndPtr() ); if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "_db2BindParameters(): "; err += (const char*)message; throw BindParameterError(err); } } } // DB2Query::_db2BindParameters //------------------------------------------------------------------------------ // DB2Query::_freeCollection //------------------------------------------------------------------------------ void DB2Query::_freeCollection( CollectionType type) { int i; switch (type) { case FIELD_INFORMATION: if (_fieldInformation) { for (i=0; i<_numFieldInformation; i++) { if (_fieldInformation[i]) { delete _fieldInformation[i]; _fieldInformation[i] = NULL; } } free(_fieldInformation); _fieldInformation = NULL; _numFieldInformation = 0; _fieldCount = 0; } break; case FIELD_VALUES: if (_recordValues) { for (i=0; i<_numRecordValues; i++) { if (_recordValues[i]) { delete _recordValues[i]; _recordValues[i] = NULL; } } free(_recordValues); _recordValues = NULL; _numRecordValues = 0; } break; case BIND_PARAMETERS: if (_parameters) { for (i=0; i<_numParameters; i++) { if (_parameters[i]) { delete _parameters[i]; _parameters[i] = NULL; } } free(_parameters); _parameters = NULL; _numParameters = 0; } break; } } // DB2Query::_freeCollection // ----------------------------------------------------------------------------- // PUBLIC: // ----------------------------------------------------------------------------- //------------------------------------------------------------------------------ // DB2Query::DB2Query //------------------------------------------------------------------------------ DB2Query::DB2Query( DB2Connection* parentConnection, int index) : _parentConnection(parentConnection), _index(index), _isTransaction(false), _hstmt(SQL_NULL_HSTMT), _db2CurrentRow(0), _recordValues(NULL), _numRecordValues(0), _fieldInformation(NULL), _numFieldInformation(0), _parameters(NULL), _numParameters(0) { } // DB2Query::DB2Query //------------------------------------------------------------------------------ // DB2Query::~DB2Query //------------------------------------------------------------------------------ DB2Query::~DB2Query() { // If there is still a transaction, rollback if (_isTransaction) rollback(); //Make sure all DB2 resources are released if (_hstmt != SQL_NULL_HSTMT) { SQLFreeHandle(SQL_HANDLE_STMT, _hstmt); _hstmt = SQL_NULL_HSTMT; } // Free any parameters _freeCollection(BIND_PARAMETERS); // Free the current field values _freeCollection(FIELD_VALUES); // Clear any previouse field information. _freeCollection(FIELD_INFORMATION); // Release this connection from the parent connection object. _parentConnection->releaseQueryConnection(this); } // DB2Query::~DB2Query //------------------------------------------------------------------------------ // DB2Query::clearBindParams //------------------------------------------------------------------------------ void DB2Query::clearBindParams() { // Free all the bind parameters. _freeCollection(BIND_PARAMETERS); } // DB2Query::clearBindParams //------------------------------------------------------------------------------ // DB2Query::command //------------------------------------------------------------------------------ void DB2Query::command( const string& sqlStatement) { // Clear any bind parameters as we now have a new query clearBindParams(); // Check if this is a function been called and build the correct sql if it is //string newSqlStatement = _pgsqlParseFunctionCall(sqlStatement); string newSqlStatement = sqlStatement; // TODO: Add procedure calling "CALL XYZ(?,?)" // Call the base query to store a copy of the query. BaseQuery::command(newSqlStatement); } // DB2Query::command //------------------------------------------------------------------------------ // DB2Query::bindParam //------------------------------------------------------------------------------ BaseValue* DB2Query::bindParam( const string& paramName) { // Make sure the name has not already been added. If it has, return the instance to it for (int i=0; i<_numParameters; i++) if (strcasecmp(_parameters[i]->bindName.c_str(), paramName.c_str()) == 0) return _parameters[i]; // Make sure the parameter is present in the quey if (!_isBindParameterPresent(paramName)) { string err = "bindParam(): The specified bind parameter, "; err += paramName; err += ", is not present in the SQL statement: "; err += _sqlStatement; throw BindParameterNotPresent(err); } // Add the value to the parameters array. _numParameters++; _parameters = (DB2BindParam**)realloc((void*)_parameters, _numParameters * sizeof(DB2BindParam*)); _parameters[_numParameters-1] = new DB2BindParam(paramName); return _parameters[_numParameters-1]; } // DB2Query::bindParam //------------------------------------------------------------------------------ // DB2Query::execute //------------------------------------------------------------------------------ void DB2Query::execute() { // Holds pointers for the bind values (left to right alinged to the ?'s that will be substituted) vector bindParameters; SQLRETURN cliRC = SQL_SUCCESS; //Make sure all DB2 resources are released if (_hstmt != SQL_NULL_HSTMT) { SQLFreeHandle(SQL_HANDLE_STMT, _hstmt); _hstmt = SQL_NULL_HSTMT; } _queryParameterNames.clear(); // Number of rows in the result set is now 0 _db2CurrentRow = 0; // Clear any previouse field information. _freeCollection(FIELD_INFORMATION); // Free the current field values _freeCollection(FIELD_VALUES); // Replace all the bind parameters in the SQL with '?' characters and build name list for correct binding string resolvedSqlStatement = _db2ParseBindParameters(_sqlStatement, bindParameters); // Ping the connection to make sure it is still valid. _parentConnection->_db2Ping(_index); // Allocate the statement handle cliRC = SQLAllocHandle(SQL_HANDLE_STMT, _parentConnection->_handles[_index]->_hdbc, &_hstmt); if (cliRC != SQL_SUCCESS) throw ErrorQuerying("execute(): Unable to allocate the statement handle."); // Prepare the statement cliRC = SQLPrepare(_hstmt, (SQLCHAR*)resolvedSqlStatement.c_str(), SQL_NTS); if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "execute(): "; err += (const char*)message; throw ErrorQuerying(err); } // Always make sure there is a transaction that the query is occuring in // Call this after the SQLPrepare as SQLPrepare will create a transaction if (!_isTransaction) transBegin(); // Bind the parameters _db2BindParameters(resolvedSqlStatement, bindParameters); // Execute the query cliRC = SQLExecute(_hstmt); // Make sure it executed correctly if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "execute(): "; err += (const char*)message; throw ErrorQuerying(err); } // Check if there is a result set SQLSMALLINT nResultCols; cliRC = SQLNumResultCols(_hstmt, &nResultCols); if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "execute(): "; err += (const char*)message; throw ErrorQuerying(err); } // Handle the result set comming back if (nResultCols) { // We have a result set with data _fieldCount = nResultCols; // Get the field information for this query. _db2GetFieldsInformation(); _eof = false; // Pre-fetch the first row making sure there is data in the result set cliRC = SQLFetch(_hstmt); if (cliRC == SQL_NO_DATA_FOUND) { _eof = true; } else if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, _hstmt, 1, sqlState, &sqlCode, message, 250, &length); string err = "execute(): "; err += (const char*)message; throw ResultSetError(err); } } else { // We have no records, could be an update or something _fieldCount = 0; _eof = true; } } // DB2Query::execute //------------------------------------------------------------------------------ // DB2Query::next //------------------------------------------------------------------------------ void DB2Query::fetchNext() { // Do nothing if the we have reached the end of the record set. if (_eof) return; // Get the data. _db2GetResultSetRow will set the _eof parameter _db2GetResultSetRow(); _db2CurrentRow++; } // DB2Query::next //------------------------------------------------------------------------------ // DB2Query::transBegin //------------------------------------------------------------------------------ void DB2Query::transBegin() { // Make sure a transaction is not already active if (_isTransaction) throw TransactionError("transBegin(): " "A transaction is already active. Commit or rollback the transaction before creating a new transaction."); _isTransaction = true; /* * A DB2 transaction is automatically started when a SQLPrepare, SQLExecDirect or SQLGetTypeInfo call is made. * Hence a transaction is implied, and does not need to be explicilty created. * This function should remain as a token function with basic error checking, Johnathan Ingram * */ } // DB2Query::transBegin //------------------------------------------------------------------------------ // DB2Query::commit //------------------------------------------------------------------------------ void DB2Query::commit() { // Make sure a transaction is active if (!_isTransaction) throw TransactionError("commit(): " "A transaction is not active. Create a transaction before calling commit."); // Commit the transaction SQLRETURN cliRC = SQL_SUCCESS; cliRC = SQLEndTran(SQL_HANDLE_DBC, _parentConnection->_handles[_index]->_hdbc, SQL_COMMIT); // Check if an error occured while commiting if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_DBC, _parentConnection->_handles[_index]->_hdbc, 1, sqlState, &sqlCode, message, 250, &length); string err = "commit(): "; err += (const char*)message; throw TransactionError(err); } _isTransaction = false; } // DB2Query::commit //------------------------------------------------------------------------------ // DB2Query::rollback //------------------------------------------------------------------------------ void DB2Query::rollback() { // Make sure a transaction is active if (!_isTransaction) throw TransactionError("rollback(): " "A transaction is not active. Create a transaction before calling rollback."); // Roolback the transaction SQLRETURN cliRC; cliRC = SQLEndTran(SQL_HANDLE_DBC, _parentConnection->_handles[_index]->_hdbc, SQL_ROLLBACK); // Check if an error occured while rolling back if (cliRC != SQL_SUCCESS) { SQLCHAR sqlState[10]; SQLINTEGER sqlCode; SQLCHAR message[255]; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_DBC, _parentConnection->_handles[_index]->_hdbc, 1, sqlState, &sqlCode, message, 250, &length); string err = "rollback(): "; err += (const char*)message; throw TransactionError(err); } _isTransaction = false; } // DB2Query::rollback //------------------------------------------------------------------------------ // DB2Query::getFieldInfoByColumn //------------------------------------------------------------------------------ BaseFieldDescription* DB2Query::getFieldInfoByColumn( int index) { // Make sure the index is in range. if (index < 0 || index >= _numFieldInformation) throw IndexOutOfRange("getFieldInfoByColumn(): The field index is out of range for the current result set"); return _fieldInformation[index]; } // DB2Query::getFieldInfoByColumn //------------------------------------------------------------------------------ // DB2Query::getFieldInfoByName //------------------------------------------------------------------------------ BaseFieldDescription* DB2Query::getFieldInfoByName( const string& fieldName) { // Try and find the field name for (int i=0; i<_numFieldInformation; i++) if (strcasecmp(_fieldInformation[i]->name().c_str(), fieldName.c_str()) == 0) return _fieldInformation[i]; throw NameNotFound("getFieldInfoByName(): The field name was not found for the current result set."); } // DB2Query::getFieldInfoByName //------------------------------------------------------------------------------ // DB2Query::getFieldByColumn //------------------------------------------------------------------------------ BaseValue* DB2Query::getFieldByColumn( int index) { // Make sure the index is in range. if (index < 0 || index >= _numRecordValues) { throw IndexOutOfRange("getFieldByColumn(): The field index is out of range for the current result set"); } return _recordValues[index]; } // DB2Query::getFieldByColumn //------------------------------------------------------------------------------ // DB2Query::getFieldByName //------------------------------------------------------------------------------ BaseValue* DB2Query::getFieldByName( const string& fieldName) { // Try and find the field name for (int i=0; i<_numRecordValues; i++) if (strcasecmp(_recordValues[i]->name().c_str(), fieldName.c_str()) == 0) return _recordValues[i]; throw NameNotFound("getFieldByName(): The field name was not found for the current result set."); } // DB2Query::getFieldByName