changeset 4598:da2e0a457eae db-changes

OrthancPluginDatabaseV3::Transaction is fully implemented
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 18 Mar 2021 11:26:10 +0100
parents cc64385593ef
children 3875dcb65987
files OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h
diffstat 2 files changed, 404 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Tue Mar 16 17:58:16 2021 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Thu Mar 18 11:26:10 2021 +0100
@@ -40,6 +40,7 @@
 
 #include "../../../OrthancFramework/Sources/Logging.h"
 #include "../../../OrthancFramework/Sources/OrthancException.h"
+#include "../../Sources/Database/ResourcesContent.h"
 #include "../../Sources/Database/VoidDatabaseListener.h"
 #include "PluginsEnumerations.h"
 
@@ -82,15 +83,15 @@
       }
     }
 
-    
-    std::string ReadOneStringAnswer()
+
+    bool ReadSingleStringAnswer(std::string& target)
     {
       uint32_t count;
       CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
 
       if (count == 0)
       {
-        throw OrthancException(ErrorCode_InexistentItem);
+        return false;
       }
       else if (count == 1)
       {
@@ -102,7 +103,8 @@
         }
         else
         {
-          return value;
+          target.assign(value);
+          return true;
         }
       }
       else
@@ -111,6 +113,27 @@
       }
     }
 
+
+    bool ReadSingleInt64Answer(int64_t& target)
+    {
+      uint32_t count;
+      CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
+
+      if (count == 0)
+      {
+        return false;
+      }
+      else if (count == 1)
+      {
+        CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &target, 0));
+        return true;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_DatabasePlugin);
+      }
+    }
+
     
     ExportedResource ReadAnswerExportedResource(uint32_t answerIndex)
     {
@@ -432,7 +455,16 @@
     virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE
     {
       CheckSuccess(that_.backend_.getPublicId(transaction_, resourceId));
-      return ReadOneStringAnswer();
+
+      std::string s;
+      if (ReadSingleStringAnswer(s))
+      {
+        return s;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_InexistentItem);
+      }
     }
 
     
@@ -507,25 +539,62 @@
     {
       CheckSuccess(that_.backend_.logChange(transaction_, static_cast<int32_t>(change.GetChangeType()),
                                             internalId, Plugins::Convert(change.GetResourceType()),
-                                            change.GetPublicId().c_str(), change.GetDate().c_str()));
+                                            change.GetDate().c_str()));
     }
 
     
     virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE
     {
-    }   
+      CheckSuccess(that_.backend_.logExportedResource(transaction_, Plugins::Convert(resource.GetResourceType()),
+                                                      resource.GetPublicId().c_str(),
+                                                      resource.GetModality().c_str(),
+                                                      resource.GetDate().c_str(),
+                                                      resource.GetPatientId().c_str(),
+                                                      resource.GetStudyInstanceUid().c_str(),
+                                                      resource.GetSeriesInstanceUid().c_str(),
+                                                      resource.GetSopInstanceUid().c_str()));
+    }
 
     
     virtual bool LookupAttachment(FileInfo& attachment,
                                   int64_t id,
                                   FileContentType contentType) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.lookupAttachment(transaction_, id, static_cast<int32_t>(contentType)));
+
+      uint32_t count;
+      CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
+
+      if (count == 0)
+      {
+        return false;
+      }
+      else if (count == 1)
+      {
+        OrthancPluginAttachment tmp;
+        CheckSuccess(that_.backend_.readAnswerAttachment(transaction_, &tmp, 0));
+
+        attachment = FileInfo(tmp.uuid,
+                              static_cast<FileContentType>(tmp.contentType),
+                              tmp.uncompressedSize,
+                              tmp.uncompressedHash,
+                              static_cast<CompressionType>(tmp.compressionType),
+                              tmp.compressedSize,
+                              tmp.compressedHash);
+        return true;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_DatabasePlugin);
+      }
     }
 
     
     virtual bool LookupGlobalProperty(std::string& target,
                                       GlobalProperty property) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.lookupGlobalProperty(transaction_, static_cast<int32_t>(property)));
+      return ReadSingleStringAnswer(target);      
     }
 
     
