TSQLStatement.cxx

Go to the documentation of this file.
00001 // @(#)root/net:$Id: TSQLStatement.cxx 23091 2008-04-09 15:04:27Z rdm $
00002 // Author: Sergey Linev   6/02/2006
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 ////////////////////////////////////////////////////////////////////////////////
00013 //                                                                      
00014 // TSQLStatement                                                        
00015 //                                                                      
00016 // Abstract base class defining SQL statements, which can be submitted
00017 // in bulk to DB server.
00018 //                                                                      
00019 // This is alternative to TSQLServer::Query() method, which allows only pure
00020 // text queries and pure text result in TSQLResult classes.
00021 // TSQLStatement is designed to support following features:
00022 //   - usage of basic data type (like int or double) as parameters 
00023 //     in SQL statements
00024 //   - bulk operation when inserting/updating/selecting data in data base
00025 //   - uasge of basic data types when accessing result set of executed query
00026 //
00027 //
00028 // 1. Creation of statement
00029 // ======================================
00030 // To create instance of TSQLStatement class, TSQLServer::Statement() method
00031 // should be used. Depending of the driver, used for connection to ODBC,
00032 // appropriate object instance will be created. For the moment there are
00033 // three different implementation of TSQLStatement class: for MySQL, 
00034 // Oracle and ODBC. Hopefully, support of ODBC will allows usage of
00035 // statements for most existing RDBMS.
00036 //
00037 //   // first connect to data base
00038 //   TSQLServer* serv = TSQLServer::Connect("mysql://hostname.domain:3306/test",
00039 //                                          "user", "pass");
00040 //   // check if connection is ok
00041 //   if ((serv!=0) && serv->IsConnected()) {
00042 //       // create statement instance     
00043 //       TSQLStatement* stmt = serv->Statement("CREATE TABLE TESTTABLE (ID1 INT, ID2 INT, FFIELD VARCHAR(255), FVALUE VARCHAR(255))";
00044 //       // process statement
00045 //       stmt->Process();
00046 //       // destroy object
00047 //       delete stmt;
00048 //   }
00049 //   delete serv;
00050 //
00051 //
00052 // 2. Insert data to data base
00053 // ===============================================
00054 // There is a special syntax of SQL queries, which allow to use values,
00055 // provided as parameters. For instance, insert one row in TESTTABLE, created
00056 // with previous example, one can simply execute query like: 
00057 // 
00058 //    serv->Query("INSERT INTO TESTTABLE VALUES (1, 2, \"name1\", \"value1\"");
00059 //
00060 // But when many (100-1000) rows should be inserted, each call of 
00061 // TSQLServer::Query() method will cause communication loop with database
00062 // server. As a result, insertion of data will takes too much time.
00063 //
00064 // TSQLStatement provides a mechanism to insert many rows at once. First of all,
00065 // appropriate statement should be created:
00066 //
00067 //    TSQLStatement* stmt = serv->Statement("INSERT INTO TESTTABLE (ID1, ID2, FFIELD, FVALUE) VALUES (?, ?, ?, ?)", 100);
00068 //
00069 // Here question marks "?" indicates where statement parameters can be inserted.
00070 // To specify values of parameters, SetInt(), SetDouble(), SetString() and other
00071 // methods of TSQLStatement class should be used. Before parameters values
00072 // can be specified, NextIteration() method of statement class should be called.
00073 // For each new row first, NextIteration() called, that parameters values are
00074 // specified. There is one limitation - once parameter set as integer via
00075 // SetInt(), for all other rows should be specified as integer. At the end,
00076 // TSQLStatement::Process() should be called. Here a small example:
00077 //
00078 //    // first, create statement  
00079 //    TSQLStatement* stmt = serv->Statement("INSERT INTO TESTTABLE (ID1, ID2, FFIELD, FVALUE) VALUES (?, ?, ?, ?)", 100);
00080 //
00081 //    for (int n=0;n<357;n++) 
00082 //       if (stmt->NextIteration()) {
00083 //          stmt->SetInt(0, 123);
00084 //          stmt->SetUInt(1, n+10);
00085 //          stmt->SetString(2, Form("name %d",n), 200);
00086 //          stmt->SetString(3, Form("value %d", n+10), 200);
00087 //      }
00088 //   
00089 //     stmt->Process();
00090 //     delete stmt;
00091 //
00092 // Second argument in TSQLServer::Statement() method specifies depth of 
00093 // of buffers, used to keep parameter values (100 in example). It is not
00094 // a limitation of rows number, which can be inserted with the statement.
00095 // When buffers are filled, they will be submitted to database and can be
00096 // reused again. This happens transparent to the user in NextIteration()
00097 // method.
00098 //
00099 // Oracle and some ODBC drivers support buffering of parameter values and,
00100 // as a result, bulk insert (update) operation. MySQL (native driver and
00101 // MyODBC 3)  does not support such mode of operation, therefore adding
00102 // new rows will result in communication loop to database.
00103 //
00104 // One should also mention difference between Oracle and ODBC SQL syntax for
00105 // parameters. ODBC (and MySQL) uses question marks to specify position,
00106 // where parameters should be inserted (as shown in the example). Oracle uses
00107 // :1, :2 and so on marks for specify position of parameter 0, 1, and so on.
00108 // Therefore, similar to example query will look like:
00109 //
00110 //    TSQLStatement* stmt = serv->Statement("INSERT INTO TESTTABLE (ID1, ID2, FFIELD, FVALUE) VALUES (:1, :2, :3, :4)", 100);
00111 //  
00112 // There is a possibility to set parameter value to NULL with SetNull() method.
00113 // If this method called for first iteration, before one should call other Set...
00114 // to identify actual parameter type, which will be used for parameter later.
00115 //
00116 //
00117 // 3. Getting data from database
00118 // =============================
00119 // To request data from data base, SELECT statement should be used.
00120 // After SELECT statement is created, it must be processed
00121 // (with TSQLStatement::Process()) method and result of statement
00122 // should be stored in internal buffers with TSQLStatement::StoreResult()
00123 // method. Information about selected fields (columns)
00124 // can be obtained with GetNumFields() and GetFieldName() methods. 
00125 // To recieve data for next result row, NextResultRow() method should be called.
00126 // Value from each column can be taken with the GetInt(), GetDouble(),
00127 // GetString() and other methods. 
00128 // 
00129 // There are no strict limitation which method should be used
00130 // to get column values. GetString() can be used as generic method, 
00131 // which should always return correct result, but also convertion between most 
00132 // basic data types are supported. For instance, if column contains integer
00133 // values, GetInt(), GetLong64(), GetDouble() and GetString() methods can be used.
00134 // If column has float point format, GetDouble() and GetString() methods can
00135 // be used without loss of precision while GetInt() or GetLong64() will return
00136 // integer part of the value. One also can test, if value is NULL with IsNull()
00137 // method.
00138 //
00139 // Buffer length, specified for statement in TSQLServer::Statement() call,
00140 // will also be used to allocate buffers for column values. Usage of these
00141 // buffers is transparent for users and does not limit number of rows,
00142 // which can be accessed with  one statement. Example of select query:
00143 //
00144 //    stmt = serv->Statement("SELECT * FROM TESTTABLE", 100);
00145 //    // process statement
00146 //    if (stmt->Process()) {
00147 //       // store result of statement in buffer    
00148 //       stmt->StoreResult();
00149 //         
00150 //       // display info about selected field 
00151 //       cout << "NumFields = " << stmt->GetNumFields() << endl;
00152 //       for (int n=0;n<stmt->GetNumFields();n++) 
00153 //          cout << "Field " << n << "  = " << stmt->GetFieldName(n) << endl;
00154 //
00155 //       // extract rows one after another
00156 //       while (stmt->NextResultRow()) {
00157 //          Double_t id1 = stmt->GetDouble(0);
00158 //          UInt_t id2 = stmt->GetUInt(1);
00159 //          const char* name1 = stmt->GetString(2);
00160 //          const char* name2 = stmt->GetString(3);
00161 //          cout << id1 << " - " << id2 << "  " << name1 << "  " << name2 << endl;
00162 //       }
00163 //    }    
00164 //
00165 // 4. Working with date/time parameters
00166 // ====================================
00167 // Current implementation supports date, time, date&time and timestamp 
00168 // data (all time intervals not supported yet). To set or get date/time values,
00169 // following methods should be used:
00170 //   SetTime()/GetTime() - only time (hour:min:sec), 
00171 //   SetDate()/GetDate() - only date (year-month-day), 
00172 //   SetDatime()/GetDatime() - date and time 
00173 //   SetTimestamp()/GetTimestamp() - timestamp with seconds fraction
00174 // For some of these methods TDatime type can be used as parameter / return value.
00175 // Be aware, that TDatime supports only dates after 1995-01-01.
00176 // There are also methods to get separately year, month, day, hour, minutes and seconds.
00177 //
00178 // Different SQL databases has different treatement of date/time types.
00179 // For instance, MySQL has all correspondent types (TIME, DATE, DATETIME and TIMESTAMP),
00180 // Oracle native driver supports only DATE (which is actually date and time) and TIMESTAMP
00181 // ODBC interface provides access for time, date and timestamps.
00182 // Therefore, one should use correct methods to access such data.
00183 // For instance, in MySQL SQL type 'DATE' is only date (one should use GetDate() to 
00184 // access such data), while in Oracle it is date and time. Therefore, 
00185 // to get complete data from 'DATE' column in Oracle, one should use GetDatime() method.
00186 //
00187 // The only difference of timestamp from date/time, that it has fractional
00188 // seconds part. Be aware, that fractional part can has different meaning 
00189 // (actual value) in different SQL plugins.
00190 //
00191 // 5. Binary data
00192 // ==============
00193 // Most of modern data bases support just binary data, which is
00194 // typically has SQL type name 'BLOB'. To access data in such
00195 // columns, GetBinary()/SetBinary() methods should be used. 
00196 // Current implementation supposed, that complete content of the 
00197 // column must be retrieved at once. Therefore very big data of 
00198 // gigabytes size may cause a problem.
00199 //
00200 ////////////////////////////////////////////////////////////////////////////////
00201 
00202 #include "TSQLStatement.h"
00203 
00204 ClassImp(TSQLStatement)
00205 
00206 //______________________________________________________________________________
00207 Int_t TSQLStatement::GetErrorCode() const
00208 {
00209    // returns error code of last operation
00210    // if res==0, no error
00211    // Each specific implementation of TSQLStatement provides its own error coding
00212    
00213    return fErrorCode;
00214 }
00215 
00216 //______________________________________________________________________________
00217 const char* TSQLStatement::GetErrorMsg() const
00218 {
00219    //  returns error message of last operation
00220    // if no errors, return 0
00221    // Each specific implementation of TSQLStatement provides its own error messages
00222    
00223    return GetErrorCode()==0 ? 0 : fErrorMsg.Data();
00224 }
00225 
00226 //______________________________________________________________________________
00227 void TSQLStatement::ClearError()
00228 {
00229    // reset error fields
00230    
00231    fErrorCode = 0;
00232    fErrorMsg = "";
00233 }
00234 
00235 //______________________________________________________________________________
00236 void TSQLStatement::SetError(Int_t code, const char* msg, const char* method)
00237 {
00238    // set new values for error fields
00239    // if method specified, displays error message
00240    
00241    fErrorCode = code;
00242    fErrorMsg = msg;
00243    if ((method!=0) && fErrorOut)
00244       Error(method,"Code: %d  Msg: %s", code, (msg ? msg : "No message"));
00245 }
00246 
00247 //______________________________________________________________________________
00248 Bool_t TSQLStatement::SetDate(Int_t npar, const TDatime& tm)
00249 {
00250    // set only date value for specified parameter from TDatime object
00251    
00252    return SetDate(npar, tm.GetYear(), tm.GetMonth(), tm.GetDay());
00253 }
00254 
00255 //______________________________________________________________________________
00256 Bool_t TSQLStatement::SetTime(Int_t npar, const TDatime& tm)
00257 {
00258    // set only time value for specified parameter from TDatime object
00259    
00260    return SetTime(npar, tm.GetHour(), tm.GetMinute(), tm.GetSecond());
00261 }
00262 
00263 //______________________________________________________________________________
00264 Bool_t TSQLStatement::SetDatime(Int_t npar, const TDatime& tm)
00265 {
00266    // set date & time value for specified parameter from TDatime object
00267    
00268    return SetDatime(npar, tm.GetYear(), tm.GetMonth(), tm.GetDay(),
00269                           tm.GetHour(), tm.GetMinute(), tm.GetSecond());
00270 }
00271 
00272 //______________________________________________________________________________
00273 Bool_t TSQLStatement::SetTimestamp(Int_t npar, const TDatime& tm)
00274 {
00275    // set timestamp value for specified parameter from TDatime object
00276    
00277    return SetTimestamp(npar, tm.GetYear(), tm.GetMonth(), tm.GetDay(),
00278                              tm.GetHour(), tm.GetMinute(), tm.GetSecond(), 0);
00279 }
00280 
00281 //______________________________________________________________________________
00282 TDatime TSQLStatement::GetDatime(Int_t npar)
00283 {
00284    // return value of parameter in form of TDatime
00285    // Be aware, that TDatime does not allow dates before 1995-01-01 
00286    
00287    Int_t year, month, day, hour, min, sec;
00288    
00289    if (!GetDatime(npar, year, month, day, hour, min, sec))
00290      return TDatime();
00291    
00292    if (year<1995) {
00293       SetError(-1, "Date before year 1995 does not supported by TDatime type", "GetDatime");
00294       return TDatime();
00295    }
00296    
00297    return TDatime(year, month, day, hour, min, sec);
00298 }
00299 
00300 //______________________________________________________________________________
00301 Int_t TSQLStatement::GetYear(Int_t npar)
00302 {
00303    // return year value for parameter (if applicable) 
00304    
00305    Int_t year, month, day, hour, min, sec, frac;
00306    if (GetDate(npar, year, month, day)) return year;
00307    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return year;
00308    return 0;
00309 }
00310 
00311 //______________________________________________________________________________
00312 Int_t TSQLStatement::GetMonth(Int_t npar)
00313 {
00314    // return month value for parameter (if applicable) 
00315 
00316    Int_t year, month, day, hour, min, sec, frac;
00317    if (GetDate(npar, year, month, day)) return month;
00318    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return month;
00319    return 0;
00320 }
00321 
00322 //______________________________________________________________________________
00323 Int_t TSQLStatement::GetDay(Int_t npar)
00324 {
00325    // return day value for parameter (if applicable) 
00326 
00327    Int_t year, month, day, hour, min, sec, frac;
00328    if (GetDate(npar, year, month, day)) return day;
00329    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return day;
00330    return 0;
00331 }
00332 
00333 //______________________________________________________________________________
00334 Int_t TSQLStatement::GetHour(Int_t npar)
00335 {
00336    // return hours value for parameter (if applicable) 
00337 
00338    Int_t year, month, day, hour, min, sec, frac;
00339    if (GetTime(npar, hour, min, sec)) return hour;
00340    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return hour;
00341    return 0;
00342 }
00343 
00344 //______________________________________________________________________________
00345 Int_t TSQLStatement::GetMinute(Int_t npar)
00346 {
00347    // return minutes value for parameter (if applicable) 
00348 
00349    Int_t year, month, day, hour, min, sec, frac;
00350    if (GetTime(npar, hour, min, sec)) return min;
00351    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return min;
00352    return 0;
00353 }
00354 
00355 //______________________________________________________________________________
00356 Int_t TSQLStatement::GetSecond(Int_t npar)
00357 {
00358    // return seconds value for parameter (if applicable) 
00359 
00360    Int_t year, month, day, hour, min, sec, frac;
00361    if (GetTime(npar, hour, min, sec)) return sec;
00362    if (GetTimestamp(npar, year, month, day, hour, min, sec, frac)) return sec;
00363    return 0;
00364 }
00365 
00366 //______________________________________________________________________________
00367 TDatime TSQLStatement::GetTimestamp(Int_t npar)
00368 {
00369    // return value of parameter in form of TDatime
00370    // Be aware, that TDatime does not allow dates before 1995-01-01 
00371    
00372    Int_t year, month, day, hour, min, sec, frac;
00373    
00374    if (!GetTimestamp(npar, year, month, day, hour, min, sec, frac))
00375      return TDatime();
00376    
00377    if (year<1995) {
00378       SetError(-1, "Date before year 1995 does not supported by TDatime type", "GetTimestamp");
00379       return TDatime();
00380    }
00381    
00382    return TDatime(year, month, day, hour, min, sec);
00383 }
00384 

Generated on Tue Jul 5 14:46:11 2011 for ROOT_528-00b_version by  doxygen 1.5.1