1 #include <creaImageIOSQLiteTreeHandler.h>
2 #include <creaImageIOSystem.h>
3 #include <creaImageIOGimmick.h>
5 #include "CppSQLite3.h"
12 #include <boost/algorithm/string.hpp>
22 //=============================================================
23 SQLiteTreeHandler::SQLiteTreeHandler(const std::string& filename)
26 mDB = new CppSQLite3DB;
28 //GimmickMessage(1,"SQLite version : " <<std::string(mDB->SQLiteVersion())<< std::endl);
30 //=============================================================
32 //=============================================================
33 SQLiteTreeHandler::~SQLiteTreeHandler()
37 //=============================================================
40 //=====================================================================
43 //=====================================================================
44 bool SQLiteTreeHandler::Open(bool writable)
46 // std::cout << "***> SQLiteTreeHandler::Open('"<<GetFileName()<<"')"<<std::endl;
47 SetWritable(writable);
51 //=====================================================================
52 bool SQLiteTreeHandler::Create(bool writable)
54 // std::cout << "***> SQLiteTreeHandler::New('"<<GetFileName()<<"')"<<std::endl;
55 SetWritable(writable);
58 //=====================================================================
61 //=====================================================================
62 bool SQLiteTreeHandler::Close()
66 //=====================================================================
69 //=====================================================================
70 bool SQLiteTreeHandler::Destroy()
75 //=====================================================================
77 //=====================================================================
78 int SQLiteTreeHandler::LoadChildren(tree::Node* parent, int maxlevel)
80 if (parent==0) parent = GetTree().GetTree();
81 return DBLoadChildren(parent,maxlevel);
83 //=====================================================================
88 //=====================================================================
89 void SQLiteTreeHandler::UnLoad(tree::Node* n)
92 //=====================================================================
94 //=====================================================================
95 int SQLiteTreeHandler::AddBranch( const AttributeMapType& attr )
97 tree::Node* parent = DBGetParent(attr);
98 DBGraftToParent(parent,attr);
99 return (parent->GetLevel()+1);
102 //=====================================================================
105 //=====================================================================
106 bool SQLiteTreeHandler::Remove(tree::Node* node)
108 DBRecursiveRemoveNode(node);
110 // std::cout << "DELETE"<<std::endl;
112 tree::Node* parent=node->GetParent();
115 int nC = parent->RemoveChildrenFromList(node);
116 if(nC>0 && parent->GetLevel()>0)
118 std::stringstream out;
120 SetAttribute(parent,"NumberOfChildren",out.str());
129 if(remove&&parent->GetLevel()>0)
133 // std::cout << "DELETE OK"<<std::endl;
137 //=====================================================================
139 //=====================================================================
140 /// Sets an attribute of a Node
141 bool SQLiteTreeHandler::SetAttribute(tree::Node* n,
142 const std::string& key,
143 const std::string& value)
145 if (n==0) n=GetTree().GetTree();
146 return DBSetAttribute(n,key,value);
148 //=====================================================================
149 //=====================================================================
150 /// Sets an attribute
151 void SQLiteTreeHandler::SetAttribute(const std::string& levelDescriptor,
152 const std::string& key,
153 const std::string& value,
154 const std::string& searchParam,
155 const std::string& searchVal)
157 DBSetAttribute(levelDescriptor,key,value,searchParam, searchVal);
159 //=====================================================================
161 void SQLiteTreeHandler::DeleteTuple(std::string levelDescriptor,
162 std::string key, std::string value)
164 DBDelete(levelDescriptor,key,value);
166 //=====================================================================
180 //=====================================================================
181 // SQLite DB specific methods
182 //=====================================================================
187 //=====================================================================
188 char* format_sql(const std::string& s)
190 return sqlite3_mprintf("%q",s.c_str());
192 //=====================================================================
195 //=====================================================================
196 #define QUERYDB(QUER,RES) \
199 GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl); \
200 RES = mDB->execQuery(QUER.c_str()); \
202 catch (CppSQLite3Exception& e) \
204 GimmickError("SQLite query '"<<QUER<<"' : " \
205 << e.errorCode() << ":" \
206 << e.errorMessage() ); \
209 //=====================================================================
211 //=====================================================================
212 #define UPDATEDB(UP) \
215 GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl); \
216 mDB->execDML(UP.c_str()); \
218 catch (CppSQLite3Exception& e) \
220 GimmickError("SQLite update '"<<UP<<"' Error : " \
221 << e.errorCode() << ":" \
222 << e.errorMessage() ); \
224 //=====================================================================
227 //=====================================================================
228 bool SQLiteTreeHandler::DBOpen()
230 GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
231 <<"' ... "<<std::endl);
233 if (!boost::filesystem::exists(GetFileName()))
240 mDB->open(GetFileName().c_str());
242 catch (CppSQLite3Exception& e)
244 GimmickError("Opening '"<<GetFileName()<<"' : "
245 << e.errorCode() << ":"
246 << e.errorMessage());
249 // IMPORT TREE DESCRIPTION (AND TEST DB VALIDITY)
250 if (!DBImportTreeDescription())
255 GimmickDebugMessage(1,"Opening SQLite database '"<<GetFileName()
256 <<"' ... OK"<<std::endl);
259 //=====================================================================
261 //=====================================================================
262 bool SQLiteTreeHandler::DBCreate()
264 GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
265 <<"' ... "<<std::endl);
267 if (boost::filesystem::exists(GetFileName()))
269 GimmickError(GetFileName()<<"' : "
270 << "file already exists");
277 mDB->open(GetFileName().c_str());
279 catch (CppSQLite3Exception& e)
281 GimmickError(e.errorCode() << ":"
282 << e.errorMessage() <<std::endl);
290 // Create LEVELS table
291 command = "create table LEVELS\n";
292 command += "( Name text )\n";
295 // Iterate the Levels
296 for (l=0; l<GetTree().GetNumberOfLevels(); l++)
298 command = "INSERT INTO LEVELS (Name) VALUES ('";
299 command += GetTree().GetLevelDescriptor(l).GetName();
303 // Create table of level (for level>0, i.e. not Root)
306 command = "CREATE TABLE ";
307 command += GetTree().GetLevelDescriptor(l).GetName();
308 command += "\n(\nID INTEGER PRIMARY KEY";
311 command += ",\nPARENT_ID int not null";
313 SQLAppendAttributesDefinition(l,command);
316 command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
317 command += GetTree().GetLevelDescriptor(l-1).GetName();
318 command += "(ID) on delete restrict on update restrict";
323 GetTree().CopyAttributeDescriptorList(l);
325 // Add Attribute 'ID' to Description
326 GetTree().GetDescriptor().Add
327 (AttributeDescriptor( "ID",
328 "Database Identifier",
330 AttributeDescriptor::PRIVATE
335 // Add Attribute 'PARENT_ID' to Description
336 GetTree().GetDescriptor().Add
337 (AttributeDescriptor( "PARENT_ID",
338 "Database Parent Identifier",
340 AttributeDescriptor::PRIVATE
346 // Create table *_ATTRIBUTES
348 command = "CREATE TABLE ";
349 command += GetTree().GetLevelDescriptor(l).GetName();
350 command += "_Attributes\n(\n";
351 command += "Key text,\n";
352 command += "Name text,\n";
353 command += "DicomGroup int,\n";
354 command += "DicomElement int,\n";
355 command += "Flags int\n";
359 // Fill the table *_ATTRIBUTES
360 LevelDescriptor::AttributeDescriptorListType::const_iterator i;
361 for (i = GetTree().GetAttributeDescriptorList(l).begin();
362 i != GetTree().GetAttributeDescriptorList(l).end();
366 std::stringstream insert;
367 insert << "INSERT INTO "
368 << GetTree().GetLevelDescriptor(l).GetName()
369 << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
371 << i->GetKey() << "','"
372 << i->GetName() << "',"
373 << i->GetGroup() << ","
374 << i->GetElement() << ","
375 << i->GetFlags() << ");";
376 UPDATEDB(insert.str());
381 // Initialize the root attributes
382 GetTree().InitializeAttributeMap();
383 // Insert the root in the level 0 table
384 DBInsert(GetTree().GetTree());
387 GetTree().SetChildrenLoaded(true);
388 GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
389 <<"' ... OK"<<std::endl);
392 //=====================================================================
394 //=====================================================================
395 void SQLiteTreeHandler::SQLAppendAttributesDefinition(int level,
398 LevelDescriptor::AttributeDescriptorListType::const_iterator i;
399 for (i = GetTree().GetAttributeDescriptorList(level).begin();
400 i != GetTree().GetAttributeDescriptorList(level).end();
403 // if (i->second.flags==1) continue;
409 //=====================================================================
412 //=====================================================================
413 bool SQLiteTreeHandler::DBImportTreeDescription()
415 GimmickMessage(1,"Importing tree description for database ..."
418 // Test table 'LEVELS' existence
419 if ( ! mDB->tableExists("LEVELS") )
421 GimmickMessage(1,"!! ERROR : Table 'LEVELS' does not exist"
426 tree::Descriptor& desc = GetTree().GetDescriptor();
427 // clears the existing one
431 std::string query = "SELECT * FROM LEVELS";
437 std::string name = q.getStringField(0);
438 GimmickMessage(2," * Importing level '"<<name<<"'"<<std::endl);
439 desc.Add(LevelDescriptor(name));
444 for (int level = 0; level < nblevel; ++level )
446 std::string table = GetTree().GetLevelDescriptor(level).GetName();
447 table += "_Attributes";
448 // Test table 'LEVELS' existence
449 if ( ! mDB->tableExists(table.c_str()) )
451 GimmickMessage(1,"!! ERROR : Table '"<<table<<"' does not exist"
456 std::string query = "SELECT * FROM ";
461 GimmickMessage(2," * Level '"
462 <<GetTree().GetLevelDescriptor(level).GetName()
465 // Test that ID and PARENT_ID mandatory attributes exist
466 bool ID_found = false;
467 bool PARENT_ID_found = false;
468 if (level==0) ID_found = true;
469 if (level<=1) PARENT_ID_found = true;
473 std::string key(q.getStringField(0));
474 std::string name(q.getStringField(1));
475 GimmickMessage(2," - Importing attribute '"<<key<<"' '"<<name
478 (AttributeDescriptor( key, // Key
480 q.getIntField(2), // Group
481 q.getIntField(3), // Element
482 q.getIntField(4) // Flags
488 if ( key == "PARENT_ID" )
490 PARENT_ID_found = true;
495 if ( ! (ID_found || PARENT_ID_found ) )
497 GimmickMessage(1,"!! ERROR : Table '"<<table
498 <<"' does not contain mandatory attribute ID or PARENT_ID"
503 GetTree().CopyAttributeDescriptorList(level);
507 // Create the attributes table for Root (i.e. Tree)
508 LevelDescriptor::AttributeDescriptorListType::const_iterator a;
509 for (a = GetTree().GetAttributeDescriptorList(0).begin();
510 a!= GetTree().GetAttributeDescriptorList(0).end();
514 GetTree().UnsafeSetAttribute( a->GetKey(), "" );
517 // Reading Root attributes
519 query = "SELECT * FROM ";
520 query += GetTree().GetLevelDescriptor(0).GetName();
523 for (int fld = 0; fld < q.numFields(); fld++)
525 GetTree().UnsafeSetAttribute(q.fieldName(fld),
526 q.getStringField(fld));
529 GimmickMessage(1,"Importing tree description from database ... OK"
533 //=====================================================================
535 //========================================================================
537 void SQLformat(std::string i_str, std::string &o_str)
539 // quote must be doubled
540 boost::algorithm::replace_all(i_str,"'","''");
541 // Found strange strings which contained NULL char INSIDE string
542 int i,size=i_str.size();
547 i_str = i_str.substr(0,i);
553 //========================================================================
555 //=====================================================================
556 void SQLiteTreeHandler::SQLAppendAttributesValues(tree::Node* n,
559 GimmickMessage(4,"SQLAppendAttributesValues"<<std::endl);
561 std::string values="";
563 tree::Node::AttributeMapType::iterator i;
564 for (i = n->GetAttributeMap().begin();
565 i != n->GetAttributeMap().end();
573 atts += "'" + i->first + "'";
574 SQLformat(i->second, out);
575 values += "'" + out + "'";
578 GimmickMessage(4,"'"<<i->first<<"' = '"<<i->second<<"'"<<std::endl);
580 atts[atts.size()-1]=' ';
581 values[values.size()-1]=' ';
583 str = "("+atts+") VALUES ("+values+")";
584 GimmickMessage(4,"Result = '"<<str<<"'"<<std::endl);
586 //=====================================================================
588 //=====================================================================
589 tree::Node* SQLiteTreeHandler::DBGetParent( const AttributeMapType& attr)
591 Node* parent = GetTree().GetTree();
596 // Load the children of the current parent
597 DBLoadChildren(parent);
598 // Iterate the children
599 tree::Node::ChildrenListType::const_iterator i;
600 for (i = parent->GetChildrenList().begin();
601 i!= parent->GetChildrenList().end();
604 if ( (*i)->Matches( attr ) )
615 //=====================================================================
617 //=====================================================================
618 int SQLiteTreeHandler::DBLoadChildren(tree::Node* node,
621 if (node->GetLevel()+1 >= node->GetTree()->GetNumberOfLevels() )
624 GimmickMessage(2,"Loading children of '"<<node->GetLabel()
628 // If children loaded we do not have to do it but we need to recurse
629 // in order to load the children's children if necessary, and so on...
630 if (node->GetChildrenLoaded())
632 // Iterate the children
634 tree::Node::ChildrenListType::iterator i;
635 for (i = node->GetChildrenList().begin();
636 i!= node->GetChildrenList().end();
639 nbloaded += DBLoadChildren(*i,numberoflevels-1);
641 node->SetChildrenLoaded(true);
647 /// If children not loaded : do it and recurse
650 int level = node->GetLevel();
651 std::string query = "SELECT * FROM ";
653 query += GetTree().GetLevelDescriptor(level+1).GetName();
656 query += " WHERE PARENT_ID='" + node->GetAttribute("ID")
659 GimmickDebugMessage(1, "query : '" <<query <<std::endl);
667 // std::cout << "DBLoadCh : creating node level "<<level+1<<std::endl;
670 Node* n = new Node(node);
671 for (int fld = 0; fld < q.numFields(); fld++)
673 n->UnsafeSetAttribute(q.fieldName(fld),q.getStringField(fld));
677 if ( numberoflevels != 1 )
680 nbloaded += DBLoadChildren(n, numberoflevels-1);
687 node->SetChildrenLoaded(true);
694 //=====================================================================
696 //======================================================================
697 void SQLiteTreeHandler::DBInsert(tree::Node* n)
699 GimmickMessage(2,"Inserting in DB '"<<n->GetLabel()
702 SQLAppendAttributesValues(n,val);
703 std::string insert("INSERT INTO ");
704 insert += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
705 insert += " " + val + ";";
709 // Store DB id of newly created node;
710 long lastrow = mDB->lastRowId();
711 std::stringstream ri;
712 ri << mDB->lastRowId();
713 n->SetAttribute("ID",ri.str());
715 //======================================================================
717 //======================================================================
718 /// Graft the branch defined by the attributes to the parent
719 void SQLiteTreeHandler::DBGraftToParent( tree::Node* parent,
720 const AttributeMapType& attr)
722 // std::cout <<"Grafting to parent '"<<parent->GetLabel()
725 for (int level = parent->GetLevel()+1;
726 level < GetTree().GetNumberOfLevels();
730 tree::Node* child = new tree::Node(parent,attr);
731 child->SetChildrenLoaded(true);
734 int nc = GetNumberOfChildren(parent)+1;
736 // std::cout<<"Number of children "<<parent->GetNumberOfChildren()<<std::endl;
737 std::stringstream out;
739 SetAttribute(parent,"NumberOfChildren",out.str());
742 // Set PARENT_ID if necessary
743 if ( parent->GetLevel()>0 )
744 child->SetAttribute("PARENT_ID",parent->GetAttribute("ID"));
753 //======================================================================
756 //=====================================================================
757 /// Sets an attribute of a Node
758 bool SQLiteTreeHandler::DBSetAttribute(tree::Node* n,
759 const std::string& key,
760 const std::string& value)
762 GimmickMessage(3,"Setting Attribute of '"<<n->GetLabel()<<
763 "' "<<key<<"='"<<value<<"'"<<std::endl);
765 n->SetAttribute(key,value);
766 std::string sql = "UPDATE ";
767 sql += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
772 sql += "' WHERE ID = '";
773 sql += n->GetAttribute("ID");
775 // sql += " LIMIT 1";
780 //=====================================================================
781 /// Sets an attribute of a Node
782 void SQLiteTreeHandler::DBSetAttribute(const std::string& levelDescriptor,
783 const std::string& key,
784 const std::string& value,
785 const std::string& searchParam,
786 const std::string& searchVal)
789 std::string sql = "UPDATE ";
790 sql += levelDescriptor;
800 std::cout<<sql<<std::endl;
803 //=====================================================================
804 void SQLiteTreeHandler::DBRecursiveRemoveNode(Node* node)
807 std::string query = "DELETE FROM ";
808 query += GetTree().GetLevelDescriptor(node->GetLevel()).GetName();
809 query += " WHERE ID='"+ node->GetAttribute("ID") + "';";
812 if(node->GetNumberOfChildren()!=0)
814 Node::ChildrenListType::iterator i;
815 for (i = node->GetChildrenList().begin();
816 i != node->GetChildrenList().end();
819 DBRecursiveRemoveNode((*i));
822 else if(node->GetLevel()<GetTree().GetNumberOfLevels()-1)
824 DBRecursiveRemoveNode(node->GetLevel()+1,node->GetAttribute("ID"));
828 //=====================================================================
829 void SQLiteTreeHandler::DBRecursiveRemoveNode(int level, std::string parentId)
831 std::stringstream out;
832 std::stringstream result;
833 out<<"SELECT ID FROM "<<GetTree().GetLevelDescriptor(level).GetName()<<" WHERE PARENT_ID='"<<parentId<<"'";
836 QUERYDB(out.str(),q);
840 for (int fld = 0; fld < q.numFields(); fld++)
842 result<<q.getStringField(fld)<<"#";
846 std::string res=result.str();
849 while(fin<res.size()-1)
851 fin=res.find('#',ini);
852 DBDelete(GetTree().GetLevelDescriptor(level).GetName(),"ID",res.substr(ini,fin-ini));
853 if(level<GetTree().GetNumberOfLevels()-1)
855 DBRecursiveRemoveNode(level+1,res.substr(ini,fin-ini));
863 //=====================================================================
864 void SQLiteTreeHandler::DBDelete(std::string levelDescriptor, std::string key, std::string value)
867 std::stringstream query;
868 query<<"DELETE FROM "<<levelDescriptor<<" WHERE "<<key<<"='"<<value<<"';";
870 UPDATEDB(query.str());
871 GimmickDebugMessage(2," Deleting: Query: "<<query.str()<<std::endl);
875 //=====================================================================
876 void SQLiteTreeHandler::GetAttribute(std::string levelDescriptor,
877 std::string searchParam,
878 std::string searchVal,
882 std::stringstream out;
883 std::stringstream results;
884 out<<"SELECT "<<key<<" FROM "<<levelDescriptor;
887 out<<" WHERE "<<searchParam<<"='"<<searchVal<<"'";
891 QUERYDB(out.str(),q);
896 for (int fld = 0; fld < q.numFields(); fld++)
898 results<<q.getStringField(fld);
906 result=results.str();
909 //=====================================================================
910 unsigned int SQLiteTreeHandler::GetNumberOfChildren(tree::Node* n)
914 int level = n->GetLevel();
916 if(level<GetTree().GetNumberOfLevels()&& level>0)
918 std::string query = "SELECT NumberOfChildren FROM ";
919 query += GetTree().GetLevelDescriptor(level).GetName();
922 query += " WHERE ID='" + n->GetAttribute("ID")
931 for (int fld = 0; fld < q.numFields(); fld++)
933 nb=q.getIntField(fld);
947 //=====================================================================
948 // get all attributes from database for a given file
949 void SQLiteTreeHandler::getAllAttributes(std::string i_filename, std::map<std::string, std::string> &i_results)
951 int level=GetTree().GetNumberOfLevels()-1;
953 std::string search = i_filename;
954 std::string param = "FullFileName";
958 std::set<std::string> pid;
959 std::vector<AttributeDescriptor> attr;
960 std::vector<AttributeDescriptor>::iterator it_attr;
961 std::vector<std::string> values;
962 std::vector<std::string>::iterator it_val;
969 attr = GetTree().GetAttributeDescriptorList(level,1);
971 name = GetTree().GetLevelDescriptor(level).GetName();
972 std::vector<std::string> values;
973 GetUpLevelNodeId(level, param,search,id);
974 GetAttributes(name, param,search,attr, values);
975 for(it_attr = attr.begin(), it_val = values.begin(); it_attr != attr.end(); it_attr++, it_val++)
977 i_results[(*it_attr).GetKey()] = (*it_val).c_str();
986 //=====================================================================
987 // get selected attributes from database for a given file
988 void SQLiteTreeHandler::GetAttributes(std::string name, std::string i_id, std::string i_value, tree::LevelDescriptor::AttributeDescriptorListType i_attr, std::vector<std::string> &i_results)
990 //SELECT t1.ArtistName,CDs.Title FROM Artists t1, CDs WHERE t1.ArtistID=CDs.ArtistID
991 std::stringstream out;
992 std::stringstream results;
994 tree::LevelDescriptor::AttributeDescriptorListType::iterator it = i_attr.begin();
995 std::string query ="";
996 for(; it != i_attr.end(); it++)
998 query += (*it).GetKey();
1001 query = query.substr(0, query.size()-1);
1003 out << "FROM "<<name;
1004 out<<" WHERE "<<i_id <<"='"<<i_value<<"'";
1006 QUERYDB(out.str(),q);
1009 for (int fld = 0; fld < q.numFields(); fld++)
1011 i_results.push_back(q.getStringField(fld));
1017 void SQLiteTreeHandler::GetUpLevelNodeId(int level, const std::string& searchParam, const std::string& searchValue, std::string& parent_id)
1019 std::string sp=searchParam.c_str();
1020 std::string sv=searchValue.c_str();
1021 std::stringstream out;
1022 std::stringstream results;
1023 out<<"SELECT PARENT_ID FROM "<<GetTree().GetLevelDescriptor(level).GetName();
1024 out<<" WHERE "<<sp<<"='"<<sv<<"'";
1026 QUERYDB(out.str(),q);
1029 for (int fld = 0; fld < q.numFields(); fld++)
1031 results<<q.getStringField(fld);
1035 parent_id = results.str();
1040 //=====================================================================
1041 void SQLiteTreeHandler::GetTopLevelNodeId(const std::string& searchParam, const std::string& searchValue, std::string& parent_id)
1043 int level=GetTree().GetNumberOfLevels()-1;
1044 std::string sp=searchParam.c_str();
1045 std::string sv=searchValue.c_str();
1049 GetUpLevelNodeId(level, sp, sv, parent_id);
1055 // std::stringstream out;
1056 // std::stringstream results;
1057 // out<<"SELECT PARENT_ID FROM "<<GetTree().GetLevelDescriptor(level).GetName();
1058 // out<<" WHERE "<<sp<<"='"<<sv<<"'";
1059 // CppSQLite3Query q;
1060 // QUERYDB(out.str(),q);
1065 // for (int fld = 0; fld < q.numFields(); fld++)
1067 // results<<q.getStringField(fld);
1073 // sv=results.str();
1079 //=====================================================================
1080 void SQLiteTreeHandler::RemoveEntries(const std::string i_table,
1081 const std::string i_attribute,
1082 const std::string i_operand,
1083 const std::string i_val)
1085 std::stringstream query;
1086 query<<"DELETE FROM "<<i_table<<" WHERE "<<i_attribute<<" "<<i_operand<<" '"<<i_val<<"'";
1087 UPDATEDB(query.str());
1090 //=====================================================================
1091 void SQLiteTreeHandler::BeginTransaction()
1093 std::stringstream out;
1094 out<<"begin transaction;";
1095 UPDATEDB(out.str());
1098 //=====================================================================
1099 void SQLiteTreeHandler::EndTransaction()
1101 std::stringstream out;
1102 out<<"commit transaction;";
1103 UPDATEDB(out.str());
1106 } // namespace creaImageIO