@@ -533,12 +602,16 @@
                                 int64_t id,
                                 MetadataType type) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.lookupMetadata(transaction_, id, static_cast<int32_t>(type)));
+      return ReadSingleStringAnswer(target);      
     }
 
     
     virtual bool LookupParent(int64_t& parentId,
                               int64_t resourceId) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.lookupParent(transaction_, resourceId));
+      return ReadSingleInt64Answer(parentId);      
     }
 
     
@@ -546,28 +619,36 @@
                                 ResourceType& type,
                                 const std::string& publicId) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.lookupResource(transaction_, Plugins::Convert(type), publicId.c_str()));
+      return ReadSingleInt64Answer(id);      
     }
 
     
     virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.selectPatientToRecycle(transaction_));
+      return ReadSingleInt64Answer(internalId);      
     }
 
     
     virtual bool SelectPatientToRecycle(int64_t& internalId,
                                         int64_t patientIdToAvoid) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.selectPatientToRecycle2(transaction_, patientIdToAvoid));
+      return ReadSingleInt64Answer(internalId);      
     }
 
     
     virtual void SetGlobalProperty(GlobalProperty property,
                                    const std::string& value) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.setGlobalProperty(transaction_, static_cast<int32_t>(property), value.c_str()));
     }
 
     
     virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.clearMainDicomTags(transaction_, id));
     }
 
     
@@ -575,17 +656,22 @@
                              MetadataType type,
                              const std::string& value) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.setMetadata(transaction_, id, static_cast<int32_t>(type), value.c_str()));
     }
 
     
     virtual void SetProtectedPatient(int64_t internalId, 
                                      bool isProtected) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.setProtectedPatient(transaction_, internalId, (isProtected ? 1 : 0)));
     }
 
 
     virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE
     {
+      uint8_t tmp;
+      CheckSuccess(that_.backend_.isDiskSizeAbove(transaction_, &tmp, threshold));
+      return (tmp != 0);
     }
 
     
@@ -595,6 +681,56 @@
                                       ResourceType queryLevel,
                                       size_t limit) ORTHANC_OVERRIDE
     {
+      std::vector<OrthancPluginDatabaseConstraint> constraints;
+      std::vector< std::vector<const char*> > constraintsValues;
+
+      constraints.resize(lookup.size());
+      constraintsValues.resize(lookup.size());
+
+      for (size_t i = 0; i < lookup.size(); i++)
+      {
+        lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]);
+      }
+
+      CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.size(),
+                                                  (lookup.empty() ? NULL : &constraints[0]),
+                                                  Plugins::Convert(queryLevel),
+                                                  limit, (instancesId == NULL ? 0 : 1)));
+
+      uint32_t count;
+      CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
+      
+      resourcesId.clear();
+
+      if (instancesId != NULL)
+      {
+        instancesId->clear();
+      }
+      
+      for (uint32_t i = 0; i < count; i++)
+      {
+        OrthancPluginMatchingResource resource;
+        CheckSuccess(that_.backend_.readAnswerMatchingResource(transaction_, &resource, i));
+
+        if (resource.resourceId == NULL)
+        {
+          throw OrthancException(ErrorCode_DatabasePlugin);
+        }
+        
+        resourcesId.push_back(resource.resourceId);
+
+        if (instancesId != NULL)
+        {
+          if (resource.someInstanceId == NULL)
+          {
+            throw OrthancException(ErrorCode_DatabasePlugin);
+          }
+          else
+          {
+            instancesId->push_back(resource.someInstanceId);
+          }
+        }
+      }
     }
 
     
