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

FirebirdResultSet.cpp

Go to the documentation of this file.
00001 #include "../include/FirebirdResultSet.h"
00002 #include "../include/FirebirdResultSetMetaData.h"
00003 #include "../include/FirebirdDatabaseLayer.h"
00004 #include "../include/DatabaseErrorCodes.h"
00005 #include "../include/DatabaseLayerException.h"
00006 
00007 FirebirdResultSet::FirebirdResultSet()
00008  : DatabaseResultSet()
00009 {
00010   m_pDatabase = NULL;
00011   m_pTransaction = NULL;
00012   m_pStatement = NULL;
00013   m_pFields = NULL;
00014   m_bManageStatement = false;
00015   m_bManageTransaction = false;
00016 }
00017 
00018 //FirebirdResultSet::FirebirdResultSet(const IBPP::Statement& statement)
00019 FirebirdResultSet::FirebirdResultSet(isc_db_handle pDatabase, isc_tr_handle pTransaction, isc_stmt_handle pStatement, XSQLDA* pFields, bool bManageStmt /*= false*/, bool bManageTrans /*= false*/)
00020  : DatabaseResultSet()
00021 {
00022   m_pDatabase = pDatabase;
00023   m_pTransaction = pTransaction;
00024   m_pStatement = pStatement;
00025   m_pFields = pFields;
00026   m_bManageStatement = bManageStmt;
00027   m_bManageTransaction = bManageTrans;
00028 
00029   AllocateFieldSpace();
00030   PopulateFieldLookupMap();
00031 }
00032 
00033 FirebirdResultSet::~FirebirdResultSet()
00034 {
00035   Close();
00036 }
00037 
00038 bool FirebirdResultSet::Next()
00039 {
00040   ResetErrorCodes();
00041   
00042   int nReturn = isc_dsql_fetch(m_Status, &m_pStatement, 1, m_pFields);
00043   if (nReturn == 0) // No errors and retrieval successful
00044   {
00045     return true;
00046   }
00047   else if (nReturn == 100L) // No errors and no more rows
00048   {
00049     return false;
00050   }
00051   else  // Errors!!!
00052   {
00053     wxLogError(_("Error retrieving Next record\n"));
00054     InterpretErrorCodes();
00055     ThrowDatabaseException();
00056     return false;
00057   }
00058 }
00059 
00060 void FirebirdResultSet::Close()
00061 {
00062   CloseMetaData();
00063 
00064   if (m_bManageTransaction && m_pTransaction)
00065   {
00066     int nReturn = isc_commit_transaction(m_Status, &m_pTransaction);
00067     // 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
00068     m_pTransaction = NULL;
00069     if (nReturn != 0)
00070     {
00071       InterpretErrorCodes();
00072       ThrowDatabaseException();
00073     }
00074   }
00075   
00076   // Delete the statement if we have ownership of it
00077   if (m_bManageStatement && m_pStatement)
00078   {
00079     int nReturn = isc_dsql_free_statement(m_Status, &m_pStatement, DSQL_drop);
00080     m_pStatement = NULL;
00081     if (nReturn != 0)
00082     {
00083       InterpretErrorCodes();
00084       ThrowDatabaseException();
00085     }
00086   }
00087   
00088   // Free the output fields structure
00089   if (m_pFields)
00090   {
00091     FreeFieldSpace();
00092     free(m_pFields);
00093     m_pFields = NULL;
00094   }
00095 }
00096 
00097 
00098 // get field
00099 int FirebirdResultSet::GetResultInt(int nField)
00100 {
00101   ResetErrorCodes();
00102   
00103   // Don't use nField-1 here since GetResultString will take care of that
00104   return GetResultLong(nField);
00105 }
00106 
00107 wxString FirebirdResultSet::GetResultString(int nField)
00108 {
00109   ResetErrorCodes();
00110   
00111   wxString strReturn = wxEmptyString;
00112   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00113   if (IsNull(pVar))
00114   {
00115     // The column is NULL
00116     strReturn = wxEmptyString;
00117   }
00118   else
00119   {
00120     short nType = pVar->sqltype & ~1;
00121     if (nType == SQL_TEXT)
00122     {
00123       strReturn = ConvertFromUnicodeStream(pVar->sqldata);
00124     }
00125     else if (nType == SQL_VARYING)
00126     {
00127       struct vary* pVary = (struct vary*) pVar->sqldata;
00128       pVary->vary_string[pVary->vary_length] = '\0';
00129       strReturn = ConvertFromUnicodeStream(pVary->vary_string);
00130     }
00131     else
00132     {
00133       // Incompatible field type
00134       // Set error codes and throw an exception here
00135       strReturn = _("");
00136 
00137       SetErrorMessage(_("Invalid field type"));
00138       SetErrorCode(DATABASE_LAYER_INCOMPATIBLE_FIELD_TYPE);
00139 
00140       ThrowDatabaseException();
00141     }
00142   }
00143 
00144   return strReturn;
00145 }
00146 
00147 long FirebirdResultSet::GetResultLong(int nField)
00148 {
00149   ResetErrorCodes();
00150   
00151   long nReturn = 0L;
00152   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00153   if (IsNull(pVar))
00154   {
00155     // The column is NULL
00156     nReturn = 0;
00157   }
00158   else
00159   {
00160     short nType = pVar->sqltype & ~1;
00161     if (nType == SQL_SHORT)
00162     {
00163       nReturn = *((short*)pVar->sqldata);
00164     }
00165     else if (nType == SQL_LONG)
00166     {
00167       nReturn = *((long*)pVar->sqldata);
00168     }
00169     else if (nType == SQL_INT64)
00170     {
00171       nReturn = *((ISC_INT64*)pVar->sqldata);
00172     }
00173     else
00174     {
00175       // Incompatible field type
00176       // We should really set error codes and throw an exception here
00177       nReturn = 0;
00178 
00179       SetErrorMessage(_("Invalid field type"));
00180       SetErrorCode(DATABASE_LAYER_INCOMPATIBLE_FIELD_TYPE);
00181 
00182       ThrowDatabaseException();
00183     }
00184 
00185     // Apply the scale to the value
00186     if (nReturn != 0)
00187     {
00188       short nScale = pVar->sqlscale;
00189       if (nScale > 0) // Multiply by 10
00190       {
00191         int nMultiplier = nScale * 10;
00192         nReturn *= nMultiplier;
00193       }
00194       else if (nScale < 0)  // Divide by 10
00195       {
00196         int nMultiplier = abs(nScale) * 10;
00197         nReturn /= nMultiplier;
00198       }
00199     }
00200   }
00201 
00202   return nReturn;
00203 }
00204 
00205 bool FirebirdResultSet::GetResultBool(int nField)
00206 {
00207   ResetErrorCodes();
00208   
00209   // Don't use nField-1 here since GetResultString will take care of that
00210   int nValue = GetResultLong(nField);
00211   return (nValue != 0);
00212 }
00213 
00214 wxDateTime FirebirdResultSet::GetResultDate(int nField)
00215 {
00216   ResetErrorCodes();
00217   
00218   wxDateTime dateReturn = wxInvalidDateTime;
00219   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00220   if (IsNull(pVar))
00221   {
00222     // The column is NULL
00223     dateReturn = wxInvalidDateTime;
00224   }
00225   else
00226   {
00227     short nType = pVar->sqltype & ~1;
00228     if (nType == SQL_TIMESTAMP)
00229     {
00230       struct tm timeInTm;
00231                   isc_decode_timestamp((ISC_TIMESTAMP *)pVar->sqldata, &timeInTm);
00232       SetDateTimeFromTm(dateReturn, timeInTm);
00233     }
00234     else if (nType == SQL_TYPE_DATE)
00235     {
00236       struct tm timeInTm;
00237                   isc_decode_sql_date((ISC_DATE *)pVar->sqldata, &timeInTm);
00238       SetDateTimeFromTm(dateReturn, timeInTm);
00239     }
00240     else if (nType == SQL_TYPE_TIME)
00241     {
00242       struct tm timeInTm;
00243                   isc_decode_sql_time((ISC_TIME *)pVar->sqldata, &timeInTm);
00244       SetDateTimeFromTm(dateReturn, timeInTm);
00245     }
00246     else
00247     {
00248       // Incompatible field type
00249       // Set error codes and throw an exception here
00250       dateReturn = wxInvalidDateTime;
00251 
00252       SetErrorMessage(_("Invalid field type"));
00253       SetErrorCode(DATABASE_LAYER_INCOMPATIBLE_FIELD_TYPE);
00254 
00255       ThrowDatabaseException();
00256     }
00257   }
00258 
00259   return dateReturn;
00260 }
00261 
00262 void FirebirdResultSet::SetDateTimeFromTm(wxDateTime& dateReturn, struct tm& timeInTm)
00263 {
00264   // First try to set the return date via the struct tm directory
00265   dateReturn.Set(timeInTm);
00266   // If that doesn't work then use the individual pieces of the struct tm to set the return date
00267   if (dateReturn == wxInvalidDateTime)
00268     dateReturn.Set(timeInTm.tm_mday, wxDateTime::Month(timeInTm.tm_mon), timeInTm.tm_year, timeInTm.tm_hour, timeInTm.tm_min, timeInTm.tm_sec);
00269 }
00270 
00271 double FirebirdResultSet::GetResultDouble(int nField)
00272 {
00273   double dblReturn = 0.00;
00274   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00275   if (IsNull(pVar))
00276   {
00277     // The column is NULL
00278     dblReturn = 0.00;
00279   }
00280   else
00281   {
00282     short nType = pVar->sqltype & ~1;
00283     if (nType == SQL_FLOAT)
00284     {
00285       dblReturn = *(float *) (pVar->sqldata);
00286     }
00287     else if (nType == SQL_DOUBLE)
00288     {
00289                   dblReturn = *(double *) (pVar->sqldata);
00290     }
00291     else
00292     {
00293       // Incompatible field type
00294       // Set error codes and throw an exception here
00295       dblReturn = 0.00;
00296         
00297       SetErrorMessage(_("Invalid field type"));
00298       SetErrorCode(DATABASE_LAYER_INCOMPATIBLE_FIELD_TYPE);
00299 
00300       ThrowDatabaseException();
00301     }
00302   }
00303 
00304   return dblReturn;
00305 }
00306 
00307 void* FirebirdResultSet::GetResultBlob(int nField, wxMemoryBuffer& Buffer)
00308 {
00309   ResetErrorCodes();
00310   
00311   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00312   if (IsNull(pVar))
00313   {
00314     // The column is NULL
00315     Buffer.SetDataLen(0);
00316     return NULL;
00317   }
00318   else
00319   {
00320     short nType = pVar->sqltype & ~1;
00321     if (nType == SQL_BLOB)
00322     {
00323       ISC_QUAD blobId = *(ISC_QUAD *) pVar->sqldata;
00324       isc_blob_handle pBlob = NULL;
00325       char szSegment[128];
00326       unsigned short nSegmentLength;
00327       isc_open_blob2(m_Status, &m_pDatabase, &m_pTransaction, &pBlob, &blobId, 0, NULL);
00328 
00329       ISC_STATUS blobStatus = isc_get_segment(m_Status, &pBlob, &nSegmentLength, sizeof(szSegment), szSegment);
00330       while (blobStatus == 0 || m_Status[1] == isc_segment)
00331       {
00332         Buffer.AppendData(szSegment, nSegmentLength);
00333         blobStatus = isc_get_segment(m_Status, &pBlob, &nSegmentLength, sizeof(szSegment), szSegment);
00334       }
00335       isc_close_blob(m_Status, &pBlob);
00336     }
00337     else
00338     {
00339       // Incompatible field type
00340       // Set error codes and throw an exception here
00341       Buffer.SetDataLen(0);
00342 
00343       SetErrorMessage(_("Invalid field type"));
00344       SetErrorCode(DATABASE_LAYER_INCOMPATIBLE_FIELD_TYPE);
00345 
00346       ThrowDatabaseException();
00347     }
00348   }
00349 
00350   return Buffer.GetData();
00351 }
00352 
00353 bool FirebirdResultSet::IsFieldNull(int nField)
00354 {
00355   XSQLVAR* pVar = &(m_pFields->sqlvar[nField-1]);
00356   return IsNull(pVar);
00357 }
00358 
00359 bool FirebirdResultSet::IsNull(XSQLVAR* pVar)
00360 {
00361   return ((pVar->sqltype & 1) && (*pVar->sqlind < 0));
00362 }
00363 
00364 /*
00365 FirebirdResultSet& FirebirdResultSet::operator=(const IBPP::Statement& statement)
00366 {
00367   m_ResultSet = statement;
00368   return *this;
00369 }
00370 */
00371 void FirebirdResultSet::AllocateFieldSpace()
00372 {
00373   if (m_pFields == NULL)
00374     return;
00375 
00376   for (int i = 0; i < m_pFields->sqld; i++)
00377   {
00378     XSQLVAR* pVar = &(m_pFields->sqlvar[i]);
00379     switch (pVar->sqltype & ~1)
00380     {
00381       case SQL_ARRAY:
00382       case SQL_BLOB:
00383         pVar->sqldata = (char*)new ISC_QUAD;
00384         memset(pVar->sqldata, 0, sizeof(ISC_QUAD));
00385         break;
00386       case SQL_TIMESTAMP:
00387         pVar->sqldata = (char*)new ISC_TIMESTAMP;
00388         memset(pVar->sqldata, 0, sizeof(ISC_TIMESTAMP));
00389         break;
00390       case SQL_TYPE_TIME:
00391         pVar->sqldata = (char*)new ISC_TIME;
00392         memset(pVar->sqldata, 0, sizeof(ISC_TIME));
00393         break;
00394       case SQL_TYPE_DATE:
00395         pVar->sqldata = (char*)new ISC_DATE;
00396         memset(pVar->sqldata, 0, sizeof(ISC_DATE));
00397         break;
00398       case SQL_TEXT:
00399         pVar->sqldata = new char[pVar->sqllen+1];
00400         memset(pVar->sqldata, '\0', pVar->sqllen);
00401         pVar->sqldata[pVar->sqllen] = '\0';
00402         break;
00403       case SQL_VARYING:
00404         pVar->sqldata = new char[pVar->sqllen+3];
00405         memset(pVar->sqldata, 0, 2);
00406         memset(pVar->sqldata+2, '\0', pVar->sqllen);
00407         pVar->sqldata[pVar->sqllen+2] = '\0';
00408         break;
00409       case SQL_SHORT:
00410         pVar->sqldata = (char*)new short(0);
00411         break;
00412       case SQL_LONG:
00413         pVar->sqldata = (char*)new long(0);
00414         break;
00415       case SQL_INT64:
00416         pVar->sqldata = (char*)new ISC_INT64(0);
00417         break;
00418       case SQL_FLOAT:
00419         pVar->sqldata = (char*)new float(0.0);
00420         break;
00421       case SQL_DOUBLE:
00422         pVar->sqldata = (char*)new double(0.0);
00423         break;
00424       default : 
00425         break;
00426     }
00427     if (pVar->sqltype & 1)
00428       pVar->sqlind = new short(-1);     // 0 indicator
00429   }
00430 }
00431 
00432 void FirebirdResultSet::FreeFieldSpace()
00433 {
00434         if (m_pFields == NULL)
00435     return;
00436 
00437   for (int i = 0; i < m_pFields->sqln; i++)
00438   {
00439     XSQLVAR* pVar = &(m_pFields->sqlvar[i]);
00440     if (pVar->sqldata != 0)
00441     {
00442       switch (pVar->sqltype & ~1)
00443       {
00444         case SQL_ARRAY:
00445         case SQL_BLOB:
00446           wxDELETE(pVar->sqldata);
00447           break;
00448         case SQL_TIMESTAMP:
00449           wxDELETE(pVar->sqldata);
00450           break;
00451         case SQL_TYPE_TIME:
00452           wxDELETE(pVar->sqldata);
00453           break;
00454         case SQL_TYPE_DATE:
00455           wxDELETE(pVar->sqldata);
00456           break;
00457         case SQL_TEXT:
00458         case SQL_VARYING:
00459           wxDELETEA(pVar->sqldata);
00460           break;
00461         case SQL_SHORT:
00462           wxDELETE(pVar->sqldata);
00463           break;
00464         case SQL_LONG:
00465           wxDELETE(pVar->sqldata);
00466           break;
00467         case SQL_INT64:
00468           wxDELETE(pVar->sqldata);
00469           break;
00470         case SQL_FLOAT:
00471           wxDELETE(pVar->sqldata);
00472           break;
00473         case SQL_DOUBLE:
00474           wxDELETE(pVar->sqldata);
00475           break;
00476         default:
00477           break;
00478       }
00479     }
00480     if ((pVar->sqltype & 1) && (pVar->sqlind != 0))
00481       delete pVar->sqlind;
00482   }
00483 
00484   //delete [] (char*)m_pFields;
00485   //m_pFields = NULL;
00486   wxDELETEA(m_pFields);
00487 }
00488 
00489 void FirebirdResultSet::PopulateFieldLookupMap()
00490 {
00491   m_FieldLookupMap.clear();
00492 
00493   // Iterate through all the XSQLVAR structures mapping their aliasname fields to their positions in the XSQLDA->sqlvar array
00494   XSQLVAR* pVar = m_pFields->sqlvar;
00495   for (int i=0; i<m_pFields->sqld; i++, pVar++)
00496   {
00497     wxString strField = ConvertFromUnicodeStream(pVar->aliasname);
00498     m_FieldLookupMap[strField] = i;
00499   }
00500 }
00501 
00502 int FirebirdResultSet::LookupField(const wxString& strField)
00503 {
00504   wxString strUpperCaseCopy = strField;
00505   strUpperCaseCopy.MakeUpper();
00506   StringToIntMap::iterator SearchIterator = m_FieldLookupMap.find(strUpperCaseCopy);
00507   if (SearchIterator == m_FieldLookupMap.end())
00508   {
00509     wxString msg(_("Field '") + strField + _("' not found in the resultset"));
00510 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00511     DatabaseLayerException error(DATABASE_LAYER_FIELD_NOT_IN_RESULTSET, msg);
00512     throw error;
00513 #else
00514     wxLogError(msg);
00515 #endif
00516     return -1;
00517   }
00518   else
00519   {
00520     return ((*SearchIterator).second+1); // Add +1 to make the result set 1-based rather than 0-based
00521   }
00522 }
00523 
00524 void FirebirdResultSet::InterpretErrorCodes()
00525 {
00526   wxLogError(_("FirebirdResultSet::InterpretErrorCodes()\n"));
00527 
00528   long nSqlCode = isc_sqlcode(m_Status);
00529   SetErrorCode(FirebirdDatabaseLayer::TranslateErrorCode(nSqlCode));
00530   SetErrorMessage(FirebirdDatabaseLayer::TranslateErrorCodeToString(nSqlCode, m_Status));
00531 }
00532 
00533 ResultSetMetaData* FirebirdResultSet::GetMetaData()
00534 {
00535   ResultSetMetaData* pMetaData = new FirebirdResultSetMetaData(m_pFields);
00536   LogMetaDataForCleanup(pMetaData);
00537   return pMetaData;
00538 }
00539 
00540 

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