diff OrthancServer/SQLiteDatabaseWrapper.cpp @ 3025:039a9d262d64 db-changes

preparing to speed up find in databases
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 17 Dec 2018 17:05:28 +0100
parents d207f6ac1f86
children fd587cf51a89
line wrap: on
line diff
--- a/OrthancServer/SQLiteDatabaseWrapper.cpp	Mon Dec 17 10:26:01 2018 +0100
+++ b/OrthancServer/SQLiteDatabaseWrapper.cpp	Mon Dec 17 17:05:28 2018 +0100
@@ -54,7 +54,7 @@
 
     public:
       SignalFileDeleted(IDatabaseListener& listener) :
-      listener_(listener)
+        listener_(listener)
       {
       }
 
@@ -101,7 +101,7 @@
 
     public:
       SignalResourceDeleted(IDatabaseListener& listener) :
-      listener_(listener)
+        listener_(listener)
       {
       }
 
@@ -1201,4 +1201,247 @@
   {
     return GetTotalCompressedSize() > threshold;
   }
+
+
+  namespace
+  {
+    class MainDicomTagsRegistry : public boost::noncopyable
+    {
+    private:
+      class TagInfo
+      {
+      private:
+        ResourceType  level_;
+        DicomTagType  type_;
+
+      public:
+        TagInfo()
+        {
+        }
+
+        TagInfo(ResourceType level,
+                DicomTagType type) :
+          level_(level),
+          type_(type)
+        {
+        }
+
+        ResourceType GetLevel() const
+        {
+          return level_;
+        }
+
+        DicomTagType GetType() const
+        {
+          return type_;
+        }
+      };
+      
+      typedef std::map<DicomTag, TagInfo>   Registry;
+
+
+      Registry  registry_;
+      
+      void LoadTags(ResourceType level)
+      {
+        const DicomTag* tags = NULL;
+        size_t size;
+  
+        ServerToolbox::LoadIdentifiers(tags, size, level);
+  
+        for (size_t i = 0; i < size; i++)
+        {
+          if (registry_.find(tags[i]) == registry_.end())
+          {
+            registry_[tags[i]] = TagInfo(level, DicomTagType_Identifier);
+          }
+          else
+          {
+            // These patient-level tags are copied in the study level
+            assert(level == ResourceType_Study &&
+                   (tags[i] == DICOM_TAG_PATIENT_ID ||
+                    tags[i] == DICOM_TAG_PATIENT_NAME ||
+                    tags[i] == DICOM_TAG_PATIENT_BIRTH_DATE));
+          }
+        }
+  
+        DicomMap::LoadMainDicomTags(tags, size, level);
+  
+        for (size_t i = 0; i < size; i++)
+        {
+          if (registry_.find(tags[i]) == registry_.end())
+          {
+            registry_[tags[i]] = TagInfo(level, DicomTagType_Main);
+          }
+        }
+      }
+
+    public:
+      MainDicomTagsRegistry()
+      {
+        LoadTags(ResourceType_Patient);
+        LoadTags(ResourceType_Study);
+        LoadTags(ResourceType_Series);
+        LoadTags(ResourceType_Instance); 
+      }
+
+      void LookupTag(ResourceType& level,
+                     DicomTagType& type,
+                     const DicomTag& tag) const
+      {
+        Registry::const_iterator it = registry_.find(tag);
+
+        if (it == registry_.end())
+        {
+          // Default values
+          level = ResourceType_Instance;
+          type = DicomTagType_Generic;
+        }
+        else
+        {
+          level = it->second.GetLevel();
+          type = it->second.GetType();
+        }
+      }
+    };
+  }
+  
+
+  void SQLiteDatabaseWrapper::FindOneChildInstance(std::vector<std::string>& instancesId,
+                                                   const std::vector<std::string>& resourcesId,
+                                                   ResourceType level)
+  {
+    printf("ICI 3\n");
+
+    throw OrthancException(ErrorCode_NotImplemented);
+  }
+
+
+  void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId,
+                                                  const DatabaseLookup& lookup,
+                                                  size_t limit)
+  {
+    static const MainDicomTagsRegistry registry;
+    
+    printf("ICI 1\n");
+
+    std::string heading = "SELECT patient.publicId FROM Resources AS patient ";
+    std::string trailer;
+    std::vector<std::string> parameters;
+
+    for (size_t i = 0; i < lookup.GetConstraintsCount(); i++)
+    {
+      const DicomTagConstraint& constraint = lookup.GetConstraint(i);
+      
+      ResourceType level;
+      DicomTagType type;
+      registry.LookupTag(level, type, constraint.GetTag());
+
+      if (level != ResourceType_Patient)
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange,
+                               "Not a patient-level tag: (" +
+                               lookup.GetConstraint(i).GetTag().Format() + ")");
+      }
+
+      if (type == DicomTagType_Identifier ||
+          type == DicomTagType_Main)
+      {
+        std::string table = (type == DicomTagType_Identifier ? "DicomIdentifiers" : "MainDicomTags");
+        std::string tag = "t" + boost::lexical_cast<std::string>(i);
+
+        char on[128];
+        sprintf(on, " %s ON %s.id = patient.internalId AND %s.tagGroup = 0x%04x AND %s.tagElement = 0x%04x ",
+                tag.c_str(), tag.c_str(), tag.c_str(), constraint.GetTag().GetGroup(),
+                tag.c_str(), constraint.GetTag().GetElement());
+        
+        if (constraint.IsMandatory())
+        {
+          heading += "INNER JOIN " + table + std::string(on);
+        }
+        else
+        {
+          heading += "LEFT JOIN " + table + std::string(on);
+        }
+
+        trailer += "AND (";
+
+        if (!constraint.IsMandatory())
+        {
+          trailer += tag + ".value IS NULL OR ";
+        }
+
+        if (constraint.IsCaseSensitive())
+        {
+          trailer += tag + ".value ";
+        }
+        else
+        {
+          trailer += "lower(" + tag + ".value) ";
+        }
+
+        switch (constraint.GetType())
+        {
+          case ConstraintType_Equal:
+            parameters.push_back(constraint.GetValue());
+            
+            if (constraint.IsCaseSensitive())
+            {
+              trailer += "= ?";
+            }
+            else
+            {
+              trailer += "= lower(?)";
+            }
+
+            break;
+
+          default:
+            throw OrthancException(ErrorCode_NotImplemented);
+        }
+
+        trailer += ") ";
+      }
+    }
+
+    if (limit != 0)
+    {
+      trailer += " LIMIT " + boost::lexical_cast<std::string>(limit);
+    }
+
+    std::string sql = (heading + "WHERE patient.resourceType = " +
+                       boost::lexical_cast<std::string>(ResourceType_Patient) + " " + trailer);
+
+    SQLite::Statement s(db_, sql);
+
+    printf("[%s]\n", sql.c_str());
+
+    for (size_t i = 0; i < parameters.size(); i++)
+    {
+      printf("   %d = '%s'\n", i, parameters[i].c_str());
+      s.BindString(i, parameters[i]);
+    }
+
+    patientsId.clear();
+
+    while (s.Step())
+    {
+      std::string publicId = s.ColumnString(0);
+      patientsId.push_back(publicId);
+      printf("** [%s]\n", publicId.c_str());
+    }
+    
+    throw OrthancException(ErrorCode_NotImplemented);
+  }
+  
+
+  void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId,
+                                                   const DatabaseLookup& lookup,
+                                                   ResourceType queryLevel,
+                                                   size_t limit)
+  {
+    printf("ICI 2\n");
+    
+    throw OrthancException(ErrorCode_NotImplemented);
+  }
 }