]> Creatis software - creaImageIO.git/blobdiff - src2/creaImageIOSQLiteTreeHandler.cpp
*** empty log message ***
[creaImageIO.git] / src2 / creaImageIOSQLiteTreeHandler.cpp
index e1a0307b3673093365844786789de7e0d589ac02..3bea907f3f31abae26fd805192186c6992ef3b59 100644 (file)
@@ -119,7 +119,8 @@ namespace creaImageIO
   //===================================================================== 
   int SQLiteTreeHandler::LoadChildren(tree::Node* parent, int maxlevel)
   {
-    return 0;
+    if (parent==0) parent = GetTree().GetTree();
+    return DBLoadChildren(parent,maxlevel);
   }
   //===================================================================== 
 
@@ -137,52 +138,8 @@ namespace creaImageIO
   int SQLiteTreeHandler::AddBranch( const AttributeMapType& attr )
   {
     tree::Node* parent = DBGetParent(attr);
-    for (int level = parent->GetLevel()+1;
-        level < GetTree().GetNumberOfLevels();
-        level++)
-      {
-       // Create Node
-       parent = new tree::Node(parent,attr);
-       
-       // Insert into DB
-       if (node->GetType()!=Node::Patient) 
-         node->SetFieldValue("PARENT_ID",parent_id);
-       
-       // Insert in DB
-       std::string val;
-       BuildSQLFieldsValues(node,val);
-       std::string insert("INSERT INTO ");
-       insert += std::string(SQLiteTreeHandlerStructure::Table(node->GetType())) 
-         + " " + val + ";";
-       //    std::cout << "** SQL = '"<<insert<<"'"<<std::endl;
-       UPDATEDB(insert);
-       //    std::cout << "** SQL OK"<<std::endl;
-       
-       // Store DB id of newly created node;
-       long lastrow = mDB->lastRowId();
-       std::stringstream ri;
-       ri << mDB->lastRowId();
-       node_id = ri.str();
-       //    std::cout << "LastRowId='"<<mDB->lastRowId()<<"' vs '"<<created_id<<"'"<<std::endl;
-       
-       node->SetFieldValue("ID",node_id);
-       /*
-       // Insert in TypeId map
-       TypeId ti;
-       ti.type = node->GetType();
-       ti.id = node_id;
-       mTypeIdToNodeMap[ti] = node;
-       //    std::cout << "== Insert TypeId ("<<ti.type<<","<<ti.id<<")"<<std::endl; 
-       // 
-       msw[2].Pause();
-       
-       if (node->GetType()==Node::Patient) summary.added_patients++;
-       if (node->GetType()==Node::Study) summary.added_studies++;
-       if (node->GetType()==Node::Series) summary.added_series++;
-       if (node->GetType()==Node::Image) summary.added_images++;
-       */
-      }
-    return -1;
+    DBGraftToParent(parent,attr);
+    return (parent->GetLevel()+1);
   }
   //===================================================================== 
  
@@ -194,7 +151,16 @@ namespace creaImageIO
    }
   //===================================================================== 
 
-
+  //===================================================================== 
+  /// Sets an attribute of a Node
+  bool SQLiteTreeHandler::SetAttribute(tree::Node* n, 
+                                      const std::string& key,
+                                      const std::string& value)
+  {
+    if (n==0) n=GetTree().GetTree();
+    return DBSetAttribute(n,key,value);
+  }
+  //===================================================================== 
 
 
 
