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