@@ -605,11 +741,81 @@
                                 const std::string& series,
                                 const std::string& instance) ORTHANC_OVERRIDE
     {
+      OrthancPluginCreateInstanceResult output;
+      memset(&output, 0, sizeof(output));
+
+      CheckSuccess(that_.backend_.createInstance(transaction_, &output, patient.c_str(),
+                                                 study.c_str(), series.c_str(), instance.c_str()));
+
+      instanceId = output.instanceId;
+      
+      if (output.isNewInstance)
+      {
+        result.isNewPatient_ = output.isNewPatient;
+        result.isNewStudy_ = output.isNewStudy;
+        result.isNewSeries_ = output.isNewSeries;
+        result.patientId_ = output.patientId;
+        result.studyId_ = output.studyId;
+        result.seriesId_ = output.seriesId;
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+
     }
 
     
     virtual void SetResourcesContent(const ResourcesContent& content) ORTHANC_OVERRIDE
     {
+      std::vector<OrthancPluginResourcesContentTags> identifierTags;
+      std::vector<OrthancPluginResourcesContentTags> mainDicomTags;
+      std::vector<OrthancPluginResourcesContentMetadata> metadata;
+
+      identifierTags.reserve(content.GetListTags().size());
+      mainDicomTags.reserve(content.GetListTags().size());
+      metadata.reserve(content.GetListMetadata().size());
+
+      for (ResourcesContent::ListTags::const_iterator
+             it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it)
+      {
+        OrthancPluginResourcesContentTags tmp;
+        tmp.resource = it->resourceId_;
+        tmp.group = it->tag_.GetGroup();
+        tmp.element = it->tag_.GetElement();
+        tmp.value = it->value_.c_str();
+
+        if (it->isIdentifier_)
+        {
+          identifierTags.push_back(tmp);
+        }
+        else
+        {
+          mainDicomTags.push_back(tmp);
+        }
+      }
+
+      for (ResourcesContent::ListMetadata::const_iterator
+             it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it)
+      {
+        OrthancPluginResourcesContentMetadata tmp;
+        tmp.resource = it->resourceId_;
+        tmp.metadata = it->metadata_;
+        tmp.value = it->value_.c_str();
+        metadata.push_back(tmp);
+      }
+
+      assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() &&
+             metadata.size() == content.GetListMetadata().size());
+       
+      CheckSuccess(that_.backend_.setResourcesContent(transaction_,
+                                                      identifierTags.size(),
+                                                      (identifierTags.empty() ? NULL : &identifierTags[0]),
+                                                      mainDicomTags.size(),
+                                                      (mainDicomTags.empty() ? NULL : &mainDicomTags[0]),
+                                                      metadata.size(),
+                                                      (metadata.empty() ? NULL : &metadata[0])));
     }
 
     
@@ -617,12 +823,16 @@
                                      int64_t resourceId,
                                      MetadataType metadata) ORTHANC_OVERRIDE
     {
+      CheckSuccess(that_.backend_.getChildrenMetadata(transaction_, resourceId, static_cast<int32_t>(metadata)));
+      ReadStringAnswers(target);
     }
 
     
     virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE
     {
-
+      int64_t tmp;
+      CheckSuccess(that_.backend_.getLastChangeIndex(transaction_, &tmp));
+      return tmp;
     }
 
     