@@ -231,17 +197,14 @@ namespace creaImageIO
 #define QUERYDB(QUER,RES)                                              \
     try                                                                        \
       {                                                                        \
-       GimmickMessage(2,"SQL: '"<<QUER<<"'"<<std::endl);               \
+       GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl);         \
        RES = mDB->execQuery(QUER.c_str());                             \
       }                                                                        \
     catch (CppSQLite3Exception& e)                                     \
       {                                                                        \
-       std::cout << "SQLite query '"<<QUER<<"' : "                     \
-                 << e.errorCode() << ":"                               \
-                 << e.errorMessage()<<std::endl;                       \
-       creaError("SQLite query '"<<QUER<<"' : "                        \
-                 << e.errorCode() << ":"                               \
-                 << e.errorMessage() );                                \
+       GimmickError("SQLite query '"<<QUER<<"' : "                     \
+                    << e.errorCode() << ":"                            \
+                    << e.errorMessage() );                             \
       }                                                                        \
     
   //=====================================================================
@@ -250,17 +213,14 @@ namespace creaImageIO
 #define UPDATEDB(UP)                                                   \
   try                                                                  \
     {                                                                  \
-      GimmickMessage(2,"SQL: '"<<UP<<"'"<<std::endl);                  \
+      GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl);           \
       mDB->execDML(UP.c_str());                                                \
     }                                                                  \
   catch (CppSQLite3Exception& e)                                       \
     {                                                                  \
-      std::cout << "SQLite update '"<<UP<<"' Error : "                 \
-               << e.errorCode() << ":"                                 \
-               << e.errorMessage()<<std::endl;                         \
-      creaError("SQLite update '"<<UP<<"' Error : "                    \
-               << e.errorCode() << ":"                                 \
-               << e.errorMessage() );                                  \
+      GimmickError("SQLite update '"<<UP<<"' Error : "                 \
+                  << e.errorCode() << ":"                              \
+                  << e.errorMessage() );                               \
     }                                                                  
   //=====================================================================
 
@@ -282,9 +242,9 @@ namespace creaImageIO
       }
     catch (CppSQLite3Exception& e)
       {
-       std::cerr << "Opening '"<<GetFileName()<<"' : "
-                 << e.errorCode() << ":" 
-                 << e.errorMessage() << std::endl;
+       GimmickError("Opening '"<<GetFileName()<<"' : "
+                    << e.errorCode() << ":" 
+                    << e.errorMessage());
        return false;
       }
     // IMPORT TREE DESCRIPTION (AND TEST DB VALIDITY)
@@ -307,9 +267,8 @@ namespace creaImageIO
 
     if (boost::filesystem::exists(GetFileName())) 
       {
-       creaMessage("Gimmick!",1,
-                   "[Gimmick!] !! ERROR '"<<GetFileName()<<"' : "
-                   << "file already exists"<<std::endl);
+       GimmickError(GetFileName()<<"' : "
+                    << "file already exists");
        return false;
       }
     
@@ -320,113 +279,113 @@ namespace creaImageIO
       }
     catch (CppSQLite3Exception& e)
       {
-       creaMessage("Gimmick!",1,
-                   "[Gimmick!] !! ERROR '"
-                   << e.errorCode() << ":" 
-                   << e.errorMessage() <<std::endl);
+       GimmickError(e.errorCode() << ":" 
+                    << e.errorMessage() <<std::endl);
        return false;
       }
     
+     
     // CREATING TABLES
