#include "TSQLFile.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TList.h"
#include "TBrowser.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TList.h"
#include "TArrayC.h"
#include "TVirtualStreamerInfo.h"
#include "TStreamerElement.h"
#include "TProcessID.h"
#include "TError.h"
#include "TClass.h"
#include "TSQLServer.h"
#include "TSQLTableInfo.h"
#include "TSQLColumnInfo.h"
#include "TSQLStatement.h"
#include "TSQLResult.h"
#include "TSQLRow.h"
#include "TBufferSQL2.h"
#include "TSQLStructure.h"
#include "TKeySQL.h"
#include "TSQLClassInfo.h"
#include "TSQLObjectData.h"
#include "Riostream.h"
ClassImp(TSQLFile);
const char* mysql_BasicTypes[20] = {
"VARCHAR(255)",     
"TINYINT UNSIGNED", 
"SMALLINT",         
"INT",              
"BIGINT",           
"FLOAT",            
"INT",              
"VARCHAR(255)",     
"DOUBLE",           
"DOUBLE",           
"",                 
"TINYINT UNSIGNED", 
"SMALLINT UNSIGNED",
"INT UNSIGNED",     
"BIGINT UNSIGNED",  
"INT UNSIGNED",     
"BIGINT",           
"BIGINT UNSIGNED",  
"BOOL",             
""
};
const char* mysql_OtherTypes[13] = {
"VARCHAR(255)",     
"255",              
"TEXT",             
"DATETIME",         
"`",                
"dir:id",           
"key:id",           
"obj:id",           
"raw:id",           
"str:id",           
":",                
"\"",               
"InnoDB"            
};
const char* oracle_BasicTypes[20] = {
"VARCHAR(255)",     
"INT",              
"INT",              
"INT",              
"INT",              
"FLOAT",            
"INT",              
"VARCHAR(255)",     
"DOUBLE PRECISION", 
"DOUBLE PRECISION", 
"",                 
"INT",              
"INT",              
"INT",              
"INT",              
"INT",              
"INT",              
"INT",              
"INT",              
""
};
const char* oracle_OtherTypes[13] = {
"VARCHAR(1000)",    
"1000",             
"VARCHAR(4000)",    
"VARCHAR(50)",      
"\"",               
"dir:id",           
"key:id",           
"obj:id",           
"raw:id",           
"str:id",           
":",                
"'",                
""                  
};
TSQLFile::TSQLFile() :
   TFile(),
   fSQL(0),
   fSQLClassInfos(0),
   fUseSuffixes(kTRUE),
   fSQLIOversion(1),
   fArrayLimit(20),
   fCanChangeConfig(kFALSE),
   fTablesType(),
   fUseTransactions(0),
   fUseIndexes(0),
   fModifyCounter(0),
   fQuerisCounter(0),
   fBasicTypes(0),
   fOtherTypes(0),
   fUserName(),
   fLogFile(0),
   fIdsTableExists(kFALSE)
{
   
   SetBit(kBinaryFile, kFALSE);
}
TSQLFile::TSQLFile(const char* dbname, Option_t* option, const char* user, const char* pass) :
   TFile(),
   fSQL(0),
   fSQLClassInfos(0),
   fUseSuffixes(kTRUE),
   fSQLIOversion(1),
   fArrayLimit(20),
   fCanChangeConfig(kFALSE),
   fTablesType(),
   fUseTransactions(0),
   fUseIndexes(0),
   fModifyCounter(0),
   fQuerisCounter(0),
   fBasicTypes(mysql_BasicTypes),
   fOtherTypes(mysql_OtherTypes),
   fUserName(user),
   fLogFile(0),
   fIdsTableExists(kFALSE)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   if (!gROOT)
      ::Fatal("TFile::TFile", "ROOT system not initialized");
   gDirectory = 0;
   SetName(dbname);
   SetTitle("TFile interface to SQL DB");
   TDirectoryFile::Build();
   fFile = this;
   if (strstr(dbname,"oracle://")!=0) {
      fBasicTypes = oracle_BasicTypes;
      fOtherTypes = oracle_OtherTypes;
   }
   fArrayLimit = 20;
   fTablesType = SQLDefaultTableType();
   fUseIndexes = 1;
   fUseTransactions = kTransactionsAuto;
   fD          = -1;
   fFile       = this;
   fFree       = 0;
   fVersion    = gROOT->GetVersionInt();  
   fUnits      = 4;
   fOption     = option;
   SetCompressionLevel(5);
   fWritten    = 0;
   fSumBuffer  = 0;
   fSum2Buffer = 0;
   fBytesRead  = 0;
   fBytesWrite = 0;
   fClassIndex = 0;
   fSeekInfo   = 0;
   fNbytesInfo = 0;
   fProcessIDs = 0;
   fNProcessIDs= 0;
   fSeekDir    = sqlio::Ids_RootDir;
   SetBit(kBinaryFile, kFALSE);
   fOption = option;
   fOption.ToUpper();
   if (fOption == "NEW") fOption = "CREATE";
   Bool_t breaklock = kFALSE;
   if (fOption == "BREAKLOCK") { breaklock = kTRUE; fOption = "UPDATE"; }
   Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
   Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
   Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
   Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
   if (!create && !recreate && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }
   if (!dbname || !strlen(dbname)) {
      Error("TSQLFile", "Database not specified");
      goto zombie;
   }
   gROOT->cd();
   fSQL = TSQLServer::Connect(dbname, user, pass);
   if (fSQL==0) {
      Error("TSQLFile", "Cannot connect to DB %s", dbname);
      goto zombie;
   }
   if (recreate) {
      if (IsTablesExists())
         if (!IsWriteAccess()) {
            Error("TSQLFile", "no write permission, DB %s locked", dbname);
            goto zombie;
         }
      SQLDeleteAllTables();
      recreate = kFALSE;
      create   = kTRUE;
      fOption  = "CREATE";
   }
   if (create && IsTablesExists()) {
      Error("TSQLFile", "DB tables already exists");
      goto zombie;
   }
   if (update) {
      if (!IsTablesExists()) {
         update = kFALSE;
         create = kTRUE;
      }
      if (update && !breaklock && !IsWriteAccess()) {
         Error("TSQLFile", "no write permission, DB %s locked", dbname);
         goto zombie;
      }
   }
   if (read) {
      if (!IsTablesExists()) {
         Error("TSQLFile", "DB %s tables not exist", dbname);
         goto zombie;
      }
      if (!IsReadAccess()) {
         Error("TSQLFile", "no read permission for DB %s tables", dbname);
         goto zombie;
      }
   }
   fRealName = dbname;
   if (create || update) {
      SetWritable(kTRUE);
      if (update) SetLocking(kLockBusy);
   } else
      SetWritable(kFALSE);
   
   
   
   fCanChangeConfig = create;
   InitSqlDatabase(create);
   return;
