Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TSQLStructure.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 TSQLStructure
14 \ingroup IO
15 This is hierarchical structure, which is created when data is written
16 by TBufferSQL2. It contains data all structural information such:
17 version of written class, data member types of that class, value for
18 each data member and so on.
19 Such structure in some sense similar to XML node and subnodes structure
20 Once it created, it converted to SQL statements, which are submitted
21 to database server.
22 */
23 
24 #include "TSQLStructure.h"
25 
26 #include "Riostream.h"
27 #include "TMap.h"
28 #include "TClass.h"
29 #include "TStreamerInfo.h"
30 #include "TStreamerElement.h"
31 #include "TObjString.h"
32 #include "TClonesArray.h"
33 
34 #include "TSQLFile.h"
35 #include "TSQLClassInfo.h"
36 #include "TSQLObjectData.h"
37 #include "TBufferSQL2.h"
38 
39 #include "TSQLStatement.h"
40 #include "TSQLServer.h"
41 #include "TDataType.h"
42 
43 namespace sqlio {
44 const Int_t Ids_NullPtr = 0; // used to identify NULL pointer in tables
45 const Int_t Ids_RootDir = 0; // dir:id, used for keys stored in root directory.
46 const Int_t Ids_TSQLFile = 0; // keyid for TSQLFile entry in keys list
47 const Int_t Ids_StreamerInfos = 1; // keyid used to store StreamerInfos in ROOT directory
48 const Int_t Ids_FirstKey = 10; // first key id, which is used in KeysTable (beside streamer info or something else)
49 const Int_t Ids_FirstObject = 1; // first object id, allowed in object tables
50 
51 const char *ObjectRef = "ObjectRef";
52 const char *ObjectRef_Arr = "ObjectRefArr";
53 const char *ObjectPtr = "ObjectPtr";
54 const char *ObjectInst = "ObjectInst";
55 const char *Version = "Version";
56 const char *TObjectUniqueId = "UniqueId";
57 const char *TObjectBits = "Bits";
58 const char *TObjectProcessId = "ProcessId";
59 const char *TStringValue = "StringValue";
60 const char *IndexSepar = "..";
61 const char *RawSuffix = ":rawdata";
62 const char *ParentSuffix = ":parent";
63 const char *ObjectSuffix = ":object";
64 const char *PointerSuffix = ":pointer";
65 const char *StrSuffix = ":str";
66 const char *LongStrPrefix = "#~#";
67 
68 const char *Array = "Array";
69 const char *Bool = "Bool_t";
70 const char *Char = "Char_t";
71 const char *Short = "Short_t";
72 const char *Int = "Int_t";
73 const char *Long = "Long_t";
74 const char *Long64 = "Long64_t";
75 const char *Float = "Float_t";
76 const char *Double = "Double_t";
77 const char *UChar = "UChar_t";
78 const char *UShort = "UShort_t";
79 const char *UInt = "UInt_t";
80 const char *ULong = "ULong_t";
81 const char *ULong64 = "ULong64_t";
82 const char *CharStar = "CharStar";
83 const char *True = "1";
84 const char *False = "0";
85 
86 // standard tables names
87 const char *KeysTable = "KeysTable";
88 const char *KeysTableIndex = "KeysTableIndex";
89 const char *ObjectsTable = "ObjectsTable";
90 const char *ObjectsTableIndex = "ObjectsTableIndex";
91 const char *IdsTable = "IdsTable";
92 const char *IdsTableIndex = "IdsTableIndex";
93 const char *StringsTable = "StringsTable";
94 const char *ConfigTable = "Configurations";
95 
96 // columns in Keys table
97 const char *KT_Name = "Name";
98 const char *KT_Title = "Title";
99 const char *KT_Datetime = "Datime";
100 const char *KT_Cycle = "Cycle";
101 const char *KT_Class = "Class";
102 
103 const char *DT_Create = "CreateDatime";
104 const char *DT_Modified = "ModifiedDatime";
105 const char *DT_UUID = "UUID";
106 
107 // columns in Objects table
108 const char *OT_Class = "Class";
109 const char *OT_Version = "Version";
110 
111 // columns in Identifiers Table
112 const char *IT_TableID = "TableId";
113 const char *IT_SubID = "SubId";
114 const char *IT_Type = "Type";
115 const char *IT_FullName = "FullName";
116 const char *IT_SQLName = "SQLName";
117 const char *IT_Info = "Info";
118 
119 // colummns in _streamer_ tables
120 const char *BT_Field = "Field";
121 const char *BT_Value = "Value";
122 
123 // colummns in string table
124 const char *ST_Value = "LongStringValue";
125 
126 // columns in config table
127 const char *CT_Field = "Field";
128 const char *CT_Value = "Value";
129 
130 // values in config table
131 const char *cfg_Version = "SQL_IO_version";
132 const char *cfg_UseSufixes = "UseNameSuffix";
133 const char *cfg_ArrayLimit = "ArraySizeLimit";
134 const char *cfg_TablesType = "TablesType";
135 const char *cfg_UseTransactions = "UseTransactions";
136 const char *cfg_UseIndexes = "UseIndexes";
137 const char *cfg_LockingMode = "LockingMode";
138 const char *cfg_ModifyCounter = "ModifyCounter";
139 };
140 
141 //________________________________________________________________________
142 
143 Long64_t sqlio::atol64(const char *value)
144 {
145  if (!value || (*value == 0))
146  return 0;
147  return TString(value).Atoll();
148 }
149 
150 /**
151 \class TSQLColumnData
152 \ingroup IO
153 */
154 
155 ClassImp(TSQLColumnData);
156 
157 ////////////////////////////////////////////////////////////////////////////////
158 /// normal constructor of TSQLColumnData class
159 /// specifies name, type and value for one column
160 
161 TSQLColumnData::TSQLColumnData(const char *name, const char *sqltype, const char *value, Bool_t numeric)
162  : TObject(), fName(name), fType(sqltype), fValue(value), fNumeric(numeric)
163 {
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// constructs TSQLColumnData object for integer column
168 
169 TSQLColumnData::TSQLColumnData(const char *name, Long64_t value)
170  : TObject(), fName(name), fType("INT"), fValue(), fNumeric(kTRUE)
171 {
172  fValue.Form("%lld", value);
173 }
174 
175 ClassImp(TSQLTableData);
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// normal constructor
179 
180 TSQLTableData::TSQLTableData(TSQLFile *f, TSQLClassInfo *info)
181  : TObject(), fFile(f), fInfo(info)
182 {
183  if (info && !info->IsClassTableExist())
184  fColInfos = new TObjArray;
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// destructor
189 
190 TSQLTableData::~TSQLTableData()
191 {
192  fColumns.Delete();
193  if (fColInfos) {
194  fColInfos->Delete();
195  delete fColInfos;
196  }
197 }
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Add INT column to list of columns
201 
202 void TSQLTableData::AddColumn(const char *name, Long64_t value)
203 {
204  TObjString *v = new TObjString(Form("%lld", value));
205  v->SetBit(BIT(20), kTRUE);
206  fColumns.Add(v);
207 
208  // TSQLColumnData* col = new TSQLColumnData(name, value);
209  // fColumns.Add(col);
210 
211  if (fColInfos)
212  fColInfos->Add(new TSQLClassColumnInfo(name, DefineSQLName(name), "INT"));
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Add normal column to list of columns
217 
218 void TSQLTableData::AddColumn(const char *name, const char *sqltype, const char *value, Bool_t numeric)
219 {
220  TObjString *v = new TObjString(value);
221  v->SetBit(BIT(20), numeric);
222  fColumns.Add(v);
223 
224  // TSQLColumnData* col = new TSQLColumnData(name, sqltype, value, numeric);
225  // fColumns.Add(col);
226 
227  if (fColInfos != 0)
228  fColInfos->Add(new TSQLClassColumnInfo(name, DefineSQLName(name), sqltype));
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// produce suitable name for column, taking into account length limitation
233 
234 TString TSQLTableData::DefineSQLName(const char *fullname)
235 {
236  Int_t maxlen = fFile->SQLMaxIdentifierLength();
237 
238  Int_t len = strlen(fullname);
239 
240  if ((len <= maxlen) && !HasSQLName(fullname))
241  return TString(fullname);
242 
243  Int_t cnt = -1;
244  TString res, scnt;
245 
246  do {
247 
248  scnt.Form("%d", cnt);
249  Int_t numlen = cnt < 0 ? 0 : scnt.Length();
250 
251  res = fullname;
252 
253  if (len + numlen > maxlen)
254  res.Resize(maxlen - numlen);
255 
256  if (cnt >= 0)
257  res += scnt;
258 
259  if (!HasSQLName(res.Data()))
260  return res;
261 
262  cnt++;
263 
264  } while (cnt < 10000);
265 
266  Error("DefineSQLName", "Cannot find reasonable column name for field %s", fullname);
267 
268  return TString(fullname);
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// checks if columns list already has that sql name
273 
274 Bool_t TSQLTableData::HasSQLName(const char *sqlname)
275 {
276  TIter next(fColInfos);
277 
278  TSQLClassColumnInfo *col = nullptr;
279 
280  while ((col = (TSQLClassColumnInfo *)next()) != nullptr) {
281  const char *colname = col->GetSQLName();
282  if (strcmp(colname, sqlname) == 0)
283  return kTRUE;
284  }
285 
286  return kFALSE;
287 }
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// returns number of columns in provided set
291 
292 Int_t TSQLTableData::GetNumColumns()
293 {
294  return fColumns.GetLast() + 1;
295 }
296 
297 ////////////////////////////////////////////////////////////////////////////////
298 /// return column value
299 
300 const char *TSQLTableData::GetColumn(Int_t n)
301 {
302  return fColumns[n]->GetName();
303 }
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// identifies if column has numeric value
307 
308 Bool_t TSQLTableData::IsNumeric(Int_t n)
309 {
310  return fColumns[n]->TestBit(BIT(20));
311 }
312 
313 ////////////////////////////////////////////////////////////////////////////////
314 /// take ownership over colinfos
315 
316 TObjArray *TSQLTableData::TakeColInfos()
317 {
318  TObjArray *res = fColInfos;
319  fColInfos = nullptr;
320  return res;
321 }
322 
323 //________________________________________________________________________
324 
325 ClassImp(TSQLStructure);
326 
327 ////////////////////////////////////////////////////////////////////////////////
328 /// destructor
329 
330 TSQLStructure::~TSQLStructure()
331 {
332  fChilds.Delete();
333  if (GetType() == kSqlObjectData) {
334  TSQLObjectData *objdata = (TSQLObjectData *)fPointer;
335  delete objdata;
336  } else if (GetType() == kSqlCustomElement) {
337  TStreamerElement *elem = (TStreamerElement *)fPointer;
338  delete elem;
339  }
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// number of child structures
344 
345 Int_t TSQLStructure::NumChilds() const
346 {
347  return fChilds.GetLast() + 1;
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// return child structure of index n
352 
353 TSQLStructure *TSQLStructure::GetChild(Int_t n) const
354 {
355  return (n < 0) || (n > fChilds.GetLast()) ? 0 : (TSQLStructure *)fChilds[n];
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// set structure type as kSqlObject
360 
361 void TSQLStructure::SetObjectRef(Long64_t refid, const TClass *cl)
362 {
363  fType = kSqlObject;
364  fValue.Form("%lld", refid);
365  fPointer = cl;
366 }
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 /// set structure type as kSqlPointer
370 
371 void TSQLStructure::SetObjectPointer(Long64_t ptrid)
372 {
373  fType = kSqlPointer;
374  fValue.Form("%lld", ptrid);
375 }
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 /// set structure type as kSqlVersion
379 
380 void TSQLStructure::SetVersion(const TClass *cl, Int_t version)
381 {
382  fType = kSqlVersion;
383  fPointer = cl;
384  if (version < 0)
385  version = cl->GetClassVersion();
386  fValue.Form("%d", version);
387 }
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// set structure type as kSqlClassStreamer
391 
392 void TSQLStructure::SetClassStreamer(const TClass *cl)
393 {
394  fType = kSqlClassStreamer;
395  fPointer = cl;
396 }
397 
398 ////////////////////////////////////////////////////////////////////////////////
399 /// set structure type as kSqlStreamerInfo
400 
401 void TSQLStructure::SetStreamerInfo(const TStreamerInfo *info)
402 {
403  fType = kSqlStreamerInfo;
404  fPointer = info;
405 }
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 /// set structure type as kSqlElement
409 
410 void TSQLStructure::SetStreamerElement(const TStreamerElement *elem, Int_t number)
411 {
412  fType = kSqlElement;
413  fPointer = elem;
414  fArrayIndex = number;
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// set structure type as kSqlCustomClass
419 
420 void TSQLStructure::SetCustomClass(const TClass *cl, Version_t version)
421 {
422  fType = kSqlCustomClass;
423  fPointer = (void *)cl;
424  fArrayIndex = version;
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// set structure type as kSqlCustomElement
429 
430 void TSQLStructure::SetCustomElement(TStreamerElement *elem)
431 {
432  fType = kSqlCustomElement;
433  fPointer = elem;
434 }
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// set structure type as kSqlValue
438 
439 void TSQLStructure::SetValue(const char *value, const char *tname)
440 {
441  fType = kSqlValue;
442  fValue = value;
443  fPointer = tname;
444 }
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 /// change value of this structure
448 /// used as "workaround" to keep object id in kSqlElement node
449 
450 void TSQLStructure::ChangeValueOnly(const char *value)
451 {
452  fValue = value;
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// set array index for this structure
457 
458 void TSQLStructure::SetArrayIndex(Int_t indx, Int_t cnt)
459 {
460  fArrayIndex = indx;
461  fRepeatCnt = cnt;
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// set array index for last child element
466 /// if (cnt<=1) return;
467 
468 void TSQLStructure::ChildArrayIndex(Int_t index, Int_t cnt)
469 {
470  TSQLStructure *last = (TSQLStructure *)fChilds.Last();
471  if ((last != 0) && (last->GetType() == kSqlValue))
472  last->SetArrayIndex(index, cnt);
473 }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// Set structure as array element
477 
478 void TSQLStructure::SetArray(Int_t sz)
479 {
480  fType = kSqlArray;
481  if (sz >= 0)
482  fValue.Form("%d", sz);
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// return object class if type kSqlObject
487 
488 TClass *TSQLStructure::GetObjectClass() const
489 {
490  return (fType == kSqlObject) ? (TClass *)fPointer : nullptr;
491 }
492 
493 ////////////////////////////////////////////////////////////////////////////////
494 /// return class for version tag if type is kSqlVersion
495 
496 TClass *TSQLStructure::GetVersionClass() const
497 {
498  return (fType == kSqlVersion) ? (TClass *)fPointer : nullptr;
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 /// return TStreamerInfo* if type is kSqlStreamerInfo
503 
504 TStreamerInfo *TSQLStructure::GetStreamerInfo() const
505 {
506  return (fType == kSqlStreamerInfo) ? (TStreamerInfo *)fPointer : nullptr;
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// return TStremerElement* if type is kSqlElement
511 
512 TStreamerElement *TSQLStructure::GetElement() const
513 {
514  return (fType == kSqlElement) || (fType == kSqlCustomElement) ? (TStreamerElement *)fPointer : nullptr;
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 /// returns number of TStremerElement in TStreamerInfo
519 
520 Int_t TSQLStructure::GetElementNumber() const
521 {
522  return (fType == kSqlElement) ? fArrayIndex : 0;
523 }
524 
525 ////////////////////////////////////////////////////////////////////////////////
526 /// return value type if structure is kSqlValue
527 
528 const char *TSQLStructure::GetValueType() const
529 {
530  return (fType == kSqlValue) ? (const char *)fPointer : nullptr;
531 }
532 
533 ////////////////////////////////////////////////////////////////////////////////
534 /// return element custom class if structures is kSqlCustomClass
535 
536 TClass *TSQLStructure::GetCustomClass() const
537 {
538  return (fType == kSqlCustomClass) ? (TClass *)fPointer : nullptr;
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 /// return custom class version if structures is kSqlCustomClass
543 
544 Version_t TSQLStructure::GetCustomClassVersion() const
545 {
546  return (fType == kSqlCustomClass) ? fArrayIndex : 0;
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 /// provides class info if structure kSqlStreamerInfo or kSqlCustomClass
551 
552 Bool_t TSQLStructure::GetClassInfo(TClass *&cl, Version_t &version)
553 {
554  if (GetType() == kSqlStreamerInfo) {
555  TStreamerInfo *info = GetStreamerInfo();
556  if (!info)
557  return kFALSE;
558  cl = info->GetClass();
559  version = info->GetClassVersion();
560  } else if (GetType() == kSqlCustomClass) {
561  cl = GetCustomClass();
562  version = GetCustomClassVersion();
563  } else
564  return kFALSE;
565  return kTRUE;
566 }
567 
568 ////////////////////////////////////////////////////////////////////////////////
569 /// returns value
570 /// for different structure kinds has different sense
571 /// For kSqlVersion it version, for kSqlReference it is object id and so on
572 
573 const char *TSQLStructure::GetValue() const
574 {
575  return fValue.Data();
576 }
577 
578 ////////////////////////////////////////////////////////////////////////////////
579 /// Add child structure
580 
581 void TSQLStructure::Add(TSQLStructure *child)
582 {
583  if (child) {
584  child->SetParent(this);
585  fChilds.Add(child);
586  }
587 }
588 
589 ////////////////////////////////////////////////////////////////////////////////
590 /// add child as version
591 
592 void TSQLStructure::AddVersion(const TClass *cl, Int_t version)
593 {
594  TSQLStructure *ver = new TSQLStructure;
595  ver->SetVersion(cl, version);
596  Add(ver);
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// Add child structure as value
601 
602 void TSQLStructure::AddValue(const char *value, const char *tname)
603 {
604  TSQLStructure *child = new TSQLStructure;
605  child->SetValue(value, tname);
606  Add(child);
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// defines current object id, to which this structure belong
611 /// make life complicated, because some objects do not get id
612 /// automatically in TBufferSQL, but afterwards
613 
614 Long64_t TSQLStructure::DefineObjectId(Bool_t recursive)
615 {
616  TSQLStructure *curr = this;
617  while (curr) {
618  if ((curr->GetType() == kSqlObject) || (curr->GetType() == kSqlPointer) ||
619  // workaround to store object id in element structure
620  (curr->GetType() == kSqlElement) || (curr->GetType() == kSqlCustomElement) ||
621  (curr->GetType() == kSqlCustomClass) || (curr->GetType() == kSqlStreamerInfo)) {
622  const char *value = curr->GetValue();
623  if (value && (strlen(value) > 0))
624  return sqlio::atol64(value);
625  }
626 
627  curr = recursive ? curr->GetParent() : nullptr;
628  }
629  return -1;
630 }
631 
632 ////////////////////////////////////////////////////////////////////////////////
633 /// set element to be used for object data
634 
635 void TSQLStructure::SetObjectData(TSQLObjectData *objdata)
636 {
637  fType = kSqlObjectData;
638  fPointer = objdata;
639 }
640 
641 ////////////////////////////////////////////////////////////////////////////////
642 /// add element with pointer to object data
643 
644 void TSQLStructure::AddObjectData(TSQLObjectData *objdata)
645 {
646  TSQLStructure *child = new TSQLStructure;
647  child->SetObjectData(objdata);
648  Add(child);
649 }
650 
651 ////////////////////////////////////////////////////////////////////////////////
652 /// searches for objects data
653 
654 TSQLObjectData *TSQLStructure::GetObjectData(Bool_t search)
655 {
656  TSQLStructure *child = GetChild(0);
657  if ((child != 0) && (child->GetType() == kSqlObjectData))
658  return (TSQLObjectData *)child->fPointer;
659  if (search && GetParent())
660  return GetParent()->GetObjectData(search);
661  return 0;
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 /// print content of complete structure
666 
667 void TSQLStructure::Print(Option_t *) const
668 {
669  PrintLevel(0);
670 }
671 
672 ////////////////////////////////////////////////////////////////////////////////
673 /// print content of current structure
674 
675 void TSQLStructure::PrintLevel(Int_t level) const
676 {
677  for (Int_t n = 0; n < level; n++)
678  std::cout << " ";
679  switch (fType) {
680  case 0: std::cout << "Undefined type"; break;
681  case kSqlObject: std::cout << "Object ref = " << fValue; break;
682  case kSqlPointer: std::cout << "Pointer ptr = " << fValue; break;
683  case kSqlVersion: {
684  const TClass *cl = (const TClass *)fPointer;
685  std::cout << "Version cl = " << cl->GetName() << " ver = " << cl->GetClassVersion();
686  break;
687  }
688  case kSqlStreamerInfo: {
689  const TStreamerInfo *info = (const TStreamerInfo *)fPointer;
690  std::cout << "Class: " << info->GetName();
691  break;
692  }
693  case kSqlCustomElement:
694  case kSqlElement: {
695  const TStreamerElement *elem = (const TStreamerElement *)fPointer;
696  std::cout << "Member: " << elem->GetName();
697  break;
698  }
699  case kSqlValue: {
700  std::cout << "Value: " << fValue;
701  if (fRepeatCnt > 1)
702  std::cout << " cnt:" << fRepeatCnt;
703  if (fPointer != 0)
704  std::cout << " type = " << (const char *)fPointer;
705  break;
706  }
707  case kSqlArray: {
708  std::cout << "Array ";
709  if (fValue.Length() > 0)
710  std::cout << " sz = " << fValue;
711  break;
712  }
713  case kSqlCustomClass: {
714  TClass *cl = (TClass *)fPointer;
715  std::cout << "CustomClass: " << cl->GetName() << " ver = " << fValue;
716  break;
717  }
718  default: std::cout << "Unknown type";
719  }
720  std::cout << std::endl;
721 
722  for (Int_t n = 0; n < NumChilds(); n++)
723  GetChild(n)->PrintLevel(level + 2);
724 }
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// defines if value is numeric and not requires quotes when writing
728 
729 Bool_t TSQLStructure::IsNumericType(Int_t typ)
730 {
731  switch (typ) {
732  case TStreamerInfo::kShort: return kTRUE;
733  case TStreamerInfo::kInt: return kTRUE;
734  case TStreamerInfo::kLong: return kTRUE;
735  case TStreamerInfo::kFloat: return kTRUE;
736  case TStreamerInfo::kFloat16: return kTRUE;
737  case TStreamerInfo::kCounter: return kTRUE;
738  case TStreamerInfo::kDouble: return kTRUE;
739  case TStreamerInfo::kDouble32: return kTRUE;
740  case TStreamerInfo::kUChar: return kTRUE;
741  case TStreamerInfo::kUShort: return kTRUE;
742  case TStreamerInfo::kUInt: return kTRUE;
743  case TStreamerInfo::kULong: return kTRUE;
744  case TStreamerInfo::kBits: return kTRUE;
745  case TStreamerInfo::kLong64: return kTRUE;
746  case TStreamerInfo::kULong64: return kTRUE;
747  case TStreamerInfo::kBool: return kTRUE;
748  }
749  return kFALSE;
750 }
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 /// provides name for basic types
754 /// used as suffix for column name or field suffix in raw table
755 
756 const char *TSQLStructure::GetSimpleTypeName(Int_t typ)
757 {
758  switch (typ) {
759  case TStreamerInfo::kChar: return sqlio::Char;
760  case TStreamerInfo::kShort: return sqlio::Short;
761  case TStreamerInfo::kInt: return sqlio::Int;
762  case TStreamerInfo::kLong: return sqlio::Long;
763  case TStreamerInfo::kFloat: return sqlio::Float;
764  case TStreamerInfo::kFloat16: return sqlio::Float;
765  case TStreamerInfo::kCounter: return sqlio::Int;
766  case TStreamerInfo::kDouble: return sqlio::Double;
767  case TStreamerInfo::kDouble32: return sqlio::Double;
768  case TStreamerInfo::kUChar: return sqlio::UChar;
769  case TStreamerInfo::kUShort: return sqlio::UShort;
770  case TStreamerInfo::kUInt: return sqlio::UInt;
771  case TStreamerInfo::kULong: return sqlio::ULong;
772  case TStreamerInfo::kBits: return sqlio::UInt;
773  case TStreamerInfo::kLong64: return sqlio::Long64;
774  case TStreamerInfo::kULong64: return sqlio::ULong64;
775  case TStreamerInfo::kBool: return sqlio::Bool;
776  }
777 
778  return 0;
779 }
780 
781 //___________________________________________________________
782 
783 // TSqlCmdsBuffer used as buffer for data, which are correspond to
784 // particular class, defined by TSQLClassInfo instance
785 // Support both TSQLStatement and Query modes
786 
787 class TSqlCmdsBuffer : public TObject {
788 
789 public:
790  TSqlCmdsBuffer(TSQLFile *f, TSQLClassInfo *info) : TObject(), fFile(f), fInfo(info), fBlobStmt(0), fNormStmt(0) {}
791 
792  virtual ~TSqlCmdsBuffer()
793  {
794  fNormCmds.Delete();
795  fBlobCmds.Delete();
796  fFile->SQLDeleteStatement(fBlobStmt);
797  fFile->SQLDeleteStatement(fNormStmt);
798  }
799 
800  void AddValues(Bool_t isnorm, const char *values)
801  {
802  TObjString *str = new TObjString(values);
803  if (isnorm)
804  fNormCmds.Add(str);
805  else
806  fBlobCmds.Add(str);
807  }
808 
809  TSQLFile *fFile;
810  TSQLClassInfo *fInfo;
811  TObjArray fNormCmds;
812  TObjArray fBlobCmds;
813  TSQLStatement *fBlobStmt;
814  TSQLStatement *fNormStmt;
815 };
816 
817 //________________________________________________________________________
818 // TSqlRegistry keeps data, used when object data transformed to sql query or
819 // statements
820 
821 class TSqlRegistry : public TObject {
822 
823 public:
824  TSqlRegistry()
825  : TObject(), fFile(0), fKeyId(0), fLastObjId(-1), fCmds(0), fFirstObjId(0), fCurrentObjId(0), fCurrentObjClass(0),
826  fLastLongStrId(0), fPool(), fLongStrValues(), fRegValues(), fRegStmt(0)
827  {
828  }
829 
830  TSQLFile *fFile;
831  Long64_t fKeyId;
832  Long64_t fLastObjId;
833  TObjArray *fCmds;
834  Long64_t fFirstObjId;
835 
836  Long64_t fCurrentObjId;
837  TClass *fCurrentObjClass;
838 
839  Int_t fLastLongStrId;
840 
841  TMap fPool;
842  TObjArray fLongStrValues;
843  TObjArray fRegValues;
844 
845  TSQLStatement *fRegStmt;
846 
847  virtual ~TSqlRegistry()
848  {
849  fPool.DeleteValues();
850  fLongStrValues.Delete();
851  fRegValues.Delete();
852  fFile->SQLDeleteStatement(fRegStmt);
853  }
854 
855  Long64_t GetNextObjId() { return ++fLastObjId; }
856 
857  void AddSqlCmd(const char *query)
858  {
859  // add SQL command to the list
860  if (fCmds == 0)
861  fCmds = new TObjArray;
862  fCmds->Add(new TObjString(query));
863  }
864 
865  TSqlCmdsBuffer *GetCmdsBuffer(TSQLClassInfo *sqlinfo)
866  {
867  if (sqlinfo == 0)
868  return 0;
869  TSqlCmdsBuffer *buf = (TSqlCmdsBuffer *)fPool.GetValue(sqlinfo);
870  if (buf == 0) {
871  buf = new TSqlCmdsBuffer(fFile, sqlinfo);
872  fPool.Add(sqlinfo, buf);
873  }
874  return buf;
875  }
876 
877  void ConvertSqlValues(TObjArray &values, const char *tablename)
878  {
879  // this function transforms array of values for one table
880  // to SQL command. For MySQL one INSERT query can
881  // contain data for more than one row
882 
883  if ((values.GetLast() < 0) || (tablename == 0))
884  return;
885 
886  Bool_t canbelong = fFile->IsMySQL();
887 
888  Int_t maxsize = 50000;
889  TString sqlcmd(maxsize), value, onecmd, cmdmask;
890 
891  const char *quote = fFile->SQLIdentifierQuote();
892 
893  TIter iter(&values);
894  TObject *cmd = 0;
895  while ((cmd = iter()) != 0) {
896 
897  if (sqlcmd.Length() == 0)
898  sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s)", quote, tablename, quote, cmd->GetName());
899  else {
900  sqlcmd += ", (";
901  sqlcmd += cmd->GetName();
902  sqlcmd += ")";
903  }
904 
905  if (!canbelong || (sqlcmd.Length() > maxsize * 0.9)) {
906  AddSqlCmd(sqlcmd.Data());
907  sqlcmd = "";
908  }
909  }
910 
911  if (sqlcmd.Length() > 0)
912  AddSqlCmd(sqlcmd.Data());
913  }
914 
915  void ConvertPoolValues()
916  {
917  TSQLClassInfo *sqlinfo = 0;
918  TIter iter(&fPool);
919  while ((sqlinfo = (TSQLClassInfo *)iter()) != 0) {
920  TSqlCmdsBuffer *buf = (TSqlCmdsBuffer *)fPool.GetValue(sqlinfo);
921  if (buf == 0)
922  continue;
923  ConvertSqlValues(buf->fNormCmds, sqlinfo->GetClassTableName());
924  // ensure that raw table will be created
925  if (buf->fBlobCmds.GetLast() >= 0)
926  fFile->CreateRawTable(sqlinfo);
927  ConvertSqlValues(buf->fBlobCmds, sqlinfo->GetRawTableName());
928  if (buf->fBlobStmt)
929  buf->fBlobStmt->Process();
930  if (buf->fNormStmt)
931  buf->fNormStmt->Process();
932  }
933 
934  ConvertSqlValues(fLongStrValues, sqlio::StringsTable);
935  ConvertSqlValues(fRegValues, sqlio::ObjectsTable);
936  if (fRegStmt)
937  fRegStmt->Process();
938  }
939 
940  void AddRegCmd(Long64_t objid, TClass *cl)
941  {
942  Long64_t indx = objid - fFirstObjId;
943  if (indx < 0) {
944  Error("AddRegCmd", "Something wrong with objid = %lld", objid);
945  return;
946  }
947 
948  if (fFile->IsOracle() || fFile->IsODBC()) {
949  if ((fRegStmt == 0) && fFile->SQLCanStatement()) {
950  const char *quote = fFile->SQLIdentifierQuote();
951 
952  TString sqlcmd;
953  const char *pars = fFile->IsOracle() ? ":1, :2, :3, :4" : "?, ?, ?, ?";
954  sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s)", quote, sqlio::ObjectsTable, quote, pars);
955  fRegStmt = fFile->SQLStatement(sqlcmd.Data(), 1000);
956  }
957 
958  if (fRegStmt != 0) {
959  fRegStmt->NextIteration();
960  fRegStmt->SetLong64(0, fKeyId);
961  fRegStmt->SetLong64(1, objid);
962  fRegStmt->SetString(2, cl->GetName(), fFile->SQLSmallTextTypeLimit());
963  fRegStmt->SetInt(3, cl->GetClassVersion());
964  return;
965  }
966  }
967 
968  const char *valuequote = fFile->SQLValueQuote();
969  TString cmd;
970  cmd.Form("%lld, %lld, %s%s%s, %d", fKeyId, objid, valuequote, cl->GetName(), valuequote, cl->GetClassVersion());
971  fRegValues.AddAtAndExpand(new TObjString(cmd), indx);
972  }
973 
974  Int_t AddLongString(const char *strvalue)
975  {
976  // add value to special string table,
977  // where large (more than 255 bytes) strings are stored
978 
979  if (fLastLongStrId == 0)
980  fFile->VerifyLongStringTable();
981  Int_t strid = ++fLastLongStrId;
982  TString value = strvalue;
983  const char *valuequote = fFile->SQLValueQuote();
984  TSQLStructure::AddStrBrackets(value, valuequote);
985 
986  TString cmd;
987  cmd.Form("%lld, %d, %s", fCurrentObjId, strid, value.Data());
988 
989  fLongStrValues.Add(new TObjString(cmd));
990 
991  return strid;
992  }
993 
994  Bool_t InsertToNormalTableOracle(TSQLTableData *columns, TSQLClassInfo *sqlinfo)
995  {
996  TSqlCmdsBuffer *buf = GetCmdsBuffer(sqlinfo);
997  if (buf == 0)
998  return kFALSE;
999 
1000  TSQLStatement *stmt = buf->fNormStmt;
1001  if (stmt == 0) {
1002  // if one cannot create statement, do it normal way
1003  if (!fFile->SQLCanStatement())
1004  return kFALSE;
1005 
1006  const char *quote = fFile->SQLIdentifierQuote();
1007  TString sqlcmd;
1008  sqlcmd.Form("INSERT INTO %s%s%s VALUES (", quote, sqlinfo->GetClassTableName(), quote);
1009  for (int n = 0; n < columns->GetNumColumns(); n++) {
1010  if (n > 0)
1011  sqlcmd += ", ";
1012  if (fFile->IsOracle()) {
1013  sqlcmd += ":";
1014  sqlcmd += (n + 1);
1015  } else
1016  sqlcmd += "?";
1017  }
1018  sqlcmd += ")";
1019 
1020  stmt = fFile->SQLStatement(sqlcmd.Data(), 1000);
1021  if (stmt == 0)
1022  return kFALSE;
1023  buf->fNormStmt = stmt;
1024  }
1025 
1026  stmt->NextIteration();
1027 
1028  Int_t sizelimit = fFile->SQLSmallTextTypeLimit();
1029 
1030  for (Int_t ncol = 0; ncol < columns->GetNumColumns(); ncol++) {
1031  const char *value = columns->GetColumn(ncol);
1032  if (value == 0)
1033  value = "";
1034  stmt->SetString(ncol, value, sizelimit);
1035  }
1036 
1037  return kTRUE;
1038  }
1039 
1040  void InsertToNormalTable(TSQLTableData *columns, TSQLClassInfo *sqlinfo)
1041  {
1042  // produce SQL query to insert object data into normal table
1043 
1044  if (fFile->IsOracle() || fFile->IsODBC())
1045  if (InsertToNormalTableOracle(columns, sqlinfo))
1046  return;
1047 
1048  const char *valuequote = fFile->SQLValueQuote();
1049 
1050  TString values;
1051 
1052  for (Int_t n = 0; n < columns->GetNumColumns(); n++) {
1053  if (n > 0)
1054  values += ", ";
1055 
1056  if (columns->IsNumeric(n))
1057  values += columns->GetColumn(n);
1058  else {
1059  TString value = columns->GetColumn(n);
1060  TSQLStructure::AddStrBrackets(value, valuequote);
1061  values += value;
1062  }
1063  }
1064 
1065  TSqlCmdsBuffer *buf = GetCmdsBuffer(sqlinfo);
1066  if (buf != 0)
1067  buf->AddValues(kTRUE, values.Data());
1068  }
1069 };
1070 
1071 //_____________________________________________________________________________
1072 
1073 // TSqlRawBuffer is used to convert raw data, which corresponds to one
1074 // object and belong to single SQL tables. Supports both statements
1075 // and query mode
1076 
1077 class TSqlRawBuffer : public TObject {
1078 
1079 public:
1080  TSqlRawBuffer(TSqlRegistry *reg, TSQLClassInfo *sqlinfo)
1081  : TObject(), fFile(0), fInfo(0), fCmdBuf(0), fObjId(0), fRawId(0), fValueMask(), fValueQuote(0), fMaxStrSize(255)
1082  {
1083  fFile = reg->fFile;
1084  fInfo = sqlinfo;
1085  fCmdBuf = reg->GetCmdsBuffer(sqlinfo);
1086  fObjId = reg->fCurrentObjId;
1087  fValueQuote = fFile->SQLValueQuote();
1088  fValueMask.Form("%lld, %s, %s%s%s, %s", fObjId, "%d", fValueQuote, "%s", fValueQuote, "%s");
1089  fMaxStrSize = reg->fFile->SQLSmallTextTypeLimit();
1090  }
1091 
1092  virtual ~TSqlRawBuffer()
1093  {
1094  // close blob statement for Oracle
1095  TSQLStatement *stmt = fCmdBuf->fBlobStmt;
1096  if ((stmt != 0) && fFile->IsOracle()) {
1097  stmt->Process();
1098  delete stmt;
1099  fCmdBuf->fBlobStmt = 0;
1100  }
1101  }
1102 
1103  Bool_t IsAnyData() const { return fRawId > 0; }
1104 
1105  void AddLine(const char *name, const char *value, const char *topname = 0, const char *ns = 0)
1106  {
1107  if (fCmdBuf == 0)
1108  return;
1109 
1110  // when first line is created, check all problems
1111  if (fRawId == 0) {
1112  Bool_t maketmt = kFALSE;
1113  if (fFile->IsOracle() || fFile->IsODBC())
1114  maketmt = (fCmdBuf->fBlobStmt == 0) && fFile->SQLCanStatement();
1115 
1116  if (maketmt) {
1117  // ensure that raw table is exists
1118  fFile->CreateRawTable(fInfo);
1119 
1120  const char *quote = fFile->SQLIdentifierQuote();
1121  TString sqlcmd;
1122  const char *params = fFile->IsOracle() ? ":1, :2, :3, :4" : "?, ?, ?, ?";
1123  sqlcmd.Form("INSERT INTO %s%s%s VALUES (%s)", quote, fInfo->GetRawTableName(), quote, params);
1124  TSQLStatement *stmt = fFile->SQLStatement(sqlcmd.Data(), 2000);
1125  fCmdBuf->fBlobStmt = stmt;
1126  }
1127  }
1128 
1129  TString buf;
1130  const char *fullname = name;
1131  if ((topname != 0) && (ns != 0)) {
1132  buf += topname;
1133  buf += ns;
1134  buf += name;
1135  fullname = buf.Data();
1136  }
1137 
1138  TSQLStatement *stmt = fCmdBuf->fBlobStmt;
1139 
1140  if (stmt != 0) {
1141  stmt->NextIteration();
1142  stmt->SetLong64(0, fObjId);
1143  stmt->SetInt(1, fRawId++);
1144  stmt->SetString(2, fullname, fMaxStrSize);
1145  // Info("AddLine","name = %s value = %s",fullname, value);
1146  stmt->SetString(3, value, fMaxStrSize);
1147  } else {
1148  TString valuebuf(value);
1149  TSQLStructure::AddStrBrackets(valuebuf, fValueQuote);
1150  TString cmd;
1151  cmd.Form(fValueMask.Data(), fRawId++, fullname, valuebuf.Data());
1152  fCmdBuf->AddValues(kFALSE, cmd.Data());
1153  }
1154  }
1155 
1156  TSQLFile *fFile;
1157  TSQLClassInfo *fInfo;
1158  TSqlCmdsBuffer *fCmdBuf;
1159  Long64_t fObjId;
1160  Int_t fRawId;
1161  TString fValueMask;
1162  const char *fValueQuote;
1163  Int_t fMaxStrSize;
1164 };
1165 
1166 ////////////////////////////////////////////////////////////////////////////////
1167 /// define maximum reference id, used for objects
1168 
1169 Long64_t TSQLStructure::FindMaxObjectId()
1170 {
1171  Long64_t max = DefineObjectId(kFALSE);
1172 
1173  for (Int_t n = 0; n < NumChilds(); n++) {
1174  Long64_t zn = GetChild(n)->FindMaxObjectId();
1175  if (zn > max)
1176  max = zn;
1177  }
1178 
1179  return max;
1180 }
1181 
1182 ////////////////////////////////////////////////////////////////////////////////
1183 /// Convert structure to sql statements
1184 /// This function is called immidiately after TBufferSQL2 produces
1185 /// this structure with object data
1186 /// Should be only called for toplevel structure
1187 
1188 Bool_t TSQLStructure::ConvertToTables(TSQLFile *file, Long64_t keyid, TObjArray *cmds)
1189 {
1190  if ((file == 0) || (cmds == 0))
1191  return kFALSE;
1192 
1193  TSqlRegistry reg;
1194 
1195  reg.fCmds = cmds;
1196  reg.fFile = file;
1197  reg.fKeyId = keyid;
1198  // this is id of main object to be stored
1199  reg.fFirstObjId = DefineObjectId(kFALSE);
1200  // this is maximum objectid which is now in use
1201  reg.fLastObjId = FindMaxObjectId();
1202 
1203  Bool_t res = StoreObject(&reg, reg.fFirstObjId, GetObjectClass());
1204 
1205  // convert values from pool to SQL commands
1206  reg.ConvertPoolValues();
1207 
1208  return res;
1209 }
1210 
1211 ////////////////////////////////////////////////////////////////////////////////
1212 /// perform conversion of structure to sql statements
1213 /// first tries convert it to normal form
1214 /// if fails, produces data for raw table
1215 
1216 void TSQLStructure::PerformConversion(TSqlRegistry *reg, TSqlRawBuffer *blobs, const char *topname, Bool_t useblob)
1217 {
1218  TString sbuf;
1219  const char *ns = reg->fFile->SQLNameSeparator();
1220 
1221  switch (fType) {
1222  case kSqlObject: {
1223 
1224  if (!StoreObject(reg, DefineObjectId(kFALSE), GetObjectClass()))
1225  break;
1226 
1227  blobs->AddLine(sqlio::ObjectRef, GetValue(), topname, ns);
1228 
1229  break;
1230  }
1231 
1232  case kSqlPointer: {
1233  blobs->AddLine(sqlio::ObjectPtr, fValue.Data(), topname, ns);
1234  break;
1235  }
1236 
1237  case kSqlVersion: {
1238  if (fPointer != 0)
1239  topname = ((TClass *)fPointer)->GetName();
1240  else
1241  Error("PerformConversion", "version without class");
1242  blobs->AddLine(sqlio::Version, fValue.Data(), topname, ns);
1243  break;
1244  }
1245 
1246  case kSqlStreamerInfo: {
1247 
1248  TStreamerInfo *info = GetStreamerInfo();
1249  if (info == 0)
1250  return;
1251 
1252  if (useblob) {
1253  for (Int_t n = 0; n <= fChilds.GetLast(); n++) {
1254  TSQLStructure *child = (TSQLStructure *)fChilds.At(n);
1255  child->PerformConversion(reg, blobs, info->GetName(), useblob);
1256  }
1257  } else {
1258  Long64_t objid = reg->GetNextObjId();
1259  TString sobjid;
1260  sobjid.Form("%lld", objid);
1261  if (!StoreObject(reg, objid, info->GetClass(), kTRUE))
1262  return;
1263  blobs->AddLine(sqlio::ObjectInst, sobjid.Data(), topname, ns);
1264  }
1265  break;
1266  }
1267 
1268  case kSqlCustomElement:
1269  case kSqlElement: {
1270  const TStreamerElement *elem = (const TStreamerElement *)fPointer;
1271 
1272  Int_t indx = 0;
1273  while (indx < NumChilds()) {
1274  TSQLStructure *child = GetChild(indx++);
1275  child->PerformConversion(reg, blobs, elem->GetName(), useblob);
1276  }
1277  break;
1278  }
1279 
1280  case kSqlValue: {
1281  const char *tname = (const char *)fPointer;
1282  if (fArrayIndex >= 0) {
1283  if (fRepeatCnt > 1)
1284  sbuf.Form("%s%d%s%d%s%s%s", "[", fArrayIndex, sqlio::IndexSepar, fArrayIndex + fRepeatCnt - 1, "]", ns,
1285  tname);
1286  else
1287  sbuf.Form("%s%d%s%s%s", "[", fArrayIndex, "]", ns, tname);
1288  } else {
1289  if (tname != 0)
1290  sbuf = tname;
1291  else
1292  sbuf = "Value";
1293  }
1294 
1295  TString buf;
1296  const char *value = fValue.Data();
1297 
1298  if ((tname == sqlio::CharStar) && (value != 0)) {
1299  Int_t size = strlen(value);
1300  if (size > reg->fFile->SQLSmallTextTypeLimit()) {
1301  Int_t strid = reg->AddLongString(value);
1302  buf = reg->fFile->CodeLongString(reg->fCurrentObjId, strid);
1303  value = buf.Data();
1304  }
1305  }
1306 
1307  blobs->AddLine(sbuf.Data(), value, (fArrayIndex >= 0) ? 0 : topname, ns);
1308 
1309  break;
1310  }
1311 
1312  case kSqlArray: {
1313  if (fValue.Length() > 0)
1314  blobs->AddLine(sqlio::Array, fValue.Data(), topname, ns);
1315  for (Int_t n = 0; n <= fChilds.GetLast(); n++) {
1316  TSQLStructure *child = (TSQLStructure *)fChilds.At(n);
1317  child->PerformConversion(reg, blobs, topname, useblob);
1318  }
1319  break;
1320  }
1321  }
1322 }
1323 
1324 ////////////////////////////////////////////////////////////////////////////////
1325 /// convert object data to sql statements
1326 /// if normal (column-wise) representation is not possible,
1327 /// complete object will be converted to raw format
1328 
1329 Bool_t TSQLStructure::StoreObject(TSqlRegistry *reg, Long64_t objid, TClass *cl, Bool_t registerobj)
1330 {
1331  if ((cl == 0) || (objid < 0))
1332  return kFALSE;
1333 
1334  if (gDebug > 1) {
1335  std::cout << "Store object " << objid << " cl = " << cl->GetName() << std::endl;
1336  if (GetStreamerInfo())
1337  std::cout << "Info = " << GetStreamerInfo()->GetName() << std::endl;
1338  else if (GetElement())
1339  std::cout << "Element = " << GetElement()->GetName() << std::endl;
1340  }
1341 
1342  Long64_t oldid = reg->fCurrentObjId;
1343  TClass *oldcl = reg->fCurrentObjClass;
1344 
1345  reg->fCurrentObjId = objid;
1346  reg->fCurrentObjClass = cl;
1347 
1348  Bool_t normstore = kFALSE;
1349 
1350  Bool_t res = kTRUE;
1351 
1352  if (cl == TObject::Class())
1353  normstore = StoreTObject(reg);
1354  else if (cl == TString::Class())
1355  normstore = StoreTString(reg);
1356  else if (GetType() == kSqlStreamerInfo)
1357  // this is a case when array of objects are stored in blob and each object
1358  // has normal streamer. Then it will be stored in normal form and only one tag
1359  // will be kept to remind about
1360  normstore = StoreClassInNormalForm(reg);
1361  else
1362  normstore = StoreObjectInNormalForm(reg);
1363 
1364  if (gDebug > 2)
1365  std::cout << "Store object " << objid << " of class " << cl->GetName() << " normal = " << normstore
1366  << " sqltype = " << GetType() << std::endl;
1367 
1368  if (!normstore) {
1369 
1370  // This is a case, when only raw table is exists
1371 
1372  TSQLClassInfo *sqlinfo = reg->fFile->RequestSQLClassInfo(cl);
1373  TSqlRawBuffer rawdata(reg, sqlinfo);
1374 
1375  for (Int_t n = 0; n < NumChilds(); n++) {
1376  TSQLStructure *child = GetChild(n);
1377  child->PerformConversion(reg, &rawdata, 0 /*cl->GetName()*/);
1378  }
1379 
1380  res = rawdata.IsAnyData();
1381  }
1382 
1383  if (registerobj)
1384  reg->AddRegCmd(objid, cl);
1385 
1386  reg->fCurrentObjId = oldid;
1387  reg->fCurrentObjClass = oldcl;
1388 
1389  return res;
1390 }
1391 
1392 ////////////////////////////////////////////////////////////////////////////////
1393 /// this function verify object child elements and
1394 /// calls transformation to class table
1395 
1396 Bool_t TSQLStructure::StoreObjectInNormalForm(TSqlRegistry *reg)
1397 {
1398  if (fChilds.GetLast() != 1)
1399  return kFALSE;
1400 
1401  TSQLStructure *s_ver = GetChild(0);
1402 
1403  TSQLStructure *s_info = GetChild(1);
1404 
1405  if (!CheckNormalClassPair(s_ver, s_info))
1406  return kFALSE;
1407 
1408  return s_info->StoreClassInNormalForm(reg);
1409 }
1410 
1411 ////////////////////////////////////////////////////////////////////////////////
1412 /// produces data for complete class table
1413 /// where not possible, raw data for some elements are created
1414 
1415 Bool_t TSQLStructure::StoreClassInNormalForm(TSqlRegistry *reg)
1416 {
1417  TClass *cl = 0;
1418  Version_t version = 0;
1419  if (!GetClassInfo(cl, version))
1420  return kFALSE;
1421  if (cl == 0)
1422  return kFALSE;
1423 
1424  TSQLClassInfo *sqlinfo = reg->fFile->RequestSQLClassInfo(cl->GetName(), version);
1425 
1426  TSQLTableData columns(reg->fFile, sqlinfo);
1427  // Bool_t needblob = kFALSE;
1428 
1429  TSqlRawBuffer rawdata(reg, sqlinfo);
1430 
1431  // Int_t currrawid = 0;
1432 
1433  // add first column with object id
1434  columns.AddColumn(reg->fFile->SQLObjectIdColumn(), reg->fCurrentObjId);
1435 
1436  for (Int_t n = 0; n <= fChilds.GetLast(); n++) {
1437  TSQLStructure *child = (TSQLStructure *)fChilds.At(n);
1438  TStreamerElement *elem = child->GetElement();
1439 
1440  if (elem == 0) {
1441  Error("StoreClassInNormalForm", "CAN NOT BE");
1442  continue;
1443  }
1444 
1445  if (child->StoreElementInNormalForm(reg, &columns))
1446  continue;
1447 
1448  Int_t columntyp = DefineElementColumnType(elem, reg->fFile);
1449  if ((columntyp != kColRawData) && (columntyp != kColObjectArray)) {
1450  Error("StoreClassInNormalForm", "Element %s typ=%d has problem with normal store ", elem->GetName(),
1451  columntyp);
1452  continue;
1453  }
1454 
1455  Bool_t doblobs = kTRUE;
1456 
1457  Int_t blobid = rawdata.fRawId; // keep id of first raw, used in class table
1458 
1459  if (columntyp == kColObjectArray)
1460  if (child->TryConvertObjectArray(reg, &rawdata))
1461  doblobs = kFALSE;
1462 
1463  if (doblobs)
1464  child->PerformConversion(reg, &rawdata, elem->GetName(), kFALSE);
1465 
1466  if (blobid == rawdata.fRawId)
1467  blobid = -1; // no data for blob was created
1468  else {
1469  // reg->fFile->CreateRawTable(sqlinfo);
1470  // blobid = currrawid; // column will contain first raw id
1471  // reg->ConvertBlobs(&blobs, sqlinfo, currrawid);
1472  // needblob = kTRUE;
1473  }
1474  // blobs.Delete();
1475 
1476  TString blobname = elem->GetName();
1477  if (reg->fFile->GetUseSuffixes())
1478  blobname += sqlio::RawSuffix;
1479 
1480  columns.AddColumn(blobname, blobid);
1481  }
1482 
1483  reg->fFile->CreateClassTable(sqlinfo, columns.TakeColInfos());
1484 
1485  reg->InsertToNormalTable(&columns, sqlinfo);
1486 
1487  return kTRUE;
1488 }
1489 
1490 ////////////////////////////////////////////////////////////////////////////////
1491 /// produce string with complete index like [1][2][0]
1492 
1493 TString TSQLStructure::MakeArrayIndex(TStreamerElement *elem, Int_t index)
1494 {
1495  TString res;
1496  if ((elem == 0) || (elem->GetArrayLength() == 0))
1497  return res;
1498 
1499  for (Int_t ndim = elem->GetArrayDim() - 1; ndim >= 0; ndim--) {
1500  Int_t ix = index % elem->GetMaxIndex(ndim);
1501  index = index / elem->GetMaxIndex(ndim);
1502  TString buf;
1503  buf.Form("%s%d%s", "[", ix, "]");
1504  res = buf + res;
1505  }
1506  return res;
1507 }
1508 
1509 ////////////////////////////////////////////////////////////////////////////////
1510 /// tries to store element data in column
1511 
1512 Bool_t TSQLStructure::StoreElementInNormalForm(TSqlRegistry *reg, TSQLTableData *columns)
1513 {
1514  TStreamerElement *elem = GetElement();
1515  if (elem == 0)
1516  return kFALSE;
1517 
1518  Int_t typ = elem->GetType();
1519 
1520  Int_t columntyp = DefineElementColumnType(elem, reg->fFile);
1521 
1522  if (gDebug > 4)
1523  std::cout << "Element " << elem->GetName() << " type = " << typ << " column = " << columntyp << std::endl;
1524 
1525  TString colname = DefineElementColumnName(elem, reg->fFile);
1526 
1527  if (columntyp == kColTString) {
1528  const char *value;
1529  if (!RecognizeTString(value))
1530  return kFALSE;
1531 
1532  Int_t len = value ? strlen(value) : 0;
1533 
1534  Int_t sizelimit = reg->fFile->SQLSmallTextTypeLimit();
1535 
1536  const char *stype = reg->fFile->SQLSmallTextType();
1537 
1538  if (len <= sizelimit)
1539  columns->AddColumn(colname.Data(), stype, value, kFALSE);
1540  else {
1541  Int_t strid = reg->AddLongString(value);
1542  TString buf = reg->fFile->CodeLongString(reg->fCurrentObjId, strid);
1543  columns->AddColumn(colname.Data(), stype, buf.Data(), kFALSE);
1544  }
1545 
1546  return kTRUE;
1547  }
1548 
1549  if (columntyp == kColParent) {
1550  Long64_t objid = reg->fCurrentObjId;
1551  TClass *basecl = elem->GetClassPointer();
1552  Int_t resversion = basecl->GetClassVersion();
1553  if (!StoreObject(reg, objid, basecl, kFALSE))
1554  resversion = -1;
1555  columns->AddColumn(colname.Data(), resversion);
1556  return kTRUE;
1557  }
1558 
1559  if (columntyp == kColObject) {
1560 
1561  Long64_t objid = -1;
1562 
1563  if (NumChilds() == 1) {
1564  TSQLStructure *child = GetChild(0);
1565 
1566  if (child->GetType() == kSqlObject) {
1567  objid = child->DefineObjectId(kFALSE);
1568  if (!child->StoreObject(reg, objid, child->GetObjectClass()))
1569  return kFALSE;
1570  } else if (child->GetType() == kSqlPointer) {
1571  TString sobjid = child->GetValue();
1572  if (sobjid.Length() > 0)
1573  objid = sqlio::atol64(sobjid.Data());
1574  }
1575  }
1576 
1577  if (objid < 0) {
1578  // std::cout << "!!!! Not standard " << elem->GetName() << " class = " << elem->GetClassPointer()->GetName() <<
1579  // std::endl;
1580  objid = reg->GetNextObjId();
1581  if (!StoreObject(reg, objid, elem->GetClassPointer()))
1582  objid = -1; // this is a case, when no data was stored for this object
1583  }
1584 
1585  columns->AddColumn(colname.Data(), objid);
1586  return kTRUE;
1587  }
1588 
1589  if (columntyp == kColNormObject) {
1590 
1591  if (NumChilds() != 1) {
1592  Error("kColNormObject", "NumChilds()=%d", NumChilds());
1593  PrintLevel(20);
1594  return kFALSE;
1595  }
1596  TSQLStructure *child = GetChild(0);
1597  if ((child->GetType() != kSqlPointer) && (child->GetType() != kSqlObject))
1598  return kFALSE;
1599 
1600  Bool_t normal = kTRUE;
1601 
1602  Long64_t objid = -1;
1603 
1604  if (child->GetType() == kSqlObject) {
1605  objid = child->DefineObjectId(kFALSE);
1606  normal = child->StoreObject(reg, objid, child->GetObjectClass());
1607  } else {
1608  objid = child->DefineObjectId(kFALSE);
1609  }
1610 
1611  if (!normal) {
1612  Error("kColNormObject", "child->StoreObject fails");
1613  return kFALSE;
1614  }
1615 
1616  columns->AddColumn(colname.Data(), objid);
1617  return kTRUE;
1618  }
1619 
1620  if (columntyp == kColNormObjectArray) {
1621 
1622  if (elem->GetArrayLength() != NumChilds())
1623  return kFALSE;
1624 
1625  for (Int_t index = 0; index < NumChilds(); index++) {
1626  TSQLStructure *child = GetChild(index);
1627  if ((child->GetType() != kSqlPointer) && (child->GetType() != kSqlObject))
1628  return kFALSE;
1629  Bool_t normal = kTRUE;
1630 
1631  Long64_t objid = child->DefineObjectId(kFALSE);
1632 
1633  if (child->GetType() == kSqlObject)
1634  normal = child->StoreObject(reg, objid, child->GetObjectClass());
1635 
1636  if (!normal)
1637  return kFALSE;
1638 
1639  colname = DefineElementColumnName(elem, reg->fFile, index);
1640 
1641  columns->AddColumn(colname.Data(), objid);
1642  }
1643  return kTRUE;
1644  }
1645 
1646  if (columntyp == kColObjectPtr) {
1647  if (NumChilds() != 1)
1648  return kFALSE;
1649  TSQLStructure *child = GetChild(0);
1650  if ((child->GetType() != kSqlPointer) && (child->GetType() != kSqlObject))
1651  return kFALSE;
1652 
1653  Bool_t normal = kTRUE;
1654  Long64_t objid = -1;
1655 
1656  if (child->GetType() == kSqlObject) {
1657  objid = child->DefineObjectId(kFALSE);
1658  normal = child->StoreObject(reg, objid, child->GetObjectClass());
1659  }
1660 
1661  if (!normal)
1662  return kFALSE;
1663 
1664  columns->AddColumn(colname.Data(), objid);
1665  return kTRUE;
1666  }
1667 
1668  if (columntyp == kColSimple) {
1669 
1670  // only child shoud existing for element
1671  if (NumChilds() != 1) {
1672  Error("StoreElementInNormalForm", "Enexpected number %d for simple element %s", NumChilds(), elem->GetName());
1673  return kFALSE;
1674  }
1675 
1676  TSQLStructure *child = GetChild(0);
1677  if (child->GetType() != kSqlValue)
1678  return kFALSE;
1679 
1680  const char *value = child->GetValue();
1681  if (value == 0)
1682  return kFALSE;
1683 
1684  const char *sqltype = reg->fFile->SQLCompatibleType(typ);
1685 
1686  columns->AddColumn(colname.Data(), sqltype, value, IsNumericType(typ));
1687 
1688  return kTRUE;
1689  }
1690 
1691  if (columntyp == kColSimpleArray) {
1692  // number of items should be exactly equal to number of children
1693 
1694  if (NumChilds() != 1) {
1695  Error("StoreElementInNormalForm", "In fixed array %s only array node should be", elem->GetName());
1696  return kFALSE;
1697  }
1698  TSQLStructure *arr = GetChild(0);
1699 
1700  const char *sqltype = reg->fFile->SQLCompatibleType(typ % 20);
1701 
1702  for (Int_t n = 0; n < arr->NumChilds(); n++) {
1703  TSQLStructure *child = arr->GetChild(n);
1704  if (child->GetType() != kSqlValue)
1705  return kFALSE;
1706 
1707  const char *value = child->GetValue();
1708  if (value == 0)
1709  return kFALSE;
1710 
1711  Int_t index = child->GetArrayIndex();
1712  Int_t last = index + child->GetRepeatCounter();
1713 
1714  while (index < last) {
1715  colname = DefineElementColumnName(elem, reg->fFile, index);
1716  columns->AddColumn(colname.Data(), sqltype, value, kTRUE);
1717  index++;
1718  }
1719  }
1720  return kTRUE;
1721  }
1722 
1723  return kFALSE;
1724 }
1725 
1726 ////////////////////////////////////////////////////////////////////////////////
1727 /// tries to write array of objects as list of object references
1728 /// in _streamer_ table, while objects itself will be stored in
1729 /// other tables. If not successful, object data will be stored
1730 /// in _streamer_ table
1731 
1732 Bool_t TSQLStructure::TryConvertObjectArray(TSqlRegistry *reg, TSqlRawBuffer *blobs)
1733 {
1734  TStreamerElement *elem = GetElement();
1735  if (elem == 0)
1736  return kFALSE;
1737 
1738  if (NumChilds() % 2 != 0)
1739  return kFALSE;
1740 
1741  Int_t indx = 0;
1742 
1743  while (indx < NumChilds()) {
1744  TSQLStructure *s_ver = GetChild(indx++);
1745  TSQLStructure *s_info = GetChild(indx++);
1746  if (!CheckNormalClassPair(s_ver, s_info))
1747  return kFALSE;
1748  }
1749 
1750  indx = 0;
1751  const char *ns = reg->fFile->SQLNameSeparator();
1752 
1753  while (indx < NumChilds() - 1) {
1754  indx++; // TSQLStructure* s_ver = GetChild(indx++);
1755  TSQLStructure *s_info = GetChild(indx++);
1756  TClass *cl = 0;
1757  Version_t version = 0;
1758  if (!s_info->GetClassInfo(cl, version))
1759  return kFALSE;
1760  Long64_t objid = reg->GetNextObjId();
1761  if (!s_info->StoreObject(reg, objid, cl))
1762  objid = -1; // this is a case, when no data was stored for this object
1763 
1764  TString sobjid;
1765  sobjid.Form("%lld", objid);
1766 
1767  blobs->AddLine(sqlio::ObjectRef_Arr, sobjid.Data(), elem->GetName(), ns);
1768  }
1769 
1770  return kTRUE;
1771 }
1772 
1773 ////////////////////////////////////////////////////////////////////////////////
1774 /// check if pair of two element corresponds
1775 /// to start of object, stored in normal form
1776 
1777 Bool_t TSQLStructure::CheckNormalClassPair(TSQLStructure *s_ver, TSQLStructure *s_info)
1778 {
1779  if ((s_ver == 0) || (s_info == 0) || (s_ver->GetType() != kSqlVersion))
1780  return kFALSE;
1781 
1782  TClass *ver_cl = s_ver->GetVersionClass();
1783 
1784  TClass *info_cl = 0;
1785  Version_t info_ver = 0;
1786  if (!s_info->GetClassInfo(info_cl, info_ver))
1787  return kFALSE;
1788 
1789  if ((ver_cl == 0) || (info_cl == 0) || (ver_cl != info_cl) || (ver_cl->GetClassVersion() != info_ver))
1790  return kFALSE;
1791 
1792  return kTRUE;
1793 }
1794 
1795 ////////////////////////////////////////////////////////////////////////////////
1796 /// store data of TObject in special table
1797 /// workaround custom TObject streamer
1798 
1799 Bool_t TSQLStructure::StoreTObject(TSqlRegistry *reg)
1800 {
1801  // check if it is really Looks like TObject data
1802  if ((NumChilds() < 3) || (NumChilds() > 4))
1803  return kFALSE;
1804 
1805  TSQLStructure *str_ver = GetChild(0);
1806  TSQLStructure *str_id = GetChild(1);
1807  TSQLStructure *str_bits = GetChild(2);
1808  TSQLStructure *str_prid = GetChild(3);
1809 
1810  if (str_ver->GetType() != kSqlVersion)
1811  return kFALSE;
1812  if ((str_id->GetType() != kSqlValue) || (str_id->GetValueType() != sqlio::UInt))
1813  return kFALSE;
1814  if ((str_bits->GetType() != kSqlValue) || (str_bits->GetValueType() != sqlio::UInt))
1815  return kFALSE;
1816  if (str_prid != 0)
1817  if ((str_prid->GetType() != kSqlValue) || (str_prid->GetValueType() != sqlio::UShort))
1818  return kFALSE;
1819 
1820  TSQLClassInfo *sqlinfo = reg->fFile->RequestSQLClassInfo(TObject::Class());
1821 
1822  if (sqlinfo == 0)
1823  return kFALSE;
1824 
1825  TSQLTableData columns(reg->fFile, sqlinfo);
1826 
1827  const char *uinttype = reg->fFile->SQLCompatibleType(TStreamerInfo::kUInt);
1828 
1829  columns.AddColumn(reg->fFile->SQLObjectIdColumn(), reg->fCurrentObjId);
1830 
1831  columns.AddColumn(sqlio::TObjectUniqueId, uinttype, str_id->GetValue(), kTRUE);
1832  columns.AddColumn(sqlio::TObjectBits, uinttype, str_bits->GetValue(), kTRUE);
1833  columns.AddColumn(sqlio::TObjectProcessId, "CHAR(3)", (str_prid ? str_prid->GetValue() : ""), kFALSE);
1834 
1835  reg->fFile->CreateClassTable(sqlinfo, columns.TakeColInfos());
1836 
1837  reg->InsertToNormalTable(&columns, sqlinfo);
1838 
1839  return kTRUE;
1840 }
1841 
1842 ////////////////////////////////////////////////////////////////////////////////
1843 /// store data of TString in special table
1844 /// it is required when TString stored as pointer and reference to it possible
1845 
1846 Bool_t TSQLStructure::StoreTString(TSqlRegistry *reg)
1847 {
1848  const char *value = 0;
1849  if (!RecognizeTString(value))
1850  return kFALSE;
1851 
1852  TSQLClassInfo *sqlinfo = reg->fFile->RequestSQLClassInfo(TString::Class());
1853  if (sqlinfo == 0)
1854  return kFALSE;
1855 
1856  TSQLTableData columns(reg->fFile, sqlinfo);
1857 
1858  columns.AddColumn(reg->fFile->SQLObjectIdColumn(), reg->fCurrentObjId);
1859  columns.AddColumn(sqlio::TStringValue, reg->fFile->SQLBigTextType(), value, kFALSE);
1860 
1861  reg->fFile->CreateClassTable(sqlinfo, columns.TakeColInfos());
1862 
1863  reg->InsertToNormalTable(&columns, sqlinfo);
1864  return kTRUE;
1865 }
1866 
1867 ////////////////////////////////////////////////////////////////////////////////
1868 /// prove that structure contains TString data
1869 
1870 Bool_t TSQLStructure::RecognizeTString(const char *&value)
1871 {
1872  value = 0;
1873 
1874  if ((NumChilds() == 0) || (NumChilds() > 3))
1875  return kFALSE;
1876 
1877  TSQLStructure *len = 0, *lenbig = 0, *chars = 0;
1878  for (Int_t n = 0; n < NumChilds(); n++) {
1879  TSQLStructure *curr = GetChild(n);
1880  if (curr->fType != kSqlValue)
1881  return kFALSE;
1882  if (curr->fPointer == sqlio::UChar) {
1883  if (len == 0)
1884  len = curr;
1885  else
1886  return kFALSE;
1887  } else if (curr->fPointer == sqlio::Int) {
1888  if (lenbig == 0)
1889  lenbig = curr;
1890  else
1891  return kFALSE;
1892  } else if (curr->fPointer == sqlio::CharStar) {
1893  if (chars == 0)
1894  chars = curr;
1895  else
1896  return kFALSE;
1897  } else
1898  return kFALSE;
1899  }
1900 
1901  if (len == 0)
1902  return kFALSE;
1903  if ((lenbig != 0) && (chars == 0))
1904  return kFALSE;
1905 
1906  if (chars != 0)
1907  value = chars->GetValue();
1908 
1909  return kTRUE;
1910 }
1911 
1912 ////////////////////////////////////////////////////////////////////////////////
1913 /// defines which kind of column can be assigned for this element
1914 /// Possible cases
1915 /// kColSimple - basic data type
1916 /// kColSimpleArray - fixed array of basic types
1917 /// kColParent - parent class
1918 /// kColObject - object as data member
1919 /// kColObjectPtr - object as pointer
1920 /// kColTString - TString
1921 /// kColRawData - anything else as raw data
1922 
1923 Int_t TSQLStructure::DefineElementColumnType(TStreamerElement *elem, TSQLFile *f)
1924 {
1925  if (elem == 0)
1926  return kColUnknown;
1927 
1928  Int_t typ = elem->GetType();
1929 
1930  if (typ == TStreamerInfo::kMissing)
1931  return kColRawData;
1932 
1933  if ((typ > 0) && (typ < 20) && (typ != TStreamerInfo::kCharStar))
1934  return kColSimple;
1935 
1936  if ((typ > TStreamerInfo::kOffsetL) && (typ < TStreamerInfo::kOffsetP))
1937  if ((f->GetArrayLimit() < 0) || (elem->GetArrayLength() <= f->GetArrayLimit()))
1938  return kColSimpleArray;
1939 
1940  if (typ == TStreamerInfo::kTObject) {
1941  if (elem->InheritsFrom(TStreamerBase::Class()))
1942  return kColParent;
1943  else
1944  return kColObject;
1945  }
1946 
1947  if (typ == TStreamerInfo::kTNamed) {
1948  if (elem->InheritsFrom(TStreamerBase::Class()))
1949  return kColParent;
1950  else
1951  return kColObject;
1952  }
1953 
1954  if (typ == TStreamerInfo::kTString)
1955  return kColTString;
1956 
1957  if (typ == TStreamerInfo::kBase)
1958  return kColParent;
1959 
1960  if (typ == TStreamerInfo::kSTL)
1961  if (elem->InheritsFrom(TStreamerBase::Class()))
1962  return kColParent;
1963 
1964  // this is workaround
1965  // these two tags stored with WriteFastArray, but read with cl->Streamer()
1966  if ((typ == TStreamerInfo::kObject) || (typ == TStreamerInfo::kAny)) {
1967  if (elem->GetArrayLength() == 0)
1968  return kColObject;
1969  else if (elem->GetStreamer() == 0)
1970  return kColObjectArray;
1971  }
1972 
1973  if ((typ == TStreamerInfo::kObject) || (typ == TStreamerInfo::kAny) || (typ == TStreamerInfo::kAnyp) ||
1974  (typ == TStreamerInfo::kObjectp) || (typ == TStreamerInfo::kAnyP) || (typ == TStreamerInfo::kObjectP)) {
1975  if ((elem->GetArrayLength() == 0) || (elem->GetStreamer() != 0))
1976  return kColNormObject;
1977  else
1978  return kColNormObjectArray;
1979  }
1980 
1981  if ((typ == TStreamerInfo::kObject + TStreamerInfo::kOffsetL) ||
1982  (typ == TStreamerInfo::kAny + TStreamerInfo::kOffsetL) ||
1983  (typ == TStreamerInfo::kAnyp + TStreamerInfo::kOffsetL) ||
1984  (typ == TStreamerInfo::kObjectp + TStreamerInfo::kOffsetL) ||
1985  (typ == TStreamerInfo::kAnyP + TStreamerInfo::kOffsetL) ||
1986  (typ == TStreamerInfo::kObjectP + TStreamerInfo::kOffsetL)) {
1987  if (elem->GetStreamer() != 0)
1988  return kColNormObject;
1989  else
1990  return kColNormObjectArray;
1991  }
1992 
1993  if ((typ == TStreamerInfo::kObject) || (typ == TStreamerInfo::kAny) || (typ == TStreamerInfo::kAnyp) ||
1994  (typ == TStreamerInfo::kObjectp) || (typ == TStreamerInfo::kSTL)) {
1995  if (elem->GetArrayLength() == 0)
1996  return kColObject;
1997  else if (elem->GetStreamer() == 0)
1998  return kColObjectArray;
1999  }
2000 
2001  if (((typ == TStreamerInfo::kAnyP) || (typ == TStreamerInfo::kObjectP)) && (elem->GetArrayDim() == 0))
2002  return kColObjectPtr;
2003 
2004  // if ((typ==TStreamerInfo::kSTLp) &&
2005  // (elem->GetArrayDim()==0)) {
2006  // TStreamerSTL* stl = dynamic_cast<TStreamerSTL*> (elem);
2007  // if ((stl!=0) && (dynamic_cast<TStreamerSTLstring*>(elem)==0))
2008  // return kColObjectPtr;
2009  // }
2010 
2011  return kColRawData;
2012 }
2013 
2014 ////////////////////////////////////////////////////////////////////////////////
2015 /// returns name of the column in class table for that element
2016 
2017 TString TSQLStructure::DefineElementColumnName(TStreamerElement *elem, TSQLFile *f, Int_t indx)
2018 {
2019  TString colname = "";
2020 
2021  Int_t coltype = DefineElementColumnType(elem, f);
2022  if (coltype == kColUnknown)
2023  return colname;
2024 
2025  const char *elemname = elem->GetName();
2026 
2027  switch (coltype) {
2028  case kColSimple: {
2029  colname = elemname;
2030  if (f->GetUseSuffixes()) {
2031  colname += f->SQLNameSeparator();
2032  colname += GetSimpleTypeName(elem->GetType());
2033  }
2034  break;
2035  }
2036 
2037  case kColSimpleArray: {
2038  colname = elemname;
2039  colname += MakeArrayIndex(elem, indx);
2040  break;
2041  }
2042 
2043  case kColParent: {
2044  colname = elemname;
2045  if (f->GetUseSuffixes())
2046  colname += sqlio::ParentSuffix;
2047  break;
2048  }
2049 
2050  case kColNormObject: {
2051  colname = elemname;
2052  if (f->GetUseSuffixes())
2053  colname += sqlio::ObjectSuffix;
2054  break;
2055  }
2056 
2057  case kColNormObjectArray: {
2058  colname = elemname;
2059  colname += MakeArrayIndex(elem, indx);
2060  if (f->GetUseSuffixes())
2061  colname += sqlio::ObjectSuffix;
2062  break;
2063  }
2064 
2065  case kColObject: {
2066  colname = elemname;
2067  if (f->GetUseSuffixes())
2068  colname += sqlio::ObjectSuffix;
2069  break;
2070  }
2071 
2072  case kColObjectPtr: {
2073  colname = elemname;
2074  if (f->GetUseSuffixes())
2075  colname += sqlio::PointerSuffix;
2076  break;
2077  }
2078 
2079  case kColTString: {
2080  colname = elem->GetName();
2081  if (f->GetUseSuffixes())
2082  colname += sqlio::StrSuffix;
2083  break;
2084  }
2085 
2086  case kColRawData: {
2087  colname = elemname;
2088  if (f->GetUseSuffixes())
2089  colname += sqlio::RawSuffix;
2090  break;
2091  }
2092 
2093  case kColObjectArray: {
2094  colname = elemname;
2095  if (f->GetUseSuffixes())
2096  colname += sqlio::RawSuffix;
2097  break;
2098  }
2099  }
2100 
2101  return colname;
2102 }
2103 
2104 ////////////////////////////////////////////////////////////////////////////////
2105 /// find column in TSQLObjectData object, which correspond to current element
2106 
2107 Int_t TSQLStructure::LocateElementColumn(TSQLFile *f, TBufferSQL2 *buf, TSQLObjectData *data)
2108 {
2109  TStreamerElement *elem = GetElement();
2110  if ((elem == 0) || (data == 0))
2111  return kColUnknown;
2112 
2113  Int_t coltype = DefineElementColumnType(elem, f);
2114 
2115  if (gDebug > 4)
2116  std::cout << "TSQLStructure::LocateElementColumn " << elem->GetName() << " coltyp = " << coltype << " : "
2117  << elem->GetType() << " len = " << elem->GetArrayLength() << std::endl;
2118 
2119  if (coltype == kColUnknown)
2120  return kColUnknown;
2121 
2122  const char *elemname = elem->GetName();
2123  Bool_t located = kFALSE;
2124 
2125  TString colname = DefineElementColumnName(elem, f);
2126 
2127  if (gDebug > 4)
2128  std::cout << " colname = " << colname << " in " << data->GetInfo()->GetClassTableName() << std::endl;
2129 
2130  switch (coltype) {
2131  case kColSimple: {
2132  located = data->LocateColumn(colname.Data());
2133  break;
2134  }
2135 
2136  case kColSimpleArray: {
2137  located = data->LocateColumn(colname);
2138  break;
2139  }
2140 
2141  case kColParent: {
2142  located = data->LocateColumn(colname.Data());
2143  if (located == kColUnknown)
2144  return kColUnknown;
2145 
2146  Long64_t objid = DefineObjectId(kTRUE);
2147  const char *clname = elemname;
2148  Version_t version = atoi(data->GetValue());
2149 
2150  // this is a case, when parent store nothing in the database
2151  if (version < 0)
2152  break;
2153 
2154  // special treatment for TObject
2155  if (strcmp(clname, TObject::Class()->GetName()) == 0) {
2156  UnpackTObject(f, buf, data, objid, version);
2157  break;
2158  }
2159 
2160  TSQLClassInfo *sqlinfo = f->FindSQLClassInfo(clname, version);
2161  if (sqlinfo == 0)
2162  return kColUnknown;
2163 
2164  // this will indicate that streamer is completely custom
2165  if (sqlinfo->IsClassTableExist()) {
2166  data->AddUnpackInt(sqlio::Version, version);
2167  } else {
2168  TSQLObjectData *objdata = buf->SqlObjectData(objid, sqlinfo);
2169  if ((objdata == 0) || !objdata->PrepareForRawData())
2170  return kColUnknown;
2171  AddObjectData(objdata);
2172  }
2173 
2174  break;
2175  }
2176 
2177  // This is a case when streamer of object will be called directly.
2178  // Typically it happens when object is data member of the class.
2179  // Here we need to define class of object and if it was written by
2180  // normal streamer (via TStreamerInfo methods) or directly as blob.
2181  // When blob was used, blob data should be read.
2182  // In normal case only version is required. Other object data will be
2183  // read by TBufferSQL2::IncrementLevel method
2184  case kColObject: {
2185  located = data->LocateColumn(colname.Data());
2186  if (located == kColUnknown)
2187  return located;
2188 
2189  const char *strobjid = data->GetValue();
2190  if (strobjid == 0)
2191  return kColUnknown;
2192 
2193  Long64_t objid = sqlio::atol64(strobjid);
2194 
2195  // when nothing was stored, nothing need to be read. skip
2196  if (objid < 0)
2197  break;
2198 
2199  TString clname;
2200  Version_t version;
2201 
2202  if (!buf->SqlObjectInfo(objid, clname, version))
2203  return kColUnknown;
2204 
2205  // special treatment for TObject
2206  if (clname == TObject::Class()->GetName()) {
2207  UnpackTObject(f, buf, data, objid, version);
2208  break;
2209  }
2210 
2211  TSQLClassInfo *sqlinfo = f->FindSQLClassInfo(clname.Data(), version);
2212  if (sqlinfo == 0)
2213  return kColUnknown;
2214 
2215  if (sqlinfo->IsClassTableExist()) {
2216  data->AddUnpackInt(sqlio::Version, version);
2217  } else {
2218  TSQLObjectData *objdata = buf->SqlObjectData(objid, sqlinfo);
2219  if ((objdata == 0) || !objdata->PrepareForRawData())
2220  return kColUnknown;
2221  AddObjectData(objdata);
2222  }
2223 
2224  // work around to store objid of object, which is memeber of class
2225  fValue = strobjid;
2226 
2227  break;
2228  }
2229 
2230  // this is case of pointer on any object
2231  // field contains objectid.
2232  // Object id, class of object and so on will be checked
2233  // when TBuffer::ReadObject method will be called
2234  case kColObjectPtr: {
2235  located = data->LocateColumn(colname.Data());
2236  break;
2237  }
2238 
2239  // this is case of on object which is treated normally in TBuffer
2240  // field should contains objectid.
2241  // Object id, class of object and so on will be checked
2242  // when TBuffer::StreamObject method will be called
2243  case kColNormObject: {
2244  located = data->LocateColumn(colname.Data());
2245  break;
2246  }
2247 
2248  case kColNormObjectArray: {
2249  located = data->LocateColumn(colname.Data());
2250  break;
2251  }
2252 
2253  case kColTString: {
2254  located = data->LocateColumn(colname);
2255  if (located == kColUnknown)
2256  return located;
2257  const char *value = data->GetValue();
2258 
2259  Long64_t objid = DefineObjectId(kTRUE);
2260  Int_t strid = f->IsLongStringCode(objid, value);
2261 
2262  TString buf2;
2263 
2264  // if special prefix found, than try get such string
2265  if (strid > 0)
2266  if (f->GetLongString(objid, strid, buf2))
2267  value = buf2.Data();
2268 
2269  Int_t len = (value == 0) ? 0 : strlen(value);
2270  if (len < 255) {
2271  data->AddUnpackInt(sqlio::UChar, len);
2272  } else {
2273  data->AddUnpackInt(sqlio::UChar, 255);
2274  data->AddUnpackInt(sqlio::Int, len);
2275  }
2276  if (len > 0)
2277  data->AddUnpack(sqlio::CharStar, value);
2278  break;
2279  }
2280 
2281  case kColRawData: {
2282  located = data->LocateColumn(colname.Data(), kTRUE);
2283  break;
2284  }
2285 
2286  case kColObjectArray: {
2287  located = data->LocateColumn(colname.Data(), kTRUE);
2288  break;
2289  }
2290  }
2291 
2292  if (!located)
2293  coltype = kColUnknown;
2294 
2295  return coltype;
2296 }
2297 
2298 ////////////////////////////////////////////////////////////////////////////////
2299 /// Unpack TObject data in form, accepted by custom TObject streamer
2300 
2301 Bool_t
2302 TSQLStructure::UnpackTObject(TSQLFile *f, TBufferSQL2 *buf, TSQLObjectData *data, Long64_t objid, Int_t clversion)
2303 {
2304  TSQLClassInfo *sqlinfo = f->FindSQLClassInfo(TObject::Class()->GetName(), clversion);
2305  if (sqlinfo == 0)
2306  return kFALSE;
2307 
2308  TSQLObjectData *tobjdata = buf->SqlObjectData(objid, sqlinfo);
2309  if (tobjdata == 0)
2310  return kFALSE;
2311 
2312  data->AddUnpackInt(sqlio::Version, clversion);
2313 
2314  tobjdata->LocateColumn(sqlio::TObjectUniqueId);
2315  data->AddUnpack(sqlio::UInt, tobjdata->GetValue());
2316  tobjdata->ShiftToNextValue();
2317 
2318  tobjdata->LocateColumn(sqlio::TObjectBits);
2319  data->AddUnpack(sqlio::UInt, tobjdata->GetValue());
2320  tobjdata->ShiftToNextValue();
2321 
2322  tobjdata->LocateColumn(sqlio::TObjectProcessId);
2323  const char *value = tobjdata->GetValue();
2324  if ((value != 0) && (strlen(value) > 0))
2325  data->AddUnpack(sqlio::UShort, value);
2326 
2327  delete tobjdata;
2328 
2329  return kTRUE;
2330 }
2331 
2332 ////////////////////////////////////////////////////////////////////////////////
2333 /// Unpack TString data in form, accepted by custom TString streamer
2334 
2335 Bool_t
2336 TSQLStructure::UnpackTString(TSQLFile *f, TBufferSQL2 *buf, TSQLObjectData *data, Long64_t objid, Int_t clversion)
2337 {
2338  TSQLClassInfo *sqlinfo = f->FindSQLClassInfo(TString::Class()->GetName(), clversion);
2339  if (sqlinfo == 0)
2340  return kFALSE;
2341 
2342  TSQLObjectData *tstringdata = buf->SqlObjectData(objid, sqlinfo);
2343  if (tstringdata == 0)
2344  return kFALSE;
2345 
2346  tstringdata->LocateColumn(sqlio::TStringValue);
2347 
2348  const char *value = tstringdata->GetValue();
2349 
2350  Int_t len = (value == 0) ? 0 : strlen(value);
2351  if (len < 255) {
2352  data->AddUnpackInt(sqlio::UChar, len);
2353  } else {
2354  data->AddUnpackInt(sqlio::UChar, 255);
2355  data->AddUnpackInt(sqlio::Int, len);
2356  }
2357  if (len > 0)
2358  data->AddUnpack(sqlio::CharStar, value);
2359 
2360  delete tstringdata;
2361 
2362  return kTRUE;
2363 }
2364 
2365 ////////////////////////////////////////////////////////////////////////////////
2366 /// adds quotes around string value and replaces some special symbols
2367 
2368 void TSQLStructure::AddStrBrackets(TString &s, const char *quote)
2369 {
2370  if (strcmp(quote, "\"") == 0)
2371  s.ReplaceAll("\"", "\\\"");
2372  else
2373  s.ReplaceAll("'", "''");
2374  s.Prepend(quote);
2375  s.Append(quote);
2376 }