-    try
+    
+    std::string command;
+    // Create LEVELS table
+    command = "create table LEVELS\n";
+    command += "( Name text )\n";
+    UPDATEDB(command);
+    
+    // Iterate the Levels
+    for (int l=0; l<GetTree().GetNumberOfLevels(); ++l)
       {
-       std::string command;
-       // Create LEVELS table
-       command = "create table LEVELS\n";
-       command += "( Name text )\n";
+       command = "INSERT INTO LEVELS (Name) VALUES ('";
+       command += GetTree().GetLevelDescriptor(l).GetName();
+       command += "')";
        UPDATEDB(command);
-
-       // Iterate the Levels
-       for (int l=0; l<GetTree().GetNumberOfLevels(); ++l)
+       
+       // Create table of level (for level>0, i.e. not Root)
+       if (l>=0)
          {
-           command = "INSERT INTO LEVELS (Name) VALUES ('";
+           command = "CREATE TABLE ";
            command += GetTree().GetLevelDescriptor(l).GetName();
-           command += "')";
+           command += "\n(\nID INTEGER PRIMARY KEY";
+           if (l>1) 
+             {
+               command += ",\nPARENT_ID int not null"; 
+             }
+           SQLAppendAttributesDefinition(l,command);
+           if (l>1) 
+             {
+               command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
+               command += GetTree().GetLevelDescriptor(l-1).GetName();
+               command += "(ID) on delete restrict on update restrict";
+             }
+           command += "\n)";
            UPDATEDB(command);
            
-           // Create table of level (for level>0, i.e. not Root)
-           if (l>0)
+           
+           // Add Attribute 'ID' to Description
+           GetTree().GetLevelDescriptor(l).Add
+             (AttributeDescriptor( "ID",
+                                   "Database Identifier",
+                                   0,0,
+                                   AttributeDescriptor::PRIVATE
+                                   ));
+           
+           if (l>1) 
              {
-               command = "CREATE TABLE ";
-               command += GetTree().GetLevelDescriptor(l).GetName();
-               command += "\n(\nID INTEGER PRIMARY KEY";
-               if (l>1) 
-                 {
-                   command += ",\nPARENT_ID int not null";     
-                 }
-               AppendAttributesSQLDefinition(l,command);
-               if (l>1) 
-                 {
-                   command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
-                   command += GetTree().GetLevelDescriptor(l-1).GetName();
-                   command += "(ID) on delete restrict on update restrict";
-                 }
-               command += "\n)";
-               UPDATEDB(command);
-
-
-               // Add Attribute 'ID' to Description
-               GetTree().GetAttributeDescriptorList(l).push_back
-                 (AttributeDescriptor( "ID",
-                                       "Database Identifier",
+               // Add Attribute 'PARENT_ID' to Description
+               GetTree().GetLevelDescriptor(l).Add
+                 (AttributeDescriptor( "PARENT_ID",
+                                       "Database Parent Identifier",
                                        0,0,
                                        AttributeDescriptor::PRIVATE
                                        ));
-
-               if (l>1) 
-                 {
-                   // Add Attribute 'PARENT_ID' to Description
-                   GetTree().GetAttributeDescriptorList(l).push_back
-                     (AttributeDescriptor( "PARENT_ID",
-                                           "Database Parent Identifier",
-                                           0,0,
-                                           AttributeDescriptor::PRIVATE
-                                           ));
-                 }
-               
              }
            
-           // Create table *_ATTRIBUTES
+         }
+       
+       // Create table *_ATTRIBUTES
+       
+       command = "CREATE TABLE ";
+       command += GetTree().GetLevelDescriptor(l).GetName();
+       command += "_Attributes\n(\n";
+       command += "Key text,\n";
+       command += "Name text,\n";          
+       command += "DicomGroup int,\n";
+       command += "DicomElement int,\n";           
+       command += "Flags int\n";           
+       command += "\n)";
+       UPDATEDB(command);
+       
+       
+       // Fill the table *_ATTRIBUTES
+       LevelDescriptor::AttributeDescriptorListType::const_iterator i;
+       for (i  = GetTree().GetAttributeDescriptorList(l).begin();
+            i != GetTree().GetAttributeDescriptorList(l).end();
+            ++i)
+         {
            
-           command = "CREATE TABLE ";
-           command += GetTree().GetLevelDescriptor(l).GetName();
-           command += "_Attributes\n(\n";
-           command += "Key text,\n";
-           command += "Name text,\n";      
-           command += "DicomGroup int,\n";
-           command += "DicomElement int,\n";       
-           command += "Flags int\n";       
-           command += "\n)";
-           UPDATEDB(command);
-         
-  
-           // Fill the table *_ATTRIBUTES
-           LevelDescriptor::AttributeDescriptorListType::const_iterator i;
-           for (i  = GetTree().GetAttributeDescriptorList(l).begin();
-                i != GetTree().GetAttributeDescriptorList(l).end();
-                ++i)
-             {
-               
-               std::stringstream insert;
-               insert << "INSERT INTO "
-                      << GetTree().GetLevelDescriptor(l).GetName()
-                      << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
-                      << "VALUES ('"
-                      << i->GetKey() << "','"
-                      << i->GetName() << "',"
-                      << i->GetGroup() << ","
-                      << i->GetElement() << ","
-                      << i->GetFlags() << ");";
-               
-               UPDATEDB(insert.str());
-             }
+           std::stringstream insert;
+           insert << "INSERT INTO "
+                  << GetTree().GetLevelDescriptor(l).GetName()
+                  << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
+                  << "VALUES ('"
+                  << i->GetKey() << "','"
+                  << i->GetName() << "',"
+                  << i->GetGroup() << ","
+                  << i->GetElement() << ","
+                  << i->GetFlags() << ");";
+           
+           UPDATEDB(insert.str());
          }
-      }
-    catch (std::exception)
-      {
-       return false;
-      }
 
+      } // For l=0...
+
+    // Initialize the root attributes
+    GetTree().InitializeAttributeMap();
+    // Insert the root in the level 0 table 
+    DBInsert(GetTree().GetTree());
+    
+    
     GetTree().SetChildrenLoaded(true);
     GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
                   <<"' ... OK"<<std::endl);
