diff --git a/sql/inc/LinkDef.h b/sql/inc/LinkDef.h index d7450200d0a07ce1c2d6171fff2f56c0279a3362..ce322ce5a2edcb1f082571c1e064a7ffd33acb86 100644 --- a/sql/inc/LinkDef.h +++ b/sql/inc/LinkDef.h @@ -1,4 +1,4 @@ -/* @(#)root/sql:$Name: $:$Id: LinkDef.h,v 1.2 2005/12/07 14:59:57 rdm Exp $ */ +/* @(#)root/sql:$Name: $:$Id: LinkDef.h,v 1.3 2006/02/01 18:57:41 pcanal Exp $ */ /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * @@ -10,14 +10,16 @@ #ifdef __CINT__ -#pragma link C++ class TSQLFile; +#pragma link C++ class TSQLFile-; #pragma link C++ class TBufferSQL2; #pragma link C++ class TKeySQL; #pragma link C++ class TSQLClassInfo; +#pragma link C++ class TSQLClassColumnInfo; #pragma link C++ class TSQLObjectInfo; #pragma link C++ class TSQLObjectData; #pragma link C++ class TSQLObjectDataPool; #pragma link C++ class TSQLStructure; #pragma link C++ class TSQLColumnData; +#pragma link C++ class TSQLTableData; #endif diff --git a/sql/inc/TSQLClassInfo.h b/sql/inc/TSQLClassInfo.h index a084dba85ad09d4b72291027cb46dbeed194c7f0..f4a95e14be4de4133d5fc28e49ffb2d990b3f08d 100644 --- a/sql/inc/TSQLClassInfo.h +++ b/sql/inc/TSQLClassInfo.h @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLClassInfo.h,v 1.3 2005/12/07 14:59:57 rdm Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLClassInfo.h,v 1.4 2006/05/22 08:55:57 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -31,15 +31,46 @@ class TObjArray; +class TSQLClassColumnInfo : public TObject { + +public: + TSQLClassColumnInfo(); + TSQLClassColumnInfo(const char* name, + const char* sqlname, + const char* sqltype); + virtual ~TSQLClassColumnInfo(); + + virtual const char* GetName() const { return fName.Data(); } + const char* GetSQLName() const { return fSQLName.Data(); } + const char* GetSQLType() const { return fSQLType.Data(); } + +protected: + TString fName; + TString fSQLName; + TString fSQLType; + + ClassDef(TSQLClassColumnInfo, 1); // Keeps information about single column in class table +}; + +//_________________________________________________________________________________ + class TSQLClassInfo : public TObject { public: TSQLClassInfo(); - TSQLClassInfo(const char* classname, Int_t version); + TSQLClassInfo(Long64_t classid, + const char* classname, + Int_t version); virtual ~TSQLClassInfo(); + + Long64_t GetClassId() const { return fClassId; } + virtual const char* GetName() const { return fClassName.Data(); } Int_t GetClassVersion() const { return fClassVersion; } + void SetClassTableName(const char* name) { fClassTable = name; } + void SetRawTableName(const char* name) { fRawTable = name; } + const char* GetClassTableName() const { return fClassTable.Data(); } const char* GetRawTableName() const { return fRawTable.Data(); } @@ -51,11 +82,13 @@ public: Bool_t IsRawTableExist() const { return fRawtableExist; } TObjArray* GetColumns() const { return fColumns; } + Int_t FindColumn(const char* name, Bool_t sqlname = kFALSE); protected: TString fClassName; //! class name Int_t fClassVersion; //! class version + Long64_t fClassId; //! sql class id TString fClassTable; //! name of table with class data TString fRawTable; //! name of table with raw data TObjArray* fColumns; //! name and type of columns - array of TNamed diff --git a/sql/inc/TSQLFile.h b/sql/inc/TSQLFile.h index 407bfae97e042a7d8a71ec3ce78684f6fc13e667..65d01704b1ef7838809c7e0e94651373d4fefd44 100644 --- a/sql/inc/TSQLFile.h +++ b/sql/inc/TSQLFile.h @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLFile.h,v 1.7 2006/02/01 18:57:41 pcanal Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLFile.h,v 1.8 2006/05/22 08:55:57 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -41,7 +41,10 @@ class TSQLFile : public TFile { friend class TBufferSQL2; friend class TKeySQL; friend class TSQLStructure; + friend class TSQLTableData; friend class TSqlRegistry; + friend class TSqlRawBuffer; + friend class TSqlCmdsBuffer; protected: enum ELockingKinds { @@ -58,6 +61,12 @@ protected: virtual Int_t SysStat(Int_t, Long_t*, Long64_t*, Long_t*, Long_t*) { return 0; } virtual Int_t SysSync(Int_t) { return 0; } + // Overwrite methods for directory I/O + virtual Long64_t DirCreateEntry(TDirectory*); + virtual Int_t DirReadKeys(TDirectory*); + virtual void DirWriteKeys(TDirectory*); + virtual void DirWriteHeader(TDirectory*); + // functions to manipulate basic tables (Configurations, Objects, Keys) in database void SaveToDatabase(); Bool_t ReadConfigurations(); @@ -68,21 +77,23 @@ protected: void SetLocking(Int_t mode); Int_t GetLocking(); - // function for read/write access infos, not implemented + // function for read/write access infos Bool_t IsWriteAccess(); Bool_t IsReadAccess(); // generic sql functions TSQLResult* SQLQuery(const char* cmd, Int_t flag = 0, Bool_t* res = 0); + Bool_t SQLCanStatement(); + TSQLStatement* SQLStatement(const char* cmd, Int_t bufsize = 1000); + void SQLDeleteStatement(TSQLStatement* stmt); Bool_t SQLApplyCommands(TObjArray* cmds); - TObjArray* SQLTablesList(const char* searchtable = 0); Bool_t SQLTestTable(const char* tablename); - TObjArray* SQLTableColumns(const char* tablename); Long64_t SQLMaximumValue(const char* tablename, const char* columnname); void SQLDeleteAllTables(); Bool_t SQLStartTransaction(); Bool_t SQLCommit(); Bool_t SQLRollback(); + Int_t SQLMaxIdentifierLength(); // operation with keys structures in database void DeleteKeyFromDB(Long64_t keyid); @@ -94,11 +105,18 @@ protected: // handling SQL class info structures TSQLClassInfo* FindSQLClassInfo(const char* clname, Int_t version); - TSQLClassInfo* RequestSQLClassInfo(const char* clname, Int_t version, Bool_t force = kFALSE); - TSQLClassInfo* RequestSQLClassInfo(const TClass* cl, Bool_t force = kFALSE); - Bool_t SyncSQLClassInfoRawTables(TSQLClassInfo* sqlinfo, Bool_t hasrawdata); - Bool_t SyncSQLClassInfo(TSQLClassInfo* sqlinfo, TObjArray* columns, Bool_t hasrawdata); + TSQLClassInfo* FindSQLClassInfo(const TClass* cl); + TSQLClassInfo* RequestSQLClassInfo(const char* clname, Int_t version); + TSQLClassInfo* RequestSQLClassInfo(const TClass* cl); + Bool_t CreateClassTable(TSQLClassInfo* sqlinfo, TObjArray* colinfos); + Bool_t CreateRawTable(TSQLClassInfo* sqlinfo); + Bool_t ProduceClassSelectQuery(TStreamerInfo* info, TSQLClassInfo* sqlinfo, TString& columns, TString& tables, Int_t& tablecnt); + void AddIdEntry(Long64_t tableid, Int_t subid, Int_t type, + const char* name, const char* sqlname, const char* info); + void ReadSQLClassInfos(); + TString DefineTableName(const char* clname, Int_t version, Bool_t rawtable); + Bool_t HasTable(const char* name); // operations with long string table TString CodeLongString(Long64_t objid, Int_t strid); @@ -155,6 +173,9 @@ protected: TString fUserName; //! user name, used to access objects from database std::ofstream* fLogFile; //! log file with SQL statements + + Bool_t fIdsTableExists; //! indicate if IdsTable exists + Int_t fStmtCounter; //! count numbers of active statements private: //let the compiler do the job. gcc complains when the following line is activated diff --git a/sql/inc/TSQLObjectData.h b/sql/inc/TSQLObjectData.h index 84a61e9817856243ead7709f8ec7629c5a13d0d9..03508d7a63b233f5c6fd32f1f31bf2110a89d5fd 100644 --- a/sql/inc/TSQLObjectData.h +++ b/sql/inc/TSQLObjectData.h @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLObjectData.h,v 1.7 2006/05/12 08:17:02 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLObjectData.h,v 1.8 2006/05/22 08:55:58 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -48,7 +48,6 @@ public: const char* GetObjClassName() const { return fClassName.Data(); } Version_t GetObjVersion() const { return fVersion; } - protected: Long64_t fObjId; TString fClassName; @@ -85,7 +84,7 @@ public: void AddUnpackInt(const char* tname, Int_t value); const char* GetValue() const { return fLocatedValue; } - const char* GetColumnName() const { return fLocatedField; } + const char* GetLocatedField() const { return fLocatedField; } const char* GetBlobPrefixName() const { return fBlobPrefixName; } const char* GetBlobTypeName() const { return fBlobTypeName; } diff --git a/sql/inc/TSQLStructure.h b/sql/inc/TSQLStructure.h index 330350c0b03fa8de9c8554253ff13548c4a2b21b..a3fb87f376b9f0f0ea8ea5afd1e979053b9cd975 100644 --- a/sql/inc/TSQLStructure.h +++ b/sql/inc/TSQLStructure.h @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLStructure.h,v 1.6 2005/12/07 14:59:57 rdm Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLStructure.h,v 1.7 2006/02/01 18:57:41 pcanal Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -38,7 +38,9 @@ class TStreamerInfo; class TStreamerElement; class TSQLFile; class TSqlRegistry; +class TSqlRawBuffer; class TSQLObjectData; +class TSQLClassInfo; class TBufferSQL2; class TSQLColumnData : public TObject { @@ -50,7 +52,7 @@ protected: Bool_t fNumeric; //! for numeric quotes (double quotes) are not required public: TSQLColumnData(); - TSQLColumnData(const char* name, + TSQLColumnData(const char* name, const char* sqltype, const char* value, Bool_t numeric); @@ -68,25 +70,55 @@ public: //______________________________________________________________________ +class TSQLTableData : public TObject { + +protected: + TSQLFile* fFile; //! + TSQLClassInfo* fInfo; //! + TObjArray fColumns; //! collection of columns + TObjArray* fColInfos; //! array with TSQLClassColumnInfo, used later for TSQLClassInfo + + TString DefineSQLName(const char* fullname); + Bool_t HasSQLName(const char* sqlname); + +public: + TSQLTableData(TSQLFile* f = 0, TSQLClassInfo* info = 0); + virtual ~TSQLTableData(); + + void AddColumn(const char* name, Long64_t value); + void AddColumn(const char* name, + const char* sqltype, + const char* value, + Bool_t numeric); + + TObjArray* TakeColInfos(); + + Int_t GetNumColumns(); + const char* GetColumn(Int_t n); + Bool_t IsNumeric(Int_t n); + + ClassDef(TSQLTableData, 1); // Collection of columns data for single SQL table +}; + +//______________________________________________________________________ + class TSQLStructure : public TObject { protected: Bool_t CheckNormalClassPair(TSQLStructure* vers, TSQLStructure* info); Long64_t FindMaxObjectId(); - void PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const char* topname, Bool_t useblob = kFALSE); + void PerformConversion(TSqlRegistry* reg, TSqlRawBuffer* blobs, const char* topname, Bool_t useblob = kFALSE); Bool_t StoreObject(TSqlRegistry* reg, Long64_t objid, TClass* cl, Bool_t registerobj = kTRUE); Bool_t StoreObjectInNormalForm(TSqlRegistry* reg); Bool_t StoreClassInNormalForm(TSqlRegistry* reg); - Bool_t StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* columns); - Bool_t TryConvertObjectArray(TSqlRegistry* reg, TObjArray* blobs); + Bool_t StoreElementInNormalForm(TSqlRegistry* reg, TSQLTableData* columns); + Bool_t TryConvertObjectArray(TSqlRegistry* reg, TSqlRawBuffer* blobs); Bool_t StoreTObject(TSqlRegistry* reg); Bool_t StoreTString(TSqlRegistry* reg); Bool_t RecognizeTString(const char* &value); - void AddCmd(TObjArray* cmds, const char* name, const char* value, const char* topname = 0, const char* ns = 0); - TSQLStructure* fParent; //! Int_t fType; //! const void* fPointer; //! @@ -164,32 +196,39 @@ public: static void AddStrBrackets(TString &s, const char* quote); enum ESQLTypes { - kSqlObject = 10001, - kSqlPointer = 10002, - kSqlVersion = 10003, - kSqlStreamerInfo = 10004, - kSqlClassStreamer= 10005, - kSqlElement = 10006, - kSqlValue = 10007, - kSqlArray = 10008, - kSqlObjectData = 10009, - kSqlCustomClass = 10010, - kSqlCustomElement= 10011 + kSqlObject = 10001, + kSqlPointer = 10002, + kSqlVersion = 10003, + kSqlStreamerInfo = 10004, + kSqlClassStreamer= 10005, + kSqlElement = 10006, + kSqlValue = 10007, + kSqlArray = 10008, + kSqlObjectData = 10009, + kSqlCustomClass = 10010, + kSqlCustomElement= 10011 }; enum ESQLColumns { - kColUnknown = 0, - kColSimple = 1, - kColSimpleArray = 2, - kColParent = 3, - kColObject = 4, - kColObjectArray = 5, - kColNormObject = 6, - kColNormObjectArray = 7, - kColObjectPtr = 8, - kColTString = 9, - kColRawData = 10 - }; + kColUnknown = 0, + kColSimple = 1, + kColSimpleArray = 2, + kColParent = 3, + kColObject = 4, + kColObjectArray = 5, + kColNormObject = 6, + kColNormObjectArray = 7, + kColObjectPtr = 8, + kColTString = 9, + kColRawData = 10 + }; + + enum ESQLIdType { + kIdTable = 0, + kIdRawTable = 1, + kIdColumn = 2 + }; + ClassDef(TSQLStructure, 1); // Table/structure description used internally by YBufferSQL. }; @@ -258,6 +297,15 @@ namespace sqlio { extern const char* ObjectsTableIndex; extern const char* OT_Class; extern const char* OT_Version; + + extern const char* IdsTable; + extern const char* IdsTableIndex; + extern const char* IT_TableID; + extern const char* IT_SubID; + extern const char* IT_Type; + extern const char* IT_FullName; + extern const char* IT_SQLName; + extern const char* IT_Info; extern const char* BT_Field; extern const char* BT_Value; diff --git a/sql/src/TBufferSQL2.cxx b/sql/src/TBufferSQL2.cxx index a3415d13b0a79a732e3093887dd6bde9c2df070d..58e22cc5911ee7ad062989cbc4069be584383663 100644 --- a/sql/src/TBufferSQL2.cxx +++ b/sql/src/TBufferSQL2.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TBufferSQL2.cxx,v 1.11 2006/05/11 10:29:45 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TBufferSQL2.cxx,v 1.12 2006/05/22 08:55:58 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -287,11 +287,11 @@ TSQLObjectData* TBufferSQL2::SqlObjectData(Long64_t objid, TSQLClassInfo* sqlinf } TSQLResult *blobdata = 0; - TSQLStatement* stmt = fSQL->GetBlobClassDataStmt(objid, sqlinfo); + TSQLStatement* blobstmt = fSQL->GetBlobClassDataStmt(objid, sqlinfo); - if (stmt==0) blobdata = fSQL->GetBlobClassData(objid, sqlinfo); + if (blobstmt==0) blobdata = fSQL->GetBlobClassData(objid, sqlinfo); - return new TSQLObjectData(sqlinfo, objid, classdata, classrow, blobdata, stmt); + return new TSQLObjectData(sqlinfo, objid, classdata, classrow, blobdata, blobstmt); } //______________________________________________________________________________ @@ -330,6 +330,9 @@ Int_t TBufferSQL2::SqlWriteObject(const void* obj, const TClass* cl, TMemberStre if (value>0) objid = fFirstObjId + value - 1; } + + if (gDebug>1) + cout << " Find objectid = " << objid << endl; if (objid>=0) { Stack()->SetObjectPointer(objid); @@ -381,7 +384,7 @@ void* TBufferSQL2::SqlReadObject(void* obj, TClass** cl, TMemberStreamer *stream sscanf(refid, FLong64, &objid); if (gDebug>2) - Info("SqlReadObject","Starting objid = %lld column=%s", objid, fCurrentData->GetColumnName()); + Info("SqlReadObject","Starting objid = %lld column=%s", objid, fCurrentData->GetLocatedField()); if (!fCurrentData->IsBlobData() || fCurrentData->VerifyDataType(sqlio::ObjectPtr,kFALSE)) @@ -442,7 +445,7 @@ void* TBufferSQL2::SqlReadObjectDirect(void* obj, TClass** cl, Long64_t objid, T if (gDebug>2) Info("SqlReadObjectDirect","objid = %lld clname = %s ver = %d",objid, clname.Data(), version); - TSQLClassInfo* sqlinfo = fSQL->RequestSQLClassInfo(clname.Data(), version); + TSQLClassInfo* sqlinfo = fSQL->FindSQLClassInfo(clname.Data(), version); TClass* objClass = gROOT->GetClass(clname); if ((objClass==0) || (sqlinfo==0)) { @@ -802,7 +805,7 @@ void TBufferSQL2::WorkWithClass(const char* classname, Version_t classversion) return; } - TSQLClassInfo* sqlinfo = fSQL->RequestSQLClassInfo(classname, classversion); + TSQLClassInfo* sqlinfo = fSQL->FindSQLClassInfo(classname, classversion); if (sqlinfo==0) { Error("WorkWithClass","Can not find table for class %s version %d", classname, classversion); fErrorFlag = 1; diff --git a/sql/src/TKeySQL.cxx b/sql/src/TKeySQL.cxx index 67d664c5c5fce1106301e4993a419c97a280fdab..97047c6eeb028732b50cb496de28ed6acc4ebafe 100644 --- a/sql/src/TKeySQL.cxx +++ b/sql/src/TKeySQL.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TKeySQL.cxx,v 1.8 2006/05/11 10:29:45 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TKeySQL.cxx,v 1.9 2006/05/22 08:55:58 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -214,9 +214,9 @@ TObject* TKeySQL::ReadObj() TDirectory *dir = (TDirectory*) tobj; dir->SetName(GetName()); dir->SetTitle(GetTitle()); - //dir->SetSeekDir(GetDBKeyId()); - dir->ReadKeys(); + dir->SetSeekDir(GetDBKeyId()); dir->SetMother(fMotherDir); + dir->ReadKeys(); fMotherDir->Append(dir); } } diff --git a/sql/src/TSQLClassInfo.cxx b/sql/src/TSQLClassInfo.cxx index 1a9d7b9cd609f1411a3635c88275e55e17047894..12985a46697cae38f31c53caaef75e31bcd7ba2e 100644 --- a/sql/src/TSQLClassInfo.cxx +++ b/sql/src/TSQLClassInfo.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLClassInfo.cxx,v 1.2 2005/11/22 20:42:36 pcanal Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLClassInfo.cxx,v 1.3 2005/12/07 14:59:57 rdm Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -14,7 +14,7 @@ // TSQLClassInfo class containes info about tables specific to one class and // version. It provides names of table for that class. For each version of // class not more than two tables can exists. Normal table has typically -// name like TH1_ver4 and additional table has name like TH1_streamer_ver4 +// name like TH1_ver4 and additional table has name like TH1_raw4 // List of this objects are kept by TSQLFile class // //________________________________________________________________________ @@ -23,6 +23,38 @@ #include "TObjArray.h" + +ClassImp(TSQLClassColumnInfo) + +//______________________________________________________________________________ +TSQLClassColumnInfo::TSQLClassColumnInfo() : + TObject(), + fName(), + fSQLName(), + fSQLType() +{ + // default constructor +} + +//______________________________________________________________________________ +TSQLClassColumnInfo::TSQLClassColumnInfo(const char* name, + const char* sqlname, + const char* sqltype) : + TObject(), + fName(name), + fSQLName(sqlname), + fSQLType(sqltype) +{ + // normal constructor +} + +//______________________________________________________________________________ +TSQLClassColumnInfo::~TSQLClassColumnInfo() +{ + // destructor +} + + ClassImp(TSQLClassInfo) //______________________________________________________________________________ @@ -30,6 +62,7 @@ TSQLClassInfo::TSQLClassInfo() : TObject(), fClassName(), fClassVersion(0), + fClassId(0), fClassTable(), fRawTable(), fColumns(0), @@ -37,21 +70,24 @@ TSQLClassInfo::TSQLClassInfo() : { // default constructor } - + //______________________________________________________________________________ -TSQLClassInfo::TSQLClassInfo(const char* classname, Int_t version) : +TSQLClassInfo::TSQLClassInfo(Long64_t classid, + const char* classname, + Int_t version) : TObject(), fClassName(classname), fClassVersion(version), + fClassId(classid), fClassTable(), fRawTable(), fColumns(0), fRawtableExist(kFALSE) { -// normal constructor of TSQLClassInfo class -// Sets names of tables, which are used for that version of class + // normal constructor of TSQLClassInfo class + // Sets names of tables, which are used for that version of class fClassTable.Form("%s_ver%d", classname, version); - fRawTable.Form("%s_streamer_ver%d", classname, version); + fRawTable.Form("%s_raw%d", classname, version); } //______________________________________________________________________________ @@ -63,7 +99,6 @@ TSQLClassInfo::~TSQLClassInfo() fColumns->Delete(); delete fColumns; } - } //______________________________________________________________________________ @@ -86,3 +121,28 @@ void TSQLClassInfo::SetTableStatus(TObjArray* columns, Bool_t israwtable) SetColumns(columns); fRawtableExist = israwtable; } + +//______________________________________________________________________________ +Int_t TSQLClassInfo::FindColumn(const char* name, Bool_t sqlname) +{ + // Search for column of that name + // Can search either for full column name (sqlname = kFALSE, default) + // or for name, used as column name (sqlname = kTRUE) + // Return index of column in list (-1 if not found) + + if ((name==0) || (fColumns==0)) return -1; + + TIter next(fColumns); + + TSQLClassColumnInfo* col = 0; + + Int_t indx = 0; + + while ((col = (TSQLClassColumnInfo*) next()) != 0) { + const char* colname = sqlname ? col->GetSQLName() : col->GetName(); + if (strcmp(colname, name)==0) return indx; + indx++; + } + + return -1; +} diff --git a/sql/src/TSQLFile.cxx b/sql/src/TSQLFile.cxx index a535168949991dd0d5c2e2c4d57b34e184cb44a9..04351fd15b40d0f8b401eb2de44bcc1c5380e6ef 100644 --- a/sql/src/TSQLFile.cxx +++ b/sql/src/TSQLFile.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLFile.cxx,v 1.10 2006/05/22 08:55:58 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLFile.cxx,v 1.11 2006/05/23 06:16:27 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -15,17 +15,17 @@ // "transparent" access to SQL data base via standard TFile interface. // // The main approach that each class (but not each object) has one or two tables -// with names like $(CLASSNAME)_ver$(VERSION) and $(CLASSNAME)_streamer_ver$(VERSION) -// For example: TAxis_ver8 or TList_streamer_ver5 +// with names like $(CLASSNAME)_ver$(VERSION) and $(CLASSNAME)_raw$(VERSION) +// For example: TAxis_ver8 or TList_raw5 // Second kind of tables appears, when some of class members can not be converted to // normalized form or when class has custom streamer. -// For instance, for TH1 class two tables are required: TH1_ver4 and TH1_streamer_ver4 +// For instance, for TH1 class two tables are required: TH1_ver4 and TH1_raw4 // Most of memebers are stored in TH1_ver4 table columnwise, and only memeber: // // Double_t* fBuffer; //[fBufferSize] // // can not be represented as column while size of array is not known apriory. -// Therefore, fBuffer will be written as list of values in TH1_streamer_ver4 table. +// Therefore, fBuffer will be written as list of values in TH1_raw4 table. // // All objects, stored in the DB, will be registered in table "ObjectsTable". // In this there are following columns: @@ -172,6 +172,7 @@ #include "TBrowser.h" #include "TObjArray.h" #include "TObjString.h" +#include "TList.h" #include "TArrayC.h" #include "TStreamerInfo.h" #include "TStreamerElement.h" @@ -180,6 +181,8 @@ #include "TClass.h" #include "TSQLServer.h" +#include "TSQLTableInfo.h" +#include "TSQLColumnInfo.h" #include "TSQLStatement.h" #include "TSQLResult.h" #include "TSQLRow.h" @@ -257,7 +260,7 @@ const char* oracle_BasicTypes[20] = { const char* oracle_OtherTypes[13] = { "VARCHAR(1000)", // smallest text -"4095", // maximum size of smallest text +"1000", // maximum size of smallest text "VARCHAR(4000)", // biggest size text, CLOB is not yet supported by TOracleRow "VARCHAR(50)", // date & time "\"", // quote for identifier like table name or column name @@ -271,111 +274,6 @@ const char* oracle_OtherTypes[13] = { "" // default tables types, used only for MySQL tables }; -// ****************************************************************** - -// these are two class to produce deep copy of sql result tables -// introduced to overcome Oracle problem - -class TSQLRowCopy : public TSQLRow { - -protected: - TObjArray fFields; - -public: - TSQLRowCopy(TSQLRow* res, Int_t nfields) : - TSQLRow(), - fFields() - { - for(Int_t n=0;n<nfields;n++) { - const char* value = res->GetField(n); - fFields.Add(new TObjString(value)); - } - } - - virtual ~TSQLRowCopy() - { - } - - virtual void Close(Option_t *option="") - { - fFields.Delete(option); - } - - virtual ULong_t GetFieldLength(Int_t field) - { - const char * value = GetField(field); - if ((value==0) || (*value==0)) return 0; - return strlen(value); - } - - virtual const char *GetField(Int_t field) - { - if ((field<0) || (field>fFields.GetLast())) return 0; - return fFields[field]->GetName(); - } -}; - -class TSQLResultCopy : public TSQLResult { -protected: - TObjArray fRows; - TObjArray fNames; - Int_t fCounter; - -public: - TSQLResultCopy(TSQLResult* res) : - TSQLResult(), - fRows(), - fNames(), - fCounter(0) - { - Int_t nfields = res->GetFieldCount(); - - for (Int_t n=0;n<nfields;n++) { - const char* name = res->GetFieldName(n); - fNames.Add(new TObjString(name)); - } - - fRowCount = 0; - TSQLRow* row = res->Next(); - while (row!=0) { - fRowCount++; - fRows.Add(new TSQLRowCopy(row, nfields)); - delete row; - row = res->Next(); - } - - delete res; - } - - virtual ~TSQLResultCopy() - { - } - - virtual void Close(Option_t* option="") - { - fRows.Delete(option); - fNames.Delete(option); - } - - virtual Int_t GetFieldCount() - { - return fNames.GetLast() + 1; - } - - virtual const char *GetFieldName(Int_t field) - { - if ((field<0) || (field>fNames.GetLast())) return 0; - return fNames[field]->GetName(); - } - - virtual TSQLRow* Next() - { - if (fCounter>fRows.GetLast()) return 0; - TSQLRow* curr = (TSQLRow*) fRows.At(fCounter++); - fRows.Remove(curr); // not make a copy, just remove from buffer, cannot use again - return curr; - } -}; //______________________________________________________________________________ TSQLFile::TSQLFile() : @@ -394,9 +292,11 @@ TSQLFile::TSQLFile() : fBasicTypes(0), fOtherTypes(0), fUserName(), - fLogFile(0) + fLogFile(0), + fIdsTableExists(kFALSE) { // default TSQLFile constructor + SetBit(kBinaryFile, kFALSE); } //______________________________________________________________________________ @@ -416,7 +316,8 @@ TSQLFile::TSQLFile(const char* dbname, Option_t* option, const char* user, const fBasicTypes(mysql_BasicTypes), fOtherTypes(mysql_OtherTypes), fUserName(user), - fLogFile(0) + fLogFile(0), + fIdsTableExists(kFALSE) { // Connects to SQL server with provided arguments. // If the constructor fails in any way IsZombie() will @@ -477,6 +378,7 @@ TSQLFile::TSQLFile(const char* dbname, Option_t* option, const char* user, const fProcessIDs = 0; fNProcessIDs= 0; fSeekDir = sqlio::Ids_RootDir; + SetBit(kBinaryFile, kFALSE); fOption = option; fOption.ToUpper(); @@ -917,7 +819,7 @@ void TSQLFile::WriteHeader() { // Write file info like configurations, title, UUID and other -// WriteSpecialObject(sqlio::Ids_TSQLFile, this, GetName(), GetTitle()); + WriteSpecialObject(sqlio::Ids_TSQLFile, this, GetName(), GetTitle()); } //______________________________________________________________________________ @@ -982,7 +884,7 @@ Bool_t TSQLFile::WriteSpecialObject(Long64_t keyid, TObject* obj, const char* na //______________________________________________________________________________ TObject* TSQLFile::ReadSpecialObject(Long64_t keyid, TObject* obj) { -// Read data of special kind of objects + // Read data of special kind of objects TKeySQL* key = 0; @@ -996,7 +898,7 @@ TObject* TSQLFile::ReadSpecialObject(Long64_t keyid, TObject* obj) void* res = buffer.SqlReadAny(key->GetDBKeyId(), key->GetDBObjId(), &cl, obj); if ((cl==TSQLFile::Class()) && (res!=0) && (obj==this)) { - // name should not be preserved while name of database may be was changed + // name should not be preserved while name of database may be changed SetTitle(key->GetTitle()); } @@ -1127,14 +1029,18 @@ void TSQLFile::InitSqlDatabase(Bool_t create) if (len<5000) len = 5000; fClassIndex = new TArrayC(len); fClassIndex->Reset(0); - + if (!create) { + Bool_t ok = ReadConfigurations(); // read data corresponding to TSQLFile if (ok) { + ReadSQLClassInfos(); + ReadStreamerInfo(); -// ok = (ReadSpecialObject(sqlio::Ids_TSQLFile, this) != 0); + + ok = (ReadSpecialObject(sqlio::Ids_TSQLFile, this) != 0); } // read list of keys @@ -1343,7 +1249,7 @@ TString TSQLFile::MakeSelectQuery(TClass* cl) // VIEWs supported by latest MySQL 5 and Oracle TString res = ""; - TSQLClassInfo* sqlinfo = RequestSQLClassInfo(cl); + TSQLClassInfo* sqlinfo = FindSQLClassInfo(cl); if (sqlinfo==0) return res; TString columns, tables; @@ -1424,7 +1330,7 @@ Bool_t TSQLFile::ProduceClassSelectQuery(TStreamerInfo* info, case TSQLStructure::kColParent: { TClass* parentcl = elem->GetClassPointer(); ProduceClassSelectQuery(parentcl->GetStreamerInfo(), - RequestSQLClassInfo(parentcl), + FindSQLClassInfo(parentcl), columns, tables, tablecnt); break; } @@ -1531,6 +1437,12 @@ TSQLResult* TSQLFile::SQLQuery(const char* cmd, Int_t flag, Bool_t* ok) if (gDebug>2) Info("SQLQuery",cmd); fQuerisCounter++; + + if (flag==0) { + Bool_t res = fSQL->Exec(cmd); + if (ok!=0) *ok = res; + return 0; + } TSQLResult* res = fSQL->Query(cmd); if (ok!=0) *ok = res!=0; @@ -1544,6 +1456,46 @@ TSQLResult* TSQLFile::SQLQuery(const char* cmd, Int_t flag, Bool_t* ok) return res; } +//______________________________________________________________________________ +Bool_t TSQLFile::SQLCanStatement() +{ + // Test if DB support statement and number of open statements is not exceeded + + if (fSQL==0) return kFALSE; + + if (!fSQL->IsSupportStatement()) return kFALSE; + + return kTRUE; // !IsOracle() || (fStmtCounter<15); +} + +//______________________________________________________________________________ +TSQLStatement* TSQLFile::SQLStatement(const char* cmd, Int_t bufsize) +{ + // Produces statement for + + if (fSQL==0) return 0; + + if (gDebug>1) + Info("SQLStatement",cmd); + + fStmtCounter++; + fQuerisCounter++; // one statement counts as one query + + return fSQL->Statement(cmd, bufsize); +} + +//______________________________________________________________________________ +void TSQLFile::SQLDeleteStatement(TSQLStatement* stmt) +{ + // delete statement and decrease counter + + if (stmt==0) return; + + fStmtCounter--; + + delete stmt; +} + //______________________________________________________________________________ Bool_t TSQLFile::SQLApplyCommands(TObjArray* cmds) { @@ -1563,153 +1515,14 @@ Bool_t TSQLFile::SQLApplyCommands(TObjArray* cmds) return ok; } -//______________________________________________________________________________ -TObjArray* TSQLFile::SQLTablesList(const char* searchtable) -{ - // Produces list of tables, presented in database - // if searchtable!=0, looks only for this specific table - // list should be deleted by user afterwards - // P.S. Unfortunately, the TSQLServer::GetTables function is not - // correctly implemented for all cases, - // therefore special function is required. - - if (fSQL==0) return 0; - - TObjArray* res = 0; - - if (IsOracle()) { - TString sqlcmd; - TString user = fUserName; - user.ToUpper(); - sqlcmd.Form("SELECT table_name FROM all_tables WHERE owner='%s'",user.Data()); - if (searchtable!=0) - sqlcmd += ::Form(" and table_name LIKE '%s'",searchtable); - - TSQLResult* tables = SQLQuery(sqlcmd.Data(), 1); - if (tables==0) return 0; - - TSQLRow* row = tables->Next(); - while (row!=0) { - const char* tablename = row->GetField(0); - if (strpbrk(tablename,"$=")==0) { - if (res==0) res = new TObjArray; - res->Add(new TObjString(tablename)); - } - delete row; - row = tables->Next(); - } - delete tables; - } else - if (IsODBC()) { - TSQLResult* tables = fSQL->GetTables("",searchtable); - if (tables==0) return 0; - - TSQLRow* row = tables->Next(); - while (row!=0) { - if (res==0) res = new TObjArray; - res->Add(new TObjString(row->GetField(2))); - delete row; - row = tables->Next(); - } - delete tables; - - } else { - TSQLResult* tables = fSQL->GetTables(GetDataBaseName(), searchtable); - if (tables==0) return 0; - - TSQLRow* row = tables->Next(); - while (row!=0) { - if (res==0) res = new TObjArray; - res->Add(new TObjString(row->GetField(0))); - delete row; - row = tables->Next(); - } - delete tables; - } - if (res!=0) res->SetOwner(kTRUE); - - return res; -} - -//______________________________________________________________________________ -TObjArray* TSQLFile::SQLTableColumns(const char* tablename) -{ - // produces list of columns for specified table - // list consist of TNamed objects with name and type for each column - // list should be deleted aftrewards - // P.S. Oracle plug-in do not provides types - - if (fSQL==0) return 0; - - TObjArray* res = 0; - - if (IsOracle()) { - -// TSQLResult* cols = fSQL->GetColumns(0, tablename, ""); -// if (cols==0) return 0; -// for (Int_t n=0;n<cols->GetFieldCount();n++) { -// TNamed* col = new TNamed(cols->GetFieldName(n), "TYPE?"); -// if (res==0) res = new TObjArray; -// res->Add(col); -// } -// delete cols; - TString sqlcmd; - const char* quote = SQLIdentifierQuote(); - sqlcmd.Form("SELECT * FROM %s%s%s WHERE ROWNUM<2", - quote, tablename, quote); - TSQLResult* cols = SQLQuery(sqlcmd.Data(), 1); - if (cols==0) return 0; - for (Int_t n=0;n<cols->GetFieldCount();n++) { - TNamed* col = new TNamed(cols->GetFieldName(n), "TYPE?"); - if (res==0) res = new TObjArray; - res->Add(col); - } - delete cols; - } else - if (IsODBC()) { - TSQLResult* cols = fSQL->GetColumns("", tablename); - if (cols==0) return 0; - - TSQLRow* row = cols->Next(); - while (row!=0) { - TNamed* col = new TNamed(row->GetField(3), row->GetField(5)); - if (res==0) res = new TObjArray; - res->Add(col); - delete row; - row = cols->Next(); - } - delete cols; - } else { - TSQLResult* cols = fSQL->GetColumns(GetDataBaseName(), tablename, ""); - - if (cols==0) return 0; - - TSQLRow* row = cols->Next(); - while (row!=0) { - TNamed* col = new TNamed(row->GetField(0), row->GetField(1)); - if (res==0) res = new TObjArray; - res->Add(col); - delete row; - row = cols->Next(); - } - - delete cols; - } - return res; -} - //______________________________________________________________________________ Bool_t TSQLFile::SQLTestTable(const char* tablename) { // Test, if table of specified name exists - TObjArray* list = SQLTablesList(tablename); - - Bool_t res = (list!=0); - - delete list; - - return res; + if (fSQL==0) return kFALSE; + + return fSQL->HasTable(tablename); } //______________________________________________________________________________ @@ -1720,8 +1533,6 @@ Long64_t TSQLFile::SQLMaximumValue(const char* tablename, const char* columnname if (fSQL==0) return -1; - if (fSQL==0) return -1; - if (gDebug>2) Info("SQLMaximumValue","Requests for %s column %s", tablename, columnname); @@ -1756,7 +1567,9 @@ void TSQLFile::SQLDeleteAllTables() { // Delete all tables in database - TObjArray* tables = SQLTablesList(); + if (fSQL==0) return; + + TList* tables = fSQL->GetTablesList(); if (tables==0) return; TString sqlcmd; @@ -1776,9 +1589,7 @@ Bool_t TSQLFile::SQLStartTransaction() { // Start SQL transaction. - Bool_t ok; - SQLQuery("START TRANSACTION", 0, &ok); - return ok; + return fSQL ? fSQL->StartTransaction() : kFALSE; } //______________________________________________________________________________ @@ -1786,9 +1597,7 @@ Bool_t TSQLFile::SQLCommit() { // Commit SQL transaction - Bool_t ok; - SQLQuery("COMMIT", 0, &ok); - return ok; + return fSQL ? fSQL->Commit() : kFALSE; } //______________________________________________________________________________ @@ -1796,9 +1605,20 @@ Bool_t TSQLFile::SQLRollback() { // Rollback all SQL operations, done after start transaction - Bool_t ok; - SQLQuery("ROLLBACK", 0, &ok); - return ok; + return fSQL ? fSQL->Rollback() : kFALSE; +} + +//______________________________________________________________________________ +Int_t TSQLFile::SQLMaxIdentifierLength() +{ + // returns maximum allowed length of identifiers + + Int_t maxlen = fSQL==0 ? 32 : fSQL->GetMaxIdentifierLength(); + + // lets exclude absolute ubnormal data + if (maxlen<10) maxlen = 10; + + return maxlen; } //______________________________________________________________________________ @@ -1831,25 +1651,26 @@ void TSQLFile::DeleteKeyFromDB(Long64_t keyid) // can be that object tables does not include any entry this that keyid if (minid<=maxid) { - TObjArray* tables = SQLTablesList(); - TIter iter(tables); - TObject* obj = 0; - while ((obj=iter())!=0) { - TString tablename = obj->GetName(); - - if ((tablename.CompareTo(sqlio::KeysTable,TString::kIgnoreCase)==0) || - (tablename.CompareTo(sqlio::ObjectsTable,TString::kIgnoreCase)==0) || - (tablename.CompareTo(sqlio::ConfigTable,TString::kIgnoreCase)==0)) continue; - - TString query; - query.Form("DELETE FROM %s%s%s WHERE %s%s%s BETWEEN %lld AND %lld", - quote, tablename.Data(), quote, + TIter iter(fSQLClassInfos); + TSQLClassInfo* info = 0; + TString querymask, query; + querymask.Form("DELETE FROM %s%s%s WHERE %s%s%s BETWEEN %lld AND %lld", + quote, "%s", quote, quote, SQLObjectIdColumn(), quote, minid, maxid); - SQLQuery(query.Data()); + + while ((info = (TSQLClassInfo*) iter()) !=0 ) { + + if (info->IsClassTableExist()) { + query.Form(querymask.Data(), info->GetClassTableName()); + SQLQuery(query.Data()); + } + + if (info->IsRawTableExist()) { + query.Form(querymask.Data(), info->GetRawTableName()); + SQLQuery(query.Data()); + } } - - delete tables; } sqlcmd.Form("DELETE FROM %s%s%s WHERE %s%s%s=%lld", quote, sqlio::ObjectsTable, quote, quote, SQLKeyIdColumn(), quote, keyid); @@ -1921,13 +1742,21 @@ Bool_t TSQLFile::UpdateKeyData(TKeySQL* key) TString sqlcmd; const char* valuequote = SQLValueQuote(); const char* quote = SQLIdentifierQuote(); - - sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%s, %s%s%s=%s, %s%s%s=%s, %s=%s WHERE %s%s%s=%lld", + + TString keyname = key->GetName(); + TString keytitle = key->GetTitle(); + TString keydatime = key->GetDatime().AsSQLString(); + + TSQLStructure::AddStrBrackets(keyname, valuequote); + TSQLStructure::AddStrBrackets(keytitle, valuequote); + TSQLStructure::AddStrBrackets(keydatime, valuequote); + + 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", quote, sqlio::KeysTable, quote, - sqlio::KT_Name, valuequote, key->GetName(), valuequote, - sqlio::KT_Title, valuequote, key->GetTitle(), valuequote, - sqlio::KT_Datetime, valuequote, key->GetDatime().AsSQLString(), valuequote, - sqlio::KT_Cycle, key->GetCycle(), + quote, sqlio::KT_Name, quote, keyname.Data(), + quote, sqlio::KT_Title, quote, keytitle.Data(), + quote, sqlio::KT_Datetime, quote, keydatime.Data(), + quote, sqlio::KT_Cycle, quote, key->GetCycle(), quote, SQLKeyIdColumn(), quote, key->GetDBKeyId()); Bool_t ok = kTRUE; @@ -1957,7 +1786,7 @@ Long64_t TSQLFile::DefineNextKeyId() //______________________________________________________________________________ TSQLClassInfo* TSQLFile::FindSQLClassInfo(const char* clname, Int_t version) { - // return (if exists) TSQLClassInfo for specified class and version + // return (if exists) TSQLClassInfo for specified class name and version if (fSQLClassInfos==0) return 0; @@ -1972,26 +1801,38 @@ TSQLClassInfo* TSQLFile::FindSQLClassInfo(const char* clname, Int_t version) } //______________________________________________________________________________ -TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const char* clname, Int_t version, Bool_t force) +TSQLClassInfo* TSQLFile::FindSQLClassInfo(const TClass* cl) +{ + // return (if exists) TSQLClassInfo for specified class + + return FindSQLClassInfo(cl->GetName(), cl->GetClassVersion()); +} + +//______________________________________________________________________________ +TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const char* clname, Int_t version) { // search in database tables for specified class and return TSQLClassInfo object TSQLClassInfo* info = FindSQLClassInfo(clname, version); - if (!force && (info!=0)) return info; + if (info!=0) return info; if (fSQL==0) return 0; + + Long64_t maxid = 0; - if (info==0) info = new TSQLClassInfo(clname, version); - - TObjArray* columns = 0; - - // first check if class table is exist - if (SQLTestTable(info->GetClassTableName())) - columns = SQLTableColumns(info->GetClassTableName()); + if (fSQLClassInfos!=0) { + TIter iter(fSQLClassInfos); + TSQLClassInfo* info = 0; + while ((info = (TSQLClassInfo*) iter()) !=0 ) { + if (info->GetClassId()>maxid) + maxid = info->GetClassId(); + } + } - Bool_t israwtable = SQLTestTable(info->GetRawTableName()); + info = new TSQLClassInfo(maxid+1, clname, version); - info->SetTableStatus(columns, israwtable); + info->SetClassTableName(DefineTableName(clname, version, kFALSE)); + info->SetRawTableName(DefineTableName(clname, version, kTRUE)); if (fSQLClassInfos==0) fSQLClassInfos = new TList; fSQLClassInfos->Add(info); @@ -2000,159 +1841,368 @@ TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const char* clname, Int_t version, } //______________________________________________________________________________ -TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const TClass* cl, Bool_t force) +TString TSQLFile::DefineTableName(const char* clname, Int_t version, Bool_t rawtable) { - // search in database tables for specified class and return TSQLClassInfo object + // proposes table name for class + + Int_t maxlen = SQLMaxIdentifierLength(); - return RequestSQLClassInfo(cl->GetName(), cl->GetClassVersion(), force); -} + TString res; -//______________________________________________________________________________ -Bool_t TSQLFile::SyncSQLClassInfo(TSQLClassInfo* sqlinfo, TObjArray* columns, Bool_t hasrawdata) -{ - // Synchronise TSQLClassInfo structure with specified columns list and - // create/delete appropriate tables in database + const char *suffix = rawtable ? "_raw" : "_ver"; - if (sqlinfo==0) return kFALSE; + res.Form("%s%s%d", clname, suffix, version); - if (gDebug>2) - Info("SyncSQLClassInfo", sqlinfo->GetName()); + if ((res.Length() <= maxlen) && !HasTable(res.Data())) + return res; + + TString scnt; + + Int_t len = strlen(clname); + Int_t cnt = version; + if (cnt>100) cnt = 0; // do not start with the biggest values + + do { + scnt.Form("%d%s",cnt, suffix); + Int_t numlen = scnt.Length(); + if (numlen>=maxlen-2) break; + + res = clname; + + if (len + numlen > maxlen) + res.Resize(maxlen - numlen); + + res+=scnt; + + if (!HasTable(res.Data())) return res; + + cnt++; + + } while (cnt<10000); - const char* quote = SQLIdentifierQuote(); + Error("DefineTableName","Cannot produce table name for class %s ver %d", clname, version); + res.Form("%s%s%d", clname, suffix, version); - if (sqlinfo->IsClassTableExist() && (columns==0)) { - TString sqlcmd; - sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlinfo->GetClassTableName(), quote); - SQLQuery(sqlcmd.Data()); + return res; +} + +//______________________________________________________________________________ +Bool_t TSQLFile::HasTable(const char* name) +{ + // test if table name exists - sqlinfo->SetColumns(0); + if (fSQLClassInfos==0) return kFALSE; + + TIter iter(fSQLClassInfos); + TSQLClassInfo* info = 0; + while ((info = (TSQLClassInfo*) iter()) !=0 ) { + if (strcmp(info->GetClassTableName(), name)==0) return kTRUE; + if (strcmp(info->GetRawTableName(), name)==0) return kTRUE; } + + return kFALSE; +} - if (!sqlinfo->IsClassTableExist() && (columns!=0)) { +//______________________________________________________________________________ +TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const TClass* cl) +{ + // search in database tables for specified class and return TSQLClassInfo object - TString sqlcmd; - sqlcmd.Form("CREATE TABLE %s%s%s (", - quote, sqlinfo->GetClassTableName(), quote); - - TObjArray* newcolumns = new TObjArray(); - TIter iter(columns); - TSQLColumnData* col; - Bool_t first = kTRUE; - Bool_t forcequote = IsOracle(); - while ((col=(TSQLColumnData*)iter())!=0) { - if (!first) sqlcmd+=", "; else first = false; - - const char* colname = col->GetName(); - if ((strpbrk(colname,"[:.]<>")!=0) || forcequote) { - sqlcmd += quote; - sqlcmd += colname; - sqlcmd += quote; - sqlcmd += " "; - } else { - sqlcmd += colname, - sqlcmd += " "; + return RequestSQLClassInfo(cl->GetName(), cl->GetClassVersion()); +} + +//______________________________________________________________________________ +void TSQLFile::ReadSQLClassInfos() +{ + // Read all class infos from IdsTable + + if (fSQL==0) return; + + fIdsTableExists = SQLTestTable(sqlio::IdsTable); + + if (!fIdsTableExists) return; + + TString sqlcmd; + const char* quote = SQLIdentifierQuote(); + + sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %d ORDER BY %s%s%s", + quote, sqlio::IdsTable, quote, + quote, sqlio::IT_Type, quote, TSQLStructure::kIdTable, + quote, sqlio::IT_TableID, quote); + + TSQLResult* res = SQLQuery(sqlcmd.Data(), 1); + + TSQLRow* row = 0; + + if (res!=0) + while ((row = res->Next())!=0) { + Long64_t tableid = sqlio::atol64(row->GetField(0)); + Int_t version = atoi(row->GetField(1)); + + const char* classname = row->GetField(3); + const char* classtable = row->GetField(4); + + TSQLClassInfo* info = new TSQLClassInfo(tableid, classname, version); + info->SetClassTableName(classtable); + + if (fSQLClassInfos==0) fSQLClassInfos = new TList; + fSQLClassInfos->Add(info); + + delete row; + } + delete res; + + + TIter next(fSQLClassInfos); + TSQLClassInfo* info = 0; + + while ((info = (TSQLClassInfo*) next()) != 0) { + sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %lld ORDER BY %s%s%s", + quote, sqlio::IdsTable, quote, + quote, sqlio::IT_TableID, quote, info->GetClassId(), + quote, sqlio::IT_SubID, quote); + res = SQLQuery(sqlcmd.Data(), 1); + + TObjArray* cols = 0; + + if (res!=0) + while ((row = res->Next())!=0) { + + Int_t typ = atoi(row->GetField(2)); + + const char* fullname = row->GetField(3); + const char* sqlname = row->GetField(4); + const char* info = row->GetField(5); + + if (typ==TSQLStructure::kIdColumn) { + if (cols==0) cols = new TObjArray; + cols->Add(new TSQLClassColumnInfo(fullname, sqlname, info)); + } + + delete row; } + + delete res; + + info->SetColumns(cols); + } + + sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s = %d ORDER BY %s%s%s", + quote, sqlio::IdsTable, quote, + quote, sqlio::IT_Type, quote, TSQLStructure::kIdRawTable, + quote, sqlio::IT_TableID, quote); + + res = SQLQuery(sqlcmd.Data(), 1); + + if (res!=0) + while ((row = res->Next())!=0) { + Long64_t tableid = sqlio::atol64(row->GetField(0)); + Int_t version = atoi(row->GetField(1)); + + const char* classname = row->GetField(3); + const char* rawtable = row->GetField(4); + + TSQLClassInfo* info = FindSQLClassInfo(classname, version); + + if (info==0) { + info = new TSQLClassInfo(tableid, classname, version); + + if (fSQLClassInfos==0) fSQLClassInfos = new TList; + fSQLClassInfos->Add(info); + } + + info->SetRawTableName(rawtable); + info->SetRawExist(kTRUE); + + delete row; + } + + delete res; +} - sqlcmd += col->GetType(); - newcolumns->Add(new TNamed(col->GetName(), col->GetType())); +//______________________________________________________________________________ +void TSQLFile::AddIdEntry(Long64_t tableid, Int_t subid, Int_t type, + const char* name, const char* sqlname, const char* info) +{ + // Add entry into IdsTable, where all tables names and columns names are listed + + if ((fSQL==0) || !IsWritable()) return; + + TString sqlcmd; + const char* valuequote = SQLValueQuote(); + const char* quote = SQLIdentifierQuote(); + + if (!fIdsTableExists) { + + if (SQLTestTable(sqlio::IdsTable)) { + sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::IdsTable, quote); + SQLQuery(sqlcmd.Data()); } - sqlcmd += ")"; - - if ((fTablesType.Length()>0) && IsMySQL()) { + + 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)", + quote, sqlio::IdsTable, quote, + quote, sqlio::IT_TableID, quote, SQLIntType(), + quote, sqlio::IT_SubID, quote, SQLIntType(), + quote, sqlio::IT_Type, quote, SQLIntType(), + quote, sqlio::IT_FullName, quote, SQLSmallTextType(), + quote, sqlio::IT_SQLName, quote, SQLSmallTextType(), + quote, sqlio::IT_Info, quote, SQLSmallTextType()); + if ((fTablesType.Length()>0) && IsMySQL()) { sqlcmd +=" TYPE="; sqlcmd += fTablesType; } - SQLQuery(sqlcmd.Data()); - - sqlinfo->SetColumns(newcolumns); - if (GetUseIndexes()>kIndexesBasic) { - sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I1%s ON %s%s%s (%s%s%s)", - quote, sqlinfo->GetClassTableName(), quote, - quote, sqlinfo->GetClassTableName(), quote, - quote, SQLObjectIdColumn(), quote); - SQLQuery(sqlcmd.Data()); - } + fIdsTableExists = kTRUE; } - SyncSQLClassInfoRawTables(sqlinfo, hasrawdata); + sqlcmd.Form("INSERT INTO %s%s%s VALUES (%lld, %d, %d, %s%s%s, %s%s%s, %s%s%s)", + quote, sqlio::IdsTable, quote, + tableid, subid, type, + valuequote, name, valuequote, + valuequote, sqlname, valuequote, + valuequote, info, valuequote); -/* - if (hasrawdata && !sqlinfo->IsRawTableExist()) { - TString sqlcmd; + SQLQuery(sqlcmd.Data()); +} - sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s %s, %s %s)", - quote, sqlinfo->GetRawTableName(), quote, - quote, SQLObjectIdColumn(), quote, SQLIntType(), - quote, SQLRawIdColumn(), quote, SQLIntType(), - sqlio::BT_Field, SQLSmallTextType(), - sqlio::BT_Value, SQLSmallTextType()); - - if ((fTablesType.Length()>0) && IsMySQL()) { - sqlcmd +=" TYPE="; - sqlcmd += fTablesType; +//______________________________________________________________________________ +Bool_t TSQLFile::CreateClassTable(TSQLClassInfo* sqlinfo, TObjArray* colinfos) +{ + // Create normal class table if required + + if (sqlinfo==0) return kFALSE; + + // this is normal situation, when no extra column infos was created when not necessary + if (colinfos==0) return sqlinfo->IsClassTableExist(); + + if (sqlinfo->IsClassTableExist()) { + if (colinfos!=0) { + colinfos->Delete(); + delete colinfos; + //Error("CreateClassTable","Why colinfos for table %s", sqlinfo->GetClassTableName()); } + return kTRUE; + } - SQLQuery(sqlcmd.Data()); - sqlinfo->SetRawExist(kTRUE); - - if (GetUseIndexes()>kIndexesClass) { - sqlcmd.Form("CREATE UNIQUE INDEX %s%s_Index%s ON %s%s%s (%s%s%s, %s%s%s)", - quote, sqlinfo->GetRawTableName(), quote, - quote, sqlinfo->GetRawTableName(), quote, - quote, SQLObjectIdColumn(), quote, - quote, SQLRawIdColumn(), quote); - SQLQuery(sqlcmd.Data()); + if (gDebug>2) + Info("CreateClassTable", "cl:%s", sqlinfo->GetName()); + + const char* quote = SQLIdentifierQuote(); + + AddIdEntry(sqlinfo->GetClassId(), + sqlinfo->GetClassVersion(), + TSQLStructure::kIdTable, + sqlinfo->GetName(), + sqlinfo->GetClassTableName(), + "Main class table"); + + TString sqlcmd; + sqlcmd.Form("CREATE TABLE %s%s%s (", + quote, sqlinfo->GetClassTableName(), quote); + + TIter iter(colinfos); + TSQLClassColumnInfo* col; + Bool_t first = kTRUE; + Bool_t forcequote = IsOracle(); + Int_t colid = 0; + while ((col=(TSQLClassColumnInfo*)iter())!=0) { + if (!first) sqlcmd+=", "; else first = false; + + const char* colname = col->GetSQLName(); + if ((strpbrk(colname,"[:.]<>")!=0) || forcequote) { + sqlcmd += quote; + sqlcmd += colname; + sqlcmd += quote; + sqlcmd += " "; + } else { + sqlcmd += colname, + sqlcmd += " "; } + sqlcmd += col->GetSQLType(); + + AddIdEntry(sqlinfo->GetClassId(), + colid++, + TSQLStructure::kIdColumn, + col->GetName(), + col->GetSQLName(), + col->GetSQLType()); + } + sqlcmd += ")"; + + if ((fTablesType.Length()>0) && IsMySQL()) { + sqlcmd +=" TYPE="; + sqlcmd += fTablesType; + } + + SQLQuery(sqlcmd.Data()); + + sqlinfo->SetColumns(colinfos); + + if (GetUseIndexes()>kIndexesBasic) { + + TString indxname = sqlinfo->GetClassTableName(); + indxname.ReplaceAll("_ver","_i1x"); + + sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I1%s ON %s%s%s (%s%s%s)", + quote, indxname.Data(), quote, + quote, sqlinfo->GetClassTableName(), quote, + quote, SQLObjectIdColumn(), quote); + SQLQuery(sqlcmd.Data()); } -*/ return kTRUE; } //______________________________________________________________________________ -Bool_t TSQLFile::SyncSQLClassInfoRawTables(TSQLClassInfo* sqlinfo, Bool_t hasrawdata) +Bool_t TSQLFile::CreateRawTable(TSQLClassInfo* sqlinfo) { - // creates table for class raw data, if it is not exists - if (sqlinfo==0) return kFALSE; + + if (sqlinfo->IsRawTableExist()) return kTRUE; const char* quote = SQLIdentifierQuote(); - if (hasrawdata && !sqlinfo->IsRawTableExist()) { - if (gDebug>2) - Info("SyncSQLClassInfoRawTables", sqlinfo->GetName()); + if (gDebug>2) + Info("CreateRawTable", sqlinfo->GetName()); - TString sqlcmd; + TString sqlcmd; - sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s %s, %s %s)", - quote, sqlinfo->GetRawTableName(), quote, - quote, SQLObjectIdColumn(), quote, SQLIntType(), - quote, SQLRawIdColumn(), quote, SQLIntType(), - sqlio::BT_Field, SQLSmallTextType(), - sqlio::BT_Value, SQLSmallTextType()); - - if ((fTablesType.Length()>0) && IsMySQL()) { - sqlcmd +=" TYPE="; - sqlcmd += fTablesType; - } + sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s %s, %s %s)", + quote, sqlinfo->GetRawTableName(), quote, + quote, SQLObjectIdColumn(), quote, SQLIntType(), + quote, SQLRawIdColumn(), quote, SQLIntType(), + sqlio::BT_Field, SQLSmallTextType(), + sqlio::BT_Value, SQLSmallTextType()); + + if ((fTablesType.Length()>0) && IsMySQL()) { + sqlcmd +=" TYPE="; + sqlcmd += fTablesType; + } - SQLQuery(sqlcmd.Data()); - sqlinfo->SetRawExist(kTRUE); - - if (GetUseIndexes()>kIndexesClass) { - sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I2%s ON %s%s%s (%s%s%s, %s%s%s)", - quote, sqlinfo->GetClassTableName(), quote, - quote, sqlinfo->GetRawTableName(), quote, - quote, SQLObjectIdColumn(), quote, - quote, SQLRawIdColumn(), quote); - SQLQuery(sqlcmd.Data()); - } + SQLQuery(sqlcmd.Data()); + sqlinfo->SetRawExist(kTRUE); + + if (GetUseIndexes()>kIndexesClass) { + TString indxname = sqlinfo->GetClassTableName(); + indxname.ReplaceAll("_ver","_i2x"); + sqlcmd.Form("CREATE UNIQUE INDEX %s%s_I2%s ON %s%s%s (%s%s%s, %s%s%s)", + quote, indxname.Data(), quote, + quote, sqlinfo->GetRawTableName(), quote, + quote, SQLObjectIdColumn(), quote, + quote, SQLRawIdColumn(), quote); + SQLQuery(sqlcmd.Data()); } + + AddIdEntry(sqlinfo->GetClassId(), + sqlinfo->GetClassVersion(), + TSQLStructure::kIdRawTable, + sqlinfo->GetName(), + sqlinfo->GetRawTableName(), + "Raw data class table"); return kTRUE; } @@ -2533,3 +2583,135 @@ const char* TSQLFile::SQLIntType() const return SQLCompatibleType(TStreamerInfo::kInt); } +//______________________________________________________________________________ +Long64_t TSQLFile::DirCreateEntry(TDirectory* dir) +{ + // Create entry for directory in database + + TDirectory* mother = dir->GetMotherDir(); + if (mother==0) mother = this; + + // key will be added to mother directory + TKeySQL* key = new TKeySQL(mother, dir, dir->GetName(), dir->GetTitle()); + + return key->GetDBKeyId(); +} + +//______________________________________________________________________________ +Int_t TSQLFile::DirReadKeys(TDirectory* dir) +{ + // Read directory list of keys from database + + // First delete all old keys + dir->GetListOfKeys()->Delete(); + + if (gDebug>2) + Info("DirReadKeys","dir = %s id = %d", dir->GetName(), dir->GetSeekDir()); + + return StreamKeysForDirectory(dir, kFALSE); +} + +//______________________________________________________________________________ +void TSQLFile::DirWriteKeys(TDirectory* dir) +{ + // Write directory keys list to database + + StreamKeysForDirectory(dir, kTRUE); +} + +//______________________________________________________________________________ +void TSQLFile::DirWriteHeader(TDirectory* dir) +{ + // Update dir header in the file + + TSQLClassInfo* sqlinfo = FindSQLClassInfo("TDirectory",TDirectory::Class()->GetClassVersion()); + if (sqlinfo==0) return; + + // try to identify key with data for our directory + TKeySQL* key = FindSQLKey(dir->GetMotherDir(), dir->GetSeekDir()); + if (key==0) return; + + const char* valuequote = SQLValueQuote(); + const char* quote = SQLIdentifierQuote(); + + TString timeC = dir->GetCreationDate().AsSQLString(); + TSQLStructure::AddStrBrackets(timeC, valuequote); + + TString timeM = dir->GetModificationDate().AsSQLString(); + TSQLStructure::AddStrBrackets(timeM, valuequote); + + TString uuid = dir->GetUUID().AsString(); + TSQLStructure::AddStrBrackets(uuid, valuequote); + + TString sqlcmd; + + TString col1name = "CreateTime"; + TString col2name = "ModifyTime"; + TString col3name = "UUID"; + if (GetUseSuffixes()) { + col1name+=sqlio::StrSuffix; + col2name+=sqlio::StrSuffix; + col3name+=sqlio::StrSuffix; + } + + sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%s, %s%s%s=%s, %s%s%s=%s WHERE %s%s%s=%d", + quote, sqlinfo->GetClassTableName(), quote, + quote, col1name.Data(), quote, timeC.Data(), + quote, col2name.Data(), quote, timeM.Data(), + quote, col3name.Data(), quote, uuid.Data(), + quote, SQLObjectIdColumn(), quote, key->GetDBObjId()); + + SQLQuery(sqlcmd.Data()); +} + +//______________________________________________________________________________ +void TSQLFile::Streamer(TBuffer &b) +{ + // streamer for TSQLFile class + // stores only data for TDirectory + + + TString sbuf; + + if (b.IsReading()) { + Version_t R__v = b.ReadVersion(0, 0); + b.ClassBegin(TSQLFile::Class(), R__v); + + b.ClassMember("CreateTime","TString"); + sbuf.Streamer(b); + TDatime timeC(sbuf.Data()); + fDatimeC = timeC; + + b.ClassMember("ModifyTime","TString"); + sbuf.Streamer(b); + TDatime timeM(sbuf.Data()); + fDatimeM = timeM; + + b.ClassMember("UUID","TString"); + sbuf.Streamer(b); + TUUID id(sbuf.Data()); + fUUID = id; + + b.ClassEnd(TSQLFile::Class()); + } else { + + b.WriteVersion(TSQLFile::Class()); + + b.ClassBegin(TSQLFile::Class()); + + b.ClassMember("CreateTime","TString"); + sbuf = fDatimeC.AsSQLString(); + sbuf.Streamer(b); + + b.ClassMember("ModifyTime","TString"); + fDatimeM.Set(); + sbuf = fDatimeM.AsSQLString(); + sbuf.Streamer(b); + + b.ClassMember("UUID","TString"); + sbuf = fUUID.AsString(); + sbuf.Streamer(b); + + b.ClassEnd(TSQLFile::Class()); + } +} diff --git a/sql/src/TSQLObjectData.cxx b/sql/src/TSQLObjectData.cxx index 7653019535b5d15ee2b3eafb791e3579d7a2cf6e..21735672eecc8ffcacbfba57287195c968969afa 100644 --- a/sql/src/TSQLObjectData.cxx +++ b/sql/src/TSQLObjectData.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLObjectData.cxx,v 1.6 2006/05/11 10:29:45 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLObjectData.cxx,v 1.7 2006/05/22 08:55:58 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -15,7 +15,7 @@ // It contains data, request from database table for one specifc // object for one specific class. For instance, when data for // class TH1 required, requests will be done to -// TH1_ver4 and TH1_streamer_ver4 tables and result of these reuests +// TH1_ver4 and TH1_raw4 tables and result of these requests // will be kept in single TSQLObjectData instance. // //________________________________________________________________________ @@ -164,9 +164,17 @@ Bool_t TSQLObjectData::LocateColumn(const char* colname, Bool_t isblob) if ((fClassData==0) || (fClassRow==0)) return kFALSE; - Int_t numfields = GetNumClassFields(); +// Int_t numfields = GetNumClassFields(); - for (Int_t ncol=1;ncol<numfields;ncol++) { + Int_t ncol = fInfo->FindColumn(colname, kFALSE); + if (ncol>0) { + fLocatedColumn = ncol; + fLocatedField = GetClassFieldName(ncol); + fLocatedValue = fClassRow->GetField(ncol); + } + + +/* for (Int_t ncol=1;ncol<numfields;ncol++) { const char* fieldname = GetClassFieldName(ncol); if (strcmp(colname, fieldname)==0) { fLocatedColumn = ncol; @@ -175,6 +183,7 @@ Bool_t TSQLObjectData::LocateColumn(const char* colname, Bool_t isblob) break; } } +*/ if (fLocatedField==0) return kFALSE; diff --git a/sql/src/TSQLStructure.cxx b/sql/src/TSQLStructure.cxx index 0775ac63fc2a293498b666a9541d65efaaf9d81f..b008b345db2c29b907da67cc0b053e2b6f94286a 100644 --- a/sql/src/TSQLStructure.cxx +++ b/sql/src/TSQLStructure.cxx @@ -1,4 +1,4 @@ -// @(#)root/sql:$Name: $:$Id: TSQLStructure.cxx,v 1.11 2006/05/12 08:17:02 brun Exp $ +// @(#)root/sql:$Name: $:$Id: TSQLStructure.cxx,v 1.12 2006/05/22 08:55:58 brun Exp $ // Author: Sergey Linev 20/11/2005 /************************************************************************* @@ -88,6 +88,8 @@ namespace sqlio { const char* KeysTableIndex = "KeysTableIndex"; const char* ObjectsTable = "ObjectsTable"; const char* ObjectsTableIndex = "ObjectsTableIndex"; + const char* IdsTable = "IdsTable"; + const char* IdsTableIndex = "IdsTableIndex"; const char* StringsTable = "StringsTable"; const char* ConfigTable = "Configurations"; @@ -106,6 +108,14 @@ namespace sqlio { const char* OT_Class = "Class"; const char* OT_Version = "Version"; + // columns in Identifiers Table + const char* IT_TableID = "TableId"; + const char* IT_SubID = "SubId"; + const char* IT_Type = "Type"; + const char* IT_FullName = "FullName"; + const char* IT_SQLName = "SQLName"; + const char* IT_Info = "Info"; + // colummns in _streamer_ tables const char* BT_Field = "Field"; const char* BT_Value = "Value"; @@ -194,19 +204,171 @@ TSQLColumnData::~TSQLColumnData() // TSQLColumnData destructor } + +ClassImp(TSQLTableData); + //________________________________________________________________________ +TSQLTableData::TSQLTableData(TSQLFile* f, TSQLClassInfo* info) : + TObject(), + fFile(f), + fInfo(info), + fColumns(), + fColInfos(0) +{ + // normal constructor + + if (!info->IsClassTableExist()) + fColInfos = new TObjArray; +} -ClassImp(TSQLStructure) +//________________________________________________________________________ +TSQLTableData::~TSQLTableData() +{ + // destructor + + fColumns.Delete(); + if (fColInfos!=0) { + fColInfos->Delete(); + delete fColInfos; + } +} - TSQLStructure::TSQLStructure() : - TObject(), - fParent(0), - fType(0), - fPointer(0), - fValue(), - fArrayIndex(-1), - fRepeatCnt(0), - fChilds() +//________________________________________________________________________ +void TSQLTableData::AddColumn(const char* name, Long64_t value) +{ + // Add INT column to list of columns + + TObjString* v = new TObjString(Form("%lld",value)); + v->SetBit(BIT(20), kTRUE); + fColumns.Add(v); + +// TSQLColumnData* col = new TSQLColumnData(name, value); +// fColumns.Add(col); + + if (fColInfos!=0) + fColInfos->Add(new TSQLClassColumnInfo(name, DefineSQLName(name), "INT")); +} + +//________________________________________________________________________ +void TSQLTableData::AddColumn(const char* name, + const char* sqltype, + const char* value, + Bool_t numeric) +{ + // Add nomral column to list of columns + + TObjString* v = new TObjString(value); + v->SetBit(BIT(20), numeric); + fColumns.Add(v); + +// TSQLColumnData* col = new TSQLColumnData(name, sqltype, value, numeric); +// fColumns.Add(col); + + if (fColInfos!=0) + fColInfos->Add(new TSQLClassColumnInfo(name, DefineSQLName(name), sqltype)); +} + +//________________________________________________________________________ +TString TSQLTableData::DefineSQLName(const char* fullname) +{ + // produce suitable name for column, taking into account length limitation + + Int_t maxlen = fFile->SQLMaxIdentifierLength(); + + Int_t len = strlen(fullname); + + if ((len<=maxlen) && !HasSQLName(fullname)) return TString(fullname); + + Int_t cnt = -1; + TString res, scnt; + + do { + + scnt.Form("%d",cnt); + Int_t numlen = cnt<0 ? 0 : scnt.Length(); + + res = fullname; + + if (len + numlen > maxlen) + res.Resize(maxlen - numlen); + + if (cnt>=0) res+=scnt; + + if (!HasSQLName(res.Data())) return res; + + cnt++; + + } while (cnt<10000); + + Error("DefineSQLName","Cannot find reasonable column name for field %s",fullname); + + return TString(fullname); +} + +//________________________________________________________________________ +Bool_t TSQLTableData::HasSQLName(const char* sqlname) +{ + // checks if columns list already has that sql name + + TIter next(fColInfos); + + TSQLClassColumnInfo* col = 0; + + while ((col = (TSQLClassColumnInfo*) next()) != 0) { + const char* colname = col->GetSQLName(); + if (strcmp(colname, sqlname)==0) return kTRUE; + } + + return kFALSE; + +} + +//________________________________________________________________________ +Int_t TSQLTableData::GetNumColumns() +{ + // returns number of columns in provided set + + return fColumns.GetLast() +1; +} + +//________________________________________________________________________ +const char* TSQLTableData::GetColumn(Int_t n) +{ + // returm column value + return fColumns[n]->GetName(); +} + +//________________________________________________________________________ +Bool_t TSQLTableData::IsNumeric(Int_t n) +{ + // identifies if column has numeric value + + return fColumns[n]->TestBit(BIT(20)); +} + +//________________________________________________________________________ +TObjArray* TSQLTableData::TakeColInfos() +{ + // take ownership over colinfos + + TObjArray* res = fColInfos; + fColInfos = 0; + return res; +} + +//________________________________________________________________________ + +ClassImp(TSQLStructure); + +TSQLStructure::TSQLStructure() : + TObject(), + fParent(0), + fType(0), + fPointer(0), + fValue(), + fArrayIndex(-1), + fRepeatCnt(0), + fChilds() { // default constructor } @@ -608,23 +770,6 @@ void TSQLStructure::PrintLevel(Int_t level) const GetChild(n)->PrintLevel(level+2); } -//________________________________________________________________________ -void TSQLStructure::AddCmd(TObjArray* cmds, - const char* name, const char* value, - const char* topname, const char* ns) -{ - // Add SQL command for raw table - - if ((topname!=0) && (ns!=0)) { - TString buf; - buf+=topname; - buf+=ns; - buf+=name; - cmds->Add(new TNamed(buf.Data(), value)); - } else - cmds->Add(new TNamed(name, value)); -} - //________________________________________________________________________ Bool_t TSQLStructure::IsNumericType(Int_t typ) { @@ -678,13 +823,18 @@ const char* TSQLStructure::GetSimpleTypeName(Int_t typ) return 0; } -// ====================================================================== +//___________________________________________________________ + +// TSqlCmdsBuffer used as buffer for data, which are correspond to +// particular class, defined by TSQLClassInfo instance +// Support both TSQLStatement and Query modes class TSqlCmdsBuffer : public TObject { public: - TSqlCmdsBuffer(TSQLClassInfo* info = 0) : + TSqlCmdsBuffer(TSQLFile* f, TSQLClassInfo* info) : TObject(), + fFile(f), fInfo(info), fBlobStmt(0), fNormStmt(0) @@ -695,8 +845,8 @@ public: { fNormCmds.Delete(); fBlobCmds.Delete(); - if (fBlobStmt!=0) delete fBlobStmt; - if (fNormStmt!=0) delete fNormStmt; + fFile->SQLDeleteStatement(fBlobStmt); + fFile->SQLDeleteStatement(fNormStmt); } void AddValues(Bool_t isnorm, const char* values) @@ -706,6 +856,7 @@ public: else fBlobCmds.Add(str); } + TSQLFile* fFile; TSQLClassInfo* fInfo; TObjArray fNormCmds; TObjArray fBlobCmds; @@ -713,9 +864,10 @@ public: TSQLStatement* fNormStmt; }; - - //________________________________________________________________________ +// TSqlRegistry keeps data, used when object data transformed to sql query or +// statements + class TSqlRegistry : public TObject { public: @@ -759,7 +911,7 @@ public: fPool.DeleteValues(); fLongStrValues.Delete(); fRegValues.Delete(); - if (fRegStmt) delete fRegStmt; + f->SQLDeleteStatement(fRegStmt); } Long64_t GetNextObjId() { return ++fLastObjId; } @@ -776,7 +928,7 @@ public: if (sqlinfo==0) return 0; TSqlCmdsBuffer* buf = (TSqlCmdsBuffer*) fPool.GetValue(sqlinfo); if (buf==0) { - buf = new TSqlCmdsBuffer(sqlinfo); + buf = new TSqlCmdsBuffer(f, sqlinfo); fPool.Add(sqlinfo, buf); } return buf; @@ -827,6 +979,8 @@ public: TSqlCmdsBuffer* buf = (TSqlCmdsBuffer*) fPool.GetValue(sqlinfo); if (buf==0) continue; ConvertSqlValues(buf->fNormCmds, sqlinfo->GetClassTableName()); + // ensure that raw table will be created + if (buf->fBlobCmds.GetLast()>=0) f->CreateRawTable(sqlinfo); ConvertSqlValues(buf->fBlobCmds, sqlinfo->GetRawTableName()); if (buf->fBlobStmt) buf->fBlobStmt->Process(); @@ -848,24 +1002,25 @@ public: return; } - if (f->IsOracle()) { - if (fRegStmt==0) { + if (f->IsOracle() || f->IsODBC()) { + if ((fRegStmt==0) && f->SQLCanStatement()) { const char* quote = f->SQLIdentifierQuote(); - TString sqlcmd; - sqlcmd.Form("INSERT INTO %s%s%s VALUES (:1, :2, :3, :4)", - quote, sqlio::ObjectsTable, quote); - fRegStmt = f->fSQL->Statement(sqlcmd.Data(), 1000); - f->fQuerisCounter++; + + TString sqlcmd; + const char* pars = f->IsOracle() ? ":1, :2, :3, :4" : "?, ?, ?, ?"; + sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s)", + quote, sqlio::ObjectsTable, quote, pars); + fRegStmt = f->SQLStatement(sqlcmd.Data(), 1000); } - fRegStmt->NextIteration(); - - fRegStmt->SetLong64(0, fKeyId); - fRegStmt->SetLong64(1, objid); - fRegStmt->SetString(2, cl->GetName()); - fRegStmt->SetInt(3, cl->GetClassVersion()); - - return; + if (fRegStmt!=0) { + fRegStmt->NextIteration(); + fRegStmt->SetLong64(0, fKeyId); + fRegStmt->SetLong64(1, objid); + fRegStmt->SetString(2, cl->GetName(), f->SQLSmallTextTypeLimit()); + fRegStmt->SetInt(3, cl->GetClassVersion()); + return; + } } const char* valuequote = f->SQLValueQuote(); @@ -895,123 +1050,68 @@ public: return strid; } - - void ConvertBlobsOracle(TObjArray* blobs, TSQLClassInfo* sqlinfo, Int_t& rawid) - { - TSqlCmdsBuffer* buf = GetCmdsBuffer(sqlinfo); - if (buf==0) return; - - TSQLStatement* stmt = buf->fBlobStmt; - if (stmt==0) { - const char* quote = f->SQLIdentifierQuote(); - TString sqlcmd; - sqlcmd.Form("INSERT INTO %s%s%s VALUES (:1, :2, :3, :4)", - quote, sqlinfo->GetRawTableName(), quote); - stmt = f->fSQL->Statement(sqlcmd.Data(), 2000); - f->fQuerisCounter++; - buf->fBlobStmt = stmt; - } - TIter iter(blobs); - TNamed* cmd = 0; - - while ((cmd = (TNamed*)iter())!=0) { - stmt->NextIteration(); - - stmt->SetLong64(0, fCurrentObjId); - stmt->SetInt(1, rawid); - stmt->SetString(2, cmd->GetName()); - stmt->SetString(3, cmd->GetTitle()); - - rawid++; - } - } - - void InsertToNormalTableOracle(TObjArray* columns, TSQLClassInfo* sqlinfo) + Bool_t InsertToNormalTableOracle(TSQLTableData* columns, TSQLClassInfo* sqlinfo) { TSqlCmdsBuffer* buf = GetCmdsBuffer(sqlinfo); - if (buf==0) return; + if (buf==0) return kFALSE; TSQLStatement* stmt = buf->fNormStmt; if (stmt==0) { + // if one cannot create statement, do it normal way + if (!f->SQLCanStatement()) return kFALSE; + const char* quote = f->SQLIdentifierQuote(); TString sqlcmd; - sqlcmd.Form("INSERT INTO %s%s%s VALUES (:", + sqlcmd.Form("INSERT INTO %s%s%s VALUES (", quote, sqlinfo->GetClassTableName(), quote); - for (int n=0;n<=columns->GetLast();n++) { - if (n>0) sqlcmd +=", :"; - sqlcmd += (n+1); + for (int n=0;n<columns->GetNumColumns();n++) { + if (n>0) sqlcmd +=", "; + if (f->IsOracle()) { + sqlcmd += ":"; + sqlcmd += (n+1); + } else + sqlcmd += "?"; } sqlcmd += ")"; - stmt = f->fSQL->Statement(sqlcmd.Data(), 1000); - f->fQuerisCounter++; + stmt = f->SQLStatement(sqlcmd.Data(), 1000); + if (stmt==0) return kFALSE; buf->fNormStmt = stmt; } stmt->NextIteration(); + + Int_t sizelimit = f->SQLSmallTextTypeLimit(); - TIter iter(columns); - TSQLColumnData* col; - Int_t ncol = 0; - while ((col=(TSQLColumnData*)iter())!=0) { - const char* value = col->GetValue(); - stmt->SetString(ncol, value); - ncol++; - } - } - - void ConvertBlobs(TObjArray* blobs, TSQLClassInfo* sqlinfo, Int_t& rawid) - { - - if (f->IsOracle()) { - ConvertBlobsOracle(blobs, sqlinfo, rawid); - return; - } - - TSqlCmdsBuffer* buf = GetCmdsBuffer(sqlinfo); - if (buf==0) return; - - TString value, onecmd, cmdmask; - - const char* valuequote = f->SQLValueQuote(); - - cmdmask.Form("%lld, %s, %s%s%s, %s", fCurrentObjId, "%d", valuequote, "%s", valuequote, "%s"); - - TIter iter(blobs); - TNamed* cmd = 0; - while ((cmd = (TNamed*)iter())!=0) { - value = cmd->GetTitle(); - TSQLStructure::AddStrBrackets(value, valuequote); - onecmd.Form(cmdmask.Data(), rawid++, cmd->GetName(), value.Data()); - buf->AddValues(kFALSE, onecmd.Data()); + for (Int_t ncol=0;ncol<columns->GetNumColumns();ncol++) { + const char* value = columns->GetColumn(ncol); + if (value==0) value = ""; + stmt->SetString(ncol, value, sizelimit); } + + return kTRUE; } - void InsertToNormalTable(TObjArray* columns, TSQLClassInfo* sqlinfo) + void InsertToNormalTable(TSQLTableData* columns, TSQLClassInfo* sqlinfo) { // produce SQL query to insert object data into normal table - if (f->IsOracle()) { - InsertToNormalTableOracle(columns, sqlinfo); - return; - } + if (f->IsOracle() || f->IsODBC()) + if (InsertToNormalTableOracle(columns, sqlinfo)) + return; - TIter iter(columns); - TSQLColumnData* col; const char* valuequote = f->SQLValueQuote(); TString values; - Bool_t first = kTRUE; - - while ((col=(TSQLColumnData*)iter())!=0) { - if (first) first = kFALSE; - else values+=", "; - if (col->IsNumeric()) - values+=col->GetValue(); + for (Int_t n=0;n<columns->GetNumColumns();n++) { + if (n>0) values+=", "; + + if (columns->IsNumeric(n)) + values+=columns->GetColumn(n); else { - TString value = col->GetValue(); + TString value = columns->GetColumn(n); TSQLStructure::AddStrBrackets(value, valuequote); values += value; } @@ -1022,6 +1122,113 @@ public: } }; + +//_____________________________________________________________________________ + +// TSqlRawBuffer is used to convert raw data, which corresponds to one +// object and belong to single SQL tables. Supoorts both statements +// and query mode + +class TSqlRawBuffer : public TObject { + +public: + + TSqlRawBuffer(TSqlRegistry* reg, TSQLClassInfo* sqlinfo) : + TObject(), + fFile(0), + fInfo(0), + fCmdBuf(0), + fObjId(0), + fRawId(0), + fValueMask(), + fValueQuote(0), + fMaxStrSize(255) + { + fFile = reg->f; + fInfo = sqlinfo; + fCmdBuf = reg->GetCmdsBuffer(sqlinfo); + fObjId = reg->fCurrentObjId; + fValueQuote = fFile->SQLValueQuote(); + fValueMask.Form("%lld, %s, %s%s%s, %s", fObjId, "%d", fValueQuote, "%s", fValueQuote, "%s"); + fMaxStrSize = reg->f->SQLSmallTextTypeLimit(); + } + + virtual ~TSqlRawBuffer() + { + // close blob statement for Oracle + TSQLStatement* stmt = fCmdBuf->fBlobStmt; + if ((stmt!=0) && fFile->IsOracle()) { + stmt->Process(); + delete stmt; + fCmdBuf->fBlobStmt = 0; + } + } + + Bool_t IsAnyData() const { return fRawId>0; } + + void AddLine(const char* name, const char* value, const char* topname = 0, const char* ns = 0) + { + if (fCmdBuf==0) return; + + // when first line is created, check all problems + if (fRawId==0) { + Bool_t maketmt = kFALSE; + if (fFile->IsOracle() || fFile->IsODBC()) + maketmt = (fCmdBuf->fBlobStmt==0) && fFile->SQLCanStatement(); + + if (maketmt) { + // ensure that raw table is exists + fFile->CreateRawTable(fInfo); + + const char* quote = fFile->SQLIdentifierQuote(); + TString sqlcmd; + const char* params = fFile->IsOracle() ? ":1, :2, :3, :4" : "?, ?, ?, ?"; + sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s)", + quote, fInfo->GetRawTableName(), quote, params); + TSQLStatement* stmt = fFile->SQLStatement(sqlcmd.Data(), 2000); + fCmdBuf->fBlobStmt = stmt; + } + } + + TString buf; + const char* fullname = name; + if ((topname!=0) && (ns!=0)) { + buf+=topname; + buf+=ns; + buf+=name; + fullname = buf.Data(); + } + + TSQLStatement* stmt = fCmdBuf->fBlobStmt; + + if (stmt!=0) { + stmt->NextIteration(); + stmt->SetLong64(0, fObjId); + stmt->SetInt(1, fRawId++); + stmt->SetString(2, fullname, fMaxStrSize); +// Info("AddLine","name = %s value = %s",fullname, value); + stmt->SetString(3, value, fMaxStrSize); + } else { + TString valuebuf(value); + TSQLStructure::AddStrBrackets(valuebuf, fValueQuote); + TString cmd; + cmd.Form(fValueMask.Data(), fRawId++, fullname, valuebuf.Data()); + fCmdBuf->AddValues(kFALSE, cmd.Data()); + } + } + + TSQLFile* fFile; + TSQLClassInfo* fInfo; + TSqlCmdsBuffer* fCmdBuf; + Long64_t fObjId; + Int_t fRawId; + TString fValueMask; + const char* fValueQuote; + TSQLStatement* fStmt; + Bool_t fUseStmt; + Int_t fMaxStrSize; +}; + //________________________________________________________________________ Long64_t TSQLStructure::FindMaxObjectId() { @@ -1066,7 +1273,7 @@ Bool_t TSQLStructure::ConvertToTables(TSQLFile* file, Long64_t keyid, TObjArray* } //________________________________________________________________________ -void TSQLStructure::PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const char* topname, Bool_t useblob) +void TSQLStructure::PerformConversion(TSqlRegistry* reg, TSqlRawBuffer* blobs, const char* topname, Bool_t useblob) { // perform conversion of structure to sql statements // first tries convert it to normal form @@ -1080,13 +1287,13 @@ void TSQLStructure::PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const if (!StoreObject(reg, DefineObjectId(kFALSE), GetObjectClass())) break; - AddCmd(blobs, sqlio::ObjectRef, GetValue(), topname, ns); + blobs->AddLine(sqlio::ObjectRef, GetValue(), topname, ns); break; } case kSqlPointer: { - AddCmd(blobs, sqlio::ObjectPtr, fValue.Data(), topname,ns); + blobs->AddLine(sqlio::ObjectPtr, fValue.Data(), topname,ns); break; } @@ -1095,7 +1302,7 @@ void TSQLStructure::PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const topname = ((TClass*) fPointer)->GetName(); else Error("PerformConversion","version without class"); - AddCmd(blobs, sqlio::Version, fValue.Data(), topname, ns); + blobs->AddLine(sqlio::Version, fValue.Data(), topname, ns); break; } @@ -1114,7 +1321,7 @@ void TSQLStructure::PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const TString sobjid; sobjid.Form("%lld",objid); if (!StoreObject(reg, objid, info->GetClass(), kTRUE)) return; - AddCmd(blobs, sqlio::ObjectInst, sobjid.Data(), topname, ns); + blobs->AddLine(sqlio::ObjectInst, sobjid.Data(), topname, ns); } break; } @@ -1155,14 +1362,14 @@ void TSQLStructure::PerformConversion(TSqlRegistry* reg, TObjArray* blobs, const } } - AddCmd(blobs, sbuf.Data(), value, (fArrayIndex>=0) ? 0 : topname, ns); + blobs->AddLine(sbuf.Data(), value, (fArrayIndex>=0) ? 0 : topname, ns); break; } case kSqlArray: { if (fValue.Length()>0) - AddCmd(blobs, sqlio::Array, fValue.Data(), topname, ns); + blobs->AddLine(sqlio::Array, fValue.Data(), topname, ns); for(Int_t n=0;n<=fChilds.GetLast();n++) { TSQLStructure* child = (TSQLStructure*) fChilds.At(n); child->PerformConversion(reg, blobs, topname, useblob); @@ -1187,8 +1394,6 @@ Bool_t TSQLStructure::StoreObject(TSqlRegistry* reg, Long64_t objid, TClass* cl, if (GetElement()) cout << "Element = " << GetElement()->GetName() << endl; } - TSQLClassInfo* sqlinfo = 0; - Long64_t oldid = reg->fCurrentObjId; TClass* oldcl = reg->fCurrentObjClass; @@ -1218,24 +1423,17 @@ Bool_t TSQLStructure::StoreObject(TSqlRegistry* reg, Long64_t objid, TClass* cl, if (!normstore) { - TObjArray objblobs; + // This is a case, when only raw table is exists + + TSQLClassInfo* sqlinfo = reg->f->RequestSQLClassInfo(cl); + TSqlRawBuffer rawdata(reg, sqlinfo); - // when TClonesArray, all data will be stored in raw format for(Int_t n=0;n<NumChilds();n++) { TSQLStructure* child = GetChild(n); - child->PerformConversion(reg, &objblobs, 0 /*cl->GetName()*/); - } - - if (objblobs.GetLast()<0) - res = kFALSE; - else { - sqlinfo = reg->f->RequestSQLClassInfo(cl); - reg->f->SyncSQLClassInfo(sqlinfo, 0, kTRUE); - Int_t currrawid = 0; - reg->ConvertBlobs(&objblobs, sqlinfo, currrawid); + child->PerformConversion(reg, &rawdata, 0 /*cl->GetName()*/); } - objblobs.Delete(); + res = rawdata.IsAnyData(); } if (registerobj) @@ -1277,13 +1475,15 @@ Bool_t TSQLStructure::StoreClassInNormalForm(TSqlRegistry* reg) TSQLClassInfo* sqlinfo = reg->f->RequestSQLClassInfo(cl->GetName(), version); - TObjArray columns; + TSQLTableData columns(reg->f, sqlinfo); Bool_t needblob = kFALSE; - Int_t currrawid = 0; + TSqlRawBuffer rawdata(reg, sqlinfo); + +// Int_t currrawid = 0; // add first column with object id - columns.Add(new TSQLColumnData(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId)); + columns.AddColumn(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId); for(Int_t n=0;n<=fChilds.GetLast();n++) { TSQLStructure* child = (TSQLStructure*) fChilds.At(n); @@ -1302,39 +1502,39 @@ Bool_t TSQLStructure::StoreClassInNormalForm(TSqlRegistry* reg) continue; } - TObjArray blobs; Bool_t doblobs = kTRUE; + Int_t blobid = rawdata.fRawId; // keep id of first raw, used in class table + if (columntyp==kColObjectArray) - if (child->TryConvertObjectArray(reg, &blobs)) + if (child->TryConvertObjectArray(reg, &rawdata)) doblobs = kFALSE; if (doblobs) - child->PerformConversion(reg, &blobs, elem->GetName(), kFALSE); - - Int_t blobid = -1; - if (blobs.GetLast()>=0) { - reg->f->SyncSQLClassInfoRawTables(sqlinfo, kTRUE); - blobid = currrawid; // column will contain first raw id - reg->ConvertBlobs(&blobs, sqlinfo, currrawid); + child->PerformConversion(reg, &rawdata, elem->GetName(), kFALSE); + + if (blobid==rawdata.fRawId) + blobid = -1; // no data for blob was created + else { + //reg->f->CreateRawTable(sqlinfo); + //blobid = currrawid; // column will contain first raw id + //reg->ConvertBlobs(&blobs, sqlinfo, currrawid); needblob = kTRUE; } - blobs.Delete(); + //blobs.Delete(); TString blobname = elem->GetName(); if (reg->f->GetUseSuffixes()) blobname += sqlio::RawSuffix; - columns.Add(new TSQLColumnData(blobname, blobid)); + columns.AddColumn(blobname, blobid); } - reg->f->SyncSQLClassInfo(sqlinfo, &columns, needblob); + reg->f->CreateClassTable(sqlinfo, columns.TakeColInfos()); reg->InsertToNormalTable(&columns, sqlinfo); - columns.Delete(); - return kTRUE; } @@ -1357,7 +1557,7 @@ TString TSQLStructure::MakeArrayIndex(TStreamerElement* elem, Int_t index) } //________________________________________________________________________ -Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* columns) +Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TSQLTableData* columns) { // tries to store element data in column @@ -1386,11 +1586,11 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col const char* stype = reg->f->SQLSmallTextType(); if (len<=sizelimit) - columns->Add(new TSQLColumnData(colname.Data(), stype, value, kFALSE)); + columns->AddColumn(colname.Data(), stype, value, kFALSE); else { Int_t strid = reg->AddLongString(value); TString buf = reg->f->CodeLongString(reg->fCurrentObjId, strid); - columns->Add(new TSQLColumnData(colname.Data(), stype, buf.Data(), kFALSE)); + columns->AddColumn(colname.Data(), stype, buf.Data(), kFALSE); } return kTRUE; @@ -1402,7 +1602,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col Int_t resversion = basecl->GetClassVersion(); if (!StoreObject(reg, objid, basecl, kFALSE)) resversion = -1; - columns->Add(new TSQLColumnData(colname.Data(), resversion)); + columns->AddColumn(colname.Data(), resversion); return kTRUE; } @@ -1431,7 +1631,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col objid = -1; // this is a case, when no data was stored for this object } - columns->Add(new TSQLColumnData(colname.Data(), objid)); + columns->AddColumn(colname.Data(), objid); return kTRUE; } @@ -1461,11 +1661,12 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col return kFALSE; } - columns->Add(new TSQLColumnData(colname.Data(), objid)); + columns->AddColumn(colname.Data(), objid); return kTRUE; } if (columntyp==kColNormObjectArray) { + if (elem->GetArrayLength()!=NumChilds()) return kFALSE; for (Int_t index=0;index<NumChilds();index++) { @@ -1474,18 +1675,16 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col (child->GetType()!=kSqlObject)) return kFALSE; Bool_t normal = kTRUE; - Long64_t objid = -1; + Long64_t objid = child->DefineObjectId(kFALSE); - if (child->GetType()==kSqlObject) { - objid = child->DefineObjectId(kFALSE); + if (child->GetType()==kSqlObject) normal = child->StoreObject(reg, objid, child->GetObjectClass()); - } if (!normal) return kFALSE; colname = DefineElementColumnName(elem, reg->f, index); - columns->Add(new TSQLColumnData(colname.Data(), objid)); + columns->AddColumn(colname.Data(), objid); } return kTRUE; } @@ -1505,7 +1704,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col if (!normal) return kFALSE; - columns->Add(new TSQLColumnData(colname.Data(), objid)); + columns->AddColumn(colname.Data(), objid); return kTRUE; } @@ -1525,7 +1724,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col const char* sqltype = reg->f->SQLCompatibleType(typ); - columns->Add(new TSQLColumnData(colname.Data(), sqltype, value, IsNumericType(typ))); + columns->AddColumn(colname.Data(), sqltype, value, IsNumericType(typ)); return kTRUE; } @@ -1553,7 +1752,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col while (index<last) { colname = DefineElementColumnName(elem, reg->f, index); - columns->Add(new TSQLColumnData(colname.Data(), sqltype, value, kTRUE)); + columns->AddColumn(colname.Data(), sqltype, value, kTRUE); index++; } } @@ -1564,7 +1763,7 @@ Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry* reg, TObjArray* col } //________________________________________________________________________ -Bool_t TSQLStructure::TryConvertObjectArray(TSqlRegistry* reg, TObjArray* blobs) +Bool_t TSQLStructure::TryConvertObjectArray(TSqlRegistry* reg, TSqlRawBuffer* blobs) { // tries to write array of objects as lis of object refereneces // in _streamer_ table, while objects itself will be stored in @@ -1600,7 +1799,7 @@ Bool_t TSQLStructure::TryConvertObjectArray(TSqlRegistry* reg, TObjArray* blobs) TString sobjid; sobjid.Form("%lld", objid); - AddCmd(blobs, sqlio::ObjectRef_Arr, sobjid.Data(), elem->GetName(), ns); + blobs->AddLine(sqlio::ObjectRef_Arr, sobjid.Data(), elem->GetName(), ns); } return kTRUE; @@ -1653,22 +1852,20 @@ Bool_t TSQLStructure::StoreTObject(TSqlRegistry* reg) if (sqlinfo==0) return kFALSE; - TObjArray columns; + TSQLTableData columns(reg->f, sqlinfo); const char* uinttype = reg->f->SQLCompatibleType(TStreamerInfo::kUInt); - columns.Add(new TSQLColumnData(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId)); + columns.AddColumn(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId); - columns.Add(new TSQLColumnData(sqlio::TObjectUniqueId, uinttype, str_id->GetValue(), kTRUE)); - columns.Add(new TSQLColumnData(sqlio::TObjectBits, uinttype, str_bits->GetValue(), kTRUE)); - columns.Add(new TSQLColumnData(sqlio::TObjectProcessId, "CHAR(3)", (str_prid ? str_prid->GetValue() : ""), kFALSE)); + columns.AddColumn(sqlio::TObjectUniqueId, uinttype, str_id->GetValue(), kTRUE); + columns.AddColumn(sqlio::TObjectBits, uinttype, str_bits->GetValue(), kTRUE); + columns.AddColumn(sqlio::TObjectProcessId, "CHAR(3)", (str_prid ? str_prid->GetValue() : ""), kFALSE); - reg->f->SyncSQLClassInfo(sqlinfo, &columns, kFALSE); + reg->f->CreateClassTable(sqlinfo, columns.TakeColInfos()); reg->InsertToNormalTable(&columns, sqlinfo); - columns.Delete(); - return kTRUE; } @@ -1684,14 +1881,14 @@ Bool_t TSQLStructure::StoreTString(TSqlRegistry* reg) TSQLClassInfo* sqlinfo = reg->f->RequestSQLClassInfo(TString::Class()); if (sqlinfo==0) return kFALSE; - TObjArray columns; + TSQLTableData columns(reg->f, sqlinfo); - columns.Add(new TSQLColumnData(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId)); - columns.Add(new TSQLColumnData(sqlio::TStringValue, reg->f->SQLBigTextType(), value, kFALSE)); + columns.AddColumn(reg->f->SQLObjectIdColumn(), reg->fCurrentObjId); + columns.AddColumn(sqlio::TStringValue, reg->f->SQLBigTextType(), value, kFALSE); - reg->f->SyncSQLClassInfo(sqlinfo, &columns, kFALSE); + reg->f->CreateClassTable(sqlinfo, columns.TakeColInfos()); + reg->InsertToNormalTable(&columns, sqlinfo); - columns.Delete(); return kTRUE; } @@ -1966,7 +2163,7 @@ Int_t TSQLStructure::LocateElementColumn(TSQLFile* f, TBufferSQL2* buf, TSQLObje break; } - TSQLClassInfo* sqlinfo = f->RequestSQLClassInfo(clname, version); + TSQLClassInfo* sqlinfo = f->FindSQLClassInfo(clname, version); if (sqlinfo==0) return kColUnknown; // this will indicate that streamer is completely custom @@ -2011,7 +2208,7 @@ Int_t TSQLStructure::LocateElementColumn(TSQLFile* f, TBufferSQL2* buf, TSQLObje break; } - TSQLClassInfo* sqlinfo = f->RequestSQLClassInfo(clname.Data(), version); + TSQLClassInfo* sqlinfo = f->FindSQLClassInfo(clname.Data(), version); if (sqlinfo==0) return kColUnknown; if (sqlinfo->IsClassTableExist()) { @@ -2099,7 +2296,7 @@ Bool_t TSQLStructure::UnpackTObject(TSQLFile* f, TBufferSQL2* buf, TSQLObjectDat { // Unpack TObject data in form, understodable by custom TObject streamer - TSQLClassInfo* sqlinfo = f->RequestSQLClassInfo(TObject::Class()->GetName(), clversion); + TSQLClassInfo* sqlinfo = f->FindSQLClassInfo(TObject::Class()->GetName(), clversion); if (sqlinfo==0) return kFALSE; TSQLObjectData* tobjdata = buf->SqlObjectData(objid, sqlinfo); @@ -2130,7 +2327,7 @@ Bool_t TSQLStructure::UnpackTString(TSQLFile* f, TBufferSQL2* buf, TSQLObjectDat { // Unpack TString data in form, understodable by custom TString streamer - TSQLClassInfo* sqlinfo = f->RequestSQLClassInfo(TString::Class()->GetName(), clversion); + TSQLClassInfo* sqlinfo = f->FindSQLClassInfo(TString::Class()->GetName(), clversion); if (sqlinfo==0) return kFALSE; TSQLObjectData* tstringdata = buf->SqlObjectData(objid, sqlinfo); diff --git a/xml/inc/TKeyXML.h b/xml/inc/TKeyXML.h index 4743f4373c246d290e41a009b1afd858db2370eb..8ac63e37e043fac58fe1ce0e9400348d56291b69 100644 --- a/xml/inc/TKeyXML.h +++ b/xml/inc/TKeyXML.h @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TKeyXML.h,v 1.4 2006/01/25 16:00:11 pcanal Exp $ +// @(#)root/xml:$Name: $:$Id: TKeyXML.h,v 1.5 2006/02/01 18:57:41 pcanal Exp $ // Author: Sergey Linev 10.05.2004 /************************************************************************* @@ -26,9 +26,9 @@ class TKeyXML : public TKey { TKeyXML(); public: - TKeyXML(TDirectory* mother, const TObject* obj, const char* name = 0); - TKeyXML(TDirectory* mother, const void* obj, const TClass* cl, const char* name); - TKeyXML(TDirectory* mother, XMLNodePointer_t keynode); + TKeyXML(TDirectory* mother, Long64_t keyid, const TObject* obj, const char* name = 0, const char* title = 0); + TKeyXML(TDirectory* mother, Long64_t keyid, const void* obj, const TClass* cl, const char* name, const char* title = 0); + TKeyXML(TDirectory* mother, Long64_t keyid, XMLNodePointer_t keynode); virtual ~TKeyXML(); // redefined TKey Methods @@ -55,15 +55,23 @@ class TKeyXML : public TKey { // TKeyXML specific methods XMLNodePointer_t KeyNode() const { return fKeyNode; } - + Long64_t GetKeyId() const { return fKeyId; } + Bool_t IsSubdir() const { return fSubdir; } + void SetSubir() { fSubdir = kTRUE; } + void UpdateObject(TObject* obj); + void UpdateAttributes(); + protected: virtual Int_t Read(const char *name) { return TKey::Read(name); } void StoreObject(const void* obj, const TClass* cl); + void StoreKeyAttributes(); TXMLEngine* XMLEngine(); void* XmlReadAny(void* obj, const TClass* expectedClass); - XMLNodePointer_t fKeyNode; //! + XMLNodePointer_t fKeyNode; //! node with stored object + Long64_t fKeyId; //! unique identifier of key for search methods + Bool_t fSubdir; //! indicates that key contains subdirectory ClassDef(TKeyXML,1) // a special TKey for XML files }; diff --git a/xml/inc/TXMLEngine.h b/xml/inc/TXMLEngine.h index 16b59a2419a17b4f270c026184fea3a8b3e6478b..996050e3af7aa7a3bd1a3497f9bbff842e4da6d6 100644 --- a/xml/inc/TXMLEngine.h +++ b/xml/inc/TXMLEngine.h @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TXMLEngine.h,v 1.10 2006/01/20 01:12:13 pcanal Exp $ +// @(#)root/xml:$Name: $:$Id: TXMLEngine.h,v 1.11 2006/05/30 12:59:30 brun Exp $ // Author: Sergey Linev 10.05.2004 /************************************************************************* @@ -37,6 +37,7 @@ class TXMLEngine : public TObject { const char* name, const char* value); XMLAttrPointer_t NewIntAttr(XMLNodePointer_t xmlnode, const char* name, Int_t value); void FreeAttr(XMLNodePointer_t xmlnode, const char* name); + void FreeAllAttr(XMLNodePointer_t xmlnode); XMLAttrPointer_t GetFirstAttr(XMLNodePointer_t xmlnode); XMLAttrPointer_t GetNextAttr(XMLAttrPointer_t xmlattr); const char* GetAttrName(XMLAttrPointer_t xmlattr); @@ -48,6 +49,7 @@ class TXMLEngine : public TObject { const char* GetNSName(XMLNsPointer_t ns); const char* GetNSReference(XMLNsPointer_t ns); void AddChild(XMLNodePointer_t parent, XMLNodePointer_t child); + void AddChildFirst(XMLNodePointer_t parent, XMLNodePointer_t child); void UnlinkNode(XMLNodePointer_t node); void FreeNode(XMLNodePointer_t xmlnode); void UnlinkFreeNode(XMLNodePointer_t xmlnode); diff --git a/xml/inc/TXMLFile.h b/xml/inc/TXMLFile.h index a1582abfec3024e7d3bbf3008509f8128dc996c3..8f97e6652aefd1a9b5dbce9c2b8be0a3ceb0f9e7 100644 --- a/xml/inc/TXMLFile.h +++ b/xml/inc/TXMLFile.h @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TXMLFile.h,v 1.12 2006/01/20 01:12:13 pcanal Exp $ +// @(#)root/xml:$Name: $:$Id: TXMLFile.h,v 1.13 2006/02/01 18:57:41 pcanal Exp $ // Author: Sergey Linev 10.05.2004 /************************************************************************* @@ -30,101 +30,115 @@ class TStreamerInfo; class TXMLFile : public TFile, public TXMLSetup { - protected: - void InitXmlFile(Bool_t create); - // Interface to basic system I/O routines - virtual Int_t SysOpen(const char*, Int_t, UInt_t) { return 0; } - virtual Int_t SysClose(Int_t) { return 0; } - virtual Int_t SysRead(Int_t, void*, Int_t) { return 0; } - virtual Int_t SysWrite(Int_t, const void*, Int_t) { return 0; } - virtual Long64_t SysSeek(Int_t, Long64_t, Int_t) { return 0; } - virtual Int_t SysStat(Int_t, Long_t*, Long64_t*, Long_t*, Long_t*) { return 0; } - virtual Int_t SysSync(Int_t) { return 0; } - - private: - //let the compiler do the job. gcc complains when the following line is activated - //TXMLFile(const TXMLFile &) {} //Files cannot be copied - void operator=(const TXMLFile &); - - public: - TXMLFile(); - TXMLFile(const char* filename, Option_t* option = "read", const char* title = "title", Int_t compression = 1); - virtual ~TXMLFile(); - - virtual void Close(Option_t *option=""); // *MENU* - virtual TKey* CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize); - virtual TKey* CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize); - virtual void DrawMap(const char* ="*",Option_t* ="") {} - virtual void FillBuffer(char* &) {} - virtual void Flush() {} - - virtual Long64_t GetEND() const { return 0; } - virtual Int_t GetErrno() const { return 0; } - virtual void ResetErrno() const {} - - virtual Int_t GetNfree() const { return 0; } - virtual Int_t GetNbytesInfo() const {return 0; } - virtual Int_t GetNbytesFree() const {return 0; } - virtual Long64_t GetSeekFree() const {return 0; } - virtual Long64_t GetSeekInfo() const {return 0; } - virtual Long64_t GetSize() const { return 0; } - virtual TList* GetStreamerInfoList(); - Int_t GetIOVersion() const { return fIOVersion; } - - virtual Bool_t IsOpen() const; - - virtual void MakeFree(Long64_t, Long64_t) {} - virtual void MakeProject(const char *, const char* ="*", Option_t* ="new") {} // *MENU* - virtual void Map() {} // - virtual void Paint(Option_t* ="") {} - virtual void Print(Option_t* ="") const {} - virtual Bool_t ReadBuffer(char*, Int_t) { return kFALSE; } - virtual void ReadFree() {} - virtual Int_t Recover() { return 0; } - virtual Int_t ReOpen(Option_t *mode); - virtual void Seek(Long64_t, ERelativeTo=kBeg) {} - - virtual void SetEND(Long64_t) {} - virtual Int_t Sizeof() const { return 0; } - - virtual void UseCache(Int_t = 10, Int_t = TCache::kDfltPageSize) {} - virtual Bool_t WriteBuffer(const char*, Int_t) { return kFALSE; } - virtual Int_t Write(const char* =0, Int_t=0, Int_t=0) { return 0; } - virtual Int_t Write(const char* =0, Int_t=0, Int_t=0) const { return 0; } - virtual void WriteFree() {} - virtual void WriteHeader() {} - virtual void WriteStreamerInfo(); - - // XML specific functions - - virtual void SetXmlLayout(EXMLLayout layout); - virtual void SetStoreStreamerInfos(Bool_t iConvert = kTRUE); - virtual void SetUsedDtd(Bool_t use = kTRUE); - virtual void SetUseNamespaces(Bool_t iUseNamespaces = kTRUE); - - TXMLEngine* XML() { return fXML; } - - protected: - // functions to store streamer infos - - void StoreStreamerElement(XMLNodePointer_t node, TStreamerElement* elem); - void ReadStreamerElement(XMLNodePointer_t node, TStreamerInfo* info); - - Bool_t ReadFromFile(); - - void SaveToFile(); - - static void ProduceFileNames(const char* filename, TString& fname, TString& dtdname); - - XMLDocPointer_t fDoc; //! - - XMLNodePointer_t fStreamerInfoNode; //! pointer of node with streamer info data - - TXMLEngine* fXML; //! object for interface with xml library - - Int_t fIOVersion; //! indicates format of ROOT xml file - - ClassDef(TXMLFile, 2) //ROOT file in XML format + +protected: + + void InitXmlFile(Bool_t create); + // Interface to basic system I/O routines + virtual Int_t SysOpen(const char*, Int_t, UInt_t) { return 0; } + virtual Int_t SysClose(Int_t) { return 0; } + virtual Int_t SysRead(Int_t, void*, Int_t) { return 0; } + virtual Int_t SysWrite(Int_t, const void*, Int_t) { return 0; } + virtual Long64_t SysSeek(Int_t, Long64_t, Int_t) { return 0; } + virtual Int_t SysStat(Int_t, Long_t*, Long64_t*, Long_t*, Long_t*) { return 0; } + virtual Int_t SysSync(Int_t) { return 0; } + + // Overwrite methods for directory I/O + virtual Long64_t DirCreateEntry(TDirectory*); + virtual Int_t DirReadKeys(TDirectory*); + virtual void DirWriteKeys(TDirectory*); + virtual void DirWriteHeader(TDirectory*); + +private: + //let the compiler do the job. gcc complains when the following line is activated + //TXMLFile(const TXMLFile &) {} //Files cannot be copied + void operator=(const TXMLFile &); + +public: + TXMLFile(); + TXMLFile(const char* filename, Option_t* option = "read", const char* title = "title", Int_t compression = 1); + virtual ~TXMLFile(); + + virtual void Close(Option_t *option=""); // *MENU* + virtual TKey* CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize); + virtual TKey* CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize); + virtual void DrawMap(const char* ="*",Option_t* ="") {} + virtual void FillBuffer(char* &) {} + virtual void Flush() {} + + virtual Long64_t GetEND() const { return 0; } + virtual Int_t GetErrno() const { return 0; } + virtual void ResetErrno() const {} + + virtual Int_t GetNfree() const { return 0; } + virtual Int_t GetNbytesInfo() const {return 0; } + virtual Int_t GetNbytesFree() const {return 0; } + virtual Long64_t GetSeekFree() const {return 0; } + virtual Long64_t GetSeekInfo() const {return 0; } + virtual Long64_t GetSize() const { return 0; } + virtual TList* GetStreamerInfoList(); + Int_t GetIOVersion() const { return fIOVersion; } + + virtual Bool_t IsOpen() const; + + virtual void MakeFree(Long64_t, Long64_t) {} + virtual void MakeProject(const char *, const char* ="*", Option_t* ="new") {} // *MENU* + virtual void Map() {} // + virtual void Paint(Option_t* ="") {} + virtual void Print(Option_t* ="") const {} + virtual Bool_t ReadBuffer(char*, Int_t) { return kFALSE; } + virtual void ReadFree() {} + virtual Int_t Recover() { return 0; } + virtual Int_t ReOpen(Option_t *mode); + virtual void Seek(Long64_t, ERelativeTo=kBeg) {} + + virtual void SetEND(Long64_t) {} + virtual Int_t Sizeof() const { return 0; } + + virtual void UseCache(Int_t = 10, Int_t = TCache::kDfltPageSize) {} + virtual Bool_t WriteBuffer(const char*, Int_t) { return kFALSE; } + virtual Int_t Write(const char* =0, Int_t=0, Int_t=0) { return 0; } + virtual Int_t Write(const char* =0, Int_t=0, Int_t=0) const { return 0; } + virtual void WriteFree() {} + virtual void WriteHeader() {} + virtual void WriteStreamerInfo(); + + // XML specific functions + + virtual void SetXmlLayout(EXMLLayout layout); + virtual void SetStoreStreamerInfos(Bool_t iConvert = kTRUE); + virtual void SetUsedDtd(Bool_t use = kTRUE); + virtual void SetUseNamespaces(Bool_t iUseNamespaces = kTRUE); + + TXMLEngine* XML() { return fXML; } + +protected: + // functions to store streamer infos + + void StoreStreamerElement(XMLNodePointer_t node, TStreamerElement* elem); + void ReadStreamerElement(XMLNodePointer_t node, TStreamerInfo* info); + + Bool_t ReadFromFile(); + Int_t ReadKeysList(TDirectory* dir, XMLNodePointer_t topnode); + TKeyXML* FindDirKey(TDirectory* dir); + TDirectory* FindKeyDir(TDirectory* mother, Long64_t keyid); + void CombineNodesTree(TDirectory* dir, XMLNodePointer_t topnode, Bool_t dolink); + + void SaveToFile(); + + static void ProduceFileNames(const char* filename, TString& fname, TString& dtdname); + + XMLDocPointer_t fDoc; //! + + XMLNodePointer_t fStreamerInfoNode; //! pointer of node with streamer info data + + TXMLEngine* fXML; //! object for interface with xml library + + Int_t fIOVersion; //! indicates format of ROOT xml file + + Long64_t fKeyCounter; //! counter of created keys, used for keys id + +ClassDef(TXMLFile, 2) //ROOT file in XML format }; diff --git a/xml/src/TKeyXML.cxx b/xml/src/TKeyXML.cxx index 0cd49c9350b2048648bd055861a3b3c59a260274..f126889c78231db9c8d471b199e48784930b2d27 100644 --- a/xml/src/TKeyXML.cxx +++ b/xml/src/TKeyXML.cxx @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TKeyXML.cxx,v 1.6 2006/01/25 16:00:11 pcanal Exp $ +// @(#)root/xml:$Name: $:$Id: TKeyXML.cxx,v 1.7 2006/02/01 18:57:41 pcanal Exp $ // Author: Sergey Linev, Rene Brun 10.05.2004 /************************************************************************* @@ -30,15 +30,19 @@ ClassImp(TKeyXML); //______________________________________________________________________________ TKeyXML::TKeyXML() : TKey(), - fKeyNode(0) + fKeyNode(0), + fKeyId(0), + fSubdir(kFALSE) { // default constructor } //______________________________________________________________________________ -TKeyXML::TKeyXML(TDirectory* mother, const TObject* obj, const char* name) : +TKeyXML::TKeyXML(TDirectory* mother, Long64_t keyid, const TObject* obj, const char* name, const char* title) : TKey(mother), - fKeyNode(0) + fKeyNode(0), + fKeyId(keyid), + fSubdir(kFALSE) { // Creates TKeyXML and convert obj data to xml structures @@ -51,26 +55,50 @@ TKeyXML::TKeyXML(TDirectory* mother, const TObject* obj, const char* name) : } else SetName("Noname"); + if (title) SetTitle(title); + + fCycle = GetMotherDir()->AppendKey(this); + + TXMLEngine* xml = XMLEngine(); + if (xml!=0) + fKeyNode = xml->NewChild(0, 0, xmlio::Xmlkey, 0); + + fDatime.Set(); + StoreObject((void*)obj, obj ? obj->IsA() : 0); } //______________________________________________________________________________ -TKeyXML::TKeyXML(TDirectory* mother, const void* obj, const TClass* cl, const char* name) : +TKeyXML::TKeyXML(TDirectory* mother, Long64_t keyid, const void* obj, const TClass* cl, const char* name, const char* title) : TKey(mother), - fKeyNode(0) + fKeyNode(0), + fKeyId(keyid), + fSubdir(kFALSE) { // Creates TKeyXML and convert obj data to xml structures if (name && *name) SetName(name); else SetName(cl ? cl->GetName() : "Noname"); + if (title) SetTitle(title); + + fCycle = GetMotherDir()->AppendKey(this); + + TXMLEngine* xml = XMLEngine(); + if (xml!=0) + fKeyNode = xml->NewChild(0, 0, xmlio::Xmlkey, 0); + + fDatime.Set(); + StoreObject(obj, cl); } //______________________________________________________________________________ -TKeyXML::TKeyXML(TDirectory* mother, XMLNodePointer_t keynode) : +TKeyXML::TKeyXML(TDirectory* mother, Long64_t keyid, XMLNodePointer_t keynode) : TKey(mother), - fKeyNode(keynode) + fKeyNode(keynode), + fKeyId(keyid), + fSubdir(kFALSE) { // Creates TKeyXML and takes ownership over xml node, from which object can be restored @@ -119,17 +147,14 @@ void TKeyXML::Delete(Option_t * /*option*/) } //______________________________________________________________________________ -void TKeyXML::StoreObject(const void* obj, const TClass* cl) +void TKeyXML::StoreKeyAttributes() { - // convert object to xml structure and keep this structure in key + // Stores keys attributes in key node - TXMLFile* f = (TXMLFile*) GetFile(); TXMLEngine* xml = XMLEngine(); - if ((f==0) || (xml==0)) return; - - fCycle = GetMotherDir()->AppendKey(this); + TXMLFile* f = (TXMLFile*) GetFile(); + if ((f==0) || (xml==0) || (fKeyNode==0)) return; - fKeyNode = xml->NewChild(0, 0, xmlio::Xmlkey, 0); xml->NewAttr(fKeyNode, 0, xmlio::Name, GetName()); xml->NewIntAttr(fKeyNode, xmlio::Cycle, fCycle); @@ -137,10 +162,21 @@ void TKeyXML::StoreObject(const void* obj, const TClass* cl) if (f->GetIOVersion()>1) { if (strlen(GetTitle())>0) xml->NewAttr(fKeyNode, 0, xmlio::Title, GetTitle()); - fDatime.Set(); xml->NewAttr(fKeyNode, 0, xmlio::CreateTm, fDatime.AsSQLString()); } +} + +//______________________________________________________________________________ +void TKeyXML::StoreObject(const void* obj, const TClass* cl) +{ + // convert object to xml structure and keep this structure in key + TXMLFile* f = (TXMLFile*) GetFile(); + TXMLEngine* xml = XMLEngine(); + if ((f==0) || (xml==0) || (fKeyNode==0)) return; + + StoreKeyAttributes(); + TBufferXML buffer(TBuffer::kWrite, f); if (f->GetIOVersion()==1) buffer.SetBit(TBuffer::kCannotHandleMemberWiseStreaming, kFALSE); @@ -148,13 +184,49 @@ void TKeyXML::StoreObject(const void* obj, const TClass* cl) XMLNodePointer_t node = buffer.XmlWriteAny(obj, cl); if (node!=0) - xml->AddChild(fKeyNode, node); - + xml->AddChildFirst(fKeyNode, node); + buffer.XmlWriteBlock(fKeyNode); if (cl) fClassName = cl->GetName(); } +//______________________________________________________________________________ +void TKeyXML::UpdateAttributes() +{ + // update key attributes in key node + + TXMLEngine* xml = XMLEngine(); + if ((xml==0) || (fKeyNode==0)) return; + + xml->FreeAllAttr(fKeyNode); + + StoreKeyAttributes(); +} + +//______________________________________________________________________________ +void TKeyXML::UpdateObject(TObject* obj) +{ + // updates object, stored in the node + // Used for TDirectory data update + + TXMLFile* f = (TXMLFile*) GetFile(); + TXMLEngine* xml = XMLEngine(); + if ((f==0) || (xml==0) || (obj==0) || (fKeyNode==0)) return; + + XMLNodePointer_t objnode = xml->GetChild(fKeyNode); + xml->SkipEmpty(objnode); + + if (objnode==0) return; + + xml->UnlinkNode(objnode); + xml->FreeNode(objnode); + + xml->FreeAllAttr(fKeyNode); + + StoreObject(obj, obj->IsA()); +} + //______________________________________________________________________________ Int_t TKeyXML::Read(TObject* tobj) { @@ -184,9 +256,12 @@ TObject* TKeyXML::ReadObj() TDirectory *dir = (TDirectory*) tobj; dir->SetName(GetName()); dir->SetTitle(GetTitle()); - dir->ReadKeys(); + dir->SetSeekDir(GetKeyId()); + // set mother before reading keys dir->SetMother(fMotherDir); + dir->ReadKeys(); fMotherDir->Append(dir); + fSubdir = kTRUE; } } diff --git a/xml/src/TXMLEngine.cxx b/xml/src/TXMLEngine.cxx index 79eea149798d038b04f4addc38dcb8fb728c6f59..789aaeb52bd3b029a94fa062a004eef7315eec67 100644 --- a/xml/src/TXMLEngine.cxx +++ b/xml/src/TXMLEngine.cxx @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TXMLEngine.cxx,v 1.18 2006/05/09 10:24:27 brun Exp $ +// @(#)root/xml:$Name: $:$Id: TXMLEngine.cxx,v 1.19 2006/05/30 12:59:30 brun Exp $ // Author: Sergey Linev 10.05.2004 /************************************************************************* @@ -475,6 +475,23 @@ void TXMLEngine::FreeAttr(XMLNodePointer_t xmlnode, const char* name) } } +//______________________________________________________________________________ +void TXMLEngine::FreeAllAttr(XMLNodePointer_t xmlnode) +{ + // Free all attributes of the node + if (xmlnode==0) return; + + SXmlNode_t* node = (SXmlNode_t*) xmlnode; + SXmlAttr_t* attr = node->fAttr; + while (attr!=0) { + SXmlAttr_t* next = attr->fNext; + free(attr); + attr = next; + } + node->fAttr = 0; +} + + //______________________________________________________________________________ XMLAttrPointer_t TXMLEngine::GetFirstAttr(XMLNodePointer_t xmlnode) { @@ -623,6 +640,23 @@ void TXMLEngine::AddChild(XMLNodePointer_t parent, XMLNodePointer_t child) } } +//______________________________________________________________________________ +void TXMLEngine::AddChildFirst(XMLNodePointer_t parent, XMLNodePointer_t child) +{ + // add node as first child + + if ((parent==0) || (child==0)) return; + SXmlNode_t* pnode = (SXmlNode_t*) parent; + SXmlNode_t* cnode = (SXmlNode_t*) child; + cnode->fParent = pnode; + + cnode->fNext = pnode->fChild; + pnode->fChild = cnode; + + if (pnode->fLastChild==0) pnode->fLastChild = cnode; +} + + //______________________________________________________________________________ void TXMLEngine::UnlinkNode(XMLNodePointer_t xmlnode) { diff --git a/xml/src/TXMLFile.cxx b/xml/src/TXMLFile.cxx index 6170f0fca048a5de033fbe26dfef53a8d7d8839f..fbc98ad22085b68df82e887657841b1631144f71 100644 --- a/xml/src/TXMLFile.cxx +++ b/xml/src/TXMLFile.cxx @@ -1,4 +1,4 @@ -// @(#)root/xml:$Name: $:$Id: TXMLFile.cxx,v 1.18 2006/02/01 18:57:41 pcanal Exp $ +// @(#)root/xml:$Name: $:$Id: TXMLFile.cxx,v 1.19 2006/03/20 21:43:44 pcanal Exp $ // Author: Sergey Linev, Rene Brun 10.05.2004 /************************************************************************* @@ -96,9 +96,12 @@ TXMLFile::TXMLFile() : TXMLSetup(), fDoc(0), fStreamerInfoNode(0), - fXML(0) + fXML(0), + fKeyCounter(0) { // default TXMLFile constructor + + SetBit(kBinaryFile, kFALSE); } @@ -107,7 +110,9 @@ TXMLFile::TXMLFile(const char* filename, Option_t* option, const char* title, In TFile(), TXMLSetup(), fDoc(0), - fStreamerInfoNode(0) + fStreamerInfoNode(0), + fXML(0), + fKeyCounter(0) { // Open or creates local XML file with name filename. // It is recommended to specify filename as "<file>.xml". The suffix ".xml" @@ -162,6 +167,7 @@ TXMLFile::TXMLFile(const char* filename, Option_t* option, const char* title, In fProcessIDs = 0; fNProcessIDs= 0; fIOVersion = TXMLFile::Class_Version(); + SetBit(kBinaryFile, kFALSE); fOption = option; fOption.ToUpper(); @@ -327,7 +333,6 @@ void TXMLFile::Close(Option_t *option) fClassIndex = 0; } - if (fStreamerInfoNode) { fXML->FreeNode(fStreamerInfoNode); fStreamerInfoNode = 0; @@ -436,7 +441,7 @@ TKey* TXMLFile::CreateKey(TDirectory* mother, const TObject* obj, const char* na { // create XML key, which will store object in xml structures - return new TKeyXML(mother, obj, name); + return new TKeyXML(mother, ++fKeyCounter, obj, name); } //______________________________________________________________________________ @@ -444,7 +449,7 @@ TKey* TXMLFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, { // create XML key, which will store object in xml structures - return new TKeyXML(mother, obj, cl, name); + return new TKeyXML(mother, ++fKeyCounter, obj, cl, name); } //______________________________________________________________________________ @@ -517,11 +522,14 @@ void TXMLFile::SaveToFile() TString fname, dtdname; ProduceFileNames(fRealName, fname, dtdname); +/* TIter iter(GetListOfKeys()); TKeyXML* key = 0; - while ((key=(TKeyXML*)iter()) !=0) fXML->AddChild(fRootNode, key->KeyNode()); +*/ + + CombineNodesTree(this, fRootNode, kTRUE); WriteStreamerInfo(); @@ -532,14 +540,37 @@ void TXMLFile::SaveToFile() fXML->SaveDoc(fDoc, fname, layout); - iter.Reset(); +/* iter.Reset(); while ((key=(TKeyXML*)iter()) !=0) fXML->UnlinkNode(key->KeyNode()); +*/ + CombineNodesTree(this, fRootNode, kFALSE); if (fStreamerInfoNode) fXML->UnlinkNode(fStreamerInfoNode); } +//______________________________________________________________________________ +void TXMLFile::CombineNodesTree(TDirectory* dir, XMLNodePointer_t topnode, Bool_t dolink) +{ + // Connect/disconnect all file nodes to single tree before/after saving + + if (dir==0) return; + + TIter iter(dir->GetListOfKeys()); + TKeyXML* key = 0; + + while ((key=(TKeyXML*)iter()) !=0) { + if (dolink) + fXML->AddChild(topnode, key->KeyNode()); + else + fXML->UnlinkNode(key->KeyNode()); + if (key->IsSubdir()) + CombineNodesTree(FindKeyDir(dir, key->GetKeyId()), key->KeyNode(), dolink); + } +} + + //______________________________________________________________________________ Bool_t TXMLFile::ReadFromFile() { @@ -602,6 +633,9 @@ Bool_t TXMLFile::ReadFromFile() return kFALSE; } + ReadKeysList(this, fRootNode); + +/* XMLNodePointer_t keynode = fXML->GetChild(fRootNode); fXML->SkipEmpty(keynode); while (keynode!=0) { @@ -610,7 +644,7 @@ Bool_t TXMLFile::ReadFromFile() if (strcmp(xmlio::Xmlkey, fXML->GetNodeName(keynode))==0) { fXML->UnlinkNode(keynode); - TKeyXML* key = new TKeyXML(this, keynode); + TKeyXML* key = new TKeyXML(this, ++fKeyCounter, keynode); AppendKey(key); if (gDebug>2) @@ -620,12 +654,46 @@ Bool_t TXMLFile::ReadFromFile() keynode = next; fXML->SkipEmpty(keynode); } +*/ fXML->CleanNode(fRootNode); return kTRUE; } +//______________________________________________________________________________ +Int_t TXMLFile::ReadKeysList(TDirectory* dir, XMLNodePointer_t topnode) +{ + // Read list of keys for directory + + if ((dir==0) || (topnode==0)) return 0; + + Int_t nkeys = 0; + + XMLNodePointer_t keynode = fXML->GetChild(topnode); + fXML->SkipEmpty(keynode); + while (keynode!=0) { + XMLNodePointer_t next = fXML->GetNext(keynode); + + if (strcmp(xmlio::Xmlkey, fXML->GetNodeName(keynode))==0) { + fXML->UnlinkNode(keynode); + + TKeyXML* key = new TKeyXML(dir, ++fKeyCounter, keynode); + dir->AppendKey(key); + + if (gDebug>2) + Info("ReadKeysList","Add key %s from node %s",key->GetName(), fXML->GetNodeName(keynode)); + + nkeys++; + } + + keynode = next; + fXML->SkipEmpty(keynode); + } + + return nkeys; +} + //______________________________________________________________________________ void TXMLFile::WriteStreamerInfo() { @@ -917,3 +985,92 @@ void TXMLFile::SetUseNamespaces(Bool_t iUseNamespaces) if (IsWritable() && (GetListOfKeys()->GetSize()==0)) TXMLSetup::SetUseNamespaces(iUseNamespaces); } + +//______________________________________________________________________________ +Long64_t TXMLFile::DirCreateEntry(TDirectory* dir) +{ + // Create key for directory entry in the key + + TDirectory* mother = dir->GetMotherDir(); + if (mother==0) mother = this; + + TKeyXML* key = new TKeyXML(mother, ++fKeyCounter, dir, dir->GetName(), dir->GetTitle()); + + key->SetSubir(); + + return key->GetKeyId(); +} + +//______________________________________________________________________________ +TKeyXML* TXMLFile::FindDirKey(TDirectory* dir) +{ + // Serach for key which correspond to direcory dir + + TDirectory* motherdir = dir->GetMotherDir(); + if (motherdir==0) motherdir = this; + + TIter next(motherdir->GetListOfKeys()); + TObject* obj = 0; + + while ((obj = next())!=0) { + TKeyXML* key = dynamic_cast<TKeyXML*> (obj); + + if (key!=0) + if (key->GetKeyId()==dir->GetSeekDir()) return key; + } + + return 0; +} + + +//______________________________________________________________________________ +TDirectory* TXMLFile::FindKeyDir(TDirectory* motherdir, Long64_t keyid) +{ + if (motherdir==0) motherdir = this; + + TIter next(motherdir->GetList()); + TObject* obj = 0; + + while ((obj = next())!=0) { + TDirectory* dir = dynamic_cast<TDirectory*> (obj); + if (dir!=0) + if (dir->GetSeekDir()==keyid) return dir; + } + + return 0; + +} + +//______________________________________________________________________________ +Int_t TXMLFile::DirReadKeys(TDirectory* dir) +{ + // Read keys for directory + // Make sence only once, while next time no new subnodes will be created + + TKeyXML* key = FindDirKey(dir); + if (key==0) return 0; + + return ReadKeysList(dir, key->KeyNode()); +} + +//______________________________________________________________________________ +void TXMLFile::DirWriteKeys(TDirectory*) +{ + // Update key attributes + + TIter next(GetListOfKeys()); + TObject* obj = 0; + + while ((obj = next())!=0) { + TKeyXML* key = dynamic_cast<TKeyXML*> (obj); + if (key!=0) key->UpdateAttributes(); + } +} + +//______________________________________________________________________________ +void TXMLFile::DirWriteHeader(TDirectory* dir) +{ + TKeyXML* key = FindDirKey(dir); + if (key!=0) + key->UpdateObject(dir); +}