Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

DbiResultSet.cxx

Go to the documentation of this file.
00001 
00005 
00006 #include <sstream>
00007 
00008 #include "DatabaseInterface/DbiFieldType.h"
00009 #include "DatabaseInterface/DbiResultSet.h"
00010 #include "DatabaseInterface/DbiString.h"
00011 #include "DatabaseInterface/DbiStatement.h"
00012 #include "DatabaseInterface/DbiTableMetaData.h"
00013 #include "LeakChecker/Lea.h"
00014 #include "MessageService/MsgService.h"
00015 #include "Util/UtilString.h"
00016 #include "Validity/VldTimeStamp.h"
00017 
00018 ClassImp(DbiResultSet)
00019 
00020 
00021 //   Definition of static data members
00022 //   *********************************
00023 
00024 CVSID("$Id: DbiResultSet.cxx,v 1.40 2007/07/05 11:36:05 west Exp $");
00025 
00026 //    Definition of all member functions (static or otherwise)
00027 //    *******************************************************
00028 //
00029 //    -  ordered: ctors, dtor, operators then in alphabetical order.
00030 
00031 
00032 //.....................................................................
00033 
00034 DbiResultSet::DbiResultSet(DbiStatement* stmtDb,
00035                            const DbiString& sql,
00036                            const DbiTableMetaData* metaData,
00037                            const DbiTableProxy* tableProxy,
00038                            UInt_t dbNo,
00039                            const string& fillOpts) :
00040 DbiRowStream(metaData),
00041 fCurRow(0),
00042 fDbNo(dbNo),
00043 fDbType(Dbi::kMySQL),
00044 fStatement(stmtDb),
00045 fTSQLStatement(0),
00046 fExhausted(true),
00047 fTableProxy(tableProxy),
00048 fFillOpts(fillOpts)
00049 {
00050 //
00051 //
00052 //  Purpose:  Default constructor
00053 //
00054 //  Arguments:
00055 //     stmtDb     in  DbiStatement to be used for query.  May be zero.
00056 //     sql        in  The query to be applied to the statement.
00057 //     metaData   in  Meta data for query.
00058 //     tableProxy in  Source DbiTableProxy.
00059 //     dbNo       in  Cascade no. of source.
00060 //
00061 //  Return:    n/a
00062 //
00063 //  Contact:   N. West
00064 //
00065 //  Specification:-
00066 //  =============
00067 //
00068 //  o  Create ResultSet for query.
00069 
00070 
00071 //  Program Notes:-
00072 //  =============
00073 
00074 //  None.
00075 
00076   LEA_CTOR    //Leak Checker
00077 
00078   MSG("Dbi", Msg::kVerbose) << "Creating DbiResultSet" << endl;
00079 
00080   if ( stmtDb ) { 
00081     fDbType = stmtDb->GetDBType();
00082     fTSQLStatement = stmtDb->ExecuteQuery(sql.c_str());
00083     if ( fTSQLStatement && fTSQLStatement->NextResultRow() ) fExhausted = false;
00084     stmtDb->PrintExceptions(Msg::kDebug);
00085   }
00086   
00087 }
00088 
00089 
00090 //.....................................................................
00091 
00092 DbiResultSet::~DbiResultSet() {
00093 //
00094 //
00095 //  Purpose: Destructor
00096 //
00097 //  Arguments: 
00098 //    None.
00099 //
00100 //  Return:    n/a
00101 //
00102 //  Contact:   N. West
00103 //
00104 //  Specification:-
00105 //  =============
00106 //
00107 //  o  Destroy ResultSet and owned DbiStatement if any.
00108 
00109 
00110 //  Program Notes:-
00111 //  =============
00112 
00113 //  None.
00114 
00115   LEA_DTOR    //Leak Checker
00116 
00117   MSG("Dbi", Msg::kVerbose) << "Destroying DbiResultSet" << endl;
00118   delete fTSQLStatement;
00119   fTSQLStatement = 0;
00120   delete fStatement;
00121   fStatement = 0;
00122 
00123 }
00124 
00125 //.....................................................................
00126 
00127 
00128 #define IN(t) istringstream in(AsString(t)); in  
00129 
00130 // On first row use AsString to force type checking.  
00131 // On subsequent rows use binary interface for speed.
00132 // Caution: Column numbering in TSQLStatement starts at 0.                    
00133 #define IN2(t,m)                            \
00134   int col = CurColNum()-1;                  \
00135   if ( CurRowNum() == 0 ) {                 \
00136     istringstream in(AsString(t));          \
00137     in >> dest;                             \
00138   }                                         \
00139   else {                                    \
00140     dest = fTSQLStatement->m(col);          \
00141     IncrementCurCol();                      \
00142   }                                         \
00143 
00144 // Handling reading of unsigned application data stored as signed database data. 
00145 // Both GetInt(int) and GetString(int) return the signed data correctly.
00146 // So first read into signed equivalent, then copy and finally
00147 // trim off leading extended sign bits beyond the capacity of
00148 // the database column.
00149 // For BIGINT (size 8) make an exception.  It's used only as
00150 // an alternative to unsigned int and getUInt(int) (but not GetInt(int))
00151 // returns it correctly so can load directly into destination
00152 // Caution: Column numbering in TSQLStatement starts at 0.                    
00153 #define IN3(t)                                                      \
00154 int col = this->CurColNum()-1;                                      \
00155 const DbiFieldType& fType = this->ColFieldType(col+1);              \
00156 if ( fType.GetSize() == 8 ) {                                       \
00157   dest=fTSQLStatement->GetUInt(col);                                \
00158 }                                                                   \
00159 else {                                                              \
00160   t dest_signed;                                                    \
00161   *this >> dest_signed;                                             \
00162   dest = dest_signed;                                               \
00163   if ( fType.GetSize() == 1 ) dest &= 0xff;                         \
00164   if ( fType.GetSize() == 2 ) dest &= 0xffff;                       \
00165   if ( fType.GetSize() == 4 ) dest &= 0xffffffff;                   \
00166 }\
00167 
00168 DbiResultSet& DbiResultSet::operator>>(Bool_t& dest) {
00169                                  IN(Dbi::kBool) >> dest;  return *this;}
00170 DbiResultSet& DbiResultSet::operator>>(Char_t& dest) {
00171                                  IN(Dbi::kChar) >> dest; return *this;}
00172 DbiResultSet& DbiResultSet::operator>>(Short_t& dest) {
00173                                  IN2(Dbi::kInt,GetInt);    return *this;}
00174 DbiResultSet& DbiResultSet::operator>>(UShort_t& dest) {
00175                                  IN3(Short_t); return *this;}
00176 DbiResultSet& DbiResultSet::operator>>(Int_t& dest) {
00177                                  IN2(Dbi::kInt,GetInt);      return *this;}
00178 DbiResultSet& DbiResultSet::operator>>(UInt_t& dest) {
00179                                  IN3(Int_t);  return *this;}
00180 DbiResultSet& DbiResultSet::operator>>(Long_t& dest) {
00181                                  IN2(Dbi::kLong, GetLong);   return *this;}
00182 DbiResultSet& DbiResultSet::operator>>(ULong_t& dest) {
00183                                  IN3(Long_t);  return *this;}
00184 DbiResultSet& DbiResultSet::operator>>(Float_t& dest) {
00185                                  IN2(Dbi::kFloat,GetDouble);  return *this;}
00186 DbiResultSet& DbiResultSet::operator>>(Double_t& dest) {
00187                                  IN2(Dbi::kDouble,GetDouble);return *this;}
00188 
00189 // Also use AsString() for string and VldTimeStamp; conversion to string
00190 // is needed in any case.
00191 DbiResultSet& DbiResultSet::operator>>(string& dest) {
00192                           dest = AsString(Dbi::kString);  return *this;}
00193 DbiResultSet& DbiResultSet::operator>>(VldTimeStamp& dest){
00194            dest=Dbi::MakeTimeStamp(AsString(Dbi::kDate)); return *this;}
00195 
00196 //.....................................................................
00197 
00198 string& DbiResultSet::AsString(Dbi::DataTypes type) {
00199 //
00200 //
00201 //  Purpose: Return current column value as a modifiable string and 
00202 //           move on. 
00203 //
00204 //  Arguments: 
00205 //    type         in    Required data type (as defined in Dbi.h).
00206 //
00207 //  Return:   Current column value as a string (null if missing) 
00208 //            Note: Caller must dispose of value before calling
00209 //                  this member function again as the value is
00210 //                  assembled into fValString.
00211 //
00212 //  Contact:   N. West
00213 //
00214 //  Specification:-
00215 //  =============
00216 //
00217 // o Return the datum at current (row,column) as a string and
00218 //   increment column number.
00219 //
00220 // o Check for compatibility between required data type and table
00221 //   data type, report problems and return default if incompatible.
00222 
00223 //  Program Notes:-
00224 //  =============
00225 
00226 //  None.
00227 
00228   DbiFieldType  reqdt(type);
00229 
00230 //  Place table value string in value string buffer.
00231 
00232   Bool_t fail = ! LoadCurValue();
00233 // Internally columns number from zero.
00234   UInt_t col = CurColNum();
00235   IncrementCurCol();
00236 
00237   if ( fail ) {
00238     string udef = reqdt.UndefinedValue();
00239     MAXMSG("Dbi",Msg::kError,20) 
00240        << "... value \"" << udef
00241        << "\" will be substitued." <<  endl;
00242     fValString = udef;
00243     return fValString;
00244   }
00245  
00246 //  Check for compatibility with required data type.
00247 
00248   const DbiFieldType& actdt = MetaData()->ColFieldType(col);
00249 
00250   if ( reqdt.IsCompatible(actdt) ) {
00251     Bool_t smaller = reqdt.IsSmaller(actdt);
00252 //  Allow one character String to be stored in Char
00253     if ( reqdt.GetConcept() == Dbi::kChar && fValString.size() == 1 
00254        ) smaller = kFALSE;
00255     if ( smaller  ) {
00256        MAXMSG("Dbi",Msg::kWarning,20) 
00257           << "In table " << TableNameTc() 
00258           << " row " << fCurRow 
00259           << " column "<< col 
00260           << " (" << MetaData()->ColName(col) << ")"
00261           << " value \"" << fValString
00262           << "\" of type " << actdt.AsString()
00263           << " may be truncated before storing in " << reqdt.AsString()
00264           <<  endl;
00265     }
00266   }
00267   else {
00268     string udef = reqdt.UndefinedValue();
00269     MAXMSG("Dbi",Msg::kError,20) 
00270         << "In table " << TableNameTc() 
00271          << " row " << fCurRow
00272         << " column "<< col 
00273         << " (" << MetaData()->ColName(col) << ")"
00274         << " value \"" << fValString
00275         << "\" of type " << actdt.AsString()
00276         << " is incompatible with user type " << reqdt.AsString()
00277         << ", value \"" << udef
00278         << "\" will be substituted." <<  endl;
00279     fValString = udef;
00280   }
00281 
00282   return fValString;
00283 }
00284 
00285 
00286 //.....................................................................
00287 
00288 Bool_t DbiResultSet::CurColExists() const {
00289 //
00290 //
00291 //  Purpose:  Test if current column exists.
00292 //
00293 //  Arguments: None.
00294 //
00295 //  Return:    kTRUE if column exists.
00296 //
00297 //  Contact:   N. West
00298 //
00299 //  Specification:-
00300 //  =============
00301 //
00302 //  o  Test if current column exists.
00303 
00304 //  Program Notes:-
00305 //  =============
00306 
00307 //  None.
00308 
00309   Int_t col = CurColNum();
00310 
00311   if ( IsExhausted() ) {
00312     MAXMSG("Dbi",Msg::kError,20) 
00313       << "In table " << TableNameTc() 
00314       << " attempting to access row " << fCurRow  
00315       << " column " << col 
00316       << " but only " << fCurRow << " rows in table."  << endl;
00317     return kFALSE;
00318   }
00319 
00320   int numCols = NumCols();
00321   if ( col > numCols ) {
00322     MAXMSG("Dbi",Msg::kError,20) 
00323       << "In table " << TableNameTc() 
00324       << " row " << fCurRow 
00325       << " attempting to access column "<< col 
00326       << " but only " << NumCols() << " in table ."  << endl;
00327     return kFALSE;
00328   }
00329 
00330   return kTRUE;
00331 
00332 }
00333 //.....................................................................
00334 
00335 string DbiResultSet::CurColString() const {
00336 //
00337 //
00338 //  Purpose:  Return current column as a string.
00339 //
00340 //  Arguments: None.
00341 //
00342 //  Return:   Current column as a string (or null string if non-existant).
00343 //
00344 //  Contact:   N. West
00345 //
00346 //  Specification:-
00347 //  =============
00348 //
00349 //  o Return current column as a string.
00350 
00351 //  Program Notes:-
00352 //  =============
00353 
00354 //  None.
00355 
00356   if ( ! CurColExists() ) return "";
00357 
00358   TString valStr = this->GetStringFromTSQL(CurColNum());
00359   return valStr.Data();
00360 
00361 }
00362 
00363 //.....................................................................
00364 
00365 Bool_t DbiResultSet::FetchRow() {
00366 
00367 //
00368 //
00369 //  Purpose: Fetch next row of result set.. 
00370 //
00371 //  Arguments: None.
00372 //
00373 //  Return:   kTRUE if row exists, kFALSE otherwise.
00374 //
00375 //  Contact:   N. West
00376 //
00377 //  Specification:-
00378 //  =============
00379 //
00380 //  o Load next row with string lengths.
00381 
00382 //  Program Notes:-
00383 //  =============
00384 
00385 //  None.
00386 
00387   ClearCurCol();
00388   if ( IsExhausted() ) return kFALSE;
00389   ++fCurRow;
00390   if ( ! fTSQLStatement->NextResultRow() ) fExhausted = true;
00391   return ! fExhausted;
00392 
00393 }
00394 //.....................................................................
00395 
00396 TString DbiResultSet::GetStringFromTSQL(Int_t col) const {
00397 //
00398 //
00399 //  Purpose: Get string from underlying TSQL interface 
00400 //
00401 //  N.B.  No check that col is valid - caller beware. 
00402 //
00403 //  Specification:-
00404 //  =============
00405 //
00406 //  o Get string from underlying TSQL interface converting  supported 
00407 //    binary characters for ORACLE text fields (ORACLE doesn't convert 
00408 //    external representation to binary on input).
00409 //
00410 
00411 // Caution: Column numbering in TSQLStatement starts at 0.                    
00412   TString valStr = fTSQLStatement->GetString(col-1);
00413   if (    this->GetDBType() == Dbi::kOracle
00414        && this->ColFieldType(col).GetConcept() == Dbi::kString ) {
00415     MSG("Dbi",Msg::kDebug) << "ORACLE string conversion from: " << valStr << endl;
00416     valStr.ReplaceAll("\\n", "\n");
00417     valStr.ReplaceAll("\\t", "\t");
00418     valStr.ReplaceAll("\\\'","\'");
00419     valStr.ReplaceAll("\\\"","\"");
00420     valStr.ReplaceAll("\\\\","\\");
00421     MSG("Dbi",Msg::kDebug) << "                           to: " << valStr <<endl;
00422   }
00423   return valStr;
00424 }
00425 
00426 //.....................................................................
00427 
00428 Bool_t DbiResultSet::LoadCurValue() const{
00429 //
00430 //
00431 //  Purpose:  Load current value into buffer fValString
00432 //
00433 //  Arguments: None.
00434 //
00435 //  Return:    kTRUE if current column in range, otherwise kFALSE.
00436 //
00437 //  Contact:   N. West
00438 //
00439 //  Specification:-
00440 //  =============
00441 //
00442 //  o Load current value into buffer fValString stripping off any
00443 //    enclosing quotes.
00444 
00445   
00446   fValString.clear();
00447 
00448   if ( ! CurColExists() ) return kFALSE;
00449 
00450   Int_t col = CurColNum();
00451   TString valStr = this->GetStringFromTSQL(col);
00452 
00453   // For floating point, use binary interface to preserve precision 
00454   // e.g.-1.234567890123457e-100 as string is -0.000000
00455   if ( CurColFieldType().GetConcept() == Dbi::kFloat ) {
00456     ostringstream out;
00457     out << setprecision(8);
00458     if ( CurColFieldType().GetType() == Dbi::kDouble )  out << setprecision(16);
00459 //  Caution: Column numbering in TSQLStatement starts at 0.                    
00460     out << fTSQLStatement->GetDouble(col-1);
00461     valStr = out.str().c_str();
00462   }
00463   int len = valStr.Length();
00464 
00465 
00466 
00467   const char* pVal = valStr.Data();
00468   // Remove leading and trailing quotes if dealing with a string.
00469   if (    len >= 2
00470        && ( *pVal == *(pVal+len-1) )  
00471        && ( *pVal == '\'' || *pVal == '"' ) ) {
00472     ++pVal;
00473     len -= 2;
00474   }
00475   fValString.assign(pVal,len);
00476 
00477   return kTRUE;
00478 
00479 }
00480 //.....................................................................
00481 
00482 void DbiResultSet::RowAsCsv(string& row) const {
00483 //
00484 //
00485 //  Purpose:  Append row as a Comma Separated Values string.
00486 //
00487 //  Arguments: 
00488 //    row          in    String to append to.
00489 //
00490 
00491   const DbiTableMetaData* md = this->MetaData();
00492 
00493   Int_t maxCol = this->NumCols();
00494   for (Int_t col = 1; col <= maxCol; ++col) {
00495     // Deal with NULL values.  Caution: Column numbering in TSQLStatement starts at 0.
00496     if ( fTSQLStatement->IsNull(col-1) ) {
00497       row += "NULL";
00498       if ( col < maxCol ) row += ',';
00499       continue;
00500     }
00501     Bool_t mustDelimit  = md->ColMustDelimit(col);
00502     UInt_t concept      = md->ColFieldConcept(col);
00503     if ( mustDelimit ) row += '\'';
00504     TString str = this->GetStringFromTSQL(col);
00505     const char* value = str.Data();
00506 
00507     // Make strings printable. 
00508     if ( concept == Dbi::kString ) UtilString::MakePrintable(value,row);
00509 
00510     // For floating point, use binary interface to preserve precision 
00511     // e.g.-1.234567890123457e-100 as string is -0.000000
00512     else if ( concept == Dbi::kFloat ) {
00513       ostringstream out;
00514       out << setprecision(8);
00515       if ( md->ColFieldType(col).GetType() == Dbi::kDouble ) out << setprecision(16);
00516       out << fTSQLStatement->GetDouble(col-1);
00517       row += out.str();
00518     }
00519 
00520     // Everything else (!) is O.K.
00521     else                        row += value;
00522 
00523     if ( mustDelimit ) row += '\'';
00524     if ( col < maxCol ) row += ',';
00525   }
00526 }
00527 
00528 

Generated on Mon Feb 15 11:06:34 2010 for loon by  doxygen 1.3.9.1