@@ -435,7 +394,7 @@ namespace creaImageIO
   //=====================================================================
   
   //=====================================================================
-  void SQLiteTreeHandler::AppendAttributesSQLDefinition(int level,
+  void SQLiteTreeHandler::SQLAppendAttributesDefinition(int level,
                                                        std::string& s)
   {
     LevelDescriptor::AttributeDescriptorListType::const_iterator i;
@@ -517,7 +476,7 @@ namespace creaImageIO
            std::string name(q.getStringField(1));
            GimmickMessage(2,"  - Importing attribute '"<<key<<"' '"<<name
                           <<"'"<<std::endl);
-           desc.GetAttributeDescriptorList(level).push_back
+           desc.GetLevelDescriptor(level).Add
              (AttributeDescriptor( key, // Key
                                    name, // Name
                                    q.getIntField(2), // Group
@@ -545,6 +504,36 @@ namespace creaImageIO
          }
       }
 
+
+    // Create the attributes table for Root (i.e. Tree)
+    LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+    for (a = GetTree().GetAttributeDescriptorList(0).begin();
+        a!= GetTree().GetAttributeDescriptorList(0).end();
+        ++a)
+      {
+       /*
+       std::string v;
+       AttributeMapType::const_iterator i = attr.find(a->GetKey());
+       if ( i != attr.end() )  
+         {
+           v = i->second;
+         }
+       */
+       GetTree().UnsafeSetAttribute( a->GetKey(), "" );
+      }
+
+    // Reading Root attributes
+    // Query DB
+    query = "SELECT * FROM ";
+    query += GetTree().GetLevelDescriptor(0).GetName();
+    QUERYDB(query,q);
+
+    for (int fld = 0; fld < q.numFields(); fld++)
+      {
+       GetTree().UnsafeSetAttribute(q.fieldName(fld),
+                                    q.getStringField(fld));        
+      }
+
     GimmickMessage(1,"Importing tree description from database ... OK"
                   <<std::endl);
     return true;
@@ -565,6 +554,60 @@ namespace creaImageIO
 
 
 
+
+
+  //========================================================================
+  /// 
+  std::string& SQLformat(std::string& str)
+  {
+    // quote must be doubled
+    boost::algorithm::replace_all(str,"'","''");
+    // Found strange strings which contained NULL char INSIDE string 
+    int i,size=str.size();
+    for (i=0;i<size;++i) 
+      {
+       if (str[i]==0) 
+         {
+           str = str.substr(0,i);
+           break;
+         }
+      }
+    //    if (i<str.size())
+    return str;
+  }
+  //========================================================================
+  
+  //=====================================================================
+  void SQLiteTreeHandler::SQLAppendAttributesValues(tree::Node* n, 
+                                                   std::string& str)
+  {
+    GimmickMessage(4,"SQLAppendAttributesValues"<<std::endl);
+    std::string atts="";
+    std::string values="";
+    tree::Node::AttributeMapType::iterator i;
+    for (i =  n->GetAttributeMap().begin();
+        i != n->GetAttributeMap().end();
+        i++)
+      {
+       if (i->first=="ID") 
+         {
+           continue;
+         }
+       //      std::cout << "("<<i->first<<","<<i->second<<")"<<std::endl;
+       atts += "'" + i->first + "'";
+       values += "'" + SQLformat(i->second) + "'"; 
+       atts += ",";
+       values += ",";
+       GimmickMessage(4,"'"<<i->first<<"' = '"<<i->second<<"'"<<std::endl);
+      }
+    atts[atts.size()-1]=' ';
+    values[values.size()-1]=' ';
+
+    str = "("+atts+") VALUES ("+values+")";
+    GimmickMessage(4,"Result = '"<<str<<"'"<<std::endl);
+  }
+  //=====================================================================
+
   //=====================================================================
   tree::Node* SQLiteTreeHandler::DBGetParent( const AttributeMapType& attr) 
   {
@@ -585,6 +628,7 @@ namespace creaImageIO
              {
                go_down = true;
                parent = *i;
+               break;
              }
          }     
       }
@@ -595,19 +639,40 @@ namespace creaImageIO
 
 
   //=====================================================================
-  int SQLiteTreeHandler::DBLoadChildren(tree::Node* parent
+  int SQLiteTreeHandler::DBLoadChildren(tree::Node* node
                                        int numberoflevels)
   {
+    if (node->GetLevel()+1 >= node->GetTree()->GetNumberOfLevels() ) 
+      return 0;
+
+    GimmickMessage(2,"Loading children of '"<<node->GetLabel()
+                  <<"'"<<std::endl);
+
     int nbloaded = 0;
-    if (parent->GetChildrenLoaded()) return nbloaded;
+    // If children loaded we do not have to do it but we need to recurse
+    // in order to load the children's children if necessary, and so on...
+    if (node->GetChildrenLoaded()) 
+      {
+       // Iterate the children 
+       tree::Node::ChildrenListType::iterator i;
+       for (i = node->GetChildrenList().begin();
+            i!= node->GetChildrenList().end();
+            ++i)
+         {
+           nbloaded += DBLoadChildren(*i,numberoflevels-1);
+         }
+       return nbloaded;
+      }
+    
+    /// If children not loaded : do it and recurse
 
     // Query DB
-    int level = parent->GetLevel();
+    int level = node->GetLevel();
     std::string query = "SELECT * FROM ";
     query += GetTree().GetLevelDescriptor(level+1).GetName();
-    if (level>1)
+    if (level>0)
       {
-       query += " WHERE PARENT_ID='" + parent->UnsafeGetAttribute("ID") 
+       query += " WHERE PARENT_ID='" + node->UnsafeGetAttribute("ID") 
          + "'";
       }
     CppSQLite3Query q;
@@ -616,7 +681,7 @@ namespace creaImageIO
     while (!q.eof())
       {
        nbloaded++;
-       Node* n = new Node(parent);
+       Node* n = new Node(node);
        for (int fld = 0; fld < q.numFields(); fld++)
          {
            n->UnsafeSetAttribute(q.fieldName(fld),q.getStringField(fld));          
@@ -629,7 +694,7 @@ namespace creaImageIO
        mTypeIdToNodeMap[ti] = n;
        */
        // recurse 
-       if ( numberoflevels > 1 ) 
+       if ( numberoflevels != 1 ) 
          {
            //  msw[2].Pause();
            nbloaded += DBLoadChildren(n, numberoflevels-1);
@@ -639,88 +704,113 @@ namespace creaImageIO
        q.nextRow();
       }
 
-    parent->SetChildrenLoaded(true);
+    node->SetChildrenLoaded(true);
     
     //    msw[2].Pause();
     return nbloaded;
+  }
+  //=====================================================================
 
-    //    std::cout << "SQLiteTreeHandler::DBLoadChildren("<<parent<<","<<maxlevel
-    //      << ")"<<std::endl;
-    /*
-    int nbloaded = 0;
-    if (parent == GetTree()) { parent = 0; }
-    Node* xparent = parent;
-    if ( xparent==0 ) xparent = GetTree();
-    if ( xparent->ChildrenLoaded() ) 
-      {
-       //      std::cout << "--> Children already loaded"<<std::endl;
-       return nbloaded;
-      }
-    if ( xparent->GetType() == Node::Image ) 
-      {
-       return nbloaded;
-      }
-    if ( xparent->GetType() >= maxlevel ) 
-      {
-       return nbloaded;
-      }
-   
-    //    msw[2].Pause();
-    //    msw[2].Resume();
-
-    Node::Type type = xparent->GetType()+1;
-
-    // Query DB
-
-    std::string query = "SELECT * FROM ";
-    query += GetTree().GetDescriptor().GetLevelDescriptor(level).GetName();
-      //SQLiteTreeHandlerStructure::Table(type);
-    if (parent!=0)
-      {
-       query += " WHERE PARENT_ID='" + parent->GetFieldValue("ID") + "'";
-      }
-
-    //    std::cout << "** SQL = '"<<query<<"'"<<std::endl;
+  //======================================================================
+  void SQLiteTreeHandler::DBInsert(tree::Node* n)
+  {
+    GimmickMessage(2,"Inserting in DB '"<<n->GetLabel()
+                  <<"'"<<std::endl);
+    std::string val;
+    SQLAppendAttributesValues(n,val);
+    std::string insert("INSERT INTO ");
+    insert += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
+    insert += " " + val + ";";
+    UPDATEDB(insert);
+       
+    // Store DB id of newly created node;
+    long lastrow = mDB->lastRowId();
+    std::stringstream ri;
+    ri << mDB->lastRowId();
+    n->SetAttribute("ID",ri.str());
+  }
+  //======================================================================
 
-    CppSQLite3Query q;
-    QUERYDB(query,q);
+  //======================================================================
+  /// Graft the branch defined by the attributes to the parent
+  void SQLiteTreeHandler::DBGraftToParent( tree::Node* parent, 
+                                           const AttributeMapType& attr)
+  {
+    GimmickMessage(2,"Grafting to parent '"<<parent->GetLabel()
+                  <<"'"<<std::endl);
 
-    while (!q.eof())
+    for (int level = parent->GetLevel()+1;
+        level < GetTree().GetNumberOfLevels();
+        level++)
       {
-       nbloaded++;
-       Node* n = new Node(type,
-                          this,xparent);
-       for (int fld = 0; fld < q.numFields(); fld++)
-         {
-           n->SetFieldValue(q.fieldName(fld),q.getStringField(fld));       
-         }
-       // Index 
+       // Create Node
+       tree::Node* child = new tree::Node(parent,attr);
+       
+       // Set PARENT_ID if necessary 
+       if ( parent->GetLevel()>0 )
+         child->SetAttribute("PARENT_ID",parent->GetAttribute("ID"));
+       
+       // Insert in DB
+       DBInsert(child);
+       /*
+       std::string val;
+       SQLAppendAttributesValues(child,val);
+       std::string insert("INSERT INTO ");
+       insert += GetTree().GetLevelDescriptor(child->GetLevel()).GetName();
+       insert += " " + val + ";";
+       UPDATEDB(insert);
+       
+       // Store DB id of newly created node;
+       long lastrow = mDB->lastRowId();
+       std::stringstream ri;
+       ri << mDB->lastRowId();
+       child->SetAttribute("ID",ri.str());
+       */
+       // Down one level
+       parent = child;
+       
+       /*
+       // Insert in TypeId map
        TypeId ti;
-       ti.type = type;
-       ti.id = n->GetFieldValue("ID");    
-       mTypeIdToNodeMap[ti] = n;
-       // recurse 
-       if ( type < maxlevel ) 
-         {
-           msw[2].Pause();
-           nbloaded += DBLoadChildren(n,maxlevel);
-           msw[2].Resume();
-         }
-       // next entry in db
-       q.nextRow();
+       ti.type = node->GetType();
+       ti.id = node_id;
+       mTypeIdToNodeMap[ti] = node;
+       //    std::cout << "== Insert TypeId ("<<ti.type<<","<<ti.id<<")"<<std::endl; 
+       // 
+       msw[2].Pause();
+       
+       if (node->GetType()==Node::Patient) summary.added_patients++;
+       if (node->GetType()==Node::Study) summary.added_studies++;
+       if (node->GetType()==Node::Series) summary.added_series++;
+       if (node->GetType()==Node::Image) summary.added_images++;
+       */
       }
-
-    xparent->SetChildrenLoaded(true);
-    
-    //    msw[2].Pause();
-    return nbloaded;
-    */
   }
-  //=====================================================================
-
-
+  //======================================================================
 
 
+  //===================================================================== 
+  /// Sets an attribute of a Node
+  bool SQLiteTreeHandler::DBSetAttribute(tree::Node* n, 
+                                        const std::string& key,
+                                        const std::string& value)
+  {
+    GimmickMessage(3,"Setting Attribute of '"<<n->GetLabel()<<
+                  "' "<<key<<"='"<<value<<"'"<<std::endl);
+
+    n->SetAttribute(key,value);
+    std::string sql = "UPDATE ";
+    sql += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
+    sql += " SET ";
+    sql += key;
+    sql += "='";
+    sql += value;
+    sql += "' WHERE ID=";
+    sql += n->GetAttribute("ID");
+    //    sql += " LIMIT 1";
+    UPDATEDB(sql);
+  }
+  //===================================================================== 
 
   /*
   //=====================================================================
@@ -1070,57 +1160,8 @@ namespace creaImageIO
   }
   //=====================================================================
  
-  //========================================================================
-  std::string& format_sql2(std::string& str)
-  {
-    // quote must be doubled
-    //    crea::Utils::Replace( str, "'", "''" );
-    boost::algorithm::replace_all(str,"'","''");
-    // Found strange strings which contained NULL char INSIDE string 
-    int i,size=str.size();
-    for (i=0;i<size;++i) 
-      {
-       if (str[i]==0) 
-         {
-           str = str.substr(0,i);
-           break;
-         }
-      }
-    //    if (i<str.size())
-    return str;
-  }
-   //========================================================================
-
-  //=====================================================================
-  void SQLiteTreeHandler::BuildSQLFieldsValues(Node* n,
-                                       std::string& str)
-  {
-    //    std::cout << "BuildSQLFieldsValues('"<<n->GetLabel()<<"')"<<std::endl;
-
-    std::string atts="";
-    std::string values="";
-    Node::FieldValueMapType::iterator i;
-    for (i =  n->GetFieldValueMap().begin();
-        i != n->GetFieldValueMap().end();
-        i++)
-      {
-       if (i->first=="ID") 
-         {
-           continue;
-         }
-       //      std::cout << "("<<i->first<<","<<i->second<<")"<<std::endl;
-       atts += "'" + i->first + "'";
-       values += "'" + format_sql2(i->second) + "'"; 
-       atts += ",";
-       values += ",";
-      }
-    atts[atts.size()-1]=' ';
-    values[values.size()-1]=' ';
-
-    str = "("+atts+") VALUES ("+values+")";
 
-  }
-  //=====================================================================
 */