zombie:
   delete fSQL;
   fSQL = 0;
   MakeZombie();
   gDirectory = gROOT;
}
void TSQLFile::StartLogFile(const char* fname)
{
   
   StopLogFile();
   fLogFile = new std::ofstream(fname);
}
void TSQLFile::StopLogFile()
{
   
   if (fLogFile!=0) {
      delete fLogFile;
      fLogFile = 0;
   }
}
Bool_t TSQLFile::IsMySQL() const
{
   
   if (fSQL==0) return kFALSE;
   return strcmp(fSQL->ClassName(),"TMySQLServer")==0;
}
Bool_t TSQLFile::IsOracle() const
{
   
   if (fSQL==0) return kFALSE;
   return strcmp(fSQL->ClassName(),"TOracleServer")==0;
}
Bool_t TSQLFile::IsODBC() const
{
   
   if (fSQL==0) return kFALSE;
   return strcmp(fSQL->ClassName(),"TODBCServer")==0;
}
void TSQLFile::SetUseSuffixes(Bool_t on)
{
   
   
   if (!fCanChangeConfig)
      Error("SetUseSuffixes", "Configurations already cannot be changed");
   else
      fUseSuffixes = on;
}
void TSQLFile::SetArrayLimit(Int_t limit)
{
   
   
   
   
   
   
   if (!fCanChangeConfig)
      Error("SetArrayLimit", "Configurations already cannot be changed");
   else
      fArrayLimit = limit;
}
void TSQLFile::SetTablesType(const char* tables_type)
{
   
   
   
   
   if (!fCanChangeConfig)
      Error("SetTablesType", "Configurations already cannot be changed");
   else
      fTablesType = tables_type;
}
void TSQLFile::SetUseTransactions(Int_t mode)
{
   
   
   
   
   
   
   
   
   fUseTransactions = mode;
}
Bool_t TSQLFile::StartTransaction()
{
   
   
   
   
   
   
   
   
   
   if (GetUseTransactions()!=kTransactionsUser) {
      Error("SQLStartTransaction","Only allowed when SetUseTransactions(kUserTransactions) was configured");
      return kFALSE;
   }
   return SQLStartTransaction();
}
Bool_t TSQLFile::Commit()
{
   
   
   if (GetUseTransactions()!=kTransactionsUser) {
      Error("SQLCommit","Only allowed when SetUseTransactions(kUserTransactions) was configured");
      return kFALSE;
   }
   return SQLCommit();
}
Bool_t TSQLFile::Rollback()
{
   
   
   if (GetUseTransactions()!=kTransactionsUser) {
      Error("SQLRollback","Only allowed when SetUseTransactions(kUserTransactions) was configured");
      return kFALSE;
   }
   return SQLRollback();
}
void TSQLFile::SetUseIndexes(Int_t use_type)
{
   
   
   
   
   
   
   
   
   if (!fCanChangeConfig)
      Error("SetUseIndexes", "Configurations already cannot be changed");
   else
      fUseIndexes = use_type;
}
const char* TSQLFile::GetDataBaseName() const
{
   
   
   if (IsOracle()) return 0;
   const char* name = strrchr(GetName(),'/');
   if (name==0) return 0;
   return name + 1;
}
void TSQLFile::Close(Option_t *option)
{
   
   
   if (!IsOpen()) return;
   TString opt = option;
   if (opt.Length()>0)
      opt.ToLower();
   if (IsWritable()) {
      SaveToDatabase();
      SetLocking(kLockFree);
   }
   fWritable = kFALSE;
   if (fClassIndex) {
      delete fClassIndex;
      fClassIndex = 0;
   }
   TDirectory *cursav = gDirectory;
   cd();
   if (cursav == this || cursav->GetFile() == this) {
      cursav = 0;
   }
   
   TDirectoryFile::Close();
   cd();      
   if (cursav)
      cursav->cd();
   else {
      gFile      = 0;
      gDirectory = gROOT;
   }
   
   TList pidDeleted;
   TIter next(fProcessIDs);
   TProcessID *pid;
   while ((pid = (TProcessID*)next())) {
      if (!pid->DecrementCount()) {
         if (pid != TProcessID::GetSessionProcessID()) pidDeleted.Add(pid);
      } else if(opt.Contains("r")) {
         pid->Clear();
      }
   }
   pidDeleted.Delete();
   gROOT->GetListOfFiles()->Remove(this);
}
TSQLFile::~TSQLFile()
{
   
   Close();
   if (fSQLClassInfos!=0) {
      fSQLClassInfos->Delete();
      delete fSQLClassInfos;
   }
   StopLogFile();
   if (fSQL!=0) {
      delete fSQL;
      fSQL = 0;
   }
}
void TSQLFile::operator=(const TSQLFile &)
{
   
}
Bool_t TSQLFile::IsOpen() const
{
   
   return fSQL != 0;
}
Int_t TSQLFile::ReOpen(Option_t* mode)
{
   
   
   cd();
   TString opt = mode;
   opt.ToUpper();
   if (opt != "READ" && opt != "UPDATE") {
      Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
      return 1;
   }
   if (opt == fOption || (opt == "UPDATE" && fOption == "CREATE"))
      return 1;
   if (opt == "READ") {
      
      if (IsOpen() && IsWritable()) {
         SaveToDatabase();
         SetLocking(kLockFree);
      }
      fOption = opt;
      SetWritable(kFALSE);
   } else {
      
      if (!IsWriteAccess()) {
         Error("ReOpen","Tables are locked, no write access");
         return 1;
      }
      fOption = opt;
      SetWritable(kTRUE);
      SetLocking(kLockBusy);
   }
   return 0;
}
TKey* TSQLFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t )
{
   
   return new TKeySQL(mother, obj, name);
}
TKey* TSQLFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t )
{
   
   return new TKeySQL(mother, obj, cl, name);
}
void TSQLFile::WriteHeader()
{
   
   WriteSpecialObject(sqlio::Ids_TSQLFile, this, GetName(), GetTitle());
}
void TSQLFile::WriteStreamerInfo()
{
   
   
   
   if (!IsTablesExists()) return;
   if (gDebug>1)
      Info("WriteStreamerInfo","Saving streamer infos to database");
   TList list;
   TIter iter(gROOT->GetListOfStreamerInfo());
   TVirtualStreamerInfo* info = 0;
   while ((info = (TVirtualStreamerInfo*) iter()) !=0 ) {
      Int_t uid = info->GetNumber();
      if (fClassIndex->fArray[uid]) {
         if (gDebug>1) Info("WriteStreamerInfo","Add %s",info->GetName());
         list.Add(info);
      }
   }
   if (list.GetSize()==0) return;
   fClassIndex->fArray[0] = 2; 
   WriteSpecialObject(sqlio::Ids_StreamerInfos, &list, "StreamerInfo", "StreamerInfos of this file");
   fClassIndex->fArray[0] = 0; 
}
Bool_t TSQLFile::WriteSpecialObject(Long64_t keyid, TObject* obj, const char* name, const char* title)
{
   DeleteKeyFromDB(keyid);
   if (obj==0) return kTRUE;
   Long64_t objid = StoreObjectInTables(keyid, obj, obj->IsA());
   if (objid>0) {
      TDatime now;
      TKeySQL* key = new TKeySQL(this, keyid, objid,
                                 name, title,
                                 now.AsSQLString(), 1, obj->ClassName());
      WriteKeyData(key);
      delete key;
   }
   return (objid>0);
}
TObject* TSQLFile::ReadSpecialObject(Long64_t keyid, TObject* obj)
{
   
   TKeySQL* key = 0;
   StreamKeysForDirectory(this, kFALSE, keyid, &key);
   if (key==0) return obj;
   TBufferSQL2 buffer(TBuffer::kRead, this);
   TClass* cl = 0;
   void* res = buffer.SqlReadAny(key->GetDBKeyId(), key->GetDBObjId(), &cl, obj);
   if ((cl==TSQLFile::Class()) && (res!=0) && (obj==this)) {
      
      SetTitle(key->GetTitle());
   }
   delete key;
   return (TObject*) res;
}
TList* TSQLFile::GetStreamerInfoList()
{
   
   
   
   if (gDebug>1)
      Info("GetStreamerInfoList","Start reading of streamer infos");
   TObject* obj = ReadSpecialObject(sqlio::Ids_StreamerInfos);
   TList* list = dynamic_cast<TList*> (obj);
   if (list==0) { delete obj; list = new TList; }
   return list;
}
void TSQLFile::SaveToDatabase()
{
   
   
   if (fSQL==0) return;
   WriteStreamerInfo();
   WriteHeader();
}
Int_t TSQLFile::StreamKeysForDirectory(TDirectory* dir, Bool_t doupdate, Long64_t specialkeyid, TKeySQL** specialkey)
{
   
   
   
   if (dir==0) return -1;
   const char* quote = SQLIdentifierQuote();
   Long64_t dirid = dir->GetSeekDir();
   TString sqlcmd;
   sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s=%lld",
               quote, sqlio::KeysTable, quote,
               quote, SQLDirIdColumn(), quote, dirid);
   if (specialkeyid>=0) {
      TString buf;
      buf.Form(" AND %s%s%s=%lld", quote, SQLKeyIdColumn(), quote, specialkeyid);
      sqlcmd += buf;
   }
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
   if (res==0) return -1;
   Int_t nkeys = 0;
   TSQLRow* row = 0;
   while ((row = res->Next()) != 0) {
      nkeys++;
      Long64_t keyid = sqlio::atol64((*row)[0]);
      
      Long64_t objid = sqlio::atol64((*row)[2]);
      const char* keyname = (*row)[3];
      const char* keytitle = (*row)[4];
      const char* keydatime = (*row)[5];
      Int_t cycle = atoi((*row)[6]);
      const char* classname = (*row)[7];
      if (gDebug>4)
        cout << "  Reading keyid = " << keyid << " name = " << keyname << endl;
      if ((keyid>=sqlio::Ids_FirstKey) || (keyid==specialkeyid))
         if (doupdate) {
            TKeySQL* key = FindSQLKey(dir, keyid);
            if (key==0) {
               Error("StreamKeysForDirectory","Key with id %d not exist in list", keyid);
               nkeys = -1; 
            } else
            if (key->IsKeyModified(keyname, keytitle, keydatime, cycle, classname))
               UpdateKeyData(key);
         } else {
            TKeySQL* key = new TKeySQL(dir, keyid, objid,
                                       keyname, keytitle,
                                       keydatime, cycle, classname);
            if (specialkey!=0)
               { *specialkey = key; nkeys = 1; }
            else
               dir->GetListOfKeys()->Add(key);
         }
      delete row;
   }
   delete res;
   if (gDebug>4) {
      Info("StreamKeysForDirectory","dir = %s numread = %d",dir->GetName(), nkeys);
      dir->GetListOfKeys()->Print("*");
   }
   return nkeys;
}
void TSQLFile::InitSqlDatabase(Bool_t create)
{
   
   
   Int_t len = gROOT->GetListOfStreamerInfo()->GetSize()+1;
   if (len<5000) len = 5000;
   fClassIndex = new TArrayC(len);
   fClassIndex->Reset(0);
   if (!create) {
      Bool_t ok = ReadConfigurations();
      
      if (ok) {
         ReadSQLClassInfos();
         ReadStreamerInfo();
         ok = (ReadSpecialObject(sqlio::Ids_TSQLFile, this) != 0);
      }
      
      if (ok)
         ok = StreamKeysForDirectory(this, kFALSE)>=0;
      if (!ok) {
         Error("InitSqlDatabase", "Cannot detect proper tabled in database. Close.");
         Close();
         delete fSQL;
         fSQL = 0;
         MakeZombie();
         gDirectory = gROOT;
         return;
      }
   }
   gROOT->GetListOfFiles()->Add(this);
   cd();
   fNProcessIDs = 0;
   TKey* key = 0;
   TIter iter(fKeys);
   while ((key = (TKey*)iter())!=0) {
      if (!strcmp(key->GetClassName(),"TProcessID")) fNProcessIDs++;
   }
   fProcessIDs = new TObjArray(fNProcessIDs+1);
}
Bool_t TSQLFile::ReadConfigurations()
{
   
   const char* quote = SQLIdentifierQuote();
   TString sqlcmd;
   sqlcmd.Form("SELECT * FROM %s%s%s",
               quote, sqlio::ConfigTable, quote);
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
   if (res==0) return kFALSE;
   
   fSQLIOversion = 0;
   Int_t lock = 0;
   #define ReadIntCfg(name, target)                        \
     if ((field.CompareTo(name, TString::kIgnoreCase)==0)) \
        target = value.Atoi(); else
   #define ReadBoolCfg(name, target)                        \
     if ((field.CompareTo(name, TString::kIgnoreCase)==0))  \
        target = value.CompareTo(sqlio::True, TString::kIgnoreCase)==0; else
   #define ReadStrCfg(name, target)                         \
     if ((field.CompareTo(name, TString::kIgnoreCase)==0))  \
        target = value; else
   TSQLRow* row = 0;
   while ((row = res->Next()) != 0) {
      TString field = row->GetField(0);
      TString value = row->GetField(1);
      delete row;
      ReadIntCfg(sqlio::cfg_Version, fSQLIOversion)
      ReadBoolCfg(sqlio::cfg_UseSufixes, fUseSuffixes)
      ReadIntCfg(sqlio::cfg_ArrayLimit, fArrayLimit)
      ReadStrCfg(sqlio::cfg_TablesType, fTablesType)
      ReadIntCfg(sqlio::cfg_UseTransactions, fUseTransactions)
      ReadIntCfg(sqlio::cfg_UseIndexes, fUseIndexes)
      ReadIntCfg(sqlio::cfg_ModifyCounter, fModifyCounter)
      ReadIntCfg(sqlio::cfg_LockingMode, lock)
      {
         Error("ReadConfigurations","Invalid configuration field %s", field.Data());
         fSQLIOversion = 0;
         break;
      }
   }
   delete res;
   return (fSQLIOversion>0);
}
void TSQLFile::CreateBasicTables()
{
   
   
   
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   const char* vquote = SQLValueQuote();
   if (SQLTestTable(sqlio::ConfigTable)) {
      sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::ConfigTable, quote);
      SQLQuery(sqlcmd.Data());
   }
   sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s)",
               quote, sqlio::ConfigTable, quote,
               quote, sqlio::CT_Field, quote, SQLSmallTextType(),
               quote, sqlio::CT_Value, quote, SQLSmallTextType());
   if ((fTablesType.Length()>0) && IsMySQL()) {
      sqlcmd +=" TYPE=";
      sqlcmd += fTablesType;
   }
   SQLQuery(sqlcmd.Data());
   #define WrintCfg(name, type, value)                              \
   {                                                                \
      sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s%s%s, %s"type"%s)", \
                  quote, sqlio::ConfigTable, quote,                 \
                  vquote, name, vquote,                             \
                  vquote, value, vquote);                           \
      SQLQuery(sqlcmd.Data());                                      \
   }
   WrintCfg(sqlio::cfg_Version, "%d", fSQLIOversion);
   WrintCfg(sqlio::cfg_UseSufixes, "%s", fUseSuffixes ? sqlio::True : sqlio::False);
   WrintCfg(sqlio::cfg_ArrayLimit, "%d", fArrayLimit);
   WrintCfg(sqlio::cfg_TablesType, "%s", fTablesType.Data());
   WrintCfg(sqlio::cfg_UseTransactions, "%d", fUseTransactions);
   WrintCfg(sqlio::cfg_UseIndexes, "%d", fUseIndexes);
   WrintCfg(sqlio::cfg_ModifyCounter, "%d", fModifyCounter);
   WrintCfg(sqlio::cfg_LockingMode, "%d", kLockBusy);
   
   fCanChangeConfig = kFALSE;
   if (SQLTestTable(sqlio::KeysTable)) {
      sqlcmd.Form("DROP TABLE %s%s%s", quote, sqlio::KeysTable, quote);
      SQLQuery(sqlcmd.Data());
   }
   sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s)",
               quote, sqlio::KeysTable, quote,
               quote, SQLKeyIdColumn(), quote, SQLIntType(),
               quote, SQLDirIdColumn(), quote, SQLIntType(),
               quote, SQLObjectIdColumn(), quote, SQLIntType(),
               quote, sqlio::KT_Name, quote, SQLSmallTextType(),
               quote, sqlio::KT_Title, quote, SQLSmallTextType(),
               quote, sqlio::KT_Datetime, quote, SQLDatetimeType(),
               quote, sqlio::KT_Cycle, quote, SQLIntType(),
               quote, sqlio::KT_Class, quote, SQLSmallTextType());
   if ((fTablesType.Length()>0) && IsMySQL()) {
      sqlcmd +=" TYPE=";
      sqlcmd += fTablesType;
   }
   SQLQuery(sqlcmd.Data());
   if (GetUseIndexes()>kIndexesNone) {
      sqlcmd.Form("CREATE UNIQUE INDEX %s%s%s ON %s%s%s (%s%s%s)",
                   quote, sqlio::KeysTableIndex, quote,
                   quote, sqlio::KeysTable, quote,
                   quote, SQLKeyIdColumn(), quote);
      SQLQuery(sqlcmd.Data());
   }
}
void TSQLFile::IncrementModifyCounter()
{
   
   
   
   
   if (!IsWritable()) {
      Error("IncrementModifyCounter","Cannot update tables without write accsess");
      return;
   }
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   const char* vquote = SQLValueQuote();
   sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%d WHERE %s%s%s=%s%s%s",
                quote, sqlio::ConfigTable, quote,
                quote, sqlio::CT_Value, quote, ++fModifyCounter,
                quote, sqlio::CT_Field, quote,
                vquote, sqlio::cfg_ModifyCounter, vquote);
   SQLQuery(sqlcmd.Data());
}
TString TSQLFile::MakeSelectQuery(TClass* cl)
{
   
   
   
   
   
   
   
   TString res = "";
   TSQLClassInfo* sqlinfo = FindSQLClassInfo(cl);
   if (sqlinfo==0) return res;
   TString columns, tables;
   Int_t tablecnt = 0;
   if (!ProduceClassSelectQuery(cl->GetStreamerInfo(), sqlinfo, columns, tables, tablecnt))
      return res;
   res.Form("SELECT %s FROM %s", columns.Data(), tables.Data());
   return res;
}
Bool_t TSQLFile::ProduceClassSelectQuery(TVirtualStreamerInfo* info,
                                         TSQLClassInfo* sqlinfo,
                                         TString& columns,
                                         TString& tables,
                                         Int_t& tablecnt)
{
   
   
   if ((info==0) || (sqlinfo==0)) return kFALSE;
   if (!sqlinfo->IsClassTableExist()) return kFALSE;
   const char* quote = SQLIdentifierQuote();
   TString table_syn;
   table_syn.Form("t%d", ++tablecnt);
   Bool_t start = tables.Length()==0;
   TString buf;
   if (start)
      buf.Form("%s AS %s", sqlinfo->GetClassTableName(), table_syn.Data());
   else
      buf.Form(" LEFT JOIN %s AS %s USING(%s%s%s)",
               sqlinfo->GetClassTableName(), table_syn.Data(),
               quote, SQLObjectIdColumn(), quote);
   tables += buf;
   if (start)
      columns.Form("%s.%s%s%s",table_syn.Data(), quote, SQLObjectIdColumn(), quote);
   if (info->GetClass()==TObject::Class()) {
      buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectUniqueId);
      columns+=buf;
      buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectBits);
      columns+=buf;
      buf.Form(", %s.%s",table_syn.Data(), sqlio::TObjectProcessId);
      columns+=buf;
      return kTRUE;
   }
   TIter iter(info->GetElements());
   TStreamerElement* elem = 0;
   while ((elem = (TStreamerElement*) iter()) != 0) {
      Int_t coltype = TSQLStructure::DefineElementColumnType(elem, this);
      TString colname = TSQLStructure::DefineElementColumnName(elem, this);
      buf = "";
      switch (coltype) {
         case TSQLStructure::kColObject:
         case TSQLStructure::kColObjectPtr:
         case TSQLStructure::kColTString:
         case TSQLStructure::kColSimple: {
            buf.Form(", %s.%s%s%s",table_syn.Data(), quote, colname.Data(), quote);
            columns+=buf;
            break;
         }
         case TSQLStructure::kColParent: {
            TClass* parentcl = elem->GetClassPointer();
            ProduceClassSelectQuery(parentcl->GetStreamerInfo(),
                                    FindSQLClassInfo(parentcl),
                                    columns, tables, tablecnt);
            break;
         }
         case TSQLStructure::kColSimpleArray: {
            for(Int_t n=0;n<elem->GetArrayLength();n++) {
               colname = TSQLStructure::DefineElementColumnName(elem, this, n);
               buf.Form(", %s.%s%s%s",table_syn.Data(), quote, colname.Data(), quote);
               columns+=buf;
            }
            break;
         }
      } 
   }
   return (columns.Length()>0) && (tables.Length()>0);
}
Bool_t TSQLFile::IsTablesExists()
{
   
   return SQLTestTable(sqlio::KeysTable) && SQLTestTable(sqlio::ConfigTable);
}
Bool_t TSQLFile::IsWriteAccess()
{
   
   return GetLocking()==kLockFree;
}
void TSQLFile::SetLocking(Int_t mode)
{
   
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   const char* vquote = SQLValueQuote();
   sqlcmd.Form("UPDATE %s%s%s SET %s%s%s=%d WHERE %s%s%s=%s%s%s",
                quote, sqlio::ConfigTable, quote,
                quote, sqlio::CT_Value, quote, mode,
                quote, sqlio::CT_Field, quote,
                vquote, sqlio::cfg_LockingMode, vquote);
   SQLQuery(sqlcmd.Data());
}
Int_t TSQLFile::GetLocking()
{
   
   const char* quote = SQLIdentifierQuote();
   const char* vquote = SQLValueQuote();
   TString sqlcmd;
   sqlcmd.Form("SELECT %s%s%s FROM %s%s%s WHERE %s%s%s=%s%s%s",
                quote, sqlio::CT_Value, quote,
                quote, sqlio::ConfigTable, quote,
                quote, sqlio::CT_Field, quote,
                vquote, sqlio::cfg_LockingMode, vquote);
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
   TSQLRow* row = (res==0) ? 0 : res->Next();
   TString field = (row==0) ? "" : row->GetField(0);
   delete row;
   delete res;
   if (field.Length()==0) return kLockFree;
   return field.Atoi();
}
Bool_t TSQLFile::IsReadAccess()
{
   
   return kTRUE;
}
TSQLResult* TSQLFile::SQLQuery(const char* cmd, Int_t flag, Bool_t* ok)
{
   
   
   
   
   
   
   
   if (fLogFile!=0)
      *fLogFile << cmd << endl;
   if (ok!=0) *ok = kFALSE;
   if (fSQL==0) return 0;
   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;
   if (res==0) return 0;
   if (flag==0) {
      delete res;
      return 0;
   }
   return res;
}
Bool_t TSQLFile::SQLCanStatement()
{
   
   if (fSQL==0) return kFALSE;
   if (!fSQL->HasStatement()) return kFALSE;
   return kTRUE; 
}
TSQLStatement* TSQLFile::SQLStatement(const char* cmd, Int_t bufsize)
{
   
   if (fSQL==0) return 0;
   if (!fSQL->HasStatement()) return 0;
   if (gDebug>1)
      Info("SQLStatement",cmd);
   fStmtCounter++;
   fQuerisCounter++; 
   return fSQL->Statement(cmd, bufsize);
}
void TSQLFile::SQLDeleteStatement(TSQLStatement* stmt)
{
   
   if (stmt==0) return;
   fStmtCounter--;
   delete stmt;
}
Bool_t TSQLFile::SQLApplyCommands(TObjArray* cmds)
{
   
   
   if ((cmds==0) || (fSQL==0)) return kFALSE;
   Bool_t ok = kTRUE;
   TIter iter(cmds);
   TObject* cmd= 0;
   while ((cmd=iter())!=0) {
      SQLQuery(cmd->GetName(),0,&ok);
      if(!ok) break;
   }
   return ok;
}
Bool_t TSQLFile::SQLTestTable(const char* tablename)
{
   
   if (fSQL==0) return kFALSE;
   return fSQL->HasTable(tablename);
}
Long64_t TSQLFile::SQLMaximumValue(const char* tablename, const char* columnname)
{
   
   
   if (fSQL==0) return -1;
   if (gDebug>2)
      Info("SQLMaximumValue","Requests for %s column %s", tablename, columnname);
   const char* quote = SQLIdentifierQuote();
   TString query;
   query.Form("SELECT MAX(%s%s%s) FROM %s%s%s",
              quote, columnname, quote,
              quote, tablename, quote);
   TSQLResult* res = SQLQuery(query.Data(), 1);
   if (res==0) return -1;
   TSQLRow* row = res->Next();
   Long64_t maxid = -1;
   if (row!=0)
      if (row->GetField(0)!=0)
         maxid = sqlio::atol64(row->GetField(0));
   delete row;
   delete res;
   if (gDebug>2)
      Info("SQLMaximumValue","Result = %lld",maxid);;
   return maxid;
}
void TSQLFile::SQLDeleteAllTables()
{
   
   if (fSQL==0) return;
   TList* tables = fSQL->GetTablesList();
   if (tables==0) return;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   TIter iter(tables);
   TObject* obj = 0;
   while ((obj=iter())!=0) {
      sqlcmd.Form("DROP TABLE %s%s%s", quote, obj->GetName(), quote);
      SQLQuery(sqlcmd.Data());
   }
   delete tables;
}
Bool_t TSQLFile::SQLStartTransaction()
{
   
   return fSQL ? fSQL->StartTransaction() : kFALSE;
}
Bool_t TSQLFile::SQLCommit()
{
   
   return fSQL ? fSQL->Commit() : kFALSE;
}
Bool_t TSQLFile::SQLRollback()
{
   
   return fSQL ? fSQL->Rollback() : kFALSE;
}
Int_t TSQLFile::SQLMaxIdentifierLength()
{
   
   Int_t maxlen = fSQL==0 ? 32 : fSQL->GetMaxIdentifierLength();
   
   if (maxlen<10) maxlen = 10;
   return maxlen;
}
void TSQLFile::DeleteKeyFromDB(Long64_t keyid)
{
   if (!IsWritable() || (keyid<0) || (fSQL==0)) return;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT MIN(%s%s%s), MAX(%s%s%s) FROM %s%s%s WHERE %s%s%s=%lld",
               quote, SQLObjectIdColumn(), quote,
               quote, SQLObjectIdColumn(), quote,
               quote, sqlio::ObjectsTable, quote,
               quote, SQLKeyIdColumn(), quote, keyid);
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 2);
   TSQLRow* row = res==0 ? 0 : res->Next();
   Long64_t minid(1), maxid(0);
   if ((row!=0) && (row->GetField(0)!=0) && (row->GetField(1)!=0)) {
      minid = sqlio::atol64(row->GetField(0));
      maxid = sqlio::atol64(row->GetField(1));
   }
   delete row;
   delete res;
   
   if (minid<=maxid) {
      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);
      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());
         }
      }
   }
   sqlcmd.Form("DELETE FROM %s%s%s WHERE %s%s%s=%lld", quote, sqlio::ObjectsTable, quote, quote, SQLKeyIdColumn(), quote, keyid);
   SQLQuery(sqlcmd.Data());
   sqlcmd.Form("DELETE FROM %s%s%s WHERE %s%s%s=%lld", quote, sqlio::KeysTable, quote, quote, SQLKeyIdColumn(), quote, keyid);
   SQLQuery(sqlcmd.Data());
   IncrementModifyCounter();
}
TKeySQL* TSQLFile::FindSQLKey(TDirectory* dir, Long64_t keyid)
{
   
   if (dir==0) return 0;
   TIter next(dir->GetListOfKeys());
   TObject* obj = 0;
   while ((obj = next())!=0) {
      TKeySQL* key = dynamic_cast<TKeySQL*> (obj);
      if (key!=0)
         if (key->GetDBKeyId()==keyid) return key;
   }
   return 0;
}
Bool_t TSQLFile::WriteKeyData(TKeySQL* key)
{
   
   if ((fSQL==0) || (key==0)) return kFALSE;
   if (!IsTablesExists()) CreateBasicTables();
   TString sqlcmd;
   const char* valuequote = SQLValueQuote();
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("INSERT INTO %s%s%s VALUES (%lld, %lld, %lld, %s%s%s, %s%s%s, %s%s%s, %d, %s%s%s)",
               quote, sqlio::KeysTable, quote,
               key->GetDBKeyId(), key->GetDBDirId(), key->GetDBObjId(),
               valuequote, key->GetName(), valuequote,
               valuequote, key->GetTitle(), valuequote,
               valuequote, key->GetDatime().AsSQLString(), valuequote,
               key->GetCycle(),
               valuequote, key->GetClassName(), valuequote);
   Bool_t ok = kTRUE;
   SQLQuery(sqlcmd.Data(), 0, &ok);
   if (ok) IncrementModifyCounter();
   return ok;
}
Bool_t TSQLFile::UpdateKeyData(TKeySQL* key)
{
   
   if ((fSQL==0) || (key==0)) return kFALSE;
   TString sqlcmd;
   const char* valuequote = SQLValueQuote();
   const char* quote = SQLIdentifierQuote();
   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,
                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;
   SQLQuery(sqlcmd.Data(), 0, &ok);
   if (ok) IncrementModifyCounter();
   return ok;
}
Long64_t TSQLFile::DefineNextKeyId()
{
   
   Long64_t max = -1;
   if (SQLTestTable(sqlio::KeysTable))
      max = SQLMaximumValue(sqlio::KeysTable, SQLKeyIdColumn());
   if (max<0) return sqlio::Ids_FirstKey;
   return max+1;
}
TSQLClassInfo* TSQLFile::FindSQLClassInfo(const char* clname, Int_t version)
{
   
   if (fSQLClassInfos==0) return 0;
   TIter iter(fSQLClassInfos);
   TSQLClassInfo* info = 0;
   while ((info = (TSQLClassInfo*) iter()) !=0 ) {
      if (strcmp(info->GetName(), clname)==0)
         if (info->GetClassVersion()==version) return info;
   }
   return 0;
}
TSQLClassInfo* TSQLFile::FindSQLClassInfo(const TClass* cl)
{
   
   return FindSQLClassInfo(cl->GetName(), cl->GetClassVersion());
}
TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const char* clname, Int_t version)
{
   
   TSQLClassInfo* info = FindSQLClassInfo(clname, version);
   if (info!=0) return info;
   if (fSQL==0) return 0;
   Long64_t maxid = 0;
   if (fSQLClassInfos!=0) {
      TIter iter(fSQLClassInfos);
      TSQLClassInfo* info = 0;
      while ((info = (TSQLClassInfo*) iter()) !=0 ) {
         if (info->GetClassId()>maxid)
            maxid = info->GetClassId();
      }
   }
   info = new TSQLClassInfo(maxid+1, clname, version);
   info->SetClassTableName(DefineTableName(clname, version, kFALSE));
   info->SetRawTableName(DefineTableName(clname, version, kTRUE));
   if (fSQLClassInfos==0) fSQLClassInfos = new TList;
   fSQLClassInfos->Add(info);
   return info;
}
TString TSQLFile::DefineTableName(const char* clname, Int_t version, Bool_t rawtable)
{
   
   Int_t maxlen = SQLMaxIdentifierLength();
   TString res;
   const char *suffix = rawtable ? "_raw" : "_ver";
   res.Form("%s%s%d", clname, suffix, version);
   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 {
      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);
   Error("DefineTableName","Cannot produce table name for class %s ver %d", clname, version);
   res.Form("%s%s%d", clname, suffix, version);
   return res;
}
Bool_t TSQLFile::HasTable(const char* name)
{
   
   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;
}
TSQLClassInfo* TSQLFile::RequestSQLClassInfo(const TClass* cl)
{
   
   return RequestSQLClassInfo(cl->GetName(), cl->GetClassVersion());
}
void TSQLFile::ReadSQLClassInfos()
{
   
   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;
}
void TSQLFile::AddIdEntry(Long64_t tableid, Int_t subid, Int_t type,
                          const char* name, const char* sqlname, const char* info)
{
   
   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.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());
      fIdsTableExists = kTRUE;
   }
   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);
   SQLQuery(sqlcmd.Data());
}
Bool_t TSQLFile::CreateClassTable(TSQLClassInfo* sqlinfo, TObjArray* colinfos)
{
   
   if (sqlinfo==0) return kFALSE;
   
   if (colinfos==0) return sqlinfo->IsClassTableExist();
   if (sqlinfo->IsClassTableExist()) {
      if (colinfos!=0) {
         colinfos->Delete();
         delete colinfos;
         
      }
      return kTRUE;
   }
   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::CreateRawTable(TSQLClassInfo* sqlinfo)
{
   
   if (sqlinfo==0) return kFALSE;
   if (sqlinfo->IsRawTableExist()) return kTRUE;
   const char* quote = SQLIdentifierQuote();
   if (gDebug>2)
      Info("CreateRawTable", sqlinfo->GetName());
   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;
   }
   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;
}
Bool_t TSQLFile::VerifyLongStringTable()
{
   
   
   if (fSQL==0) return kFALSE;
   if (SQLTestTable(sqlio::StringsTable)) return kTRUE;
   const char* quote = SQLIdentifierQuote();
   TString sqlcmd;
   sqlcmd.Form("CREATE TABLE %s (%s%s%s %s, %s%s%s %s, %s %s)",
               sqlio::StringsTable,
               quote, SQLObjectIdColumn(), quote, SQLIntType(),
               quote, SQLStrIdColumn(), quote, SQLIntType(),
               sqlio::ST_Value, SQLBigTextType());
   if (fTablesType.Length()>0) {
      sqlcmd +=" TYPE=";
      sqlcmd += fTablesType;
   }
   SQLQuery(sqlcmd.Data());
   return kTRUE;
}
TString TSQLFile::CodeLongString(Long64_t objid, Int_t strid)
{
   
   TString res;
   res.Form("%s %lld %s %d %s", sqlio::LongStrPrefix, objid, sqlio::LongStrPrefix, strid, sqlio::LongStrPrefix);
   return res;
}
Int_t TSQLFile::IsLongStringCode(Long64_t objid, const char* value)
{
   
   
   if (value==0) return 0;
   if (strlen(value)<strlen(sqlio::LongStrPrefix)*3+6) return 0;
   if (strstr(value, sqlio::LongStrPrefix)!=value) return 0;
   value+=strlen(sqlio::LongStrPrefix);
   if (*value++!=' ') return 0;
   TString s_strid, s_objid;
   if ((*value<'1') || (*value>'9')) return 0;
   do {
      s_objid.Append(*value++);
   } while ((*value!=0) && (*value>='0') && (*value<='9'));
   if (*value++ != ' ') return 0;
   if ((*value==0) || (strstr(value, sqlio::LongStrPrefix)!=value)) return 0;
   value+=strlen(sqlio::LongStrPrefix);
   if (*value++!=' ') return 0;
   if ((*value<'1') || (*value>'9')) return 0;
   do {
      s_strid.Append(*value++);
   } while ((*value!=0) && (*value>='0') && (*value<='9'));
   if (*value++!=' ') return 0;
   if ((*value==0) || (strcmp(value, sqlio::LongStrPrefix)!=0)) return 0;
   Long64_t objid2 = sqlio::atol64(s_objid.Data());
   if (objid2!=objid) return 0;
   return atoi(s_strid.Data());
}
Bool_t TSQLFile::GetLongString(Long64_t objid, Int_t strid, TString& value)
{
   
   
   if (!SQLTestTable(sqlio::StringsTable)) return kFALSE;
   TString cmd;
   const char* quote = SQLIdentifierQuote();
   cmd.Form("SELECT %s FROM %s%s%s WHERE %s%s%s=%lld AND %s%s%s=%d",
            sqlio::ST_Value,
            quote, sqlio::StringsTable, quote,
            quote, SQLObjectIdColumn(), quote, objid,
            quote, SQLStrIdColumn(), quote, strid);
   TSQLResult* res = SQLQuery(cmd.Data(), 1);
   if (res==0) return kFALSE;
   TSQLRow* row = res->Next();
   if (row==0) { delete res; return kFALSE; }
   value = row->GetField(0);
   delete row;
   delete res;
   return kTRUE;
}
Long64_t TSQLFile::VerifyObjectTable()
{
   
   
   
   if (fSQL==0) return -1;
   Long64_t maxid = -1;
   if (gDebug>2)
      Info("VerifyObjectTable", "Checks if object table is there");
   if (SQLTestTable(sqlio::ObjectsTable))
      maxid = SQLMaximumValue(sqlio::ObjectsTable, SQLObjectIdColumn());
   else {
      TString sqlcmd;
      const char* quote = SQLIdentifierQuote();
      sqlcmd.Form("CREATE TABLE %s%s%s (%s%s%s %s, %s%s%s %s, %s%s%s %s, %s%s%s %s)",
                  quote, sqlio::ObjectsTable, quote,
                  quote, SQLKeyIdColumn(), quote, SQLIntType(),
                  quote, SQLObjectIdColumn(), quote, SQLIntType(),
                  quote, sqlio::OT_Class, quote, SQLSmallTextType(),
                  quote, sqlio::OT_Version, quote, SQLIntType());
      if ((fTablesType.Length()>0) && IsMySQL()) {
         sqlcmd +=" TYPE=";
         sqlcmd += fTablesType;
      }
      SQLQuery(sqlcmd.Data());
      if (GetUseIndexes()>kIndexesNone) {
         sqlcmd.Form("CREATE UNIQUE INDEX %s%s%s ON %s%s%s (%s%s%s)",
                      quote, sqlio::ObjectsTableIndex, quote,
                      quote, sqlio::ObjectsTable, quote,
                      quote, SQLObjectIdColumn(), quote);
         SQLQuery(sqlcmd.Data());
      }
   }
   return maxid;
}
Bool_t TSQLFile::SQLObjectInfo(Long64_t objid, TString& clname, Version_t &version)
{
   
   if (fSQL==0) return kFALSE;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT %s%s%s, %s%s%s FROM %s%s%s WHERE %s%s%s=%lld",
               quote, sqlio::OT_Class, quote,
               quote, sqlio::OT_Version, quote,
               quote, sqlio::ObjectsTable, quote,
               quote, SQLObjectIdColumn(), quote, objid);
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
   if (res==0) return kFALSE;
   TSQLRow* row = res->Next();
   if (row!=0) {
      clname = row->GetField(0);
      version = atoi(row->GetField(1));
   }
   delete row;
   delete res;
   return row!=0;
}
TObjArray* TSQLFile::SQLObjectsInfo(Long64_t keyid)
{
   if (fSQL==0) return 0;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT %s%s%s, %s%s%s, %s%s%s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
               quote, SQLObjectIdColumn(), quote,
               quote, sqlio::OT_Class, quote,
               quote, sqlio::OT_Version, quote,
               quote, sqlio::ObjectsTable, quote,
               quote, SQLKeyIdColumn(), quote, keyid,
               quote, SQLObjectIdColumn(), quote);
   TObjArray* arr = 0;
   if (fLogFile!=0)
      *fLogFile << sqlcmd << endl;
   if (gDebug>2) Info("SQLObjectsInfo",sqlcmd);
   fQuerisCounter++;
   TSQLStatement* stmt = SQLStatement(sqlcmd.Data(), 1000);
   if (stmt!=0) {
      stmt->Process();
      stmt->StoreResult();
      while (stmt->NextResultRow()) {
         Long64_t objid = stmt->GetLong64(0);
         const char* clname = stmt->GetString(1);
         Int_t version = stmt->GetInt(2);
         TSQLObjectInfo* info = new TSQLObjectInfo(objid, clname, version);
         if (arr==0) arr = new TObjArray();
         arr->Add(info);
      }
      delete stmt;
      return arr;
   }
   TSQLResult* res = SQLQuery(sqlcmd.Data(), 1);
   if (res==0) return 0;
   TSQLRow* row = 0;
   while ((row = res->Next()) != 0) {
      Long64_t objid = atoi(row->GetField(0));
      const char* clname = row->GetField(1);
      Int_t version = atoi(row->GetField(2));
      TSQLObjectInfo* info = new TSQLObjectInfo(objid, clname, version);
      if (arr==0) arr = new TObjArray();
      arr->Add(info);
      delete row;
   }
   delete res;
   return arr;
}
TSQLResult* TSQLFile::GetNormalClassData(Long64_t objid, TSQLClassInfo* sqlinfo)
{
   if (!sqlinfo->IsClassTableExist()) return 0;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s=%lld",
               quote, sqlinfo->GetClassTableName(), quote,
               quote, SQLObjectIdColumn(), quote, objid);
   return SQLQuery(sqlcmd.Data(), 2);
}
TSQLResult* TSQLFile::GetNormalClassDataAll(Long64_t minobjid, Long64_t maxobjid, TSQLClassInfo* sqlinfo)
{
   
   if (!sqlinfo->IsClassTableExist()) return 0;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT * FROM %s%s%s WHERE %s%s%s BETWEEN %lld AND %lld ORDER BY %s%s%s",
               quote, sqlinfo->GetClassTableName(), quote,
               quote, SQLObjectIdColumn(), quote, minobjid, maxobjid,
               quote, SQLObjectIdColumn(), quote);
   return SQLQuery(sqlcmd.Data(), 2);
}
TSQLResult* TSQLFile::GetBlobClassData(Long64_t objid, TSQLClassInfo* sqlinfo)
{
   if (!sqlinfo->IsRawTableExist()) return 0;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT %s, %s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
               sqlio::BT_Field, sqlio::BT_Value,
               quote, sqlinfo->GetRawTableName(), quote,
               quote, SQLObjectIdColumn(), quote, objid,
               quote, SQLRawIdColumn(), quote);
   return SQLQuery(sqlcmd.Data(), 2);
}
TSQLStatement* TSQLFile::GetBlobClassDataStmt(Long64_t objid, TSQLClassInfo* sqlinfo)
{
   if (!sqlinfo->IsRawTableExist()) return 0;
   TString sqlcmd;
   const char* quote = SQLIdentifierQuote();
   sqlcmd.Form("SELECT %s, %s FROM %s%s%s WHERE %s%s%s=%lld ORDER BY %s%s%s",
               sqlio::BT_Field, sqlio::BT_Value,
               quote, sqlinfo->GetRawTableName(), quote,
               quote, SQLObjectIdColumn(), quote, objid,
               quote, SQLRawIdColumn(), quote);
   if (fLogFile!=0)
      *fLogFile << sqlcmd << endl;
   if (gDebug>2) Info("BuildStatement",sqlcmd);
   fQuerisCounter++;
   TSQLStatement* stmt = SQLStatement(sqlcmd.Data(), 1000);
   if (stmt==0) return 0;
   stmt->Process();
   stmt->StoreResult();
   return stmt;
}
Long64_t TSQLFile::StoreObjectInTables(Long64_t keyid, const void* obj, const TClass* cl)
{
   
   if (fSQL==0) return -1;
   Long64_t objid = VerifyObjectTable();
   if (objid<=0) objid = 1; else objid++;
   TBufferSQL2 buffer(TBuffer::kWrite, this);
   TSQLStructure* s = buffer.SqlWriteAny(obj, cl, objid);
   if ((buffer.GetErrorFlag()>0) && (s!=0)) {
      Error("StoreObjectInTables","Cannot convert object data to TSQLStructure");
      objid = -1;
   } else {
      TObjArray cmds;
      
      
      if (!s->ConvertToTables(this, keyid, &cmds)) {
         Error("StoreObjectInTables","Cannot convert to SQL statements");
         objid = -1;
      } else {
         Bool_t needcommit = kFALSE;
         if (GetUseTransactions()==kTransactionsAuto) {
            SQLStartTransaction();
            needcommit = kTRUE;
         }
         if (!SQLApplyCommands(&cmds)) {
            Error("StoreObject","Cannot correctly store object data in database");
            objid = -1;
            if (needcommit) SQLRollback();
         } else {
            if (needcommit) SQLCommit();
         }
      }
      cmds.Delete();
   }
   return objid;
}
const char* TSQLFile::SQLCompatibleType(Int_t typ) const
{
   
   
   return (typ<0) || (typ>18) ? 0 : fBasicTypes[typ];
}
const char* TSQLFile::SQLIntType() const
{
   
   return SQLCompatibleType(TVirtualStreamerInfo::kInt);
}
Long64_t TSQLFile::DirCreateEntry(TDirectory* dir)
{
   
   TDirectory* mother = dir->GetMotherDir();
   if (mother==0) mother = this;
   
   TKeySQL* key = new TKeySQL(mother, dir, dir->GetName(), dir->GetTitle());
   return key->GetDBKeyId();
}
Int_t TSQLFile::DirReadKeys(TDirectory* dir)
{
   
   
   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)
{
   
   StreamKeysForDirectory(dir, kTRUE);
}
void TSQLFile::DirWriteHeader(TDirectory* dir)
{
   
   TSQLClassInfo* sqlinfo = FindSQLClassInfo("TDirectory",TDirectoryFile::Class()->GetClassVersion());
   if (sqlinfo==0) return;
   
   TKeySQL* key = FindSQLKey(dir->GetMotherDir(), dir->GetSeekDir());
   if (key==0) return;
   const char* valuequote = SQLValueQuote();
   const char* quote = SQLIdentifierQuote();
   TString timeC = fDatimeC.AsSQLString();
   TSQLStructure::AddStrBrackets(timeC, valuequote);
   TString timeM = fDatimeM.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)
{
   
   
   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());
   }
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.