Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TSQLResultSet.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TSQLResultSet.cxx
1 // $Id: TSQLResultSet.cxx,v 1.1.1.1 2004/02/18 20:58:02 dave Exp $
2 //*-- Author : Valeriy Onuchin 14/02/2000
3 //
4 
6 //
7 // A TSQLResultSet provides access to a table of data. A
8 // TSQLResultSet object is usually generated by executing
9 // TSQLStatement.
10 //
11 // A TSQLResultSet maintains a cursor pointing to its current row
12 // of data. Initially the cursor is positioned before the first
13 // row. The Next() method moves the cursor to the next row.
14 //
15 // The GetXXX methods retrieve column values for the current row.
16 // You can retrieve values using either the index number of the
17 // column or the name of the column. In general,using the column
18 // index will be more efficient. Columns are numbered from 1.
19 //
20 // For maximum portability, TSQLResultSet columns within each row
21 // should be read in left-to-right order and each column should be
22 // read only once.
23 //
24 // For the GetXXX methods, the driver attempts to convert the
25 // underlying data to the specified ROOT type and returns a suitable
26 // value. See the specification for allowable mappings
27 // from SQL types to ROOT types with the TSQLResultSet::GetXXX
28 // methods.
29 //
30 // Column names used as input to GetXXX methods are case
31 // insensitive. When performing a GetXXX using a column name,
32 // if several columns have the same name, then the value of the
33 // first matching column will be returned. The column name option
34 // is designed to be used when column names are used in the SQL
35 // query. For columns that are NOT explicitly named in the query,
36 // it is best to use column numbers. If column names are used, there
37 // is no way for the programmer to guarantee that they actually refer
38 // to the intended columns.
39 //
40 // A TSQLResultSet is automatically closed by the TSQLStatement that
41 // generated it when that TSQLStatement is closed, re-executed,
42 // or used to retrieve the next result from a sequence of multiple
43 // results.
44 //
45 // The number, types and properties of a TSQLResultSet's columns are
46 // provided by the TSQLResulSetMetaData object returned by the
47 // GetMetaData() method.
48 //
49 // See also:
50 // TSQLStatement::ExecuteQuery(const TString&),
51 // TSQLStatement::GetResultSet(), TSQLResultSetMetaData
52 //
53 //___________________________________________________________________
54 //
55 // kCONCUR_READ_ONLY
56 //
57 // The concurrency mode for a TSQLResultSet object that may
58 // NOT be updated.
59 //___________________________________________________________________
60 //
61 // kCONCUR_UPDATABLE
62 //
63 // The concurrency mode for a TSQLResultSet
64 // object that may be updated.
65 //___________________________________________________________________
66 //
67 // kFETCH_FORWARD
68 //
69 // The rows in a result set will be
70 // processed in a forward direction; first-to-last.
71 //___________________________________________________________________
72 //
73 // kFETCH_REVERSE
74 //
75 // The rows in a result set will be
76 // processed in a reverse direction; last-to-first.
77 //___________________________________________________________________
78 //
79 // kFETCH_UNKNOWN
80 //
81 // The order in which rows in a result set
82 // will be processed is unknown.
83 //___________________________________________________________________
84 //
85 // kTYPE_FORWARD_ONLY
86 //
87 // The type for a TSQLResultSet object whose
88 // cursor may move only forward.
89 //___________________________________________________________________
90 //
91 // kTYPE_SCROLL_INSENSITIVE
92 //
93 // The type for a TSQLResultSet object that is
94 // scrollable but generally not sensitive to changes made by
95 // others.
96 //___________________________________________________________________
97 //
98 // kTYPE_SCROLL_SENSITIVE
99 //
100 // The type for a TSQLResultSet object that is
101 // scrollable and generally sensitive to changes made by
102 // others.
103 //
105 
106 #include <RDBC/TSQLResultSet.h>
108 #include <RDBC/TSQLStatement.h>
109 #include <TList.h>
110 #include <TTree.h>
111 #include <TBranch.h>
112 #include <ctype.h>
113 #include <time.h>
114 #include <iostream>
115 using std::cout;
116 using std::endl;
117 #include <stdlib.h>
118 
120 
121 
122 //___________________________________________________________________
123 TSQLResultSet::TSQLResultSet(TSQLStatement* stmt,void* imp):TSQL(imp)
124 {
125  // ctor
126 
127  fStatement = stmt;
128  fRow = 0;
129  fMetaData = 0;
130 }
131 
132 //___________________________________________________________________
134 {
135  // dtor
136 
137  fRow = 0;
138  fMetaData = 0;
139 }
140 
141 //___________________________________________________________________
143 {
144  // Get number of fields(aka columns) in result.
145 
146  return fMetaData->GetColumnCount();
147 }
148 
149 //___________________________________________________________________
150 const char* TSQLResultSet::GetFieldName(Int_t field)
151 {
152  // Get name of specified field( aka column ).
153 
154  return (const char*)fMetaData->GetColumnName(field);
155 }
156 
157 //___________________________________________________________________
158 void TSQLResultSet::Close(const Option_t * /* option */)
159 {
160  // Releases this TSQLResultSet object's database and resources
161  // immediately instead of waiting for this to happen when it is
162  // automatically closed.
163  //
164  // Note: A TSQLResultSet is automatically closed by the
165  // statement that generated it when that statement
166  // is closed, re-executed, or is used to retrieve the next
167  // result from a sequence of multiple results. A TSQLResultSet
168  // is also automatically closed when it is garbage collected.
169  //
170  // Throws:
171  // TSQLException - if a database access error occurs
172 
173  fMetaData = 0;
174  fRow = 0;
175  fImp = 0;
176  Destroyed();
177 }
178 
180 //___________________________________________________________________
181 TString GetValueFromOption(const TString& pattern,const TString& option)
182 {
183  // internal use func.
184 
185  Ssiz_t t1,t2;
186  const char* tmp;
187 
188  TString stropt = option;
189  stropt.ReplaceAll(" ",""); // strip blanks
190  stropt.ToLower();
191 
192  t1 = stropt.Index(pattern.Data());
193  t1 = t2 = stropt.Index("=",t1) + 1;
194  TString str = stropt(t1,1024); //
195  tmp = str.Data();
196 
197  for(int i=0;isdigit(tmp[i])!=0;i++) t2=i+1;
198  str = stropt(t1,t2);
199  return str;
200 }
201 
202 //___________________________________________________________________
203 void SaveAsCSV(TSQLResultSet* rs,const TString& filename)
204 {
205  // Auxilary function for saving content of the result set
206  // in ASCI file in CSV format
207 
208  TString colname;
209  TString tmpstr;
210  TString str;
211  FILE* fd;
212 
213  if( (fd=fopen(filename.Data(),"w")) == NULL ) {
214  return;
215  }
216 
218  Int_t ncollumns = md->GetColumnCount();
219  Int_t type;
220 
221  for( int i=1; i <= ncollumns; ++i ) {
222  type = md->GetColumnType(i);
223  colname = md->GetColumnName(i);
224 
225  switch( type ) {
226  case kCHAR:
227  case kVARCHAR:
228  break;
229  case kINTEGER:
230  break;
231  case kDATE:
232  case kTIME:
233  case kTIMESTAMP:
234  break;
235  case kBIT:
236  case kTINYINT:
237  case kSMALLINT:
238  break;
239  case kREAL:
240  break;
241  case kLONGVARCHAR:
242  case kLONGVARBINARY:
243  case kVARBINARY:
244  break;
245  case kBIGINT:
246  case kDECIMAL:
247  case kNUMERIC:
248  case kDOUBLE:
249  case kFLOAT:
250  default:
251  break;
252  }
253  }
254 
255  // write data in CSV format
256 
257  while ( rs->Next() ) {
258  str = ""; // clear
259 
260  for(int i=1; i<ncollumns+1; i++) {
261  type = md->GetColumnType(i); // slowdown?
262 
263  switch(type) {
264  case kVARCHAR:
265  case kLONGVARCHAR:
266  tmpstr = rs->GetString(i);
267 // if(!tmpstr.IsNull()) tmpstr = '\"' + tmpstr + '\"'; // put quotas around field
268  break;
269  case kLONGVARBINARY:
270  case kVARBINARY:
271  tmpstr="";
272  break;
273  default:
274  tmpstr = rs->GetString(i);
275  break;
276  }
277 
278  str += tmpstr;
279  if(i<ncollumns) str += ",";
280  }
281  str += "\n";
282  fputs(str.Data(),fd);
283  }
284  fclose(fd);
285 }
286 
287 //___________________________________________________________________
288 void TSQLResultSet::Print(Option_t *option) const
289 {
290  // Print a resultset contents
291  //
292  // The following options are valid:
293  //
294  // begin=nnn - start print from #nnn'th row, for example Print("begin=100")
295  // end=nnn - end print at #nnn'th row, for example Print("begin=100 end=1000")
296  // nrows=nnn - print #nnn rows, for example Print("begin=100 nrows=1000")
297  // file=filename - save content as CSV file, for example Print("file=result.csv")
298 
299  TSQLResultSet* th = (TSQLResultSet*)this;
300 
301  if(!fImp) {
302  Warning("Print()","TSQLResultSet is destroyed\n");
303  th->Throw(new TSQLException("TSQLResultSet is destroyed"));
304  th->Destroyed();
305  return;
306  }
307 
308  TString str;
309  TString stropt = option;
310 
311  if(stropt.Contains("file")) {
312  str = GetValueFromOption("file",stropt); // extract filename
313  SaveAsCSV(th,str.Data());
314  return;
315  }
316 
317  TString colname;
318  Int_t ds;
319  Int_t dl;
320  Int_t* nn;
321  Int_t* pd1;
322  Int_t pd2;
323  Int_t save_row = th->GetRow();
324  Int_t cur_row;
325  Int_t nr = 0;
326 
327  Int_t srow = save_row; // start from srow, default is current
328  Int_t nrows = -1; // -1 - stand for "all rows"
329  Int_t erow = -1; // -1 - stand for "to the last row"
330 
331  stropt.ToLower();
332 
333  if(stropt.Contains("begin")) {
334  str = GetValueFromOption("begin",stropt);
335  srow = atoi(str.Data());
336  }
337 
338  if (stropt.Contains("end")) {
339  str = GetValueFromOption("end",stropt);
340  erow = atoi(str.Data());
341  }
342 
343  if (stropt.Contains("nrows")) {
344  str = GetValueFromOption("nrows",stropt);
345  nrows = atoi(str.Data());
346  }
347 
348  Int_t ncols = fMetaData->GetColumnCount();
349 
350  nn = new Int_t[ncols+1];
351  pd1 = new Int_t[ncols+1];
352 
353  for(int i=1; i<ncols+1; i++) {
354  colname = fMetaData->GetColumnName(i);
356  dl = colname.Length() + 2;
357  nn[i] = dl > ds ? dl : ds;
358  pd1[i] = nn[i]-dl;
359  }
360 
361  //
362  for(int i=1; i<ncols+1; i++) {
363  cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
364  } cout << endl;
365 
366  for(int i=1; i<ncols+1; i++) {
367  colname = fMetaData->GetColumnName(i);
368  cout << "| " << colname << " ";
369  cout.fill(' '); cout.width(pd1[i]+1); cout << "|";
370  } cout << endl;
371 
372  //
373  for(int i=1; i<ncols+1; i++) {
374  cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
375  } cout << endl;
376 
377  cur_row = th->GetRow();
378 
379  if(fStatement) {
381  th->Absolute(srow-1);
382  } else {
383  if(srow>cur_row) {
384  while ( th->Next() && cur_row+2 < srow) cur_row = th->GetRow();
385  }
386  }
387  }
388 
389  nr = 0;
390  cur_row = th->GetRow();
391 
392  while ( th->Next() ) {
393 
394  if(nrows > 0 && nr >= nrows) break;
395  if(erow > 0 && cur_row >= erow ) break;
396  nr++;
397  cur_row = th->GetRow();
398 
399  for(int i=1; i<ncols+1; i++) {
400  str = th->GetString(i);
401  cout << "| " << str;
402  pd2 = nn[i] - str.Length();
403  cout.fill(' '); cout.width(pd2); cout << "|";
404  } cout << endl;
405  }
406 
407  for(int i=1; i<ncols+1; i++) {
408  cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
409  } cout << endl;
410 
411  if(fStatement) {
413  th->Absolute(save_row);
414  } else {
415  Warning("Print","To set cursor to initial position -> re-execute Query.");
416  }
417  }
418  delete [] nn;
419  delete [] pd1;
420 }
421 
422 //___________________________________________________________________
423 TTree* TSQLResultSet::Tree(Int_t begin,Int_t end)
424 {
425  // Writes resultset content to ROOT tree
426  //
427  // This method creates "new TTree".
428  // To avoid memory leakage it should be deleted if not used.
429  //
430  // See also TTree
431  //
432  // Comment: this method is experimental nad buggy
433 
434  TString leafList; // leaf description string
435  TString clmname; // column name
436 
437  Int_t siz = 0;
438  Int_t ncollumns = 0;
439  char* buf = 0;
440  Int_t type,offset,prec;
441  TString str;
442  char tmpstr[40];
443 
444  Int_t intg = 0;
445  Short_t shrt = 0;
446  Float_t flt = 0;
447  Double_t dbl = 0;
448  Int_t yy, mm, dd, hh, mi, ss;
449  UInt_t t =0;
450  struct tm tp;
451  Int_t save_row = GetRow();
452  Int_t cur_row =0;
453 
454  Int_t srow = begin > 0 ? begin : save_row;
455  Int_t erow = end > 0 ? end : -1;
456  Int_t tmp = 0;
457 
458  if(srow>erow) {
459  tmp = erow;
460  erow = srow;
461  srow = tmp;
462  }
463 
464  // calculate "leaf buffer" size
465  ncollumns = fMetaData->GetColumnCount();
466 
467  for( int i=1; i <= ncollumns; ++i ) {
468  type = fMetaData->GetColumnType(i);
469 
470  switch( type ) {
471  case kCHAR:
472  case kVARCHAR:
473  siz += fMetaData->GetPrecision(i)+1; // length + zero
474  break;
475  case kINTEGER:
476  siz += sizeof(Int_t);
477  break;
478  case kDATE:
479  case kTIME:
480  case kTIMESTAMP:
481  siz += sizeof(UInt_t);
482  break;
483  case kBIT:
484  case kTINYINT:
485  case kSMALLINT:
486  siz += sizeof(Short_t);
487  break;
488  case kREAL:
489  siz += sizeof(Float_t);
490  break;
491  case kLONGVARCHAR: // not resolved yet how to handle
492  case kLONGVARBINARY:
493  case kVARBINARY:
494  break;
495  case kBIGINT: // convert all these types to Double_t
496  case kDECIMAL:
497  case kNUMERIC:
498  case kDOUBLE:
499  case kFLOAT:
500  default:
501  siz += sizeof(Double_t);
502  break;
503  }
504  }
505 
506  // determine leaf description string
507  for( int i=1; i <= ncollumns; ++i ) {
508  type = fMetaData->GetColumnType(i);
509  clmname = fMetaData->GetColumnName(i);
510 
511  switch( type ) {
512  case kCHAR:
513  case kVARCHAR:
514  prec = fMetaData->GetPrecision(i)+1;
515  sprintf(tmpstr,"[%d]",prec);
516  leafList += clmname + tmpstr + "/C:"; //
517  break;
518  case kINTEGER:
519  leafList += clmname + "/I:"; // signed integer
520  break;
521  case kDATE:
522  case kTIME:
523  case kTIMESTAMP:
524  leafList += clmname + "/i:"; // unsigned integer ( time_t format )
525  break;
526  case kBIT:
527  case kTINYINT:
528  case kSMALLINT:
529  leafList += clmname + "/S:"; // signed short
530  break;
531  case kREAL:
532  leafList += clmname + "/F:"; // floating point
533  break;
534  case kLONGVARCHAR: // not resolved yet how to handle
535  case kLONGVARBINARY:
536  case kVARBINARY:
537  break;
538  case kBIGINT: // convert all these types to Double_t
539  case kDECIMAL:
540  case kNUMERIC:
541  case kDOUBLE:
542  case kFLOAT:
543  default:
544  leafList += clmname + "/D:"; // double
545  break;
546  }
547  }
548  if(!leafList.IsNull()) leafList.Resize(leafList.Length()-1); // cut off last ":"
549 
550  // Dinamically allocate "leaf buffer"
551  buf = new char[siz]; // buffer
552 
553  TString tblname = fMetaData->GetTableName(1);
554 
555  if(tblname.IsNull()) { // if table name unknown => generate "random name"
556  tblname = "table";
557  sprintf(tmpstr,"%d",rand()%1000);
558  tblname += tmpstr;
559  }
560 
561  // Create a ROOT Tree
562  //
563  TTree* tree = new TTree(tblname.Data(),"Created by TSQLResultSet:Tree() method");
564 
565  tree->Branch(tblname.Data(),(void*)buf,leafList.Data());
566 
567  // skip to start
568  cur_row = GetRow();
569 
570  if(fStatement) {
572  Absolute(srow-1);
573  } else {
574  if(srow>cur_row) {
575  while ( Next() && cur_row+2 < srow) cur_row = GetRow();
576  }
577  }
578  }
579 
580  // tree filling
581  while( Next() ) { // iterate rows
582  offset = 0;
583 
584  if(erow>0 && cur_row >= erow) break;
585  cur_row = GetRow();
586 
587  for( int i=1; i <= ncollumns; ++i ) {
588  type = fMetaData->GetColumnType(i);
589 
590  switch( type ) {
591  case kCHAR:
592  case kVARCHAR:
593  siz = fMetaData->GetPrecision(i)+1;
594  str = GetString(i);
595  memcpy(&buf[offset],str.Data(),siz);
596  break;
597  case kINTEGER:
598  siz = sizeof(Int_t);
599  intg = GetInt(i);
600  memcpy(&buf[offset],&intg,siz);
601  break;
602  case kBIT:
603  case kTINYINT:
604  case kSMALLINT:
605  siz = sizeof(Short_t);
606  shrt = GetShort(i);
607  memcpy(&buf[offset],&shrt,siz);
608  break;
609  case kREAL:
610  siz = sizeof(Float_t);
611  dbl = GetFloat(i);
612  memcpy(&buf[offset],&flt,siz);
613  break;
614  case kDATE: // convert all date-times into time_t
615  case kTIME: // probably not working for kTIME
616  case kTIMESTAMP:
617  siz = sizeof(UInt_t);
618  str = GetString(i);
619  sscanf(str.Data(), "%d-%d-%d %d:%d:%d",
620  &yy, &mm, &dd, &hh, &mi, &ss);
621  tp.tm_year = yy-1900;
622  tp.tm_mon = mm;
623  tp.tm_mday = dd;
624  tp.tm_hour = hh;
625  tp.tm_min = mi;
626  tp.tm_sec = ss;
627  tp.tm_isdst = -1;
628  t = (UInt_t)mktime(&tp);
629  memcpy(&buf[offset],&t,siz);
630  break;
631  case kLONGVARCHAR: // not resolved how to handle
632  case kLONGVARBINARY:
633  case kVARBINARY:
634  break;
635  case kBIGINT: // convert all these types to Double_t
636  case kDECIMAL:
637  case kNUMERIC:
638  case kDOUBLE:
639  case kFLOAT:
640  default:
641  siz = sizeof(Double_t);
642  dbl = GetDouble(i);
643  memcpy(&buf[offset],&dbl,siz);
644  break;
645  }
646  offset += siz;
647  }
648  tree->Fill();
649  }
650 
651  delete [] buf;
652 
653  if(fStatement) {
655  Absolute(save_row);
656  } else {
657  Warning("Print","To set cursor to initial position -> re-execute Query.");
658  }
659  }
660 
661  return tree;
662 }