]> Creatis software - creaImageIO.git/blobdiff - src2/creaImageIOSQLiteTreeHandler.cpp
*** empty log message ***
[creaImageIO.git] / src2 / creaImageIOSQLiteTreeHandler.cpp
index 4d0d49eae165825a158b77f9788857c54d07a3a1..e1a0307b3673093365844786789de7e0d589ac02 100644 (file)
@@ -50,22 +50,6 @@ namespace creaImageIO
   //=============================================================
   
 
-  //=============================================================
-  void SQLiteTreeHandler::BuildDefaultTreeDescription()
-  {
-    /*
-    for (int i = Node::Patient;
-        i <= Node::Image; 
-        ++i)
-      {
-       mNodeTypeDescription[i].BuildDefault(i);
-      }
-    */
-
-    // TODO : GetTree().GetDescription().LoadXML(FILE);
-  }
-  //=============================================================
-
   //=============================================================
   //  void SQLiteTreeHandler::Print() const 
   //  {
@@ -91,54 +75,6 @@ namespace creaImageIO
   */
   //=====================================================================
 
-  //=====================================================================
-  char* format_sql(const std::string& s)
-  { 
-    return sqlite3_mprintf("%q",s.c_str());
-  }
-  //=====================================================================
-
-  //  sqlite3_exec(db, zSQL, 0, 0, 0);
-  //  sqlite3_free(zSQL);
-  //   char* CHAIN = format_sql(QUER);         \
-//  sqlite3_free(CHAIN);                               \
-
-  //=====================================================================
-#define QUERYDB(QUER,RES)                                              \
-    try                                                                        \
-      {                                                                        \
-       GimmickMessage(2,"SQL: '"<<QUER<<"'"<<std::endl);               \
-       RES = mDB->execQuery(QUER.c_str());                             \
-      }                                                                        \
-    catch (CppSQLite3Exception& e)                                     \
-      {                                                                        \
-       std::cout << "SQLite query '"<<QUER<<"' : "                     \
-                 << e.errorCode() << ":"                               \
-                 << e.errorMessage()<<std::endl;                       \
-       creaError("SQLite query '"<<QUER<<"' : "                        \
-                 << e.errorCode() << ":"                               \
-                 << e.errorMessage() );                                \
-      }                                                                        \
-    
-  //=====================================================================
-  
-  //=====================================================================
-#define UPDATEDB(UP)                                                   \
-  try                                                                  \
-    {                                                                  \
-      GimmickMessage(2,"SQL: '"<<UP<<"'"<<std::endl);                  \
-      mDB->execDML(UP.c_str());                                                \
-    }                                                                  \
-  catch (CppSQLite3Exception& e)                                       \
-    {                                                                  \
-      std::cout << "SQLite update '"<<UP<<"' Error : "                 \
-               << e.errorCode() << ":"                                 \
-               << e.errorMessage()<<std::endl;                         \
-      creaError("SQLite update '"<<UP<<"' Error : "                    \
-               << e.errorCode() << ":"                                 \
-               << e.errorMessage() );                                  \
-    }                                                                  
-  //=====================================================================
 
   //=====================================================================
   bool SQLiteTreeHandler::Open(bool writable)
@@ -161,7 +97,7 @@ namespace creaImageIO
   //=====================================================================
   bool SQLiteTreeHandler::Close()
   {
-    return false;
+    return true;
   }
   //=====================================================================
 
@@ -198,8 +134,54 @@ namespace creaImageIO
 
 
   //===================================================================== 
