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