Index: trunk/MagicSoft/Mars/Changelog
===================================================================
--- trunk/MagicSoft/Mars/Changelog	(revision 7939)
+++ trunk/MagicSoft/Mars/Changelog	(revision 7940)
@@ -65,4 +65,15 @@
    * resources/sequences.rc:
      - resource file how to build sequences... added.
+
+   * msql/MSQLMagic.[h,cc]:
+     - added
+
+   * msql/MSQLServer.[h,cc]:
+     - added copy constructor
+     - allow fServ to be NULL (added sanity checks)
+     - Implemented Exec-command
+
+   * msql/Makefile, msql/SqlLinkDef.h:
+     - added MSQLMagic
 
 
Index: trunk/MagicSoft/Mars/msql/MSQLMagic.cc
===================================================================
--- trunk/MagicSoft/Mars/msql/MSQLMagic.cc	(revision 7940)
+++ trunk/MagicSoft/Mars/msql/MSQLMagic.cc	(revision 7940)
@@ -0,0 +1,247 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz 7/2006 <mailto:tbretz@astro.uni-wuerzburg.de>
+!
+!   Copyright: MAGIC Software Development, 2006
+!
+!
+\* ======================================================================== */
+
+////////////////////////////////////////////////////////////////////////
+//
+//  MSQLMagic
+//
+// This is an enhancement of MSQLServer especially made the feature
+// the interfaction with our database.
+//
+////////////////////////////////////////////////////////////////////////
+#include "MSQLMagic.h"
+
+#include <iostream>
+
+#include <TSQLRow.h>
+#include <TSQLResult.h>
+
+ClassImp(MSQLMagic);
+
+using namespace std;
+
+// --------------------------------------------------------------------------
+//
+// Return the name corresponding to a key. If col starts with f or
+// end with KEY it is stripped.
+//
+//  If the query fails an empty string is returned.
+//
+//  On success the name of the key is returned.
+//
+TString MSQLMagic::QueryNameOfKey(TString col, const char *key)
+{
+    if (col.EndsWith("KEY"))
+        col.Remove(col.Length()-3);
+    if (col.BeginsWith("f"))
+        col.Remove(0, 1);
+
+    const TString query=Form("SELECT f%sName FROM %s WHERE f%sKEY=%s",
+                             col.Data(), col.Data(), col.Data(), key);
+
+    TSQLResult *res = Query(query);
+    if (!res)
+        return "";
+
+    TSQLRow *row=res->Next();
+
+    const TString rc = row ? (*row)[0] : "";
+
+    delete res;
+    return rc;
+}
+
+// --------------------------------------------------------------------------
+//
+//  return the key of f[col]KEY where f[col]Name=[name]
+//
+//  if value [name] is not existing, insert value (creates anew key)
+//  and return the new key
+//
+//  return -1 if the query failed or the KEY was not found (insert=kFALSE)
+//  return  0 if the KEY could not be determined after inserting
+//  return the KEY in case of success
+//
+Int_t MSQLMagic::QueryKeyOfName(const char *col, const char *name, Bool_t insert)
+{
+    const TString query1 = Form("SELECT f%sKEY FROM %s WHERE f%sName='%s'",
+                                col, col, col, name);
+
+    TSQLResult *res1 = Query(query1);
+    if (!res1)
+    {
+        cout << "ERROR - Query has failed: " << query1 << endl;
+        return -1;
+    }
+
+    TSQLRow *row=res1->Next();
+
+    const Int_t rc1 = row && (*row)[0] ? atoi((*row)[0]) : -1;
+
+    delete res1;
+
+    if (rc1>=0)
+        return rc1;
+
+    if (!insert)
+        return -1;
+
+    //insert new value
+    const Int_t rc2 = Insert(col, Form("f%sName=\"%s\"", col, name));
+    if (rc2<0)       // Dummy mode
+        return 0;
+    if (rc2==kFALSE) // Query failed
+        return -1;
+
+    const Int_t key = QueryKeyOfName(col, name, kFALSE);
+    if (key>0)
+    {
+        cout << " - New " << col << ": " << name << endl;
+        return key;
+    }
+
+    return 0;
+}
+
+Bool_t MSQLMagic::ExistStr(const char *column, const char *table, const char *test)
+{
+    TString query(Form("SELECT %s FROM %s WHERE %s='%s'", column, table, column, test));
+    TSQLResult *res = Query(query);
+    if (!res)
+        return kFALSE;
+
+    Bool_t rc = kFALSE;
+
+    TSQLRow *row=res->Next();
+    if (row && (*row)[0])
+        rc=kTRUE;
+
+    delete res;
+    return rc;
+}
+
+// --------------------------------------------------------------------------
+//
+// An abbreviation for an Insert-Query.
+//
+// It builds "INSERT table SET vars"
+// The whitespaces are already conatined.
+//
+// On success kTRUE is returned, kFALSE otherwise.
+// In Dummy mode no query is send an -1 is returned.
+//
+Int_t MSQLMagic::Insert(const char *table, const char *vars)
+{
+    // Build query
+    TString query("INSERT ");
+    query += table;
+    query += " SET ";
+    query += vars;
+
+    // Check for dummy mode
+    if (fIsDummy)
+    {
+        cout << "MSQLMagic - DUMMY: " << query << endl;
+        return -1;
+    }
+
+    // Execute query
+    if (Exec(query))
+        return kTRUE;
+
+    // Return error on failure
+    cout << "Error - Insert failed: " << query << endl;
+    return kFALSE;
+}
+
+// --------------------------------------------------------------------------
+//
+// An abbreviation for an Update-Query.
+//
+// It builds "UPDATE table SET vars WHERE where"
+// The whitespaces are already conatined.
+//
+// On success kTRUE is returned, kFALSE otherwise.
+// In Dummy mode no query is send an -1 is returned.
+//
+Int_t MSQLMagic::Update(const char *table, const char *vars, const char *where)
+{
+    // Build query
+    TString query("UPDATE ");
+    query += table;
+    query += " SET ";
+    query += vars;
+    query += " WHERE ";
+    query += where;
+
+    // Check for dummy mode
+    if (fIsDummy)
+    {
+        cout << "MSQLMagic - DUMMY: " << query << endl;
+        return -1;
+    }
+
+    // Execute Query
+    if (Exec(query))
+        return kTRUE;
+
+    // return kFALSE on failure
+    cout << "Error - Update failed: " << query << endl;
+    return kFALSE;
+}
+
+// --------------------------------------------------------------------------
+//
+// An abbreviation for a Dalete-Query.
+//
+// It builds "DELETE table WHERE where"
+// The whitespaces are already conatined.
+//
+// On success kTRUE is returned, kFALSE otherwise.
+// In Dummy mode no query is send an -1 is returned.
+//
+Int_t MSQLMagic::Delete(const char *table, const char *where)
+{
+    // Build query
+    TString query("DELETE ");
+    query += table;
+    query += " WHERE ";
+    query += where;
+
+    // Check for dummy mode
+    if (fIsDummy)
+    {
+        cout << "MSQLMagic - DUMMY: " << query << endl;
+        return -1;
+    }
+
+    // Execute query
+    if (Exec(query))
+        return kTRUE;
+
+    // return kFALSE on failure
+    cout << "Error - Delete failed: " << query << endl;
+    return kFALSE;
+}
+
Index: trunk/MagicSoft/Mars/msql/MSQLMagic.h
===================================================================
--- trunk/MagicSoft/Mars/msql/MSQLMagic.h	(revision 7940)
+++ trunk/MagicSoft/Mars/msql/MSQLMagic.h	(revision 7940)
@@ -0,0 +1,53 @@
+#ifndef MARS_MSQLMagic
+#define MARS_MSQLMagic
+
+#ifndef MARS_MSQLServer
+#include "MSQLServer.h"
+#endif
+
+class MSQLMagic : public MSQLServer
+{
+    Bool_t fIsDummy;
+
+public:
+    MSQLMagic(TSQLServer *serv, const char *dbname=0, const char *tname=0, const char *col=0) :
+        MSQLServer(serv, dbname, tname, col), fIsDummy(kFALSE)
+    {
+    }
+
+    MSQLMagic(const char *connection, const char *user, const char *password) :
+        MSQLServer(connection, user, password), fIsDummy(kFALSE)
+    {
+    }
+
+    MSQLMagic(const char *link) : MSQLServer(link), fIsDummy(kFALSE)
+    {
+    }
+
+    MSQLMagic(TEnv &env, const char *prefix=0) :
+        MSQLServer(env, prefix), fIsDummy(kFALSE)
+    {
+    }
+
+    MSQLMagic() : MSQLServer(), fIsDummy(kFALSE)
+    {
+    }
+
+
+    void SetIsDummy(Bool_t dummy=kTRUE) { fIsDummy=dummy; }
+    Bool_t IsDummy() const { return fIsDummy; }
+
+    TString QueryNameOfKey(TString col, const char *key);
+    Int_t   QueryKeyOfName(const char *col, const char *name, Bool_t insert=kTRUE);
+    Bool_t  ExistStr(const char *column, const char *table, const char *test);
+
+    Int_t Insert(const char *table, const char *vars);
+    Int_t Update(const char *table, const char *vars, const char *where);
+    Int_t Delete(const char *table, const char *where);
+
+    void Delete(const Option_t *o) { TObject::Delete(o); }
+
+    ClassDef(MSQLMagic, 0) // An enhancement of MSQLServer featuring our database
+};
+
+#endif
Index: trunk/MagicSoft/Mars/msql/MSQLServer.cc
===================================================================
--- trunk/MagicSoft/Mars/msql/MSQLServer.cc	(revision 7939)
+++ trunk/MagicSoft/Mars/msql/MSQLServer.cc	(revision 7940)
@@ -64,4 +64,7 @@
 void MSQLServer::BrowseColumn(TBrowser *b) /*FOLD00*/
 {
+    if (!fServ)
+        return;
+
     const TString query0(Form("EXPLAIN %s.%s %s", (const char*)fDataBase, (const char*)fTable, (const char*)fColumn));
     const TString query1(Form("SELECT %s FROM %s.%s", (const char*)fColumn, (const char*)fDataBase, (const char*)fTable));
@@ -161,4 +164,7 @@
 void MSQLServer::BrowseTable(TBrowser *b) /*FOLD00*/
 {
+    if (!fServ)
+        return;
+
     TSQLResult *res = fServ->GetColumns(fDataBase, fTable);
     if (!res)
@@ -182,4 +188,7 @@
 void MSQLServer::BrowseDataBase(TBrowser *b) /*FOLD00*/
 {
+    if (!fServ)
+        return;
+
     TSQLResult *res = fServ->GetTables(fDataBase);
     if (!res)
@@ -203,4 +212,7 @@
 void MSQLServer::BrowseServer(TBrowser *b) /*FOLD00*/
 {
+    if (!fServ)
+        return;
+
     TSQLResult *res = fServ->GetDataBases();
     if (!res)
@@ -278,4 +290,7 @@
 TString MSQLServer::GetFields() const /*FOLD00*/
 {
+    if (!fServ)
+        return "";
+
     TSQLResult *res = fServ->GetColumns(fDataBase, fTable);
     if (!res)
@@ -303,4 +318,7 @@
 void MSQLServer::PrintQuery(const char *query) const /*FOLD00*/
 {
+    if (!fServ)
+        return;
+
     TSQLResult *res = fServ->Query(query);
     if (res)
@@ -407,11 +425,20 @@
 void MSQLServer::Close(Option_t *option) /*FOLD00*/
 {
-    if (fType==kIsServer)
+    if (fType==kIsServer && fServ)
+    {
         fServ->Close(option);
+        if (TestBit(kIsOwner))
+        {
+            delete fServ;
+            fServ=0;
+            ResetBit(kIsOwner);
+            fType=kIsZombie;
+        }
+    }
 }
 
 // --------------------------------------------------------------------------
 //
-// Send a SQL query to the SQl server.
+// Send a SQL query to the SQL server.
 //
 // If MSQLServer is no server (column, row, ...) NULL is returned and an
@@ -426,4 +453,7 @@
 TSQLResult *MSQLServer::Query(const char *sql) /*FOLD00*/
 {
+    if (!fServ)
+        return NULL;
+
     if (fType!=kIsServer)
     {
@@ -435,5 +465,5 @@
     if (!res)
     {
-        cout << "ERROR: MSQLServer::Query - Query failed: " << sql << endl;
+        cout << /*"ERROR: MSQLServer::Query - Query failed: " <<*/ sql << endl;
         return NULL;
     }
@@ -442,57 +472,96 @@
 }
 
+// --------------------------------------------------------------------------
+//
+// Send a SQL query to the SQL server.
+//
+// If MSQLServer is no server (column, row, ...) NULL is returned and an
+//  error message is send to stdout.
+//
+// If the query failed kFALSE is returned.
+//
+// On success kTRUE is returned.
+//
+Bool_t MSQLServer::Exec(const char* sql)
+{
+    if (!fServ)
+        return kFALSE;
+
+#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
+    TSQLResult *res = fServ->Query(sql);
+    if (!res)
+    {
+        cout << "ERROR: MSQLServer::Exec - Query failed: " << sql << endl;
+        return kFALSE;
+    }
+    delete res;
+    return kTRUE;
+#else
+    if (fType!=kIsServer)
+    {
+        cout << "ERROR: MSQLServer::Exec - this is not a server!" << endl;
+        return kFALSE;
+    }
+
+    return fServ->Exec(sql);
+#endif
+}
+
 Int_t MSQLServer::SelectDataBase(const char *dbname) /*FOLD00*/
 {
     fDataBase = dbname;
-    return fType==kIsServer ? fServ->SelectDataBase(dbname) : 0;
+    return fType==kIsServer && fServ ? fServ->SelectDataBase(dbname) : 0;
 }
 
 TSQLResult *MSQLServer::GetDataBases(const char *wild) /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->GetDataBases(wild) : NULL;
+    return fType==kIsServer && fServ ? fServ->GetDataBases(wild) : NULL;
 }
 
 TSQLResult *MSQLServer::GetTables(const char *dbname, const char *wild) /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->GetTables(dbname, wild) : NULL;
+    return fType==kIsServer && fServ ? fServ->GetTables(dbname, wild) : NULL;
 }
 
 TSQLResult *MSQLServer::GetColumns(const char *dbname, const char *table, const char *wild) /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->GetColumns(dbname, table, wild) : NULL;
+    return fType==kIsServer && fServ ? fServ->GetColumns(dbname, table, wild) : NULL;
 }
 
 Int_t MSQLServer::CreateDataBase(const char *dbname) /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->CreateDataBase(dbname) : 0;
+    return fType==kIsServer && fServ ? fServ->CreateDataBase(dbname) : 0;
 }
 
 Int_t MSQLServer::DropDataBase(const char *dbname) /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->DropDataBase(dbname) : 0;
+    return fType==kIsServer && fServ ? fServ->DropDataBase(dbname) : 0;
 }
 
 Int_t MSQLServer::Reload() /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->Reload() : 0;
+    return fType==kIsServer && fServ ? fServ->Reload() : 0;
 }
 
 Int_t MSQLServer::Shutdown() /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->Shutdown() : 0;
+    return fType==kIsServer && fServ ? fServ->Shutdown() : 0;
 }
 
 const char *MSQLServer::ServerInfo() /*FOLD00*/
 {
-    return fType==kIsServer ? fServ->ServerInfo() : "";
+    return fType==kIsServer && fServ ? fServ->ServerInfo() : "";
 }
 
 Bool_t MSQLServer::IsConnected() const
 {
-    return fType==kIsServer ? fServ->IsConnected() : kFALSE;
+    return fType==kIsServer && fServ ? fServ->IsConnected() : kFALSE;
 }
 
 const char *MSQLServer::GetName() const
 {
+    if (!fServ)
+        return "Unconnected!";
+
     switch (fType)
     {
@@ -531,4 +600,6 @@
         gROOT->GetListOfBrowsables()->Add(this, connection);
         fType = kIsServer;
+        SetBit(kIsOwner);
+        SetBit(kMustCleanup);
     }
     else
@@ -567,5 +638,5 @@
         if (!Split(url, user, pass))
         {
-            SetBit(kIsZombie);
+            fType = kIsZombie;
             return;
         }
@@ -590,5 +661,5 @@
     if (!Split(url, user, pasw))
     {
-        SetBit(kIsZombie);
+        fType = kIsZombie;
         return;
     }
@@ -607,9 +678,20 @@
 }
 