-  int SQLiteTreeHandler::AddBranch( const std::map<std::string,std::string>& attr )
+  int SQLiteTreeHandler::AddBranch( const AttributeMapType& attr )
   {
+    tree::Node* parent = DBGetParent(attr);
+    for (int level = parent->GetLevel()+1;
+        level < GetTree().GetNumberOfLevels();
+        level++)
+      {
+       // Create Node
+       parent = new tree::Node(parent,attr);
+       
+       // Insert into DB
+       if (node->GetType()!=Node::Patient) 
+         node->SetFieldValue("PARENT_ID",parent_id);
+       
+       // Insert in DB
+       std::string val;
+       BuildSQLFieldsValues(node,val);
+       std::string insert("INSERT INTO ");
+       insert += std::string(SQLiteTreeHandlerStructure::Table(node->GetType())) 
+         + " " + val + ";";
+       //    std::cout << "** SQL = '"<<insert<<"'"<<std::endl;
+       UPDATEDB(insert);
+       //    std::cout << "** SQL OK"<<std::endl;
+       
+       // Store DB id of newly created node;
+       long lastrow = mDB->lastRowId();
+       std::stringstream ri;
+       ri << mDB->lastRowId();
+       node_id = ri.str();
+       //    std::cout << "LastRowId='"<<mDB->lastRowId()<<"' vs '"<<created_id<<"'"<<std::endl;
+       
+       node->SetFieldValue("ID",node_id);
+       /*
+       // Insert in TypeId map
+       TypeId ti;
+       ti.type = node->GetType();
+       ti.id = node_id;
+       mTypeIdToNodeMap[ti] = node;
+       //    std::cout << "== Insert TypeId ("<<ti.type<<","<<ti.id<<")"<<std::endl; 
+       // 
+       msw[2].Pause();
+       
+       if (node->GetType()==Node::Patient) summary.added_patients++;
+       if (node->GetType()==Node::Study) summary.added_studies++;
+       if (node->GetType()==Node::Series) summary.added_series++;
+       if (node->GetType()==Node::Image) summary.added_images++;
+       */
+      }
     return -1;
   }
   //===================================================================== 
@@ -218,10 +200,76 @@ namespace creaImageIO
 
 
 
+
+
+
+
+
+
+
+
+  //=====================================================================
+  // SQLite DB specific methods
+  //=====================================================================
+
+
+
+
+  //=====================================================================
+  char* format_sql(const std::string& s)
+  { 
+    return sqlite3_mprintf("%q",s.c_str());
+  }
+  //=====================================================================
+
+  //  sqlite3_exec(db, zSQL, 0, 0, 0);
+  //  sqlite3_free(zSQL);
+  //   char* CHAIN = format_sql(QUER);         \
+//  sqlite3_free(CHAIN);                               \
+
+  //=====================================================================
+#define QUERYDB(QUER,RES)                                              \
+    try                                                                        \
+      {                                                                        \
+       GimmickMessage(2,"SQL: '"<<QUER<<"'"<<std::endl);               \
+       RES = mDB->execQuery(QUER.c_str());                             \
+      }                                                                        \
+    catch (CppSQLite3Exception& e)                                     \
+      {                                                                        \
+       std::cout << "SQLite query '"<<QUER<<"' : "                     \
+                 << e.errorCode() << ":"                               \
+                 << e.errorMessage()<<std::endl;                       \
+       creaError("SQLite query '"<<QUER<<"' : "                        \
+                 << e.errorCode() << ":"                               \
+                 << e.errorMessage() );                                \
+      }                                                                        \
+    
+  //=====================================================================
+  
+  //=====================================================================
+#define UPDATEDB(UP)                                                   \
+  try                                                                  \
+    {                                                                  \
+      GimmickMessage(2,"SQL: '"<<UP<<"'"<<std::endl);                  \
+      mDB->execDML(UP.c_str());                                                \
+    }                                                                  \
+  catch (CppSQLite3Exception& e)                                       \
+    {                                                                  \
+      std::cout << "SQLite update '"<<UP<<"' Error : "                 \
+               << e.errorCode() << ":"                                 \
+               << e.errorMessage()<<std::endl;                         \
+      creaError("SQLite update '"<<UP<<"' Error : "                    \
+               << e.errorCode() << ":"                                 \
+               << e.errorMessage() );                                  \
+    }                                                                  
+  //=====================================================================
+
+
   //=====================================================================
   bool SQLiteTreeHandler::DBOpen()
   {
-    GimmickMessage(2,"Opening SQLite database '"<<GetFileName()<<std::endl);
+    GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
     // OPENING FILE
     if (!boost::filesystem::exists(GetFileName())) 
       {
@@ -239,15 +287,14 @@ namespace creaImageIO
                  << e.errorMessage() << std::endl;
        return false;
       }
-    // TESTING STRUCTURE VALIDITY
-    if (!DBStructureIsValid())
+    // IMPORT TREE DESCRIPTION (AND TEST DB VALIDITY)
+    if (!DBImportTreeDescription())
       {
-       std::cerr << "Opening '"<<GetFileName()<<"' : "
-                 << " invalid database structure" << std::endl;
        return false;
       }
-    // IMPORTING NODE TYPE DESCRIPTIONS
-    DBImportTreeDescription();
+
+    GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... OK"<<std::endl);
     return true;
   }
   //=====================================================================