@@ -631,6 +841,64 @@
                                          std::string& parentPublicId,
                                          const std::string& publicId) ORTHANC_OVERRIDE
     {
+      uint8_t isExisting;
+      OrthancPluginResourceType tmpType;
+      CheckSuccess(that_.backend_.lookupResourceAndParent(transaction_, &isExisting, &id, &tmpType, publicId.c_str()));
+
+      if (isExisting)
+      {
+        type = Plugins::Convert(tmpType);
+        
+        uint32_t count;
+        CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
+
+        if (count > 1)
+        {
+          throw OrthancException(ErrorCode_DatabasePlugin);
+        }
+
+        switch (type)
+        {
+          case ResourceType_Patient:
+            // A patient has no parent
+            if (count == 1)
+            {
+              throw OrthancException(ErrorCode_DatabasePlugin);
+            }
+            break;
+
+          case ResourceType_Study:
+          case ResourceType_Series:
+          case ResourceType_Instance:
+            if (count == 0)
+            {
+              throw OrthancException(ErrorCode_DatabasePlugin);
+            }
+            else
+            {
+              const char* value = NULL;
+              CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0));
+              if (value == NULL)
+              {
+                throw OrthancException(ErrorCode_DatabasePlugin);
+              }
+              else
+              {
+                parentPublicId.assign(value);
+              }              
+            }
+            break;
+
+          default:
+            throw OrthancException(ErrorCode_DatabasePlugin);
+        }
+        
+        return true;
+      }
+      else
+      {
+        return false;
+      }
     }
   };
 
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h	Tue Mar 16 17:58:16 2021 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h	Thu Mar 18 11:26:10 2021 +0100
@@ -994,10 +994,14 @@
      **/
     
     OrthancPluginErrorCode (*readAnswersCount) (OrthancPluginDatabaseTransaction* transaction,
-                                                uint32_t* target);
+                                                uint32_t* target /* out */);
+
+    OrthancPluginErrorCode (*readAnswerAttachment) (OrthancPluginDatabaseTransaction* transaction,
+                                                    OrthancPluginAttachment* target /* out */,
+                                                    uint32_t index);
 
     OrthancPluginErrorCode (*readAnswerChange) (OrthancPluginDatabaseTransaction* transaction,
-                                                OrthancPluginChange* target,
+                                                OrthancPluginChange* target /* out */,
                                                 uint32_t index);
 
     OrthancPluginErrorCode (*readAnswerDicomTag) (OrthancPluginDatabaseTransaction* transaction,
@@ -1007,23 +1011,28 @@
                                                   uint32_t index);
 
     OrthancPluginErrorCode (*readAnswerExportedResource) (OrthancPluginDatabaseTransaction* transaction,
-                                                          OrthancPluginExportedResource* target,
+                                                          OrthancPluginExportedResource* target /* out */,
                                                           uint32_t index);
 
     OrthancPluginErrorCode (*readAnswerInt32) (OrthancPluginDatabaseTransaction* transaction,
-                                               int32_t* target,
+                                               int32_t* target /* out */,
                                                uint32_t index);
 
     OrthancPluginErrorCode (*readAnswerInt64) (OrthancPluginDatabaseTransaction* transaction,
-                                               int64_t* target,
+                                               int64_t* target /* out */,
                                                uint32_t index);
 
+    OrthancPluginErrorCode (*readAnswerMatchingResource) (OrthancPluginDatabaseTransaction* transaction,
+                                                          OrthancPluginMatchingResource* target /* out */,
+                                                          uint32_t index);
+    
     OrthancPluginErrorCode (*readAnswerMetadata) (OrthancPluginDatabaseTransaction* transaction,
-                                                  int32_t* metadata,
-                                                  const char** value,
+                                                  int32_t* metadata /* out */,
+                                                  const char** value /* out */,
                                                   uint32_t index);
+
     OrthancPluginErrorCode (*readAnswerString) (OrthancPluginDatabaseTransaction* transaction,
-                                                const char** target,
+                                                const char** target /* out */,
                                                 uint32_t index);
 
     
@@ -1039,14 +1048,14 @@
     OrthancPluginErrorCode (*destructDatabase) (OrthancPluginDatabaseContext* database);
 
     OrthancPluginErrorCode (*getDatabaseVersion) (OrthancPluginDatabaseContext* database,
-                                                  uint32_t* target);
+                                                  uint32_t* target /* out */);
 
     OrthancPluginErrorCode (*upgradeDatabase) (OrthancPluginDatabaseContext* database,
                                                OrthancPluginStorageArea* storageArea,
-                                               uint32_t target);
+                                               uint32_t targetVersion);
 
     OrthancPluginErrorCode (*startTransaction) (OrthancPluginDatabaseContext* database,
-                                                OrthancPluginDatabaseTransaction** target,
+                                                OrthancPluginDatabaseTransaction** target /* out */,
                                                 _OrthancPluginDatabaseTransactionType type);
 
     OrthancPluginErrorCode (*destructTransaction) (OrthancPluginDatabaseTransaction* transaction);
@@ -1070,6 +1079,16 @@
     
     OrthancPluginErrorCode (*clearExportedResources) (OrthancPluginDatabaseTransaction* transaction);
     
