source: trunk/Mars/msql/MSQLServer.cc@ 15465

Last change on this file since 15465 was 15444, checked in by tbretz, 12 years ago
Allow to use Print as PrintQuery
File size: 20.9 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 2/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2006
21!
22!
23\* ======================================================================== */
24
25////////////////////////////////////////////////////////////////////////
26//
27// MSQLServer
28//
29// Using this instead of a TSQLServer gives the possibility to
30// browse a database server through the TBrowser and it will offer
31// many features usefull working with relational tables.
32//
33// Use it like TSQlServer:
34// new MSQLServer("mysql://localhost:3306?compress", "hercules", "stdmagicpassword");
35// // now start your TBrowser
36// new TBrowser;
37//
38////////////////////////////////////////////////////////////////////////
39#include "MSQLServer.h"
40
41#include <iostream>
42#include <iomanip>
43#include <stdlib.h>
44
45#include <TROOT.h>
46#include <TMath.h>
47
48#include <TH1.h>
49#include <TEnv.h>
50#include <TPRegexp.h>
51
52#include <TSQLResult.h>
53#include <TSQLServer.h>
54#include <TSQLRow.h>
55
56#include <TBrowser.h>
57
58#include <TObjString.h>
59#include <TObjArray.h>
60
61#include "MTreeSQL.h"
62
63ClassImp(MSQLServer);
64
65using namespace std;
66
67// --------------------------------------------------------------------------
68//
69// Used in virtual function TObject::Browse() to create the
70//
71void MSQLServer::BrowseColumn(TBrowser *b) /*FOLD00*/
72{
73 if (!fServ)
74 return;
75
76 const TString query0(Form("EXPLAIN %s.%s %s", (const char*)fDataBase, (const char*)fTable, (const char*)fColumn));
77 const TString query1(Form("SELECT %s FROM %s.%s", (const char*)fColumn, (const char*)fDataBase, (const char*)fTable));
78
79 //cout << query0 << endl;
80 TSQLResult *res = fServ->Query(query0);
81 if (!res)
82 {
83 cout << "query - failed: " << query0 << endl;
84 return;
85 }
86
87 TSQLRow *row=res->Next();
88 const TString desc(row ? (*row)[1] : "");
89
90 if (row)
91 delete row;
92
93 delete res;
94
95 const Bool_t isnum =
96 !desc.Contains("char", TString::kIgnoreCase) &&
97 !desc.Contains("text", TString::kIgnoreCase);
98
99 cout << query1 << endl;
100 res = fServ->Query(query1);
101 if (!res)
102 {
103 cout << "query - failed: " << query1 << endl;
104 return;
105 }
106
107 TArrayD arr(2);
108 Int_t num=0;
109 Double_t max=0;
110 Double_t min=0;
111 Double_t sum=0;
112 Double_t sqr=0;
113
114 while ((row=res->Next()))
115 {
116 const TString row0((*row)[0]);
117
118 if (!isnum)
119 {
120 cout << row0 << endl;
121 continue;
122 }
123
124 if (num==arr.GetSize())
125 arr.Set(arr.GetSize()*2);
126
127 arr[num] = atof(row0.Data());
128
129 if (num==0)
130 min=max=arr[0];
131
132 if (arr[num]>max) max = arr[num];
133 if (arr[num]<min) min = arr[num];
134
135 sum += arr[num];
136 sqr += arr[num]*arr[num];
137
138 num++;
139 }
140
141 delete res;
142
143 if (!isnum)
144 return;
145
146 if (max==min) max += 1;
147
148 Int_t num0 = 1;
149
150 if (num>0)
151 {
152 /*
153 cout << "Num: " << num << endl;
154 cout << "Mean: " << sum/num << endl;
155 cout << "Range: " << max-min << endl;
156 cout << "RMS: " << TMath::Sqrt(sqr/num-sum*sum/num/num) << endl;
157 */
158
159 num0 = (Int_t)((max-min)*40/TMath::Sqrt(sqr/num-sum*sum/num/num));
160 }
161
162 const TString title(Form("#splitline{%s}{<%s>}", (const char*)query1, (const char*)desc));
163
164 TH1F *hist=new TH1F(fColumn, title, num0, min, max);
165 for (int i=0; i<num; i++)
166 hist->Fill(arr[i]);
167
168 //cout << "Done." << endl;
169
170 hist->Draw();
171 hist->SetBit(kCanDelete);
172}
173
174void MSQLServer::BrowseTable(TBrowser *b) /*FOLD00*/
175{
176 if (!fServ)
177 return;
178
179 TSQLResult *res = fServ->GetColumns(fDataBase, fTable);
180 if (!res)
181 return;
182
183 TSQLRow *row;
184 while ((row=res->Next()))
185 {
186 TString row0((*row)[0]);
187 delete row;
188
189 MSQLServer *sql = (MSQLServer*)fList.FindObject(Form("%s/%s/%s", (const char*)fDataBase, (const char*)fTable, (const char*)row0));
190 if (!sql)
191 {
192 sql = new MSQLColumn(fServ, fDataBase, fTable, row0);
193 fList.Add(sql);
194 }
195 b->Add(sql, row0);
196 }
197}
198
199void MSQLServer::BrowseDataBase(TBrowser *b) /*FOLD00*/
200{
201 if (!fServ)
202 return;
203
204 TSQLResult *res = fServ->GetTables(fDataBase);
205 if (!res)
206 return;
207
208 TSQLRow *row;
209 while ((row=res->Next()))
210 {
211 TString row0((*row)[0]);
212 delete row;
213
214 MSQLServer *sql = (MSQLServer*)fList.FindObject(Form("%s/%s", (const char*)fDataBase, (const char*)row0));
215 if (!sql)
216 {
217 sql = new MSQLServer(fServ, fDataBase, row0);
218 fList.Add(sql);
219 }
220 b->Add(sql, row0);
221 }
222}
223
224void MSQLServer::BrowseServer(TBrowser *b) /*FOLD00*/
225{
226 if (!fServ)
227 return;
228
229 TSQLResult *res = fServ->GetDataBases();
230 if (!res)
231 return;
232
233 TSQLRow *row;
234 while ((row=res->Next()))
235 {
236 const TString row0((*row)[0]);
237 delete row;
238
239 MSQLServer *sql = (MSQLServer*)fList.FindObject(row0);
240 if (!sql)
241 {
242 sql = new MSQLServer(fServ, row0);
243 fList.Add(sql);
244 }
245 b->Add(sql, row0);
246 }
247}
248
249void MSQLServer::PrintLine(const TArrayI &max) /*FOLD00*/
250{
251 cout << "+" << setfill('-');
252 for (int i=0; i<max.GetSize(); i++)
253 cout << setw(max[i]+1) << "-" << "-+";
254 cout << endl;
255}
256
257void MSQLServer::PrintTable(TSQLResult &res) /*FOLD00*/
258{
259 Int_t n = res.GetFieldCount();
260
261 TArrayI max(n);
262
263 for (int i=0; i<n; i++)
264 max[i] = strlen(res.GetFieldName(i));
265
266 TSQLRow *row;
267
268 TList rows;
269 rows.SetOwner();
270
271 while ((row=res.Next()))
272 {
273 for (int i=0; i<n; i++)
274 max[i] = TMath::Max((ULong_t)max[i], row->GetFieldLength(i));
275 rows.Add(row);
276 }
277
278 cout << endl;
279
280 PrintLine(max);
281
282 cout << "|" << setfill(' ');
283 for (int i=0; i<n; i++)
284 cout << setw(max[i]+1) << res.GetFieldName(i) << " |";
285 cout << endl;
286
287 PrintLine(max);
288
289 cout << setfill(' ');
290 TIter Next(&rows);
291 while ((row=(TSQLRow*)Next()))
292 {
293 cout << "|";
294 for (int i=0; i<n; i++)
295 {
296 const char *c = (*row)[i];
297 cout << setw(max[i]+1) << (c?c:"") << " |";
298 }
299 cout << endl;
300 }
301
302 PrintLine(max);
303}
304
305TString MSQLServer::GetFields() const /*FOLD00*/
306{
307 if (!fServ)
308 return "";
309
310 TSQLResult *res = fServ->GetColumns(fDataBase, fTable);
311 if (!res)
312 return "";
313
314 TString fields;
315
316 TSQLRow *row;
317
318 TList rows;
319 rows.SetOwner();
320
321 while ((row=res->Next()))
322 rows.Add(row);
323
324 TIter Next(&rows);
325 while ((row=(TSQLRow*)Next()))
326 {
327 fields += (*row)[0];
328 if (row!=rows.Last())
329 fields += ", ";
330 }
331
332 return fields;
333}
334
335void MSQLServer::PrintQuery(const char *query) const /*FOLD00*/
336{
337 if (!fServ)
338 return;
339
340 TSQLResult *res = fServ->Query(query);
341 if (res)
342 {
343 PrintTable(*res);
344 delete res;
345 }
346 else
347 cout << "Query failed: " << query << endl;
348}
349
350void MSQLServer::Print(Option_t *o) const /*FOLD00*/
351{
352 const TString opt(o);
353 if (!opt.IsNull())
354 {
355 PrintQuery(o);
356 return;
357 }
358
359 switch (fType)
360 {
361 case kIsServer:
362 PrintQuery("SHOW DATABASES");
363 break;
364
365 case kIsDataBase:
366 PrintQuery(Form("SHOW TABLES FROM %s", (const char*)fDataBase));
367 break;
368
369 case kIsTable:
370 PrintQuery(Form("SELECT * FROM %s.%s", (const char*)fDataBase, (const char*)fTable));
371 break;
372
373 case kIsColumn:
374 PrintQuery(Form("SELECT %s FROM %s.%s", (const char*)fColumn, (const char*)fDataBase, (const char*)fTable));
375 break;
376
377 default:
378 break;
379 }
380}
381
382void MSQLServer::ShowColumns() const /*FOLD00*/
383{
384 switch (fType)
385 {
386 case kIsTable:
387 PrintQuery(Form("SHOW FULL COLUMNS FROM %s.%s", (const char*)fDataBase, (const char*)fTable));
388 break;
389
390 case kIsColumn:
391 PrintQuery(Form("SHOW FULL COLUMNS FROM %s.%s LIKE %s", (const char*)fDataBase, (const char*)fTable, (const char*)fColumn));
392 break;
393
394 default:
395 //Print();
396 break;
397 }
398}
399
400void MSQLServer::ShowStatus() const /*FOLD00*/
401{
402 switch (fType)
403 {
404 case kIsServer:
405 PrintQuery("SHOW STATUS");
406 break;
407
408 case kIsDataBase:
409 PrintQuery(Form("SHOW TABLE STATUS FROM %s", (const char*)fDataBase));
410 break;
411
412 case kIsTable:
413 PrintQuery(Form("SHOW TABLE STATUS FROM %s LIKE %s", (const char*)fDataBase, (const char*)fTable));
414 break;
415
416 default:
417 break;
418 }
419}
420
421void MSQLServer::ShowTableIndex() const /*FOLD00*/
422{
423 switch (fType)
424 {
425 case kIsTable:
426 case kIsColumn:
427 PrintQuery(Form("SHOW INDEX FROM %s.%s", (const char*)fDataBase, (const char*)fTable));
428 break;
429
430 default:
431 break;
432 }
433}
434
435void MSQLServer::ShowTableCreate() const /*FOLD00*/
436{
437 switch (fType)
438 {
439 case kIsTable:
440 case kIsColumn:
441 PrintQuery(Form("SHOW CREATE TABLE %s.%s", (const char*)fDataBase, (const char*)fTable));
442 break;
443
444 default:
445 break;
446 }
447}
448
449void MSQLServer::Close(Option_t *option) /*FOLD00*/
450{
451 if (fType==kIsServer && fServ)
452 {
453 fServ->Close(option);
454 if (TestBit(kIsOwner))
455 {
456 fTrees.Delete();
457
458 delete fServ;
459 fServ=0;
460 ResetBit(kIsOwner);
461 fType=kIsZombie;
462 }
463 }
464}
465
466// --------------------------------------------------------------------------
467//
468// Send a SQL query to the SQL server.
469//
470// If MSQLServer is no server (column, row, ...) NULL is returned and an
471// error message is send to stdout.
472//
473// If the query failed for some reason an error message is send to stdout
474// and NULL is returned.
475//
476// If everything works fine a TSQLResult is returned. Make sure that you
477// delete it!
478//
479TSQLResult *MSQLServer::Query(const char *sql) /*FOLD00*/
480{
481 if (!fServ)
482 return NULL;
483
484 if (fType!=kIsServer)
485 {
486 cout << "ERROR: MSQLServer::Query - this is not a server!" << endl;
487 return NULL;
488 }
489
490 TSQLResult *res = fServ->Query(sql);
491 if (!res)
492 {
493 cout << /*"ERROR: MSQLServer::Query - Query failed: " <<*/ sql << endl;
494 return NULL;
495 }
496
497 return res;
498}
499
500// --------------------------------------------------------------------------
501//
502// Send a SQL query to the SQL server.
503//
504// If MSQLServer is no server (column, row, ...) NULL is returned and an
505// error message is send to stdout.
506//
507// If the query failed kFALSE is returned.
508//
509// On success kTRUE is returned.
510//
511Bool_t MSQLServer::Exec(const char* sql)
512{
513 if (!fServ)
514 return kFALSE;
515
516#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
517 TSQLResult *res = fServ->Query(sql);
518 if (!res)
519 {
520 cout << "ERROR: MSQLServer::Exec - Query failed: " << sql << endl;
521 return kFALSE;
522 }
523 delete res;
524 return kTRUE;
525#else
526 if (fType!=kIsServer)
527 {
528 cout << "ERROR: MSQLServer::Exec - this is not a server!" << endl;
529 return kFALSE;
530 }
531
532 return fServ->Exec(sql);
533#endif
534}
535
536Int_t MSQLServer::SelectDataBase(const char *dbname) /*FOLD00*/
537{
538 fDataBase = dbname;
539 return fType==kIsServer && fServ ? fServ->SelectDataBase(dbname) : 0;
540}
541
542TSQLResult *MSQLServer::GetDataBases(const char *wild) /*FOLD00*/
543{
544 return fType==kIsServer && fServ ? fServ->GetDataBases(wild) : NULL;
545}
546
547TSQLResult *MSQLServer::GetTables(const char *wild, const char *dbname) /*FOLD00*/
548{
549 return fType==kIsServer && fServ ? fServ->GetTables(dbname?dbname:fDataBase.Data(), wild) : NULL;
550}
551
552TSQLResult *MSQLServer::GetColumns(const char *table, const char *wild, const char *dbname) /*FOLD00*/
553{
554 return fType==kIsServer && fServ ? fServ->GetColumns(dbname?dbname:fDataBase.Data(), table, wild) : NULL;
555}
556
557Int_t MSQLServer::CreateDataBase(const char *dbname) /*FOLD00*/
558{
559 return fType==kIsServer && fServ ? fServ->CreateDataBase(dbname) : 0;
560}
561
562Int_t MSQLServer::DropDataBase(const char *dbname) /*FOLD00*/
563{
564 return fType==kIsServer && fServ ? fServ->DropDataBase(dbname) : 0;
565}
566
567Int_t MSQLServer::Reload() /*FOLD00*/
568{
569 return fType==kIsServer && fServ ? fServ->Reload() : 0;
570}
571
572Int_t MSQLServer::Shutdown() /*FOLD00*/
573{
574 return fType==kIsServer && fServ ? fServ->Shutdown() : 0;
575}
576
577const char *MSQLServer::ServerInfo() /*FOLD00*/
578{
579 return fType==kIsServer && fServ ? fServ->ServerInfo() : "";
580}
581
582Bool_t MSQLServer::IsConnected() const
583{
584 return fType==kIsServer && fServ ? fServ->IsConnected() : kFALSE;
585}
586
587const char *MSQLServer::GetName() const
588{
589 if (!fServ)
590 return "Unconnected!";
591
592 switch (fType)
593 {
594 case kIsServer: return Form("%s://%s:%d/%s", fServ->GetDBMS(), fServ->GetHost(), fServ->GetPort(), fDataBase.Data());
595 case kIsDataBase: return GetNameDataBase();
596 case kIsTable: return GetNameTable();
597 case kIsColumn: return GetNameColumn();
598 default: return "n/a";
599 }
600}
601
602Bool_t MSQLServer::Split(TString &url, TString &user, TString &pasw) const
603{
604 const Ssiz_t pos1 = url.First("://")+3;
605 const Ssiz_t pos2 = url.Last(':') +1;
606 const Ssiz_t pos3 = url.First('@');
607
608 if (pos1<0 || pos2<0 || pos3<0 || pos1>pos2 || pos2>pos3)
609 return kFALSE;
610
611 user = url(pos1, pos2-pos1-1);
612 pasw = url(pos2, pos3-pos2);
613
614 url.Remove(pos1, pos3+1-pos1);
615
616 return kTRUE;
617}
618
619void MSQLServer::Init(const char *connection, const char *user, const char *password) /*FOLD00*/
620{
621 fType = kIsZombie;
622
623 fServ = TSQLServer::Connect(connection, user, password);
624 if (fServ)
625 {
626 gROOT->GetListOfBrowsables()->Add(this, connection);
627 fType = kIsServer;
628 SetBit(kIsOwner);
629 SetBit(kMustCleanup);
630 }
631 else
632 fType = kIsZombie;
633
634 fList.SetOwner();
635}
636
637void MSQLServer::InitEnv(TEnv &env, const char *prefix)
638{
639 TString url = env.GetValue("URL", "");
640 TString db = env.GetValue("Database", "");
641 TString user = env.GetValue("User", "");
642 TString pass = env.GetValue("Password", "");
643
644 user = env.GetValue(Form("%s.User", db.Data()), user);
645
646 pass = env.GetValue(Form("%s.Password", user.Data()), pass);
647 pass = env.GetValue(Form("%s.%s.Password", db.Data(), user.Data()), pass);
648
649 if (prefix)
650 {
651 url = env.GetValue(Form("%s.URL", prefix), url);
652 db = env.GetValue(Form("%s.Database", prefix), db);
653
654 user = env.GetValue(Form("%s.User", prefix), user);
655 user = env.GetValue(Form("%s.%s.User", prefix, db.Data()), user);
656
657 pass = env.GetValue(Form("%s.Password", prefix), pass);
658 pass = env.GetValue(Form("%s.%s.Password", prefix, user.Data()), pass);
659 pass = env.GetValue(Form("%s.%s.%s.Password", prefix, db.Data(), user.Data()), pass);
660 }
661
662 user = user.Strip(TString::kBoth);
663 pass = pass.Strip(TString::kBoth);
664 url = url.Strip(TString::kBoth);
665
666 if (user.IsNull() && pass.IsNull())
667 {
668 if (!Split(url, user, pass))
669 {
670 fType = kIsZombie;
671 return;
672 }
673 }
674
675 Init(url, user, pass);
676
677 if (IsConnected() && !db.IsNull())
678 SelectDataBase(db);
679}
680
681MSQLServer::MSQLServer(const char *connection, const char *user, const char *password) /*FOLD00*/
682{
683 Init(connection, user, password);
684}
685
686// --------------------------------------------------------------------------
687//
688// Instantiate a dabase connection either by
689// mysql://user:password@url/database
690// or by a resource file (in teh given string doesn't contain mysql://)
691//
692MSQLServer::MSQLServer(const char *u) : fType(kIsZombie) /*FOLD00*/
693{
694 if (TString(u).Contains("mysql://", TString::kIgnoreCase))
695 {
696 TString url(u);
697 TString user, pasw;
698
699 if (!Split(url, user, pasw))
700 {
701 fType = kIsZombie;
702 return;
703 }
704 Init(url, user, pasw);
705 }
706 else
707 {
708 TEnv env(u);
709 InitEnv(env);
710 }
711}
712
713MSQLServer::MSQLServer(TEnv &env, const char *prefix)
714{
715 InitEnv(env, prefix);
716}
717
718MSQLServer::MSQLServer()
719{
720 if (gEnv)
721 InitEnv(*gEnv);
722}
723
724MSQLServer::MSQLServer(MSQLServer &serv)
725{
726 fServ = serv.fServ;
727
728 fDataBase = serv.fDataBase;
729 fTable = serv.fTable;
730 fColumn = serv.fColumn;
731
732 fType = serv.fType;
733}
734
735MSQLServer::~MSQLServer() /*FOLD00*/
736{
737 if (gDebug>0)
738 cout << "Delete: " << GetName() << endl;
739
740 Close();
741}
742
743Bool_t MSQLServer::PrintError(const char *txt, const char *q) const /*FOLD00*/
744{
745 cout << "Fatal error acessing database: " << txt << endl;
746 cout << "Query: " << q << endl;
747 return kFALSE;
748}
749
750TString MSQLServer::GetEntry(const char *where, const char *col, const char *table) const /*FOLD00*/
751{
752 if (!fServ)
753 return "";
754
755 if (table==0)
756 table = Form("%s.%s", (const char *)fDataBase, (const char*)fTable);
757 if (col==0)
758 col = (const char *)fColumn;
759
760 const TString query(Form("SELECT %s FROM %s WHERE %s", col, table, where));
761
762 TSQLResult *res = fServ->Query(query);
763 if (!res)
764 return (PrintError("GetEntry - TSQLResult==NULL", query), "");
765
766 if (res->GetFieldCount()!=1)
767 {
768 delete res;
769 return (PrintError("GetEntry - Number of columns != 1", query), "");
770 }
771
772 if (res->GetRowCount()>1)
773 {
774 delete res;
775 return (PrintError("GetEntry - Number of rows > 1", query), "");
776 }
777
778 if (res->GetRowCount()==0)
779 {
780 delete res;
781 return "";
782 }
783
784 const char *fld = res->Next()->GetField(0);
785 if (!fld)
786 {
787 delete res;
788 return (PrintError("GetEntry - Entry is empty", query), "");
789 }
790
791 const TString rc(fld);
792 delete res;
793 return rc;
794}
795
796// --------------------------------------------------------------------------
797//
798// Return the name of the (first) column with a primary key
799//
800TString MSQLServer::GetPrimaryKeys(const char *table)
801{
802 TSQLResult *res = GetColumns(table);
803 if (!res)
804 return "";
805
806 TObjArray arr;
807 arr.SetOwner();
808
809 TSQLRow *row = 0;
810 while ((row=res->Next()))
811 {
812 const TString key = (*row)[3];
813 if (key=="PRI")
814 arr.Add(new TObjString((*row)[0]));
815 delete row;
816 }
817 delete res;
818
819 arr.Sort();
820
821 TString rc;
822 for (int i=0; i<arr.GetEntries(); i++)
823 {
824 if (i>0)
825 rc += ", ";
826 rc += arr[i]->GetName();
827 }
828 return rc;
829}
830
831// --------------------------------------------------------------------------
832//
833// Searches in the text for patterns like "Table.Column". If such a pettern
834// is found the primary key of the table is requested a "LEFT JOIN"
835// with this Table is added ON the identity of the primary key of Table
836// with the given table.
837//
838TString MSQLServer::GetJoins(const char *table, const TString text)
839{
840 Int_t p=0;
841
842 TString mods;
843 TArrayI pos;
844
845 // Find all Table.Column expression. Because also floating point
846 // numbers can contain a dot the result has to be checked carefully
847 TString joins;
848 TPRegexp reg = TPRegexp("\\w+[.]\\w+");
849 while (1)
850 {
851 // Check whether expression is found
852 if (reg.Match(text, mods, p, 130, &pos)==0)
853 break;
854
855 // Get expression from text
856 const TString expr = text(pos[0], pos[1]-pos[0]);
857 p = pos[1];
858
859 if (expr.IsFloat())
860 continue;
861
862 const TString tab = expr(0, expr.First('.'));
863 //const TString var = expr(expr.First('.')+1, expr.Length());
864
865 // If the table found is the primary table itself skip it.
866 if (tab==table)
867 continue;
868
869 // If this join has already be set, skip it.
870 if (joins.Contains(Form(" %s ", tab.Data())))
871 continue;
872
873 // Now get the primary key of the table to be joined
874 const TString prim = GetPrimaryKeys(tab);
875 if (prim.IsNull())
876 continue;
877
878 joins += Form("LEFT JOIN %s USING (%s) ", tab.Data(), prim.Data());
879 }
880
881 if (!joins.IsNull())
882 joins += " ";
883
884 return joins;
885}
886
887MTreeSQL *MSQLServer::GetTree(TString table, TString addon)
888{
889 if (fType!=kIsServer || !fServ || !TestBit(kIsOwner))
890 return 0;
891
892 TIter Next(&fTrees);
893 TObject *o = 0;
894 while ((o=Next()))
895 {
896 if (o->GetName()==table && o->GetName()==addon)
897 return (MTreeSQL*)o;
898 }
899
900 MTreeSQL *t = new MTreeSQL(this, table, addon);
901 fTrees.Add(t);
902
903 return t;
904}
905
906void MSQLServer::RecursiveRemove(TObject *obj)
907{
908 if (fServ==obj)
909 {
910 fServ=NULL;
911 fType = kIsZombie;
912 ResetBit(kIsOwner);
913 }
914}
Note: See TracBrowser for help on using the repository browser.