changeset 5681:77875b51cf95 find-refactoring

integration mainline->find-refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 09 Jul 2024 10:15:15 +0200
parents 527918e9c5d9 (current diff) 68fc5af30c03 (diff)
children fd4c5e064cbe
files OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp OrthancServer/Sources/Database/Compatibility/GenericFind.cpp OrthancServer/Sources/Database/FindRequest.cpp OrthancServer/Sources/Database/FindRequest.h OrthancServer/Sources/Database/IDatabaseWrapper.h OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp OrthancServer/Sources/Database/MainDicomTagsRegistry.h OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.h OrthancServer/Sources/Search/DatabaseConstraint.cpp OrthancServer/Sources/Search/DatabaseConstraint.h OrthancServer/Sources/Search/ISqlLookupFormatter.h
diffstat 23 files changed, 182 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -564,7 +564,7 @@
     
     virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                       std::list<std::string>* instancesId,
-                                      const std::vector<DatabaseConstraint>& lookup,
+                                      const DatabaseConstraints& lookup,
                                       ResourceType queryLevel,
                                       const std::set<std::string>& labels,
                                       LabelsConstraint labelsConstraint,
@@ -586,20 +586,20 @@
         std::vector<OrthancPluginDatabaseConstraint> constraints;
         std::vector< std::vector<const char*> > constraintsValues;
 
-        constraints.resize(lookup.size());
-        constraintsValues.resize(lookup.size());
+        constraints.resize(lookup.GetSize());
+        constraintsValues.resize(lookup.GetSize());
 
-        for (size_t i = 0; i < lookup.size(); i++)
+        for (size_t i = 0; i < lookup.GetSize(); i++)
         {
-          lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]);
+          lookup.GetConstraint(i).EncodeForPlugins(constraints[i], constraintsValues[i]);
         }
 
         ResetAnswers();
         answerMatchingResources_ = &resourcesId;
         answerMatchingInstances_ = instancesId;
       
-        CheckSuccess(that_.extensions_.lookupResources(that_.GetContext(), that_.payload_, lookup.size(),
-                                                       (lookup.empty() ? NULL : &constraints[0]),
+        CheckSuccess(that_.extensions_.lookupResources(that_.GetContext(), that_.payload_, lookup.GetSize(),
+                                                       (lookup.IsEmpty() ? NULL : &constraints[0]),
                                                        Plugins::Convert(queryLevel),
                                                        limit, (instancesId == NULL ? 0 : 1)));
       }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -798,7 +798,7 @@
     
     virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                       std::list<std::string>* instancesId, // Can be NULL if not needed
-                                      const std::vector<DatabaseConstraint>& lookup,
+                                      const DatabaseConstraints& lookup,
                                       ResourceType queryLevel,
                                       const std::set<std::string>& labels,
                                       LabelsConstraint labelsConstraint,
@@ -812,16 +812,16 @@
       std::vector<OrthancPluginDatabaseConstraint> constraints;
       std::vector< std::vector<const char*> > constraintsValues;
 
-      constraints.resize(lookup.size());
-      constraintsValues.resize(lookup.size());
+      constraints.resize(lookup.GetSize());
+      constraintsValues.resize(lookup.GetSize());
 
-      for (size_t i = 0; i < lookup.size(); i++)
+      for (size_t i = 0; i < lookup.GetSize(); i++)
       {
-        lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]);
+        lookup.GetConstraint(i).EncodeForPlugins(constraints[i], constraintsValues[i]);
       }
 
-      CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.size(),
-                                                  (lookup.empty() ? NULL : &constraints[0]),
+      CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.GetSize(),
+                                                  (lookup.IsEmpty() ? NULL : &constraints[0]),
                                                   Plugins::Convert(queryLevel),
                                                   limit, (instancesId == NULL ? 0 : 1)));
       CheckNoEvent();
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -976,7 +976,7 @@
     
     virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                       std::list<std::string>* instancesId, // Can be NULL if not needed
-                                      const std::vector<DatabaseConstraint>& lookup,
+                                      const DatabaseConstraints& lookup,
                                       ResourceType queryLevel,
                                       const std::set<std::string>& labels,
                                       LabelsConstraint labelsConstraint,
