| 1 | // @(#)root/tree:$Id: MTreeSQL.cxx 43270 2012-03-06 22:46:11Z pcanal $
|
|---|
| 2 | // Author: Philippe Canal and al. 08/2004
|
|---|
| 3 |
|
|---|
| 4 | /*************************************************************************
|
|---|
| 5 | * Copyright (C) 1995-2000, 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 | // //
|
|---|
| 14 | // MTreeSQL //
|
|---|
| 15 | // //
|
|---|
| 16 | // Implement TTree for a SQL backend //
|
|---|
| 17 | // //
|
|---|
| 18 | //////////////////////////////////////////////////////////////////////////
|
|---|
| 19 |
|
|---|
| 20 | #include <Riostream.h>
|
|---|
| 21 | #include <map>
|
|---|
| 22 | #include <stdlib.h>
|
|---|
| 23 |
|
|---|
| 24 | #include "TString.h"
|
|---|
| 25 | #include "TROOT.h"
|
|---|
| 26 | #include "TSystem.h"
|
|---|
| 27 | #include "TError.h"
|
|---|
| 28 | #include "TFile.h"
|
|---|
| 29 | #include "TTree.h"
|
|---|
| 30 | #include "TLeaf.h"
|
|---|
| 31 | #include "TBranch.h"
|
|---|
| 32 | #include "TPRegexp.h"
|
|---|
| 33 |
|
|---|
| 34 | #include "TSQLRow.h"
|
|---|
| 35 | #include "TSQLResult.h"
|
|---|
| 36 |
|
|---|
| 37 | #include "MSQLServer.h"
|
|---|
| 38 |
|
|---|
| 39 | #include "MTreeSQL.h"
|
|---|
| 40 | #include "MBasketSQL.h"
|
|---|
| 41 |
|
|---|
| 42 | ClassImp(MTreeSQL);
|
|---|
| 43 |
|
|---|
| 44 | using namespace std;
|
|---|
| 45 |
|
|---|
| 46 | //______________________________________________________________________________
|
|---|
| 47 | MTreeSQL::MTreeSQL(MSQLServer *server, const TString& table, const TString &addon) :
|
|---|
| 48 | TTree(table, addon, 0), fServer(server), fQuery(table+" "+addon), fResult(0), fRow(0)
|
|---|
| 49 | {
|
|---|
| 50 | fEntries = 0;
|
|---|
| 51 |
|
|---|
| 52 | if (fServer==0)
|
|---|
| 53 | {
|
|---|
| 54 | Error("MTreeSQL","No TSQLServer specified");
|
|---|
| 55 | return;
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | fTables.push_back(table);
|
|---|
| 59 |
|
|---|
| 60 | // Constructor with an explicit TSQLServer
|
|---|
| 61 | TPRegexp reg(" +JOIN +([a-zA-Z0-9_.]+)");
|
|---|
| 62 |
|
|---|
| 63 | Int_t p = -1;
|
|---|
| 64 | while (p<addon.Length())
|
|---|
| 65 | {
|
|---|
| 66 | TArrayI pos;
|
|---|
| 67 | if (reg.Match(addon, "ig", ++p, 100, &pos)!=2)
|
|---|
| 68 | continue;
|
|---|
| 69 |
|
|---|
| 70 | if (pos[2] >= 0 && pos[3] >= 0)
|
|---|
| 71 | {
|
|---|
| 72 | const TString subStr = addon(pos[2], pos[3]-pos[2]);
|
|---|
| 73 | fTables.push_back(subStr);
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | p = pos[3];
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | for (auto it=fTables.begin(); it!=fTables.end(); it++)
|
|---|
| 80 | if (!CheckTable(*it))
|
|---|
| 81 | return;
|
|---|
| 82 |
|
|---|
| 83 | Init();
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | MTreeSQL::~MTreeSQL()
|
|---|
| 87 | {
|
|---|
| 88 | for (auto it=fRows.begin(); it!=fRows.end(); it++)
|
|---|
| 89 | delete *it;
|
|---|
| 90 |
|
|---|
| 91 | delete fResult;
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | //______________________________________________________________________________
|
|---|
| 95 | Bool_t MTreeSQL::CheckTable(const TString &table) const
|
|---|
| 96 | {
|
|---|
| 97 | // Check the table exist in the database
|
|---|
| 98 | if (fServer==0)
|
|---|
| 99 | return kFALSE;
|
|---|
| 100 |
|
|---|
| 101 | TSQLResult *tables = fServer->GetTables(table);
|
|---|
| 102 | if (!tables)
|
|---|
| 103 | return kFALSE;
|
|---|
| 104 |
|
|---|
| 105 | TSQLRow * row = 0;
|
|---|
| 106 | while ((row = tables->Next()))
|
|---|
| 107 | {
|
|---|
| 108 | if (table.CompareTo(row->GetField(0),TString::kIgnoreCase)==0)
|
|---|
| 109 | return kTRUE;
|
|---|
| 110 |
|
|---|
| 111 | delete row;
|
|---|
| 112 | }
|
|---|
| 113 | delete tables;
|
|---|
| 114 |
|
|---|
| 115 | // The table is a not a permanent table, let's see if it is a 'temporary' table
|
|---|
| 116 | const Int_t before = gErrorIgnoreLevel;
|
|---|
| 117 | gErrorIgnoreLevel = kFatal;
|
|---|
| 118 |
|
|---|
| 119 | TSQLResult *res = fServer->GetColumns(table);
|
|---|
| 120 | if (res)
|
|---|
| 121 | delete res;
|
|---|
| 122 |
|
|---|
| 123 | gErrorIgnoreLevel = before;
|
|---|
| 124 |
|
|---|
| 125 | if (!res)
|
|---|
| 126 | Error("CheckTable", "%s", ("Table "+table+" not found.").Data());
|
|---|
| 127 |
|
|---|
| 128 | return res ? kTRUE : kFALSE;
|
|---|
| 129 | }
|
|---|
| 130 |
|
|---|
| 131 | //______________________________________________________________________________
|
|---|
| 132 | void MTreeSQL::Init()
|
|---|
| 133 | {
|
|---|
| 134 | // Initializeation routine
|
|---|
| 135 | // Number of entries needed to create the branches
|
|---|
| 136 | //GetEntries();
|
|---|
| 137 |
|
|---|
| 138 | vector<pair<TString,TString>> cols;
|
|---|
| 139 |
|
|---|
| 140 | for (auto it=fTables.begin(); it!=fTables.end(); it++)
|
|---|
| 141 | {
|
|---|
| 142 | TSQLResult *res = fServer->GetColumns(*it);
|
|---|
| 143 |
|
|---|
| 144 | TSQLRow *row = 0;
|
|---|
| 145 | while ((row=res->Next()))
|
|---|
| 146 | {
|
|---|
| 147 | TString f1 = row->GetField(1);
|
|---|
| 148 |
|
|---|
| 149 | Int_t p0 = f1.First('(');
|
|---|
| 150 | if (p0<0)
|
|---|
| 151 | p0 = f1.First(' ');
|
|---|
| 152 | if (p0<0)
|
|---|
| 153 | p0 = f1.Length();
|
|---|
| 154 |
|
|---|
| 155 | const TString type = f1(0, p0);
|
|---|
| 156 |
|
|---|
| 157 | if (type.CompareTo("int", TString::kIgnoreCase) &&
|
|---|
| 158 | type.CompareTo("date", TString::kIgnoreCase) &&
|
|---|
| 159 | type.CompareTo("time", TString::kIgnoreCase) &&
|
|---|
| 160 | type.CompareTo("datetime", TString::kIgnoreCase) &&
|
|---|
| 161 | type.CompareTo("year", TString::kIgnoreCase) &&
|
|---|
| 162 | type.CompareTo("timestamp", TString::kIgnoreCase) &&
|
|---|
| 163 | type.CompareTo("bit", TString::kIgnoreCase) &&
|
|---|
| 164 | type.CompareTo("tinyint", TString::kIgnoreCase) &&
|
|---|
| 165 | type.CompareTo("smallint", TString::kIgnoreCase) &&
|
|---|
| 166 | type.CompareTo("mediumint", TString::kIgnoreCase) &&
|
|---|
| 167 | type.CompareTo("integer", TString::kIgnoreCase) &&
|
|---|
| 168 | type.CompareTo("bigint", TString::kIgnoreCase) &&
|
|---|
| 169 | type.CompareTo("decimal", TString::kIgnoreCase) &&
|
|---|
| 170 | type.CompareTo("int", TString::kIgnoreCase) &&
|
|---|
| 171 | type.CompareTo("real", TString::kIgnoreCase) &&
|
|---|
| 172 | type.CompareTo("float", TString::kIgnoreCase) &&
|
|---|
| 173 | type.CompareTo("double", TString::kIgnoreCase))
|
|---|
| 174 | {
|
|---|
| 175 | Info("Init", "%s", ("Skipping "+*it+"."+TString(row->GetField(0))+" ["+type+"]").Data());
|
|---|
| 176 | continue;
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | const TString name = *it+"."+row->GetField(0);
|
|---|
| 180 | cols.push_back(make_pair(name, type));
|
|---|
| 181 |
|
|---|
| 182 | delete row;
|
|---|
| 183 | }
|
|---|
| 184 | delete res;
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | TString list;
|
|---|
| 188 | for (auto it=cols.begin(); it!=cols.end(); it++)
|
|---|
| 189 | list += ","+it->first;
|
|---|
| 190 |
|
|---|
| 191 | list.Remove(0, 1);
|
|---|
| 192 |
|
|---|
| 193 | fResult = fServer->Query(("SELECT "+list+" FROM "+fQuery).Data());
|
|---|
| 194 | if (!fResult)
|
|---|
| 195 | return;
|
|---|
| 196 |
|
|---|
| 197 | TSQLRow *row = 0;
|
|---|
| 198 | while ((row=(TSQLRow*)fResult->Next()))
|
|---|
| 199 | fRows.push_back(row);
|
|---|
| 200 |
|
|---|
| 201 | fEntries = fRows.size();
|
|---|
| 202 |
|
|---|
| 203 | // ==============================================================
|
|---|
| 204 |
|
|---|
| 205 | // determine leaf description string
|
|---|
| 206 | Int_t idx = 0;
|
|---|
| 207 | for (auto it=cols.begin(); it!=cols.end(); it++, idx++)
|
|---|
| 208 | {
|
|---|
| 209 | const TString name = it->first;
|
|---|
| 210 |
|
|---|
| 211 | TBranch *br = TTree::Branch(name, 0, name+"/D");
|
|---|
| 212 |
|
|---|
| 213 | br->ResetAddress();
|
|---|
| 214 | br->SetEntries(fEntries);
|
|---|
| 215 |
|
|---|
| 216 | auto entry = br->GetBasketEntry();
|
|---|
| 217 | entry[0] = 0;
|
|---|
| 218 | entry[1] = fEntries;
|
|---|
| 219 |
|
|---|
| 220 | TBasket *bsk = new MBasketSQL(br, &fRow, idx, it->second);
|
|---|
| 221 |
|
|---|
| 222 | br->GetListOfBaskets()->AddAtAndExpand(bsk, 0);
|
|---|
| 223 | }
|
|---|
| 224 | }
|
|---|
| 225 |
|
|---|
| 226 | //______________________________________________________________________________
|
|---|
| 227 | Long64_t MTreeSQL::GetEntries() const
|
|---|
| 228 | {
|
|---|
| 229 | // Get the number of rows in the database
|
|---|
| 230 | return GetEntriesFast();
|
|---|
| 231 | }
|
|---|
| 232 |
|
|---|
| 233 | //______________________________________________________________________________
|
|---|
| 234 | Long64_t MTreeSQL::GetEntriesFast() const
|
|---|
| 235 | {
|
|---|
| 236 | // Return the number of entries as of the last check.
|
|---|
| 237 | // Use GetEntries for a more accurate count.
|
|---|
| 238 |
|
|---|
| 239 | return fEntries;
|
|---|
| 240 | }
|
|---|
| 241 |
|
|---|
| 242 | //______________________________________________________________________________
|
|---|
| 243 | Long64_t MTreeSQL::LoadTree(Long64_t entry)
|
|---|
| 244 | {
|
|---|
| 245 | // Setup the tree to the load the specified entry.
|
|---|
| 246 | // Make sure the server and result set are setup for the requested entry
|
|---|
| 247 | if (entry<0 || entry>=fEntries)
|
|---|
| 248 | return -1;
|
|---|
| 249 |
|
|---|
| 250 | fReadEntry = entry;
|
|---|
| 251 | fRow = fRows[entry];
|
|---|
| 252 |
|
|---|
| 253 | return entry;
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | //______________________________________________________________________________
|
|---|
| 257 | void MTreeSQL::Refresh()
|
|---|
| 258 | {
|
|---|
| 259 | if (!fServer)
|
|---|
| 260 | return;
|
|---|
| 261 |
|
|---|
| 262 | // Refresh contents of this Tree and his branches from the current
|
|---|
| 263 | // Tree status in the database
|
|---|
| 264 | // One can call this function in case the Tree on its file is being
|
|---|
| 265 | // updated by another process
|
|---|
| 266 | for (auto it=fRows.begin(); it!=fRows.end(); it++)
|
|---|
| 267 | delete *it;
|
|---|
| 268 |
|
|---|
| 269 | fRows.clear();
|
|---|
| 270 |
|
|---|
| 271 | delete fResult;
|
|---|
| 272 |
|
|---|
| 273 | Init();
|
|---|
| 274 | }
|
|---|
| 275 |
|
|---|
| 276 | //______________________________________________________________________________
|
|---|
| 277 | TBranch* MTreeSQL::BranchImp(const char *, const char *,
|
|---|
| 278 | TClass *, void *, Int_t ,
|
|---|
| 279 | Int_t )
|
|---|
| 280 | {
|
|---|
| 281 | // Not implemented yet
|
|---|
| 282 |
|
|---|
| 283 | Fatal("BranchImp","Not implemented yet");
|
|---|
| 284 | return 0;
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | //______________________________________________________________________________
|
|---|
| 288 | TBranch* MTreeSQL::BranchImp(const char *, TClass *,
|
|---|
| 289 | void *, Int_t , Int_t )
|
|---|
| 290 | {
|
|---|
| 291 | // Not implemented yet
|
|---|
| 292 |
|
|---|
| 293 | Fatal("BranchImp","Not implemented yet");
|
|---|
| 294 | return 0;
|
|---|
| 295 | }
|
|---|
| 296 |
|
|---|
| 297 | //______________________________________________________________________________
|
|---|
| 298 | Int_t MTreeSQL::Branch(TCollection *, Int_t,
|
|---|
| 299 | Int_t, const char *)
|
|---|
| 300 | {
|
|---|
| 301 | // Not implemented yet
|
|---|
| 302 |
|
|---|
| 303 | Fatal("Branch","Not implemented yet");
|
|---|
| 304 | return 0;
|
|---|
| 305 | }
|
|---|
| 306 |
|
|---|
| 307 | //______________________________________________________________________________
|
|---|
| 308 | Int_t MTreeSQL::Branch(TList *, Int_t, Int_t)
|
|---|
| 309 | {
|
|---|
| 310 | // Not implemented yet
|
|---|
| 311 |
|
|---|
| 312 | Fatal("Branch","Not implemented yet");
|
|---|
| 313 | return 0;
|
|---|
| 314 | }
|
|---|
| 315 |
|
|---|
| 316 | //______________________________________________________________________________
|
|---|
| 317 | Int_t MTreeSQL::Branch(const char *, Int_t ,
|
|---|
| 318 | Int_t)
|
|---|
| 319 | {
|
|---|
| 320 | // Not implemented yet
|
|---|
| 321 |
|
|---|
| 322 | Fatal("Branch","Not implemented yet");
|
|---|
| 323 | return 0;
|
|---|
| 324 | }
|
|---|
| 325 |
|
|---|
| 326 | //______________________________________________________________________________
|
|---|
| 327 | TBranch* MTreeSQL::Bronch(const char *, const char *, void *,
|
|---|
| 328 | Int_t, Int_t)
|
|---|
| 329 | {
|
|---|
| 330 | // Not implemented yet
|
|---|
| 331 |
|
|---|
| 332 | Fatal("Bronc","Not implemented yet");
|
|---|
| 333 | return 0;
|
|---|
| 334 | }
|
|---|
| 335 |
|
|---|
| 336 | //______________________________________________________________________________
|
|---|
| 337 | TBranch* MTreeSQL::BranchOld(const char *, const char *,
|
|---|
| 338 | void *, Int_t, Int_t)
|
|---|
| 339 | {
|
|---|
| 340 | // Not implemented yet
|
|---|
| 341 |
|
|---|
| 342 | Fatal("BranchOld","Not implemented yet");
|
|---|
| 343 | return 0;
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | //______________________________________________________________________________
|
|---|
| 347 | TBranch *MTreeSQL::Branch(const char *, const char *, void *,
|
|---|
| 348 | Int_t, Int_t)
|
|---|
| 349 | {
|
|---|
| 350 | // Not implemented yet
|
|---|
| 351 |
|
|---|
| 352 | Fatal("Branch","Not implemented yet");
|
|---|
| 353 | return 0;
|
|---|
| 354 | }
|
|---|
| 355 |
|
|---|
| 356 | //______________________________________________________________________________
|
|---|
| 357 | Int_t MTreeSQL::Fill()
|
|---|
| 358 | {
|
|---|
| 359 | Fatal("Fill","Not implemented yet");
|
|---|
| 360 | return -1;
|
|---|
| 361 | }
|
|---|