KaliVeda
Toolkit for HIC analysis
KVSQLROOTFile.cpp
1 #include "KVSQLROOTFile.h"
2 #include "TSystem.h"
3 
5 
6 
7 
10 KVString KVSQLROOTFile::UUID_for_object(const KVString& name) const
11 {
12  // Return unique identifier used to store object with given name in ROOT file
13 
14  fObjDB->select_data("objTable", "unique_id", Form("name = '%s'", name.Data()));
15  KVString uuid;
16  while (fObjDB->get_next_result())
17  uuid = get_objTable()["unique_id"].get_data<KVString>();
18  return uuid;
19 }
20 
21 
22 
25 
27 {
28  // Retrieve object from file using its name
29 
30  auto it = fObjList.find(uuid.Data());// object already retrieved from file ?
31  if (it != fObjList.end()) return it->second;
32  auto t = fObjStore->Get(uuid);
33  fObjList[uuid.Data()] = t;
34  return t;
35 }
36 
37 
38 
57 
59 {
60  // Open or (re)create a combined ROOT object store & SQL database with info on the stored objects.
61  //
62  // \param[in] filepath path to file. any shell variables will be expanded.
63  // \param[in] option see TFile constructors for possible values. default="READ".
64  //
65  // This will actually open or create two files in the directory given by filepath:
66  // + `objStore.root` - ROOT file containing objects
67  // + `objInfos.sqlite` - SQLite database containing metadata for objects
68  //
69  // When first created, the SQLite database contains a table `objTable` with the
70  // following columns:
71  //
72  // obj_idx | name | class | unique_id
73  // ------- | ---- | ----- | ---------
74  // * | * | * | *
75  //
76  // The `unique_id` for each object is generated using TUUID.
77 
78  TString FP = filepath;
79  TString OPT = option;
80  OPT.ToUpper();
81 
83  if (OPT.Contains("CREATE")) {
84  // create directory using path
85  gSystem->mkdir(filepath, true); // recursive: create any missing directories in path
86  gSystem->Chmod(filepath, 0775); // make writable for group
87  }
88  FP.Append("/");
89  TString rpath = FP + "objStore.root";
90  if (OPT == "RECREATE") gSystem->Unlink(rpath);
92  fObjStore.reset(new TFile(rpath, OPT));
94  fCurrentROOTFilePath = rpath;
95 
96  TString sqlpath = FP + "objInfos.sqlite";
97  if (OPT == "RECREATE") gSystem->Unlink(sqlpath);
98  fObjDB.reset(new KVSQLite::database(sqlpath));
99  if (OPT.Contains("CREATE")) {
100  // set up object table
101  KVSQLite::table tmp("objTable");
102  tmp.add_column("obj_idx", "INTEGER");
103  tmp.primary_key("obj_idx");
104  tmp.add_column("name", "TEXT");
105  tmp.add_column("class", "TEXT");
106  tmp.add_column("unique_id", "TEXT");
107  fObjDB->add_table(tmp);
108  }
109  gSystem->Chmod(sqlpath, 0664); // make writable for group
110 }
111 
112 
113 
117 
119 {
120  // Manually 'delete' ROOT file in order to force writing to disk,
121  // then change access permissions to make it writable for group
122 
123  fObjStore.reset(nullptr);
125 }
126 
127 
128 
148 
149 void KVSQLROOTFile::WriteObject(const TObject* obj, const KVNameValueList& infos)
150 {
151  // Write object in ROOT file, store infos given in list
152  //
153  // @param obj pointer to object to store
154  // @param infos list of metadata associated with object
155  //
156  // If it does not already exist, this will add to the SQLite database a table `objInfos` with the following columns:
157  //
158  // info_idx | obj_idx
159  // -------- | -------
160  // * | *
161  //
162  // This table will be augmented with columns corresponding to the names of the metadata contained in infos.
163  // e.g. if infos = {{"name","john"},{"age",50}} the table will become
164  //
165  // info_idx | obj_idx | name | age
166  // -------- | ------- | ---- | ---
167  // * | * | * | *
168  //
169 
170  if (!fObjDB->has_table("objInfos")) {
171  // set up object info table if not already done
172  KVSQLite::table tmp("objInfos");
173  tmp.add_column("info_idx", "INTEGER");
174  tmp.primary_key("info_idx");
175  tmp.add_column("obj_idx", "INTEGER");
176  tmp.foreign_key("obj_idx", "objTable", "obj_idx");
177  fObjDB->add_table(tmp);
178  }
179  // add any missing columns to info table
180  fObjDB->add_missing_columns("objInfos", infos);
181  // get unique ID for object
182  TUUID unid;
183  TString unique_id = unid.AsString();
184  // write object in ROOT file
186  fObjStore->cd();
187  obj->Write(unique_id);
189  // store infos on object
190  // 1 - write name, class & unique id in object table
191  fObjDB->prepare_data_insertion("objTable");
192  get_objTable()["name"] = obj->GetName();
193  get_objTable()["class"] = obj->ClassName();
194  get_objTable()["unique_id"] = unique_id;
195  fObjDB->insert_data_row();
196  fObjDB->end_data_insertion();
197  // 2 - get index of object from object table
198  fObjDB->select_data("objTable", "obj_idx", Form("unique_id='%s'", unique_id.Data()));
199  int obj_idx;
200  while (fObjDB->get_next_result()) obj_idx = get_objTable()["obj_idx"].get_data<int>();
201  // 3 - add infos on object in info table
202  fObjDB->prepare_data_insertion("objInfos");
203  KVNameValueList info_copy(infos);
204  info_copy.SetValue("obj_idx", obj_idx);
205  //get_objInfos()["obj_idx"]=obj_idx;
206  //for(auto& info : infos) get_objInfos()[info.GetName()]=info;
207  get_objInfos().prepare_data(info_copy);
208  fObjDB->insert_data_row();
209  fObjDB->end_data_insertion();
210 }
211 
212 
213 
216 
218 {
219  // Return pointer to object with given name
220 
222 }
223 
224 
225 
228 
230 {
231  // List the contents of the file with associated infos
232  KVString colnames = "name,class,";
233  colnames += get_objInfos().get_column_names("obj_idx info_idx");
234  colnames.Begin(",");
235  TString tabs("\t\t\t\t");
236  while (!colnames.End()) {
237  std::cout << colnames.Next() << tabs;
238  }
239  std::cout << "\n==========================================================================================\n";
240  if (fObjDB->select_data("objTable,objInfos", colnames)) {
241  while (fObjDB->get_next_result()) {
242  colnames.Begin(",");
243  while (!colnames.End()) {
244  auto colname = colnames.Next();
245  if (colname == "name" || colname == "class")
246  std::cout << get_objTable()[colname].get_data<TString>() << tabs;
247  else
248  std::cout << get_objInfos()[colname].get_data<TString>() << tabs;
249  }
250  std::cout << std::endl;
251  }
252  }
253  else {
254  Error("ls", "Problem with KVSQLite::database::select_data");
255  }
256 }
257 
258 
259 
280 
282 {
283  // Fill the list given as argument with pointers to all objects which obey the given selection.
284  //
285  // The 'where' string will be used as the `WHERE` clause of an SQLite selection.
286  //
287  // Examples:
288  //
289  //~~~~
290  //WHERE column_1 = 100;
291  //
292  //WHERE column_2 IN (1,2,3);
293  //
294  //WHERE column_3 LIKE 'An%';
295  //
296  //WHERE column_4 BETWEEN 10 AND 20;
297  //~~~~
298  //
299  // Note that string arguments should be enclosed in single quotes.
300  //
301  // The columns of both the `objTable` (`name`, `class`) and `objInfos` tables can be used in the selection.
302 
303  fObjDB->select_data("objTable,objInfos", "unique_id", where);
304  while (fObjDB->get_next_result()) {
305  auto uuid = get_objTable()["unique_id"].get_data<KVString>();
306  list->Add(get_object_with_UUID(uuid));
307  }
308 }
309 
310 
334 
335 void KVSQLROOTFile::FillListOfObjectsWithSelection(KVSeqCollection* list, const KVString& where, const KVString& numberlist_column, int value)
336 {
337  // Fill the list given as argument with pointers to all objects which obey the given selection.
338  // 'numberlist_column' is the name of a column in the `objInfos` table containing strings which may be
339  // interpreted as KVNumberList objects. Only the entries with a number list containing 'value'
340  // will be selected.
341  //
342  // The 'where' string will be used as the `WHERE` clause of an SQLite selection.
343  //
344  // Examples:
345  //
346  //~~~~
347  //WHERE column_1 = 100;
348  //
349  //WHERE column_2 IN (1,2,3);
350  //
351  //WHERE column_3 LIKE 'An%';
352  //
353  //WHERE column_4 BETWEEN 10 AND 20;
354  //~~~~
355  //
356  // Note that string arguments should be enclosed in single quotes.
357  //
358  // The columns of both the `objTable` (`name`, `class`) and `objInfos` tables can be used in the selection.
359 
360  fObjDB->select_data("objTable,objInfos", Form("unique_id,%s", numberlist_column.Data()), where);
361  while (fObjDB->get_next_result()) {
362  KVNumberList nl(get_objInfos()[numberlist_column].get_data<KVString>());
363  if (nl.Contains(value)) {
364  auto uuid = get_objTable()["unique_id"].get_data<KVString>();
365  list->Add(get_object_with_UUID(uuid));
366  }
367  }
368 }
369 
370 
#define OPT
const char Option_t
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
void SetValue(const Char_t *name, value_type value)
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:85
Bool_t Contains(Int_t val) const
returns kTRUE if the value 'val' is contained in the ranges defined by the number list
Combine ROOT file containing objects with SQLite database with info on the objects.
Definition: KVSQLROOTFile.h:76
void WriteObject(const TObject *, const KVNameValueList &)
void FillListOfObjectsWithSelection(KVSeqCollection *list, const KVString &where)
KVSQLite::table & get_objTable() const
Definition: KVSQLROOTFile.h:90
KVSQLite::table & get_objInfos() const
Definition: KVSQLROOTFile.h:94
TObject * Get(const KVString &name) const
Return pointer to object with given name.
std::unordered_map< std::string, TObject * > fObjList
for quick look-up of objects using unique id
Definition: KVSQLROOTFile.h:99
TObject * get_object_with_UUID(const KVString &name) const
Retrieve object from file using its name.
void ls(Option_t *="") const override
List the contents of the file with associated infos.
void restore_working_directory()
Definition: KVSQLROOTFile.h:85
KVString UUID_for_object(const KVString &) const
Return unique identifier used to store object with given name in ROOT file.
std::unique_ptr< TFile > fObjStore
Definition: KVSQLROOTFile.h:77
TString fCurrentROOTFilePath
full path to current ROOT file
std::unique_ptr< KVSQLite::database > fObjDB
Definition: KVSQLROOTFile.h:78
KVSQLROOTFile(const KVString &filepath, Option_t *option="READ")
void save_working_directory()
Definition: KVSQLROOTFile.h:81
Interface to ROOT SQLite database backend.
Definition: SQLiteDB.h:477
void primary_key(const TString &cols)
Definition: SQLiteDB.h:432
void foreign_key(const TString &child_key, const TString &parent_table, const TString &parent_key)
Definition: SQLiteDB.cpp:1674
TString get_column_names(const TString &exclude="", const TString &delim=",") const
Definition: SQLiteDB.cpp:1779
column & add_column(const KVSQLite::column &c)
Definition: SQLiteDB.cpp:1623
void prepare_data(const KVNameValueList &, const KVNamedParameter *=nullptr)
Definition: SQLiteDB.cpp:1741
KaliVeda extensions to ROOT collection classes.
void Add(TObject *obj) override
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
virtual const char * GetName() const
virtual const char * ClassName() const
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
virtual void Error(const char *method, const char *msgfmt,...) const
const char * Data() const
TString & Append(char c, Ssiz_t rep=1)
virtual int Chmod(const char *file, UInt_t mode)
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
virtual char * ExpandPathName(const char *path)
virtual int Unlink(const char *name)
const char * AsString() const
ClassImp(TPyArg)