Main Page | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

FirebirdPreparedStatement.cpp

Go to the documentation of this file.
00001 #include "../include/FirebirdPreparedStatement.h"
00002 #include "../include/FirebirdDatabaseLayer.h"
00003 #include "../include/DatabaseErrorCodes.h"
00004 #include "../include/DatabaseLayerException.h"
00005 
00006 #include <wx/tokenzr.h>
00007 
00008 // ctor()
00009 FirebirdPreparedStatement::FirebirdPreparedStatement(isc_db_handle pDatabase, isc_tr_handle pTransaction)
00010  : PreparedStatement()
00011 {
00012   m_bManageTransaction = false;
00013   m_pTransaction = pTransaction;
00014   m_pDatabase = pDatabase;
00015 }
00016 /*
00017 FirebirdPreparedStatement::FirebirdPreparedStatement(FirebirdPreparedStatementWrapper Statement)
00018 {
00019   SetErrorCode(DATABASE_LAYER_OK);
00020   SetErrorMessage(_(""));
00021   
00022   m_Statements.push_back(Statement);
00023 }
00024 */
00025 FirebirdPreparedStatement::~FirebirdPreparedStatement()
00026 {
00027   Close();
00028 }
00029 
00030 void FirebirdPreparedStatement::Close()
00031 {
00032   CloseResultSets();
00033 
00034   FirebirdStatementVector::iterator start = m_Statements.begin();
00035   FirebirdStatementVector::iterator stop = m_Statements.end();
00036 
00037   while (start != stop)
00038   {
00039     wxDELETE((*start));
00040     start++;
00041   }
00042 
00043   // Close the transaction if we're in charge of it
00044   if (m_bManageTransaction && m_pTransaction)
00045   {
00046     int nReturn = isc_commit_transaction(m_Status, &m_pTransaction);
00047     m_pTransaction = NULL;
00048     if (nReturn != 0)
00049     {
00050       InterpretErrorCodes();
00051       ThrowDatabaseException();
00052     }
00053   }
00054 }
00055   
00056 void FirebirdPreparedStatement::AddPreparedStatement(const wxString& strSQL)
00057 {
00058   FirebirdPreparedStatementWrapper* pWrapper = new FirebirdPreparedStatementWrapper(m_pDatabase, m_pTransaction, strSQL);
00059   pWrapper->SetEncoding(GetEncoding());
00060   m_Statements.push_back(pWrapper);
00061 }
00062 
00063 FirebirdPreparedStatement* FirebirdPreparedStatement::CreateStatement(isc_db_handle pDatabase, isc_tr_handle pTransaction, const wxString& strSQL, const wxCSConv* conv)
00064 {
00065   wxArrayString Queries = ParseQueries(strSQL);
00066 
00067   wxArrayString::iterator start = Queries.begin();
00068   wxArrayString::iterator stop = Queries.end();
00069 
00070   FirebirdPreparedStatement *pStatement = NULL;
00071 
00072   if (Queries.size() < 1)
00073   {
00074     pStatement = new FirebirdPreparedStatement(pDatabase, pTransaction);
00075     pStatement->SetEncoding(conv);
00076 
00077     pStatement->SetErrorCode(DATABASE_LAYER_ERROR);
00078     pStatement->SetErrorMessage(_("No SQL Statements found"));
00079 
00080 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00081     // If we're using exceptions, then assume that the calling program won't
00082     //  won't get the pStatement pointer back.  So delete is now before
00083     //  throwing the exception
00084     try
00085     {
00086       delete pStatement; //It's probably better to manually iterate over the list and close the statements, but for now just let close do it
00087     }
00088     catch (DatabaseLayerException& e)
00089     {
00090     }
00091 
00092     DatabaseLayerException error(pStatement->GetErrorCode(), pStatement->GetErrorMessage());
00093     throw error;
00094 #endif
00095     return pStatement;
00096   }
00097   
00098   
00099   // Start a new transaction if appropriate
00100   if (pTransaction == NULL)
00101   {
00102     pTransaction = 0L;
00103     ISC_STATUS_ARRAY status;
00104     int nReturn = isc_start_transaction(status, &pTransaction, 1, &pDatabase, 0 /*tpb_length*/, NULL/*tpb*/);
00105     pStatement = new FirebirdPreparedStatement(pDatabase, pTransaction);
00106     pStatement->SetEncoding(conv);
00107     if (nReturn != 0)
00108     {
00109       long nSqlCode = isc_sqlcode(status);
00110       pStatement->SetErrorCode(FirebirdDatabaseLayer::TranslateErrorCode(nSqlCode));
00111       pStatement->SetErrorMessage(FirebirdDatabaseLayer::TranslateErrorCodeToString(nSqlCode, status));
00112 
00113 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00114       // If we're using exceptions, then assume that the calling program won't
00115       //  won't get the pStatement pointer back.  So delete is now before
00116       //  throwing the exception
00117       try
00118       {
00119         delete pStatement; //It's probably better to manually iterate over the list and close the statements, but for now just let close do it
00120       }
00121       catch (DatabaseLayerException& e)
00122       {
00123       }
00124 
00125       DatabaseLayerException error(pStatement->GetErrorCode(), pStatement->GetErrorMessage());
00126       throw error;
00127 #endif
00128       return pStatement;
00129     }
00130     
00131     pStatement->SetManageTransaction(true);
00132   }
00133   else
00134   {
00135     pStatement = new FirebirdPreparedStatement(pDatabase, pTransaction);
00136     pStatement->SetEncoding(conv);
00137     pStatement->SetManageTransaction(false);
00138   }
00139 
00140   while (start != stop)
00141   {
00142     pStatement->AddPreparedStatement((*start));
00143     if (pStatement->GetErrorCode() != DATABASE_LAYER_OK)
00144     {
00145       // If we're using exceptions, then assume that the calling program won't
00146       //  won't get the pStatement pointer back.  So delete is now before
00147       //  throwing the exception
00148 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00149       // Set the error code and message
00150       DatabaseLayerException error(pStatement->GetErrorCode(), pStatement->GetErrorMessage());
00151  
00152       try
00153       {
00154         delete pStatement; //It's probably better to manually iterate over the list and close the statements, but for now just let close do it
00155       }
00156       catch (DatabaseLayerException& e)
00157       {
00158       }
00159 
00160       // Pass on the error
00161       throw error;
00162 #endif
00163 
00164       return pStatement;
00165     }
00166     start++;
00167   }
00168     
00169   // Success?  Return the statement
00170   return pStatement;
00171 }
00172 
00173 // get field
00174 void FirebirdPreparedStatement::SetParamInt(int nPosition, int nValue)
00175 {
00176   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00177   if (nIndex > -1)
00178     m_Statements[nIndex]->SetParam(nPosition, nValue);
00179   else
00180     SetInvalidParameterPositionError(nPosition);
00181 }
00182 
00183 void FirebirdPreparedStatement::SetParamDouble(int nPosition, double dblValue)
00184 {
00185   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00186   if (nIndex > -1)
00187     m_Statements[nIndex]->SetParam(nPosition, dblValue);
00188   else
00189     SetInvalidParameterPositionError(nPosition);
00190 }
00191 
00192 void FirebirdPreparedStatement::SetParamString(int nPosition, const wxString& strValue)
00193 {
00194   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00195   if (nIndex > -1)
00196     m_Statements[nIndex]->SetParam(nPosition, strValue);
00197   else
00198     SetInvalidParameterPositionError(nPosition);
00199 }
00200 
00201 void FirebirdPreparedStatement::SetParamNull(int nPosition)
00202 {
00203   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00204   if (nIndex > -1)
00205     m_Statements[nIndex]->SetParam(nPosition);
00206   else
00207     SetInvalidParameterPositionError(nPosition);
00208 }
00209 
00210 void FirebirdPreparedStatement::SetParamBlob(int nPosition, const void* pData, long nDataLength)
00211 {
00212   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00213   if (nIndex > -1)
00214     m_Statements[nIndex]->SetParam(nPosition, pData, nDataLength);
00215   else
00216     SetInvalidParameterPositionError(nPosition);
00217 }
00218 
00219 void FirebirdPreparedStatement::SetParamDate(int nPosition, const wxDateTime& dateValue)
00220 {
00221   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00222   if (nIndex > -1)
00223     m_Statements[nIndex]->SetParam(nPosition, dateValue);
00224   else
00225     SetInvalidParameterPositionError(nPosition);
00226 }
00227 
00228 void FirebirdPreparedStatement::SetParamBool(int nPosition, bool bValue)
00229 {
00230   int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
00231   if (nIndex > -1)
00232     m_Statements[nIndex]->SetParam(nPosition, bValue);
00233   else
00234     SetInvalidParameterPositionError(nPosition);
00235 }
00236 
00237 int FirebirdPreparedStatement::GetParameterCount()
00238 {
00239   FirebirdStatementVector::iterator start = m_Statements.begin();
00240   FirebirdStatementVector::iterator stop = m_Statements.end();
00241 
00242   int nParameters = 0;
00243   while (start != stop)
00244   {
00245     nParameters += (*start)->GetParameterCount();
00246     start++;
00247   }
00248   return nParameters;
00249 }
00250   
00251 void FirebirdPreparedStatement::RunQuery()
00252 {
00253   FirebirdStatementVector::iterator start = m_Statements.begin();
00254   FirebirdStatementVector::iterator stop = m_Statements.end();
00255 
00256   while (start != stop)
00257   {
00258     (*start)->RunQuery();
00259     if ((*start)->GetErrorCode() != DATABASE_LAYER_OK)
00260     {
00261       SetErrorCode((*start)->GetErrorCode());
00262       SetErrorMessage((*start)->GetErrorMessage());
00263       return;
00264     }
00265     
00266     start++;
00267   }
00268 
00269   // If the statement is managing the transaction then commit it now
00270   if (m_bManageTransaction)
00271   {
00272     int nReturn = isc_commit_retaining(m_Status, &m_pTransaction);
00273     //int nReturn = isc_commit_transaction(m_Status, &m_pTransaction);
00274     // We're done with the transaction, so set it to NULL so that we know that a new transaction must be started if we run any queries
00275     if (nReturn != 0)
00276     {
00277       InterpretErrorCodes();
00278       ThrowDatabaseException();
00279     }
00280   }
00281 }
00282 
00283 DatabaseResultSet* FirebirdPreparedStatement::RunQueryWithResults()
00284 {
00285   if (m_Statements.size() > 0)
00286   {
00287     // Assume that only the last statement in the array returns the result set
00288     for (unsigned int i=0; i<m_Statements.size()-1; i++)
00289     {
00290       m_Statements[i]->RunQuery();
00291       if (m_Statements[i]->GetErrorCode() != DATABASE_LAYER_OK)
00292       {
00293         SetErrorCode(m_Statements[i]->GetErrorCode());
00294         SetErrorMessage(m_Statements[i]->GetErrorMessage());
00295         return NULL;
00296       }
00297     }
00298 
00299     FirebirdPreparedStatementWrapper* pLastStatement = m_Statements[m_Statements.size()-1];
00300     // If the statement is managing the transaction then commit it now
00301     if (m_bManageTransaction)
00302     {
00303       //int nReturn = isc_commit_retaining(m_Status, &m_pTransaction);
00304       int nReturn = isc_commit_transaction(m_Status, &m_pTransaction);
00305       // We're done with the transaction, so set it to NULL so that we know that a new transaction must be started if we run any queries
00306       if (nReturn != 0)
00307       {
00308         InterpretErrorCodes();
00309         ThrowDatabaseException();
00310       }
00311       
00312       // Start a new transaction
00313       nReturn = isc_start_transaction(m_Status, &m_pTransaction, 1, &m_pDatabase, 0 /*tpb_length*/, NULL/*tpb*/);
00314       if (nReturn != 0)
00315       {
00316         InterpretErrorCodes();
00317         ThrowDatabaseException();
00318         return NULL;
00319       }
00320 
00321       // Make sure to update the last statements pointer to the transaction
00322       pLastStatement->SetTransaction(m_pTransaction);
00323     }
00324 
00325     // The result set will be in charge of the result set now so change flag so that we don't try to close the transaction when the statement closes
00326     //m_bManageTransaction = false;
00327 
00328     DatabaseResultSet* pResultSet = pLastStatement->RunQueryWithResults();
00329     if (pResultSet)
00330       pResultSet->SetEncoding(GetEncoding());
00331     if (pLastStatement->GetErrorCode() != DATABASE_LAYER_OK)
00332     {
00333       SetErrorCode(pLastStatement->GetErrorCode());
00334       SetErrorMessage(pLastStatement->GetErrorMessage());
00335       
00336       // Wrap the result set deletion in try/catch block if using exceptions.
00337       //We want to make sure the original error gets to the user
00338 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00339       try
00340       {
00341 #endif
00342       if (pResultSet)
00343         delete pResultSet;
00344 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00345       }
00346       catch (DatabaseLayerException& e)
00347       {
00348       }
00349 #endif
00350 
00351       return NULL;
00352     }
00353 
00354     LogResultSetForCleanup(pResultSet);
00355     return pResultSet;
00356   }
00357   else
00358     return NULL;
00359 }
00360 
00361 int FirebirdPreparedStatement::FindStatementAndAdjustPositionIndex(int* pPosition)
00362 {
00363   // Don't mess around if there's just one entry in the vector
00364   if (m_Statements.size() <= 1)
00365     return 0;
00366     
00367   // Go through all the elements in the vector
00368   // Get the number of parameters in each statement
00369   // Adjust the nPosition for the the broken up statements
00370   for (unsigned int i=0; i<m_Statements.size(); i++)
00371   {
00372     int nParametersInThisStatement = 0;
00373     nParametersInThisStatement = m_Statements[i]->GetParameterCount();
00374     if (*pPosition > nParametersInThisStatement)
00375     {
00376       *pPosition -= nParametersInThisStatement;    // Decrement the position indicator by the number of parameters in this statement
00377     }
00378     else
00379     {
00380       // We're in the correct statement, return the index
00381       return i;
00382     }
00383   }
00384   return -1;
00385 }
00386 
00387 void FirebirdPreparedStatement::SetInvalidParameterPositionError(int nPosition)
00388 {
00389   SetErrorCode(DATABASE_LAYER_ERROR);
00390   SetErrorMessage(_("Invalid Prepared Statement Parameter"));
00391 
00392   ThrowDatabaseException();
00393 }
00394 
00395 void FirebirdPreparedStatement::InterpretErrorCodes()
00396 {
00397   wxLogError(_("FirebirdPreparesStatement::InterpretErrorCodes()\n"));
00398 
00399   long nSqlCode = isc_sqlcode(m_Status);
00400   SetErrorCode(FirebirdDatabaseLayer::TranslateErrorCode(nSqlCode));
00401   SetErrorMessage(FirebirdDatabaseLayer::TranslateErrorCodeToString(nSqlCode, m_Status));
00402 }
00403 

Generated on Sat May 13 17:31:34 2006 for databaselayer by  doxygen 1.4.1