@@ -255,7 +302,8 @@ namespace creaImageIO
   //=====================================================================
   bool SQLiteTreeHandler::DBCreate()
   {
-    //    std::cout << "### Creating SQLite database '"<<GetFileName()<<std::endl;
+    GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
 
     if (boost::filesystem::exists(GetFileName())) 
       {
@@ -288,60 +336,101 @@ namespace creaImageIO
        command += "( Name text )\n";
        UPDATEDB(command);
 
-       // Level 0
-       command = "INSERT INTO Levels (Name) VALUES ('";
-       command += GetTree().GetLevelDescriptor(0).GetName();
-       command += "')";
-       UPDATEDB(command);
-
-       command = "CREATE TABLE ";
-       command += GetTree().GetLevelDescriptor(0).GetName();
-       command += "\n(\nID INTEGER PRIMARY KEY";
-       AppendAttributesSQLDefinition(0,command);
-       command += "\n)";
-       UPDATEDB(command);
-       
-       // Iterate the other Levels
-       for (int l=1; l<GetTree().GetNumberOfLevels(); ++l)
+       // Iterate the Levels
+       for (int l=0; l<GetTree().GetNumberOfLevels(); ++l)
          {
            command = "INSERT INTO LEVELS (Name) VALUES ('";
            command += GetTree().GetLevelDescriptor(l).GetName();
            command += "')";
            UPDATEDB(command);
            
+           // Create table of level (for level>0, i.e. not Root)
+           if (l>0)
+             {
+               command = "CREATE TABLE ";
+               command += GetTree().GetLevelDescriptor(l).GetName();
+               command += "\n(\nID INTEGER PRIMARY KEY";
+               if (l>1) 
+                 {
+                   command += ",\nPARENT_ID int not null";     
+                 }
+               AppendAttributesSQLDefinition(l,command);
+               if (l>1) 
+                 {
+                   command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
+                   command += GetTree().GetLevelDescriptor(l-1).GetName();
+                   command += "(ID) on delete restrict on update restrict";
+                 }
+               command += "\n)";
+               UPDATEDB(command);
+
+
+               // Add Attribute 'ID' to Description
+               GetTree().GetAttributeDescriptorList(l).push_back
+                 (AttributeDescriptor( "ID",
+                                       "Database Identifier",
+                                       0,0,
+                                       AttributeDescriptor::PRIVATE
+                                       ));
+
+               if (l>1) 
+                 {
+                   // Add Attribute 'PARENT_ID' to Description
+                   GetTree().GetAttributeDescriptorList(l).push_back
+                     (AttributeDescriptor( "PARENT_ID",
+                                           "Database Parent Identifier",
+                                           0,0,
+                                           AttributeDescriptor::PRIVATE
+                                           ));
+                 }
+               
+             }
+           
+           // Create table *_ATTRIBUTES
+           
            command = "CREATE TABLE ";
            command += GetTree().GetLevelDescriptor(l).GetName();
-           command += "\n(\nID INTEGER PRIMARY KEY,\nPARENT_ID int not null";  
-           AppendAttributesSQLDefinition(l,command);
-           command +=",\n";
-           command +="constraint FK_PARENT foreign key (PARENT_ID) references PATIENT(ID) on delete restrict on update restrict\n)";
+           command += "_Attributes\n(\n";
+           command += "Key text,\n";
+           command += "Name text,\n";      
+           command += "DicomGroup int,\n";
+           command += "DicomElement int,\n";       
+           command += "Flags int\n";       
+           command += "\n)";
            UPDATEDB(command);
+         
+  
+           // Fill the table *_ATTRIBUTES
+           LevelDescriptor::AttributeDescriptorListType::const_iterator i;
+           for (i  = GetTree().GetAttributeDescriptorList(l).begin();
+                i != GetTree().GetAttributeDescriptorList(l).end();
+                ++i)
+             {
+               
+               std::stringstream insert;
+               insert << "INSERT INTO "
+                      << GetTree().GetLevelDescriptor(l).GetName()
+                      << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
+                      << "VALUES ('"
+                      << i->GetKey() << "','"
+                      << i->GetName() << "',"
+                      << i->GetGroup() << ","
+                      << i->GetElement() << ","
+                      << i->GetFlags() << ");";
+               
+               UPDATEDB(insert.str());
+             }
          }
-       
-       // Create tables *_ATTRIBUTES
-       // and fill the tables *_ATTRIBUTES
-       DBExportTreeDescription();
-       
       }
     catch (std::exception)
       {
        return false;
       }
-    // LG : TEST
-    if (DBStructureIsValid())
-      {
-       //      std::cout << "*** DONE ***"<<std::endl;
-       //      mDBLoaded = true;
-       GetTree().SetChildrenLoaded(true);
-       return true;
-       
-      }
-    else 
-      {
-       //      std::cout << "*** AAAARRRRGGG ***"<<std::endl;
-       
-       return false;
-      }
+
+    GetTree().SetChildrenLoaded(true);
+    GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
+                  <<"' ... OK"<<std::endl);
+    return true;
   }
   //=====================================================================
   
