TDbiInRowStream.cxx

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

Generated on 11 Aug 2013 for SKDatabase by  doxygen 1.6.1