]> Creatis software - creaImageIO.git/blob - src2/creaImageIOTimestampDatabaseHandler.cpp
Added Timestamp database to avoid repetition of files on addition.
[creaImageIO.git] / src2 / creaImageIOTimestampDatabaseHandler.cpp
1 #include <creaImageIOTimestampDatabaseHandler.h>
2 #include <creaImageIOSystem.h>
3
4 #include "CppSQLite3.h"
5
6 #include <sys/stat.h>
7
8 #include <deque>
9
10 #include "wx/wx.h"
11 #include <wx/dir.h>
12 #include <wx/filename.h>
13
14 #include <creaWx.h>
15 using namespace crea;
16
17 #include <boost/filesystem.hpp>
18 #include <boost/algorithm/string/replace.hpp>
19
20 namespace creaImageIO
21 {
22         using namespace tree;
23   //=============================================================
24   TimestampDatabaseHandler::TimestampDatabaseHandler(const std::string& filename)
25     : mFileName(filename)
26   {
27     mDB = new CppSQLite3DB;
28     GimmickMessage(1,"SQLite version : "
29                    <<std::string(mDB->SQLiteVersion())<< std::endl);
30   }
31   //=============================================================
32
33   //=============================================================
34   TimestampDatabaseHandler::~TimestampDatabaseHandler()
35   {
36     delete mDB;
37   }
38   //=============================================================
39   //=====================================================================
40   bool TimestampDatabaseHandler::Open()
41   {
42     return DBOpen();
43   }
44
45   //=====================================================================
46   bool TimestampDatabaseHandler::Create()
47   {
48     return DBCreate();
49   }
50   //=====================================================================
51
52
53   //=====================================================================
54   bool TimestampDatabaseHandler::Close()
55   {
56     return true;
57   }
58   //=====================================================================
59
60
61   //=====================================================================
62   bool TimestampDatabaseHandler::Destroy()
63   {
64     return false;
65   }
66
67
68
69
70
71
72   //=====================================================================
73   // SQLite DB specific methods
74   //=====================================================================
75   //=====================================================================
76 #define QUERYTIMESTAMPDB(QUER,RES)                                              \
77     try                                                                 \
78       {                                                                 \
79         GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl);         \
80         RES = mDB->execQuery(QUER.c_str());                             \
81       }                                                                 \
82     catch (CppSQLite3Exception& e)                                      \
83       {                                                                 \
84         GimmickError("SQLite query '"<<QUER<<"' : "                     \
85                      << e.errorCode() << ":"                            \
86                      << e.errorMessage() );                             \
87       }                                                                 \
88   //=====================================================================
89 #define UPDATETIMESTAMPDB(UP)                                                   \
90   try                                                                   \
91     {                                                                   \
92       GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl);            \
93       mDB->execDML(UP.c_str());                                         \
94     }                                                                   \
95   catch (CppSQLite3Exception& e)                                        \
96     {                                                                   \
97       GimmickError("SQLite update '"<<UP<<"' Error : "                  \
98                    << e.errorCode() << ":"                              \
99                    << e.errorMessage() );                               \
100     }                                                                   
101   //=====================================================================
102
103
104    //=====================================================================
105   bool TimestampDatabaseHandler::DBOpen()
106   {
107     GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
108                    <<"' ... "<<std::endl);
109     // OPENING FILE
110     if (!boost::filesystem::exists(GetFileName())) 
111       {
112         return false;
113       }
114
115     try
116       {
117         mDB->open(GetFileName().c_str());
118       }
119     catch (CppSQLite3Exception& e)
120       {
121         GimmickError("Opening '"<<GetFileName()<<"' : "
122                      << e.errorCode() << ":" 
123                      << e.errorMessage());
124         return false;
125       }
126
127     GimmickDebugMessage(1,"Opening SQLite database '"<<GetFileName()
128                    <<"' ... OK"<<std::endl);
129     return true;
130   }
131   //=====================================================================
132
133   //=====================================================================
134   bool TimestampDatabaseHandler::DBCreate()
135   {
136     GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
137                    <<"' ... "<<std::endl);
138
139     if (boost::filesystem::exists(GetFileName())) 
140       {
141         GimmickError(GetFileName()<<"' : "
142                      << "file already exists");
143         return false;
144       }
145     
146     // OPENING
147     try
148       {
149         mDB->open(GetFileName().c_str());
150       }
151     catch (CppSQLite3Exception& e)
152       {
153         GimmickError(e.errorCode() << ":" 
154                      << e.errorMessage() <<std::endl);
155         return false;
156       }
157     
158      
159     // CREATING TABLES
160     
161     std::string command;
162   
163     
164             command = "CREATE TABLE ";
165             command += "FILES";
166             command += "\n(\nID INTEGER PRIMARY KEY";
167                 command += ",\nPARENT_ID int not null"; 
168             command += ",\nPATH text";
169                 command += ",\nLastModified datetext";
170                 command += ",\nLastRead datetext";
171                 command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
172                 command += "FILES";
173                 command += "(ID) on delete restrict on update restrict";
174               
175             command += "\n)";
176             UPDATETIMESTAMPDB(command);
177             
178     return true;
179   }
180
181
182
183   //=====================================================================
184   void TimestampDatabaseHandler::CleanName(std::string& str) const
185   {
186          size_t pos;
187          do
188      {
189          pos = str.find('\\');
190          if (pos!=-1)  
191                  {
192                          str.replace(pos, 1, "/");
193                  }
194      }
195      while (pos!=-1);
196   }
197
198
199   //=====================================================================
200
201   bool TimestampDatabaseHandler::AddDirectory(const std::string& parent,
202                                                                                    const std::string& path, 
203                                                                                    const time_t lastModif, 
204                                                                                    const time_t lastRead)
205   {
206          bool valid=false;
207          std::string par=parent.c_str();
208          std::string pat=path.c_str();
209          CleanName(par);
210          CleanName(pat);
211
212          std::string pathId=IsIndexed(pat);
213          //Case: It is a root parent
214          if(parent.compare("")==0)
215          {
216                  if(pathId.compare("")==0)
217                  {
218                         AddFile(pat,lastModif,lastRead);
219                         valid=true;
220                  }
221                  else
222                  {
223                          valid=CheckTimestamp(pathId, lastModif);
224                  }
225          }
226          else 
227          {
228                  std::string parentId=IsIndexed(par);
229                  //Case: Parent is not in database
230                  if(parentId.compare("")==0)
231                 {
232                         AddFile(par,lastModif,lastRead);
233                         parentId=IsIndexed(par);
234                 }
235
236                 //Case path is not in database
237                 if(pathId.compare("")==0)
238                 {
239                     AddFile(parentId,pat,lastModif,lastRead);
240                         valid=true;
241                 }
242                 //Parent and path are in the database
243                 else
244                 {
245                         SetAttribute("PARENT_ID",parentId,"ID", pathId);
246                         valid=CheckTimestamp(pathId, lastModif);
247                 }
248          }
249          return valid;
250         
251   }
252
253   //=====================================================================
254
255   void TimestampDatabaseHandler::AddFile(const std::string& path, const time_t lastModif, const time_t lastRead)
256   {
257         std::stringstream out;
258         out<<"INSERT INTO FILES (PARENT_ID,PATH,LastModified,LastRead) VALUES(0,'"<<path<<"',";
259         out<<lastModif<<","<<lastRead<<");";
260     UPDATETIMESTAMPDB(out.str());
261         
262   }
263
264    //=====================================================================
265
266   void TimestampDatabaseHandler::AddFile(const std::string& parentId, 
267                                                                                  const std::string& path, 
268                                                                                  const time_t lastModif, 
269                                                                                  const time_t lastRead)
270   {
271         std::stringstream out;
272         out<<"INSERT INTO FILES (PARENT_ID,PATH,LastModified,LastRead) VALUES("<<parentId<<",'"<<path<<"',";
273         out<<lastModif<<","<<lastRead<<");";
274     UPDATETIMESTAMPDB(out.str());
275   }
276
277   //=====================================================================
278   std::string TimestampDatabaseHandler::IsIndexed(const std::string& path)
279   {
280         std::stringstream out;
281         std::stringstream result;
282         out<<"SELECT ID FROM FILES WHERE PATH='"<<path<<"'";
283                 
284         CppSQLite3Query q;
285         QUERYTIMESTAMPDB(out.str(),q);
286         
287         
288         while (!q.eof())
289           {
290             for (int fld = 0; fld < q.numFields(); fld++)
291               {
292                           result<<q.getStringField(fld);
293               }
294             q.nextRow();
295           }
296
297           return result.str();
298   }
299
300   //=====================================================================
301   void TimestampDatabaseHandler::SetAttribute(const std::string& attName, 
302                                                                                         const std::string& attValue,
303                                                                                         const std::string& searchParam,
304                                                                                         const std::string& searchValue)
305   {
306         std::string sql = "UPDATE FILES SET ";
307     sql += attName;
308     sql += " = '";
309     sql += attValue;
310     sql += "' WHERE ";
311         sql += searchParam;
312         sql += " = '";
313     sql += searchValue;
314         sql += "'";
315     UPDATETIMESTAMPDB(sql);
316   }
317  
318   //=====================================================================
319   void TimestampDatabaseHandler::RemoveNode(const std::string& searchAtt, tree::Node* node)
320   {
321           int n=node->GetNumberOfChildren();
322           if(n>0)
323           {
324                   std::vector<tree::Node*> children=node->GetChildrenList();
325                   std::vector<tree::Node*>::iterator it;
326                   for(it=children.begin();it!=children.end();++it)
327                   {
328                           RemoveNode(searchAtt,(*it));
329                   }
330           }
331           else if(node->GetLevel()==3)
332           {
333                   RemoveFile(searchAtt,node->GetAttribute("FullFileName"));
334           }
335
336
337   }
338   //=====================================================================
339   void TimestampDatabaseHandler::RemoveFile(const std::string& searchAtt, const std::string& searchVal)
340   {
341           
342           std::stringstream result;
343           std::string sel="SELECT PARENT_ID FROM FILES WHERE "+searchAtt+"='"+searchVal+"'";
344                 
345           CppSQLite3Query q;
346           QUERYTIMESTAMPDB(sel,q);
347         
348           while (!q.eof())
349           {
350             for (int fld = 0; fld < q.numFields(); fld++)
351               {
352                           result<<q.getStringField(fld);
353               }
354             q.nextRow();
355           }
356           DBRemove(searchAtt,searchVal);
357           
358                   int nChildren=0;
359                   sel="SELECT ID FROM FILES WHERE PARENT_ID='"+result.str()+"'";
360                   CppSQLite3Query q2;
361                   QUERYTIMESTAMPDB(sel,q2);
362                   while (!q2.eof())
363                         {
364                                 nChildren++;
365                                 q2.nextRow();
366                         }
367                         if(nChildren<1)
368                         {
369                                 if(!result.str().compare("0"))
370                                 {
371                                 RemoveFile("ID",result.str());
372                                 }
373                                 else
374                                 {
375                                 DBRemove("ID",result.str());
376                                 }
377                         }
378   }
379
380   //=====================================================================
381   void TimestampDatabaseHandler::DBRemove(const std::string& searchAtt, const std::string& searchVal)
382   {
383        
384     std::string query = "DELETE FROM FILES WHERE "+searchAtt+"='"+ searchVal + "';";
385     UPDATETIMESTAMPDB(query);
386   }
387
388    //=====================================================================
389   bool TimestampDatabaseHandler::CheckTimestamp(const std::string pathId, const time_t lastModif)
390   {
391         std::string sel="SELECT LastModified FROM FILES WHERE ID='"+pathId+"';";
392         CppSQLite3Query q;
393         QUERYTIMESTAMPDB(sel,q);
394         double timestamp;
395         
396         while (!q.eof())
397           {
398             for (int fld = 0; fld < q.numFields(); fld++)
399               {
400                           timestamp=q.getFloatField(fld);
401               }
402             q.nextRow();
403           }
404
405           
406           std::stringstream lm;
407           lm<<lastModif;
408           double modif=atof((lm.str()).c_str());
409           if(timestamp<modif)
410           {
411                   SetAttribute("LastModified",lm.str(),"ID",pathId);
412                   return true;
413           }
414           return false;  
415   }
416
417 }// namespace creaImageIO