TDbiSqlValPacket.cxx

Go to the documentation of this file.
00001 // $Id: TDbiSqlValPacket.cxx,v 1.1 2011/01/18 05:49:20 finch Exp $
00002 
00003 #include <algorithm>
00004 #include <memory>
00005 using std::auto_ptr;
00006 #include <sstream>
00007 #include <vector>
00008 
00009 #include "TDbi.hxx"
00010 #include "TDbiCascader.hxx"
00011 #include "TDbiConfigSet.hxx"
00012 #include "TDbiOutRowStream.hxx"
00013 #include "TDbiResultSetHandle.hxx"
00014 #include "TDbiInRowStream.hxx"
00015 #include "TDbiSqlValPacket.hxx"
00016 #include "TDbiStatement.hxx"
00017 #include "TDbiTableProxy.hxx"
00018 #include "TDbiTableRow.hxx"
00019 #include "TDbiDatabaseManager.hxx"
00020 #include "TDbiValidityRec.hxx"
00021 #include "TDbiValRecSet.hxx"
00022 
00023 #include <TSK_DBI_Log.hxx>
00024 #include <MsgFormat.h>
00025 using std::endl;
00026 #include "UtilString.hxx"
00027 #include "TVldRange.hxx"
00028 
00029 ClassImp(TDbiSqlValPacket)
00030 
00031 #ifdef IRIX6
00032 // SGI barfs at generating an operator != for this enum if it
00033 // is anonymous and in the Fill() method.
00034 enum EFillState { kLOOKING_FOR_HEADER,
00035                   kLOOKING_FOR_TRAILER };
00036 #endif
00037 
00038 //   Definition of static data members
00039 //   *********************************
00040 
00041 
00042 //   Definition of file static members functions
00043 //   *******************************************
00044 
00045 static bool compStringPtrs(const string* str1, const string* str2 ) {
00046   return *str1 < *str2; }
00047 
00048 //    Definition of all member functions (static or otherwise)
00049 //    *******************************************************
00050 //
00051 //    -  ordered: ctors, dtor, operators then in alphabetical order.
00052 
00053 //.....................................................................
00054 /// Default constructor.
00055 TDbiSqlValPacket::TDbiSqlValPacket() :
00056 fNumErrors(0),
00057 fSeqNo(0),
00058 fNumStmts(0)
00059 {
00060 //
00061 //
00062 //  Purpose:  Default ctor.
00063 
00064 
00065   SK_DBI_Trace( "Creating TDbiSqlValPacket" << "  ");
00066 }
00067 
00068 //.....................................................................
00069 ///\verbatim
00070 ///
00071 ///  Purpose:  Constructor reading from input stream.
00072 ///
00073 ///  Arguments:
00074 ///      is    in/out    Input stream.
00075 ///
00076 ///  Return:   n/a.
00077 ///
00078 ///  Contact:   N. West
00079 ///
00080 ///  Specification:-
00081 ///  =============
00082 ///
00083 ///  o  Create TDbiSqlValPacket and fill from input stream by calling Fill .
00084 ///\endverbatim
00085 TDbiSqlValPacket::TDbiSqlValPacket(std::ifstream& is) :
00086 fNumErrors(0),
00087 fSeqNo(0),
00088 fNumStmts(0)
00089 {
00090 
00091 
00092 //  Program Notes:-
00093 //  =============
00094 
00095 //  None.
00096 
00097 
00098   SK_DBI_Trace( "Creating TDbiSqlValPacket" << "  ");
00099 
00100   Fill(is);
00101 
00102 }
00103 //.....................................................................
00104 ///\verbatim
00105 ///
00106 ///  Purpose:  Constructor from a TDbiValidityRec.
00107 ///
00108 ///  Arguments:
00109 ///      vrec  in   TDbiValidityRec from which to create packet.     .
00110 ///
00111 ///  Return:   n/a.
00112 ///
00113 ///  Contact:   N. West
00114 ///
00115 ///  Specification:-
00116 ///  =============
00117 ///
00118 ///  o  Create TDbiSqlValPacket from TDbiValidityRec and associated data.
00119 ///
00120 ///
00121 ///  Program Notes:-
00122 ///  =============
00123 ///
00124 ///  This member function uses TDbiConfigSet as a generic concrete
00125 ///  TDbiTableRow that can be used to create SQL for any type of table.
00126 ///\endverbatim
00127 TDbiSqlValPacket::TDbiSqlValPacket(const TDbiValidityRec& vrec) :
00128 fNumErrors(0),
00129 fSeqNo(vrec.GetSeqNo()),
00130 fNumStmts(0),
00131 fTableName(vrec.GetTableProxy()->GetTableName()),
00132 fCreationDate(vrec.GetCreationDate())
00133 {
00134 
00135 
00136   SK_DBI_Trace( "Creating TDbiSqlValPacket" << "  ");
00137 
00138   const TDbiTableProxy& tableProxy = *vrec.GetTableProxy();
00139   Int_t seqNo  = vrec.GetSeqNo();
00140   UInt_t dbNo  = vrec.GetDbNo();
00141 
00142   // Create the SQL for the TDbiValidityRec itself.
00143   this->AddRow(tableProxy,0,vrec);
00144 
00145   // Create the SQL for the rows.
00146 
00147   const TDbiDBProxy& dbProxy = tableProxy.GetDBProxy();
00148   TDbiInRowStream* rset = dbProxy.QuerySeqNo(seqNo,dbNo);
00149 
00150 
00151   for(; ! rset->IsExhausted(); rset->FetchRow()) {
00152     string str;
00153     rset->RowAsCsv(str);
00154     this->AddRow(str);
00155   }
00156   delete rset;
00157   rset = 0;
00158 }
00159 
00160 //.....................................................................
00161 
00162 TDbiSqlValPacket::~TDbiSqlValPacket() {
00163 //
00164 //
00165 //  Purpose: Destructor
00166 //
00167 //  Arguments:
00168 //    None.
00169 //
00170 //  Return:    n/a
00171 //
00172 //  Contact:   N. West
00173 //
00174 //  Specification:-
00175 //  =============
00176 //
00177 //  o  Destroy TDbiSqlValPacket.
00178 
00179 
00180 //  Program Notes:-
00181 //  =============
00182 
00183 //  None.
00184 
00185 
00186   SK_DBI_Trace( "Destroying TDbiSqlValPacket" << "  ");
00187 
00188   Clear();
00189 
00190 }
00191 
00192 //.....................................................................
00193 /// Add data row tblProxy vrec row to this object.
00194 Bool_t TDbiSqlValPacket::AddDataRow(const TDbiTableProxy& tblProxy,
00195                                    const TDbiValidityRec* vrec,
00196                                    const TDbiTableRow& row){
00197 //
00198 //
00199 //  Purpose: Add data row.
00200 //
00201 
00202   if ( this->GetNumSqlStmts() == 0 ) {
00203        SK_DBI_Severe(  "Cannot add data row - packet does not have a VLD row"  << "  ");
00204     ++fNumErrors;
00205     return kFALSE;
00206   }
00207 
00208   return this->AddRow(tblProxy,vrec,row);
00209 
00210 }
00211 
00212 //.....................................................................
00213 /// add row to sql statements
00214 void TDbiSqlValPacket::AddRow(const string & row){
00215 //
00216 //
00217 //  Purpose: Add row.
00218 //
00219 
00220   string sql("INSERT INTO ");
00221   sql += this->GetTableName();
00222   if ( this->GetNumSqlStmts() == 0 ) sql += "VLD";
00223   sql += " VALUES (" + row + ");";
00224   ostringstream seqno;
00225   seqno << this->GetSeqNo();
00226   this->SetSeqNoOnRow(sql,seqno.str());
00227   fSqlStmts.push_back(sql);
00228   ++fNumStmts;
00229 
00230 }
00231 
00232 //.....................................................................
00233 
00234 Bool_t TDbiSqlValPacket::AddRow(const TDbiTableProxy& tblProxy,
00235                                const TDbiValidityRec* vrec,
00236                                const TDbiTableRow& row){
00237 //
00238 //
00239 //  Purpose: Add row.
00240 //
00241 
00242 
00243   bool isVld = this->GetNumSqlStmts() == 0;
00244   const TDbiTableMetaData& meta = isVld ? tblProxy.GetMetaValid() : tblProxy.GetMetaData();
00245   TDbiOutRowStream outRow(&meta);
00246 
00247 // Store dummy SEQNO and ROW_COUNTER for data rows.
00248   if ( ! isVld ) {
00249     outRow << 0;          // dummy SEQNO
00250     outRow <<  fNumStmts; // ROW_COUNTER
00251   }
00252   row.Store(outRow,vrec);
00253   if ( ! outRow.HasGoodData() ) {
00254     if ( ! outRow.IsComplete() ) {
00255          SK_DBI_Severe(  "Incomplete data supplied for row " << this->GetNumSqlStmts()-1
00256         << " of table "
00257         << tblProxy.GetTableName() << "  ");
00258     }
00259     else {
00260          SK_DBI_Severe(  "Complete but bad data supplied for table "
00261         << tblProxy.GetTableName() << "  ");
00262     }
00263     ++fNumErrors;
00264     return kFALSE;
00265   }
00266   this->AddRow(outRow.GetCSV());
00267   return kTRUE;
00268 }
00269 //.....................................................................
00270 ///\verbatim
00271 ///  Purpose:  Compare to another TDbiSqlValPacket
00272 ///
00273 ///  Arguments:
00274 ///    that         in    The other TDbiSqlValPacket to be compared.
00275 ///    log          in    If true list differences to MSG("TDbi",kInfo)
00276 ///    thisName     in    Optional name for this packet (default: this)
00277 ///    thatName     in    Optional name for that packet (default: that)
00278 ///
00279 ///  Return:    kIdentical   if identical (apart from InsertDate)
00280 ///             kUpdate      "that" is more up to date
00281 ///             kOutOfDate   "that" is out of date
00282 ///             kConflict    records are incompatible
00283 ///
00284 ///  Contact:   N. West
00285 ///\endverbatim
00286 TDbiSqlValPacket::CompResult_t TDbiSqlValPacket::Compare(
00287                                 const TDbiSqlValPacket& that,
00288                                 Bool_t log,
00289                                 const Char_t* thisName,
00290                                 const Char_t* thatName ) const {
00291 //
00292 //
00293 
00294   if ( this->IsEqual(that,log,thisName,thatName ) ) return kIdentical;
00295 
00296   if (    fSeqNo           != that.fSeqNo
00297        || fTableName       != that.fTableName     ) return kConflict;
00298 
00299   std::vector<std::string> valuesThis = this->GetStmtValues(0);
00300   std::vector<std::string> valuesThat = that.GetStmtValues(0);
00301 
00302   // Assume CreationDate is the 9th element (counting from 0).
00303   int comp = valuesThis[9].compare(valuesThat[9]);
00304 
00305   if ( comp < 0 ) {
00306     if ( log ) SK_DBI_Info(  "  Difference classified as Update" << "  ");;
00307     return kUpdate;
00308   }
00309   else if ( comp > 0 ) {
00310     if ( log ) SK_DBI_Info(  "  Difference classified as OutOfDate" << "  ");
00311     return kOutOfDate;
00312   }
00313   return kConflict;
00314 
00315 }
00316 
00317 
00318 //.....................................................................
00319 ///\verbatim
00320 ///
00321 ///  Purpose:  Create table in specified database.
00322 ///
00323 ///  Arguments:
00324 ///    dbNo         in    Number of database in the cascade.
00325 ///
00326 ///  Return:    kTRUE if successfully created.
00327 ///
00328 ///  Contact:   N. West
00329 ///
00330 ///  Specification:-
00331 ///  =============
00332 ///
00333 ///  o If SQL to create tables is available, use it to create
00334 ///    the main and auxiliary tables and refresh the corresponding
00335 ///    TDbiTableProxy.
00336 ///\endverbatim
00337 Bool_t TDbiSqlValPacket::CreateTable(UInt_t dbNo) const {
00338 
00339 //  Program Notes:-
00340 //  =============
00341 
00342 //  None.
00343 
00344   if ( ! CanBeStored() ) return kFALSE;
00345 
00346   // Locate required TDbiStatement.
00347   auto_ptr<TDbiStatement> stmtDb(TDbiDatabaseManager::Instance()
00348                                .GetCascader()
00349                                .CreateStatement(dbNo));
00350   if ( ! stmtDb.get() ) {
00351     SK_DBI_Warn(  "Attempting to write to non-existant cascade entry " << dbNo
00352       << "  ");
00353     return kFALSE;
00354   }
00355   if ( fSqlMySqlMetaMain == "" || fSqlMySqlMetaVld  == "" ) {
00356     SK_DBI_Warn(  "No SQL available to create table " << fTableName
00357       << " in cascade entry: " << dbNo << "  ");
00358     return kFALSE;
00359   }
00360 
00361   stmtDb->ExecuteUpdate(fSqlMySqlMetaVld.c_str());
00362   if ( stmtDb->PrintExceptions() ) return kFALSE;
00363   stmtDb->ExecuteUpdate(fSqlMySqlMetaMain.c_str());
00364   if ( stmtDb->PrintExceptions() ) return kFALSE;
00365 
00366   TDbiDatabaseManager::Instance().RefreshMetaData(this->GetTableName());
00367 
00368   return kTRUE;
00369 
00370 }
00371 
00372 //.....................................................................
00373 ///\verbatim
00374 ///
00375 ///  Purpose:  Refill object from input string.
00376 ///
00377 ///  Arguments:
00378 ///      is    in/out    Input stream.
00379 ///
00380 ///  Return:   kTRUE "is" object has been refilled.
00381 ///
00382 ///  Contact:   N. West
00383 ///
00384 ///  Specification:-
00385 ///  =============
00386 ///
00387 ///  o Collect SQL statements, and possibly metadata (as SQL to
00388 ///    create table) bracketed by >>>> ... <<<<< checking that
00389 ///    the table name and SeqNos match.  Count and discard any data that
00390 ///    looks bad.
00391 
00392 Bool_t TDbiSqlValPacket::Fill(std::ifstream& is) {
00393 
00394 //  Program Notes:-
00395 //  =============
00396 
00397 //  None.
00398 
00399 #ifdef IRIX6
00400   EFillState state = kLOOKING_FOR_HEADER;
00401 #else
00402   enum { kLOOKING_FOR_HEADER,
00403          kLOOKING_FOR_TRAILER } state = kLOOKING_FOR_HEADER;
00404 #endif
00405 
00406   enum { kMAXTABLENAMELEN        = TDbi::kMAXTABLENAMELEN,
00407          kHEADER_TRAILER_MAX_LEN = kMAXTABLENAMELEN + 20 };
00408 
00409   string nameHead;
00410   string nameTrail;
00411   UInt_t seqNoHead  = 0;
00412   UInt_t seqNoTrail = 0;
00413 
00414   string line;
00415   string msg;
00416   string sql;
00417   int lineNum = 0;
00418 
00419   this->Reset();
00420   //  Loop until EOF reading lines.
00421 
00422   while ( ! is.eof() ) {
00423     getline(is,line);
00424     ++lineNum;
00425     // Skip null lines.
00426     if (line.size() == 0 ) continue;
00427 
00428     // Look for header line
00429     if ( state == kLOOKING_FOR_HEADER ) {
00430       if ( line.substr(0,5) == ">>>>>" ) {
00431         if ( line.size() >= kHEADER_TRAILER_MAX_LEN ) {
00432           Report("Bad header",lineNum,line);
00433           continue;
00434         }
00435 
00436         // Look for optional metadata.
00437         if ( line.find("Metadata") != string::npos ) {
00438           getline(is,fSqlMySqlMetaVld);
00439           ++lineNum;
00440           getline(is,fSqlMySqlMetaMain);
00441           ++lineNum;
00442           getline(is,line);
00443           ++lineNum;
00444           if (   line.substr(0,5) != "<<<<<"
00445               || line.find("Metadata") == string::npos ) {
00446             Report("Bad metadata",lineNum,line);
00447             continue;
00448           }
00449           getline(is,line);
00450           ++lineNum;
00451           if ( line.size() >= kHEADER_TRAILER_MAX_LEN ) {
00452             Report("Bad header",lineNum,line);
00453             continue;
00454           }
00455         }
00456 
00457         //  Collect table name and SeqNo.
00458         istringstream istr(line.substr(5));
00459         istr.width(kMAXTABLENAMELEN);
00460         istr >> nameHead >> seqNoHead;
00461         if ( ! istr.eof() ) {
00462           Report("Input error",lineNum,line);
00463           continue;
00464         }
00465 
00466         // Header looks good, start to collect SQL.
00467         state = kLOOKING_FOR_TRAILER;
00468         sql = "";
00469       }
00470       else {
00471         Report("Not header",lineNum,line);
00472       }
00473     }
00474 
00475     //Look for trailer line.
00476 
00477     else {
00478       if ( line.substr(0,5) == "<<<<<" ) {
00479         if ( line.size() >= kHEADER_TRAILER_MAX_LEN
00480            ) msg = "Bad trailer";
00481 
00482         else {
00483 
00484           //  Collect table name and SeqNo.
00485           istringstream istr(line.substr(5));
00486           istr.width(kMAXTABLENAMELEN);
00487           istr >> nameTrail >> seqNoTrail;
00488           if ( ! istr.eof() ) msg = "Input error";
00489 
00490           else if (    nameTrail != nameHead
00491                     || seqNoHead != seqNoTrail ) {
00492             msg = "Header/Trailer mismatch: Header: ";
00493             msg += istr.str();
00494           }
00495           else if ( GetNumSqlStmts() == 0
00496                   ) msg = "No SQL statements between Header/Trailer";
00497           else {
00498 
00499             // Trailer looks good return with object filled.
00500             fSeqNo     = seqNoHead;
00501             fTableName = nameHead;
00502 
00503             //Dig out the creation date from the first record.
00504             string date = this->GetStmtValues(0)[9];
00505             //Remove the quotes.
00506             date.erase(0,1);
00507             date.erase(date.size()-1,1);
00508             fCreationDate = TDbi::MakeTimeStamp(date);
00509             return kTRUE;
00510 
00511           }
00512         }
00513 
00514         // Trailer bad, start again!
00515         Report(msg.c_str(),lineNum,line);
00516         state = kLOOKING_FOR_HEADER;
00517       }
00518 
00519       // Not a trailer line, must be SQL, collect and append lines
00520       // until a trailing ; found.
00521       else {
00522         sql += line;
00523         if ( sql[sql.size()-1] == ';') {
00524           fSqlStmts.push_back(sql);
00525           ++fNumStmts;
00526           sql = "";
00527         }
00528       }
00529     }
00530 
00531   }
00532 
00533   if ( state != kLOOKING_FOR_HEADER
00534      ) Report("Unexpected EOF",lineNum,"EOF");
00535   this->Reset();
00536   return kFALSE;
00537 
00538 }
00539 //.....................................................................
00540 /// Return a selected statment
00541 string TDbiSqlValPacket::GetStmt(UInt_t stmtNo) const {
00542 //
00543 //
00544 //  Purpose:  Return a selected statment
00545 
00546   if ( stmtNo >= this->GetNumSqlStmts() ) return "";
00547 
00548   // Locate statement
00549   std::list<std::string>::const_iterator itr = fSqlStmts.begin();
00550   while ( stmtNo ) { ++itr; --stmtNo; }
00551 
00552   return *itr;
00553 
00554 }
00555 //.....................................................................
00556 ///\verbatim
00557 ///
00558 ///  Purpose:  Return all the values associated with a selected statment
00559 ///
00560 ///  Arguments:
00561 ///    stmtNo       in    The statement number (starting at 0)
00562 ///
00563 ///  Return:              vector of string values.
00564 ///                       Empty vector if stmt does not exits.
00565 ///
00566 ///  Contact:   N. West
00567 ///\endverbatim
00568 std::vector<std::string> TDbiSqlValPacket::GetStmtValues(UInt_t stmtNo) const {
00569 
00570 
00571   std::vector<std::string> vec;
00572   if ( stmtNo >= this->GetNumSqlStmts() ) return vec;
00573 
00574   // Locate statement
00575   std::string str = this->GetStmt(stmtNo);
00576 
00577   // Extract ...(list-of-values)... and parse it into tokens.
00578   std::string::size_type pos = str.find('(');
00579   ++pos;
00580   std::string::size_type n = str.find(')') - pos;
00581   UtilString::StringTok(vec,str.substr(pos,n),",");
00582 
00583   return vec;
00584 
00585 }
00586 
00587 //.....................................................................
00588 
00589 ///\verbatim
00590 ///  Purpose:  Test for equality to another TDbiSqlValPacket
00591 ///
00592 ///  Arguments:
00593 ///    that         in    The other TDbiSqlValPacket to be compared.
00594 ///    log          in    If true list differences to MSG("TDbi",kInfo)
00595 ///    thisName     in    Optional name for this packet (default: this)
00596 ///    thatName     in    Optional name for that packet (default: that)
00597 ///
00598 ///  Return:    kTRUE if identical (apart from InsertDate).
00599 ///
00600 ///  Contact:   N. West
00601 ///
00602 ///  Specification:-
00603 ///  =============
00604 ///
00605 ///  o Compare to another TDbiSqlValPacket.
00606 ///
00607 ///  Program Notes:-
00608 ///  =============
00609 ///
00610 ///  The InsertDate reflects the date when the data was written into the
00611 /// local database so has to be excluded from the comparison.
00612 ///\endverbatim
00613 
00614 Bool_t TDbiSqlValPacket::IsEqual(const TDbiSqlValPacket& that,
00615                                 Bool_t log,
00616                                 const Char_t* thisName,
00617                                 const Char_t* thatName ) const {
00618 //
00619   if (    fSeqNo           != that.fSeqNo
00620        || fTableName       != that.fTableName
00621        || fNumStmts != that.fNumStmts ) {
00622     SK_DBI_Log("Conflict found:"
00623              << " for : " << thisName << " , " << thatName << " :-\n"
00624              << "  SeqNo " << fSeqNo << "," << that.fSeqNo
00625              << "\n  TableName " << fTableName << "," << that.fTableName
00626              << "\n  Size " << fNumStmts << ","
00627              << that.fNumStmts);
00628     return kFALSE;
00629   }
00630 
00631   list<string>::const_iterator itrThisBegin = fSqlStmts.begin();
00632   list<string>::const_iterator itrThisEnd   = fSqlStmts.end();
00633   list<string>::const_iterator itrThatBegin = that.fSqlStmts.begin();
00634   list<string>::const_iterator itrThatEnd   = that.fSqlStmts.end();
00635 
00636   list<string>::const_iterator itrThis = itrThisBegin;
00637   list<string>::const_iterator itrThat = itrThatBegin;
00638 
00639   Bool_t isEqual = kTRUE;
00640 
00641   // Strip off InsertDate from first statement (assume its
00642   // the last parameter in list).
00643 
00644   string strThis = (*itrThis).substr(0,(*itrThis).rfind(','));
00645   string strThat = (*itrThat).substr(0,(*itrThat).rfind(','));
00646   if ( strThis != strThat ) {
00647   if ( ! log ) return kFALSE;
00648   isEqual = kFALSE;
00649   SK_DBI_Info(  "Difference on VLD record " << ":-\n"
00650       << "  " << thisName << ": " << strThis  << "  "
00651       << "  " << thatName << ": " << strThat  << "  ");
00652   }
00653 
00654   // Rows can come in any order (after the first) so we have
00655   // to sort before comparing.  However, if we are lucky, they
00656   // may be in the same order or inverse order so do a quick
00657   // test to see if there are no conflicts assuming these
00658   // relative orderings.
00659 
00660   ++itrThis;
00661   ++itrThat;
00662   while ( itrThis != itrThisEnd && (*itrThis) == (*itrThat) ) {
00663 //     cout << "Debug: trying forward compare ..." << *itrThis
00664 //       << "::" << *itrThat << endl;
00665     ++itrThis;
00666     ++itrThat;
00667   }
00668   if ( itrThis == itrThisEnd ) return isEqual;
00669 
00670   itrThis = itrThisBegin;
00671   itrThat = itrThatEnd;
00672   ++itrThis;
00673   --itrThat;
00674 
00675   while ( itrThis != itrThisEnd &&  (*itrThis) == (*itrThat) ) {
00676 //   cout << "Debug: trying reverse compare ..." << *itrThis
00677 //       << "::" << *itrThat << endl;
00678     ++itrThis;
00679     --itrThat;
00680   }
00681   if ( itrThis == itrThisEnd ) return isEqual;
00682 
00683   // O.K., we are out of luck so set up pointers to both sets
00684   // and sort these.
00685 
00686   typedef vector<const string*>      shadow_list_t;
00687   typedef shadow_list_t::iterator  shadow_list_itr_t;
00688 
00689   shadow_list_t shadowThis;
00690   shadow_list_t shadowThat;
00691 
00692   itrThis = itrThisBegin;
00693   itrThat = itrThatBegin;
00694   ++itrThis;
00695   ++itrThat;
00696 
00697   while ( itrThis != itrThisEnd ) {
00698     shadowThis.push_back(&(*itrThis));
00699     shadowThat.push_back(&(*itrThat));
00700     ++itrThis;
00701     ++itrThat;
00702   }
00703 
00704   shadow_list_itr_t shadowThisItr    = shadowThis.begin();
00705   shadow_list_itr_t shadowThisItrEnd = shadowThis.end();
00706   shadow_list_itr_t shadowThatItr    = shadowThat.begin();
00707   shadow_list_itr_t shadowThatItrEnd = shadowThat.end();
00708 
00709   sort(shadowThisItr,shadowThisItrEnd,compStringPtrs);
00710   sort(shadowThatItr,shadowThatItrEnd,compStringPtrs);
00711 
00712   while ( shadowThisItr != shadowThisItrEnd ) {
00713     if ( (**shadowThisItr) != (**shadowThatItr) ){
00714       if ( ! log ) return kFALSE;
00715       isEqual = kFALSE;
00716       SK_DBI_Info( "Difference on data record "
00717          << ":-\n"
00718          << "  " << thisName << ": " << **shadowThisItr  << "  "
00719          << "  " << thatName << ": " << **shadowThatItr  << "  ");
00720     }
00721    ++shadowThisItr;
00722    ++shadowThatItr;
00723   }
00724 
00725   return isEqual;
00726 
00727 }
00728 
00729 //.....................................................................
00730 /// Print the current state
00731 void TDbiSqlValPacket::Print(Option_t * /* option */) const {
00732 //
00733 //
00734 //  Purpose:  Print the current state.
00735 
00736   SK_DBI_Info(  "TDbiSQLValPacket:"
00737     << " table \"" << fTableName << "\" "
00738     << " SeqNo " << fSeqNo
00739     << " NumErrors " << fNumErrors
00740     << "  "
00741     << "   CreationDate " << fCreationDate
00742     << "  ");
00743 
00744   SK_DBI_Info(  "   MySQL Main table creation: \"" << fSqlMySqlMetaMain << "\"" << "  ");
00745 
00746   SK_DBI_Info(  "   MySQL VLD table creation: \"" << fSqlMySqlMetaVld << "\"" << "  ");
00747 
00748   if ( GetNumSqlStmts() > 0 ) {
00749     std::list<string>::const_iterator itr    = fSqlStmts.begin();
00750     std::list<string>::const_iterator itrEnd = fSqlStmts.end();
00751     for (; itr != itrEnd; ++itr)
00752       SK_DBI_Info(  "   SqlStmt \"" << *itr << "\"" << "  ");
00753   }
00754   else {
00755     SK_DBI_Info( "   No SqlStmts." << "  ");
00756   }
00757 
00758 }
00759 
00760 
00761 //.....................................................................
00762 //
00763 ///  Purpose:  Recreate and define first row (VLD - the validity record).
00764 void TDbiSqlValPacket::Recreate(const string& tableName,
00765                                const TVldRange& vr,
00766                                Int_t aggNo,
00767                                TDbi::Task task,             /*  Default: 0 */
00768                                TVldTimeStamp creationDate   /*  Default: now */
00769                                ) {
00770 //
00771 
00772 
00773 
00774   this->Clear();
00775 
00776   TDbiDatabaseManager& tablePR = TDbiDatabaseManager::Instance();
00777   if ( ! tablePR.GetCascader().TableExists(tableName) ) {
00778        SK_DBI_Severe( "Cannot create packet - table " << tableName
00779                            << " does not exist." << "  ");
00780     fNumErrors = 1;
00781     return;
00782   }
00783 
00784   fTableName = tableName;
00785 
00786 
00787   // Create a TDbiValidityRec from the supplied data.
00788   TDbiValidityRec vrec(vr,task,aggNo,0);
00789 
00790   //  Create a TDbiOutRowStream that can serialise this validity record
00791   TDbiConfigSet dummy;     // For validity row any TDbiTableRow will do.
00792   const TDbiTableMetaData&  metaValid = tablePR.GetTableProxy(tableName,&dummy)
00793                                               .GetMetaValid();
00794   TDbiOutRowStream buff(&metaValid);
00795 
00796   vrec.Store(buff,0);
00797   this->AddRow(buff.GetCSV());
00798   this->SetCreationDate(creationDate);
00799 
00800 }
00801 
00802 //.....................................................................
00803 ///\verbatim
00804 ///  Purpose:  Report and count errors.
00805 ///
00806 ///  Arguments:
00807 ///    msg          in    Message to be reported.
00808 ///    lineNum      in    Line number.
00809 ///    line         in    Input line causing error.
00810 ///
00811 ///  Return:
00812 ///
00813 ///  Contact:   N. West
00814 ///
00815 ///  Specification:-
00816 ///  =============
00817 ///
00818 ///  o Reset object, report and count errors.
00819 ///\endverbatim
00820 void TDbiSqlValPacket::Report(const char* msg,
00821                              UInt_t lineNum,
00822                              const string& line) {
00823 //
00824 
00825 //  Program Notes:-
00826 //  =============
00827 
00828 //  None.
00829 
00830      SK_DBI_Severe( " on line " << lineNum
00831                          <<":- \n  " << line << "  ");
00832   this->Reset();
00833   ++fNumErrors;
00834 
00835 }
00836 //.....................................................................
00837 ///  Purpose:  Clear out back to unfilled status except for fNumErrors.
00838 
00839 void TDbiSqlValPacket::Reset() {
00840 //
00841 //
00842 //
00843   fSeqNo       = 0;
00844   fSqlMySqlMetaMain = "";
00845   fSqlMySqlMetaVld  = "";
00846   fSqlStmts.clear();
00847   fNumStmts    = 0;
00848   fTableName   = "";
00849 
00850 }
00851 //.....................................................................
00852 /// Purpose:  Set creation date.
00853 void TDbiSqlValPacket::SetCreationDate(TVldTimeStamp ts) {
00854 //
00855 //
00856 //
00857   fCreationDate = ts;
00858 
00859   //  Update the validity row assuming:  "...,'creationdate',insertdate);"
00860   if ( this->GetNumSqlStmts() == 0 ) return;
00861 
00862   string& vldRow = *fSqlStmts.begin();
00863   string::size_type locEnd = vldRow.rfind(',');
00864   if ( locEnd == string::npos ) return;
00865   locEnd -=2;
00866   string::size_type locStart = vldRow.rfind(',',locEnd);
00867   if ( locStart == string::npos ) return;
00868   locStart+=2;
00869   vldRow.replace(locStart,locEnd-locStart+1,ts.AsString("s"));
00870 
00871 }
00872 //.....................................................................
00873 /// Set EPOCH
00874 void TDbiSqlValPacket::SetEpoch(UInt_t epoch) {
00875 //
00876 //
00877 //  Purpose:  Set EPOCH
00878 
00879   //  Update the validity row assuming:  "(seqno,timestart,timeend,epoch,....)
00880   if ( this->GetNumSqlStmts() == 0 ) return;
00881 
00882   string& vldRow = *fSqlStmts.begin();
00883   string::size_type locStart = 0;
00884   for (int field = 0; field < 3; ++field) {
00885     locStart = vldRow.find(',',locStart+1);
00886     if ( locStart == string::npos ) return;
00887   }
00888   string::size_type locEnd = vldRow.find(',',locStart+1);
00889   if ( locEnd == string::npos ) return;
00890   locEnd  -=1;
00891   locStart+=1;
00892   ostringstream epoch_str;
00893   epoch_str << epoch;
00894   vldRow.replace(locStart,locEnd-locStart+1,epoch_str.str());
00895 
00896 }
00897 
00898 //.....................................................................
00899 ///  Purpose:  Set up meta-data as SQL table creation statements.
00900 
00901 void TDbiSqlValPacket::SetMetaData() const {
00902 //
00903 //
00904 //
00905   TDbiDatabaseManager& tbprxreg = TDbiDatabaseManager::Instance();
00906 
00907   //  Locate the table in the cascade.
00908   TDbiCascader& cas = tbprxreg.GetCascader();
00909   Int_t dbNo = cas.GetTableDbNo(this->GetTableName());
00910   if ( dbNo < 0 ) return;
00911 
00912   //  Any table proxy will do to get the meta-data so use the one for a
00913   //  TDbiConfigSet;
00914   TDbiConfigSet dummy;
00915   const TDbiTableMetaData & metaVld =  tbprxreg.GetTableProxy(this->GetTableName(),&dummy)
00916                                      .GetMetaValid();
00917   const TDbiTableMetaData & metaMain = tbprxreg.GetTableProxy(this->GetTableName(),&dummy)
00918                                      .GetMetaData();
00919   fSqlMySqlMetaVld   = metaVld.Sql();
00920   fSqlMySqlMetaMain  = metaMain.Sql();
00921 
00922 }
00923 
00924 //.....................................................................
00925 /// Set sequence number
00926 void TDbiSqlValPacket::SetSeqNo(UInt_t seqno) {
00927 //
00928 //
00929 //  Purpose:  Set Sequence number.
00930 
00931   fSeqNo = seqno;
00932 
00933   //  Update all rows
00934   if ( this->GetNumSqlStmts() == 0 ) return;
00935 
00936   ostringstream tmp;
00937   tmp << seqno;
00938   const string seqnoStr = tmp.str();
00939 
00940   std::list<string>::iterator itr    = fSqlStmts.begin();
00941   std::list<string>::iterator itrEnd = fSqlStmts.end();
00942   for (; itr != itrEnd; ++itr) SetSeqNoOnRow(*itr,seqnoStr);
00943 
00944 
00945 }
00946 
00947 //.....................................................................
00948 ///  Purpose:  Set Sequence number on supplied row
00949 void TDbiSqlValPacket::SetSeqNoOnRow(string& row,const string& seqno) {
00950 //
00951 //
00952 
00953 //  Update row assuming:  "...(seqno, ...."
00954 
00955   string::size_type locStart = row.find('(');
00956   if ( locStart == string::npos ) return;
00957   ++locStart;
00958   string::size_type locEnd = row.find(',',locStart);
00959   if ( locEnd == string::npos ) return;
00960   row.replace(locStart,locEnd-locStart,seqno);
00961 
00962 }
00963 
00964 //.....................................................................
00965 ///\verbatim
00966 ///
00967 ///  Purpose:  Output validity packet to specified database.
00968 ///
00969 ///  Arguments:
00970 ///    dbNo         in    Number of database in the cascade.
00971 ///    replace      in    If true replace existing SeqNo (default: kFALSE).
00972 ///
00973 ///  Return:    kTRUE if successfully stored.
00974 ///
00975 ///  Contact:   N. West
00976 ///
00977 ///  Specification:-
00978 ///  =============
00979 ///
00980 ///  o Output validity packet to specified database modifying
00981 ///    InsertDate to be current date.
00982 ///\endverbatim
00983 Bool_t TDbiSqlValPacket::Store(UInt_t dbNo, Bool_t replace) const {
00984 
00985 
00986   if ( ! CanBeStored() ) return kFALSE;
00987 
00988   //Just use any old table row object just to get a TDbiDBProxy.
00989   TDbiConfigSet pet;
00990   TDbiTableProxy& tp =  TDbiDatabaseManager::Instance()
00991                       .GetTableProxy(this->GetTableName(),&pet);
00992   if ( replace ) {
00993     const TDbiDBProxy & proxy = tp.GetDBProxy();
00994     if ( ! proxy.RemoveSeqNo(this->GetSeqNo(),dbNo) ) return kFALSE;
00995   }
00996 
00997   // Locate required TDbiStatement.
00998   auto_ptr<TDbiStatement> stmtDb(TDbiDatabaseManager::Instance()
00999                                .GetCascader()
01000                                .CreateStatement(dbNo));
01001   if ( ! stmtDb.get() ) {
01002     SK_DBI_Warn(  "Attempting to write to non-existant cascade entry " << dbNo
01003       << "  ");
01004     return kFALSE;
01005   }
01006 
01007 
01008   // Loop processing all SQL statements
01009   Bool_t first = kTRUE;
01010   int combineInserts = 0;
01011   int maxInserts = 20;
01012   string sqlInserts;
01013 
01014   for (list<string>::const_iterator itr = fSqlStmts.begin();
01015        itr != fSqlStmts.end();
01016        ++itr) {
01017     if ( first ) {
01018 //    On first statement replace InsertDate by current datetime.
01019       string sql = *itr;
01020       list<string>::size_type locDate = sql.rfind(",\'");
01021       if ( locDate !=  string::npos ) {
01022         TVldTimeStamp now;
01023         sql.replace(locDate+2,19,TDbi::MakeDateTimeString(now));
01024       }
01025       stmtDb->ExecuteUpdate(sql.c_str());
01026       if ( stmtDb->PrintExceptions() ) return kFALSE;
01027       first = kFALSE;
01028       continue;
01029     }
01030 
01031     string sql = *itr;
01032 
01033 //  Reduce database I/O by combining groups of insert commands.
01034 
01035     string::size_type insertIndex = sql.find("VALUES (");
01036     if ( insertIndex == string::npos) {
01037          SK_DBI_Severe( "Unexpected SQL : " << sql
01038                              << "\n  should be of form INSERT INTO ... VALUES (...);" << "  ");
01039       return kFALSE;
01040     }
01041     ++combineInserts;
01042     if ( combineInserts == 1 ) sqlInserts = sql;
01043     else {
01044       sqlInserts[sqlInserts.size()-1] = ',';
01045       sqlInserts += sql.substr(insertIndex+7);
01046     }
01047     if ( combineInserts >= maxInserts ) {
01048       stmtDb->ExecuteUpdate(sqlInserts.c_str());
01049       if ( stmtDb->PrintExceptions() ) return kFALSE;
01050       combineInserts = 0;
01051     }
01052   }
01053 
01054 // Deal with last group of inserts.
01055   if ( combineInserts ) {
01056     stmtDb->ExecuteUpdate(sqlInserts.c_str());
01057     combineInserts = 0;
01058     if ( stmtDb->PrintExceptions() ) return kFALSE;
01059   }
01060 
01061   return kTRUE;
01062 
01063 }
01064 //.....................................................................
01065 //
01066 ///\verbatim
01067 ///  Purpose:  Export to an iostream.
01068 ///
01069 ///  Arguments:
01070 ///     ios          in/out    Output stream.
01071 ///     addMetadata  in        if kTRUE, output SQL metadata (in form
01072 ///                            of a create table SQL)
01073 ///
01074 ///  Return:    kTRUE is I/O successful.
01075 ///
01076 ///  Contact:   N. West
01077 ///
01078 ///  Specification:-
01079 ///  =============
01080 ///
01081 ///  o Export to an iostream.
01082 ///\endverbatim
01083 Bool_t TDbiSqlValPacket::Write(std::ofstream& ios,
01084                               Bool_t addMetadata) const {
01085 
01086 //  Program Notes:-
01087 //  =============
01088 
01089 //  None.
01090 
01091   if ( ! CanBeStored() ) return kFALSE;
01092   if ( addMetadata ) {
01093     if ( fSqlMySqlMetaMain.size() == 0 ) this->SetMetaData();
01094     if ( fSqlMySqlMetaMain.size() == 0 ) {
01095       SK_DBI_Warn(  "Cannot write metadata; no associated TDbiTableProxy "
01096       << "  ");
01097     }
01098     else {
01099 
01100 
01101       ios << ">>>>>" << GetTableName() << " Metadata [MySQL]" << endl;
01102       ios << fSqlMySqlMetaVld   << endl;
01103       ios << fSqlMySqlMetaMain  << endl;
01104       ios << "<<<<<" << GetTableName() << " Metadata" << endl;
01105     }
01106   }
01107 
01108   ios << ">>>>>" << GetTableName() << "  " << GetSeqNo() << endl;
01109 
01110   for ( list<string>::const_iterator itr = fSqlStmts.begin();
01111         itr != fSqlStmts.end();
01112         ++itr) ios << (*itr) << endl;
01113 
01114   ios << "<<<<<" << GetTableName() << "  " << GetSeqNo() << endl;
01115 
01116   return kTRUE;
01117 
01118 }
01119 
01120 

Generated on 11 Aug 2013 for SKDatabase by  doxygen 1.6.1