@@ -993,44 +993,46 @@
       request.mutable_lookup_resources()->set_limit(limit);
       request.mutable_lookup_resources()->set_retrieve_instances_ids(instancesId != NULL);
 
-      request.mutable_lookup_resources()->mutable_lookup()->Reserve(lookup.size());
+      request.mutable_lookup_resources()->mutable_lookup()->Reserve(lookup.GetSize());
       
-      for (size_t i = 0; i < lookup.size(); i++)
+      for (size_t i = 0; i < lookup.GetSize(); i++)
       {
-        DatabasePluginMessages::DatabaseConstraint* constraint = request.mutable_lookup_resources()->add_lookup();
-        constraint->set_level(Convert(lookup[i].GetLevel()));
-        constraint->set_tag_group(lookup[i].GetTag().GetGroup());
-        constraint->set_tag_element(lookup[i].GetTag().GetElement());
-        constraint->set_is_identifier_tag(lookup[i].IsIdentifier());
-        constraint->set_is_case_sensitive(lookup[i].IsCaseSensitive());
-        constraint->set_is_mandatory(lookup[i].IsMandatory());
+        const DatabaseConstraint& source = lookup.GetConstraint(i);
 
-        constraint->mutable_values()->Reserve(lookup[i].GetValuesCount());
-        for (size_t j = 0; j < lookup[i].GetValuesCount(); j++)
+        DatabasePluginMessages::DatabaseConstraint* target = request.mutable_lookup_resources()->add_lookup();
+        target->set_level(Convert(source.GetLevel()));
+        target->set_tag_group(source.GetTag().GetGroup());
+        target->set_tag_element(source.GetTag().GetElement());
+        target->set_is_identifier_tag(source.IsIdentifier());
+        target->set_is_case_sensitive(source.IsCaseSensitive());
+        target->set_is_mandatory(source.IsMandatory());
+
+        target->mutable_values()->Reserve(source.GetValuesCount());
+        for (size_t j = 0; j < source.GetValuesCount(); j++)
         {
-          constraint->add_values(lookup[i].GetValue(j));
+          target->add_values(source.GetValue(j));
         }
 
-        switch (lookup[i].GetConstraintType())
+        switch (source.GetConstraintType())
         {
           case ConstraintType_Equal:
-            constraint->set_type(DatabasePluginMessages::CONSTRAINT_EQUAL);
+            target->set_type(DatabasePluginMessages::CONSTRAINT_EQUAL);
             break;
             
           case ConstraintType_SmallerOrEqual:
-            constraint->set_type(DatabasePluginMessages::CONSTRAINT_SMALLER_OR_EQUAL);
+            target->set_type(DatabasePluginMessages::CONSTRAINT_SMALLER_OR_EQUAL);
             break;
             
           case ConstraintType_GreaterOrEqual:
-            constraint->set_type(DatabasePluginMessages::CONSTRAINT_GREATER_OR_EQUAL);
+            target->set_type(DatabasePluginMessages::CONSTRAINT_GREATER_OR_EQUAL);
             break;
             
           case ConstraintType_Wildcard:
-            constraint->set_type(DatabasePluginMessages::CONSTRAINT_WILDCARD);
+            target->set_type(DatabasePluginMessages::CONSTRAINT_WILDCARD);
             break;
             
           case ConstraintType_List:
-            constraint->set_type(DatabasePluginMessages::CONSTRAINT_LIST);
+            target->set_type(DatabasePluginMessages::CONSTRAINT_LIST);
             break;
 
           default:
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -153,7 +153,7 @@
     static void ApplyLevel(SetOfResources& candidates,
                            IDatabaseWrapper::ITransaction& transaction,
                            ILookupResources& compatibility,
-                           const std::vector<DatabaseConstraint>& lookup,
+                           const DatabaseConstraints& lookup,
                            ResourceType level)
     {
       typedef std::set<const DatabaseConstraint*>  SetOfConstraints;
@@ -166,17 +166,19 @@
       Identifiers       identifiers;
       SetOfConstraints  mainTags;
       
-      for (size_t i = 0; i < lookup.size(); i++)
+      for (size_t i = 0; i < lookup.GetSize(); i++)
       {
-        if (lookup[i].GetLevel() == level)
+        const DatabaseConstraint& constraint = lookup.GetConstraint(i);
+
+        if (constraint.GetLevel() == level)
         {
-          if (lookup[i].IsIdentifier())
+          if (constraint.IsIdentifier())
           {
-            identifiers[lookup[i].GetTag()].insert(&lookup[i]);
+            identifiers[constraint.GetTag()].insert(&constraint);
           }
           else
           {
-            mainTags.insert(&lookup[i]);
+            mainTags.insert(&constraint);
           }
         }
       }
@@ -306,7 +308,7 @@
 
     void DatabaseLookup::ApplyLookupResources(std::list<std::string>& resourcesId,
                                               std::list<std::string>* instancesId,
-                                              const std::vector<DatabaseConstraint>& lookup,
+                                              const DatabaseConstraints& lookup,
                                               ResourceType queryLevel,
                                               size_t limit)
     {
@@ -320,9 +322,9 @@
       ResourceType upperLevel = queryLevel;
       ResourceType lowerLevel = queryLevel;
 
-      for (size_t i = 0; i < lookup.size(); i++)
+      for (size_t i = 0; i < lookup.GetSize(); i++)
       {
-        ResourceType level = lookup[i].GetLevel();
+        ResourceType level = lookup.GetConstraint(i).GetLevel();
 
         if (level < upperLevel)
         {
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h	Tue Jul 09 10:15:15 2024 +0200
@@ -46,7 +46,7 @@
 
       void ApplyLookupResources(std::list<std::string>& resourcesId,
                                 std::list<std::string>* instancesId,
-                                const std::vector<DatabaseConstraint>& lookup,
+                                const DatabaseConstraints& lookup,
                                 ResourceType queryLevel,
                                 size_t limit);
     };
--- a/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -35,7 +35,7 @@
   {
     static bool IsRequestWithoutContraint(const FindRequest& request)
     {
-      return (request.GetDicomTagConstraintsCount() == 0 &&
+      return (request.GetDicomTagConstraints().IsEmpty() &&
               request.GetMetadataConstraintsCount() == 0 &&
               request.GetLabels().empty() &&
               request.GetOrdering().empty());
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -35,7 +35,7 @@
       ILookupResources& compatibility,
       std::list<std::string>& resourcesId,
       std::list<std::string>* instancesId,
-      const std::vector<DatabaseConstraint>& lookup,
+      const DatabaseConstraints& lookup,
       ResourceType queryLevel,
       size_t limit)
     {
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.h	Tue Jul 09 10:15:15 2024 +0200
@@ -60,7 +60,7 @@
                         ILookupResources& compatibility,
                         std::list<std::string>& resourcesId,
                         std::list<std::string>* instancesId,
-                        const std::vector<DatabaseConstraint>& lookup,
+                        const DatabaseConstraints& lookup,
                         ResourceType queryLevel,
                         size_t limit);
     };
--- a/OrthancServer/Sources/Database/FindRequest.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/FindRequest.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -182,49 +182,6 @@
   }
 
 
-  void FindRequest::AddDicomTagConstraint(const DicomTagConstraint& constraint)
-  {
-    // This behaves like "StatelessDatabaseOperations::NormalizeLookup()" in Orthanc <= 1.12.3
-
-    if (mainDicomTagsRegistry_.get() == NULL)
-    {
-      // Lazy creation of the registry of main DICOM tags
-      mainDicomTagsRegistry_.reset(new MainDicomTagsRegistry());
-    }
-
-    ResourceType level;
-    DicomTagType type;
-
-    mainDicomTagsRegistry_->LookupTag(level, type, constraint.GetTag());
-
-    if (type == DicomTagType_Identifier ||
-        type == DicomTagType_Main)
-    {
-      // Use the fact that patient-level tags are copied at the study level
-      if (level == ResourceType_Patient &&
-          GetLevel() != ResourceType_Patient)
-      {
-        level = ResourceType_Study;
-      }
-
-      dicomTagConstraints_.push_back(constraint.ConvertToDatabaseConstraint(level, type));
-    }
-  }
-
-
-  const DatabaseConstraint& FindRequest::GetDicomTagConstraint(size_t index) const
-  {
-    if (index >= dicomTagConstraints_.size())
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-    else
-    {
-      return dicomTagConstraints_[index];
-    }
-  }
-
-
   void FindRequest::SetLimits(uint64_t since,
                               uint64_t count)
   {
--- a/OrthancServer/Sources/Database/FindRequest.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/FindRequest.h	Tue Jul 09 10:15:15 2024 +0200
@@ -249,7 +249,7 @@
     // filter & ordering fields
     ResourceType                         level_;                // The level of the response (the filtering on tags, labels and metadata also happens at this level)
     OrthancIdentifiers                   orthancIdentifiers_;   // The response must belong to this Orthanc resources hierarchy
-    std::deque<DatabaseConstraint>       dicomTagConstraints_;  // All tags filters (note: the order is not important)
+    DatabaseConstraints                  dicomTagConstraints_;  // All tags filters (note: the order is not important)
     std::deque<void*>   /* TODO-FIND */       metadataConstraints_;  // All metadata filters (note: the order is not important)
     bool                                 hasLimits_;
     uint64_t                             limitsSince_;
@@ -299,14 +299,15 @@
       return orthancIdentifiers_;
     }
 
-    void AddDicomTagConstraint(const DicomTagConstraint& constraint);
-
-    size_t GetDicomTagConstraintsCount() const
+    DatabaseConstraints& GetDicomTagConstraints()
     {
-      return dicomTagConstraints_.size();
+      return dicomTagConstraints_;
     }
 
-    const DatabaseConstraint& GetDicomTagConstraint(size_t index) const;
+    const DatabaseConstraints& GetDicomTagConstraints() const
+    {
+      return dicomTagConstraints_;
+    }
 
     size_t GetMetadataConstraintsCount() const
     {
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h	Tue Jul 09 10:15:15 2024 +0200
@@ -39,7 +39,7 @@
 
 namespace Orthanc
 {
-  class DatabaseConstraint;
+  class DatabaseConstraints;
   class ResourcesContent;
 
   class IDatabaseWrapper : public boost::noncopyable
@@ -284,7 +284,7 @@
     
       virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                         std::list<std::string>* instancesId, // Can be NULL if not needed
-                                        const std::vector<DatabaseConstraint>& lookup,
+                                        const DatabaseConstraints& lookup,
                                         ResourceType queryLevel,
                                         const std::set<std::string>& labels,
                                         LabelsConstraint labelsConstraint,
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -98,12 +98,11 @@
   }
 
 
-  void MainDicomTagsRegistry::NormalizeLookup(std::vector<DatabaseConstraint>& target,
+  void MainDicomTagsRegistry::NormalizeLookup(DatabaseConstraints& target,
                                               const DatabaseLookup& source,
                                               ResourceType queryLevel) const
   {
-    target.clear();
-    target.reserve(source.GetConstraintsCount());
+    target.Clear();
 
     for (size_t i = 0; i < source.GetConstraintsCount(); i++)
     {
@@ -122,7 +121,7 @@
           level = ResourceType_Study;
         }
 
-        target.push_back(source.GetConstraint(i).ConvertToDatabaseConstraint(level, type));
+        target.AddConstraint(source.GetConstraint(i).ConvertToDatabaseConstraint(level, type));
       }
     }
   }
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.h	Tue Jul 09 10:15:15 2024 +0200
@@ -75,7 +75,7 @@
                    DicomTagType& type,
                    const DicomTag& tag) const;
 
-    void NormalizeLookup(std::vector<DatabaseConstraint>& target,
+    void NormalizeLookup(DatabaseConstraints& target,
                          const DatabaseLookup& source,
                          ResourceType queryLevel) const;
   };
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -341,7 +341,7 @@
 
     virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                       std::list<std::string>* instancesId,
-                                      const std::vector<DatabaseConstraint>& lookup,
+                                      const DatabaseConstraints& lookup,
                                       ResourceType queryLevel,
                                       const std::set<std::string>& labels,
                                       LabelsConstraint labelsConstraint,
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -1551,20 +1551,20 @@
 
     DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true);
 
-    std::vector<DatabaseConstraint> query;
-    query.push_back(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
+    DatabaseConstraints query;
+    query.AddConstraint(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
 
 
     class Operations : public IReadOnlyOperations
     {
     private:
-      std::vector<std::string>&               result_;
-      const std::vector<DatabaseConstraint>&  query_;
-      ResourceType                            level_;
+      std::vector<std::string>&   result_;
+      const DatabaseConstraints&  query_;
+      ResourceType                level_;
       
     public:
       Operations(std::vector<std::string>& result,
-                 const std::vector<DatabaseConstraint>& query,
+                 const DatabaseConstraints& query,
                  ResourceType level) :
         result_(result),
         query_(query),
@@ -1850,7 +1850,7 @@
                                                          LabelsConstraint labelsConstraint,
                                                          uint32_t limit)
   {
-    class Operations : public ReadOnlyOperationsT6<bool, const std::vector<DatabaseConstraint>&, ResourceType,
+    class Operations : public ReadOnlyOperationsT6<bool, const DatabaseConstraints&, ResourceType,
                                                    const std::set<std::string>&, LabelsConstraint, size_t>
     {
     private:
@@ -1896,7 +1896,7 @@
       ServerToolbox::CheckValidLabel(*it);
     }
 
-    std::vector<DatabaseConstraint> normalized;
+    DatabaseConstraints normalized;
 
     assert(mainDicomTagsRegistry_.get() != NULL);
     mainDicomTagsRegistry_->NormalizeLookup(normalized, lookup, queryLevel);
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Tue Jul 09 10:15:15 2024 +0200
@@ -221,7 +221,7 @@
 
       void ApplyLookupResources(std::list<std::string>& resourcesId,
                                 std::list<std::string>* instancesId, // Can be NULL if not needed
-                                const std::vector<DatabaseConstraint>& lookup,
+                                const DatabaseConstraints& lookup,
                                 ResourceType queryLevel,
                                 const std::set<std::string>& labels,  // New in Orthanc 1.12.0
                                 LabelsConstraint labelsConstraint,    // New in Orthanc 1.12.0
--- a/OrthancServer/Sources/Search/DatabaseConstraint.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/DatabaseConstraint.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -246,4 +246,43 @@
     constraint.values = (tmpValues.empty() ? NULL : &tmpValues[0]);
   }
 #endif    
+
+
+  void DatabaseConstraints::Clear()
+  {
+    for (size_t i = 0; i < constraints_.size(); i++)
+    {
+      assert(constraints_[i] != NULL);
+      delete constraints_[i];
+    }
+
+    constraints_.clear();
+  }
+
+
+  void DatabaseConstraints::AddConstraint(DatabaseConstraint* constraint)
+  {
+    if (constraint == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+    else
+    {
+      constraints_.push_back(constraint);
+    }
+  }
+
+
+  const DatabaseConstraint& DatabaseConstraints::GetConstraint(size_t index) const
+  {
+    if (index >= constraints_.size())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      assert(constraints_[index] != NULL);
+      return *constraints_[index];
+    }
+  }
 }
--- a/OrthancServer/Sources/Search/DatabaseConstraint.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/DatabaseConstraint.h	Tue Jul 09 10:15:15 2024 +0200
@@ -46,6 +46,8 @@
 #  endif
 #endif
 
+#include <deque>
+
 namespace Orthanc
 {
   enum ConstraintType
@@ -78,7 +80,7 @@
 
 
   // This class is also used by the "orthanc-databases" project
-  class DatabaseConstraint
+  class DatabaseConstraint : public boost::noncopyable
   {
   public:
     enum KeyType  // used for ordering and filters
@@ -157,4 +159,33 @@
                           std::vector<const char*>& tmpValues) const;
 #endif    
   };
+
+
+  class DatabaseConstraints : public boost::noncopyable
+  {
+  private:
+    std::deque<DatabaseConstraint*>  constraints_;
+
+  public:
+    ~DatabaseConstraints()
+    {
+      Clear();
+    }
+
+    void Clear();
+
+    void AddConstraint(DatabaseConstraint* constraint);  // Takes ownership
+
+    bool IsEmpty() const
+    {
+      return constraints_.empty();
+    }
+
+    size_t GetSize() const
+    {
+      return constraints_.size();
+    }
+
+    const DatabaseConstraint& GetConstraint(size_t index) const;
+  };
 }
--- a/OrthancServer/Sources/Search/DicomTagConstraint.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/DicomTagConstraint.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -342,8 +342,8 @@
   }
 
 
-  DatabaseConstraint DicomTagConstraint::ConvertToDatabaseConstraint(ResourceType level,
-                                                                     DicomTagType tagType) const
+  DatabaseConstraint* DicomTagConstraint::ConvertToDatabaseConstraint(ResourceType level,
+                                                                      DicomTagType tagType) const
   {
     bool isIdentifier, caseSensitive;
     
@@ -379,7 +379,7 @@
       }
     }
 
-    return DatabaseConstraint(level, tag_, isIdentifier, constraintType_,
-                              values, caseSensitive, mandatory_);
+    return new DatabaseConstraint(level, tag_, isIdentifier, constraintType_,
+                                  values, caseSensitive, mandatory_);
   }  
 }