+    OrthancPluginErrorCode (*clearMainDicomTags) (OrthancPluginDatabaseTransaction* transaction,
+                                                  int64_t resourceId);
+
+    OrthancPluginErrorCode (*createInstance) (OrthancPluginDatabaseTransaction* transaction,
+                                              OrthancPluginCreateInstanceResult* target /* out */,
+                                              const char* hashPatient,
+                                              const char* hashStudy,
+                                              const char* hashSeries,
+                                              const char* hashInstance);
+
     OrthancPluginErrorCode (*deleteAttachment) (OrthancPluginDatabaseTransaction* transaction,
                                                 int64_t id,
                                                 int32_t contentType);
@@ -1097,7 +1116,7 @@
 
     /* Answers are read using "readAnswerChange()" */
     OrthancPluginErrorCode (*getChanges) (OrthancPluginDatabaseTransaction* transaction,
-                                          uint8_t* targetDone,
+                                          uint8_t* targetDone /* out */,
                                           int64_t since,
                                           uint32_t maxResults);
     
@@ -1106,18 +1125,26 @@
                                                      int64_t id);
     
     /* Answers are read using "readAnswerString()" */
+    OrthancPluginErrorCode  (*getChildrenMetadata) (OrthancPluginDatabaseTransaction* transaction,
+                                                    int64_t resourceId,
+                                                    int32_t metadata);
+
+    /* Answers are read using "readAnswerString()" */
     OrthancPluginErrorCode (*getChildrenPublicId) (OrthancPluginDatabaseTransaction* transaction,
                                                    int64_t id);
 
     /* Answers are read using "readAnswerExportedResource()" */
     OrthancPluginErrorCode (*getExportedResources) (OrthancPluginDatabaseTransaction* transaction,
-                                                    uint8_t* targetDone,
+                                                    uint8_t* targetDone /* out */,
                                                     int64_t since,
                                                     uint32_t maxResults);
     
     /* Answer is read using "readAnswerChange()" */
     OrthancPluginErrorCode (*getLastChange) (OrthancPluginDatabaseTransaction* transaction);
     
+    OrthancPluginErrorCode (*getLastChangeIndex) (OrthancPluginDatabaseTransaction* transaction,
+                                                  int64_t* target /* out */);
+    
     /* Answer is read using "readAnswerExportedResource()" */
     OrthancPluginErrorCode (*getLastExportedResource) (OrthancPluginDatabaseTransaction* transaction);
     
@@ -1130,25 +1157,29 @@
                                            int64_t internalId);
     
     OrthancPluginErrorCode (*getResourcesCount) (OrthancPluginDatabaseTransaction* transaction,
-                                                 uint64_t* target,
+                                                 uint64_t* target /* out */,
                                                  OrthancPluginResourceType resourceType);
     
     OrthancPluginErrorCode (*getResourceType) (OrthancPluginDatabaseTransaction* transaction,
-                                               OrthancPluginResourceType* target,
+                                               OrthancPluginResourceType* target /* out */,
                                                uint64_t resourceId);
     
     OrthancPluginErrorCode (*getTotalCompressedSize) (OrthancPluginDatabaseTransaction* transaction,
-                                                      uint64_t* target);
+                                                      uint64_t* target /* out */);
     
     OrthancPluginErrorCode (*getTotalUncompressedSize) (OrthancPluginDatabaseTransaction* transaction,
-                                                        uint64_t* target);
+                                                        uint64_t* target /* out */);
+    
+    OrthancPluginErrorCode (*isDiskSizeAbove) (OrthancPluginDatabaseTransaction* transaction,
+                                               uint8_t* target /* out */,
+                                               uint64_t threshold);
     
     OrthancPluginErrorCode (*isExistingResource) (OrthancPluginDatabaseTransaction* transaction,
-                                                  uint8_t* target,
+                                                  uint8_t* target /* out */,
                                                   int64_t resourceId);
     
     OrthancPluginErrorCode (*isProtectedPatient) (OrthancPluginDatabaseTransaction* transaction,
-                                                  uint8_t* target,
+                                                  uint8_t* target /* out */,
                                                   int64_t resourceId);
     
     /* Answer is read using "readAnswerInt32()" */
@@ -1157,11 +1188,87 @@
 
     OrthancPluginErrorCode (*logChange) (OrthancPluginDatabaseTransaction* transaction,
                                          int32_t changeType,
-                                         int64_t internalId,
+                                         int64_t resourceId,
                                          OrthancPluginResourceType resourceType,
-                                         const char* publicId,
                                          const char* date);