+MSQLServer::MSQLServer(MSQLServer &serv)
+{
+    fServ = serv.fServ;
+
+    fDataBase = serv.fDataBase;
+    fTable = serv.fTable;
+    fColumn = serv.fColumn;
+
+    fType = serv.fType;
+}
+
 MSQLServer::~MSQLServer() /*FOLD00*/
 {
-    Close();
     if (gDebug>0)
         cout << "Delete: " << GetName() << endl;
+    Close();
 }
 
@@ -666,2 +748,12 @@
     return rc;
 }
+
+void MSQLServer::RecursiveRemove(TObject *obj)
+{
+    if (fServ==obj)
+    {
+        fServ=NULL;
+        fType = kIsZombie;
+        ResetBit(kIsOwner);
+    }
+}
Index: trunk/MagicSoft/Mars/msql/MSQLServer.h
===================================================================
--- trunk/MagicSoft/Mars/msql/MSQLServer.h	(revision 7939)
+++ trunk/MagicSoft/Mars/msql/MSQLServer.h	(revision 7940)
@@ -14,4 +14,5 @@
 class MSQLServer : public TObject
 {
+private:
     TSQLServer *fServ;
 
@@ -25,4 +26,6 @@
 
     Type_t  fType;
+
+    enum { kIsOwner=BIT(14) };
 
     Bool_t IsFolder() const { return kTRUE; }
@@ -85,4 +88,5 @@
     MSQLServer(const char *link);
     MSQLServer(TEnv &env, const char *prefix=0);
+    MSQLServer(MSQLServer &serv);
     MSQLServer();
     ~MSQLServer();
@@ -106,4 +110,5 @@
     void Close(Option_t *option="");
     TSQLResult *Query(const char *sql);
+    Bool_t      Exec(const char* sql);
     Int_t       SelectDataBase(const char *dbname);
     TSQLResult *GetDataBases(const char *wild = 0);
@@ -118,4 +123,6 @@
 
     TString     GetEntry(const char *where, const char *col=0, const char *table=0) const;
+
+    void RecursiveRemove(TObject *obj);
 
     ClassDef(MSQLServer, 0) // An enhancement of TSQLServer
Index: trunk/MagicSoft/Mars/msql/Makefile
===================================================================
--- trunk/MagicSoft/Mars/msql/Makefile	(revision 7939)
+++ trunk/MagicSoft/Mars/msql/Makefile	(revision 7940)
@@ -22,5 +22,6 @@
 
 SRCFILES = \
-	MSQLServer.cc
+	MSQLServer.cc \
+        MSQLMagic.cc
 
 ############################################################
Index: trunk/MagicSoft/Mars/msql/SqlLinkDef.h
===================================================================
--- trunk/MagicSoft/Mars/msql/SqlLinkDef.h	(revision 7939)
+++ trunk/MagicSoft/Mars/msql/SqlLinkDef.h	(revision 7940)
@@ -8,3 +8,5 @@
 #pragma link C++ class MSQLServer+;
 
+#pragma link C++ class MSQLMagic+;
+
 #endif
