]> Creatis software - creaImageIO.git/blob - src2/creaImageIOSQLiteTreeHandler.cpp
Clean-Up with Juan Sebastien
[creaImageIO.git] / src2 / creaImageIOSQLiteTreeHandler.cpp
1 #include <creaImageIOSQLiteTreeHandler.h>
2 #include <creaImageIOSystem.h>
3
4 #include "CppSQLite3.h"
5
6 #include <sys/stat.h>
7
8 //#include <creaImageIOSQLiteTreeHandlerStructure.h>
9
10 //#include <creaImageIOUtilities.h>
11
12 //#include <icons/database.xpm>
13
14 #include <deque>
15
16 //#include <icons/close.xpm>
17
18 #include <creaWx.h>
19 using namespace crea;
20
21 #include <boost/filesystem.hpp>
22 #include <boost/algorithm/string/replace.hpp>
23
24 namespace creaImageIO
25 {
26   using namespace tree;
27
28
29   //=============================================================
30   SQLiteTreeHandler::SQLiteTreeHandler(const std::string& filename)
31     : mFileName(filename)
32   {
33     mDB = new CppSQLite3DB;
34         mIsAdding=false;
35     GimmickMessage(1,"SQLite version : "
36                    <<std::string(mDB->SQLiteVersion())<< std::endl);
37   }
38   //=============================================================
39
40   //=============================================================
41   SQLiteTreeHandler::~SQLiteTreeHandler()
42   {
43     delete mDB;
44   }
45   //=============================================================
46   
47
48   //=====================================================================
49
50
51   //=====================================================================
52   bool SQLiteTreeHandler::Open(bool writable)
53   {
54     //    std::cout << "***> SQLiteTreeHandler::Open('"<<GetFileName()<<"')"<<std::endl;
55     SetWritable(writable);
56     return DBOpen();
57   }
58
59   //=====================================================================
60   bool SQLiteTreeHandler::Create(bool writable)
61   {
62     //    std::cout << "***> SQLiteTreeHandler::New('"<<GetFileName()<<"')"<<std::endl;
63     SetWritable(writable);
64     return DBCreate();
65   }
66   //=====================================================================
67
68
69   //=====================================================================
70   bool SQLiteTreeHandler::Close()
71   {
72     return true;
73   }
74   //=====================================================================
75
76
77   //=====================================================================
78   bool SQLiteTreeHandler::Destroy()
79   {
80     return false;
81   }
82   
83   //===================================================================== 
84
85   //===================================================================== 
86   int SQLiteTreeHandler::LoadChildren(tree::Node* parent, int maxlevel)
87   {
88     if (parent==0) parent = GetTree().GetTree();
89     return DBLoadChildren(parent,maxlevel);
90   }
91   //===================================================================== 
92
93
94
95
96   //===================================================================== 
97   void SQLiteTreeHandler::UnLoad(tree::Node* n)
98   {
99   }
100   //===================================================================== 
101
102   //===================================================================== 
103   int SQLiteTreeHandler::AddBranch( const AttributeMapType& attr )
104   {
105     tree::Node* parent = DBGetParent(attr);
106     DBGraftToParent(parent,attr);
107     return (parent->GetLevel()+1);
108           
109   }
110   //===================================================================== 
111  
112
113   //===================================================================== 
114    bool SQLiteTreeHandler::Remove(tree::Node* node)
115    {
116    DBRecursiveRemoveNode(node);
117  
118     //    std::cout << "DELETE"<<std::endl;
119    bool remove=false;
120    tree::Node* parent=node->GetParent();
121     if (parent)
122       {
123         int nC = parent->RemoveChildrenFromList(node);
124         if(nC>0 && parent->GetLevel()>0)
125         {       
126                 std::stringstream out;
127                 out <<nC;
128                 SetAttribute(parent,"NumberOfChildren",out.str());
129         }
130         else
131         {
132                 remove=true;
133         }
134
135       }
136     delete node;
137         if(remove&&parent->GetLevel()>0)
138         {
139                 Remove(parent);
140         }
141     //    std::cout << "DELETE OK"<<std::endl;
142     return true;
143    }
144   
145   //===================================================================== 
146
147   //===================================================================== 
148   /// Sets an attribute of a Node
149   bool SQLiteTreeHandler::SetAttribute(tree::Node* n, 
150                                        const std::string& key,
151                                        const std::string& value)
152   {
153     if (n==0) n=GetTree().GetTree();
154     return DBSetAttribute(n,key,value);
155   }
156   //===================================================================== 
157    //===================================================================== 
158   /// Sets an attribute
159   void SQLiteTreeHandler::SetAttribute(const std::string& levelDescriptor, 
160                               const std::string& key,
161                               const std::string& value,
162                                   const std::string& searchParam, 
163                                   const std::string& searchVal)
164   {
165         DBSetAttribute(levelDescriptor,key,value,searchParam, searchVal);
166   }
167   //===================================================================== 
168   /// Deletes a tuple
169   void SQLiteTreeHandler::DeleteTuple(std::string levelDescriptor, 
170                                                                 std::string key, std::string value)
171   {
172     DBDelete(levelDescriptor,key,value);
173   }
174   //===================================================================== 
175
176
177
178
179
180
181
182
183
184
185
186
187
188   //=====================================================================
189   // SQLite DB specific methods
190   //=====================================================================
191
192
193
194
195   //=====================================================================
196   char* format_sql(const std::string& s)
197   { 
198     return sqlite3_mprintf("%q",s.c_str());
199   }
200   //=====================================================================
201
202   
203   //=====================================================================
204 #define QUERYDB(QUER,RES)                                               \
205     try                                                                 \
206       {                                                                 \
207         GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl);         \
208         RES = mDB->execQuery(QUER.c_str());                             \
209       }                                                                 \
210     catch (CppSQLite3Exception& e)                                      \
211       {                                                                 \
212         GimmickError("SQLite query '"<<QUER<<"' : "                     \
213                      << e.errorCode() << ":"                            \
214                      << e.errorMessage() );                             \
215       }                                                                 \
216     
217   //=====================================================================
218   
219   //=====================================================================
220 #define UPDATEDB(UP)                                                    \
221   try                                                                   \
222     {                                                                   \
223       GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl);            \
224       mDB->execDML(UP.c_str());                                         \
225     }                                                                   \
226   catch (CppSQLite3Exception& e)                                        \
227     {                                                                   \
228       GimmickError("SQLite update '"<<UP<<"' Error : "                  \
229                    << e.errorCode() << ":"                              \
230                    << e.errorMessage() );                               \
231     }                                                                   
232   //=====================================================================
233
234
235   //=====================================================================
236   bool SQLiteTreeHandler::DBOpen()
237   {
238     GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
239                    <<"' ... "<<std::endl);
240     // OPENING FILE
241     if (!boost::filesystem::exists(GetFileName())) 
242       {
243         return false;
244       }
245
246     try
247       {
248         mDB->open(GetFileName().c_str());
249       }
250     catch (CppSQLite3Exception& e)
251       {
252         GimmickError("Opening '"<<GetFileName()<<"' : "
253                      << e.errorCode() << ":" 
254                      << e.errorMessage());
255         return false;
256       }
257     // IMPORT TREE DESCRIPTION (AND TEST DB VALIDITY)
258     if (!DBImportTreeDescription())
259       {
260         return false;
261       }
262
263     GimmickDebugMessage(1,"Opening SQLite database '"<<GetFileName()
264                    <<"' ... OK"<<std::endl);
265     return true;
266   }
267   //=====================================================================
268
269   //=====================================================================
270   bool SQLiteTreeHandler::DBCreate()
271   {
272     GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
273                    <<"' ... "<<std::endl);
274
275     if (boost::filesystem::exists(GetFileName())) 
276       {
277         GimmickError(GetFileName()<<"' : "
278                      << "file already exists");
279         return false;
280       }
281     
282     // OPENING
283     try
284       {
285         mDB->open(GetFileName().c_str());
286       }
287     catch (CppSQLite3Exception& e)
288       {
289         GimmickError(e.errorCode() << ":" 
290                      << e.errorMessage() <<std::endl);
291         return false;
292       }
293     
294      
295     // CREATING TABLES
296     
297     std::string command;
298     // Create LEVELS table
299     command = "create table LEVELS\n";
300     command += "( Name text )\n";
301     UPDATEDB(command);
302     int l;
303     // Iterate the Levels
304     for (l=0; l<GetTree().GetNumberOfLevels(); l++)
305       {
306         command = "INSERT INTO LEVELS (Name) VALUES ('";
307         command += GetTree().GetLevelDescriptor(l).GetName();
308         command += "')";
309         UPDATEDB(command);
310         
311         // Create table of level (for level>0, i.e. not Root)
312         if (l>=0)
313           {
314             command = "CREATE TABLE ";
315             command += GetTree().GetLevelDescriptor(l).GetName();
316             command += "\n(\nID INTEGER PRIMARY KEY";
317             if (l>1) 
318               {
319                 command += ",\nPARENT_ID int not null"; 
320               }
321             SQLAppendAttributesDefinition(l,command);
322             if (l>1) 
323               {
324                 command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
325                 command += GetTree().GetLevelDescriptor(l-1).GetName();
326                 command += "(ID) on delete restrict on update restrict";
327               }
328             command += "\n)";
329             UPDATEDB(command);
330             
331             
332             // Add Attribute 'ID' to Description
333             GetTree().GetDescriptor().Add
334               (AttributeDescriptor( "ID",
335                                     "Database Identifier",
336                                     0,0,
337                                     AttributeDescriptor::PRIVATE
338                                     ),l);
339             
340             if (l>1) 
341               {
342                 // Add Attribute 'PARENT_ID' to Description
343                 GetTree().GetDescriptor().Add
344                   (AttributeDescriptor( "PARENT_ID",
345                                         "Database Parent Identifier",
346                                         0,0,
347                                         AttributeDescriptor::PRIVATE
348                                         ),l);
349               }
350             
351           }
352         
353         // Create table *_ATTRIBUTES
354         
355         command = "CREATE TABLE ";
356         command += GetTree().GetLevelDescriptor(l).GetName();
357         command += "_Attributes\n(\n";
358         command += "Key text,\n";
359         command += "Name text,\n";          
360         command += "DicomGroup int,\n";
361         command += "DicomElement int,\n";           
362         command += "Flags int\n";           
363         command += "\n)";
364         UPDATEDB(command);
365         
366         
367         // Fill the table *_ATTRIBUTES
368         LevelDescriptor::AttributeDescriptorListType::const_iterator i;
369         for (i  = GetTree().GetAttributeDescriptorList(l).begin();
370              i != GetTree().GetAttributeDescriptorList(l).end();
371              ++i)
372           {
373             
374             std::stringstream insert;
375             insert << "INSERT INTO "
376                    << GetTree().GetLevelDescriptor(l).GetName()
377                    << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
378                    << "VALUES ('"
379                    << i->GetKey() << "','"
380                    << i->GetName() << "',"
381                    << i->GetGroup() << ","
382                    << i->GetElement() << ","
383                    << i->GetFlags() << ");";
384             UPDATEDB(insert.str());
385           }
386
387       } // For l=0...
388
389     // Initialize the root attributes
390     GetTree().InitializeAttributeMap();
391     // Insert the root in the level 0 table 
392     DBInsert(GetTree().GetTree());
393     
394     
395     GetTree().SetChildrenLoaded(true);
396     GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
397                    <<"' ... OK"<<std::endl);
398     return true;
399   }
400   //=====================================================================
401   
402   //=====================================================================
403   void SQLiteTreeHandler::SQLAppendAttributesDefinition(int level,
404                                                         std::string& s)
405   {
406     LevelDescriptor::AttributeDescriptorListType::const_iterator i;
407     for (i  = GetTree().GetAttributeDescriptorList(level).begin();
408          i != GetTree().GetAttributeDescriptorList(level).end();
409          ++i)
410       {
411         //      if (i->second.flags==1) continue;
412         s += ",\n";
413         s += i->GetKey();
414         s += " text";
415       }
416   }
417   //=====================================================================
418   
419   
420   //=====================================================================
421   bool SQLiteTreeHandler::DBImportTreeDescription()
422   {
423     GimmickMessage(1,"Importing tree description for database ..."
424                    <<std::endl);
425
426     // Test table 'LEVELS' existence
427     if ( ! mDB->tableExists("LEVELS") )
428       {
429         GimmickMessage(1,"!! ERROR : Table 'LEVELS' does not exist"
430                        <<std::endl);
431         return false;
432       }
433
434     tree::Descriptor& desc = GetTree().GetDescriptor();
435     // clears the existing one
436     desc.Clear();
437      
438     int nblevel = 0;
439     std::string query = "SELECT * FROM LEVELS";
440     CppSQLite3Query q;
441     QUERYDB(query,q);
442
443     while (!q.eof())
444       {
445         std::string name = q.getStringField(0);
446         GimmickMessage(2," * Importing level '"<<name<<"'"<<std::endl);
447         desc.Add(LevelDescriptor(name));
448         nblevel++;
449         q.nextRow();
450       }   
451     
452     for (int level = 0; level < nblevel; ++level )
453       {
454         std::string table = GetTree().GetLevelDescriptor(level).GetName();
455         table += "_Attributes";
456         // Test table 'LEVELS' existence
457         if ( ! mDB->tableExists(table.c_str()) )
458           {
459             GimmickMessage(1,"!! ERROR : Table '"<<table<<"' does not exist"
460                            <<std::endl);
461             return false;
462           }
463         
464         std::string query = "SELECT * FROM ";
465         query += table;
466         CppSQLite3Query q;
467         QUERYDB(query,q);
468         
469         GimmickMessage(2," * Level '"
470                        <<GetTree().GetLevelDescriptor(level).GetName()
471                        <<"'"<<std::endl);
472
473         // Test that ID and PARENT_ID mandatory attributes exist
474         bool ID_found = false;
475         bool PARENT_ID_found = false;
476         if (level==0) ID_found = true;
477         if (level<=1) PARENT_ID_found = true;
478
479         while (!q.eof())
480           {
481             std::string key(q.getStringField(0));
482             std::string name(q.getStringField(1));
483             GimmickMessage(2,"  - Importing attribute '"<<key<<"' '"<<name
484                            <<"'"<<std::endl);
485             desc.Add
486               (AttributeDescriptor( key, // Key
487                                     name, // Name
488                                     q.getIntField(2), // Group
489                                     q.getIntField(3), // Element 
490                                     q.getIntField(4) // Flags
491                                     ),level);
492             if ( key == "ID" ) 
493               {
494                 ID_found = true;
495               }
496             if ( key == "PARENT_ID" ) 
497               {
498                 PARENT_ID_found = true;
499               }
500             q.nextRow();
501           }
502         
503         if ( ! (ID_found || PARENT_ID_found ) )
504           {
505             GimmickMessage(1,"!! ERROR : Table '"<<table
506                            <<"' does not contain mandatory attribute ID or PARENT_ID"
507                            <<std::endl);
508             return false;
509  
510           }
511       }
512
513
514     // Create the attributes table for Root (i.e. Tree)
515     LevelDescriptor::AttributeDescriptorListType::const_iterator a;
516     for (a = GetTree().GetAttributeDescriptorList(0).begin();
517          a!= GetTree().GetAttributeDescriptorList(0).end();
518          ++a)
519       {
520
521         GetTree().UnsafeSetAttribute( a->GetKey(), "" );
522       }
523
524     // Reading Root attributes
525     // Query DB
526     query = "SELECT * FROM ";
527     query += GetTree().GetLevelDescriptor(0).GetName();
528     QUERYDB(query,q);
529
530     for (int fld = 0; fld < q.numFields(); fld++)
531       {
532         GetTree().UnsafeSetAttribute(q.fieldName(fld),
533                                      q.getStringField(fld));        
534       }
535
536     GimmickMessage(1,"Importing tree description from database ... OK"
537                    <<std::endl);
538     return true;
539   }
540   //=====================================================================
541
542   //========================================================================
543   /// 
544   std::string& SQLformat(std::string& str)
545   {
546     // quote must be doubled
547     boost::algorithm::replace_all(str,"'","''");
548     // Found strange strings which contained NULL char INSIDE string 
549     int i,size=str.size();
550     for (i=0;i<size;++i) 
551       {
552         if (str[i]==0) 
553           {
554             str = str.substr(0,i);
555             break;
556           }
557       }
558     //    if (i<str.size())
559     return str;
560   }
561   //========================================================================
562   
563   //=====================================================================
564   void SQLiteTreeHandler::SQLAppendAttributesValues(tree::Node* n, 
565                                                     std::string& str)
566   {
567     GimmickMessage(4,"SQLAppendAttributesValues"<<std::endl);
568     std::string atts="";
569     std::string values="";
570     tree::Node::AttributeMapType::iterator i;
571     for (i =  n->GetAttributeMap().begin();
572          i != n->GetAttributeMap().end();
573          i++)
574       {
575         if (i->first=="ID") 
576           {
577             continue;
578           }
579
580         atts += "'" + i->first + "'";
581         values += "'" + SQLformat(i->second) + "'"; 
582         atts += ",";
583         values += ",";
584         GimmickMessage(4,"'"<<i->first<<"' = '"<<i->second<<"'"<<std::endl);
585       }
586     atts[atts.size()-1]=' ';
587     values[values.size()-1]=' ';
588
589     str = "("+atts+") VALUES ("+values+")";
590     GimmickMessage(4,"Result = '"<<str<<"'"<<std::endl);
591   }
592   //=====================================================================
593
594   //=====================================================================
595   tree::Node* SQLiteTreeHandler::DBGetParent( const AttributeMapType& attr) 
596   {
597     Node* parent = GetTree().GetTree();
598     bool go_down;
599     do 
600       {
601         go_down = false;
602         // Load the children of the current parent
603         DBLoadChildren(parent);
604         // Iterate the children 
605         tree::Node::ChildrenListType::const_iterator i;
606         for (i = parent->GetChildrenList().begin();
607              i!= parent->GetChildrenList().end();
608              ++i)
609           {
610             if ( (*i)->Matches( attr ) ) 
611               {
612                 go_down = true;
613                 parent = *i;
614                 break;
615               }
616           }     
617       }
618     while (go_down);
619     return parent;
620   }
621   //=====================================================================
622
623   //=====================================================================
624   int SQLiteTreeHandler::DBLoadChildren(tree::Node* node, 
625                                         int numberoflevels)
626   {
627     if (node->GetLevel()+1 >= node->GetTree()->GetNumberOfLevels() ) 
628       return 0;
629
630     GimmickMessage(2,"Loading children of '"<<node->GetLabel()
631                    <<"'"<<std::endl);
632
633     int nbloaded = 0;
634     // If children loaded we do not have to do it but we need to recurse
635     // in order to load the children's children if necessary, and so on...
636     if (node->GetChildrenLoaded()) 
637       {
638         // Iterate the children 
639
640         tree::Node::ChildrenListType::iterator i;
641         for (i = node->GetChildrenList().begin();
642              i!= node->GetChildrenList().end();
643              ++i)
644           {
645             nbloaded += DBLoadChildren(*i,numberoflevels-1);
646           }
647         node->SetChildrenLoaded(true);
648         return nbloaded;
649
650       }
651         else
652         {
653     /// If children not loaded : do it and recurse
654
655     // Query DB
656     int level = node->GetLevel();
657     std::string query = "SELECT * FROM ";
658         
659     query += GetTree().GetLevelDescriptor(level+1).GetName();
660     if (level>0)
661       {
662         query += " WHERE PARENT_ID='" + node->GetAttribute("ID") 
663           + "'";
664       }
665     CppSQLite3Query q;
666     QUERYDB(query,q);
667
668         int p=0;
669     while (!q.eof())
670       {
671
672         //      std::cout << "DBLoadCh : creating node level "<<level+1<<std::endl;
673
674         nbloaded++;
675         Node* n = new Node(node);
676         for (int fld = 0; fld < q.numFields(); fld++)
677           {
678             n->UnsafeSetAttribute(q.fieldName(fld),q.getStringField(fld));          
679           }
680
681         // recurse 
682         if ( numberoflevels != 1 ) 
683           {
684             //  msw[2].Pause();
685             nbloaded += DBLoadChildren(n, numberoflevels-1);
686             //      msw[2].Resume();
687           }
688         // next entry in db
689         q.nextRow();
690       }
691
692     node->SetChildrenLoaded(true);
693         
694     
695     //    msw[2].Pause();
696     return nbloaded;
697         }
698   }
699   //=====================================================================
700
701   //======================================================================
702   void SQLiteTreeHandler::DBInsert(tree::Node* n)
703   {
704     GimmickMessage(2,"Inserting in DB '"<<n->GetLabel()
705                    <<"'"<<std::endl);
706     std::string val;
707     SQLAppendAttributesValues(n,val);
708     std::string insert("INSERT INTO ");
709     insert += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
710     insert += " " + val + ";";
711
712     UPDATEDB(insert);
713         
714     // Store DB id of newly created node;
715     long lastrow = mDB->lastRowId();
716     std::stringstream ri;
717     ri << mDB->lastRowId();
718     n->SetAttribute("ID",ri.str());
719   }
720   //======================================================================
721
722   //======================================================================
723   /// Graft the branch defined by the attributes to the parent
724   void SQLiteTreeHandler::DBGraftToParent( tree::Node* parent, 
725                                             const AttributeMapType& attr)
726   {
727     //    std::cout <<"Grafting to parent '"<<parent->GetLabel()
728     //             <<"'"<<std::endl;
729
730     for (int level = parent->GetLevel()+1;
731          level < GetTree().GetNumberOfLevels();
732          level++)
733       {
734         // Create Node
735         tree::Node* child = new tree::Node(parent,attr);
736         child->SetChildrenLoaded(true);
737         if (level>1)
738           {
739             int nc = GetNumberOfChildren(parent)+1;
740             
741             //  std::cout<<"Number of children "<<parent->GetNumberOfChildren()<<std::endl;
742             std::stringstream out;
743             out << nc;
744             SetAttribute(parent,"NumberOfChildren",out.str());
745           }
746
747         // Set PARENT_ID if necessary 
748         if ( parent->GetLevel()>0 )
749           child->SetAttribute("PARENT_ID",parent->GetAttribute("ID"));
750         
751         // Insert in DB
752         DBInsert(child);
753         
754         // Down one level
755         parent = child;
756           }
757   }
758   //======================================================================
759
760
761   //===================================================================== 
762   /// Sets an attribute of a Node
763   bool SQLiteTreeHandler::DBSetAttribute(tree::Node* n, 
764                                          const std::string& key,
765                                          const std::string& value)
766   {
767     GimmickMessage(3,"Setting Attribute of '"<<n->GetLabel()<<
768                    "' "<<key<<"='"<<value<<"'"<<std::endl);
769
770     n->SetAttribute(key,value);
771     std::string sql = "UPDATE ";
772     sql += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
773     sql += " SET ";
774     sql += key;
775     sql += " = '";
776     sql += value;
777     sql += "' WHERE ID = '";
778     sql += n->GetAttribute("ID");
779         sql +="'";
780     //    sql += " LIMIT 1";
781     UPDATEDB(sql);
782         return true;
783   }
784
785   //===================================================================== 
786   /// Sets an attribute of a Node
787   void SQLiteTreeHandler::DBSetAttribute(const std::string& levelDescriptor, 
788                               const std::string& key,
789                               const std::string& value,
790                                   const std::string& searchParam, 
791                                   const std::string& searchVal)
792   {
793
794     std::string sql = "UPDATE ";
795     sql += levelDescriptor;
796     sql += " SET ";
797     sql += key;
798     sql += " = '";
799     sql += value;
800     sql += "' WHERE ";
801         sql += searchParam;
802         sql += " = '";
803     sql += searchVal;
804         sql += "'";
805         std::cout<<sql<<std::endl;
806     UPDATEDB(sql);
807   }
808    //=====================================================================
809   void SQLiteTreeHandler::DBRecursiveRemoveNode(Node* node)
810   {
811        
812     std::string query = "DELETE FROM ";
813    
814     query += GetTree().GetLevelDescriptor(node->GetLevel()).GetName();
815     query += " WHERE ID='"+ node->GetAttribute("ID") + "';";
816  
817     UPDATEDB(query);
818         GimmickDebugMessage(2,
819                             " Deleting '"
820                                 <<node->GetLabel()<<"' with ID '"
821                             <<node->GetAttribute("ID")
822                             <<"' in level "<< GetTree().GetLevelDescriptor(node->GetLevel()).GetName()
823                             <<std::endl);
824
825
826         if(node->GetNumberOfChildren()!=0)
827         {
828                 Node::ChildrenListType::iterator i;
829                 for (i  = node->GetChildrenList().begin();
830                 i != node->GetChildrenList().end();
831                 i++)
832                 {
833                 DBRecursiveRemoveNode((*i));
834                 }
835         }
836         else if(node->GetLevel()<GetTree().GetNumberOfLevels()-1)
837         {
838                 DBRecursiveRemoveNode(node->GetLevel()+1,node->GetAttribute("ID"));
839     }
840   }
841
842   //=====================================================================
843   void SQLiteTreeHandler::DBRecursiveRemoveNode(int level, std::string parentId)
844   {
845     std::stringstream out;
846         std::stringstream result;
847         out<<"SELECT ID FROM "<<GetTree().GetLevelDescriptor(level).GetName()<<" WHERE PARENT_ID='"<<parentId<<"'";
848                 
849         CppSQLite3Query q;
850         QUERYDB(out.str(),q);
851         
852         while (!q.eof())
853           {
854             for (int fld = 0; fld < q.numFields(); fld++)
855               {
856                           result<<q.getStringField(fld)<<"#";
857               }
858             q.nextRow();
859           }
860           std::string res=result.str();
861           size_t ini=0;
862           size_t fin=0;
863           while(fin<res.size()-1)
864           {
865            fin=res.find('#',ini);
866            DBDelete(GetTree().GetLevelDescriptor(level).GetName(),"ID",res.substr(ini,fin-ini));
867           if(level<GetTree().GetNumberOfLevels()-1)
868           {
869                 DBRecursiveRemoveNode(level+1,res.substr(ini,fin-ini));
870           } 
871            ini=fin+1;
872           }
873           
874     
875   }
876
877   //=====================================================================
878   void SQLiteTreeHandler::DBDelete(std::string levelDescriptor, std::string key, std::string value)
879   {
880        
881     std::stringstream query;
882         query<<"DELETE FROM "<<levelDescriptor<<" WHERE "<<key<<"='"<<value<<"';";
883  
884     UPDATEDB(query.str());
885         GimmickDebugMessage(2," Deleting: Query: "<<query.str()<<std::endl);
886   }
887
888
889   //===================================================================== 
890   void SQLiteTreeHandler::GetAttribute(std::string levelDescriptor,
891                                                                            std::string searchParam, 
892                                                                            std::string searchVal, 
893                                                                            std::string key, 
894                                                                            std::string& result) 
895   { 
896         std::stringstream out;
897         std::stringstream results;
898         out<<"SELECT "<<key<<" FROM "<<levelDescriptor;
899         if(searchParam!="")
900         {
901                 out<<" WHERE "<<searchParam<<"='"<<searchVal<<"'";
902         }
903         
904         CppSQLite3Query q;
905         QUERYDB(out.str(),q);
906         
907         
908         while (!q.eof())
909           {
910             for (int fld = 0; fld < q.numFields(); fld++)
911               {
912                           results<<q.getStringField(fld);
913                           if(searchParam=="")
914                           {
915                                   results<<"#";
916                           }
917               }
918             q.nextRow();
919           }
920         result=results.str();
921       
922   }
923   //===================================================================== 
924   unsigned int SQLiteTreeHandler::GetNumberOfChildren(tree::Node* n) 
925   { 
926     // Query DB
927     int nb=0;
928     int level = n->GetLevel();
929
930     if(level<GetTree().GetNumberOfLevels()&& level>0)
931       {
932         std::string query = "SELECT NumberOfChildren FROM ";
933         query += GetTree().GetLevelDescriptor(level).GetName();
934         if (level>0)
935           {
936             query += " WHERE ID='" + n->GetAttribute("ID") 
937               + "'";
938           }
939         CppSQLite3Query q;
940         QUERYDB(query,q);
941         
942         
943         while (!q.eof())
944           {
945             for (int fld = 0; fld < q.numFields(); fld++)
946               {
947                 nb=q.getIntField(fld);  
948               }
949             q.nextRow();
950           }
951       }
952     /*
953     if(nb==0)
954       { 
955         nb=1;
956       }
957     */
958     return nb; 
959   }
960
961   //===================================================================== 
962   void SQLiteTreeHandler::GetTopLevelNodeId(const std::string& searchParam, const std::string& searchValue, std::string& parent_id) 
963   {
964           int level=GetTree().GetNumberOfLevels()-1;
965           std::string sp=searchParam.c_str();
966           std::string sv=searchValue.c_str();
967
968           while(level>1)
969           {
970                 std::stringstream out;
971                 std::stringstream results;
972                 out<<"SELECT PARENT_ID FROM "<<GetTree().GetLevelDescriptor(level).GetName();
973                 out<<" WHERE "<<sp<<"='"<<sv<<"'";      
974                 CppSQLite3Query q;
975                 QUERYDB(out.str(),q);
976                 
977                 
978                 while (!q.eof())
979                 {
980                         for (int fld = 0; fld < q.numFields(); fld++)
981                         {
982                                 results<<q.getStringField(fld);
983                         }
984                         q.nextRow();
985                 }
986                 level=level-1;
987                 sp="ID";
988                 sv=results.str();
989           }
990           parent_id=sv;
991
992   }
993
994   //=====================================================================
995   void SQLiteTreeHandler::RemoveEntries(const std::string i_table, 
996                 const std::string i_attribute, 
997                 const std::string i_operand, 
998                 const std::string i_val)
999     {
1000         std::stringstream query;
1001                 query<<"DELETE  FROM "<<i_table<<" WHERE "<<i_attribute<<" "<<i_operand<<" '"<<i_val<<"'";
1002         UPDATEDB(query.str());
1003         }
1004
1005         //=====================================================================
1006   void SQLiteTreeHandler::BeginTransaction()
1007     {
1008                 std::stringstream out;
1009                 out<<"begin transaction;";
1010         UPDATEDB(out.str());
1011         }
1012
1013         //=====================================================================
1014   void SQLiteTreeHandler::EndTransaction()
1015     {
1016        std::stringstream out;
1017                 out<<"commit transaction;";
1018         UPDATEDB(out.str());
1019         }
1020
1021 } // namespace creaImageIO