#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[21] = {
"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",
"DOUBLE",
""
};
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[21] = {
"VARCHAR(255)",
"INT",
"INT",
"INT",
"INT",
"FLOAT",
"INT",
"VARCHAR(255)",
"DOUBLE PRECISION",
"DOUBLE PRECISION",
"",
"INT",
"INT",
"INT",
"INT",
"INT",
"INT",
"INT",
"INT",
"FLOAT",
""
};
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(21),
fCanChangeConfig(kFALSE),
fTablesType(),
fUseTransactions(0),
fUseIndexes(0),
fModifyCounter(0),
fQuerisCounter(0),
fBasicTypes(0),
fOtherTypes(0),
fUserName(),
fLogFile(0),
fIdsTableExists(kFALSE),
fStmtCounter(0)
{
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(21),
fCanChangeConfig(kFALSE),
fTablesType(),
fUseTransactions(0),
fUseIndexes(0),
fModifyCounter(0),
fQuerisCounter(0),
fBasicTypes(mysql_BasicTypes),
fOtherTypes(mysql_OtherTypes),
fUserName(user),
fLogFile(0),
fIdsTableExists(kFALSE),
fStmtCounter(0)
{
if (!gROOT)
::Fatal("TFile::TFile", "ROOT system not initialized");
gDirectory = 0;
SetName(dbname);
SetTitle("TFile interface to SQL DB");
TDirectoryFile::Build();
fFile = this;
if (dbname && strstr(dbname,"oracle://")!=0) {
fBasicTypes = oracle_BasicTypes;
fOtherTypes = oracle_OtherTypes;
}
fArrayLimit = 21;
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 || !dbname[0]) {
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::TContext ctxt(this);
TDirectoryFile::Close();
}
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)
std::cout << " Reading keyid = " << keyid << " name = " << keyname << std::endl;
if ((keyid>=sqlio::Ids_FirstKey) || (keyid==specialkeyid)) {
if (doupdate) {
TKeySQL* key = FindSQLKey(dir, keyid);
if (key==0) {
Error("StreamKeysForDirectory","Key with id %lld 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;
#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)
{
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 << std::endl;
if (ok!=0) *ok = kFALSE;
if (fSQL==0) return 0;
if (gDebug>2) Info("SQLQuery", "%s", 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;
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", "%s", 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;
if (fSQL->HasTable(tablename)) return kTRUE;
TString buf(tablename);
buf.ToLower();
if (fSQL->HasTable(buf.Data())) return kTRUE;
buf.ToUpper();
return fSQL->HasTable(buf.Data());
}
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);
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* info2 = row->GetField(5);
if (typ==TSQLStructure::kIdColumn) {
if (cols==0) cols = new TObjArray;
cols->Add(new TSQLClassColumnInfo(fullname, sqlname, info2));
}
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* info2 = FindSQLClassInfo(classname, version);
if (info2==0) {
info2 = new TSQLClassInfo(tableid, classname, version);
if (fSQLClassInfos==0) fSQLClassInfos = new TList;
fSQLClassInfos->Add(info2);
}
info2->SetRawTableName(rawtable);
info2->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", "%s", 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 << std::endl;
if (gDebug>2) Info("SQLObjectsInfo", "%s", sqlcmd.Data());
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 << std::endl;
if (gDebug>2) Info("BuildStatement", "%s", sqlcmd.Data());
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) {
Error("StoreObjectInTables","Cannot convert object data to TSQLStructure");
objid = -1;
} else {
TObjArray cmds;
if (s && !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 = %lld", 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=%lld",
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());
}
}