TSQLFile.cxx

Go to the documentation of this file.
00001 // @(#)root/sql:$Id: TSQLFile.cxx 35766 2010-09-27 07:56:34Z rdm $
00002 // Author: Sergey Linev  20/11/2005
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, 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 // The main motivation for the TSQLFile development is to have
00015 // "transparent" access to SQL data base via standard TFile interface.
00016 //
00017 // The main approach that each class (but not each object) has one or two tables
00018 // with names like $(CLASSNAME)_ver$(VERSION) and $(CLASSNAME)_raw$(VERSION)
00019 // For example: TAxis_ver8 or TList_raw5
00020 // Second kind of tables appears, when some of class members can not be converted to
00021 // normalized form or when class has custom streamer.
00022 // For instance, for TH1 class two tables are required: TH1_ver4 and TH1_raw4
00023 // Most of memebers are stored in TH1_ver4 table columnwise, and only memeber:
00024 //
00025 //  Double_t*  fBuffer;  //[fBufferSize]
00026 //
00027 // can not be represented as column while size of array is not known apriory.
00028 // Therefore, fBuffer will be written as list of values in TH1_raw4 table.
00029 //
00030 // All objects, stored in the DB, will be registered in table "ObjectsTable".
00031 // In this there are following columns:
00032 //     "key:id"  - key identifier to which belong object
00033 //     "obj:id"  - object identifier
00034 //     "Class"   - object class name
00035 //     "Version" - object class version
00036 //  Data in each "ObjectsTable" row uniqly identify, in which table
00037 //  and which column object is stored.
00038 //
00039 // In normal situation all class data should be sorted columnwise.
00040 // Up to now following member are supported:
00041 // 1) Basic data types
00042 //     Here is everything clear. Column SQL type will be as much as possible
00043 //     close to the original type of value.
00044 // 2) Fixed array of basic data types
00045 //     In this case n columns like fArr[0], fArr[1] and so on will be created.
00046 //     If there is multidimensional array, names will be fArr2[1][2][1] and so on
00047 // 3) Parent class
00048 //     In this case version of parent class is stored and
00049 //     data of parent class will be stored with the same obj:id in corrspondent table.
00050 //     There is a special case, when parent store nothing (this is for instance TQObject).
00051 //     In that case just -1 is written to avoid any extra checks if table exist or not.
00052 // 4) Object as data member.
00053 //     In that case object is saved in normal way to data base and column
00054 //     will contain id of this object.
00055 // 5) Pointer on object
00056 //     Same as before. In case if object was already stored, just its id
00057 //     will be placed in the column. For NULL pointer 0 is used.
00058 // 6) TString
00059 //     Now column with limited width like VARCAHR(255) in MySQL is used.
00060 //     Later this will be improved to support maximum possible strings
00061 // 7) Anything else.
00062 //     Data will be converted to raw format and saved in _streamer_ table.
00063 //     Each row supplied with obj:id and row:id, where row:id indicates
00064 //     data, corresponding to this particular data member, and column
00065 //     will contain this raw:id
00066 //
00067 // All conversion to SQL statements are done with help of TSQLStructure class.
00068 // This is special hierarchical structure wich internally is very similar
00069 // to XML structures. TBufferSQL2 creates these structures, when object
00070 // data is streamed by ROOT and only afterwards all SQL statements will be produced
00071 // and applied all together.
00072 //
00073 // When data is reading, TBufferSQL2 will produce requests to database
00074 // during unstreaming of object data.
00075 //
00076 // Optionally (default this options on) name of column includes
00077 // suffix which indicates type of column. For instance:
00078 //   *:parent  - parent class, column contain class version
00079 //   *:object  - other object, column contain object id
00080 //   *:rawdata - raw data, column contains id of raw data from _streamer_ table
00081 //   *:Int_t   - column with integer value
00082 // Use TSQLFile::SetUseSuffixes(kFALSE) to disable suffixes usage.
00083 //
00084 // This and several other options can be changed only when
00085 // TSQLFile created with options "CREATE" or "RECREATE" and only before
00086 // first write operation. These options are:
00087 //     SetUseSuffixes() - suffix usage in column names (default - on)
00088 //     SetArrayLimit()  - defines maximum array size, which can
00089 //                        has column for each element (default 21)
00090 //     SetTablesType()  - table type name in MySQL database (default "InnoDB")
00091 //     SetUseIndexes()  - usage of indexes in database (default kIndexesBasic)
00092 // Normally these functions should be called immidiately after TSQLFile constructor.
00093 //
00094 // When objects data written to database, by default START TRANSACTION/COMMIT
00095 // SQL commands are used before and after data storage. If TSQLFile detects
00096 // any problems, ROLLBACK command will be used to restore
00097 // previous state of data base. If transactions not supported by SQL server,
00098 // they can be disabled by SetUseTransactions(kTransactionsOff). Or user
00099 // can take responsibility to use transactions function to hime
00100 //
00101 // By default only indexes for basic tables are created.
00102 // In most cases usage of indexes increase perfomance to data reading,
00103 // but it also can increase time of writing data to database.
00104 // There are several modes of index usage available in SetUseIndexes() method
00105 //
00106 // There is MakeSelectQuery(TClass*) method, which
00107 // produces SELECT statement to get objects data of specified class.
00108 // Difference from simple statement like:
00109 //   mysql> SELECT * FROM TH1I_ver1
00110 // that not only data for that class, but also data from parent classes
00111 // will be extracted from other tables and combined in single result table.
00112 // Such select query can be usufull for external access to objects data.
00113 //
00114 // Up to now MySQL 4.1 and Oracle 9i were tested.
00115 // Some extra work is required for other SQL databases.
00116 // Hopefully, this should be straigthforward.
00117 //
00118 // Known problems and open questions.
00119 // 1) TTree is not supported by TSQLFile. There is independent development
00120 //    of TTreeSQL class, which allows to store trees directly in SQL database
00121 // 2) TClonesArray is store objects in raw format,
00122 //    which can not be accessed outside ROOT.
00123 //    This will be changed later.
00124 // 3) TDirectory cannot work. Hopefully, will (changes in ROOT basic I/O is required)
00125 // 4) Streamer infos are not written to file, therefore schema evolution
00126 //    is not yet supported. All eforts are done to enable this feature in
00127 //    the near future
00128 //
00129 // Example how TSQLFile can be used:
00130 //
00131 // example of a session saving data to a SQL data base
00132 // =====================================================
00133 //
00134 //  const char* dbname = "mysql://host.domain:3306/dbname";
00135 //  const char* username = "username";
00136 //  const char* userpass = "userpass";
00137 //
00138 //  // Clean data base and create primary tables
00139 //  TSQLFile* f = new TSQLFile(dbname, "recreate", username, userpass);
00140 //  // Write with standard I/O functions
00141 //  arr->Write("arr", TObject::kSingleKey);
00142 //  h1->Write("histo");
00143 //  // Close connection to DB
00144 //  delete f;
00145 //
00146 // example of a session read data from SQL data base
00147 // =====================================================
00148 //
00149 //  // Open database again in read-only mode
00150 //  TSQLFile* f = new TSQLFile(dbname, "open", username, userpass);
00151 //  // Show list of keys
00152 //  f->ls();
00153 //  // Read stored object, again standard ROOT I/O
00154 //  TH1* h1 = (TH1*) f->Get("histo");
00155 //  if (h1!=0) { h1->SetDirectory(0); h1->Draw(); }
00156 //  TObject* obj = f->Get("arr");
00157 //  if (obj!=0) obj->Print("*");
00158 //  // close connection to DB
00159 //  delete f;
00160 //
00161 // The "SQL I/O" package is currently under development.
00162 // Any bug reports and suggestions are welcome.
00163 // Author: S.Linev, GSI Darmstadt,   S.Linev@gsi.de
00164 //
00165 //______________________________________________________________________________
00166 
00167 #include "TSQLFile.h"
00168 
00169 #include "TROOT.h"
00170 #include "TSystem.h"
00171 #include "TList.h"
00172 #include "TBrowser.h"
00173 #include "TObjArray.h"
00174 #include "TObjString.h"
00175 #include "TList.h"
00176 #include "TArrayC.h"
00177 #include "TVirtualStreamerInfo.h"
00178 #include "TStreamerElement.h"
00179 #include "TProcessID.h"
00180 #include "TError.h"
00181 #include "TClass.h"
00182 
00183 #include "TSQLServer.h"
00184 #include "TSQLTableInfo.h"
00185 #include "TSQLColumnInfo.h"
00186 #include "TSQLStatement.h"
00187 #include "TSQLResult.h"
00188 #include "TSQLRow.h"
00189 #include "TBufferSQL2.h"
00190 #include "TSQLStructure.h"
00191 #include "TKeySQL.h"
00192 #include "TSQLClassInfo.h"
00193 #include "TSQLObjectData.h"
00194 
00195 #include "Riostream.h"
00196 
00197 ClassImp(TSQLFile);
00198 
00199 const char* mysql_BasicTypes[21] = {
00200 "VARCHAR(255)",     // kBase     =  0,  used for text
00201 "TINYINT UNSIGNED", // kChar     =  1,
00202 "SMALLINT",         // kShort   =  2,
00203 "INT",              // kInt     =  3,
00204 "BIGINT",           // kLong    =  4,
00205 "FLOAT",            // kFloat    = 5,
00206 "INT",              // kCounter =  6,
00207 "VARCHAR(255)",     // kCharStar = 7,
00208 "DOUBLE",           // kDouble   = 8,
00209 "DOUBLE",           // kDouble32=  9,
00210 "",                 // nothing
00211 "TINYINT UNSIGNED", // kUChar    = 11,
00212 "SMALLINT UNSIGNED",// kUShort  = 12,
00213 "INT UNSIGNED",     // kUInt    = 13,
00214 "BIGINT UNSIGNED",  // kULong   = 14,
00215 "INT UNSIGNED",     // kBits     = 15,
00216 "BIGINT",           // kLong64   = 16,
00217 "BIGINT UNSIGNED",  // kULong64 = 17,
00218 "BOOL",             // kBool    = 18,
00219 "DOUBLE",           // kFloat16 = 19,
00220 ""
00221 };
00222 
00223 const char* mysql_OtherTypes[13] = {
00224 "VARCHAR(255)",     // smallest text
00225 "255",              // maximum length of small text
00226 "TEXT",             // biggest size text
00227 "DATETIME",         // date & time
00228 "`",                // quote for identifier like table name or column name
00229 "dir:id",           // dir id column
00230 "key:id",           // key id column
00231 "obj:id",           // object id column
00232 "raw:id",           // raw data id column
00233 "str:id",           // string id column
00234 ":",                // name separator between name and type like TObject:Parent
00235 "\"",               // quote for string values in MySQL
00236 "InnoDB"            // default tables types, used only for MySQL tables
00237 };
00238 
00239 const char* oracle_BasicTypes[21] = {
00240 "VARCHAR(255)",     // kBase     =  0,  used for text
00241 "INT",              // kChar     =  1,
00242 "INT",              // kShort   =  2,
00243 "INT",              // kInt     =  3,
00244 "INT",              // kLong    =  4,
00245 "FLOAT",            // kFloat    = 5,
00246 "INT",              // kCounter =  6,
00247 "VARCHAR(255)",     // kCharStar = 7,
00248 "DOUBLE PRECISION", // kDouble   = 8,
00249 "DOUBLE PRECISION", // kDouble32=  9,
00250 "",                 // nothing
00251 "INT",              // kUChar    = 11,
00252 "INT",              // kUShort  = 12,
00253 "INT",              // kUInt    = 13,
00254 "INT",              // kULong   = 14,
00255 "INT",              // kBits     = 15,
00256 "INT",              // kLong64   = 16,
00257 "INT",              // kULong64 = 17,
00258 "INT",              // kBool    = 18,
00259 "FLOAT",            // kFloat16 = 19,
00260 ""
00261 };
00262 
00263 const char* oracle_OtherTypes[13] = {
00264 "VARCHAR(1000)",    // smallest text
00265 "1000",             // maximum size of smallest text
00266 "VARCHAR(4000)",    // biggest size text, CLOB is not yet supported by TOracleRow
00267 "VARCHAR(50)",      // date & time
00268 "\"",               // quote for identifier like table name or column name
00269 "dir:id",           // dir id column
00270 "key:id",           // key id column
00271 "obj:id",           // object id column
00272 "raw:id",           // raw data id column
00273 "str:id",           // string id column
00274 ":",                // name separator between name and type like TObject:parent
00275 "'",                // quote for string values in Oracle
00276 ""                  // default tables types, used only for MySQL tables
00277 };
00278 
00279 
00280 //______________________________________________________________________________
00281 TSQLFile::TSQLFile() :
00282    TFile(),
00283    fSQL(0),
00284    fSQLClassInfos(0),
00285    fUseSuffixes(kTRUE),
00286    fSQLIOversion(1),
00287    fArrayLimit(21),
00288    fCanChangeConfig(kFALSE),
00289    fTablesType(),
00290    fUseTransactions(0),
00291    fUseIndexes(0),
00292    fModifyCounter(0),
00293    fQuerisCounter(0),
00294    fBasicTypes(0),
00295    fOtherTypes(0),
00296    fUserName(),
00297    fLogFile(0),
00298    fIdsTableExists(kFALSE),
00299    fStmtCounter(0)
00300 {
00301    // default TSQLFile constructor
00302    SetBit(kBinaryFile, kFALSE);
00303 }
00304 
00305 //______________________________________________________________________________
00306 TSQLFile::TSQLFile(const char* dbname, Option_t* option, const char* user, const char* pass) :
00307    TFile(),
00308    fSQL(0),
00309    fSQLClassInfos(0),
00310    fUseSuffixes(kTRUE),
00311    fSQLIOversion(1),
00312    fArrayLimit(21),
00313    fCanChangeConfig(kFALSE),
00314    fTablesType(),
00315    fUseTransactions(0),
00316    fUseIndexes(0),
00317    fModifyCounter(0),
00318    fQuerisCounter(0),
00319    fBasicTypes(mysql_BasicTypes),
00320    fOtherTypes(mysql_OtherTypes),
00321    fUserName(user),
00322    fLogFile(0),
00323    fIdsTableExists(kFALSE),
00324    fStmtCounter(0)
00325 {
00326    // Connects to SQL server with provided arguments.
00327    // If the constructor fails in any way IsZombie() will
00328    // return true. Use IsOpen() to check if the file is (still) open.
00329    //
00330    // If option = NEW or CREATE   create a ROOT tables in database
00331    //                             if the tables already exists connection is
00332    //                             not opened.
00333    //           = RECREATE        create completely new tables. Any existing tables
00334    //                             will be deleted
00335    //           = UPDATE          open an existing database for writing.
00336    //                             If data base open by other TSQLFile instance for writing,
00337    //                             write access will be rejected
00338    //           = BREAKLOCK       Special case when lock was not correctly released
00339    //                             by TSQLFile instance. This may happen if program crashed when
00340    //                             TSQLFile was open with write access mode.
00341    //           = READ or OPEN    open an existing data base for reading.
00342    //
00343    // For more details see comments for TFile::TFile() constructor
00344    //
00345    // For a moment TSQLFile does not support TTree objects and subdirectories
00346 
00347    if (!gROOT)
00348       ::Fatal("TFile::TFile", "ROOT system not initialized");
00349 
00350    gDirectory = 0;
00351    SetName(dbname);
00352    SetTitle("TFile interface to SQL DB");
00353    TDirectoryFile::Build();
00354    fFile = this;
00355 
00356    if (dbname && strstr(dbname,"oracle://")!=0) {
00357       fBasicTypes = oracle_BasicTypes;
00358       fOtherTypes = oracle_OtherTypes;
00359    }
00360 
00361    fArrayLimit = 21;
00362    fTablesType = SQLDefaultTableType();
00363    fUseIndexes = 1;
00364    fUseTransactions = kTransactionsAuto;
00365 
00366    fD          = -1;
00367    fFile       = this;
00368    fFree       = 0;
00369    fVersion    = gROOT->GetVersionInt();  //ROOT version in integer format
00370    fUnits      = 4;
00371    fOption     = option;
00372    SetCompressionLevel(5);
00373    fWritten    = 0;
00374    fSumBuffer  = 0;
00375    fSum2Buffer = 0;
00376    fBytesRead  = 0;
00377    fBytesWrite = 0;
00378    fClassIndex = 0;
00379    fSeekInfo   = 0;
00380    fNbytesInfo = 0;
00381    fProcessIDs = 0;
00382    fNProcessIDs= 0;
00383    fSeekDir    = sqlio::Ids_RootDir;
00384    SetBit(kBinaryFile, kFALSE);
00385 
00386    fOption = option;
00387    fOption.ToUpper();
00388 
00389    if (fOption == "NEW") fOption = "CREATE";
00390 
00391    Bool_t breaklock = kFALSE;
00392 
00393    if (fOption == "BREAKLOCK") { breaklock = kTRUE; fOption = "UPDATE"; }
00394 
00395    Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
00396    Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
00397    Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
00398    Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
00399 
00400    if (!create && !recreate && !update && !read) {
00401       read    = kTRUE;
00402       fOption = "READ";
00403    }
00404 
00405    if (!dbname || !strlen(dbname)) {
00406       Error("TSQLFile", "Database not specified");
00407       goto zombie;
00408    }
00409 
00410    gROOT->cd();
00411 
00412    fSQL = TSQLServer::Connect(dbname, user, pass);
00413 
00414    if (fSQL==0) {
00415       Error("TSQLFile", "Cannot connect to DB %s", dbname);
00416       goto zombie;
00417    }
00418 
00419    if (recreate) {
00420       if (IsTablesExists())
00421          if (!IsWriteAccess()) {
00422             Error("TSQLFile", "no write permission, DB %s locked", dbname);
00423             goto zombie;
00424          }
00425       SQLDeleteAllTables();
00426       recreate = kFALSE;
00427       create   = kTRUE;
00428       fOption  = "CREATE";
00429    }
00430 
00431    if (create && IsTablesExists()) {
00432       Error("TSQLFile", "DB tables already exists");
00433       goto zombie;
00434    }
00435 
00436    if (update) {
00437       if (!IsTablesExists()) {
00438          update = kFALSE;
00439          create = kTRUE;
00440       }
00441 
00442       if (update && !breaklock && !IsWriteAccess()) {
00443          Error("TSQLFile", "no write permission, DB %s locked", dbname);
00444          goto zombie;
00445       }
00446    }
00447 
00448    if (read) {
00449       if (!IsTablesExists()) {
00450          Error("TSQLFile", "DB %s tables not exist", dbname);
00451          goto zombie;
00452       }
00453       if (!IsReadAccess()) {
00454          Error("TSQLFile", "no read permission for DB %s tables", dbname);
00455          goto zombie;
00456       }
00457    }
00458 
00459    fRealName = dbname;
00460 
00461    if (create || update) {
00462       SetWritable(kTRUE);
00463       if (update) SetLocking(kLockBusy);
00464    } else
00465       SetWritable(kFALSE);
00466 
00467    // user can change configurations only when create (recreate) options
00468    // was specified. When first object will be saved, configurations will
00469    // be frozen.
00470    fCanChangeConfig = create;
00471 
00472    InitSqlDatabase(create);
00473 
00474    return;
00475 
00476 zombie:
00477 
00478    delete fSQL;
00479    fSQL = 0;
00480    MakeZombie();
00481    gDirectory = gROOT;
00482 }
00483 
00484 //______________________________________________________________________________
00485 void TSQLFile::StartLogFile(const char* fname)
00486 {
00487    // start logging of all SQL statements in specified file
00488 
00489    StopLogFile();
00490    fLogFile = new std::ofstream(fname);
00491 }
00492 
00493 //______________________________________________________________________________
00494 void TSQLFile::StopLogFile()
00495 {
00496    // close logging file
00497    if (fLogFile!=0) {
00498       delete fLogFile;
00499       fLogFile = 0;
00500    }
00501 }
00502 
00503 //______________________________________________________________________________
00504 Bool_t TSQLFile::IsMySQL() const
00505 {
00506    // checks, if MySQL database
00507    if (fSQL==0) return kFALSE;
00508    return strcmp(fSQL->ClassName(),"TMySQLServer")==0;
00509 }
00510 
00511 //______________________________________________________________________________
00512 Bool_t TSQLFile::IsOracle() const
00513 {
00514    // checks, if Oracle database
00515 
00516    if (fSQL==0) return kFALSE;
00517    return strcmp(fSQL->ClassName(),"TOracleServer")==0;
00518 }
00519 
00520 //______________________________________________________________________________
00521 Bool_t TSQLFile::IsODBC() const
00522 {
00523    // checks, if ODBC driver used for database connection
00524 
00525    if (fSQL==0) return kFALSE;
00526    return strcmp(fSQL->ClassName(),"TODBCServer")==0;
00527 
00528 }
00529 
00530 //______________________________________________________________________________
00531 void TSQLFile::SetUseSuffixes(Bool_t on)
00532 {
00533    // enable/disable uasge of suffixes in columns names
00534    // can be changed before first object is saved into file
00535 
00536    if (!fCanChangeConfig)
00537       Error("SetUseSuffixes", "Configurations already cannot be changed");
00538    else
00539       fUseSuffixes = on;
00540 }
00541 
00542 //______________________________________________________________________________
00543 void TSQLFile::SetArrayLimit(Int_t limit)
00544 {
00545    // Defines maximum number of columns for array representation
00546    // If array size bigger than limit, array data will be converted to raw format
00547    // This is usefull to prevent tables with very big number of columns
00548    // If limit==0, all arrays will be stored in raw format
00549    // If limit<0, all array values will be stored in column form
00550    // Default value is 21
00551 
00552    if (!fCanChangeConfig)
00553       Error("SetArrayLimit", "Configurations already cannot be changed");
00554    else
00555       fArrayLimit = limit;
00556 }
00557 
00558 //______________________________________________________________________________
00559 void TSQLFile::SetTablesType(const char* tables_type)
00560 {
00561    // Defines tables type, which is used in CREATE TABLE statements
00562    // Now is only used for MySQL database, where following types are supported:
00563    //    "BDB", "HEAP", "ISAM", "InnoDB", "MERGE", "MRG_MYISAM", "MYISAM"
00564    // Default for TSQLFile is "InnoDB". For more detailes see MySQL docs.
00565 
00566    if (!fCanChangeConfig)
00567       Error("SetTablesType", "Configurations already cannot be changed");
00568    else
00569       fTablesType = tables_type;
00570 }
00571 
00572 //______________________________________________________________________________
00573 void TSQLFile::SetUseTransactions(Int_t mode)
00574 {
00575    // Defines usage of transactions statements for writing objects data to database.
00576    //    kTransactionsOff=0   - no transaction operation are allowed
00577    //    kTransactionsAuto=1  - automatic mode. Each write operation,
00578    //        produced by TSQLFile, will be supplied by START TRANSACTION and COMMIT calls.
00579    //        If any error happen, ROLLBACK will returns database to previous state
00580    //    kTransactionsUser=2  - transactions are delegated to user. Methods
00581    //        StartTransaction(), Commit() and Rollback() should be called by user.
00582    // Default UseTransactions option is kTransactionsAuto
00583 
00584    fUseTransactions = mode;
00585 }
00586 
00587 //______________________________________________________________________________
00588 Bool_t TSQLFile::StartTransaction()
00589 {
00590    // Start user transaction.
00591    // This can be usesfull, when big number of objects should be stored in
00592    // data base and commitment required only if all operations were succesfull.
00593    // In that case in the end of all operations method Commit() should be
00594    // called. If operation on user-level is looks like not successfull,
00595    // method Rollback() will return database data and TSQLFile instance to
00596    // previous state.
00597    // In MySQL not all tables types support transaction mode of operation.
00598    // See SetTablesType() method for details .
00599 
00600    if (GetUseTransactions()!=kTransactionsUser) {
00601       Error("SQLStartTransaction","Only allowed when SetUseTransactions(kUserTransactions) was configured");
00602       return kFALSE;
00603    }
00604 
00605    return SQLStartTransaction();
00606 }
00607 
00608 //______________________________________________________________________________
00609 Bool_t TSQLFile::Commit()
00610 {
00611    // Commit transaction, started by StartTransaction() call.
00612    // Only after that call data will be written and visible on database side.
00613 
00614    if (GetUseTransactions()!=kTransactionsUser) {
00615       Error("SQLCommit","Only allowed when SetUseTransactions(kUserTransactions) was configured");
00616       return kFALSE;
00617    }
00618 
00619    return SQLCommit();
00620 }
00621 
00622 //______________________________________________________________________________
00623 Bool_t TSQLFile::Rollback()
00624 {
00625    // Rollback all operations, done after StartTransaction() call.
00626    // Database should return to initial state.
00627 
00628    if (GetUseTransactions()!=kTransactionsUser) {
00629       Error("SQLRollback","Only allowed when SetUseTransactions(kUserTransactions) was configured");
00630       return kFALSE;
00631    }
00632 
00633    return SQLRollback();
00634 }
00635 
00636 //______________________________________________________________________________
00637 void TSQLFile::SetUseIndexes(Int_t use_type)
00638 {
00639    // Specify usage of indexes for data tables
00640    //    kIndexesNone = 0  - no indexes are used
00641    //    kIndexesBasic = 1 - indexes used only for keys list and
00642    //                        objects list tables (default)
00643    //    kIndexesClass = 2 - index also created for every normal class table
00644    //    kIndexesAll = 3   - index created for every table, including _streamer_ tables
00645    // Indexes in general should increase speed of access to objects data,
00646    // but they required more operations and more disk space on server side
00647 
00648    if (!fCanChangeConfig)
00649       Error("SetUseIndexes", "Configurations already cannot be changed");
00650    else
00651       fUseIndexes = use_type;
00652 }
00653 
00654 //______________________________________________________________________________
00655 const char* TSQLFile::GetDataBaseName() const
00656 {
00657    // Return name of data base on the host
00658    // For Oracle always return 0
00659 
00660    if (IsOracle()) return 0;
00661    const char* name = strrchr(GetName(),'/');
00662    if (name==0) return 0;
00663    return name + 1;
00664 }
00665 
00666 //______________________________________________________________________________
00667 void TSQLFile::Close(Option_t *option)
00668 {
00669    // Close a SQL file
00670    // For more comments see TFile::Close() function
00671 
00672    if (!IsOpen()) return;
00673 
00674    TString opt = option;
00675    if (opt.Length()>0)
00676       opt.ToLower();
00677 
00678    if (IsWritable()) {
00679       SaveToDatabase();
00680       SetLocking(kLockFree);
00681    }
00682 
00683    fWritable = kFALSE;
00684 
00685    if (fClassIndex) {
00686       delete fClassIndex;
00687       fClassIndex = 0;
00688    }
00689 
00690    TDirectory *cursav = gDirectory;
00691    cd();
00692 
00693    if (cursav == this || cursav->GetFile() == this) {
00694       cursav = 0;
00695    }
00696 
00697    // Delete all supported directories structures from memory
00698    TDirectoryFile::Close();
00699    cd();      // Close() sets gFile = 0
00700 
00701    if (cursav)
00702       cursav->cd();
00703    else {
00704       gFile      = 0;
00705       gDirectory = gROOT;
00706    }
00707 
00708    //delete the TProcessIDs
00709    TList pidDeleted;
00710    TIter next(fProcessIDs);
00711    TProcessID *pid;
00712    while ((pid = (TProcessID*)next())) {
00713       if (!pid->DecrementCount()) {
00714          if (pid != TProcessID::GetSessionProcessID()) pidDeleted.Add(pid);
00715       } else if(opt.Contains("r")) {
00716          pid->Clear();
00717       }
00718    }
00719    pidDeleted.Delete();
00720 
00721    gROOT->GetListOfFiles()->Remove(this);
00722 }
00723 
00724 //______________________________________________________________________________
00725 TSQLFile::~TSQLFile()
00726 {
00727    // destructor of TSQLFile object
00728 
00729    Close();
00730 
00731    if (fSQLClassInfos!=0) {
00732       fSQLClassInfos->Delete();
00733       delete fSQLClassInfos;
00734    }
00735 
00736    StopLogFile();
00737 
00738    if (fSQL!=0) {
00739       delete fSQL;
00740       fSQL = 0;
00741    }
00742 }
00743 
00744 //______________________________________________________________________________
00745 void TSQLFile::operator=(const TSQLFile &)
00746 {
00747    // make private to exclude copy operator
00748 }
00749 
00750 //______________________________________________________________________________
00751 Bool_t TSQLFile::IsOpen() const
00752 {
00753    // return kTRUE if file is opened and can be accessed
00754 
00755    return fSQL != 0;
00756 }
00757 
00758 //______________________________________________________________________________
00759 Int_t TSQLFile::ReOpen(Option_t* mode)
00760 {
00761    // Reopen a file with a different access mode, like from READ to
00762    // See TFile::Open() for details
00763 
00764    cd();
00765 
00766    TString opt = mode;
00767    opt.ToUpper();
00768 
00769    if (opt != "READ" && opt != "UPDATE") {
00770       Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
00771       return 1;
00772    }
00773 
00774    if (opt == fOption || (opt == "UPDATE" && fOption == "CREATE"))
00775       return 1;
00776 
00777    if (opt == "READ") {
00778       // switch to READ mode
00779 
00780       if (IsOpen() && IsWritable()) {
00781          SaveToDatabase();
00782          SetLocking(kLockFree);
00783       }
00784       fOption = opt;
00785 
00786       SetWritable(kFALSE);
00787 
00788    } else {
00789       // switch to UPDATE mode
00790 
00791       if (!IsWriteAccess()) {
00792          Error("ReOpen","Tables are locked, no write access");
00793          return 1;
00794       }
00795 
00796       fOption = opt;
00797 
00798       SetWritable(kTRUE);
00799 
00800       SetLocking(kLockBusy);
00801    }
00802 
00803    return 0;
00804 }
00805 
00806 //______________________________________________________________________________
00807 TKey* TSQLFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t )
00808 {
00809    // create SQL key, which will store object in data base
00810    return new TKeySQL(mother, obj, name);
00811 }
00812 
00813 //______________________________________________________________________________
00814 TKey* TSQLFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t )
00815 {
00816    // create SQL key, which will store object in data base
00817    return new TKeySQL(mother, obj, cl, name);
00818 }
00819 
00820 //______________________________________________________________________________
00821 void TSQLFile::WriteHeader()
00822 {
00823    // Write file info like configurations, title, UUID and other
00824 
00825    WriteSpecialObject(sqlio::Ids_TSQLFile, this, GetName(), GetTitle());
00826 }
00827 
00828 //______________________________________________________________________________
00829 void TSQLFile::WriteStreamerInfo()
00830 {
00831    // Store all TVirtualStreamerInfo, used in file, in sql database
00832 
00833    // return;
00834 
00835    // do not write anything when no basic tables was created
00836    if (!IsTablesExists()) return;
00837 
00838    if (gDebug>1)
00839       Info("WriteStreamerInfo","Saving streamer infos to database");
00840 
00841    TList list;
00842 
00843    TIter iter(gROOT->GetListOfStreamerInfo());
00844 
00845    TVirtualStreamerInfo* info = 0;
00846 
00847    while ((info = (TVirtualStreamerInfo*) iter()) !=0 ) {
00848       Int_t uid = info->GetNumber();
00849       if (fClassIndex->fArray[uid]) {
00850          if (gDebug>1) Info("WriteStreamerInfo","Add %s",info->GetName());
00851          list.Add(info);
00852       }
00853    }
00854    if (list.GetSize()==0) return;
00855    fClassIndex->fArray[0] = 2; //to prevent adding classes in TVirtualStreamerInfo::TagFile
00856 
00857    WriteSpecialObject(sqlio::Ids_StreamerInfos, &list, "StreamerInfo", "StreamerInfos of this file");
00858 
00859    fClassIndex->fArray[0] = 0; //to prevent adding classes in TVirtualStreamerInfo::TagFile
00860 }
00861 
00862 //______________________________________________________________________________
00863 Bool_t TSQLFile::WriteSpecialObject(Long64_t keyid, TObject* obj, const char* name, const char* title)
00864 {
00865 // write special kind of object like streamer infos or file itself
00866 // keys for that objects should exist in tables but not indicated in list of keys,
00867 // therefore users can not get them with TDirectoryFile::Get() method
00868 
00869    DeleteKeyFromDB(keyid);
00870    if (obj==0) return kTRUE;
00871 
00872    Long64_t objid = StoreObjectInTables(keyid, obj, obj->IsA());
00873 
00874    if (objid>0) {
00875       TDatime now;
00876 
00877       TKeySQL* key = new TKeySQL(this, keyid, objid,
00878                                  name, title,
00879                                  now.AsSQLString(), 1, obj->ClassName());
00880       WriteKeyData(key);
00881       delete key;
00882    }
00883 
00884    return (objid>0);
00885 }
00886 
00887 //______________________________________________________________________________
00888 TObject* TSQLFile::ReadSpecialObject(Long64_t keyid, TObject* obj)
00889 {
00890    // Read data of special kind of objects
00891 
00892    TKeySQL* key = 0;
00893 
00894    StreamKeysForDirectory(this, kFALSE, keyid, &key);
00895    if (key==0) return obj;
00896 
00897    TBufferSQL2 buffer(TBuffer::kRead, this);
00898 
00899    TClass* cl = 0;
00900 
00901    void* res = buffer.SqlReadAny(key->GetDBKeyId(), key->GetDBObjId(), &cl, obj);
00902 
00903    if ((cl==TSQLFile::Class()) && (res!=0) && (obj==this)) {
00904       // name should not be preserved while name of database may be changed
00905       SetTitle(key->GetTitle());
00906    }
00907 
00908    delete key;
00909 
00910    return (TObject*) res;
00911 }
00912 
00913 //______________________________________________________________________________
00914 TList* TSQLFile::GetStreamerInfoList()
00915 {
00916    // Read back streamer infos from database
00917    // List of streamer infos is always stored with key:id 0,
00918    // which is not shown in normal keys list
00919 
00920 //   return new TList;
00921 
00922    if (gDebug>1)
00923       Info("GetStreamerInfoList","Start reading of streamer infos");
00924 
00925    TObject* obj = ReadSpecialObject(sqlio::Ids_StreamerInfos);
00926 
00927    TList* list = dynamic_cast<TList*> (obj);
00928    if (list==0) { delete obj; list = new TList; }
00929 
00930    return list;
00931 }
00932 
00933 //______________________________________________________________________________
00934 void TSQLFile::SaveToDatabase()
00935 {
00936    // save data which is not yet in Database
00937    // Typically this is streamerinfos structures or
00938 
00939    if (fSQL==0) return;
00940 
00941    WriteStreamerInfo();
00942    WriteHeader();
00943 }
00944 
00945 //______________________________________________________________________________
00946 Int_t TSQLFile::StreamKeysForDirectory(TDirectory* dir, Bool_t doupdate, Long64_t specialkeyid, TKeySQL** specialkey)
00947 {
00948    // read keys for specified directory (when update == kFALSE)
00949    // or update value for modified keys when update == kTRUE
00950    // Returns number of succesfully read keys or -1 if error
00951 
00952    if (dir==0) return -1;
00953 
00954    const char* quote = SQLIdentifierQuote();
00955 
00956    Long64_t dirid = dir->GetSeekDir();
00957 
00958    TString sqlcmd;
00959    sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s=%lld",
00960                quote, sqlio::KeysTable, quote,
00961                quote, SQLDirIdColumn(), quote, dirid);
00962    if (specialkeyid>=0) {
00963       TString buf;
00964       buf.Form(" AND %s%s%s=%lld", quote, SQLKeyIdColumn(), quote, specialkeyid);
00965       sqlcmd += buf;
00966    }
00967 
00968    TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
00969 
00970    if (res==0) return -1;
00971 
00972    Int_t nkeys = 0;
00973 
00974    TSQLRow* row = 0;
00975 
00976    while ((row = res->Next()) != 0) {
00977       nkeys++;
00978 
00979       Long64_t keyid = sqlio::atol64((*row)[0]);
00980       //      Int_t dirid = atoi((*row)[1]);
00981       Long64_t objid = sqlio::atol64((*row)[2]);
00982       const char* keyname = (*row)[3];
00983       const char* keytitle = (*row)[4];
00984       const char* keydatime = (*row)[5];
00985       Int_t cycle = atoi((*row)[6]);
00986       const char* classname = (*row)[7];
00987 
00988       if (gDebug>4)
00989         cout << "  Reading keyid = " << keyid << " name = " << keyname << endl;
00990 
00991       if ((keyid>=sqlio::Ids_FirstKey) || (keyid==specialkeyid)) {
00992          if (doupdate) {
00993             TKeySQL* key = FindSQLKey(dir, keyid);
00994 
00995             if (key==0) {
00996                Error("StreamKeysForDirectory","Key with id %lld not exist in list", keyid);
00997                nkeys = -1; // this will finish execution
00998             } else
00999             if (key->IsKeyModified(keyname, keytitle, keydatime, cycle, classname))
01000                UpdateKeyData(key);
01001 
01002          } else {
01003             TKeySQL* key = new TKeySQL(dir, keyid, objid,
01004                                        keyname, keytitle,
01005                                        keydatime, cycle, classname);
01006             if (specialkey!=0)
01007                { *specialkey = key; nkeys = 1; }
01008             else
01009                dir->GetListOfKeys()->Add(key);
01010          }
01011       }
01012       delete row;
01013    }
01014 
01015    delete res;
01016 
01017    if (gDebug>4) {
01018       Info("StreamKeysForDirectory","dir = %s numread = %d",dir->GetName(), nkeys);
01019       dir->GetListOfKeys()->Print("*");
01020    }
01021 
01022    return nkeys;
01023 }
01024 
01025 //______________________________________________________________________________
01026 void TSQLFile::InitSqlDatabase(Bool_t create)
01027 {
01028    // initialize sql database and correspondent structures
01029    // identical to TFile::Init() function
01030 
01031    Int_t len = gROOT->GetListOfStreamerInfo()->GetSize()+1;
01032    if (len<5000) len = 5000;
01033    fClassIndex = new TArrayC(len);
01034    fClassIndex->Reset(0);
01035 
01036    if (!create) {
01037 
01038       Bool_t ok = ReadConfigurations();
01039 
01040       // read data corresponding to TSQLFile
01041       if (ok) {
01042          ReadSQLClassInfos();
01043 
01044          ReadStreamerInfo();
01045 
01046          ok = (ReadSpecialObject(sqlio::Ids_TSQLFile, this) != 0);
01047       }
01048 
01049       // read list of keys
01050       if (ok)
01051          ok = StreamKeysForDirectory(this, kFALSE)>=0;
01052 
01053       if (!ok) {
01054          Error("InitSqlDatabase", "Cannot detect proper tabled in database. Close.");
01055          Close();
01056          delete fSQL;
01057          fSQL = 0;
01058          MakeZombie();
01059          gDirectory = gROOT;
01060          return;
01061       }
01062    }
01063 
01064    gROOT->GetListOfFiles()->Add(this);
01065    cd();
01066 
01067    fNProcessIDs = 0;
01068    TKey* key = 0;
01069    TIter iter(fKeys);
01070    while ((key = (TKey*)iter())!=0) {
01071       if (!strcmp(key->GetClassName(),"TProcessID")) fNProcessIDs++;
01072    }
01073 
01074    fProcessIDs = new TObjArray(fNProcessIDs+1);
01075 }
01076 
01077 //______________________________________________________________________________
01078 Bool_t TSQLFile::ReadConfigurations()
01079 {
01080    // read table configurations as special table
01081 
01082    const char* quote = SQLIdentifierQuote();
01083 
01084    TString sqlcmd;
01085    sqlcmd.Form("SELECT * FROM %s%s%s",
01086                quote, sqlio::ConfigTable, quote);
01087    TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
01088 
01089    if (res==0) return kFALSE;
01090 
01091    // should be found, otherwise will be error
01092    fSQLIOversion = 0;
01093 
01094    Int_t lock = 0;
01095 
01096    #define ReadIntCfg(name, target)                        \
01097      if ((field.CompareTo(name, TString::kIgnoreCase)==0)) \
01098         target = value.Atoi(); else
01099 
01100    #define ReadBoolCfg(name, target)                        \
01101      if ((field.CompareTo(name, TString::kIgnoreCase)==0))  \
01102         target = value.CompareTo(sqlio::True, TString::kIgnoreCase)==0; else
01103 
01104    #define ReadStrCfg(name, target)                         \
01105      if ((field.CompareTo(name, TString::kIgnoreCase)==0))  \
01106         target = value; else
01107 
01108    TSQLRow* row = 0;
01109 
01110    while ((row = res->Next()) != 0) {
01111 
01112       TString field = row->GetField(0);
01113       TString value = row->GetField(1);
01114 
01115       delete row;
01116 
01117       ReadIntCfg(sqlio::cfg_Version, fSQLIOversion)
01118       ReadBoolCfg(sqlio::cfg_UseSufixes, fUseSuffixes)
01119       ReadIntCfg(sqlio::cfg_ArrayLimit, fArrayLimit)
01120       ReadStrCfg(sqlio::cfg_TablesType, fTablesType)
01121       ReadIntCfg(sqlio::cfg_UseTransactions, fUseTransactions)
01122       ReadIntCfg(sqlio::cfg_UseIndexes, fUseIndexes)
01123       ReadIntCfg(sqlio::cfg_ModifyCounter, fModifyCounter)
01124       ReadIntCfg(sqlio::cfg_LockingMode, lock)
01125       {
01126          Error("ReadConfigurations","Invalid configuration field %s", field.Data());
01127          fSQLIOversion = 0;
01128          break;
01129       }
01130    }
01131 
01132    delete res;
01133 
01134    return (fSQLIOversion>0);
01135 }
01136 
01137 //______________________________________________________________________________
01138 void TSQLFile::CreateBasicTables()
01139 {
01140    // Creates initial tables in database
01141    // This is table with configurations and table with keys
01142    // Function called once when first object is stored to the file.
01143 
01144    TString sqlcmd;
01145 
01146    const char* quote = SQLIdentifierQuote();
01147    const char* vquote = SQLValueQuote();
01148 
01149    if (SQLTestTable(sqlio::ConfigTable)) {
01150       sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::ConfigTable, quote);
01151       SQLQuery(sqlcmd.Data());
01152    }
01153 
01154    sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s)",
01155                quote, sqlio::ConfigTable, quote,
01156                quote, sqlio::CT_Field, quote, SQLSmallTextType(),
01157                quote, sqlio::CT_Value, quote, SQLSmallTextType());
01158    if ((fTablesType.Length()>0) && IsMySQL()) {
01159       sqlcmd +=" TYPE=";
01160       sqlcmd += fTablesType;
01161    }
01162 
01163    SQLQuery(sqlcmd.Data());
01164 
01165    #define WrintCfg(name, type, value)                              \
01166    {                                                                \
01167       sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s%s%s, %s"type"%s)", \
01168                   quote, sqlio::ConfigTable, quote,                 \
01169                   vquote, name, vquote,                             \
01170                   vquote, value, vquote);                           \
01171       SQLQuery(sqlcmd.Data());                                      \
01172    }
01173 
01174    WrintCfg(sqlio::cfg_Version, "%d", fSQLIOversion);
01175    WrintCfg(sqlio::cfg_UseSufixes, "%s", fUseSuffixes ? sqlio::True : sqlio::False);
01176    WrintCfg(sqlio::cfg_ArrayLimit, "%d", fArrayLimit);
01177    WrintCfg(sqlio::cfg_TablesType, "%s", fTablesType.Data());
01178    WrintCfg(sqlio::cfg_UseTransactions, "%d", fUseTransactions);
01179    WrintCfg(sqlio::cfg_UseIndexes, "%d", fUseIndexes);
01180    WrintCfg(sqlio::cfg_ModifyCounter, "%d", fModifyCounter);
01181    WrintCfg(sqlio::cfg_LockingMode, "%d", kLockBusy);
01182 
01183    // from this moment on user cannot change configurations
01184    fCanChangeConfig = kFALSE;
01185 
01186    if (SQLTestTable(sqlio::KeysTable)) {
01187       sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::KeysTable, quote);
01188       SQLQuery(sqlcmd.Data());
01189    }
01190 
01191    sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s)",
01192                quote, sqlio::KeysTable, quote,
01193                quote, SQLKeyIdColumn(), quote, SQLIntType(),
01194                quote, SQLDirIdColumn(), quote, SQLIntType(),
01195                quote, SQLObjectIdColumn(), quote, SQLIntType(),
01196                quote, sqlio::KT_Name, quote, SQLSmallTextType(),
01197                quote, sqlio::KT_Title, quote, SQLSmallTextType(),
01198                quote, sqlio::KT_Datetime, quote, SQLDatetimeType(),
01199                quote, sqlio::KT_Cycle, quote, SQLIntType(),
01200                quote, sqlio::KT_Class, quote, SQLSmallTextType());
01201 
01202    if ((fTablesType.Length()>0) && IsMySQL()) {
01203       sqlcmd +=" TYPE=";
01204       sqlcmd += fTablesType;
01205    }
01206 
01207    SQLQuery(sqlcmd.Data());
01208 
01209    if (GetUseIndexes()>kIndexesNone) {
01210       sqlcmd.Form("CREATE UNIQUE INDEX %s%s%s ON %s%s%s (%s%s%s)",
01211                    quote, sqlio::KeysTableIndex, quote,
01212                    quote, sqlio::KeysTable, quote,
01213                    quote, SQLKeyIdColumn(), quote);
01214       SQLQuery(sqlcmd.Data());
01215    }
01216 }
01217 
01218 //______________________________________________________________________________
01219 void TSQLFile::IncrementModifyCounter()
01220 {
01221    // Update value of modify counter in config table
01222    // Modify counter used to indicate that something was changed in database.
01223    // It will be used when multiple instances of TSQLFile for the same data base
01224    // will be connected.
01225 
01226    if (!IsWritable()) {
01227       Error("IncrementModifyCounter","Cannot update tables without write accsess");
01228       return;
01229    }
01230 
01231    TString sqlcmd;
01232    const char* quote = SQLIdentifierQuote();
01233    const char* vquote = SQLValueQuote();
01234 
01235    sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%d WHERE %s%s%s=%s%s%s",
01236                 quote, sqlio::ConfigTable, quote,
01237                 quote, sqlio::CT_Value, quote, ++fModifyCounter,
01238                 quote, sqlio::CT_Field, quote,
01239                 vquote, sqlio::cfg_ModifyCounter, vquote);
01240    SQLQuery(sqlcmd.Data());
01241 }
01242 
01243 //______________________________________________________________________________
01244 TString TSQLFile::MakeSelectQuery(TClass* cl)
01245 {
01246    // Produce SELECT statement which can be used to get all data
01247    // of class cl in one SELECT statement
01248    // This statement also can be used to create VIEW by command like
01249    // mysql> CREATE VIEW TH1I_view AS $CLASSSELECT$
01250    // Where $CLASSSELECT$ argument should be produced by call
01251    //   f->MakeSelectQuery(TH1I::Class());
01252    // VIEWs supported by latest MySQL 5 and Oracle
01253 
01254    TString res = "";
01255    TSQLClassInfo* sqlinfo = FindSQLClassInfo(cl);
01256    if (sqlinfo==0) return res;
01257 
01258    TString columns, tables;
01259    Int_t tablecnt = 0;
01260 
01261    if (!ProduceClassSelectQuery(cl->GetStreamerInfo(), sqlinfo, columns, tables, tablecnt))
01262       return res;
01263 
01264    res.Form("SELECT %s FROM %s", columns.Data(), tables.Data());
01265 
01266    return res;
01267 }
01268 
01269 //______________________________________________________________________________
01270 Bool_t TSQLFile::ProduceClassSelectQuery(TVirtualStreamerInfo* info,
01271                                          TSQLClassInfo* sqlinfo,
01272                                          TString& columns,
01273                                          TString& tables,
01274                                          Int_t& tablecnt)
01275 {
01276    // used by MakeClassSelectQuery method to add columns from table of
01277    // class, specified by TVirtualStreamerInfo structure
01278 
01279    if ((info==0) || (sqlinfo==0)) return kFALSE;
01280 
01281    if (!sqlinfo->IsClassTableExist()) return kFALSE;
01282 
01283    const char* quote = SQLIdentifierQuote();
01284 
01285    TString table_syn;
01286    table_syn.Form("t%d", ++tablecnt);
01287 
01288    Bool_t start = tables.Length()==0;
01289 
01290    TString buf;
01291 
01292    if (start)
01293       buf.Form("%s AS %s", sqlinfo->GetClassTableName(), table_syn.Data());
01294    else
01295       buf.Form(" LEFT JOIN %s AS %s USING(%s%s%s)",
01296                sqlinfo->GetClassTableName(), table_syn.Data(),
01297                quote, SQLObjectIdColumn(), quote);
01298 
01299    tables += buf;
01300 
01301    if (start)
01302       columns.Form("%s.%s%s%s",table_syn.Data(), quote, SQLObjectIdColumn(), quote);
01303 
01304    if (info->GetClass()==TObject::Class()) {
01305       buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectUniqueId);
01306       columns+=buf;
01307       buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectBits);
01308       columns+=buf;
01309       buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectProcessId);
01310       columns+=buf;
01311       return kTRUE;
01312    }
01313 
01314    TIter iter(info->GetElements());
01315    TStreamerElement* elem = 0;
01316 
01317    while ((elem = (TStreamerElement*) iter()) != 0) {
01318       Int_t coltype = TSQLStructure::DefineElementColumnType(elem, this);
01319       TString colname = TSQLStructure::DefineElementColumnName(elem, this);
01320 
01321       buf = "";
01322       switch (coltype) {
01323 
01324          case TSQLStructure::kColObject:
01325          case TSQLStructure::kColObjectPtr:
01326          case TSQLStructure::kColTString:
01327          case TSQLStructure::kColSimple: {
01328             buf.Form(", %s.%s%s%s",table_syn.Data(), quote, colname.Data(), quote);
01329             columns+=buf;
01330             break;
01331          }
01332 
01333          case TSQLStructure::kColParent: {
01334             TClass* parentcl = elem->GetClassPointer();
01335             ProduceClassSelectQuery(parentcl->GetStreamerInfo(),
01336                                     FindSQLClassInfo(parentcl),
01337                                     columns, tables, tablecnt);
01338             break;
01339          }
01340 
01341          case TSQLStructure::kColSimpleArray: {
01342             for(Int_t n=0;n<elem->GetArrayLength();n++) {
01343                colname = TSQLStructure::DefineElementColumnName(elem, this, n);
01344                buf.Form(", %s.%s%s%s",table_syn.Data(), quote, colname.Data(), quote);
01345                columns+=buf;
01346             }
01347             break;
01348          }
01349       } // switch
01350    }
01351 
01352    return (columns.Length()>0) && (tables.Length()>0);
01353 }
01354 
01355 //______________________________________________________________________________
01356 Bool_t TSQLFile::IsTablesExists()
01357 {
01358    // Checks if main keys table is existing
01359 
01360    return SQLTestTable(sqlio::KeysTable) && SQLTestTable(sqlio::ConfigTable);
01361 }
01362 
01363 //______________________________________________________________________________
01364 Bool_t TSQLFile::IsWriteAccess()
01365 {
01366    // Checkis, if lock is free in configuration tables
01367 
01368    return GetLocking()==kLockFree;
01369 }
01370 
01371 //______________________________________________________________________________
01372 void TSQLFile::SetLocking(Int_t mode)
01373 {
01374    // Set locking mode for current database
01375 
01376    TString sqlcmd;
01377    const char* quote = SQLIdentifierQuote();
01378    const char* vquote = SQLValueQuote();
01379 
01380    sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%d WHERE %s%s%s=%s%s%s",
01381                 quote, sqlio::ConfigTable, quote,
01382                 quote, sqlio::CT_Value, quote, mode,
01383                 quote, sqlio::CT_Field, quote,
01384                 vquote, sqlio::cfg_LockingMode, vquote);
01385    SQLQuery(sqlcmd.Data());
01386 }
01387 
01388 //______________________________________________________________________________
01389 Int_t TSQLFile::GetLocking()
01390 {
01391    // Return current locking mode for that file
01392 
01393    const char* quote = SQLIdentifierQuote();
01394    const char* vquote = SQLValueQuote();
01395 
01396    TString sqlcmd;
01397    sqlcmd.Form("SELECT %s%s%s FROM %s%s%s WHERE %s%s%s=%s%s%s",
01398                 quote, sqlio::CT_Value, quote,
01399                 quote, sqlio::ConfigTable, quote,
01400                 quote, sqlio::CT_Field, quote,
01401                 vquote, sqlio::cfg_LockingMode, vquote);
01402 
01403    TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
01404    TSQLRow* row = (res==0) ? 0 : res->Next();
01405    TString field = (row==0) ? "" : row->GetField(0);
01406    delete row;
01407    delete res;
01408 
01409    if (field.Length()==0) return kLockFree;
01410 
01411    return field.Atoi();
01412 }
01413 
01414 //______________________________________________________________________________
01415 Bool_t TSQLFile::IsReadAccess()
01416 {
01417    // dummy, in future should check about read access to database
01418 
01419    return kTRUE;
01420 }
01421 
01422 //______________________________________________________________________________
01423 TSQLResult* TSQLFile::SQLQuery(const char* cmd, Int_t flag, Bool_t* ok)
01424 {
01425    // submits query to SQL server
01426    // if flag==0, result is not interesting and will be deleted
01427    // if flag==1, return result of submitted query
01428    // if flag==2, results is may be necessary for long time
01429    //             Oracle plugin do not support working with several TSQLResult
01430    //             objects, therefore explicit deep copy will be produced
01431    // If ok!=0, it will contains kTRUE is Query was successfull, otherwise kFALSE
01432 
01433    if (fLogFile!=0)
01434       *fLogFile << cmd << endl;
01435 
01436    if (ok!=0) *ok = kFALSE;
01437 
01438    if (fSQL==0) return 0;
01439 
01440    if (gDebug>2) Info("SQLQuery", "%s", cmd);
01441 
01442    fQuerisCounter++;
01443 
01444    if (flag==0) {
01445       Bool_t res = fSQL->Exec(cmd);
01446       if (ok!=0) *ok = res;
01447       return 0;
01448    }
01449 
01450    TSQLResult* res = fSQL->Query(cmd);
01451    if (ok!=0) *ok = res!=0;
01452    if (res==0) return 0;
01453 //   if ((flag==2) && IsOracle())
01454 //      res = new TSQLResultCopy(res);
01455    return res;
01456 }
01457 
01458 //______________________________________________________________________________
01459 Bool_t TSQLFile::SQLCanStatement()
01460 {
01461    // Test if DB support statement and number of open statements is not exceeded
01462 
01463    if (fSQL==0) return kFALSE;
01464 
01465    if (!fSQL->HasStatement()) return kFALSE;
01466 
01467    return kTRUE; // !IsOracle() || (fStmtCounter<15);
01468 }
01469 
01470 //______________________________________________________________________________
01471 TSQLStatement* TSQLFile::SQLStatement(const char* cmd, Int_t bufsize)
01472 {
01473    // Produces SQL statement for currently conected DB server
01474 
01475    if (fSQL==0) return 0;
01476 
01477    if (!fSQL->HasStatement()) return 0;
01478 
01479    if (gDebug>1)
01480       Info("SQLStatement", "%s", cmd);
01481 
01482    fStmtCounter++;
01483    fQuerisCounter++; // one statement counts as one query
01484 
01485    return fSQL->Statement(cmd, bufsize);
01486 }
01487 
01488 //______________________________________________________________________________
01489 void TSQLFile::SQLDeleteStatement(TSQLStatement* stmt)
01490 {
01491    // delete statement and decrease counter
01492 
01493    if (stmt==0) return;
01494 
01495    fStmtCounter--;
01496 
01497    delete stmt;
01498 }
01499 
01500 //______________________________________________________________________________
01501 Bool_t TSQLFile::SQLApplyCommands(TObjArray* cmds)
01502 {
01503    // supplies set of commands to server
01504    // Commands is stored as array of TObjString
01505 
01506    if ((cmds==0) || (fSQL==0)) return kFALSE;
01507 
01508    Bool_t ok = kTRUE;
01509    TIter iter(cmds);
01510    TObject* cmd= 0;
01511    while ((cmd=iter())!=0) {
01512       SQLQuery(cmd->GetName(),0,&ok);
01513       if(!ok) break;
01514    }
01515 
01516    return ok;
01517 }
01518 
01519 //______________________________________________________________________________
01520 Bool_t TSQLFile::SQLTestTable(const char* tablename)
01521 {
01522    // Test, if table of specified name exists
01523 
01524    if (fSQL==0) return kFALSE;
01525 
01526    if (fSQL->HasTable(tablename)) return kTRUE;
01527 
01528    TString buf(tablename);
01529    buf.ToLower();
01530    if (fSQL->HasTable(buf.Data())) return kTRUE;
01531    buf.ToUpper();
01532    return fSQL->HasTable(buf.Data());
01533 }
01534 
01535 //______________________________________________________________________________
01536 Long64_t TSQLFile::SQLMaximumValue(const char* tablename, const char* columnname)
01537 {
01538    // Returns maximum value, found in specified columnname of table tablename
01539    // Column type should be numeric
01540 
01541    if (fSQL==0) return -1;
01542 
01543    if (gDebug>2)
01544       Info("SQLMaximumValue","Requests for %s column %s", tablename, columnname);
01545 
01546    const char* quote = SQLIdentifierQuote();
01547 
01548    TString query;
01549    query.Form("SELECT MAX(%s%s%s) FROM %s%s%s",
01550               quote, columnname, quote,
01551               quote, tablename, quote);
01552    TSQLResult* res = SQLQuery(query.Data(), 1);
01553 
01554    if (res==0) return -1;
01555 
01556    TSQLRow* row = res->Next();
01557 
01558    Long64_t maxid = -1;
01559    if (row!=0)
01560       if (row->GetField(0)!=0)
01561          maxid = sqlio::atol64(row->GetField(0));
01562 
01563    delete row;
01564    delete res;
01565 
01566    if (gDebug>2)
01567       Info("SQLMaximumValue","Result = %lld",maxid);;
01568 
01569    return maxid;
01570 }
01571 
01572 //______________________________________________________________________________
01573 void TSQLFile::SQLDeleteAllTables()
01574 {
01575    // Delete all tables in database
01576 
01577    if (fSQL==0) return;
01578 
01579    TList* tables = fSQL->GetTablesList();
01580    if (tables==0) return;
01581 
01582    TString sqlcmd;
01583    const char* quote = SQLIdentifierQuote();
01584 
01585    TIter iter(tables);
01586    TObject* obj = 0;
01587    while ((obj=iter())!=0) {
01588       sqlcmd.Form("DROP TABLE %s%s%s", quote, obj->GetName(), quote);
01589       SQLQuery(sqlcmd.Data());
01590    }
01591    delete tables;
01592 }
01593 
01594 //______________________________________________________________________________
01595 Bool_t TSQLFile::SQLStartTransaction()
01596 {
01597    // Start SQL transaction.
01598 
01599    return fSQL ? fSQL->StartTransaction() : kFALSE;
01600 }
01601 
01602 //______________________________________________________________________________
01603 Bool_t TSQLFile::SQLCommit()
01604 {
01605    // Commit SQL transaction
01606 
01607    return fSQL ? fSQL->Commit() : kFALSE;
01608 }
01609 
01610 //______________________________________________________________________________
01611 Bool_t TSQLFile::SQLRollback()
01612 {
01613    // Rollback all SQL operations, done after start transaction
01614 
01615    return fSQL ? fSQL->Rollback() : kFALSE;
01616 }
01617 
01618 //______________________________________________________________________________
01619 Int_t TSQLFile::SQLMaxIdentifierLength()
01620 {
01621    // returns maximum allowed length of identifiers
01622 
01623    Int_t maxlen = fSQL==0 ? 32 : fSQL->GetMaxIdentifierLength();
01624 
01625    // lets exclude absolute ubnormal data
01626    if (maxlen<10) maxlen = 10;
01627 
01628    return maxlen;
01629 }
01630 
01631 //______________________________________________________________________________
01632 void TSQLFile::DeleteKeyFromDB(Long64_t keyid)
01633 {
01634 // remove key with specified id from keys table
01635 // also removes all objects data, related to this table
01636 
01637    if (!IsWritable() || (keyid<0) || (fSQL==0)) return;
01638 
01639    TString sqlcmd;
01640    const char* quote = SQLIdentifierQuote();
01641 
01642    sqlcmd.Form("SELECT MIN(%s%s%s), MAX(%s%s%s) FROM %s%s%s WHERE %s%s%s=%lld",
01643                quote, SQLObjectIdColumn(), quote,
01644                quote, SQLObjectIdColumn(), quote,
01645                quote, sqlio::ObjectsTable, quote,
01646                quote, SQLKeyIdColumn(), quote, keyid);
01647    TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
01648    TSQLRow* row = res==0 ? 0 : res->Next();
01649    Long64_t minid(1), maxid(0);
01650 
01651    if ((row!=0) && (row->GetField(0)!=0) && (row->GetField(1)!=0)) {
01652       minid = sqlio::atol64(row->GetField(0));
01653       maxid = sqlio::atol64(row->GetField(1));
01654    }
01655 
01656    delete row;
01657    delete res;
01658 
01659    // can be that object tables does not include any entry this that keyid
01660    if (minid<=maxid) {
01661       TIter iter(fSQLClassInfos);
01662       TSQLClassInfo* info = 0;
01663       TString querymask, query;
01664       querymask.Form("DELETE FROM %s%s%s WHERE %s%s%s BETWEEN %lld AND %lld",
01665                      quote, "%s", quote,
01666                      quote, SQLObjectIdColumn(), quote,
01667                      minid, maxid);
01668 
01669       while ((info = (TSQLClassInfo*) iter()) !=0 ) {
01670 
01671          if (info->IsClassTableExist()) {
01672             query.Form(querymask.Data(), info->GetClassTableName());
01673             SQLQuery(query.Data());
01674          }
01675 
01676          if (info->IsRawTableExist()) {
01677             query.Form(querymask.Data(), info->GetRawTableName());
01678             SQLQuery(query.Data());
01679          }
01680       }
01681    }
01682 
01683    sqlcmd.Form("DELETE FROM %s%s%s WHERE %s%s%s=%lld", quote, sqlio::ObjectsTable, quote, quote, SQLKeyIdColumn(), quote, keyid);
01684    SQLQuery(sqlcmd.Data());
01685 
01686    sqlcmd.Form("DELETE FROM %s%s%s WHERE %s%s%s=%lld", quote, sqlio::KeysTable, quote, quote, SQLKeyIdColumn(), quote, keyid);
01687    SQLQuery(sqlcmd.Data());
01688 
01689    IncrementModifyCounter();
01690 }
01691 
01692 //______________________________________________________________________________
01693 TKeySQL* TSQLFile::FindSQLKey(TDirectory* dir, Long64_t keyid)
01694 {
01695    // Search for TKeySQL object with specified keyid
01696 
01697    if (dir==0) return 0;
01698 
01699    TIter next(dir->GetListOfKeys());
01700    TObject* obj = 0;
01701 
01702    while ((obj = next())!=0) {
01703       TKeySQL* key = dynamic_cast<TKeySQL*> (obj);
01704       if (key!=0)
01705          if (key->GetDBKeyId()==keyid) return key;
01706    }
01707 
01708    return 0;
01709 }
01710 
01711 //______________________________________________________________________________
01712 Bool_t TSQLFile::WriteKeyData(TKeySQL* key)
01713 {
01714    // add entry into keys table
01715 
01716    if ((fSQL==0) || (key==0)) return kFALSE;
01717 
01718    if (!IsTablesExists()) CreateBasicTables();
01719 
01720    TString sqlcmd;
01721    const char* valuequote = SQLValueQuote();
01722    const char* quote = SQLIdentifierQuote();
01723 
01724    sqlcmd.Form("INSERT INTO %s%s%s VALUES (%lld, %lld, %lld, %s%s%s, %s%s%s, %s%s%s, %d, %s%s%s)",
01725                quote, sqlio::KeysTable, quote,
01726                key->GetDBKeyId(), key->GetDBDirId(), key->GetDBObjId(),
01727                valuequote, key->GetName(), valuequote,
01728                valuequote, key->GetTitle(), valuequote,
01729                valuequote, key->GetDatime().AsSQLString(), valuequote,
01730                key->GetCycle(),
01731                valuequote, key->GetClassName(), valuequote);
01732 
01733    Bool_t ok = kTRUE;
01734 
01735    SQLQuery(sqlcmd.Data(), 0, &ok);
01736 
01737    if (ok) IncrementModifyCounter();
01738 
01739    return ok;
01740 }
01741 
01742 //______________________________________________________________________________
01743 Bool_t TSQLFile::UpdateKeyData(TKeySQL* key)
01744 {
01745    // updates (overwrites) key data in KeysTable
01746 
01747    if ((fSQL==0) || (key==0)) return kFALSE;
01748 
01749    TString sqlcmd;
01750    const char* valuequote = SQLValueQuote();
01751    const char* quote = SQLIdentifierQuote();
01752 
01753    TString keyname = key->GetName();
01754    TString keytitle = key->GetTitle();
01755    TString keydatime = key->GetDatime().AsSQLString();
01756 
01757    TSQLStructure::AddStrBrackets(keyname, valuequote);
01758    TSQLStructure::AddStrBrackets(keytitle, valuequote);
01759    TSQLStructure::AddStrBrackets(keydatime, valuequote);
01760 
01761    sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%s, %s%s%s=%s, %s%s%s=%s, %s%s%s=%d WHERE %s%s%s=%lld",
01762                 quote, sqlio::KeysTable, quote,
01763                 quote, sqlio::KT_Name, quote, keyname.Data(),
01764                 quote, sqlio::KT_Title, quote, keytitle.Data(),
01765                 quote, sqlio::KT_Datetime, quote, keydatime.Data(),
01766                 quote, sqlio::KT_Cycle, quote, key->GetCycle(),
01767                 quote, SQLKeyIdColumn(), quote, key->GetDBKeyId());
01768 
01769    Bool_t ok = kTRUE;
01770 
01771    SQLQuery(sqlcmd.Data(), 0, &ok);
01772 
01773    if (ok) IncrementModifyCounter();
01774 
01775    return ok;
01776 }
01777 
01778 //______________________________________________________________________________
01779 Long64_t TSQLFile::DefineNextKeyId()
01780 {
01781    // Returns next possible key identifier
01782 
01783    Long64_t max = -1;
01784 
01785    if (SQLTestTable(sqlio::KeysTable))
01786       max = SQLMaximumValue(sqlio::KeysTable, SQLKeyIdColumn());
01787 
01788    if (max<0) return sqlio::Ids_FirstKey;
01789 
01790    return max+1;
01791 }
01792 
01793 //______________________________________________________________________________
01794 TSQLClassInfo* TSQLFile::FindSQLClassInfo(const char* clname, Int_t version)
01795 {
01796    // return (if exists) TSQLClassInfo for specified class name and version
01797 
01798    if (fSQLClassInfos==0) return 0;
01799 
01800    TIter iter(fSQLClassInfos);
01801    TSQLClassInfo* info = 0;
01802 
01803    while ((info = (TSQLClassInfo*) iter()) !=0 ) {
01804       if (strcmp(info->GetName(), clname)==0)
01805          if (info->GetClassVersion()==version) return info;
01806    }
01807    return 0;
01808 }
01809 
01810 //______________________________________________________________________________
01811 TSQLClassInfo* TSQLFile::FindSQLClassInfo(const TClass* cl)
01812 {
01813    // return (if exists) TSQLClassInfo for specified class
01814 
01815    return FindSQLClassInfo(cl->GetName(), cl->GetClassVersion());
01816 }
01817 
01818 //______________________________________________________________________________
01819 TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const char* clname, Int_t version)
01820 {
01821    // search in database tables for specified class and return TSQLClassInfo object
01822 
01823    TSQLClassInfo* info = FindSQLClassInfo(clname, version);
01824    if (info!=0) return info;
01825 
01826    if (fSQL==0) return 0;
01827 
01828    Long64_t maxid = 0;
01829 
01830    if (fSQLClassInfos!=0) {
01831       TIter iter(fSQLClassInfos);
01832       info = 0;
01833       while ((info = (TSQLClassInfo*) iter()) !=0 ) {
01834          if (info->GetClassId()>maxid)
01835             maxid = info->GetClassId();
01836       }
01837    }
01838 
01839    info = new TSQLClassInfo(maxid+1, clname, version);
01840 
01841    info->SetClassTableName(DefineTableName(clname, version, kFALSE));
01842    info->SetRawTableName(DefineTableName(clname, version, kTRUE));
01843 
01844    if (fSQLClassInfos==0) fSQLClassInfos = new TList;
01845    fSQLClassInfos->Add(info);
01846 
01847    return info;
01848 }
01849 
01850 //______________________________________________________________________________
01851 TString TSQLFile::DefineTableName(const char* clname, Int_t version, Bool_t rawtable)
01852 {
01853    // proposes table name for class
01854 
01855    Int_t maxlen = SQLMaxIdentifierLength();
01856 
01857    TString res;
01858 
01859    const char *suffix = rawtable ? "_raw" : "_ver";
01860 
01861    res.Form("%s%s%d", clname, suffix, version);
01862 
01863    if ((res.Length() <= maxlen) && !HasTable(res.Data()))
01864       return res;
01865 
01866    TString scnt;
01867 
01868    Int_t len = strlen(clname);
01869    Int_t cnt = version;
01870    if (cnt>100) cnt = 0; // do not start with the biggest values
01871 
01872    do {
01873       scnt.Form("%d%s",cnt, suffix);
01874       Int_t numlen = scnt.Length();
01875       if (numlen>=maxlen-2) break;
01876 
01877       res = clname;
01878 
01879       if (len + numlen > maxlen)
01880          res.Resize(maxlen - numlen);
01881 
01882       res+=scnt;
01883 
01884       if (!HasTable(res.Data())) return res;
01885 
01886       cnt++;
01887 
01888    } while (cnt<10000);
01889 
01890    Error("DefineTableName","Cannot produce table name for class %s ver %d", clname, version);
01891    res.Form("%s%s%d", clname, suffix, version);
01892 
01893    return res;
01894 }
01895 
01896 //______________________________________________________________________________
01897 Bool_t TSQLFile::HasTable(const char* name)
01898 {
01899    // test if table name exists
01900 
01901    if (fSQLClassInfos==0) return kFALSE;
01902 
01903    TIter iter(fSQLClassInfos);
01904    TSQLClassInfo* info = 0;
01905    while ((info = (TSQLClassInfo*) iter()) !=0 ) {
01906       if (strcmp(info->GetClassTableName(), name)==0) return kTRUE;
01907       if (strcmp(info->GetRawTableName(), name)==0) return kTRUE;
01908    }
01909 
01910    return kFALSE;
01911 }
01912 
01913 //______________________________________________________________________________
01914 TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const TClass* cl)
01915 {
01916    // search in database tables for specified class and return TSQLClassInfo object
01917 
01918    return RequestSQLClassInfo(cl->GetName(), cl->GetClassVersion());
01919 }
01920 
01921 //______________________________________________________________________________
01922 void TSQLFile::ReadSQLClassInfos()
01923 {
01924    // Read all class infos from IdsTable
01925 
01926    if (fSQL==0) return;
01927 
01928    fIdsTableExists = SQLTestTable(sqlio::IdsTable);
01929 
01930    if (!fIdsTableExists) return;
01931 
01932    TString sqlcmd;
01933    const char* quote = SQLIdentifierQuote();
01934 
01935    sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %d ORDER BY %s%s%s",
01936                 quote, sqlio::IdsTable, quote,
01937                 quote, sqlio::IT_Type, quote, TSQLStructure::kIdTable,
01938                 quote, sqlio::IT_TableID, quote);
01939 
01940    TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
01941 
01942    TSQLRow* row = 0;
01943 
01944    if (res!=0)
01945       while ((row = res->Next())!=0) {
01946          Long64_t tableid = sqlio::atol64(row->GetField(0));
01947          Int_t version = atoi(row->GetField(1));
01948 
01949          const char* classname = row->GetField(3);
01950          const char* classtable = row->GetField(4);
01951 
01952          TSQLClassInfo* info = new TSQLClassInfo(tableid, classname, version);
01953          info->SetClassTableName(classtable);
01954 
01955          if (fSQLClassInfos==0) fSQLClassInfos = new TList;
01956          fSQLClassInfos->Add(info);
01957 
01958          delete row;
01959       }
01960    delete res;
01961 
01962 
01963    TIter next(fSQLClassInfos);
01964    TSQLClassInfo* info = 0;
01965 
01966    while ((info = (TSQLClassInfo*) next()) != 0) {
01967       sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %lld ORDER BY %s%s%s",
01968                    quote, sqlio::IdsTable, quote,
01969                    quote, sqlio::IT_TableID, quote, info->GetClassId(),
01970                    quote, sqlio::IT_SubID, quote);
01971       res = SQLQuery(sqlcmd.Data(), 1);
01972 
01973       TObjArray* cols = 0;
01974 
01975       if (res!=0)
01976          while ((row = res->Next())!=0) {
01977 
01978             Int_t typ = atoi(row->GetField(2));
01979 
01980             const char* fullname = row->GetField(3);
01981             const char* sqlname = row->GetField(4);
01982             const char* info2 = row->GetField(5);
01983 
01984             if (typ==TSQLStructure::kIdColumn) {
01985                 if (cols==0) cols = new TObjArray;
01986                 cols->Add(new TSQLClassColumnInfo(fullname, sqlname, info2));
01987             }
01988 
01989             delete row;
01990          }
01991 
01992       delete res;
01993 
01994       info->SetColumns(cols);
01995    }
01996 
01997    sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %d ORDER BY %s%s%s",
01998                 quote, sqlio::IdsTable, quote,
01999                 quote, sqlio::IT_Type, quote, TSQLStructure::kIdRawTable,
02000                 quote, sqlio::IT_TableID, quote);
02001 
02002    res = SQLQuery(sqlcmd.Data(), 1);
02003 
02004    if (res!=0)
02005       while ((row = res->Next())!=0) {
02006          Long64_t tableid = sqlio::atol64(row->GetField(0));
02007          Int_t version = atoi(row->GetField(1));
02008 
02009          const char* classname = row->GetField(3);
02010          const char* rawtable = row->GetField(4);
02011 
02012          TSQLClassInfo* info2 = FindSQLClassInfo(classname, version);
02013 
02014          if (info2==0) {
02015             info2 = new TSQLClassInfo(tableid, classname, version);
02016 
02017             if (fSQLClassInfos==0) fSQLClassInfos = new TList;
02018             fSQLClassInfos->Add(info2);
02019          }
02020 
02021          info2->SetRawTableName(rawtable);
02022          info2->SetRawExist(kTRUE);
02023 
02024          delete row;
02025       }
02026 
02027    delete res;
02028 }
02029 
02030 
02031 //______________________________________________________________________________
02032 void TSQLFile::AddIdEntry(Long64_t tableid, Int_t subid, Int_t type,
02033                           const char* name, const char* sqlname, const char* info)
02034 {
02035    // Add entry into IdsTable, where all tables names and columns names are listed
02036 
02037    if ((fSQL==0) || !IsWritable()) return;
02038 
02039    TString sqlcmd;
02040    const char* valuequote = SQLValueQuote();
02041    const char* quote = SQLIdentifierQuote();
02042 
02043    if (!fIdsTableExists) {
02044 
02045       if (SQLTestTable(sqlio::IdsTable)) {
02046          sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::IdsTable, quote);
02047          SQLQuery(sqlcmd.Data());
02048       }
02049 
02050       sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s)",
02051                   quote, sqlio::IdsTable, quote,
02052                   quote, sqlio::IT_TableID, quote, SQLIntType(),
02053                   quote, sqlio::IT_SubID, quote, SQLIntType(),
02054                   quote, sqlio::IT_Type, quote, SQLIntType(),
02055                   quote, sqlio::IT_FullName, quote, SQLSmallTextType(),
02056                   quote, sqlio::IT_SQLName, quote, SQLSmallTextType(),
02057                   quote, sqlio::IT_Info, quote, SQLSmallTextType());
02058       if ((fTablesType.Length()>0) && IsMySQL()) {
02059          sqlcmd +=" TYPE=";
02060          sqlcmd += fTablesType;
02061       }
02062       SQLQuery(sqlcmd.Data());
02063 
02064       fIdsTableExists = kTRUE;
02065    }
02066 
02067    sqlcmd.Form("INSERT INTO %s%s%s VALUES (%lld, %d, %d, %s%s%s, %s%s%s, %s%s%s)",
02068                quote, sqlio::IdsTable, quote,
02069                tableid, subid, type,
02070                valuequote, name, valuequote,
02071                valuequote, sqlname, valuequote,
02072                valuequote, info, valuequote);
02073 
02074    SQLQuery(sqlcmd.Data());
02075 }
02076 
02077 //______________________________________________________________________________
02078 Bool_t TSQLFile::CreateClassTable(TSQLClassInfo* sqlinfo, TObjArray* colinfos)
02079 {
02080    // Create normal class table if required
02081 
02082    if (sqlinfo==0) return kFALSE;
02083 
02084    // this is normal situation, when no extra column infos was created when not necessary
02085    if (colinfos==0) return sqlinfo->IsClassTableExist();
02086 
02087    if (sqlinfo->IsClassTableExist()) {
02088       if (colinfos!=0) {
02089          colinfos->Delete();
02090          delete colinfos;
02091          //Error("CreateClassTable","Why colinfos for table %s", sqlinfo->GetClassTableName());
02092       }
02093       return kTRUE;
02094    }
02095 
02096    if (gDebug>2)
02097       Info("CreateClassTable", "cl:%s", sqlinfo->GetName());
02098 
02099    const char* quote = SQLIdentifierQuote();
02100 
02101    AddIdEntry(sqlinfo->GetClassId(),
02102               sqlinfo->GetClassVersion(),
02103               TSQLStructure::kIdTable,
02104               sqlinfo->GetName(),
02105               sqlinfo->GetClassTableName(),
02106               "Main class table");
02107 
02108    TString sqlcmd;
02109    sqlcmd.Form("CREATE TABLE %s%s%s (",
02110                 quote, sqlinfo->GetClassTableName(), quote);
02111 
02112    TIter iter(colinfos);
02113    TSQLClassColumnInfo* col;
02114    Bool_t first = kTRUE;
02115    Bool_t forcequote = IsOracle();
02116    Int_t colid = 0;
02117    while ((col=(TSQLClassColumnInfo*)iter())!=0) {
02118       if (!first) sqlcmd+=", "; else first = false;
02119 
02120       const char* colname = col->GetSQLName();
02121       if ((strpbrk(colname,"[:.]<>")!=0) || forcequote) {
02122          sqlcmd += quote;
02123          sqlcmd += colname;
02124          sqlcmd += quote;
02125          sqlcmd += " ";
02126       } else {
02127          sqlcmd += colname,
02128          sqlcmd += " ";
02129       }
02130 
02131       sqlcmd += col->GetSQLType();
02132 
02133       AddIdEntry(sqlinfo->GetClassId(),
02134                  colid++,
02135                  TSQLStructure::kIdColumn,
02136                  col->GetName(),
02137                  col->GetSQLName(),
02138                  col->GetSQLType());
02139    }
02140    sqlcmd += ")";
02141 
02142    if ((fTablesType.Length()>0)  && IsMySQL()) {
02143       sqlcmd +=" TYPE=";
02144       sqlcmd += fTablesType;
02145    }
02146 
02147    SQLQuery(sqlcmd.Data());
02148 
02149    sqlinfo->SetColumns(colinfos);
02150 
02151    if (GetUseIndexes()>kIndexesBasic) {
02152 
02153       TString indxname = sqlinfo->GetClassTableName();
02154       indxname.ReplaceAll("_ver","_i1x");
02155 
02156       sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I1%s ON %s%s%s (%s%s%s)",
02157                   quote, indxname.Data(), quote,
02158                   quote, sqlinfo->GetClassTableName(), quote,
02159                   quote, SQLObjectIdColumn(), quote);
02160       SQLQuery(sqlcmd.Data());
02161    }
02162 
02163    return kTRUE;
02164 }
02165 
02166 //______________________________________________________________________________
02167 Bool_t TSQLFile::CreateRawTable(TSQLClassInfo* sqlinfo)
02168 {
02169    //create the raw table
02170    if (sqlinfo==0) return kFALSE;
02171 
02172    if (sqlinfo->IsRawTableExist()) return kTRUE;
02173 
02174    const char* quote = SQLIdentifierQuote();
02175 
02176    if (gDebug>2)
02177       Info("CreateRawTable", "%s", sqlinfo->GetName());
02178 
02179    TString sqlcmd;
02180 
02181    sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s %s, %s %s)",
02182                quote, sqlinfo->GetRawTableName(), quote,
02183                quote, SQLObjectIdColumn(), quote, SQLIntType(),
02184                quote, SQLRawIdColumn(), quote, SQLIntType(),
02185                sqlio::BT_Field, SQLSmallTextType(),
02186                sqlio::BT_Value, SQLSmallTextType());
02187 
02188    if ((fTablesType.Length()>0) && IsMySQL()) {
02189       sqlcmd +=" TYPE=";
02190       sqlcmd += fTablesType;
02191    }
02192 
02193    SQLQuery(sqlcmd.Data());
02194    sqlinfo->SetRawExist(kTRUE);
02195 
02196    if (GetUseIndexes()>kIndexesClass) {
02197       TString indxname = sqlinfo->GetClassTableName();
02198       indxname.ReplaceAll("_ver","_i2x");
02199 
02200       sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I2%s ON %s%s%s (%s%s%s, %s%s%s)",
02201                   quote, indxname.Data(), quote,
02202                   quote, sqlinfo->GetRawTableName(), quote,
02203                   quote, SQLObjectIdColumn(), quote,
02204                   quote, SQLRawIdColumn(), quote);
02205       SQLQuery(sqlcmd.Data());
02206    }
02207 
02208    AddIdEntry(sqlinfo->GetClassId(),
02209               sqlinfo->GetClassVersion(),
02210               TSQLStructure::kIdRawTable,
02211               sqlinfo->GetName(),
02212               sqlinfo->GetRawTableName(),
02213               "Raw data class table");
02214 
02215    return kTRUE;
02216 }
02217 
02218 //______________________________________________________________________________
02219 Bool_t TSQLFile::VerifyLongStringTable()
02220 {
02221    // Checks that table for big strings is exists
02222    // If not, will be created
02223 
02224    if (fSQL==0) return kFALSE;
02225 
02226    if (SQLTestTable(sqlio::StringsTable)) return kTRUE;
02227 
02228    const char* quote = SQLIdentifierQuote();
02229 
02230    TString sqlcmd;
02231    sqlcmd.Form("CREATE TABLE %s (%s%s%s %s, %s%s%s %s, %s %s)",
02232                sqlio::StringsTable,
02233                quote, SQLObjectIdColumn(), quote, SQLIntType(),
02234                quote, SQLStrIdColumn(), quote, SQLIntType(),
02235                sqlio::ST_Value, SQLBigTextType());
02236 
02237    if (fTablesType.Length()>0) {
02238       sqlcmd +=" TYPE=";
02239       sqlcmd += fTablesType;
02240    }
02241 
02242    SQLQuery(sqlcmd.Data());
02243 
02244    return kTRUE;
02245 }
02246 
02247 //______________________________________________________________________________
02248 TString TSQLFile::CodeLongString(Long64_t objid, Int_t strid)
02249 {
02250    // produces id which will be placed in column instead of string itself
02251    TString res;
02252    res.Form("%s %lld %s %d %s", sqlio::LongStrPrefix, objid, sqlio::LongStrPrefix, strid, sqlio::LongStrPrefix);
02253    return res;
02254 }
02255 
02256 //______________________________________________________________________________
02257 Int_t TSQLFile::IsLongStringCode(Long64_t objid, const char* value)
02258 {
02259    // checks if this is long string code
02260    // returns 0, if not or string id
02261    if (value==0) return 0;
02262    if (strlen(value)<strlen(sqlio::LongStrPrefix)*3+6) return 0;
02263    if (strstr(value, sqlio::LongStrPrefix)!=value) return 0;
02264 
02265    value+=strlen(sqlio::LongStrPrefix);
02266    if (*value++!=' ') return 0;
02267    TString s_strid, s_objid;
02268    if ((*value<'1') || (*value>'9')) return 0;
02269    do {
02270       s_objid.Append(*value++);
02271    } while ((*value!=0) && (*value>='0') && (*value<='9'));
02272 
02273    if (*value++ != ' ') return 0;
02274    if ((*value==0) || (strstr(value, sqlio::LongStrPrefix)!=value)) return 0;
02275    value+=strlen(sqlio::LongStrPrefix);
02276    if (*value++!=' ') return 0;
02277 
02278    if ((*value<'1') || (*value>'9')) return 0;
02279    do {
02280       s_strid.Append(*value++);
02281    } while ((*value!=0) && (*value>='0') && (*value<='9'));
02282    if (*value++!=' ') return 0;
02283 
02284    if ((*value==0) || (strcmp(value, sqlio::LongStrPrefix)!=0)) return 0;
02285 
02286    Long64_t objid2 = sqlio::atol64(s_objid.Data());
02287    if (objid2!=objid) return 0;
02288 
02289    return atoi(s_strid.Data());
02290 }
02291 
02292 //______________________________________________________________________________
02293 Bool_t TSQLFile::GetLongString(Long64_t objid, Int_t strid, TString& value)
02294 {
02295    // returns value of string, extracted from special table,
02296    // where long strings are stored
02297 
02298    if (!SQLTestTable(sqlio::StringsTable)) return kFALSE;
02299 
02300    TString cmd;
02301    const char* quote = SQLIdentifierQuote();
02302    cmd.Form("SELECT %s FROM %s%s%s WHERE %s%s%s=%lld AND %s%s%s=%d",
02303             sqlio::ST_Value,
02304             quote, sqlio::StringsTable, quote,
02305             quote, SQLObjectIdColumn(), quote, objid,
02306             quote, SQLStrIdColumn(), quote, strid);
02307 
02308    TSQLResult* res = SQLQuery(cmd.Data(), 1);
02309    if (res==0) return kFALSE;
02310    TSQLRow* row = res->Next();
02311    if (row==0) { delete res; return kFALSE; }
02312    value = row->GetField(0);
02313 
02314    delete row;
02315    delete res;
02316 
02317    return kTRUE;
02318 }
02319 
02320 //______________________________________________________________________________
02321 Long64_t TSQLFile::VerifyObjectTable()
02322 {
02323    // Checks that objects table is exists
02324    // If not, table will be created
02325    // Returns maximum value for existing objects id
02326 
02327    if (fSQL==0) return -1;
02328 
02329    Long64_t maxid = -1;
02330 
02331    if (gDebug>2)
02332       Info("VerifyObjectTable", "Checks if object table is there");
02333 
02334    if (SQLTestTable(sqlio::ObjectsTable))
02335       maxid = SQLMaximumValue(sqlio::ObjectsTable, SQLObjectIdColumn());
02336    else {
02337       TString sqlcmd;
02338       const char* quote = SQLIdentifierQuote();
02339       sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s)",
02340                   quote, sqlio::ObjectsTable, quote,
02341                   quote, SQLKeyIdColumn(), quote, SQLIntType(),
02342                   quote, SQLObjectIdColumn(), quote, SQLIntType(),
02343                   quote, sqlio::OT_Class, quote, SQLSmallTextType(),
02344                   quote, sqlio::OT_Version, quote, SQLIntType());
02345 
02346       if ((fTablesType.Length()>0) && IsMySQL()) {
02347          sqlcmd +=" TYPE=";
02348          sqlcmd += fTablesType;
02349       }
02350 
02351       SQLQuery(sqlcmd.Data());
02352 
02353       if (GetUseIndexes()>kIndexesNone) {
02354          sqlcmd.Form("CREATE UNIQUE INDEX %s%s%s ON %s%s%s (%s%s%s)",
02355                       quote, sqlio::ObjectsTableIndex, quote,
02356                       quote, sqlio::ObjectsTable, quote,
02357                       quote, SQLObjectIdColumn(), quote);
02358          SQLQuery(sqlcmd.Data());
02359       }
02360    }
02361 
02362    return maxid;
02363 }
02364 
02365 //______________________________________________________________________________
02366 Bool_t TSQLFile::SQLObjectInfo(Long64_t objid, TString& clname, Version_t &version)
02367 {
02368    // Read from objects table data for specified objectid
02369 
02370    if (fSQL==0) return kFALSE;
02371 
02372    TString sqlcmd;
02373    const char* quote = SQLIdentifierQuote();
02374    sqlcmd.Form("SELECT %s%s%s, %s%s%s FROM %s%s%s WHERE %s%s%s=%lld",
02375                quote, sqlio::OT_Class, quote,
02376                quote, sqlio::OT_Version, quote,
02377                quote, sqlio::ObjectsTable, quote,
02378                quote, SQLObjectIdColumn(), quote, objid);
02379    TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
02380    if (res==0) return kFALSE;
02381    TSQLRow* row = res->Next();
02382    if (row!=0) {
02383       clname = row->GetField(0);
02384       version = atoi(row->GetField(1));
02385    }
02386 
02387    delete row;
02388    delete res;
02389    return row!=0;
02390 }
02391 
02392 //______________________________________________________________________________
02393 TObjArray* TSQLFile::SQLObjectsInfo(Long64_t keyid)
02394 {
02395 // Produce array of TSQLObjectInfo objects for all objects, belong to that key
02396 // Array should be deleted by calling function afterwards
02397    if (fSQL==0) return 0;
02398 
02399    TString sqlcmd;
02400    const char* quote = SQLIdentifierQuote();
02401    sqlcmd.Form("SELECT %s%s%s, %s%s%s, %s%s%s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
02402                quote, SQLObjectIdColumn(), quote,
02403                quote, sqlio::OT_Class, quote,
02404                quote, sqlio::OT_Version, quote,
02405                quote, sqlio::ObjectsTable, quote,
02406                quote, SQLKeyIdColumn(), quote, keyid,
02407                quote, SQLObjectIdColumn(), quote);
02408 
02409    TObjArray* arr = 0;
02410 
02411    if (fLogFile!=0)
02412       *fLogFile << sqlcmd << endl;
02413    if (gDebug>2) Info("SQLObjectsInfo", "%s", sqlcmd.Data());
02414    fQuerisCounter++;
02415 
02416    TSQLStatement* stmt = SQLStatement(sqlcmd.Data(), 1000);
02417 
02418    if (stmt!=0) {
02419       stmt->Process();
02420       stmt->StoreResult();
02421 
02422       while (stmt->NextResultRow()) {
02423          Long64_t objid = stmt->GetLong64(0);
02424          const char* clname = stmt->GetString(1);
02425          Int_t version = stmt->GetInt(2);
02426 
02427          TSQLObjectInfo* info = new TSQLObjectInfo(objid, clname, version);
02428          if (arr==0) arr = new TObjArray();
02429          arr->Add(info);
02430       }
02431 
02432       delete stmt;
02433       return arr;
02434    }
02435 
02436    TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
02437    if (res==0) return 0;
02438 
02439    TSQLRow* row = 0;
02440    while ((row = res->Next()) != 0) {
02441       Long64_t objid = atoi(row->GetField(0));
02442       const char* clname = row->GetField(1);
02443       Int_t version = atoi(row->GetField(2));
02444 
02445       TSQLObjectInfo* info = new TSQLObjectInfo(objid, clname, version);
02446       if (arr==0) arr = new TObjArray();
02447       arr->Add(info);
02448 
02449       delete row;
02450    }
02451    delete res;
02452    return arr;
02453 }
02454 
02455 //______________________________________________________________________________
02456 TSQLResult* TSQLFile::GetNormalClassData(Long64_t objid, TSQLClassInfo* sqlinfo)
02457 {
02458 // Method return request result for specified objid from normal classtable
02459 
02460    if (!sqlinfo->IsClassTableExist()) return 0;
02461    TString sqlcmd;
02462    const char* quote = SQLIdentifierQuote();
02463    sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s=%lld",
02464                quote, sqlinfo->GetClassTableName(), quote,
02465                quote, SQLObjectIdColumn(), quote, objid);
02466    return SQLQuery(sqlcmd.Data(), 2);
02467 }
02468 
02469 //______________________________________________________________________________
02470 TSQLResult* TSQLFile::GetNormalClassDataAll(Long64_t minobjid, Long64_t maxobjid, TSQLClassInfo* sqlinfo)
02471 {
02472    // return data for several objects from the range from normal class table
02473 
02474    if (!sqlinfo->IsClassTableExist()) return 0;
02475    TString sqlcmd;
02476    const char* quote = SQLIdentifierQuote();
02477    sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s BETWEEN %lld AND %lld ORDER BY %s%s%s",
02478                quote, sqlinfo->GetClassTableName(), quote,
02479                quote, SQLObjectIdColumn(), quote, minobjid, maxobjid,
02480                quote, SQLObjectIdColumn(), quote);
02481    return SQLQuery(sqlcmd.Data(), 2);
02482 }
02483 
02484 //______________________________________________________________________________
02485 TSQLResult* TSQLFile::GetBlobClassData(Long64_t objid, TSQLClassInfo* sqlinfo)
02486 {
02487 //  Method return request results for specified objid from _streamer_ classtable
02488 
02489    if (!sqlinfo->IsRawTableExist()) return 0;
02490    TString sqlcmd;
02491    const char* quote = SQLIdentifierQuote();
02492    sqlcmd.Form("SELECT %s, %s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
02493                sqlio::BT_Field, sqlio::BT_Value,
02494                quote, sqlinfo->GetRawTableName(), quote,
02495                quote, SQLObjectIdColumn(), quote, objid,
02496                quote, SQLRawIdColumn(), quote);
02497    return SQLQuery(sqlcmd.Data(), 2);
02498 }
02499 
02500 //______________________________________________________________________________
02501 TSQLStatement* TSQLFile::GetBlobClassDataStmt(Long64_t objid, TSQLClassInfo* sqlinfo)
02502 {
02503 //  Method return request results for specified objid from _streamer_ classtable
02504 //  Data returned in form of statement, where direct access to values are possible
02505 
02506    if (!sqlinfo->IsRawTableExist()) return 0;
02507 
02508    TString sqlcmd;
02509    const char* quote = SQLIdentifierQuote();
02510    sqlcmd.Form("SELECT %s, %s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
02511                sqlio::BT_Field, sqlio::BT_Value,
02512                quote, sqlinfo->GetRawTableName(), quote,
02513                quote, SQLObjectIdColumn(), quote, objid,
02514                quote, SQLRawIdColumn(), quote);
02515 
02516    if (fLogFile!=0)
02517       *fLogFile << sqlcmd << endl;
02518    if (gDebug>2) Info("BuildStatement", "%s", sqlcmd.Data());
02519    fQuerisCounter++;
02520 
02521    TSQLStatement* stmt = SQLStatement(sqlcmd.Data(), 1000);
02522    if (stmt==0) return 0;
02523 
02524    stmt->Process();
02525 
02526    stmt->StoreResult();
02527 
02528    return stmt;
02529 }
02530 
02531 //______________________________________________________________________________
02532 Long64_t TSQLFile::StoreObjectInTables(Long64_t keyid, const void* obj, const TClass* cl)
02533 {
02534    // Store object in database. Return stored object id or -1 if error
02535 
02536    if (fSQL==0) return -1;
02537 
02538    Long64_t objid = VerifyObjectTable();
02539    if (objid<=0) objid = 1; else objid++;
02540 
02541    TBufferSQL2 buffer(TBuffer::kWrite, this);
02542 
02543    TSQLStructure* s = buffer.SqlWriteAny(obj, cl, objid);
02544 
02545    if ((buffer.GetErrorFlag()>0) && s) {
02546       Error("StoreObjectInTables","Cannot convert object data to TSQLStructure");
02547       objid = -1;
02548    } else {
02549       TObjArray cmds;
02550       // here tables may be already created, therefore
02551       // it should be protected by transactions operations
02552       if (s && !s->ConvertToTables(this, keyid, &cmds)) {
02553          Error("StoreObjectInTables","Cannot convert to SQL statements");
02554          objid = -1;
02555       } else {
02556          Bool_t needcommit = kFALSE;
02557 
02558          if (GetUseTransactions()==kTransactionsAuto) {
02559             SQLStartTransaction();
02560             needcommit = kTRUE;
02561          }
02562 
02563          if (!SQLApplyCommands(&cmds)) {
02564             Error("StoreObject","Cannot correctly store object data in database");
02565             objid = -1;
02566             if (needcommit) SQLRollback();
02567          } else {
02568             if (needcommit) SQLCommit();
02569          }
02570       }
02571       cmds.Delete();
02572    }
02573 
02574    return objid;
02575 }
02576 
02577 //______________________________________________________________________________
02578 const char* TSQLFile::SQLCompatibleType(Int_t typ) const
02579 {
02580    // returns sql type name which is most closer to ROOT basic type
02581    // typ should be from TVirtualStreamerInfo:: constansts like TVirtualStreamerInfo::kInt
02582 
02583    return (typ<0) || (typ>18) ? 0 : fBasicTypes[typ];
02584 }
02585 
02586 //______________________________________________________________________________
02587 const char* TSQLFile::SQLIntType() const
02588 {
02589    // return SQL integer type
02590 
02591    return SQLCompatibleType(TVirtualStreamerInfo::kInt);
02592 }
02593 
02594 //______________________________________________________________________________
02595 Long64_t TSQLFile::DirCreateEntry(TDirectory* dir)
02596 {
02597    // Create entry for directory in database
02598 
02599    TDirectory* mother = dir->GetMotherDir();
02600    if (mother==0) mother = this;
02601 
02602    // key will be added to mother directory
02603    TKeySQL* key = new TKeySQL(mother, dir, dir->GetName(), dir->GetTitle());
02604 
02605    return key->GetDBKeyId();
02606 }
02607 
02608 //______________________________________________________________________________
02609 Int_t TSQLFile::DirReadKeys(TDirectory* dir)
02610 {
02611    // Read directory list of keys from database
02612 
02613    // First delete all old keys
02614    dir->GetListOfKeys()->Delete();
02615 
02616    if (gDebug>2)
02617       Info("DirReadKeys","dir = %s id = %lld", dir->GetName(), dir->GetSeekDir());
02618 
02619    return StreamKeysForDirectory(dir, kFALSE);
02620 }
02621 
02622 //______________________________________________________________________________
02623 void TSQLFile::DirWriteKeys(TDirectory* dir)
02624 {
02625    // Write directory keys list to database
02626 
02627    StreamKeysForDirectory(dir, kTRUE);
02628 }
02629 
02630 //______________________________________________________________________________
02631 void TSQLFile::DirWriteHeader(TDirectory* dir)
02632 {
02633    // Update dir header in the file
02634 
02635    TSQLClassInfo* sqlinfo = FindSQLClassInfo("TDirectory",TDirectoryFile::Class()->GetClassVersion());
02636    if (sqlinfo==0) return;
02637 
02638    // try to identify key with data for our directory
02639    TKeySQL* key = FindSQLKey(dir->GetMotherDir(), dir->GetSeekDir());
02640    if (key==0) return;
02641 
02642    const char* valuequote = SQLValueQuote();
02643    const char* quote = SQLIdentifierQuote();
02644 
02645    TString timeC = fDatimeC.AsSQLString();
02646    TSQLStructure::AddStrBrackets(timeC, valuequote);
02647 
02648    TString timeM = fDatimeM.AsSQLString();
02649    TSQLStructure::AddStrBrackets(timeM, valuequote);
02650 
02651    TString uuid = dir->GetUUID().AsString();
02652    TSQLStructure::AddStrBrackets(uuid, valuequote);
02653 
02654    TString sqlcmd;
02655 
02656    TString col1name = "CreateTime";
02657    TString col2name = "ModifyTime";
02658    TString col3name = "UUID";
02659    if (GetUseSuffixes()) {
02660       col1name+=sqlio::StrSuffix;
02661       col2name+=sqlio::StrSuffix;
02662       col3name+=sqlio::StrSuffix;
02663    }
02664 
02665    sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%s, %s%s%s=%s, %s%s%s=%s WHERE %s%s%s=%lld",
02666                 quote, sqlinfo->GetClassTableName(), quote,
02667                 quote, col1name.Data(), quote, timeC.Data(),
02668                 quote, col2name.Data(), quote, timeM.Data(),
02669                 quote, col3name.Data(), quote, uuid.Data(),
02670                 quote, SQLObjectIdColumn(), quote, key->GetDBObjId());
02671 
02672    SQLQuery(sqlcmd.Data());
02673 }
02674 
02675 //______________________________________________________________________________
02676 void TSQLFile::Streamer(TBuffer &b)
02677 {
02678    // streamer for TSQLFile class
02679    // stores only data for TDirectory
02680 
02681 
02682    TString sbuf;
02683 
02684    if (b.IsReading()) {
02685       Version_t R__v = b.ReadVersion(0, 0);
02686       b.ClassBegin(TSQLFile::Class(), R__v);
02687 
02688       b.ClassMember("CreateTime","TString");
02689       sbuf.Streamer(b);
02690       TDatime timeC(sbuf.Data());
02691       fDatimeC = timeC;
02692 
02693       b.ClassMember("ModifyTime","TString");
02694       sbuf.Streamer(b);
02695       TDatime timeM(sbuf.Data());
02696       fDatimeM = timeM;
02697 
02698       b.ClassMember("UUID","TString");
02699       sbuf.Streamer(b);
02700       TUUID id(sbuf.Data());
02701       fUUID = id;
02702 
02703       b.ClassEnd(TSQLFile::Class());
02704    } else {
02705 
02706       b.WriteVersion(TSQLFile::Class());
02707 
02708       b.ClassBegin(TSQLFile::Class());
02709 
02710       b.ClassMember("CreateTime","TString");
02711       sbuf = fDatimeC.AsSQLString();
02712       sbuf.Streamer(b);
02713 
02714       b.ClassMember("ModifyTime","TString");
02715       fDatimeM.Set();
02716       sbuf = fDatimeM.AsSQLString();
02717       sbuf.Streamer(b);
02718 
02719       b.ClassMember("UUID","TString");
02720       sbuf = fUUID.AsString();
02721       sbuf.Streamer(b);
02722 
02723       b.ClassEnd(TSQLFile::Class());
02724    }
02725 }

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