@@ -362,125 +451,202 @@ namespace creaImageIO
   }
   //=====================================================================
   
-  //=====================================================================
-  void SQLiteTreeHandler::DBExportTreeDescription()
-  {
-    for (int level=0; level<GetTree().GetNumberOfLevels(); ++level)
-      {
-       std::string command;
-       command = "CREATE TABLE ";
-       command += GetTree().GetLevelDescriptor(level).GetName();
-       command += "_Attributes\n(\n";
-       command += "Key text,\n";
-       command += "Name text,\n";          
-       command += "DicomGroup int,\n";
-       command += "DicomElement int,\n";           
-       command += "Flags int\n";           
-       command += "\n)";
-       UPDATEDB(command);
-       LevelDescriptor::AttributeDescriptorListType::const_iterator i;
-       for (i  = GetTree().GetAttributeDescriptorList(level).begin();
-            i != GetTree().GetAttributeDescriptorList(level).end();
-            ++i)
-         {
-           
-           std::stringstream insert;
-           insert << "INSERT INTO "
-                  << GetTree().GetLevelDescriptor(level).GetName()
-                  << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
-                  << "VALUES ('"
-                  << i->GetKey() << "','"
-                  << i->GetName() << "',"
-                  << i->GetGroup() << ","
-                  << i->GetElement() << ","
-                  << i->GetFlags() << ");";
-
-           UPDATEDB(insert.str());
-         }
-      }
-    
-  }
-  //=====================================================================
   
   //=====================================================================
