Mercurial > hg > orthanc-databases
changeset 807:c86377097e82 pg-next-1099
merged default -> pg-next-1099
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Tue, 14 Apr 2026 12:41:50 +0200 |
| parents | 412bede39cdb (current diff) b492e1535737 (diff) |
| children | 99598fd743f5 |
| files | PostgreSQL/NEWS |
| diffstat | 44 files changed, 497 insertions(+), 324 deletions(-) [+] |
line wrap: on
line diff
--- a/Framework/Common/DatabaseManager.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Common/DatabaseManager.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -102,16 +102,16 @@ std::unique_ptr<IPrecompiledStatement> statement(GetDatabase().Compile(query)); - IPrecompiledStatement* tmp = statement.get(); - if (tmp == NULL) + if (statement.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } - - assert(cachedStatements_.find(statementId) == cachedStatements_.end()); - cachedStatements_[statementId] = statement.release(); - - return *tmp; + else + { + assert(cachedStatements_.find(statementId) == cachedStatements_.end()); + cachedStatements_[statementId] = statement.release(); + return *cachedStatements_[statementId]; + } }
--- a/Framework/Common/DatabaseManager.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Common/DatabaseManager.h Tue Apr 14 12:41:50 2026 +0200 @@ -269,7 +269,7 @@ const std::string& sql, const Query::Parameters& parametersTypes); - virtual ~StandaloneStatement(); + virtual ~StandaloneStatement() ORTHANC_OVERRIDE; void Execute() {
--- a/Framework/Common/ImplicitTransaction.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Common/ImplicitTransaction.h Tue Apr 14 12:41:50 2026 +0200 @@ -53,7 +53,7 @@ public: ImplicitTransaction(); - virtual ~ImplicitTransaction(); + virtual ~ImplicitTransaction() ORTHANC_OVERRIDE; virtual bool IsImplicit() const ORTHANC_OVERRIDE {
--- a/Framework/Common/ResultBase.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Common/ResultBase.h Tue Apr 14 12:41:50 2026 +0200 @@ -50,7 +50,7 @@ void SetFieldsCount(size_t count); public: - virtual ~ResultBase() + virtual ~ResultBase() ORTHANC_OVERRIDE { ClearFields(); }
--- a/Framework/MySQL/MySQLDatabase.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/MySQL/MySQLDatabase.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -163,7 +163,7 @@ { // Fallback to TCP connection if no UNIX socket is provided unsigned int protocol = MYSQL_PROTOCOL_TCP; - mysql_options(mysql_, MYSQL_OPT_PROTOCOL, (unsigned int *) &protocol); + mysql_options(mysql_, MYSQL_OPT_PROTOCOL, reinterpret_cast<const void*>(&protocol)); } if (parameters_.IsSsl()) @@ -172,15 +172,15 @@ { #if (MYSQL_VERSION_ID > 50110 && MYSQL_VERSION_ID < 80000) // Removed in MySQL client 8.0 my_bool verifyCert = 1; - mysql_options(mysql_, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *) &verifyCert); + mysql_options(mysql_, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, reinterpret_cast<const void*>(&verifyCert)); #endif - mysql_options(mysql_, MYSQL_OPT_SSL_CA, (void *)(parameters_.GetSslCaCertificates())); + mysql_options(mysql_, MYSQL_OPT_SSL_CA, reinterpret_cast<const void*>(parameters_.GetSslCaCertificates())); } #if (MYSQL_VERSION_ID > 50110 && MYSQL_VERSION_ID < 80000) // Removed in MySQL client 8.0 my_bool enforceTls = 1; - mysql_options(mysql_, MYSQL_OPT_SSL_ENFORCE, (void *) &enforceTls); + mysql_options(mysql_, MYSQL_OPT_SSL_ENFORCE, reinterpret_cast<const void*>(&enforceTls)); #endif } @@ -402,7 +402,7 @@ } - bool MySQLDatabase::DoesTableExist(MySQLTransaction& transaction, + bool MySQLDatabase::DoesTableExist(const MySQLTransaction& transaction, const std::string& name) { if (mysql_ == NULL) @@ -434,7 +434,7 @@ } - bool MySQLDatabase::DoesDatabaseExist(MySQLTransaction& transaction, + bool MySQLDatabase::DoesDatabaseExist(const MySQLTransaction& transaction, const std::string& name) { if (mysql_ == NULL) @@ -464,7 +464,7 @@ } - bool MySQLDatabase::DoesTriggerExist(MySQLTransaction& transaction, + bool MySQLDatabase::DoesTriggerExist(const MySQLTransaction& transaction, const std::string& name) { if (mysql_ == NULL)
--- a/Framework/MySQL/MySQLDatabase.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/MySQL/MySQLDatabase.h Tue Apr 14 12:41:50 2026 +0200 @@ -54,7 +54,7 @@ public: explicit MySQLDatabase(const MySQLParameters& parameters); - virtual ~MySQLDatabase(); + virtual ~MySQLDatabase() ORTHANC_OVERRIDE; void LogError(); @@ -88,13 +88,13 @@ void ExecuteMultiLines(const std::string& sql, bool arobaseSeparator); - bool DoesTableExist(MySQLTransaction& transaction, + bool DoesTableExist(const MySQLTransaction& transaction, const std::string& name); - bool DoesDatabaseExist(MySQLTransaction& transaction, + bool DoesDatabaseExist(const MySQLTransaction& transaction, const std::string& name); - bool DoesTriggerExist(MySQLTransaction& transaction, + bool DoesTriggerExist(const MySQLTransaction& transaction, const std::string& name); virtual Dialect GetDialect() const ORTHANC_OVERRIDE
--- a/Framework/MySQL/MySQLStatement.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/MySQL/MySQLStatement.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -295,7 +295,7 @@ MYSQL_RES* metadata_; public: - ResultMetadata(MySQLDatabase& db, + ResultMetadata(const MySQLDatabase& db, MySQLStatement& statement) : metadata_(NULL) { @@ -405,7 +405,7 @@ if (query.IsReadOnly()) { unsigned long type = (unsigned long) CURSOR_TYPE_READ_ONLY; - mysql_stmt_attr_set(statement_, STMT_ATTR_CURSOR_TYPE, (void*) &type); + mysql_stmt_attr_set(statement_, STMT_ATTR_CURSOR_TYPE, reinterpret_cast<void*>(&type)); } } @@ -450,7 +450,7 @@ } - IResult* MySQLStatement::Execute(ITransaction& transaction, + IResult* MySQLStatement::Execute(const ITransaction& transaction, const Dictionary& parameters) { std::list<long long int> int64Parameters; @@ -554,7 +554,7 @@ } - void MySQLStatement::ExecuteWithoutResult(ITransaction& transaction, + void MySQLStatement::ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters) { std::unique_ptr<IResult> dummy(Execute(transaction, parameters));
--- a/Framework/MySQL/MySQLStatement.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/MySQL/MySQLStatement.h Tue Apr 14 12:41:50 2026 +0200 @@ -50,7 +50,7 @@ MySQLStatement(MySQLDatabase& db, const Query& query); - virtual ~MySQLStatement(); + virtual ~MySQLStatement() ORTHANC_OVERRIDE; MYSQL_STMT* GetObject(); @@ -61,10 +61,10 @@ IValue* FetchResultField(size_t i); - IResult* Execute(ITransaction& transaction, + IResult* Execute(const ITransaction& transaction, const Dictionary& parameters); - void ExecuteWithoutResult(ITransaction& transaction, + void ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters); }; }
--- a/Framework/MySQL/MySQLTransaction.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/MySQL/MySQLTransaction.h Tue Apr 14 12:41:50 2026 +0200 @@ -42,7 +42,7 @@ explicit MySQLTransaction(MySQLDatabase& db, TransactionType type); - virtual ~MySQLTransaction(); + virtual ~MySQLTransaction() ORTHANC_OVERRIDE; virtual bool IsImplicit() const ORTHANC_OVERRIDE {
--- a/Framework/Odbc/OdbcDatabase.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Odbc/OdbcDatabase.h Tue Apr 14 12:41:50 2026 +0200 @@ -48,7 +48,7 @@ OdbcDatabase(OdbcEnvironment& environment, const std::string& connectionString); - virtual ~OdbcDatabase(); + virtual ~OdbcDatabase() ORTHANC_OVERRIDE; SQLHDBC GetHandle() {
--- a/Framework/Odbc/OdbcEnvironment.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Odbc/OdbcEnvironment.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -44,7 +44,7 @@ } /* We want ODBC 3 support */ - if (!SQL_SUCCEEDED(SQLSetEnvAttr(handle_, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0))) + if (!SQL_SUCCEEDED(SQLSetEnvAttr(handle_, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0))) { SQLFreeHandle(SQL_HANDLE_ENV, handle_); throw Orthanc::OrthancException(Orthanc::ErrorCode_Database,
--- a/Framework/Odbc/OdbcPreparedStatement.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Odbc/OdbcPreparedStatement.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -31,6 +31,7 @@ #include <Logging.h> #include <OrthancException.h> +#include <cassert> #include <sqlext.h>
--- a/Framework/Odbc/OdbcResult.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Odbc/OdbcResult.h Tue Apr 14 12:41:50 2026 +0200 @@ -59,7 +59,7 @@ OdbcResult(OdbcStatement& statement, Dialect dialect); - virtual ~OdbcResult(); + virtual ~OdbcResult() ORTHANC_OVERRIDE; virtual void SetExpectedType(size_t field, ValueType type) ORTHANC_OVERRIDE;
--- a/Framework/Plugins/DatabaseBackendAdapterV3.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/DatabaseBackendAdapterV3.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -645,7 +645,7 @@ std::unique_ptr<Output> output_; public: - Transaction(IndexConnectionsPool& pool) : + explicit Transaction(IndexConnectionsPool& pool) : pool_(pool), accessor_(new IndexConnectionsPool::Accessor(pool)), output_(new Output) @@ -677,7 +677,7 @@ uint32_t* target /* out */) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswersCount(*target); } @@ -687,7 +687,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerAttachment(*target, index); } @@ -697,7 +697,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerChange(*target, index); } @@ -711,7 +711,7 @@ assert(group != NULL); assert(element != NULL); assert(value != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerDicomTag(*group, *element, *value, index); } @@ -721,7 +721,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerExportedResource(*target, index); } @@ -731,7 +731,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerInt32(*target, index); } @@ -741,7 +741,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerInt64(*target, index); } @@ -751,7 +751,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerMatchingResource(*target, index); } @@ -763,7 +763,7 @@ { assert(metadata != NULL); assert(value != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerMetadata(*metadata, *value, index); } @@ -773,7 +773,7 @@ uint32_t index) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadAnswerString(*target, index); } @@ -782,7 +782,7 @@ uint32_t* target /* out */) { assert(target != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadEventsCount(*target); } @@ -792,7 +792,7 @@ uint32_t index) { assert(event != NULL); - const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction& that = *reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); return that.GetOutput().ReadEvent(*event, index); } @@ -944,7 +944,7 @@ static OrthancPluginErrorCode Rollback(OrthancPluginDatabaseTransaction* transaction) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -959,7 +959,7 @@ static OrthancPluginErrorCode Commit(OrthancPluginDatabaseTransaction* transaction, int64_t fileSizeDelta /* TODO - not used? */) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -976,7 +976,7 @@ const OrthancPluginAttachment* attachment, int64_t revision) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -990,7 +990,7 @@ static OrthancPluginErrorCode ClearChanges(OrthancPluginDatabaseTransaction* transaction) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1004,7 +1004,7 @@ static OrthancPluginErrorCode ClearExportedResources(OrthancPluginDatabaseTransaction* transaction) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1019,7 +1019,7 @@ static OrthancPluginErrorCode ClearMainDicomTags(OrthancPluginDatabaseTransaction* transaction, int64_t resourceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1038,7 +1038,7 @@ const char* hashSeries, const char* hashInstance) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1063,7 +1063,7 @@ int64_t id, int32_t contentType) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1079,7 +1079,7 @@ int64_t id, int32_t metadataType) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1094,7 +1094,7 @@ static OrthancPluginErrorCode DeleteResource(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1109,7 +1109,7 @@ static OrthancPluginErrorCode GetAllMetadata(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1132,7 +1132,7 @@ static OrthancPluginErrorCode GetAllPublicIds(OrthancPluginDatabaseTransaction* transaction, OrthancPluginResourceType resourceType) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1153,7 +1153,7 @@ uint64_t since, uint64_t limit) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1174,7 +1174,7 @@ int64_t since, uint32_t maxResults) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1193,7 +1193,7 @@ static OrthancPluginErrorCode GetChildrenInternalId(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1213,7 +1213,7 @@ int64_t resourceId, int32_t metadata) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1232,7 +1232,7 @@ static OrthancPluginErrorCode GetChildrenPublicId(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1253,7 +1253,7 @@ int64_t since, uint32_t maxResults) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1271,7 +1271,7 @@ static OrthancPluginErrorCode GetLastChange(OrthancPluginDatabaseTransaction* transaction) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1286,7 +1286,7 @@ static OrthancPluginErrorCode GetLastChangeIndex(OrthancPluginDatabaseTransaction* transaction, int64_t* target) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1300,7 +1300,7 @@ static OrthancPluginErrorCode GetLastExportedResource(OrthancPluginDatabaseTransaction* transaction) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1315,7 +1315,7 @@ static OrthancPluginErrorCode GetMainDicomTags(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1330,7 +1330,7 @@ static OrthancPluginErrorCode GetPublicId(OrthancPluginDatabaseTransaction* transaction, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1346,7 +1346,7 @@ uint64_t* target /* out */, OrthancPluginResourceType resourceType) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1362,7 +1362,7 @@ OrthancPluginResourceType* target /* out */, uint64_t resourceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1377,7 +1377,7 @@ static OrthancPluginErrorCode GetTotalCompressedSize(OrthancPluginDatabaseTransaction* transaction, uint64_t* target /* out */) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1392,7 +1392,7 @@ static OrthancPluginErrorCode GetTotalUncompressedSize(OrthancPluginDatabaseTransaction* transaction, uint64_t* target /* out */) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1408,7 +1408,7 @@ uint8_t* target, uint64_t threshold) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1425,7 +1425,7 @@ uint8_t* target, int64_t resourceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1442,7 +1442,7 @@ uint8_t* target, int64_t resourceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1458,7 +1458,7 @@ static OrthancPluginErrorCode ListAvailableAttachments(OrthancPluginDatabaseTransaction* transaction, int64_t resourceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1479,7 +1479,7 @@ OrthancPluginResourceType resourceType, const char* date) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1501,7 +1501,7 @@ const char* seriesInstanceUid, const char* sopInstanceUid) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1519,7 +1519,7 @@ int64_t resourceId, int32_t contentType) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1535,7 +1535,7 @@ const char* serverIdentifier, int32_t property) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1558,7 +1558,7 @@ int64_t id, int32_t metadata) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1581,7 +1581,7 @@ int64_t* parentId /* out */, int64_t id) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1608,7 +1608,7 @@ OrthancPluginResourceType* type /* out */, const char* publicId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1636,7 +1636,7 @@ uint32_t limit, uint8_t requestSomeInstanceId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1664,7 +1664,7 @@ OrthancPluginResourceType* type /* out */, const char* publicId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1695,7 +1695,7 @@ uint8_t* patientAvailable, int64_t* patientId) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1721,7 +1721,7 @@ int64_t* patientId, int64_t patientIdToAvoid) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1747,7 +1747,7 @@ int32_t property, const char* value) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1765,7 +1765,7 @@ const char* value, int64_t revision) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1781,7 +1781,7 @@ int64_t id, uint8_t isProtected) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try { @@ -1801,7 +1801,7 @@ uint32_t countMetadata, const OrthancPluginResourcesContentMetadata* metadata) { - DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); + const DatabaseBackendAdapterV3::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV3::Transaction*>(transaction); try {
--- a/Framework/Plugins/DatabaseBackendAdapterV4.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/DatabaseBackendAdapterV4.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -48,7 +48,9 @@ namespace OrthancDatabases { static bool isBackendInUse_ = false; // Only for sanity checks - static BaseIndexConnectionsPool* connectionPool_ = NULL; // Only for the AuditLogHandler + + // The AuditLogHandler necessitates the plugin to manage the resources associated with the pool of connections + static std::unique_ptr<BaseIndexConnectionsPool> connectionPool_; static Orthanc::DatabasePluginMessages::ResourceType Convert(OrthancPluginResourceType resourceType) { @@ -129,63 +131,63 @@ } public: - Output(Orthanc::DatabasePluginMessages::DeleteAttachment::Response& deleteAttachment) + explicit Output(Orthanc::DatabasePluginMessages::DeleteAttachment::Response& deleteAttachment) { Clear(); deleteAttachment_ = &deleteAttachment; } - Output(Orthanc::DatabasePluginMessages::DeleteResource::Response& deleteResource) + explicit Output(Orthanc::DatabasePluginMessages::DeleteResource::Response& deleteResource) { Clear(); deleteResource_ = &deleteResource; } - Output(Orthanc::DatabasePluginMessages::GetChanges::Response& getChanges) + explicit Output(Orthanc::DatabasePluginMessages::GetChanges::Response& getChanges) { Clear(); getChanges_ = &getChanges; } #if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 - Output(Orthanc::DatabasePluginMessages::GetChangesExtended::Response& getChangesExtended) + explicit Output(Orthanc::DatabasePluginMessages::GetChangesExtended::Response& getChangesExtended) { Clear(); getChangesExtended_ = &getChangesExtended; } #endif - Output(Orthanc::DatabasePluginMessages::GetExportedResources::Response& getExportedResources) + explicit Output(Orthanc::DatabasePluginMessages::GetExportedResources::Response& getExportedResources) { Clear(); getExportedResources_ = &getExportedResources; } - Output(Orthanc::DatabasePluginMessages::GetLastChange::Response& getLastChange) + explicit Output(Orthanc::DatabasePluginMessages::GetLastChange::Response& getLastChange) { Clear(); getLastChange_ = &getLastChange; } - Output(Orthanc::DatabasePluginMessages::GetLastExportedResource::Response& getLastExportedResource) + explicit Output(Orthanc::DatabasePluginMessages::GetLastExportedResource::Response& getLastExportedResource) { Clear(); getLastExportedResource_ = &getLastExportedResource; } - Output(Orthanc::DatabasePluginMessages::GetMainDicomTags::Response& getMainDicomTags) + explicit Output(Orthanc::DatabasePluginMessages::GetMainDicomTags::Response& getMainDicomTags) { Clear(); getMainDicomTags_ = &getMainDicomTags; } - Output(Orthanc::DatabasePluginMessages::LookupAttachment::Response& lookupAttachment) + explicit Output(Orthanc::DatabasePluginMessages::LookupAttachment::Response& lookupAttachment) { Clear(); lookupAttachment_ = &lookupAttachment; } - Output(Orthanc::DatabasePluginMessages::LookupResources::Response& lookupResources) + explicit Output(Orthanc::DatabasePluginMessages::LookupResources::Response& lookupResources) { Clear(); lookupResources_ = &lookupResources; @@ -581,9 +583,26 @@ countValues += constraint.values().size(); } + std::vector<size_t> valuesIndex; + valuesIndex.resize(request.lookup().size()); + std::vector<const char*> values; values.reserve(countValues); + for (int i = 0; i < request.lookup().size(); i++) + { + valuesIndex[i] = values.size(); + + const Orthanc::DatabasePluginMessages::DatabaseConstraint& constraint = request.lookup(i); + + for (int j = 0; j < constraint.values().size(); j++) + { + values.push_back(constraint.values(j).c_str()); + } + } + + assert(values.size() == countValues); + DatabaseConstraints lookup; for (int i = 0; i < request.lookup().size(); i++) @@ -638,13 +657,7 @@ } else { - c.values = &values[values.size()]; - - for (int j = 0; j < constraint.values().size(); j++) - { - assert(values.size() < countValues); - values.push_back(constraint.values(j).c_str()); - } + c.values = &values[valuesIndex[i]]; } lookup.AddConstraint(new DatabaseConstraint(c)); @@ -1454,6 +1467,20 @@ const void* requestData, uint64_t requestSize) { + if (rawPool == NULL || + connectionPool_.get() == NULL || + rawPool != connectionPool_.get()) + { + LOG(ERROR) << "Internal error: Incorrect state for the pool of connections"; + return OrthancPluginErrorCode_InternalError; + } + + if (!isBackendInUse_) + { + LOG(ERROR) << "More than one index backend was registered, internal error"; + return OrthancPluginErrorCode_InternalError; + } + Orthanc::DatabasePluginMessages::Request request; if (!request.ParseFromArray(requestData, requestSize)) { @@ -1461,14 +1488,6 @@ return OrthancPluginErrorCode_InternalError; } - if (rawPool == NULL) - { - LOG(ERROR) << "Received a NULL pointer from the database"; - return OrthancPluginErrorCode_InternalError; - } - - BaseIndexConnectionsPool& pool = *reinterpret_cast<BaseIndexConnectionsPool*>(rawPool); - try { Orthanc::DatabasePluginMessages::Response response; @@ -1476,12 +1495,12 @@ switch (request.type()) { case Orthanc::DatabasePluginMessages::REQUEST_DATABASE: - ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), pool); + ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), *connectionPool_); break; case Orthanc::DatabasePluginMessages::REQUEST_TRANSACTION: { - BaseIndexConnectionsPool::Accessor& transaction = *reinterpret_cast<BaseIndexConnectionsPool::Accessor*>(request.transaction_request().transaction()); + const BaseIndexConnectionsPool::Accessor& transaction = *reinterpret_cast<const BaseIndexConnectionsPool::Accessor*>(request.transaction_request().transaction()); ProcessTransactionOperation(*response.mutable_transaction_response(), request.transaction_request(), transaction.GetBackend(), transaction.GetManager()); break; @@ -1498,7 +1517,7 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Cannot serialize to protobuf"); } - if (OrthancPluginCreateMemoryBuffer64(pool.GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success) + if (OrthancPluginCreateMemoryBuffer64(connectionPool_->GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory, "Cannot allocate a memory buffer"); } @@ -1537,26 +1556,23 @@ static void FinalizeBackend(void* rawPool) { - if (rawPool != NULL) + if (rawPool == NULL || + connectionPool_.get() == NULL || + connectionPool_.get() != rawPool) { - BaseIndexConnectionsPool* pool = reinterpret_cast<BaseIndexConnectionsPool*>(rawPool); - - if (isBackendInUse_) - { - isBackendInUse_ = false; - connectionPool_ = NULL; - } - else - { - LOG(ERROR) << "More than one index backend was registered, internal error"; - } + LOG(ERROR) << "Internal error: Incorrect state for the pool of connections"; + } - delete pool; + if (isBackendInUse_) + { + isBackendInUse_ = false; } else { - LOG(ERROR) << "Received a null pointer from the Orthanc core, internal error"; + LOG(ERROR) << "More than one index backend was registered, internal error"; } + + connectionPool_.reset(NULL); } @@ -1569,7 +1585,7 @@ uint32_t logDataSize) { if (!isBackendInUse_ || - connectionPool_ == NULL) + connectionPool_.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } @@ -1785,29 +1801,28 @@ unsigned int maxDatabaseRetries, unsigned int housekeepingDelaySeconds) { - std::unique_ptr<BaseIndexConnectionsPool> pool; - + // The "connectionPool_" takes the ownership of the backend if (useDynamicConnectionPool) { - pool.reset(new DynamicIndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds)); + connectionPool_.reset(new DynamicIndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds)); } else { - pool.reset(new IndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds)); + connectionPool_.reset(new IndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds)); } if (isBackendInUse_) { + connectionPool_.reset(); // This implies "delete backend" throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } OrthancPluginContext* context = backend->GetContext(); - connectionPool_ = pool.get(); // we need to keep a pointer on the connectionPool for the static Audit log handler - if (OrthancPluginRegisterDatabaseBackendV4(context, pool.release(), maxDatabaseRetries, + if (OrthancPluginRegisterDatabaseBackendV4(context, connectionPool_.get(), maxDatabaseRetries, CallBackend, FinalizeBackend) != OrthancPluginErrorCode_Success) { - delete backend; + connectionPool_.reset(); // This implies "delete backend" throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); }
--- a/Framework/Plugins/DynamicIndexConnectionsPool.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/DynamicIndexConnectionsPool.h Tue Apr 14 12:41:50 2026 +0200 @@ -59,7 +59,7 @@ size_t maxConnectionsCount, unsigned int houseKeepingDelaySeconds); - virtual ~DynamicIndexConnectionsPool(); + virtual ~DynamicIndexConnectionsPool() ORTHANC_OVERRIDE; virtual void OpenConnections(bool hasIdentifierTags, const std::list<IdentifierTag>& identifierTags) ORTHANC_OVERRIDE;
--- a/Framework/Plugins/ISqlLookupFormatter.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/ISqlLookupFormatter.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -135,7 +135,7 @@ } else { - comparison = "lower(" + tag + ".value) " + op + " lower(" + parameter + ")"; + comparison = formatter.FormatLower(tag + ".value") + op + formatter.FormatLower(parameter); } break; @@ -158,7 +158,7 @@ } else { - comparison += "lower(" + parameter + ")"; + comparison += formatter.FormatLower(parameter); } } @@ -168,7 +168,7 @@ } else { - comparison = "lower(" + tag + ".value) IN (" + comparison + ")"; + comparison = formatter.FormatLower(tag + ".value") + " IN (" + comparison + ")"; } break; @@ -188,57 +188,11 @@ } else { - std::string escaped; - escaped.reserve(value.size()); - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == '*') - { - escaped += "%"; - } - else if (value[i] == '?') - { - escaped += "_"; - } - else if (value[i] == '%') - { - escaped += "\\%"; - } - else if (value[i] == '_') - { - escaped += "\\_"; - } - else if (value[i] == '\\') - { - escaped += "\\\\"; - } - else if (escapeBrackets && value[i] == '[') - { - escaped += "\\["; - } - else if (escapeBrackets && value[i] == ']') - { - escaped += "\\]"; - } - else - { - escaped += value[i]; - } - } - + std::string escaped = formatter.FormatWildcardsForLike(value); std::string parameter = formatter.GenerateParameter(escaped); - - if (isCaseSensitive) - { - comparison = (tag + ".value LIKE " + parameter + " " + - formatter.FormatWildcardEscape()); - } - else - { - comparison = ("lower(" + tag + ".value) LIKE lower(" + - parameter + ") " + formatter.FormatWildcardEscape()); - } + comparison = formatter.FormatLike(isCaseSensitive, + tag + ".value", + parameter); } break; @@ -553,7 +507,7 @@ } else { - comparison = " AND lower(value) " + op + " lower(" + parameter + ")"; + comparison = " AND " + formatter.FormatLower("value") + op + formatter.FormatLower(parameter); } break; @@ -572,7 +526,7 @@ } else { - comparisonValues.push_back("lower(" + parameter + ")"); + comparisonValues.push_back(formatter.FormatLower(parameter)); } } @@ -584,7 +538,7 @@ } else { - comparison = " AND lower(value) IN (" + values + ")"; + comparison = " AND " + formatter.FormatLower("value") + " IN (" + values + ")"; } break; @@ -604,55 +558,11 @@ } else { - std::string escaped; - escaped.reserve(value.size()); - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == '*') - { - escaped += "%"; - } - else if (value[i] == '?') - { - escaped += "_"; - } - else if (value[i] == '%') - { - escaped += "\\%"; - } - else if (value[i] == '_') - { - escaped += "\\_"; - } - else if (value[i] == '\\') - { - escaped += "\\\\"; - } - else if (escapeBrackets && value[i] == '[') - { - escaped += "\\["; - } - else if (escapeBrackets && value[i] == ']') - { - escaped += "\\]"; - } - else - { - escaped += value[i]; - } - } - + std::string escaped = formatter.FormatWildcardsForLike(value); std::string parameter = formatter.GenerateParameter(escaped); - - if (constraint.IsCaseSensitive()) - { - comparison = " AND value LIKE " + parameter + " " + formatter.FormatWildcardEscape(); - } - else - { - comparison = " AND lower(value) LIKE lower(" + parameter + ") " + formatter.FormatWildcardEscape(); - } + comparison = " AND " + formatter.FormatLike(constraint.IsCaseSensitive(), + "value", + parameter); } break; @@ -811,6 +721,10 @@ where.push_back("(SELECT COUNT(1) FROM Labels AS selectedLabels WHERE selectedLabels.id = " + FormatLevel(queryLevel) + ".internalId AND selectedLabels.label IN (" + Join(formattedLabels, "", ", ") + ")) " + condition); } + else if (labelsConstraint == LabelsConstraint_None) // from 1.12.11, 'None' with an empty labels list means "list all resources without any labels" + { + where.push_back("(SELECT COUNT(1) FROM Labels WHERE id = " + FormatLevel(queryLevel) + ".internalId) = 0"); + } sql += joins + Join(where, " WHERE ", " AND "); @@ -893,7 +807,7 @@ assert(upperLevel <= queryLevel && queryLevel <= lowerLevel); - std::string ordering; + std::string orderingSql; std::string orderingJoins; if (request.ordering_size() > 0) @@ -955,22 +869,22 @@ if (formatter.SupportsNullsLast()) { - ordering = "ROW_NUMBER() OVER (ORDER BY " + orderByFieldsString + " NULLS LAST) AS rowNumber"; + orderingSql = "ROW_NUMBER() OVER (ORDER BY " + orderByFieldsString + " NULLS LAST) AS rowNumber"; } else { - ordering = "ROW_NUMBER() OVER (ORDER BY " + orderByFieldsString + ") AS rowNumber"; + orderingSql = "ROW_NUMBER() OVER (ORDER BY " + orderByFieldsString + ") AS rowNumber"; } } else { - ordering = "ROW_NUMBER() OVER (ORDER BY " + strQueryLevel + ".publicId) AS rowNumber"; // we need a default ordering in order to make default queries repeatable when using since&limit + orderingSql = "ROW_NUMBER() OVER (ORDER BY " + strQueryLevel + ".publicId) AS rowNumber"; // we need a default ordering in order to make default queries repeatable when using since&limit } sql = ("SELECT " + strQueryLevel + ".publicId, " + strQueryLevel + ".internalId, " + - ordering + + orderingSql + " FROM Resources AS " + strQueryLevel); @@ -1126,6 +1040,10 @@ where.push_back("(SELECT COUNT(1) FROM Labels AS selectedLabels WHERE selectedLabels.id = " + strQueryLevel + ".internalId AND selectedLabels.label IN (" + Join(formattedLabels, "", ", ") + ")) " + condition); } + else if (request.labels_constraint() == Orthanc::DatabasePluginMessages::LABELS_CONSTRAINT_NONE) // from 1.12.11, 'None' with an empty labels list means "list all resources without any labels" + { + where.push_back("(SELECT COUNT(1) FROM Labels WHERE id = " + FormatLevel(queryLevel) + ".internalId) = 0"); + } sql += joins + orderingJoins + Join(where, " WHERE ", " AND "); @@ -1245,6 +1163,11 @@ ") AS temp " " WHERE labelsCount " + condition + ")"); } + else if (labelsConstraint == LabelsConstraint_None) // from 1.12.11, 'None' with an empty labels list means "list all resources without any labels" + { + sql += (" AND (SELECT COUNT(1) FROM Labels WHERE id = internalId) = 0"); + } + if (limit != 0) {
--- a/Framework/Plugins/ISqlLookupFormatter.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/ISqlLookupFormatter.h Tue Apr 14 12:41:50 2026 +0200 @@ -67,6 +67,12 @@ virtual std::string FormatNull(const char* type) = 0; + virtual std::string FormatLike(bool isCaseSensitive, const std::string& a, const std::string& b) = 0; + + virtual std::string FormatWildcardsForLike(const std::string& value) = 0; + + virtual std::string FormatLower(const std::string& value) = 0; + /** * Whether to escape '[' and ']', which is only needed for * MSSQL. New in Orthanc 1.10.0, from the following changeset:
--- a/Framework/Plugins/IndexBackend.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/IndexBackend.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -34,6 +34,10 @@ #include <OrthancException.h> #include <Toolbox.h> +#if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 12, 11) +# include <ElapsedTimer.h> +#endif + #include <boost/algorithm/string/join.hpp> @@ -48,10 +52,15 @@ } - static std::string ConvertWildcardToLike(const std::string& query) + static std::string ConvertWildcardToLike(const std::string& query, Dialect dialect) { std::string s = query; + if (dialect == Dialect_SQLite) + { + return s; // we are actually using GLOB that keeps the 'Unix' like wildcards + } + for (size_t i = 0; i < s.size(); i++) { if (s[i] == '*') @@ -158,7 +167,7 @@ void IndexBackend::ReadChangesInternal(IDatabaseBackendOutput& output, bool& done, - DatabaseManager& manager, + const DatabaseManager& manager, DatabaseManager::CachedStatement& statement, const Dictionary& args, uint32_t limit, @@ -1394,25 +1403,25 @@ case OrthancPluginIdentifierConstraint_Equal: header += "d.value = ${value}"; statement.reset(new DatabaseManager::CachedStatement( - STATEMENT_FROM_HERE, manager, header.c_str())); + STATEMENT_FROM_HERE, manager, header)); break; case OrthancPluginIdentifierConstraint_SmallerOrEqual: header += "d.value <= ${value}"; statement.reset(new DatabaseManager::CachedStatement( - STATEMENT_FROM_HERE, manager, header.c_str())); + STATEMENT_FROM_HERE, manager, header)); break; case OrthancPluginIdentifierConstraint_GreaterOrEqual: header += "d.value >= ${value}"; statement.reset(new DatabaseManager::CachedStatement( - STATEMENT_FROM_HERE, manager, header.c_str())); + STATEMENT_FROM_HERE, manager, header)); break; case OrthancPluginIdentifierConstraint_Wildcard: header += "d.value LIKE ${value}"; statement.reset(new DatabaseManager::CachedStatement( - STATEMENT_FROM_HERE, manager, header.c_str())); + STATEMENT_FROM_HERE, manager, header)); break; default: @@ -1432,7 +1441,7 @@ if (constraint == OrthancPluginIdentifierConstraint_Wildcard) { - args.SetUtf8Value("value", ConvertWildcardToLike(value)); + args.SetUtf8Value("value", ConvertWildcardToLike(value, manager.GetDialect())); } else { @@ -2226,6 +2235,114 @@ } } + virtual std::string FormatLower(const std::string& value) + { + switch (dialect_) + { + case Dialect_SQLite: + { + return " lower_with_accents(" + value + ") "; + }; + default: + return " lower(" + value + ") "; + } + } + + virtual std::string FormatWildcardsForLike(const std::string& value) + { + bool escapeBrackets = IsEscapeBrackets(); + std::string escaped; + escaped.reserve(value.size()); + + switch (dialect_) + { + case Dialect_SQLite: + { + escaped = value; // SQLite uses GLOB instead of LIKE -> no need for escaping and we keep the 'Unix' like wildcards + }; break; + default: + for (size_t i = 0; i < value.size(); i++) + { + if (value[i] == '*') + { + escaped += "%"; + } + else if (value[i] == '?') + { + escaped += "_"; + } + else if (value[i] == '%') + { + escaped += "\\%"; + } + else if (value[i] == '_') + { + escaped += "\\_"; + } + else if (value[i] == '\\') + { + escaped += "\\\\"; + } + else if (escapeBrackets && value[i] == '[') + { + escaped += "\\["; + } + else if (escapeBrackets && value[i] == ']') + { + escaped += "\\]"; + } + else + { + escaped += value[i]; + } + } + } + return escaped; + } + + + virtual std::string FormatLike(bool isCaseSensitive, const std::string& a, const std::string& b) + { + switch (dialect_) + { + case Dialect_MySQL: // LIKE is case insensitive by default ! + { + if (isCaseSensitive) + { + return a + " LIKE BINARY " + b + " " + FormatWildcardEscape(); + } + else + { + return a + " LIKE " + b + " " + FormatWildcardEscape(); + } + }; break; + case Dialect_MSSQL: + case Dialect_PostgreSQL: // LIKE is case sensitive by default ! + { + if (isCaseSensitive) + { + return a + " LIKE " + b + " " + FormatWildcardEscape(); + } + else + { + return "lower(" + a + ") LIKE lower(" + b + ") " + FormatWildcardEscape(); + } + }; break; + case Dialect_SQLite: + { + if (isCaseSensitive) + { + return a + " GLOB " + b + " "; // + FormatWildcardEscape(); + } + else + { + return "lower_with_accents(" + a + ") GLOB lower_with_accents(" + b + ") "; // + FormatWildcardEscape(); + } + }; break; + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } virtual std::string FormatLimits(uint64_t since, uint64_t count) { @@ -2356,9 +2473,8 @@ ISqlLookupFormatter::GetLookupLevels(lowerLevel, upperLevel, queryLevel, lookup); std::string sql; - bool enableNewStudyCode = true; - - if (enableNewStudyCode && lowerLevel == queryLevel && upperLevel == queryLevel) + + if (lowerLevel == queryLevel && upperLevel == queryLevel) { ISqlLookupFormatter::ApplySingleLevel(sql, formatter, lookup, queryLevel, labels, labelsConstraint, limit); @@ -3133,7 +3249,11 @@ { DatabaseManager::StandaloneStatement statement(manager, "SELECT 1"); +#if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 12, 11) + Orthanc::ElapsedTimer timer; +#else Orthanc::Toolbox::ElapsedTimer timer; +#endif statement.ExecuteWithoutResult();
--- a/Framework/Plugins/IndexBackend.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/IndexBackend.h Tue Apr 14 12:41:50 2026 +0200 @@ -73,7 +73,7 @@ private: void ReadChangesInternal(IDatabaseBackendOutput& output, bool& done, - DatabaseManager& manager, + const DatabaseManager& manager, DatabaseManager::CachedStatement& statement, const Dictionary& args, uint32_t limit, @@ -577,7 +577,7 @@ const std::list<IdentifierTag>& identifierTags); #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - ISqlLookupFormatter* CreateLookupFormatter(Dialect dialect); + static ISqlLookupFormatter* CreateLookupFormatter(Dialect dialect); #endif }; }
--- a/Framework/Plugins/IndexConnectionsPool.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/IndexConnectionsPool.h Tue Apr 14 12:41:50 2026 +0200 @@ -62,7 +62,7 @@ size_t countConnections, unsigned int houseKeepingDelaySeconds); - virtual ~IndexConnectionsPool(); + virtual ~IndexConnectionsPool() ORTHANC_OVERRIDE; virtual void OpenConnections(bool hasIdentifierTags, const std::list<IdentifierTag>& identifierTags) ORTHANC_OVERRIDE;
--- a/Framework/Plugins/IndexUnitTests.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/IndexUnitTests.h Tue Apr 14 12:41:50 2026 +0200 @@ -359,16 +359,16 @@ CheckBlob(blob); } - std::string s; - ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion)); - ASSERT_EQ("6", s); + std::string a; + ASSERT_TRUE(db.LookupGlobalProperty(a, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion)); + ASSERT_EQ("6", a); db.SetGlobalProperty(*manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9, "Hello"); - ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9)); - ASSERT_EQ("Hello", s); + ASSERT_TRUE(db.LookupGlobalProperty(a, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9)); + ASSERT_EQ("Hello", a); db.SetGlobalProperty(*manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9, "HelloWorld"); - ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9)); - ASSERT_EQ("HelloWorld", s); + ASSERT_TRUE(db.LookupGlobalProperty(a, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal9)); + ASSERT_EQ("HelloWorld", a); ASSERT_EQ(0u, db.GetAllResourcesCount(*manager)); ASSERT_EQ(0u, db.GetResourcesCount(*manager, OrthancPluginResourceType_Patient)); @@ -408,9 +408,9 @@ ASSERT_EQ(1u, db.GetResourcesCount(*manager, OrthancPluginResourceType_Study)); ASSERT_EQ(2u, db.GetResourcesCount(*manager, OrthancPluginResourceType_Series)); - ASSERT_FALSE(db.GetParentPublicId(s, *manager, studyId)); - ASSERT_TRUE(db.GetParentPublicId(s, *manager, seriesId)); ASSERT_EQ("study", s); - ASSERT_TRUE(db.GetParentPublicId(s, *manager, series2Id)); ASSERT_EQ("study", s); + ASSERT_FALSE(db.GetParentPublicId(a, *manager, studyId)); + ASSERT_TRUE(db.GetParentPublicId(a, *manager, seriesId)); ASSERT_EQ("study", a); + ASSERT_TRUE(db.GetParentPublicId(a, *manager, series2Id)); ASSERT_EQ("study", a); std::list<std::string> children; db.GetChildren(children, *manager, studyId); @@ -449,9 +449,9 @@ db.SetMetadata(*manager, studyId, Orthanc::MetadataType_ModifiedFrom, "modified", 42); db.SetMetadata(*manager, studyId, Orthanc::MetadataType_LastUpdate, "update2", 43); int64_t revision = -1; - ASSERT_FALSE(db.LookupMetadata(s, revision, *manager, seriesId, Orthanc::MetadataType_LastUpdate)); - ASSERT_TRUE(db.LookupMetadata(s, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); - ASSERT_EQ("update2", s); + ASSERT_FALSE(db.LookupMetadata(a, revision, *manager, seriesId, Orthanc::MetadataType_LastUpdate)); + ASSERT_TRUE(db.LookupMetadata(a, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); + ASSERT_EQ("update2", a); #if HAS_REVISIONS == 1 ASSERT_EQ(43, revision); @@ -460,8 +460,8 @@ #endif db.SetMetadata(*manager, studyId, Orthanc::MetadataType_LastUpdate, reinterpret_cast<const char*>(UTF8), 44); - ASSERT_TRUE(db.LookupMetadata(s, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); - ASSERT_STREQ(reinterpret_cast<const char*>(UTF8), s.c_str()); + ASSERT_TRUE(db.LookupMetadata(a, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); + ASSERT_STREQ(reinterpret_cast<const char*>(UTF8), a.c_str()); #if HAS_REVISIONS == 1 ASSERT_EQ(44, revision); @@ -496,11 +496,11 @@ db.ListAvailableMetadata(md, *manager, seriesId); ASSERT_EQ(0u, md.size()); - ASSERT_TRUE(db.LookupMetadata(s, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); + ASSERT_TRUE(db.LookupMetadata(a, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); db.DeleteMetadata(*manager, studyId, Orthanc::MetadataType_LastUpdate); - ASSERT_FALSE(db.LookupMetadata(s, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); + ASSERT_FALSE(db.LookupMetadata(a, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); db.DeleteMetadata(*manager, seriesId, Orthanc::MetadataType_LastUpdate); - ASSERT_FALSE(db.LookupMetadata(s, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); + ASSERT_FALSE(db.LookupMetadata(a, revision, *manager, studyId, Orthanc::MetadataType_LastUpdate)); db.ListAvailableMetadata(md, *manager, studyId); ASSERT_EQ(1u, md.size()); @@ -786,12 +786,12 @@ // column in "ServerProperties" is "TEXT" instead of "LONGTEXT" db.SetGlobalProperty(*manager, "some-server", Orthanc::GlobalProperty_DatabaseInternal8, longProperty.c_str()); - ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal8)); - ASSERT_EQ(longProperty, s); + ASSERT_TRUE(db.LookupGlobalProperty(a, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal8)); + ASSERT_EQ(longProperty, a); - s.clear(); - ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, "some-server", Orthanc::GlobalProperty_DatabaseInternal8)); - ASSERT_EQ(longProperty, s); + a.clear(); + ASSERT_TRUE(db.LookupGlobalProperty(a, *manager, "some-server", Orthanc::GlobalProperty_DatabaseInternal8)); + ASSERT_EQ(longProperty, a); } for (size_t level = 0; level < 4; level++) @@ -1069,7 +1069,7 @@ #if ORTHANC_PLUGINS_HAS_RESERVE_QUEUE_VALUE == 1 { std::string value; - uint64_t valueIdA, valueIdB, valueIdC, valueIdD, valueIdE, valueIdFail; + uint64_t valueIdA, valueIdB, valueIdC, valueIdD, valueIdE; { manager->StartTransaction(TransactionType_ReadWrite); @@ -1111,6 +1111,8 @@ ASSERT_EQ("d", value); ASSERT_TRUE(db.ReserveQueueValue(value, valueIdC, *manager, "test", false, 1)); ASSERT_EQ("c", value); + + uint64_t valueIdFail; ASSERT_FALSE(db.ReserveQueueValue(value, valueIdFail, *manager, "test", false, 1)); manager->CommitTransaction();
--- a/Framework/Plugins/PluginInitialization.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/PluginInitialization.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -155,7 +155,7 @@ std::string(isIndex ? "index" : "storage area") + " into a " + dbms + " database"); - OrthancPlugins::SetDescription(pluginName, description.c_str()); + OrthancPlugins::SetDescription(pluginName, description); return true; }
--- a/Framework/Plugins/StorageBackend.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/Plugins/StorageBackend.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -330,7 +330,7 @@ bool success_; public: - Visitor(OrthancPluginMemoryBuffer64* target) : + explicit Visitor(OrthancPluginMemoryBuffer64* target) : target_(target), success_(false) { @@ -406,7 +406,7 @@ bool success_; public: - Visitor(OrthancPluginMemoryBuffer64* target) : + explicit Visitor(OrthancPluginMemoryBuffer64* target) : target_(target), success_(false) { @@ -520,7 +520,7 @@ { } - ~Visitor() + virtual ~Visitor() ORTHANC_OVERRIDE { if (data_ != NULL /* this condition is invalidated by "Release()" */ && *data_ != NULL) @@ -792,7 +792,7 @@ operation.Execute(*accessor); return; // Success } - catch (Orthanc::OrthancException& e) + catch (const Orthanc::OrthancException& e) { #if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 9, 2) if (e.GetErrorCode() == Orthanc::ErrorCode_DatabaseCannotSerialize)
--- a/Framework/PostgreSQL/PostgreSQLDatabase.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/PostgreSQL/PostgreSQLDatabase.h Tue Apr 14 12:41:50 2026 +0200 @@ -57,7 +57,7 @@ { } - ~PostgreSQLDatabase(); + virtual ~PostgreSQLDatabase() ORTHANC_OVERRIDE; void Open();
--- a/Framework/PostgreSQL/PostgreSQLResult.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/PostgreSQL/PostgreSQLResult.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -211,7 +211,7 @@ Oid oid; assert(PQfsize(reinterpret_cast<PGresult*>(result_), column) == sizeof(oid)); - oid = *(const Oid*) PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column); + oid = *reinterpret_cast<const Oid*>(PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column)); oid = ntohl(oid); return boost::lexical_cast<std::string>(oid);
--- a/Framework/PostgreSQL/PostgreSQLStatement.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/PostgreSQL/PostgreSQLStatement.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -537,7 +537,7 @@ }; - IResult* PostgreSQLStatement::Execute(ITransaction& transaction, + IResult* PostgreSQLStatement::Execute(const ITransaction& transaction, const Dictionary& parameters) { for (size_t i = 0; i < formatter_.GetParametersCount(); i++) @@ -589,7 +589,7 @@ } - void PostgreSQLStatement::ExecuteWithoutResult(ITransaction& transaction, + void PostgreSQLStatement::ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters) { std::unique_ptr<IResult> dummy(Execute(transaction, parameters));
--- a/Framework/PostgreSQL/PostgreSQLStatement.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/PostgreSQL/PostgreSQLStatement.h Tue Apr 14 12:41:50 2026 +0200 @@ -72,7 +72,7 @@ PostgreSQLStatement(PostgreSQLDatabase& database, const Query& query); - ~PostgreSQLStatement(); + virtual ~PostgreSQLStatement() ORTHANC_OVERRIDE; void DeclareInputInteger(unsigned int param); @@ -103,10 +103,10 @@ return database_; } - IResult* Execute(ITransaction& transaction, + IResult* Execute(const ITransaction& transaction, const Dictionary& parameters); - void ExecuteWithoutResult(ITransaction& transaction, + void ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters); }; }
--- a/Framework/PostgreSQL/PostgreSQLTransaction.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/PostgreSQL/PostgreSQLTransaction.h Tue Apr 14 12:41:50 2026 +0200 @@ -45,7 +45,7 @@ explicit PostgreSQLTransaction(PostgreSQLDatabase& database, TransactionType type); - ~PostgreSQLTransaction(); + virtual ~PostgreSQLTransaction() ORTHANC_OVERRIDE; virtual bool IsImplicit() const ORTHANC_OVERRIDE {
--- a/Framework/SQLite/SQLiteDatabase.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/SQLite/SQLiteDatabase.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -28,6 +28,7 @@ #include "../Common/ImplicitTransaction.h" #include <OrthancException.h> +#include <Toolbox.h> namespace OrthancDatabases { @@ -114,4 +115,44 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } + + class LowerWithAccents : public Orthanc::SQLite::IScalarFunction + { + public: + LowerWithAccents() + { + } + + virtual const char* GetName() const ORTHANC_OVERRIDE + { + return "lower_with_accents"; + } + + virtual unsigned int GetCardinality() const ORTHANC_OVERRIDE + { + return 1; + } + + virtual void Compute(Orthanc::SQLite::FunctionContext& context) ORTHANC_OVERRIDE + { + std::string source = context.GetStringValue(0); + std::string modified = Orthanc::Toolbox::ToLowerCaseWithAccents(source); + + context.SetStringResult(modified); + } + + }; + + void SQLiteDatabase::OpenInMemory() + { + connection_.OpenInMemory(); + connection_.Register(new LowerWithAccents()); + } + + void SQLiteDatabase::Open(const std::string& path) + { + connection_.Open(path); + connection_.Register(new LowerWithAccents()); + } + }
--- a/Framework/SQLite/SQLiteDatabase.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/SQLite/SQLiteDatabase.h Tue Apr 14 12:41:50 2026 +0200 @@ -39,15 +39,9 @@ Orthanc::SQLite::Connection connection_; public: - void OpenInMemory() - { - connection_.OpenInMemory(); - } + void OpenInMemory(); - void Open(const std::string& path) - { - connection_.Open(path); - } + void Open(const std::string& path); Orthanc::SQLite::Connection& GetObject() {
--- a/Framework/SQLite/SQLiteStatement.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/SQLite/SQLiteStatement.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -105,7 +105,7 @@ } - IResult* SQLiteStatement::Execute(ITransaction& transaction, + IResult* SQLiteStatement::Execute(const ITransaction& transaction, const Dictionary& parameters) { BindParameters(parameters); @@ -113,7 +113,7 @@ } - void SQLiteStatement::ExecuteWithoutResult(ITransaction& transaction, + void SQLiteStatement::ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters) { BindParameters(parameters);
--- a/Framework/SQLite/SQLiteStatement.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Framework/SQLite/SQLiteStatement.h Tue Apr 14 12:41:50 2026 +0200 @@ -52,10 +52,10 @@ Orthanc::SQLite::Statement& GetObject(); - IResult* Execute(ITransaction& transaction, + IResult* Execute(const ITransaction& transaction, const Dictionary& parameters); - void ExecuteWithoutResult(ITransaction& transaction, + void ExecuteWithoutResult(const ITransaction& transaction, const Dictionary& parameters); }; }
--- a/MySQL/Plugins/MySQLStorageArea.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/MySQL/Plugins/MySQLStorageArea.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -28,11 +28,10 @@ #include "../../Framework/MySQL/MySQLTransaction.h" #include "MySQLDefinitions.h" -#include <Compatibility.h> // For std::unique_ptr<> +#include <Compatibility.h> // For std::unique_ptr<> +#include <CompatibilityMath.h> // For Orthanc::Math::iround() #include <Logging.h> -#include <boost/math/special_functions/round.hpp> - namespace OrthancDatabases { @@ -47,8 +46,8 @@ int64_t size; if (db.LookupGlobalIntegerVariable(size, "max_allowed_packet")) { - int mb = boost::math::iround(static_cast<double>(size) / - static_cast<double>(1024 * 1024)); + int mb = Orthanc::Math::iround(static_cast<double>(size) / + static_cast<double>(1024 * 1024)); LOG(WARNING) << "Your MySQL server cannot " << "store DICOM files larger than " << mb << "MB"; LOG(WARNING) << " => Consider increasing \"max_allowed_packet\" "
--- a/PostgreSQL/CMakeLists.txt Fri Jan 02 13:05:05 2026 +0100 +++ b/PostgreSQL/CMakeLists.txt Tue Apr 14 12:41:50 2026 +0200 @@ -43,7 +43,7 @@ set(ORTHANC_FRAMEWORK_VERSION "mainline") set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg") else() - set(ORTHANC_FRAMEWORK_VERSION "e0979326ac53") # while waiting for 1.12.11 + set(ORTHANC_FRAMEWORK_VERSION "e0979326ac53") # while waiting for 1.12.11 for Orthanc::Toolbox::ToLowerCaseWithAccents set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web") endif()
--- a/PostgreSQL/NEWS Fri Jan 02 13:05:05 2026 +0100 +++ b/PostgreSQL/NEWS Tue Apr 14 12:41:50 2026 +0200 @@ -13,6 +13,14 @@ 2025-12-05 08:04:24.133 UTC [73] STATEMENT: SELECT * FROM DeleteResource($1) +Release 10.1 (2026-04-14) +========================= + +Changes: +* In tools/find, filtering against "LabelsConstraint": "None" with an empty "Labels" list + now returns all resources that do not have any labels attached instead of returning all resources. + + Release 10.0 (2025-12-02) =========================
--- a/PostgreSQL/Plugins/PostgreSQLIndex.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/PostgreSQL/Plugins/PostgreSQLIndex.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -69,7 +69,8 @@ return PostgreSQLDatabase::CreateDatabaseFactory(parameters_); } - void PostgreSQLIndex::ApplyPrepareIndex(DatabaseManager::Transaction& t, DatabaseManager& manager) + void PostgreSQLIndex::ApplyPrepareIndex(DatabaseManager::Transaction& t, + const DatabaseManager& manager) { std::string query;
--- a/PostgreSQL/Plugins/PostgreSQLIndex.h Fri Jan 02 13:05:05 2026 +0100 +++ b/PostgreSQL/Plugins/PostgreSQLIndex.h Tue Apr 14 12:41:50 2026 +0200 @@ -49,7 +49,8 @@ return true; } - void ApplyPrepareIndex(DatabaseManager::Transaction& t, DatabaseManager& manager); + void ApplyPrepareIndex(DatabaseManager::Transaction& t, + const DatabaseManager& manager); public: PostgreSQLIndex(OrthancPluginContext* context,
--- a/Resources/CMake/DatabasesFrameworkConfiguration.cmake Fri Jan 02 13:05:05 2026 +0100 +++ b/Resources/CMake/DatabasesFrameworkConfiguration.cmake Tue Apr 14 12:41:50 2026 +0200 @@ -26,6 +26,7 @@ if (ENABLE_SQLITE_BACKEND) set(ENABLE_SQLITE ON) + set(ENABLE_LOCALE ON) # iconv is needed for lower_with_accents endif() if (ENABLE_POSTGRESQL_BACKEND)
--- a/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake Fri Jan 02 13:05:05 2026 +0100 +++ b/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake Tue Apr 14 12:41:50 2026 +0200 @@ -231,6 +231,11 @@ # for BlockingSharedMessageQueue.WaitEmpty() set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "c037cd2ddbe1b65b431692855483161b") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "56eb61c86f93") + # OE2 1.11.0 (framework post-1.12.10) + # for HttpClient that returns the answer body in case of HTTP error + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) + set(ORTHANC_FRAMEWORK_MD5 "665f8aa70d7c5091bc20da37cf664910") endif() endif() endif()
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -1544,11 +1544,25 @@ #endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */ + static void CheckAnswerSizeIsLessThan4GB(const std::string& answer) + { + if (answer.size() > static_cast<size_t>(std::numeric_limits<uint32_t>::max())) + { + #if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, "Cannot send HTTP response larger than 4GB"); + #else + ORTHANC_PLUGINS_LOG_ERROR("Cannot send HTTP response larger than 4GB"); + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + #endif + } + } + void AnswerJson(const Json::Value& value, OrthancPluginRestOutput* output) { std::string bodyString; - WriteStyledJson(bodyString, value); + WriteStyledJson(bodyString, value); + CheckAnswerSizeIsLessThan4GB(bodyString); OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json"); } @@ -1556,6 +1570,7 @@ const char* mimeType, OrthancPluginRestOutput* output) { + CheckAnswerSizeIsLessThan4GB(answer); OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType); } @@ -1564,6 +1579,26 @@ OrthancPluginSendHttpStatusCode(GetGlobalContext(), output, httpError); } + void AnswerHttpError(uint16_t httpError, + OrthancPluginRestOutput* output, + const std::string& answer, + const char* mimeType) + { + CheckAnswerSizeIsLessThan4GB(answer); + + OrthancPluginSetHttpHeader(GetGlobalContext(), + output, + "content-type", + mimeType); + + OrthancPluginSendHttpStatus(GetGlobalContext(), + output, + httpError, + answer.c_str(), + static_cast<uint32_t>(answer.size())); + } + + void AnswerMethodNotAllowed(OrthancPluginRestOutput *output, const char* allowedMethods) { OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowedMethods);
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Fri Jan 02 13:05:05 2026 +0100 +++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Tue Apr 14 12:41:50 2026 +0200 @@ -690,6 +690,11 @@ void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput* output); + void AnswerHttpError(uint16_t httpError, + OrthancPluginRestOutput* output, + const std::string& answer, + const char* mimeType); + void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods); #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) @@ -1025,7 +1030,20 @@ OrthancPluginSetMetricsValue(GetGlobalContext(), name, value, OrthancPluginMetricsType_Default); } +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 1) + inline void SetMetricsValue(const char* name, + int64_t value) + { + OrthancPluginSetMetricsIntegerValue(GetGlobalContext(), name, + value, OrthancPluginMetricsType_Default); + } +#endif + + +#if HAS_ORTHANC_PLUGIN_METRICS == 1 class MetricsTimer : public boost::noncopyable { private:
--- a/SQLite/CMakeLists.txt Fri Jan 02 13:05:05 2026 +0100 +++ b/SQLite/CMakeLists.txt Tue Apr 14 12:41:50 2026 +0200 @@ -43,7 +43,7 @@ set(ORTHANC_FRAMEWORK_VERSION "mainline") set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg") else() - set(ORTHANC_FRAMEWORK_VERSION "1.12.8") + set(ORTHANC_FRAMEWORK_VERSION "e0979326ac53") # while waiting for 1.12.11 for Orthanc::Toolbox::ToLowerCaseWithAccents set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web") endif()
--- a/SQLite/Plugins/IndexPlugin.cpp Fri Jan 02 13:05:05 2026 +0100 +++ b/SQLite/Plugins/IndexPlugin.cpp Tue Apr 14 12:41:50 2026 +0200 @@ -25,6 +25,7 @@ #include "../../Framework/Plugins/PluginInitialization.h" #include <Logging.h> +#include <Toolbox.h> #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 0) # include <google/protobuf/any.h> @@ -42,6 +43,8 @@ GOOGLE_PROTOBUF_VERIFY_VERSION; #endif + Orthanc::Toolbox::InitializeGlobalLocale(NULL); + if (!OrthancDatabases::InitializePlugin(context, ORTHANC_PLUGIN_NAME, "SQLite", true)) { return -1;
