Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:22:06

0001 // $Id: TSQLResultSet.cxx,v 1.1.1.1 2004/02/18 20:58:02 dave Exp $
0002 //*-- Author : Valeriy Onuchin 14/02/2000 
0003 //
0004 
0005 /////////////////////////////////////////////////////////////////////
0006 //
0007 // A TSQLResultSet provides access to a table of data. A 
0008 // TSQLResultSet object is usually generated by executing 
0009 // TSQLStatement. 
0010 //
0011 // A TSQLResultSet maintains a cursor pointing to its current row 
0012 // of data. Initially the cursor is positioned before the first
0013 // row. The Next() method moves the cursor to the next row. 
0014 //
0015 // The GetXXX methods retrieve column values for the current row.
0016 // You can retrieve values using either the index number of the 
0017 // column or the name of the column. In general,using the column 
0018 // index will be more efficient. Columns are numbered from 1. 
0019 //
0020 // For maximum portability, TSQLResultSet columns within each row
0021 // should be read in left-to-right order and each column should be 
0022 // read only once. 
0023 //
0024 // For the GetXXX methods, the driver attempts to convert the
0025 // underlying data to the specified ROOT type and returns a suitable 
0026 // value. See the specification for allowable mappings 
0027 // from SQL types to ROOT types with the TSQLResultSet::GetXXX 
0028 // methods. 
0029 //
0030 // Column names used as input to GetXXX methods are case
0031 // insensitive. When performing a GetXXX using a column name, 
0032 // if several columns have the same name, then the value of the 
0033 // first matching column will be returned. The column name option 
0034 // is designed to be used when column names are used in the SQL 
0035 // query. For columns that are NOT explicitly named in the query, 
0036 // it is best to use column numbers. If column names are used, there 
0037 // is no way for the programmer to guarantee that they actually refer 
0038 // to the intended columns. 
0039 //
0040 // A TSQLResultSet is automatically closed by the TSQLStatement that 
0041 // generated it when that TSQLStatement is closed, re-executed, 
0042 // or used  to retrieve the next result from a sequence of multiple 
0043 // results. 
0044 //
0045 // The number, types and properties of a TSQLResultSet's columns are
0046 // provided by the TSQLResulSetMetaData object returned by the 
0047 // GetMetaData() method. 
0048 //
0049 // See also: 
0050 //      TSQLStatement::ExecuteQuery(const TString&),
0051 //      TSQLStatement::GetResultSet(), TSQLResultSetMetaData
0052 //
0053 //___________________________________________________________________
0054 //
0055 //       kCONCUR_READ_ONLY 
0056 //
0057 // The concurrency mode for a TSQLResultSet object that may 
0058 // NOT be updated.
0059 //___________________________________________________________________
0060 //
0061 //       kCONCUR_UPDATABLE 
0062 //
0063 //  The concurrency mode for a TSQLResultSet
0064 //  object that may be updated.
0065 //___________________________________________________________________
0066 //
0067 //       kFETCH_FORWARD 
0068 //
0069 // The rows in a result set will be
0070 // processed in a forward direction; first-to-last.
0071 //___________________________________________________________________
0072 //
0073 //       kFETCH_REVERSE 
0074 //
0075 // The rows in a result set will be
0076 // processed in a reverse direction; last-to-first.
0077 //___________________________________________________________________
0078 //
0079 //       kFETCH_UNKNOWN 
0080 //
0081 // The order in which rows in a result set
0082 // will be processed is unknown.
0083 //___________________________________________________________________
0084 //
0085 //       kTYPE_FORWARD_ONLY 
0086 //
0087 // The type for a TSQLResultSet object whose
0088 // cursor may move only forward.
0089 //___________________________________________________________________
0090 //
0091 //       kTYPE_SCROLL_INSENSITIVE 
0092 //
0093 // The type for a TSQLResultSet object that is
0094 // scrollable but generally not sensitive to changes made by
0095 // others.
0096 //___________________________________________________________________
0097 //
0098 //       kTYPE_SCROLL_SENSITIVE 
0099 // 
0100 // The type for a TSQLResultSet object that is
0101 // scrollable and generally sensitive to changes made by
0102 // others.
0103 //
0104 /////////////////////////////////////////////////////////////////////
0105  
0106 #include <RDBC/TSQLResultSet.h>
0107 #include <RDBC/TSQLResultSetMetaData.h>
0108 #include <RDBC/TSQLStatement.h>
0109 #include <TList.h>
0110 #include <TTree.h>
0111 #include <TBranch.h>
0112 #include <ctype.h>
0113 #include <time.h>
0114 #include <iostream>
0115 using std::cout;
0116 using std::endl;
0117 #include <stdlib.h>
0118 
0119 ClassImpQ(TSQLResultSet)
0120 
0121 /////////////////////////////////////////////////////////////////////
0122 //___________________________________________________________________
0123 TSQLResultSet::TSQLResultSet(TSQLStatement* stmt,void* imp):TSQL(imp)
0124 {
0125    // ctor
0126    
0127    fStatement = stmt;
0128    fRow = 0;
0129    fMetaData = 0;
0130 }                             
0131 
0132 //___________________________________________________________________
0133 TSQLResultSet::~TSQLResultSet()
0134 {
0135    // dtor
0136 
0137    fRow = 0;
0138    fMetaData = 0;
0139 }
0140 
0141 //___________________________________________________________________
0142 Int_t TSQLResultSet::GetFieldCount()
0143 {
0144    // Get number of fields(aka columns) in result.
0145 
0146    return fMetaData->GetColumnCount();
0147 }
0148 
0149 //___________________________________________________________________
0150 const char* TSQLResultSet::GetFieldName(Int_t field)
0151 {
0152    // Get name of specified field( aka column ).
0153 
0154    return (const char*)fMetaData->GetColumnName(field);
0155 }
0156 
0157 //___________________________________________________________________
0158 void TSQLResultSet::Close(const Option_t * /* option */)
0159 {
0160    // Releases this TSQLResultSet object's database and resources
0161    // immediately instead of waiting for this to happen when it is 
0162    // automatically closed. 
0163    //
0164    // Note: A TSQLResultSet is automatically closed by the 
0165    // statement that generated it when that statement 
0166    // is closed, re-executed, or is used to retrieve the next
0167    // result from a sequence of multiple results. A TSQLResultSet 
0168    // is also automatically closed when it is garbage collected.
0169    //
0170    //  Throws:
0171    //       TSQLException - if a database access error occurs
0172  
0173    fMetaData = 0;   
0174    fRow = 0;
0175    fImp = 0;
0176    Destroyed();
0177 }
0178 
0179 //////////////////////// Print utility //////////////////////////////
0180 //___________________________________________________________________
0181 TString GetValueFromOption(const TString& pattern,const TString& option)
0182 {
0183    // internal use func.
0184 
0185    Ssiz_t t1,t2;    
0186    const char* tmp;
0187 
0188    TString stropt = option; 
0189    stropt.ReplaceAll(" ",""); // strip blanks
0190    stropt.ToLower();
0191 
0192    t1 = stropt.Index(pattern.Data());
0193    t1 = t2 = stropt.Index("=",t1) + 1;
0194    TString str = stropt(t1,1024); // 
0195    tmp = str.Data();
0196  
0197    for(int i=0;isdigit(tmp[i])!=0;i++) t2=i+1;
0198    str = stropt(t1,t2);
0199    return str; 
0200 }
0201 
0202 //___________________________________________________________________
0203 void SaveAsCSV(TSQLResultSet* rs,const TString& filename)
0204 {
0205    // Auxilary function for saving content of the result set 
0206    // in ASCI file in CSV format
0207 
0208    TString colname;
0209    TString tmpstr;
0210    TString str;
0211    FILE* fd;
0212    
0213    if( (fd=fopen(filename.Data(),"w")) == NULL ) {
0214       return;
0215    }
0216 
0217    TSQLResultSetMetaData* md = rs->GetMetaData();
0218    Int_t ncollumns = md->GetColumnCount();
0219    Int_t type;
0220 
0221    for( int i=1; i <= ncollumns; ++i ) {
0222       type = md->GetColumnType(i);
0223       colname = md->GetColumnName(i);
0224       
0225       switch( type ) { 
0226       case kCHAR: 
0227       case kVARCHAR:
0228         break;
0229       case kINTEGER:
0230          break;
0231       case kDATE:
0232       case kTIME:
0233       case kTIMESTAMP:
0234          break;      
0235       case kBIT:       
0236       case kTINYINT:
0237       case kSMALLINT:
0238          break;
0239       case kREAL:
0240          break;
0241       case kLONGVARCHAR:
0242       case kLONGVARBINARY:
0243       case kVARBINARY:
0244          break;  
0245       case kBIGINT:
0246       case kDECIMAL:
0247       case kNUMERIC:
0248       case kDOUBLE:
0249       case kFLOAT:
0250       default:
0251          break;      
0252       }  
0253    }
0254 
0255    // write data in CSV format
0256 
0257    while ( rs->Next() ) {
0258       str = "";   // clear
0259 
0260       for(int i=1; i<ncollumns+1; i++) {
0261          type = md->GetColumnType(i);  // slowdown?
0262 
0263          switch(type) {
0264             case kVARCHAR:
0265             case kLONGVARCHAR:
0266                tmpstr = rs->GetString(i);
0267 //               if(!tmpstr.IsNull()) tmpstr = '\"' + tmpstr + '\"'; // put quotas around field
0268                break;
0269             case kLONGVARBINARY:
0270             case kVARBINARY:
0271                tmpstr="";
0272                break;
0273             default:
0274                tmpstr = rs->GetString(i);
0275                break;
0276          }
0277 
0278          str += tmpstr;
0279          if(i<ncollumns) str += ",";
0280       }
0281       str += "\n";
0282       fputs(str.Data(),fd);
0283    }
0284    fclose(fd);
0285 }
0286 
0287 //___________________________________________________________________
0288 void TSQLResultSet::Print(Option_t *option) const
0289 {
0290    // Print a resultset contents
0291    //
0292    // The following options are valid:
0293    //
0294    //    begin=nnn - start print from #nnn'th row, for example Print("begin=100")
0295    //    end=nnn   - end print at  #nnn'th row, for example Print("begin=100 end=1000")
0296    //    nrows=nnn - print #nnn rows, for example Print("begin=100 nrows=1000")
0297    //    file=filename - save content as CSV file, for example Print("file=result.csv")
0298 
0299    TSQLResultSet* th = (TSQLResultSet*)this;
0300 
0301    if(!fImp) {
0302       Warning("Print()","TSQLResultSet is destroyed\n");
0303       th->Throw(new TSQLException("TSQLResultSet is destroyed"));
0304       th->Destroyed();
0305       return;
0306    }
0307    
0308    TString str;
0309    TString stropt = option;
0310 
0311    if(stropt.Contains("file")) {
0312       str = GetValueFromOption("file",stropt);  // extract filename
0313       SaveAsCSV(th,str.Data());
0314       return;
0315    }
0316 
0317    TString colname;
0318    Int_t ds;
0319    Int_t dl;
0320    Int_t* nn;
0321    Int_t* pd1;
0322    Int_t pd2;
0323    Int_t save_row = th->GetRow(); 
0324    Int_t cur_row;
0325    Int_t nr = 0;
0326 
0327    Int_t srow = save_row;  // start from srow, default is current 
0328    Int_t nrows = -1; // -1 - stand for "all rows" 
0329    Int_t erow = -1;  // -1 - stand for "to the last row" 
0330 
0331    stropt.ToLower();
0332 
0333    if(stropt.Contains("begin")) {
0334       str = GetValueFromOption("begin",stropt);
0335       srow = atoi(str.Data());
0336    }
0337 
0338    if (stropt.Contains("end")) {
0339       str = GetValueFromOption("end",stropt);
0340       erow = atoi(str.Data());
0341    } 
0342 
0343    if (stropt.Contains("nrows")) {
0344       str = GetValueFromOption("nrows",stropt);
0345       nrows = atoi(str.Data());
0346    }
0347 
0348    Int_t ncols = fMetaData->GetColumnCount();
0349 
0350    nn  = new Int_t[ncols+1];
0351    pd1 = new Int_t[ncols+1];
0352 
0353    for(int i=1; i<ncols+1; i++) {
0354       colname = fMetaData->GetColumnName(i);
0355       ds = fMetaData->GetColumnDisplaySize(i)+2;
0356       dl = colname.Length() + 2;
0357       nn[i] = dl > ds ? dl : ds;
0358       pd1[i] = nn[i]-dl;
0359    }   
0360 
0361    //  
0362    for(int i=1; i<ncols+1; i++) {
0363       cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
0364    }  cout << endl;
0365 
0366    for(int i=1; i<ncols+1; i++) { 
0367       colname = fMetaData->GetColumnName(i); 
0368       cout << "| " << colname << " "; 
0369       cout.fill(' '); cout.width(pd1[i]+1); cout << "|";
0370    } cout << endl;
0371 
0372    //  
0373    for(int i=1; i<ncols+1; i++) {
0374       cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
0375    }  cout << endl;
0376 
0377    cur_row = th->GetRow();
0378 
0379    if(fStatement) {
0380       if(fStatement->GetResultSetType() != kTYPE_FORWARD_ONLY ) {
0381          th->Absolute(srow-1);
0382       } else {
0383          if(srow>cur_row) {
0384             while ( th->Next() && cur_row+2 < srow) cur_row = th->GetRow();
0385          }
0386       }
0387    }
0388 
0389    nr = 0;
0390    cur_row = th->GetRow();
0391 
0392    while ( th->Next() ) {
0393  
0394       if(nrows > 0 && nr >= nrows) break;      
0395       if(erow > 0 && cur_row >= erow ) break;
0396       nr++;
0397       cur_row = th->GetRow();
0398 
0399       for(int i=1; i<ncols+1; i++) {
0400          str = th->GetString(i);
0401          cout << "| " << str;
0402          pd2 = nn[i] - str.Length();
0403          cout.fill(' '); cout.width(pd2); cout << "|"; 
0404       }  cout << endl;
0405    }
0406 
0407    for(int i=1; i<ncols+1; i++) {
0408       cout << "+"; cout.fill('-'); cout.width(nn[i]+1); cout << "+";
0409    }  cout << endl;
0410 
0411    if(fStatement) { 
0412       if(fStatement->GetResultSetType() != kTYPE_FORWARD_ONLY ) {
0413          th->Absolute(save_row);
0414       } else {
0415          Warning("Print","To set cursor to initial position -> re-execute Query.");
0416       }
0417    }
0418    delete [] nn;
0419    delete [] pd1;
0420 }
0421 
0422 //___________________________________________________________________
0423 TTree* TSQLResultSet::Tree(Int_t begin,Int_t end)
0424 {
0425    // Writes resultset content to ROOT tree
0426    //
0427    // This method creates "new TTree". 
0428    // To avoid memory leakage it should be deleted if not used.
0429    //
0430    // See also TTree
0431    //
0432    // Comment: this method is experimental nad buggy
0433    
0434    TString leafList;    // leaf description string
0435    TString clmname;     // column name
0436 
0437    Int_t siz = 0;
0438    Int_t ncollumns = 0;
0439    char* buf = 0;
0440    Int_t type,offset,prec;
0441    TString str;
0442    char tmpstr[40];
0443 
0444    Int_t  intg = 0;
0445    Short_t shrt = 0;
0446    Float_t flt = 0;
0447    Double_t dbl = 0;
0448    Int_t yy, mm, dd, hh, mi, ss;
0449    UInt_t t =0;
0450    struct tm tp;
0451    Int_t save_row = GetRow(); 
0452    Int_t cur_row =0;
0453 
0454    Int_t srow = begin > 0 ? begin : save_row; 
0455    Int_t erow = end > 0 ? end : -1;
0456    Int_t tmp = 0;
0457 
0458    if(srow>erow) { 
0459       tmp = erow; 
0460       erow = srow;
0461       srow = tmp; 
0462    }
0463 
0464    // calculate "leaf buffer" size
0465    ncollumns = fMetaData->GetColumnCount();
0466 
0467    for( int i=1; i <= ncollumns; ++i ) {
0468       type = fMetaData->GetColumnType(i);
0469             
0470       switch( type ) { 
0471       case kCHAR: 
0472       case kVARCHAR:
0473         siz += fMetaData->GetPrecision(i)+1; // length + zero
0474         break;
0475       case kINTEGER:
0476          siz += sizeof(Int_t);
0477          break;
0478       case kDATE:
0479       case kTIME:
0480       case kTIMESTAMP:
0481          siz += sizeof(UInt_t);
0482          break;      
0483       case kBIT:       
0484       case kTINYINT:
0485       case kSMALLINT:
0486          siz += sizeof(Short_t);
0487          break;
0488       case kREAL:
0489          siz += sizeof(Float_t);
0490          break;
0491       case kLONGVARCHAR: // not resolved yet how to handle   
0492       case kLONGVARBINARY:
0493       case kVARBINARY:
0494          break;  
0495       case kBIGINT:     // convert all these types to Double_t
0496       case kDECIMAL:
0497       case kNUMERIC:
0498       case kDOUBLE:
0499       case kFLOAT:
0500       default:
0501          siz += sizeof(Double_t);
0502          break;      
0503       }  
0504    }
0505 
0506    // determine leaf description string
0507    for( int i=1; i <= ncollumns; ++i ) {
0508       type = fMetaData->GetColumnType(i);
0509       clmname = fMetaData->GetColumnName(i);
0510       
0511       switch( type ) {
0512       case kCHAR: 
0513       case kVARCHAR:
0514          prec = fMetaData->GetPrecision(i)+1;
0515          sprintf(tmpstr,"[%d]",prec);
0516          leafList += clmname + tmpstr + "/C:"; // 
0517          break;
0518       case kINTEGER:
0519          leafList += clmname + "/I:"; // signed integer 
0520          break;
0521       case kDATE:
0522       case kTIME:
0523       case kTIMESTAMP:
0524          leafList += clmname + "/i:"; // unsigned integer ( time_t format )
0525          break;
0526       case kBIT:        
0527       case kTINYINT:      
0528       case kSMALLINT:
0529          leafList += clmname + "/S:"; //  signed short        
0530          break;
0531       case kREAL:
0532           leafList += clmname + "/F:"; // floating point
0533          break;
0534       case kLONGVARCHAR: // not resolved yet how to handle   
0535       case kLONGVARBINARY:
0536       case kVARBINARY: 
0537          break;         
0538       case kBIGINT:     // convert all these types to Double_t
0539       case kDECIMAL:
0540       case kNUMERIC:          
0541       case kDOUBLE:
0542       case kFLOAT:
0543       default:
0544          leafList += clmname + "/D:"; // double
0545          break;
0546       }
0547    }  
0548    if(!leafList.IsNull()) leafList.Resize(leafList.Length()-1);   // cut off last ":"
0549 
0550    //  Dinamically allocate  "leaf buffer"  
0551    buf = new char[siz]; // buffer
0552 
0553    TString tblname =  fMetaData->GetTableName(1);
0554 
0555    if(tblname.IsNull()) { // if table name unknown => generate "random name" 
0556       tblname = "table"; 
0557       sprintf(tmpstr,"%d",rand()%1000);
0558       tblname += tmpstr;
0559    }
0560 
0561    // Create a ROOT Tree
0562    //
0563    TTree* tree = new TTree(tblname.Data(),"Created by TSQLResultSet:Tree() method");
0564 
0565    tree->Branch(tblname.Data(),(void*)buf,leafList.Data());
0566 
0567    // skip to start 
0568    cur_row = GetRow();
0569 
0570    if(fStatement) { 
0571       if(fStatement->GetResultSetType() != kTYPE_FORWARD_ONLY ) {
0572          Absolute(srow-1);
0573       } else {
0574          if(srow>cur_row) {
0575             while ( Next() && cur_row+2 < srow) cur_row = GetRow();
0576          }
0577       }
0578    }
0579 
0580    // tree filling 
0581    while( Next() ) {   // iterate rows
0582       offset = 0;
0583    
0584       if(erow>0 && cur_row >= erow) break;
0585       cur_row = GetRow();
0586 
0587       for( int i=1; i <= ncollumns; ++i ) {
0588          type = fMetaData->GetColumnType(i);
0589          
0590          switch( type ) {      
0591          case kCHAR:  
0592          case kVARCHAR:
0593             siz = fMetaData->GetPrecision(i)+1; 
0594             str = GetString(i);
0595             memcpy(&buf[offset],str.Data(),siz); 
0596             break;  
0597          case kINTEGER:
0598             siz = sizeof(Int_t);
0599             intg = GetInt(i);
0600             memcpy(&buf[offset],&intg,siz); 
0601             break;
0602          case kBIT:
0603          case kTINYINT:  
0604          case kSMALLINT:
0605             siz = sizeof(Short_t);
0606             shrt = GetShort(i);
0607             memcpy(&buf[offset],&shrt,siz); 
0608             break;
0609          case kREAL:
0610             siz = sizeof(Float_t);
0611             dbl = GetFloat(i);
0612             memcpy(&buf[offset],&flt,siz); 
0613             break;
0614          case kDATE: // convert all date-times into time_t
0615          case kTIME:       // probably not working for kTIME  
0616          case kTIMESTAMP: 
0617             siz = sizeof(UInt_t);
0618             str = GetString(i);
0619             sscanf(str.Data(), "%d-%d-%d %d:%d:%d", 
0620                                 &yy, &mm, &dd, &hh, &mi, &ss);
0621             tp.tm_year  = yy-1900;
0622             tp.tm_mon   = mm;
0623             tp.tm_mday  = dd;
0624             tp.tm_hour  = hh;
0625             tp.tm_min   = mi;
0626             tp.tm_sec   = ss;
0627             tp.tm_isdst = -1;
0628             t = (UInt_t)mktime(&tp);
0629             memcpy(&buf[offset],&t,siz);
0630             break;            
0631          case kLONGVARCHAR: // not resolved  how to handle   
0632          case kLONGVARBINARY:
0633          case kVARBINARY:
0634             break;
0635          case kBIGINT:     // convert all these types to Double_t
0636          case kDECIMAL:
0637          case kNUMERIC:
0638          case kDOUBLE:
0639          case kFLOAT:                        
0640          default:
0641             siz = sizeof(Double_t);
0642             dbl = GetDouble(i);
0643             memcpy(&buf[offset],&dbl,siz); 
0644             break;      
0645          }  
0646          offset += siz;
0647       }
0648       tree->Fill();
0649    } 
0650 
0651    delete [] buf;
0652 
0653    if(fStatement) { 
0654       if(fStatement->GetResultSetType() != kTYPE_FORWARD_ONLY ) {
0655          Absolute(save_row);
0656       } else {
0657          Warning("Print","To set cursor to initial position -> re-execute Query.");
0658       }
0659    }
0660 
0661    return tree;  
0662 }