-  void SQLiteTreeHandler::DBImportTreeDescription()
+  bool SQLiteTreeHandler::DBImportTreeDescription()
   {
-    GimmickMessage(3,"ImportTreeDescription"<<std::endl);
-    
-    //    tree::Description& desc = GetTree().GetDescription();
-    /*
+    GimmickMessage(1,"Importing tree description from database ..."
+                  <<std::endl);
 
-    for (Node::Type type=Node::Patient; 
-        type<=Node::Image; 
-        type++)
+    // Test table 'LEVELS' existence
+    if ( ! mDB->tableExists("LEVELS") )
       {
-       std::string query = "SELECT * FROM ";
-       query += SQLiteTreeHandlerStructure::Table(type);
-       query += "_FIELDS";
+       GimmickMessage(1,"!! ERROR : Table 'LEVELS' does not exist"
+                      <<std::endl);
+       return false;
+      }
 
-       //      std::cout << "** SQL = '"<<query<<"'"<<std::endl;
+    tree::Descriptor& desc = GetTree().GetDescriptor();
+    // clears the existing one
+    desc.GetLevelDescriptorList().clear();
+     
+    int nblevel = 0;
+    std::string query = "SELECT * FROM LEVELS";
+    CppSQLite3Query q;
+    QUERYDB(query,q);
+
+    while (!q.eof())
+      {
+       std::string name = q.getStringField(0);
+       GimmickMessage(2," * Importing level '"<<name<<"'"<<std::endl);
+       desc.GetLevelDescriptorList().push_back(LevelDescriptor(name));
+       nblevel++;
+       q.nextRow();
+      }   
+    
+    for (int level = 0; level < nblevel; ++level )
+      {
+       std::string table = GetTree().GetLevelDescriptor(level).GetName();
+       table += "_Attributes";
+       // Test table 'LEVELS' existence
+       if ( ! mDB->tableExists(table.c_str()) )
+         {
+           GimmickMessage(1,"!! ERROR : Table '"<<table<<"' does not exist"
+                          <<std::endl);
+           return false;
+         }
        
+       std::string query = "SELECT * FROM ";
+       query += table;
        CppSQLite3Query q;
        QUERYDB(query,q);
        
+       GimmickMessage(2," * Level '"
+                      <<GetTree().GetLevelDescriptor(level).GetName()
+                      <<"'"<<std::endl);
+
+       // Test that ID and PARENT_ID mandatory attributes exist
+       bool ID_found = false;
+       bool PARENT_ID_found = false;
+       if (level==0) ID_found = true;
+       if (level<=1) PARENT_ID_found = true;
 
        while (!q.eof())
          {
-           Field::Description d(q.getStringField(0), // Key
-                                q.getIntField(1), // Group
-                                q.getIntField(2), // Element 
-                                q.getStringField(3), // Name
-                                q.getIntField(4) // Flags
-                                );
-           GetNodeTypeDescription(type).GetFieldDescriptionMap()[d.key] = d;
-           //      std::cout << d << std::endl;
+           std::string key(q.getStringField(0));
+           std::string name(q.getStringField(1));
+           GimmickMessage(2,"  - Importing attribute '"<<key<<"' '"<<name
+                          <<"'"<<std::endl);
+           desc.GetAttributeDescriptorList(level).push_back
+             (AttributeDescriptor( key, // Key
+                                   name, // Name
+                                   q.getIntField(2), // Group
+                                   q.getIntField(3), // Element 
+                                   q.getIntField(4) // Flags
+                                   ));
+           if ( key == "ID" ) 
+             {
+               ID_found = true;
+             }
+           if ( key == "PARENT_ID" ) 
+             {
+               PARENT_ID_found = true;
+             }
            q.nextRow();
          }
+       
+       if ( ! (ID_found || PARENT_ID_found ) )
+         {
+           GimmickMessage(1,"!! ERROR : Table '"<<table
+                          <<"' does not contain mandatory attribute ID or PARENT_ID"
+                          <<std::endl);
+           return false;
+         }
       }
-    */
+
+    GimmickMessage(1,"Importing tree description from database ... OK"
+                  <<std::endl);
+    return true;
   }
   //=====================================================================
 
 
