// @(#)root/sql:$Id$ // Author: Sergey Linev 20/11/2005 /************************************************************************* * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ /** \class TSQLObjectData \ingroup IO TSQLObjectData is used in TBufferSQL2 class in reading procedure. It contains data, request from database table for one specifc object for one specific class. For instance, when data for class TH1 required, requests will be done to TH1_ver4 and TH1_raw4 tables and result of these requests will be kept in single TSQLObjectData instance. */ #include "TSQLObjectData.h" #include "TObjArray.h" #include "TNamed.h" #include "TList.h" #include "TSQLRow.h" #include "TSQLResult.h" #include "TSQLClassInfo.h" #include "TSQLStructure.h" #include "TSQLStatement.h" /** \class TSQLObjectInfo \ingroup IO Info (classname, version) about object in database */ ClassImp(TSQLObjectInfo) //////////////////////////////////////////////////////////////////////////////// TSQLObjectInfo::TSQLObjectInfo() : TObject(), fObjId(0), fClassName(), fVersion(0) { } //////////////////////////////////////////////////////////////////////////////// TSQLObjectInfo::TSQLObjectInfo(Long64_t objid, const char* classname, Version_t version) : TObject(), fObjId(objid), fClassName(classname), fVersion(version) { } //////////////////////////////////////////////////////////////////////////////// TSQLObjectInfo::~TSQLObjectInfo() { } /** \class TSQLObjectData \ingroup IO Keeps the data requested from the SQL server for an object. */ ClassImp(TSQLObjectData) //////////////////////////////////////////////////////////////////////////////// /// default contrsuctor TSQLObjectData::TSQLObjectData() : TObject(), fInfo(0), fObjId(0), fOwner(kFALSE), fClassData(0), fBlobData(0), fBlobStmt(0), fLocatedColumn(-1), fClassRow(0), fBlobRow(0), fLocatedField(0), fLocatedValue(0), fCurrentBlob(kFALSE), fBlobPrefixName(0), fBlobTypeName(0), fUnpack(0) { } //////////////////////////////////////////////////////////////////////////////// /// normal contrsuctor, TSQLObjectData::TSQLObjectData(TSQLClassInfo* sqlinfo, Long64_t objid, TSQLResult* classdata, TSQLRow* classrow, TSQLResult* blobdata, TSQLStatement* blobstmt) : TObject(), fInfo(sqlinfo), fObjId(objid), fOwner(kFALSE), fClassData(classdata), fBlobData(blobdata), fBlobStmt(blobstmt), fLocatedColumn(-1), fClassRow(classrow), fBlobRow(0), fLocatedField(0), fLocatedValue(0), fCurrentBlob(kFALSE), fBlobPrefixName(0), fBlobTypeName(0), fUnpack(0) { // take ownership if no special row from data pool is provided if ((fClassData!=0) && (fClassRow==0)) { fOwner = kTRUE; fClassRow = fClassData->Next(); } ShiftBlobRow(); } //////////////////////////////////////////////////////////////////////////////// /// destructor of TSQLObjectData object TSQLObjectData::~TSQLObjectData() { if ((fClassData!=0) && fOwner) delete fClassData; if (fClassRow!=0) delete fClassRow; if (fBlobRow!=0) delete fBlobRow; if (fBlobData!=0) delete fBlobData; if (fUnpack!=0) { fUnpack->Delete(); delete fUnpack; } if (fBlobStmt!=0) delete fBlobStmt; } //////////////////////////////////////////////////////////////////////////////// /// return number of columns in class table result Int_t TSQLObjectData::GetNumClassFields() { if (fClassData!=0) return fClassData->GetFieldCount(); return 0; } //////////////////////////////////////////////////////////////////////////////// /// get name of class table column const char* TSQLObjectData::GetClassFieldName(Int_t n) { if (fClassData!=0) return fClassData->GetFieldName(n); return 0; } //////////////////////////////////////////////////////////////////////////////// /// locate column of that name in results Bool_t TSQLObjectData::LocateColumn(const char* colname, Bool_t isblob) { if (fUnpack!=0) { fUnpack->Delete(); delete fUnpack; fUnpack = 0; } fLocatedField = 0; fLocatedValue = 0; fCurrentBlob = kFALSE; if ((fClassData==0) || (fClassRow==0)) return kFALSE; // Int_t numfields = GetNumClassFields(); Int_t ncol = fInfo->FindColumn(colname, kFALSE); if (ncol>0) { fLocatedColumn = ncol; fLocatedField = GetClassFieldName(ncol); fLocatedValue = fClassRow->GetField(ncol); } /* for (Int_t ncol=1;ncolGetField(ncol); break; } } */ if (fLocatedField==0) return kFALSE; if (!isblob) return kTRUE; if ((fBlobRow==0) && (fBlobStmt==0)) return kFALSE; fCurrentBlob = kTRUE; ExtractBlobValues(); return kTRUE; } //////////////////////////////////////////////////////////////////////////////// /// shift cursor to next blob value Bool_t TSQLObjectData::ShiftBlobRow() { if (fBlobStmt!=0) { Bool_t res = fBlobStmt->NextResultRow(); if (!res) { delete fBlobStmt; fBlobStmt = 0; } return res; } delete fBlobRow; fBlobRow = fBlobData ? fBlobData->Next() : 0; return fBlobRow!=0; } //////////////////////////////////////////////////////////////////////////////// /// extract from curent blob row value and names identifiers Bool_t TSQLObjectData::ExtractBlobValues() { const char* name = 0; Bool_t hasdata = kFALSE; if (fBlobStmt!=0) { name = fBlobStmt->GetString(0); fLocatedValue = fBlobStmt->GetString(1); hasdata = kTRUE; } if (!hasdata) { if (fBlobRow!=0) { fLocatedValue = fBlobRow->GetField(1); name = fBlobRow->GetField(0); } } if (name==0) { fBlobPrefixName = 0; fBlobTypeName = 0; return kFALSE; } const char* separ = strstr(name, ":"); //SQLNameSeparator() if (separ==0) { fBlobPrefixName = 0; fBlobTypeName = name; } else { fBlobPrefixName = name; separ+=strlen(":"); //SQLNameSeparator() fBlobTypeName = separ; } // if (gDebug>4) // Info("ExtractBlobValues","Prefix:%s Type:%s", // (fBlobPrefixName ? fBlobPrefixName : "null"), // (fBlobTypeName ? fBlobTypeName : "null")); return kTRUE; } //////////////////////////////////////////////////////////////////////////////// /// add emulated data /// this used to place version or TObject raw data, read from normal tables void TSQLObjectData::AddUnpack(const char* tname, const char* value) { TNamed* str = new TNamed(tname, value); if (fUnpack==0) { fUnpack = new TObjArray(); fBlobPrefixName = 0; fBlobTypeName = str->GetName(); fLocatedValue = str->GetTitle(); } fUnpack->Add(str); } //////////////////////////////////////////////////////////////////////////////// /// emulate integer value in raw data void TSQLObjectData::AddUnpackInt(const char* tname, Int_t value) { TString sbuf; sbuf.Form("%d", value); AddUnpack(tname, sbuf.Data()); } //////////////////////////////////////////////////////////////////////////////// /// shift to next column or next row in blob data void TSQLObjectData::ShiftToNextValue() { Bool_t doshift = kTRUE; if (fUnpack!=0) { TObject* prev = fUnpack->First(); fUnpack->Remove(prev); delete prev; fUnpack->Compress(); if (fUnpack->GetLast()>=0) { TNamed* curr = (TNamed*) fUnpack->First(); fBlobPrefixName = 0; fBlobTypeName = curr->GetName(); fLocatedValue = curr->GetTitle(); return; } delete fUnpack; fUnpack = 0; doshift = kFALSE; } if (fCurrentBlob) { if (doshift) ShiftBlobRow(); ExtractBlobValues(); } else if (fClassData!=0) { if (doshift) fLocatedColumn++; if (fLocatedColumnGetField(fLocatedColumn); } else { fLocatedField = 0; fLocatedValue = 0; } } } //////////////////////////////////////////////////////////////////////////////// /// checks if data type corresponds to that stored in raw table Bool_t TSQLObjectData::VerifyDataType(const char* tname, Bool_t errormsg) { if (tname==0) { if (errormsg) Error("VerifyDataType","Data type not specified"); return kFALSE; } // here maybe type of column can be checked if (!IsBlobData()) return kTRUE; if (gDebug>4) if ((fBlobTypeName==0) && errormsg) { Error("VerifyDataType","fBlobTypeName is null"); return kFALSE; } TString v1(fBlobTypeName); TString v2(tname); // if (strcmp(fBlobTypeName,tname)!=0) { if (v1!=v2) { if (errormsg) Error("VerifyDataType","Data type missmatch %s - %s", fBlobTypeName, tname); return kFALSE; } return kTRUE; } //////////////////////////////////////////////////////////////////////////////// /// prepare to read data from raw table Bool_t TSQLObjectData::PrepareForRawData() { if (!ExtractBlobValues()) return kFALSE; fCurrentBlob = kTRUE; return kTRUE; } //=================================================================================== //________________________________________________________________________ // // TSQLObjectDataPool contains list (pool) of data from single class table // for differents objects, all belonging to the same key. // This is typical situation when list of objects stored as single key. // To optimize reading of such data, one query is submitted and results of that // query kept in TSQLObjectDataPool object // //________________________________________________________________________ ClassImp(TSQLObjectDataPool); //////////////////////////////////////////////////////////////////////////////// TSQLObjectDataPool::TSQLObjectDataPool() : TObject(), fInfo(0), fClassData(0), fIsMoreRows(kTRUE), fRowsPool(0) { } //////////////////////////////////////////////////////////////////////////////// TSQLObjectDataPool::TSQLObjectDataPool(TSQLClassInfo* info, TSQLResult* data) : TObject(), fInfo(info), fClassData(data), fIsMoreRows(kTRUE), fRowsPool(0) { } //////////////////////////////////////////////////////////////////////////////// /// Destructor of TSQLObjectDataPool class /// Deletes not used rows and class data table TSQLObjectDataPool::~TSQLObjectDataPool() { if (fClassData!=0) delete fClassData; if (fRowsPool!=0) { fRowsPool->Delete(); delete fRowsPool; } } //////////////////////////////////////////////////////////////////////////////// /// Returns single sql row with object data for that class TSQLRow* TSQLObjectDataPool::GetObjectRow(Long64_t objid) { if (fClassData==0) return 0; Long64_t rowid; if (fRowsPool!=0) { TObjLink* link = fRowsPool->FirstLink(); while (link!=0) { TSQLRow* row = (TSQLRow*) link->GetObject(); rowid = sqlio::atol64(row->GetField(0)); if (rowid==objid) { fRowsPool->Remove(link); return row; } link = link->Next(); } } while (fIsMoreRows) { TSQLRow* row = fClassData->Next(); if (row==0) fIsMoreRows = kFALSE; else { rowid = sqlio::atol64(row->GetField(0)); if (rowid==objid) return row; if (fRowsPool==0) fRowsPool = new TList(); fRowsPool->Add(row); } } return 0; }