--- a/OrthancServer/Sources/Search/DicomTagConstraint.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/DicomTagConstraint.h	Tue Jul 09 10:15:15 2024 +0200
@@ -109,7 +109,7 @@
 
     std::string Format() const;
 
-    DatabaseConstraint ConvertToDatabaseConstraint(ResourceType level,
-                                                   DicomTagType tagType) const;
+    DatabaseConstraint* ConvertToDatabaseConstraint(ResourceType level,
+                                                    DicomTagType tagType) const;
   };
 }
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -475,7 +475,10 @@
   }
 
 
-  void ISqlLookupFormatter::GetLookupLevels(ResourceType& lowerLevel, ResourceType& upperLevel, const ResourceType& queryLevel, const std::vector<DatabaseConstraint>& lookup)
+  void ISqlLookupFormatter::GetLookupLevels(ResourceType& lowerLevel,
+                                            ResourceType& upperLevel,
+                                            const ResourceType& queryLevel,
+                                            const DatabaseConstraints& lookup)
   {
     assert(ResourceType_Patient < ResourceType_Study &&
            ResourceType_Study < ResourceType_Series &&
@@ -484,9 +487,9 @@
     lowerLevel = queryLevel;
     upperLevel = queryLevel;
 
-    for (size_t i = 0; i < lookup.size(); i++)
+    for (size_t i = 0; i < lookup.GetSize(); i++)
     {
-      ResourceType level = lookup[i].GetLevel();
+      ResourceType level = lookup.GetConstraint(i).GetLevel();
 
       if (level < upperLevel)
       {
@@ -503,7 +506,7 @@
 
   void ISqlLookupFormatter::Apply(std::string& sql,
                                   ISqlLookupFormatter& formatter,
-                                  const std::vector<DatabaseConstraint>& lookup,
+                                  const DatabaseConstraints& lookup,
                                   ResourceType queryLevel,
                                   const std::set<std::string>& labels,
                                   LabelsConstraint labelsConstraint,
@@ -521,14 +524,16 @@
 
     size_t count = 0;
     
-    for (size_t i = 0; i < lookup.size(); i++)
+    for (size_t i = 0; i < lookup.GetSize(); i++)
     {
+      const DatabaseConstraint& constraint = lookup.GetConstraint(i);
+
       std::string comparison;
       
-      if (FormatComparison(comparison, formatter, lookup[i], count, escapeBrackets))
+      if (FormatComparison(comparison, formatter, constraint, count, escapeBrackets))
       {
         std::string join;
-        FormatJoin(join, lookup[i], count);
+        FormatJoin(join, constraint, count);
         joins += join;
 
         if (!comparison.empty())
@@ -614,7 +619,7 @@
 
   void ISqlLookupFormatter::ApplySingleLevel(std::string& sql,
                                              ISqlLookupFormatter& formatter,
-                                             const std::vector<DatabaseConstraint>& lookup,
+                                             const DatabaseConstraints& lookup,
                                              ResourceType queryLevel,
                                              const std::set<std::string>& labels,
                                              LabelsConstraint labelsConstraint,
@@ -631,15 +636,17 @@
     
     std::vector<std::string> mainDicomTagsComparisons, dicomIdentifiersComparisons;
 
-    for (size_t i = 0; i < lookup.size(); i++)
+    for (size_t i = 0; i < lookup.GetSize(); i++)
     {
+      const DatabaseConstraint& constraint = lookup.GetConstraint(i);
+
       std::string comparison;
       
-      if (FormatComparison2(comparison, formatter, lookup[i], escapeBrackets))
+      if (FormatComparison2(comparison, formatter, constraint, escapeBrackets))
       {
         if (!comparison.empty())
         {
-          if (lookup[i].IsIdentifier())
+          if (constraint.IsIdentifier())
           {
             dicomIdentifiersComparisons.push_back(comparison);
           }
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.h	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.h	Tue Jul 09 10:15:15 2024 +0200
@@ -34,8 +34,8 @@
 
 namespace Orthanc
 {
-  class DatabaseConstraint;
-
+  class DatabaseConstraints;
+  
   enum LabelsConstraint
   {
     LabelsConstraint_All,
@@ -64,11 +64,14 @@
      **/
     virtual bool IsEscapeBrackets() const = 0;
 
-    static void GetLookupLevels(ResourceType& lowerLevel, ResourceType& upperLevel, const ResourceType& queryLevel, const std::vector<DatabaseConstraint>& lookup);
+    static void GetLookupLevels(ResourceType& lowerLevel,
+                                ResourceType& upperLevel,
+                                const ResourceType& queryLevel,
+                                const DatabaseConstraints& lookup);
 
     static void Apply(std::string& sql,
                       ISqlLookupFormatter& formatter,
-                      const std::vector<DatabaseConstraint>& lookup,
+                      const DatabaseConstraints& lookup,
                       ResourceType queryLevel,
                       const std::set<std::string>& labels,  // New in Orthanc 1.12.0
                       LabelsConstraint labelsConstraint,    // New in Orthanc 1.12.0
@@ -76,7 +79,7 @@
 
     static void ApplySingleLevel(std::string& sql,
                                  ISqlLookupFormatter& formatter,
-                                 const std::vector<DatabaseConstraint>& lookup,
+                                 const DatabaseConstraints& lookup,
                                  ResourceType queryLevel,
                                  const std::set<std::string>& labels,  // New in Orthanc 1.12.0
                                  LabelsConstraint labelsConstraint,    // New in Orthanc 1.12.0
--- a/OrthancServer/UnitTestsSources/ServerIndexTests.cpp	Tue Jul 09 09:03:40 2024 +0200
+++ b/OrthancServer/UnitTestsSources/ServerIndexTests.cpp	Tue Jul 09 10:15:15 2024 +0200
@@ -166,8 +166,8 @@
       
       DicomTagConstraint c(tag, type, value, true, true);
       
-      std::vector<DatabaseConstraint> lookup;
-      lookup.push_back(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
+      DatabaseConstraints lookup;
+      lookup.AddConstraint(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
 
       std::set<std::string> noLabel;
       transaction_->ApplyLookupResources(result, NULL, lookup, level, noLabel, LabelsConstraint_All, 0 /* no limit */);
@@ -185,10 +185,10 @@
       
       DicomTagConstraint c1(tag, type1, value1, true, true);
       DicomTagConstraint c2(tag, type2, value2, true, true);
-      
-      std::vector<DatabaseConstraint> lookup;
-      lookup.push_back(c1.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
-      lookup.push_back(c2.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
+
+      DatabaseConstraints lookup;
+      lookup.AddConstraint(c1.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
+      lookup.AddConstraint(c2.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
       
       std::set<std::string> noLabel;
       transaction_->ApplyLookupResources(result, NULL, lookup, level, noLabel, LabelsConstraint_All, 0 /* no limit */);