-    //=====================================================================
-  bool SQLiteTreeHandler::DBStructureIsValid()
+
+
+
+
+
+
+
+
+
+
+
+
+
+  //=====================================================================
+  tree::Node* SQLiteTreeHandler::DBGetParent( const AttributeMapType& attr) 
   {
-    bool success = true;
+    Node* parent = GetTree().GetTree();
+    bool go_down;
+    do 
+      {
+       go_down = false;
+       // Load the children of the current parent
+       DBLoadChildren(parent);
+       // Iterate the children 
+       tree::Node::ChildrenListType::const_iterator i;
+       for (i = parent->GetChildrenList().begin();
+            i!= parent->GetChildrenList().end();
+            ++i)
+         {
+           if ( (*i)->Matches( attr ) ) 
+             {
+               go_down = true;
+               parent = *i;
+             }
+         }     
+      }
+    while (go_down);
+    return parent;
+  }
+  //=====================================================================
 
-    // TO DO : TABLE WHICH STORES THE LEVELS
-    /*
-    
-    for (int i = SQLiteTreeHandlerStructure::TableBegin();
-        i    != SQLiteTreeHandlerStructure::TableEnd();++i)
+
+  //=====================================================================
+  int SQLiteTreeHandler::DBLoadChildren(tree::Node* parent, 
+                                       int numberoflevels)
+  {
+    int nbloaded = 0;
+    if (parent->GetChildrenLoaded()) return nbloaded;
+
+    // Query DB
+    int level = parent->GetLevel();
+    std::string query = "SELECT * FROM ";
+    query += GetTree().GetLevelDescriptor(level+1).GetName();
+    if (level>1)
       {
-       bool ok = mDB->tableExists(SQLiteTreeHandlerStructure::Table(i));
-       if (ok) 
+       query += " WHERE PARENT_ID='" + parent->UnsafeGetAttribute("ID") 
+         + "'";
+      }
+    CppSQLite3Query q;
+    QUERYDB(query,q);
+
+    while (!q.eof())
+      {
+       nbloaded++;
+       Node* n = new Node(parent);
+       for (int fld = 0; fld < q.numFields(); fld++)
          {
-           //      std::cout << "** Table "<<SQLiteTreeHandlerStructure::Table(i)
-           //                <<" exists"<<std::endl;
-           // TO DO : TEST MANDATORY FIELDS EXIST
+           n->UnsafeSetAttribute(q.fieldName(fld),q.getStringField(fld));          
          }
-       else 
+       /*
+       // Index 
+       TypeId ti;
+       ti.type = type;
+       ti.id = n->GetFieldValue("ID");    
+       mTypeIdToNodeMap[ti] = n;
+       */
+       // recurse 
+       if ( numberoflevels > 1 ) 
          {
-           //      std::cout << "** Table "<<SQLiteTreeHandlerStructure::Table(i)
-           //                <<" does *NOT* exist"<<std::endl;
-           success = false;
+           //  msw[2].Pause();
+           nbloaded += DBLoadChildren(n, numberoflevels-1);
+           //      msw[2].Resume();
          }
+       // next entry in db
+       q.nextRow();
       }
-    */
-    return success;
-  }  
-  //=====================================================================
 
-  /*
-  //=====================================================================
-  int SQLiteTreeHandler::DBLoadChildren(Node* parent, 
-                                       int maxlevel)
-  {
+    parent->SetChildrenLoaded(true);
+    
+    //    msw[2].Pause();
+    return nbloaded;
 
     //    std::cout << "SQLiteTreeHandler::DBLoadChildren("<<parent<<","<<maxlevel
-    //       << ")"<<std::endl;
+    //      << ")"<<std::endl;
+    /*
     int nbloaded = 0;
     if (parent == GetTree()) { parent = 0; }
     Node* xparent = parent;
@@ -548,6 +714,7 @@ namespace creaImageIO
     
     //    msw[2].Pause();
     return nbloaded;
+    */
   }
   //=====================================================================
 
@@ -555,7 +722,7 @@ namespace creaImageIO
 
 
 
-
+  /*
   //=====================================================================
   bool SQLiteTreeHandler::DBInsert(Node* alien_node,
                                   UpdateSummary& summary)