Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TKeySQL.cxx
Go to the documentation of this file.
1 // @(#)root/sql:$Id$
2 // Author: Sergey Linev 20/11/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13 \class TKeySQL
14 \ingroup IO
15 
16 TKeySQL represents meta-information about object, which was written to
17 SQL database. It keeps object id, which used to locate object data
18 from database tables.
19 */
20 
21 #include "TKeySQL.h"
22 
23 #include "TROOT.h"
24 #include "TClass.h"
25 #include "Riostream.h"
26 
27 #include "TSQLResult.h"
28 #include "TBufferSQL2.h"
29 #include "TSQLStructure.h"
30 #include "TSQLFile.h"
31 #include <stdlib.h>
32 
33 ClassImp(TKeySQL);
34 
35 ////////////////////////////////////////////////////////////////////////////////
36 /// Creates TKeySQL and convert obj data to TSQLStructure via TBufferSQL2
37 
38 TKeySQL::TKeySQL(TDirectory *mother, const TObject *obj, const char *name, const char *title)
39  : TKey(mother)
40 {
41  if (name)
42  SetName(name);
43  else if (obj) {
44  SetName(obj->GetName());
45  fClassName = obj->ClassName();
46  } else
47  SetName("Noname");
48 
49  if (title)
50  SetTitle(title);
51 
52  StoreKeyObject((void *)obj, obj ? obj->IsA() : 0);
53 }
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// Creates TKeySQL and convert obj data to TSQLStructure via TBufferSQL2
57 
58 TKeySQL::TKeySQL(TDirectory *mother, const void *obj, const TClass *cl, const char *name, const char *title)
59  : TKey(mother)
60 {
61  if (name && *name)
62  SetName(name);
63  else
64  SetName(cl ? cl->GetName() : "Noname");
65 
66  if (title)
67  SetTitle(title);
68 
69  StoreKeyObject(obj, cl);
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Create TKeySQL object, which corresponds to single entry in keys table
74 
75 TKeySQL::TKeySQL(TDirectory *mother, Long64_t keyid, Long64_t objid, const char *name, const char *title,
76  const char *keydatetime, Int_t cycle, const char *classname)
77  : TKey(mother), fKeyId(keyid), fObjId(objid)
78 {
79  SetName(name);
80  if (title)
81  SetTitle(title);
82  TDatime dt(keydatetime);
83  fDatime = dt;
84  fCycle = cycle;
85  fClassName = classname;
86 }
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// Compares keydata with provided and return kTRUE if key was modified
90 /// Used in TFile::StreamKeysForDirectory() method to verify data for that keys
91 /// should be updated
92 
93 Bool_t TKeySQL::IsKeyModified(const char *keyname, const char *keytitle, const char *keydatime, Int_t cycle,
94  const char *classname)
95 {
96  Int_t len1 = (GetName() == 0) ? 0 : strlen(GetName());
97  Int_t len2 = (keyname == 0) ? 0 : strlen(keyname);
98  if (len1 != len2)
99  return kTRUE;
100  if ((len1 > 0) && (strcmp(GetName(), keyname) != 0))
101  return kTRUE;
102 
103  len1 = (GetTitle() == 0) ? 0 : strlen(GetTitle());
104  len2 = (keytitle == 0) ? 0 : strlen(keytitle);
105  if (len1 != len2)
106  return kTRUE;
107  if ((len1 > 0) && (strcmp(GetTitle(), keytitle) != 0))
108  return kTRUE;
109 
110  const char *tm = GetDatime().AsSQLString();
111  len1 = (tm == 0) ? 0 : strlen(tm);
112  len2 = (keydatime == 0) ? 0 : strlen(keydatime);
113  if (len1 != len2)
114  return kTRUE;
115  if ((len1 > 0) && (strcmp(tm, keydatime) != 0))
116  return kTRUE;
117 
118  if (cycle != GetCycle())
119  return kTRUE;
120 
121  len1 = (GetClassName() == 0) ? 0 : strlen(GetClassName());
122  len2 = (classname == 0) ? 0 : strlen(classname);
123  if (len1 != len2)
124  return kTRUE;
125  if ((len1 > 0) && (strcmp(GetClassName(), classname) != 0))
126  return kTRUE;
127 
128  return kFALSE;
129 }
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 /// Removes key from current directory
133 /// Note: TKeySQL object is not deleted. You still have to call "delete key"
134 
135 void TKeySQL::Delete(Option_t * /*option*/)
136 {
137  TSQLFile *f = (TSQLFile *)GetFile();
138 
139  if (f != 0)
140  f->DeleteKeyFromDB(GetDBKeyId());
141 
142  fMotherDir->GetListOfKeys()->Remove(this);
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 /// return sql id of parent directory
147 
148 Long64_t TKeySQL::GetDBDirId() const
149 {
150  return GetMotherDir() ? GetMotherDir()->GetSeekDir() : 0;
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Stores object, associated with key, into data tables
155 
156 void TKeySQL::StoreKeyObject(const void *obj, const TClass *cl)
157 {
158  TSQLFile *f = (TSQLFile *)GetFile();
159 
160  fCycle = GetMotherDir()->AppendKey(this);
161 
162  fKeyId = f->DefineNextKeyId();
163 
164  fObjId = f->StoreObjectInTables(fKeyId, obj, cl);
165 
166  if (cl)
167  fClassName = cl->GetName();
168 
169  if (GetDBObjId() >= 0) {
170  fDatime.Set();
171  if (!f->WriteKeyData(this)) {
172  // cannot add entry to keys table
173  Error("StoreKeyObject", "Cannot write data to key tables");
174  // delete everything relevant for that key
175  f->DeleteKeyFromDB(GetDBKeyId());
176  fObjId = -1;
177  }
178  }
179 
180  if (GetDBObjId() < 0)
181  GetMotherDir()->GetListOfKeys()->Remove(this);
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// To read an object from the file.
186 /// The object associated to this key is read from the file into memory.
187 /// Before invoking this function, obj has been created via the
188 /// default constructor.
189 
190 Int_t TKeySQL::Read(TObject *tobj)
191 {
192  if (tobj == 0)
193  return 0;
194 
195  void *res = ReadKeyObject(tobj, 0);
196 
197  return res == 0 ? 0 : 1;
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// Read object derived from TObject class
202 /// If it is not TObject or in case of error, return 0
203 
204 TObject *TKeySQL::ReadObj()
205 {
206  TObject *tobj = (TObject *)ReadKeyObject(0, TObject::Class());
207 
208  if (tobj) {
209  if (gROOT->GetForceStyle())
210  tobj->UseCurrentStyle();
211  if (tobj->IsA() == TDirectoryFile::Class()) {
212  TDirectoryFile *dir = (TDirectoryFile *)tobj;
213  dir->SetName(GetName());
214  dir->SetTitle(GetTitle());
215  dir->SetSeekDir(GetDBKeyId());
216  dir->SetMother(fMotherDir);
217  dir->ReadKeys();
218  fMotherDir->Append(dir);
219  }
220  }
221 
222  return tobj;
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 /// Read object derived from TObject class
227 /// If it is not TObject or in case of error, return 0
228 
229 TObject *TKeySQL::ReadObjWithBuffer(char * /*bufferRead*/)
230 {
231  TObject *tobj = (TObject *)ReadKeyObject(0, TObject::Class());
232 
233  if (tobj) {
234  if (gROOT->GetForceStyle())
235  tobj->UseCurrentStyle();
236  if (tobj->IsA() == TDirectoryFile::Class()) {
237  TDirectoryFile *dir = (TDirectoryFile *)tobj;
238  dir->SetName(GetName());
239  dir->SetTitle(GetTitle());
240  dir->SetSeekDir(GetDBKeyId());
241  dir->SetMother(fMotherDir);
242  dir->ReadKeys();
243  fMotherDir->Append(dir);
244  }
245  }
246 
247  return tobj;
248 }
249 
250 ////////////////////////////////////////////////////////////////////////////////
251 /// Read object of any type from SQL database
252 
253 void *TKeySQL::ReadObjectAny(const TClass *expectedClass)
254 {
255  void *res = ReadKeyObject(0, expectedClass);
256 
257  if (res && (expectedClass == TDirectoryFile::Class())) {
258  TDirectoryFile *dir = (TDirectoryFile *)res;
259  dir->SetName(GetName());
260  dir->SetTitle(GetTitle());
261  dir->SetSeekDir(GetDBKeyId());
262  dir->SetMother(fMotherDir);
263  dir->ReadKeys();
264  fMotherDir->Append(dir);
265  }
266 
267  return res;
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 /// Read object, associated with key, from database
272 
273 void *TKeySQL::ReadKeyObject(void *obj, const TClass *expectedClass)
274 {
275  TSQLFile *f = (TSQLFile *)GetFile();
276 
277  if ((GetDBKeyId() <= 0) || !f)
278  return obj;
279 
280  TBufferSQL2 buffer(TBuffer::kRead, f);
281 
282  buffer.InitMap();
283 
284  TClass *cl = nullptr;
285 
286  void *res = buffer.SqlReadAny(GetDBKeyId(), GetDBObjId(), &cl, obj);
287 
288  if (!cl || !res)
289  return nullptr;
290 
291  Int_t delta = 0;
292 
293  if (expectedClass != 0) {
294  delta = cl->GetBaseClassOffset(expectedClass);
295  if (delta < 0) {
296  if (obj == 0)
297  cl->Destructor(res);
298  return 0;
299  }
300  if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
301  // we cannot mix a compiled class with an emulated class in the inheritance
302  Warning("XmlReadAny", "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
303  cl->GetName(), expectedClass->GetName());
304  }
305  }
306 
307  return ((char *)res) + delta;
308 }