+
+    OrthancPluginErrorCode (*logExportedResource) (OrthancPluginDatabaseTransaction* transaction,
+                                                   OrthancPluginResourceType resourceType,
+                                                   const char* publicId,
+                                                   const char* modality,
+                                                   const char* date,
+                                                   const char* patientId,
+                                                   const char* studyInstanceUid,
+                                                   const char* seriesInstanceUid,
+                                                   const char* sopInstanceUid);
+
+    /* Answer is read using "readAnswerAttachment()" */
+    OrthancPluginErrorCode (*lookupAttachment) (OrthancPluginDatabaseTransaction* transaction,
+                                                int64_t resourceId,
+                                                int32_t contentType);
+
+    /* Answer is read using "readAnswerString()" */
+    OrthancPluginErrorCode (*lookupGlobalProperty) (OrthancPluginDatabaseTransaction* transaction,
+                                                    int32_t property);
     
+    /* Answer is read using "readAnswerString()" */
+    OrthancPluginErrorCode (*lookupMetadata) (OrthancPluginDatabaseTransaction* transaction,
+                                              int64_t id,
+                                              int32_t metadata);
+    
+    /* Answer is read using "readAnswerInt64()" */
+    OrthancPluginErrorCode (*lookupParent) (OrthancPluginDatabaseTransaction* transaction,
+                                            int64_t id);
+    
+    /* Answer is read using "readAnswerInt64()" */
+    OrthancPluginErrorCode (*lookupResource) (OrthancPluginDatabaseTransaction* transaction,
+                                              OrthancPluginResourceType level,
+                                              const char* publicId);
+    
+    /* Answers are read using "readAnswerMatchingResource()" */
+    OrthancPluginErrorCode  (*lookupResources) (OrthancPluginDatabaseTransaction* transaction,
+                                                uint32_t constraintsCount,
+                                                const OrthancPluginDatabaseConstraint* constraints,
+                                                OrthancPluginResourceType queryLevel,
+                                                uint32_t limit,
+                                                uint8_t requestSomeInstanceId);
+
+    /* The public ID of the parent resource is read using "readAnswerString()" */
+    OrthancPluginErrorCode (*lookupResourceAndParent) (OrthancPluginDatabaseTransaction* transaction,
+                                                       uint8_t* isExisting /* out */,
+                                                       int64_t* id /* out */,
+                                                       OrthancPluginResourceType* type /* out */,
+                                                       const char* publicId);
+
+    /* Answer is read using "readAnswerInt64()" */
+    OrthancPluginErrorCode (*selectPatientToRecycle) (OrthancPluginDatabaseTransaction* transaction);
+    
+    /* Answer is read using "readAnswerInt64()" */
+    OrthancPluginErrorCode (*selectPatientToRecycle2) (OrthancPluginDatabaseTransaction* transaction,
+                                                       int64_t patientIdToAvoid);
+
+    OrthancPluginErrorCode (*setGlobalProperty) (OrthancPluginDatabaseTransaction* transaction,
+                                                 int32_t property,
+                                                 const char* value);
+
+    OrthancPluginErrorCode (*setMetadata) (OrthancPluginDatabaseTransaction* transaction,
+                                           int64_t id,
+                                           int32_t metadata,
+                                           const char* value);
+    
+    OrthancPluginErrorCode (*setProtectedPatient) (OrthancPluginDatabaseTransaction* transaction,
+                                                   int64_t id,
+                                                   uint8_t isProtected);
+
+    OrthancPluginErrorCode  (*setResourcesContent) (OrthancPluginDatabaseTransaction* transaction,
+                                                    uint32_t countIdentifierTags,
+                                                    const OrthancPluginResourcesContentTags* identifierTags,
+                                                    uint32_t countMainDicomTags,
+                                                    const OrthancPluginResourcesContentTags* mainDicomTags,
+                                                    uint32_t countMetadata,
+                                                    const OrthancPluginResourcesContentMetadata* metadata);
+    
+
   } OrthancPluginDatabaseBackendV3;
 
 /*<! @endcond */