EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FairDbResult.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FairDbResult.cxx
1 #include <sstream>
2 
3 #include "FairDbBinaryFile.h"
4 #include "FairDbResult.h"
5 #include "FairDbServices.h"
6 #include "FairDbTableRow.h"
7 #include "FairDbFieldType.h"
8 #include "FairDbString.h"
9 #include "FairDbStatement.h"
10 #include "FairDbTableMetaData.h"
11 #include "FairDbProxy.h"
12 #include "FairDbCache.h"
13 #include "FairDbTimerManager.h"
15 #include "FairDbExceptionLog.h"
16 
17 
18 #include "ValTimeStamp.h"
19 
20 
21 
22 // ------------------------- Result Set Implementation ---------------------------------\\
23 
25 
26 
28  const FairDbString& sql,
29  const FairDbTableMetaData* metaData,
30  const FairDbTableProxy* tableProxy,
31  UInt_t dbNo,
32  const string& fillOpts) :
33  FairDbRowStream(metaData),
34  fCurRow(0),
35  fDbNo(dbNo),
36  fDbType(FairDb::kMySQL),
37  fStatement(stmtDb),
38  fTSQLStatement(0),
39  fExhausted(true),
40  fTableProxy(tableProxy),
41  fValString(),
42  fFillOpts(fillOpts)
43 {
44 
45  if ( stmtDb ) {
46  fDbType = stmtDb->GetDBType();
47  fTSQLStatement = stmtDb->ExecuteQuery(sql.c_str());
48  if ( fTSQLStatement && fTSQLStatement->NextResultRow() ) { fExhausted = false; }
49  }
50 
51 }
52 
54 {
55  delete fTSQLStatement;
56  fTSQLStatement = 0;
57  delete fStatement;
58  fStatement = 0;
59 
60 }
61 
62 #define IN(t) istringstream in(AsString(t)); in
63 // On first row use AsString to force type checking.
64 // On subsequent rows use binary interface for speed.
65 // Caution: Column numbering in TSQLStatement starts at 0.
66 #define IN2(t,m) \
67  int col = CurColNum()-1; \
68  if ( CurRowNum() == 0 ) { \
69  istringstream in(AsString(t)); \
70  in >> dest; \
71  } \
72  else { \
73  dest = fTSQLStatement->m(col); \
74  IncrementCurCol(); \
75  } \
76 
77 // Handling reading of unsigned application data stored as signed database data.
78 // Both GetInt(int) and GetString(int) return the signed data correctly.
79 // So first read into signed equivalent, then copy and finally
80 // trim off leading extended sign bits beyond the capacity of
81 // the database column.
82 // For BIGINT (size 8) make an exception. It's used only as
83 // an alternative to unsigned int and getUInt(int) (but not GetInt(int))
84 // returns it correctly so can load directly into destination
85 // Caution: Column numbering in TSQLStatement starts at 0.
86 #define IN3(t) \
87 int col = this->CurColNum()-1; \
88 const FairDbFieldType& fType = this->ColFieldType(col+1); \
89 if ( fType.GetSize() == 8 ) { \
90  dest=fTSQLStatement->GetUInt(col); \
91 } \
92 else { \
93  t dest_signed; \
94  *this >> dest_signed; \
95  dest = dest_signed; \
96  if ( fType.GetSize() == 1 ) dest &= 0xff; \
97  if ( fType.GetSize() == 2 ) dest &= 0xffff; \
98  if ( fType.GetSize() == 4 ) dest &= 0xffffffff; \
99 }\
100 
102 {
103  IN(FairDb::kBool) >> dest;
104  return *this;
105 }
107 {
108  IN(FairDb::kChar) >> dest;
109  return *this;
110 }
112 {
113  IN2(FairDb::kInt,GetInt);
114  return *this;
115 }
117 {
118  IN3(Short_t);
119  return *this;
120 }
122 {
123  IN2(FairDb::kInt,GetInt);
124  return *this;
125 }
127 {
128  IN3(Int_t);
129  return *this;
130 }
132 {
133  IN2(FairDb::kLong, GetLong);
134  return *this;
135 }
137 {
138  IN3(Long_t);
139  return *this;
140 }
142 {
143  IN2(FairDb::kFloat,GetDouble);
144  return *this;
145 }
147 {
148  IN2(FairDb::kDouble,GetDouble);
149  return *this;
150 }
151 
152 // Also use AsString() for string and ValTimeStamp; conversion to string
153 // is needed in any case.
155 {
156  dest = AsString(FairDb::kString);
157  return *this;
158 }
160 {
162  return *this;
163 }
164 
166 {
167 
168  FairDbFieldType reqdt(type);
169 
170 // Place table value string in value string buffer.
171  Bool_t fail = ! LoadCurValue();
172 // Internally columns number from zero.
173  UInt_t col = CurColNum();
174  IncrementCurCol();
175 
176  if ( fail ) {
177  string udef = reqdt.UndefinedValue();
178  cout << "-I- FairDbResultSet "
179  << "... value \"" << udef
180  << "\" will be substitued." << endl;
181  fValString = udef;
182  return fValString;
183  }
184 
185 // Check for compatibility with required data type.
186 
187  const FairDbFieldType& actdt = MetaData()->ColFieldType(col);
188 
189  if ( reqdt.IsCompatible(actdt) ) {
190  Bool_t smaller = reqdt.IsSmaller(actdt);
191 // Allow one character String to be stored in Char
192  if ( reqdt.GetConcept() == FairDb::kChar && fValString.size() == 1
193  ) { smaller = kFALSE; }
194  if ( smaller ) {
195 
196  cout << "-I- FairDbResultSet "
197  << "In table " << TableNameTc()
198  << " row " << fCurRow
199  << " column "<< col
200  << " (" << MetaData()->ColName(col) << ")"
201  << " value \"" << fValString
202  << "\" of type " << actdt.AsString()
203  << " may be truncated before storing in " << reqdt.AsString()
204  << endl;
205  }
206  } else {
207  string udef = reqdt.UndefinedValue();
208  cout << "-I- FairDbResultSet "
209  << "In table " << TableNameTc()
210  << " row " << fCurRow
211  << " column "<< col
212  << " (" << MetaData()->ColName(col) << ")"
213  << " value \"" << fValString
214  << "\" of type " << actdt.AsString()
215  << " is incompatible with user type " << reqdt.AsString()
216  << ", value \"" << udef
217  << "\" will be substituted." << endl;
218  fValString = udef;
219  }
220 
221  return fValString;
222 }
223 
225 {
226 
227  Int_t col = CurColNum();
228 
229  if ( IsExhausted() ) {
230  cout << "-I- FairDbResultSet "
231  << "In table " << TableNameTc()
232  << " attempting to access row " << fCurRow
233  << " column " << col
234  << " but only " << fCurRow << " rows in table." << endl;
235  return kFALSE;
236  }
237 
238  int numCols = NumCols();
239  if ( col > numCols ) {
240  cout << "-I- FairDbResultSet "
241  << "In table " << TableNameTc()
242  << " row " << fCurRow
243  << " attempting to access column "<< col
244  << " but only " << NumCols() << " in table ." << endl;
245  return kFALSE;
246  }
247 
248  return kTRUE;
249 
250 }
252 {
253 
254  if ( ! CurColExists() ) { return ""; }
255 
256  TString valStr = this->GetStringFromTSQL(CurColNum());
257  return valStr.Data();
258 
259 }
260 
262 {
263  ClearCurCol();
264  if ( IsExhausted() ) { return kFALSE; }
265  ++fCurRow;
266  if ( ! fTSQLStatement->NextResultRow() ) { fExhausted = true; }
267  return ! fExhausted;
268 
269 }
270 TString FairDbResultSet::GetStringFromTSQL(Int_t col) const
271 {
272  TString valStr = fTSQLStatement->GetString(col-1);
273  if ( this->GetDBType() == FairDb::kOracle
274  && this->ColFieldType(col).GetConcept() == FairDb::kString ) {
275  cout << "-I- FairDbResultSet" <<
276  "ORACLE string conversion from: " << valStr << endl;
277  valStr.ReplaceAll("\\n", "\n");
278  valStr.ReplaceAll("\\t", "\t");
279  valStr.ReplaceAll("\\\'","\'");
280  valStr.ReplaceAll("\\\"","\"");
281  valStr.ReplaceAll("\\\\","\\");
282  cout << " to: " << valStr <<endl;
283  }
284  return valStr;
285 }
287 {
288 
289  fValString.clear();
290 
291  if ( ! CurColExists() ) { return kFALSE; }
292 
293  Int_t col = CurColNum();
294  TString valStr = this->GetStringFromTSQL(col);
295 
296  // For floating point, use binary interface to preserve precision
297  // e.g.-1.234567890123457e-100 as string is -0.000000
298  if ( CurColFieldType().GetConcept() == FairDb::kFloat ) {
299  ostringstream out;
300 // out << ;
301  if ( CurColFieldType().GetType() == FairDb::kDouble ) { ; }
302 // Caution: Column numbering in TSQLStatement starts at 0.
303  out << fTSQLStatement->GetDouble(col-1);
304  valStr = out.str().c_str();
305  }
306  int len = valStr.Length();
307 
308 
309 
310  const char* pVal = valStr.Data();
311  // Remove leading and trailing quotes if dealing with a string.
312  if ( len >= 2
313  && ( *pVal == *(pVal+len-1) )
314  && ( *pVal == '\'' || *pVal == '"' ) ) {
315  ++pVal;
316  len -= 2;
317  }
318  fValString.assign(pVal,len);
319 
320  return kTRUE;
321 
322 }
323 void FairDbResultSet::RowAsCsv(string& row) const
324 {
325  const FairDbTableMetaData* md = this->MetaData();
326 
327  Int_t maxCol = this->NumCols();
328  for (Int_t col = 1; col <= maxCol; ++col) {
329  // Deal with NULL values. Caution: Column numbering in TSQLStatement starts at 0.
330  if ( fTSQLStatement->IsNull(col-1) ) {
331  row += "NULL";
332  if ( col < maxCol ) { row += ','; }
333  continue;
334  }
335  Bool_t mustDelimit = md->ColMustDelimit(col);
336  UInt_t concept = md->ColFieldConcept(col);
337  if ( mustDelimit ) { row += '\''; }
338  TString str = this->GetStringFromTSQL(col);
339  const char* value = str.Data();
340 
341  // Make strings printable.
342  if ( concept == FairDb::kString ) { FairUtilString::MakePrintable(value,row); }
343 
344  // For floating point, use binary interface to preserve precision
345  // e.g.-1.234567890123457e-100 as string is -0.000000
346  else if ( concept == FairDb::kFloat ) {
347  ostringstream out;
348  //out << setprecision(8);
349  if ( md->ColFieldType(col).GetType() == FairDb::kDouble ) { ; } //out << setprecision(16);
350  out << fTSQLStatement->GetDouble(col-1);
351  row += out.str();
352  }
353 
354  // Everything else (!) is O.K.
355  else { row += value; }
356 
357  if ( mustDelimit ) { row += '\''; }
358  if ( col < maxCol ) { row += ','; }
359  }
360 }
361 
362 //----------------------------- Result Key Implementation ------------------------------------//
363 
365 
366 FairDbResultKey FairDbResultKey::fgEmptyKey;
367 
368 std::ostream& operator<<(std::ostream& os, const FairDbResultKey& key)
369 {
370  os << key.AsString() << endl;
371  return os;
372 }
373 
374 
376  fTableName(),
377  fRowName(),
378  fVRecKeys(),
379  fNumVRecKeys(0)
380 {
381  if ( that ) { *this = *that; }
382 }
383 
385 
386 FairDbResultKey::FairDbResultKey(std::string tableName,
387  std::string rowName,
388  UInt_t seqno,
389  ValTimeStamp ts) :
390  fTableName(tableName),
391  fRowName(rowName),
392  fVRecKeys(),
393  fNumVRecKeys(0)
394 {
395 
396  this->AddVRecKey(seqno,ts);
397 }
398 
399 //.....................................................................
400 
402 {
403 
404 }
405 
406 //.....................................................................
407 
409 {
410 
411  fVRecKeys.push_back(VRecKey(seqno,ts));
412  ++fNumVRecKeys;
413 
414 }
415 
416 //.....................................................................
417 
418 std::string FairDbResultKey::AsString() const
419 {
420 //
421 //
422 // Return a string that summarises this key giving:-
423 // 1) The table and row names.
424 // 2) The number of validity records (aggregates)
425 // 3) The range of SEQNOs
426 // 4) The range of CREATIONDATEs.
427 
428  ostringstream os;
429  os << "Table:" << fTableName << " row:" << fRowName;
430  if ( fVRecKeys.empty() ) { os << " No vrecs"; }
431  else {
432  os << ". " << fNumVRecKeys << " vrec";
433  if ( fNumVRecKeys > 1 ) { os << "s (seqno min..max;creationdate min..max):"; }
434  else { os << " (seqno;creationdate):"; }
435  os << " ";
436  std::list<VRecKey>::const_iterator itr = fVRecKeys.begin();
437  std::list<VRecKey>::const_iterator itrEnd = fVRecKeys.end();
438  UInt_t seqnoMin = itr->SeqNo;
439  UInt_t seqnoMax = seqnoMin;
440  ValTimeStamp tsMin = itr->CreationDate;
441  ValTimeStamp tsMax = tsMin;
442  ++itr;
443  while ( itr != itrEnd ) {
444  UInt_t seqno = itr->SeqNo;
445  ValTimeStamp ts = itr->CreationDate;
446  if ( seqno < seqnoMin ) { seqnoMin = seqno; }
447  if ( seqno > seqnoMax ) { seqnoMax = seqno; }
448  if ( ts < tsMin ) { tsMin = ts; }
449  if ( ts > tsMax ) { tsMax = ts; }
450  ++itr;
451  }
452  os << seqnoMin;
453  if ( seqnoMin < seqnoMax ) { os << ".." << seqnoMax; }
454  os << ";" << tsMin.AsString("s");
455  if ( tsMin < tsMax ) { os << ".." << tsMax.AsString("s"); }
456  }
457  return string(os.str());
458 
459 }
460 //.....................................................................
461 
462 Float_t FairDbResultKey::Compare(const FairDbResultKey* that) const
463 {
464 
465  // Check in table and row names.
466  if ( fTableName != that->fTableName ) { return -2.; }
467  if ( fRowName != that->fRowName ) { return -1.; }
468 
469  // Pick the key with the most entries and compare the other to it.
470 
471  cout << "Comparing " << *this << " to "
472  << *that << endl;
473 
474  const FairDbResultKey* keyBig = this;
475  const FairDbResultKey* keySmall = that;
476  if ( that->GetNumVrecs() > this->GetNumVrecs() ) {
477  keyBig = that;
478  keySmall = this;
479  }
480  int numVrecs = keyBig->GetNumVrecs();
481  if ( numVrecs == 0 ) { return 0.; }
482 
483  std::map<UInt_t,ValTimeStamp> seqnoToCreationDate;
484  std::list<FairDbResultKey::VRecKey>::const_iterator itrEnd = keyBig->fVRecKeys.end();
485  for ( std::list<FairDbResultKey::VRecKey>::const_iterator itr = keyBig->fVRecKeys.begin();
486  itr != itrEnd;
487  ++itr ) { seqnoToCreationDate[itr->SeqNo] = itr->CreationDate; }
488  float match = 0;
489  itrEnd = keySmall->fVRecKeys.end();
490  for ( std::list<FairDbResultKey::VRecKey>::const_iterator itr = keySmall->fVRecKeys.begin();
491  itr != itrEnd;
492  ++itr ) {
493  cout << "Comparing seqno " << itr->SeqNo << " with creation date " << itr->CreationDate
494  << " to " << seqnoToCreationDate[itr->SeqNo] << endl;
495  if ( seqnoToCreationDate[itr->SeqNo] == itr->CreationDate ) { ++match; }
496  }
497  cout << "Match results: " << match << " out of " << numVrecs << endl;
498 
499  return match/numVrecs;
500 
501 }
502 
503 
505 {
506  ostringstream os;
507  os << fTableName << "::" << fRowName;
508  return os.str();
509 
510 }
511 
512 //--------------------------------- Result Aggregat Implementation --------------------------//
513 
514 
515 
517 
518 typedef vector<const FairDbResult*>::const_iterator ConstResultItr_t;
519 
520 FairDbResultAgg::FairDbResultAgg(const string& tableName,
521  const FairDbTableRow* tableRow,
522  FairDbCache* cache,
523  const FairDbValidityRecBuilder* vrecBuilder,
524  const FairDbProxy* proxy,
525  const string& sqlQualifiers) :
526  FairDbResult(0,0,sqlQualifiers),
527  fResults(),
528  fRowKeys(),
529  fSize(0)
530 {
531  typedef map<UInt_t,UInt_t> seqToRow_t;
532 
533  SetTableName(tableName);
534  if ( ! tableRow || ! cache || ! vrecBuilder || ! proxy ) { return; }
535 
536 // Unpack the extended context SQL qualifiers.
537 // Don't use StringTok - it eats null strings
538 // e.g. abc;;def gives 2 substrings.
539 
540  string::size_type loc = sqlQualifiers.find(';');
541  string::size_type loc2 = sqlQualifiers.find(';',loc+1);
542  string sqlData = string(sqlQualifiers,loc+1,loc2-loc-1);
543  string fillOpts = string(sqlQualifiers,loc2+1);
544 
545 //Loop over all rows looking to see if they are already in
546 //the cache, and if not, recording their associated sequence numbers
547 
548  vector<UInt_t> reqSeqNos; // Sequence numbers required from DB.
549  seqToRow_t seqToRow; // Map SeqNo - > RowNo.
550 // Set up a Default database number, it will be updated if anything
551 // needs to be read from the database.
552  UInt_t dbNo = 0;
553  Int_t maxRowNo = vrecBuilder->GetNumValidityRec() - 1;
554 
555 //Ignore the first entry from the validity rec builder, it will be
556 //for Agg No = -1, which should not be present for aggregated data.
557  for ( Int_t rowNo = 1; rowNo <= maxRowNo; ++rowNo ) {
558  const FairDbValidityRec& vrecRow = vrecBuilder->GetValidityRec(rowNo);
559 
560 // If its already in the cache, then just connect it in.
561  const FairDbResult* res = cache->Search(vrecRow,sqlQualifiers);
562  cout << "Checking validity rec " << rowNo
563  << " " << vrecRow
564  << "SQL qual: " << sqlQualifiers
565  << " cache search: " << (void*) res << endl;
566  if ( res ) {
567  fResults.push_back(res);
568  res->Connect();
569  fSize += res->GetNumRows();
570  }
571 
572 // If its not in the cache, but represents a gap, then create an empty
573 // FairDbResult and add it to the cache.
574  else if ( vrecRow.IsGap() ) {
575  FairDbResult* newRes = new FairDbResultNonAgg(0, tableRow, &vrecRow);
576  cache->Adopt(newRes,false);
577  fResults.push_back(newRes);
578  newRes->Connect();
579  }
580 
581 // Neither in cache, nor a gap, so record its sequence number.
582  else {
583  UInt_t seqNo = vrecRow.GetSeqNo();
584  reqSeqNos.push_back(seqNo);
585  seqToRow[seqNo] = rowNo;
586  fResults.push_back(0);
587 // All data must come from a single database, so any vrec will
588 // do to define which one.
589  dbNo = vrecRow.GetDbNo();
590  }
591  }
592 
593 //If there are required sequence numbers, then read them from the
594 //database and build FairDbResults for each.
595 
596  if ( reqSeqNos.size() ) {
597 // Sort into ascending order; it may simplify the query which will
598 // block ranges of sequence numbers together.
599  sort(reqSeqNos.begin(),reqSeqNos.end());
600  FairDbResultSet* rs = proxy->QuerySeqNos(reqSeqNos,dbNo,sqlData,fillOpts);
601 // Flag that data was read from Database.
602  this->SetResultsFromDb();
604  while ( ! rs->IsExhausted() ) {
605  Int_t seqNo;
606  *rs >> seqNo;
607  rs->DecrementCurCol();
608  Int_t rowNo = -2;
609  if ( seqToRow.find(seqNo) == seqToRow.end() ) {
610 
611  cout << "Unexpected SeqNo: " << seqNo << endl;
612 
613  } else {
614  rowNo = seqToRow[seqNo];
615  cout
616  << "Procesing SeqNo: " << seqNo
617  << " for row " << rowNo << endl;
618  }
619 
620  const FairDbValidityRec& vrecRow = vrecBuilder->GetValidityRec(rowNo);
621  FairDbResultNonAgg* newRes = new FairDbResultNonAgg(rs,tableRow,&vrecRow);
622 // Don't allow results from Extended Context queries to be reused.
623  if ( this->IsExtendedContext() ) { newRes->SetCanReuse(false); }
624  if ( rowNo == -2 ) {
625  delete newRes;
626  } else {
627  cout
628  << "SeqNo: " << seqNo
629  << " produced " << newRes->GetNumRows() << " rows" << endl;
630 // Adopt but don't register key for this component, only the overall FairDbResultAgg
631 // will have a registered key.
632  cache->Adopt(newRes,false);
633  fResults[rowNo-1] = newRes;
634  newRes->Connect();
635  fSize += newRes->GetNumRows();
636  }
637  }
638 
639 // FairDbResultSet fully processed, so delete it.
640  delete rs;
641  }
642 
643 //All component FairDbResultNonAgg objects have now been located and
644 //connected in, so set up their access keys and determine the validty
645 //range by ANDing the time windows together.
646 
647  fRowKeys.reserve(fSize);
648 
649  FairDbValidityRec vRec = vrecBuilder->GetValidityRec(1);
650  for ( Int_t rowNo = 1; rowNo <= maxRowNo; ++rowNo ) {
651 
652  const FairDbValidityRec& vrecRow = vrecBuilder->GetValidityRec(rowNo);
653  ValRange r = vrecRow.GetValRange();
654  vRec.AndTimeWindow(r.GetTimeStart(),r.GetTimeEnd());
655 
656  const FairDbResult* res = fResults[rowNo-1];
657  if ( res ) {
658  UInt_t numEnt = res->GetNumRows();
659  for (UInt_t entNo = 0; entNo < numEnt; ++entNo ) {
660  fRowKeys.push_back(res->GetTableRow(entNo));
661  }
662  }
663  }
664 
665 // Now that the row look-up table has been built the natural index
666 // look-up table can be filled in.
667  this->BuildLookUpTable();
668 
669 // Set aggregate number to -1 to show that it has multiple aggregates
670  vRec.SetAggregateNo(-1);
671  SetValidityRec(vRec);
672 
673  cout
674  << "Aggregate contains " << fSize << " entries. vRec:-" << endl
675  << vRec << endl;
676 
677  cout << "Created aggregated result set no. of rows: "
678  << this->GetNumRows() << endl;
679 
680 }
682 {
683 
684  for ( ConstResultItr_t itr = fResults.begin();
685  itr != fResults.end();
686  ++itr) if ( *itr ) { (*itr)->Disconnect(); }
687 
688 }
689 //.....................................................................
690 
692 {
693 //
694 //
695 // Purpose: Create a key that corresponds to this result.
696 // Caller must take ownership.
697 
698  FairDbResultKey* key = 0;
699  for ( ConstResultItr_t itr = fResults.begin();
700  itr != fResults.end();
701  ++itr ) {
702  const FairDbResult* result = *itr;
703  if ( result ) {
704  // Create key from first result.
705  if ( ! key ) { key = result->CreateKey(); }
706  // Extend key from the remainder.
707  else {
708  const FairDbValidityRec& vrec = result->GetValidityRec();
709  key->AddVRecKey(vrec.GetSeqNo(),vrec.GetCreationDate());
710  }
711  }
712  }
713 
714 // Should not have an empty set, but just in case.
715  if ( ! key ) { key = new FairDbResultKey(); }
716 
717  return key;
718 
719 }
720 
722 {
723 
724  return ( row >= fRowKeys.size() ) ? 0 : fRowKeys[row];
725 
726 }
727 
728 
730  const FairDbTableRow* row) const
731 {
732 
733  if ( ! row ) { return this->GetValidityRecGlobal(); }
734  FairDbResult* owner = row->GetOwner();
735  return owner ? owner->GetValidityRecGlobal() : this->GetValidityRecGlobal();
736 
737 }
738 
739 Bool_t FairDbResultAgg::Satisfies(const string& sqlQualifiers)
740 {
741  cout
742  << "Trying to satisfy: SQL: " << sqlQualifiers
743  << "\n with CanReuse: " << this->CanReuse()
744  << " sqlQualifiers: " << this->GetSqlQualifiers()
745  << endl;
746  return this->CanReuse()
747  && this->GetSqlQualifiers() == sqlQualifiers;
748 }
749 
751 {
752 
753  vector<const FairDbResult*>::const_iterator itr = fResults.begin();
754  vector<const FairDbResult*>::const_iterator end = fResults.end();
755 
756  UInt_t numNonAgg = 0;
757  for (; itr != end; ++itr) {
758  const FairDbResultNonAgg* rna = dynamic_cast<const FairDbResultNonAgg*>(*itr);
759  if ( rna && ! rna->GetValidityRecGlobal().IsGap() ) { ++numNonAgg; }
760  }
761  bf << numNonAgg;
762 
763 
764  for (itr = fResults.begin(); itr != end; ++itr) {
765  const FairDbResultNonAgg* rna = dynamic_cast<const FairDbResultNonAgg*>(*itr);
766  if ( rna && ! rna->GetValidityRecGlobal().IsGap() ) { bf << *rna; }
767  }
768 }
769 
770 
771 
772 
773 
774 //------------------------------------- FairDbResult Generic Implemenation --------------//
775 
776 
777 ClassImp(FairDbResult)
778 
779 Int_t FairDbResult::fgLastID(0);
780 
781 FairDbBinaryFile& operator<<(FairDbBinaryFile& bf, const FairDbResult& res)
782 {
783 // Writing is a const operation, but uses a non-const method, so cast away const.
784  FairDbResult& res_tmp = const_cast< FairDbResult&>(res);
785  res_tmp.Streamer(bf);
786  return bf;
787 }
788 
789 
791 {
792 
793  res.Streamer(bf);
794  return bf;
795 }
796 
797 
799  const FairDbValidityRec* vrec,
800  const string& sqlQualifiers) :
801  fID(++fgLastID),
802  fCanReuse(kTRUE),
803  fEffVRec(0),
804  fIndexKeys(),
805  fKey(0),
806  fResultsFromDb(kFALSE),
807  fNumClients(0),
808  fTableName("Unknown"),
809  fSqlQualifiers(sqlQualifiers),
810  fExceptionLog()
811 {
812 
813  if ( vrec ) { fEffVRec = *vrec; }
814  if ( resultSet ) { fTableName = resultSet->TableNameTc(); }
815 
816 }
817 
818 FairDbResult::FairDbResult(const FairDbResult& from)
819  : fID(from.fID),
820  fCanReuse(from.fCanReuse),
821  fEffVRec(from.fEffVRec),
822  fIndexKeys(from.fIndexKeys),
823  fKey(from.fKey),
824  fResultsFromDb(from.fResultsFromDb),
825  fNumClients(from.fNumClients),
826  fTableName(from.fTableName),
827  fSqlQualifiers(from.fSqlQualifiers),
828  fExceptionLog(from.fExceptionLog)
829 {
830  //TODO: should fKey be a deep copy???
831 
832 }
833 
835 {
836  if ( fNumClients ) {
837  cout << "Warning: Destroying FairDbResult with " << fNumClients
838  << " clients " << endl;
839  }
840 
841  this->DeRegisterKey();
842 
843 }
844 
845 void FairDbResult::CaptureExceptionLog(UInt_t startFrom)
846 {
847 
850 
851 }
852 
853 
854 
855 
856 
857 
859 {
860  Bool_t duplicatesOK = this->IsExtendedContext();
861 
862  cout << "Building look-uptable. Allow duplicates: "
863  << duplicatesOK << endl;
864 
865  for ( Int_t rowNo = this->GetNumRows()-1;
866  rowNo >= 0;
867  --rowNo ) {
868  const FairDbTableRow* row = this->GetTableRow(rowNo);
869  UInt_t index = row->GetIndex(rowNo);
870 // Ensure we use this class's GetTableRowByIndex, the method is
871 // virtual but if the subclass has called this method then it must
872 // be the right one to use. [Actually FairDbResultAgg overrides
873 // GetTableRowByIndex, but only to make building lazy].
874  const FairDbTableRow* row2 = this->FairDbResult::GetTableRowByIndex(index);
875 
876  cout
877  << "Look-up. Row no " << rowNo
878  << " index " << index
879  << " row,row2 " << (void*) row << "," << (void*) row2 << endl;
880 
881  if ( row2 != 0 && row2 != row && ! duplicatesOK ) {
882  std::ostringstream msg;
883  msg << "Duplicated row natural index: " << index
884  << " Found at row " << rowNo
885  << " of table " << this->TableName()
886  << ":-\n index of agg " << row->GetAggregateNo();
887  if ( row->GetOwner() ) { msg << "(SEQNO " << row->GetOwner()->GetValidityRec(row).GetSeqNo() << ")"; }
888  msg << " matches agg " << row2->GetAggregateNo();
889  if ( row2->GetOwner() ) { msg << "(SEQNO " << row2->GetOwner()->GetValidityRec(row2).GetSeqNo() << ")"; }
890  cout << msg.str() << endl;
891  }
892 
893  else { fIndexKeys[index] = row; }
894  }
895 
896 }
897 
898 
899 Bool_t FairDbResult::CanDelete(const FairDbResult* res)
900 {
901  if ( res
902  && this->CanReuse()
903  && this->GetValidityRec().HasExpired(res->GetValidityRec())
904  ) { this->SetCanReuse(kFALSE); }
905 
906  return ! this->GetNumClients() && ! this->CanReuse();
907 }
908 
910 {
911 
912  if ( ! fKey ) { return; }
913 
914 // FairDbRecord* record = FairDbServices::GetRecord();
915 // if ( ! record ) {
916 // cout << "Attempting to deregister FairDbResultKey at " << (void*) fKey
917 // << " but owning FairDbRecord cannot be found." << endl;
918 // }
919 // else {
920 // record->DeleteKey(fKey);
921 // fKey = 0;
922 // }
923 
924 }
926 {
927 
929 
930 }
931 
933 {
934  IndexToRow_t::const_iterator idx = fIndexKeys.find(index);
935  return ( idx == fIndexKeys.end() ) ? 0 : (*idx).second;
936 
937 }
938 
940 {
941  if ( fKey || this->GetNumRows() == 0) { return; }
942 
943 // FairDbRecord* record = FairDbServices::GetRecord();
944 // if ( ! record ) {
945 // cout << "cannot create and register key"
946 // << ", owning FairDbRecord cannot be found." << endl;
947 // }
948 // else {
949  FairDbResultKey* key = this->CreateKey();
950 // record->AdoptKey(key);
951  fKey = key;
952 // }
953 
954 }
955 
956 
957 
958 
959 
960 
961 
963  const FairDb::Task& task)
964 {
965 
966  Bool_t isExtendedContext = this->IsExtendedContext();
967  Bool_t canReuse = this->CanReuse();
968  Bool_t isCompatible = this->GetValidityRec().IsCompatible(vc,task);
969  Bool_t hasExpired = this->GetValidityRec().HasExpired(vc,task);
970  UInt_t numClients = this->GetNumClients();
971  cout
972  << " Checking result with FairDbValidityRec:- \n " << this->GetValidityRec()
973  << " With extended context: " << isExtendedContext
974  << " CanReuse: " << canReuse
975  << " Is Compatible: " << isCompatible
976  << " HasExpired: " << hasExpired
977  << " number of clients: " << numClients
978  << endl;
979 
980  if ( isExtendedContext ) { return kFALSE; }
981 
982  if ( canReuse && isCompatible ) { return kTRUE; }
983 
984 // If the query would be satisfied apart from the date, then
985 // assume we have moved out of the validity window, never
986 // to return!
987 
988  if ( canReuse && hasExpired && numClients == 0 ) {
989  cout << " Marking result as not reusable" << endl;
990  this-> SetCanReuse(kFALSE);
991  }
992 
993  return kFALSE;
994 
995 }
996 
998 {
999 
1000  if ( file.IsReading() ) {
1001  cout << " Restoring FairDbResult ..." << endl;
1002  file >> fCanReuse;
1003  fEffVRec.Streamer(file);
1004  cout << " Restored " << fEffVRec << endl;
1005  fResultsFromDb = kFALSE;
1006  fNumClients = 0;
1007  file >> fTableName;
1008  cout << " Restored string " << fTableName << endl;
1009  } else if ( file.IsWriting() ) {
1010  cout << " Saving FairDbResult ..." << endl;
1011  file << fCanReuse;
1012  cout << " Saving " << fEffVRec << endl;
1013  fEffVRec.Streamer(file);
1014  cout << " Saving string " << fTableName << endl;
1015  file << fTableName;
1016  }
1017 }
1018 
1019 
1021 
1023  const FairDbTableRow* tableRow,
1024  const FairDbValidityRec* vrec,
1025  Bool_t dropSeqNo,
1026  const string& sqlQualifiers)
1027  : FairDbResult(resultSet,vrec,sqlQualifiers),
1028  fRows(),
1029  fBuffer(NULL)
1030 {
1031  this->DebugCtor();
1032 
1033  if ( ! resultSet || resultSet->IsExhausted() || ! tableRow ) { return; }
1034 
1035  if ( vrec ) { FairDbTimerManager::gTimerManager.RecFillAgg(vrec->GetAggregateNo()); }
1036 
1037 //Move to first row if result set not yet started.
1038  FairDbResultSet& rs = *resultSet;
1039  if ( rs.IsBeforeFirst() ) { rs.FetchRow(); }
1040  if ( rs.IsExhausted() ) { return; }
1041 
1042 //Check and load sequence number if necessary.
1043  Int_t seqNo = 0;
1044  if ( dropSeqNo && rs.CurColName() == "SEQNO" ) {
1045  rs >> seqNo;
1046  rs.DecrementCurCol();
1047  }
1048 
1049 // Check for ROW_COUNTER (which has to be ignored when reading).
1050  bool hasRowCounter = rs.HasRowCounter();
1051 
1052 // Create and fill table row object and move result set onto next row.
1053 
1054  while ( ! rs.IsExhausted() ) {
1055 
1056 // If stripping off sequence numbers check the next and quit,
1057 // having restored the last, if it changes.
1058  if ( seqNo != 0 ) {
1059  Int_t nextSeqNo;
1060  rs >> nextSeqNo;
1061  if ( nextSeqNo != seqNo ) {
1062  rs.DecrementCurCol();
1063  break;
1064  }
1065  }
1066 
1067 // Strip off ROW_COUNTER if present.
1068  if ( hasRowCounter ) { rs.IncrementCurCol(); }
1069  FairDbTableRow* row = tableRow->CreateTableRow();
1071  row->SetOwner(this);
1072  row->Fill(rs,vrec);
1074  fRows.push_back(row);
1075  rs.FetchRow();
1077  }
1078 
1079  //Flag that data was read from Database.
1080  this->SetResultsFromDb();
1081  if ( seqNo == 0 )
1082  cout << "Created unaggregated VAL result set no. of rows: "
1083  << this->GetNumRows() << endl;
1084  else cout << "Created unaggregated result set for SeqNo: " << seqNo
1085  << " no. of rows: " << this->GetNumRows() << endl;
1086 
1087 }
1088 
1089 
1091 {
1092 
1093  if ( ! fBuffer ) for ( vector<FairDbTableRow*>::iterator itr = fRows.begin();
1094  itr != fRows.end();
1095  ++itr) { delete *itr; }
1096  else {
1097  delete [] fBuffer;
1098  fBuffer = 0;
1099  }
1100 }
1101 
1103 {
1104 
1105  string rowName("empty_table");
1106  const FairDbTableRow* row = this->GetTableRow(0);
1107  if ( row ) { rowName = row->GetName(); }
1108  const FairDbValidityRec& vrec = this->GetValidityRec();
1109  return new FairDbResultKey(this->TableName(),
1110  rowName,
1111  vrec.GetSeqNo(),
1112  vrec.GetCreationDate() );
1113 
1114 }
1116 {
1117  static const FairDbResultNonAgg* that = 0;
1118  if ( this == that ) {
1119  cout << "debug " << (void*) this << endl;
1120  }
1121 }
1122 //.....................................................................
1123 
1125 {
1126  if ( rowNum >= fRows.size() ) { return 0; }
1127  return fRows[rowNum];
1128 }
1130 {
1131 
1132  if ( ! this->LookUpBuilt() ) { this->BuildLookUpTable(); }
1133 
1134  return this->FairDbResult::GetTableRowByIndex(index);
1135 
1136 }
1137 Bool_t FairDbResultNonAgg::Owns(const FairDbTableRow* row ) const
1138 {
1139  vector<FairDbTableRow*>::const_iterator itr = fRows.begin();
1140  vector<FairDbTableRow*>::const_iterator itrEnd = fRows.end();
1141 
1142  for (; itr != itrEnd; ++itr) if ( *itr == row ) { return kTRUE; }
1143 
1144  return kFALSE;
1145 
1146 
1147 }
1148 
1150  const string& sqlQualifiers)
1151 {
1152  cout << "Trying to satisfy: Vrec " << vrec << " SQL: " << sqlQualifiers
1153  << "\n with CanReuse: " << this->CanReuse()
1154  << " vrec: " << this->GetValidityRec()
1155  << " sqlQualifiers: " << this->GetSqlQualifiers()
1156  << endl;
1157 
1158  if ( this->CanReuse() ) {
1159  const FairDbValidityRec& this_vrec = this->GetValidityRec();
1160  if ( sqlQualifiers == this->GetSqlQualifiers()
1161  && vrec.GetSeqNo() == this_vrec.GetSeqNo()
1162  && vrec.GetCreationDate() == this_vrec.GetCreationDate()
1163  ) { return kTRUE; }
1164  }
1165 
1166  return kFALSE;
1167 
1168 }
1170 {
1171 
1172  if ( file.IsReading() ) {
1173  this->FairDbResult::Streamer(file);
1174  cout << " Restoring FairDbResultNonAgg ..." << endl;
1175  file >> fRows;
1176 // Take ownership of the memory holding the array.
1177  fBuffer = file.ReleaseArrayBuffer();
1178  this->BuildLookUpTable();
1179  cout << " Restored FairDbResultNonAgg. Size:"
1180  << fRows.size() << " rows" << endl;
1181  } else if ( file.IsWriting() ) {
1182  this->FairDbResult::Streamer(file);
1183  cout << " Saving FairDbResultNonAgg. Size:"
1184  << fRows.size() << " rows" << endl;
1185  file << fRows;
1186  }
1187 }
1188