Mercurial > hg > orthanc
diff OrthancServer/SQLiteDatabaseWrapper.cpp @ 3027:fd587cf51a89 db-changes
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Dec 2018 12:50:27 +0100 |
parents | 039a9d262d64 |
children | ea653ec47f31 |
line wrap: on
line diff
--- a/OrthancServer/SQLiteDatabaseWrapper.cpp Mon Dec 17 17:05:28 2018 +0100 +++ b/OrthancServer/SQLiteDatabaseWrapper.cpp Tue Dec 18 12:50:27 2018 +0100 @@ -339,6 +339,9 @@ db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); //db_.Execute("PRAGMA TEMP_STORE=memory"); + // Make "LIKE" case-sensitive in SQLite + db_.Execute("PRAGMA case_sensitive_like = true;"); + if (!db_.DoesTableExist("GlobalProperties")) { LOG(INFO) << "Creating the database"; @@ -1203,129 +1206,19 @@ } - namespace - { - class MainDicomTagsRegistry : public boost::noncopyable - { - private: - class TagInfo - { - private: - ResourceType level_; - DicomTagType type_; - - public: - TagInfo() - { - } - - TagInfo(ResourceType level, - DicomTagType type) : - level_(level), - type_(type) - { - } - - ResourceType GetLevel() const - { - return level_; - } - - DicomTagType GetType() const - { - return type_; - } - }; - - typedef std::map<DicomTag, TagInfo> Registry; - - - Registry registry_; - - void LoadTags(ResourceType level) - { - const DicomTag* tags = NULL; - size_t size; - - ServerToolbox::LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (registry_.find(tags[i]) == registry_.end()) - { - registry_[tags[i]] = TagInfo(level, DicomTagType_Identifier); - } - else - { - // These patient-level tags are copied in the study level - assert(level == ResourceType_Study && - (tags[i] == DICOM_TAG_PATIENT_ID || - tags[i] == DICOM_TAG_PATIENT_NAME || - tags[i] == DICOM_TAG_PATIENT_BIRTH_DATE)); - } - } - - DicomMap::LoadMainDicomTags(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (registry_.find(tags[i]) == registry_.end()) - { - registry_[tags[i]] = TagInfo(level, DicomTagType_Main); - } - } - } - - public: - MainDicomTagsRegistry() - { - LoadTags(ResourceType_Patient); - LoadTags(ResourceType_Study); - LoadTags(ResourceType_Series); - LoadTags(ResourceType_Instance); - } - - void LookupTag(ResourceType& level, - DicomTagType& type, - const DicomTag& tag) const - { - Registry::const_iterator it = registry_.find(tag); - - if (it == registry_.end()) - { - // Default values - level = ResourceType_Instance; - type = DicomTagType_Generic; - } - else - { - level = it->second.GetLevel(); - type = it->second.GetType(); - } - } - }; - } - - - void SQLiteDatabaseWrapper::FindOneChildInstance(std::vector<std::string>& instancesId, - const std::vector<std::string>& resourcesId, - ResourceType level) - { - printf("ICI 3\n"); - - throw OrthancException(ErrorCode_NotImplemented); - } - - void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId, + std::vector<std::string>& instancesId, const DatabaseLookup& lookup, size_t limit) { - static const MainDicomTagsRegistry registry; - printf("ICI 1\n"); - std::string heading = "SELECT patient.publicId FROM Resources AS patient "; + { + SQLite::Statement s(db_, "DROP TABLE IF EXISTS Lookup"); + s.Run(); + } + + std::string heading = "CREATE TEMPORARY TABLE Lookup AS SELECT patient.publicId, patient.internalId FROM Resources AS patient "; std::string trailer; std::vector<std::string> parameters; @@ -1333,75 +1226,114 @@ { const DicomTagConstraint& constraint = lookup.GetConstraint(i); - ResourceType level; - DicomTagType type; - registry.LookupTag(level, type, constraint.GetTag()); - - if (level != ResourceType_Patient) + if (constraint.GetTagType() != DicomTagType_Identifier && + constraint.GetTagType() != DicomTagType_Main) { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Not a patient-level tag: (" + - lookup.GetConstraint(i).GetTag().Format() + ")"); + // This should have been set by ServerIndex::NormalizeLookup()" + throw OrthancException(ErrorCode_BadSequenceOfCalls); } + + std::string tag = "t" + boost::lexical_cast<std::string>(i); - if (type == DicomTagType_Identifier || - type == DicomTagType_Main) + char on[128]; + sprintf( + on, "%s JOIN %s %s ON %s.id = patient.internalId AND %s.tagGroup = 0x%04x AND %s.tagElement = 0x%04x ", + constraint.IsMandatory() ? "INNER" : "LEFT", + constraint.GetTagType() == DicomTagType_Identifier ? "DicomIdentifiers" : "MainDicomTags", + tag.c_str(), tag.c_str(), tag.c_str(), constraint.GetTag().GetGroup(), + tag.c_str(), constraint.GetTag().GetElement()); + + std::string comparison; + + switch (constraint.GetConstraintType()) { - std::string table = (type == DicomTagType_Identifier ? "DicomIdentifiers" : "MainDicomTags"); - std::string tag = "t" + boost::lexical_cast<std::string>(i); + case ConstraintType_Equal: + case ConstraintType_SmallerOrEqual: + case ConstraintType_GreaterOrEqual: + { + std::string op; + switch (constraint.GetConstraintType()) + { + case ConstraintType_Equal: + op = "="; + break; + + case ConstraintType_SmallerOrEqual: + op = "<="; + break; + + case ConstraintType_GreaterOrEqual: + op = ">="; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + parameters.push_back(constraint.GetValue()); - char on[128]; - sprintf(on, " %s ON %s.id = patient.internalId AND %s.tagGroup = 0x%04x AND %s.tagElement = 0x%04x ", - tag.c_str(), tag.c_str(), tag.c_str(), constraint.GetTag().GetGroup(), - tag.c_str(), constraint.GetTag().GetElement()); - - if (constraint.IsMandatory()) - { - heading += "INNER JOIN " + table + std::string(on); - } - else - { - heading += "LEFT JOIN " + table + std::string(on); + if (constraint.IsCaseSensitive()) + { + comparison = tag + ".value " + op + " ?"; + } + else + { + comparison = "lower(" + tag + ".value) " + op + " lower(?)"; + } + + break; } - trailer += "AND ("; - - if (!constraint.IsMandatory()) - { - trailer += tag + ".value IS NULL OR "; - } + case ConstraintType_List: + for (std::set<std::string>::const_iterator + it = constraint.GetValues().begin(); + it != constraint.GetValues().end(); ++it) + { + parameters.push_back(*it); - if (constraint.IsCaseSensitive()) - { - trailer += tag + ".value "; - } - else - { - trailer += "lower(" + tag + ".value) "; - } - - switch (constraint.GetType()) - { - case ConstraintType_Equal: - parameters.push_back(constraint.GetValue()); + if (!comparison.empty()) + { + comparison += ", "; + } if (constraint.IsCaseSensitive()) { - trailer += "= ?"; + comparison += "?"; } else { - trailer += "= lower(?)"; + comparison += "lower(?)"; } + } - break; + if (constraint.IsCaseSensitive()) + { + comparison = tag + ".value IN (" + comparison + ")"; + } + else + { + comparison = "lower(" + tag + ".value) IN (" + comparison + ")"; + } + + break; - default: - throw OrthancException(ErrorCode_NotImplemented); - } + //case ConstraintType_Wildcard: + //break; + + default: + continue; + } + + heading += std::string(on); - trailer += ") "; + trailer += "AND ("; + + if (!constraint.IsMandatory()) + { + trailer += tag + ".value IS NULL OR "; } + + trailer += comparison + ") "; } if (limit != 0) @@ -1409,26 +1341,41 @@ trailer += " LIMIT " + boost::lexical_cast<std::string>(limit); } - std::string sql = (heading + "WHERE patient.resourceType = " + - boost::lexical_cast<std::string>(ResourceType_Patient) + " " + trailer); + { + std::string sql = (heading + "WHERE patient.resourceType = " + + boost::lexical_cast<std::string>(ResourceType_Patient) + " " + trailer); - SQLite::Statement s(db_, sql); + printf("[%s]\n", sql.c_str()); + + SQLite::Statement s(db_, sql); - printf("[%s]\n", sql.c_str()); + for (size_t i = 0; i < parameters.size(); i++) + { + printf(" %lu = '%s'\n", i, parameters[i].c_str()); + s.BindString(i, parameters[i]); + } - for (size_t i = 0; i < parameters.size(); i++) - { - printf(" %d = '%s'\n", i, parameters[i].c_str()); - s.BindString(i, parameters[i]); + s.Run(); } - patientsId.clear(); + { + SQLite::Statement s + (db_, "SELECT patient.publicId, instances.publicID FROM Lookup AS patient " + "INNER JOIN Resources studies ON patient.internalId=studies.parentId " + "INNER JOIN Resources series ON studies.internalId=series.parentId " + "INNER JOIN Resources instances ON series.internalId=instances.parentId " + "GROUP BY patient.publicId"); + + patientsId.clear(); - while (s.Step()) - { - std::string publicId = s.ColumnString(0); - patientsId.push_back(publicId); - printf("** [%s]\n", publicId.c_str()); + while (s.Step()) + { + const std::string patient = s.ColumnString(0); + const std::string instance = s.ColumnString(1); + patientsId.push_back(patient); + instancesId.push_back(instance); + printf("** [%s] [%s]\n", patient.c_str(), instance.c_str()); + } } throw OrthancException(ErrorCode_NotImplemented); @@ -1436,6 +1383,7 @@ void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId, + std::vector<std::string>& instancesId, const DatabaseLookup& lookup, ResourceType queryLevel, size_t limit)