Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
3025:039a9d262d64 | 3027:fd587cf51a89 |
---|---|
337 db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); | 337 db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); |
338 db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); | 338 db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); |
339 db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); | 339 db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); |
340 //db_.Execute("PRAGMA TEMP_STORE=memory"); | 340 //db_.Execute("PRAGMA TEMP_STORE=memory"); |
341 | 341 |
342 // Make "LIKE" case-sensitive in SQLite | |
343 db_.Execute("PRAGMA case_sensitive_like = true;"); | |
344 | |
342 if (!db_.DoesTableExist("GlobalProperties")) | 345 if (!db_.DoesTableExist("GlobalProperties")) |
343 { | 346 { |
344 LOG(INFO) << "Creating the database"; | 347 LOG(INFO) << "Creating the database"; |
345 std::string query; | 348 std::string query; |
346 EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE); | 349 EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE); |
1201 { | 1204 { |
1202 return GetTotalCompressedSize() > threshold; | 1205 return GetTotalCompressedSize() > threshold; |
1203 } | 1206 } |
1204 | 1207 |
1205 | 1208 |
1206 namespace | 1209 void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId, |
1207 { | 1210 std::vector<std::string>& instancesId, |
1208 class MainDicomTagsRegistry : public boost::noncopyable | 1211 const DatabaseLookup& lookup, |
1209 { | 1212 size_t limit) |
1210 private: | 1213 { |
1211 class TagInfo | 1214 printf("ICI 1\n"); |
1212 { | 1215 |
1213 private: | 1216 { |
1214 ResourceType level_; | 1217 SQLite::Statement s(db_, "DROP TABLE IF EXISTS Lookup"); |
1215 DicomTagType type_; | 1218 s.Run(); |
1216 | 1219 } |
1217 public: | 1220 |
1218 TagInfo() | 1221 std::string heading = "CREATE TEMPORARY TABLE Lookup AS SELECT patient.publicId, patient.internalId FROM Resources AS patient "; |
1222 std::string trailer; | |
1223 std::vector<std::string> parameters; | |
1224 | |
1225 for (size_t i = 0; i < lookup.GetConstraintsCount(); i++) | |
1226 { | |
1227 const DicomTagConstraint& constraint = lookup.GetConstraint(i); | |
1228 | |
1229 if (constraint.GetTagType() != DicomTagType_Identifier && | |
1230 constraint.GetTagType() != DicomTagType_Main) | |
1231 { | |
1232 // This should have been set by ServerIndex::NormalizeLookup()" | |
1233 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1234 } | |
1235 | |
1236 std::string tag = "t" + boost::lexical_cast<std::string>(i); | |
1237 | |
1238 char on[128]; | |
1239 sprintf( | |
1240 on, "%s JOIN %s %s ON %s.id = patient.internalId AND %s.tagGroup = 0x%04x AND %s.tagElement = 0x%04x ", | |
1241 constraint.IsMandatory() ? "INNER" : "LEFT", | |
1242 constraint.GetTagType() == DicomTagType_Identifier ? "DicomIdentifiers" : "MainDicomTags", | |
1243 tag.c_str(), tag.c_str(), tag.c_str(), constraint.GetTag().GetGroup(), | |
1244 tag.c_str(), constraint.GetTag().GetElement()); | |
1245 | |
1246 std::string comparison; | |
1247 | |
1248 switch (constraint.GetConstraintType()) | |
1249 { | |
1250 case ConstraintType_Equal: | |
1251 case ConstraintType_SmallerOrEqual: | |
1252 case ConstraintType_GreaterOrEqual: | |
1219 { | 1253 { |
1220 } | 1254 std::string op; |
1221 | 1255 switch (constraint.GetConstraintType()) |
1222 TagInfo(ResourceType level, | |
1223 DicomTagType type) : | |
1224 level_(level), | |
1225 type_(type) | |
1226 { | |
1227 } | |
1228 | |
1229 ResourceType GetLevel() const | |
1230 { | |
1231 return level_; | |
1232 } | |
1233 | |
1234 DicomTagType GetType() const | |
1235 { | |
1236 return type_; | |
1237 } | |
1238 }; | |
1239 | |
1240 typedef std::map<DicomTag, TagInfo> Registry; | |
1241 | |
1242 | |
1243 Registry registry_; | |
1244 | |
1245 void LoadTags(ResourceType level) | |
1246 { | |
1247 const DicomTag* tags = NULL; | |
1248 size_t size; | |
1249 | |
1250 ServerToolbox::LoadIdentifiers(tags, size, level); | |
1251 | |
1252 for (size_t i = 0; i < size; i++) | |
1253 { | |
1254 if (registry_.find(tags[i]) == registry_.end()) | |
1255 { | 1256 { |
1256 registry_[tags[i]] = TagInfo(level, DicomTagType_Identifier); | 1257 case ConstraintType_Equal: |
1258 op = "="; | |
1259 break; | |
1260 | |
1261 case ConstraintType_SmallerOrEqual: | |
1262 op = "<="; | |
1263 break; | |
1264 | |
1265 case ConstraintType_GreaterOrEqual: | |
1266 op = ">="; | |
1267 break; | |
1268 | |
1269 default: | |
1270 throw OrthancException(ErrorCode_InternalError); | |
1271 } | |
1272 | |
1273 parameters.push_back(constraint.GetValue()); | |
1274 | |
1275 if (constraint.IsCaseSensitive()) | |
1276 { | |
1277 comparison = tag + ".value " + op + " ?"; | |
1257 } | 1278 } |
1258 else | 1279 else |
1259 { | 1280 { |
1260 // These patient-level tags are copied in the study level | 1281 comparison = "lower(" + tag + ".value) " + op + " lower(?)"; |
1261 assert(level == ResourceType_Study && | |
1262 (tags[i] == DICOM_TAG_PATIENT_ID || | |
1263 tags[i] == DICOM_TAG_PATIENT_NAME || | |
1264 tags[i] == DICOM_TAG_PATIENT_BIRTH_DATE)); | |
1265 } | 1282 } |
1283 | |
1284 break; | |
1266 } | 1285 } |
1267 | 1286 |
1268 DicomMap::LoadMainDicomTags(tags, size, level); | 1287 case ConstraintType_List: |
1269 | 1288 for (std::set<std::string>::const_iterator |
1270 for (size_t i = 0; i < size; i++) | 1289 it = constraint.GetValues().begin(); |
1271 { | 1290 it != constraint.GetValues().end(); ++it) |
1272 if (registry_.find(tags[i]) == registry_.end()) | |
1273 { | 1291 { |
1274 registry_[tags[i]] = TagInfo(level, DicomTagType_Main); | 1292 parameters.push_back(*it); |
1275 } | 1293 |
1276 } | 1294 if (!comparison.empty()) |
1277 } | 1295 { |
1278 | 1296 comparison += ", "; |
1279 public: | 1297 } |
1280 MainDicomTagsRegistry() | |
1281 { | |
1282 LoadTags(ResourceType_Patient); | |
1283 LoadTags(ResourceType_Study); | |
1284 LoadTags(ResourceType_Series); | |
1285 LoadTags(ResourceType_Instance); | |
1286 } | |
1287 | |
1288 void LookupTag(ResourceType& level, | |
1289 DicomTagType& type, | |
1290 const DicomTag& tag) const | |
1291 { | |
1292 Registry::const_iterator it = registry_.find(tag); | |
1293 | |
1294 if (it == registry_.end()) | |
1295 { | |
1296 // Default values | |
1297 level = ResourceType_Instance; | |
1298 type = DicomTagType_Generic; | |
1299 } | |
1300 else | |
1301 { | |
1302 level = it->second.GetLevel(); | |
1303 type = it->second.GetType(); | |
1304 } | |
1305 } | |
1306 }; | |
1307 } | |
1308 | |
1309 | |
1310 void SQLiteDatabaseWrapper::FindOneChildInstance(std::vector<std::string>& instancesId, | |
1311 const std::vector<std::string>& resourcesId, | |
1312 ResourceType level) | |
1313 { | |
1314 printf("ICI 3\n"); | |
1315 | |
1316 throw OrthancException(ErrorCode_NotImplemented); | |
1317 } | |
1318 | |
1319 | |
1320 void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId, | |
1321 const DatabaseLookup& lookup, | |
1322 size_t limit) | |
1323 { | |
1324 static const MainDicomTagsRegistry registry; | |
1325 | |
1326 printf("ICI 1\n"); | |
1327 | |
1328 std::string heading = "SELECT patient.publicId FROM Resources AS patient "; | |
1329 std::string trailer; | |
1330 std::vector<std::string> parameters; | |
1331 | |
1332 for (size_t i = 0; i < lookup.GetConstraintsCount(); i++) | |
1333 { | |
1334 const DicomTagConstraint& constraint = lookup.GetConstraint(i); | |
1335 | |
1336 ResourceType level; | |
1337 DicomTagType type; | |
1338 registry.LookupTag(level, type, constraint.GetTag()); | |
1339 | |
1340 if (level != ResourceType_Patient) | |
1341 { | |
1342 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
1343 "Not a patient-level tag: (" + | |
1344 lookup.GetConstraint(i).GetTag().Format() + ")"); | |
1345 } | |
1346 | |
1347 if (type == DicomTagType_Identifier || | |
1348 type == DicomTagType_Main) | |
1349 { | |
1350 std::string table = (type == DicomTagType_Identifier ? "DicomIdentifiers" : "MainDicomTags"); | |
1351 std::string tag = "t" + boost::lexical_cast<std::string>(i); | |
1352 | |
1353 char on[128]; | |
1354 sprintf(on, " %s ON %s.id = patient.internalId AND %s.tagGroup = 0x%04x AND %s.tagElement = 0x%04x ", | |
1355 tag.c_str(), tag.c_str(), tag.c_str(), constraint.GetTag().GetGroup(), | |
1356 tag.c_str(), constraint.GetTag().GetElement()); | |
1357 | |
1358 if (constraint.IsMandatory()) | |
1359 { | |
1360 heading += "INNER JOIN " + table + std::string(on); | |
1361 } | |
1362 else | |
1363 { | |
1364 heading += "LEFT JOIN " + table + std::string(on); | |
1365 } | |
1366 | |
1367 trailer += "AND ("; | |
1368 | |
1369 if (!constraint.IsMandatory()) | |
1370 { | |
1371 trailer += tag + ".value IS NULL OR "; | |
1372 } | |
1373 | |
1374 if (constraint.IsCaseSensitive()) | |
1375 { | |
1376 trailer += tag + ".value "; | |
1377 } | |
1378 else | |
1379 { | |
1380 trailer += "lower(" + tag + ".value) "; | |
1381 } | |
1382 | |
1383 switch (constraint.GetType()) | |
1384 { | |
1385 case ConstraintType_Equal: | |
1386 parameters.push_back(constraint.GetValue()); | |
1387 | 1298 |
1388 if (constraint.IsCaseSensitive()) | 1299 if (constraint.IsCaseSensitive()) |
1389 { | 1300 { |
1390 trailer += "= ?"; | 1301 comparison += "?"; |
1391 } | 1302 } |
1392 else | 1303 else |
1393 { | 1304 { |
1394 trailer += "= lower(?)"; | 1305 comparison += "lower(?)"; |
1395 } | 1306 } |
1396 | 1307 } |
1397 break; | 1308 |
1398 | 1309 if (constraint.IsCaseSensitive()) |
1399 default: | 1310 { |
1400 throw OrthancException(ErrorCode_NotImplemented); | 1311 comparison = tag + ".value IN (" + comparison + ")"; |
1401 } | 1312 } |
1402 | 1313 else |
1403 trailer += ") "; | 1314 { |
1404 } | 1315 comparison = "lower(" + tag + ".value) IN (" + comparison + ")"; |
1316 } | |
1317 | |
1318 break; | |
1319 | |
1320 //case ConstraintType_Wildcard: | |
1321 //break; | |
1322 | |
1323 default: | |
1324 continue; | |
1325 } | |
1326 | |
1327 heading += std::string(on); | |
1328 | |
1329 trailer += "AND ("; | |
1330 | |
1331 if (!constraint.IsMandatory()) | |
1332 { | |
1333 trailer += tag + ".value IS NULL OR "; | |
1334 } | |
1335 | |
1336 trailer += comparison + ") "; | |
1405 } | 1337 } |
1406 | 1338 |
1407 if (limit != 0) | 1339 if (limit != 0) |
1408 { | 1340 { |
1409 trailer += " LIMIT " + boost::lexical_cast<std::string>(limit); | 1341 trailer += " LIMIT " + boost::lexical_cast<std::string>(limit); |
1410 } | 1342 } |
1411 | 1343 |
1412 std::string sql = (heading + "WHERE patient.resourceType = " + | 1344 { |
1413 boost::lexical_cast<std::string>(ResourceType_Patient) + " " + trailer); | 1345 std::string sql = (heading + "WHERE patient.resourceType = " + |
1414 | 1346 boost::lexical_cast<std::string>(ResourceType_Patient) + " " + trailer); |
1415 SQLite::Statement s(db_, sql); | 1347 |
1416 | 1348 printf("[%s]\n", sql.c_str()); |
1417 printf("[%s]\n", sql.c_str()); | 1349 |
1418 | 1350 SQLite::Statement s(db_, sql); |
1419 for (size_t i = 0; i < parameters.size(); i++) | 1351 |
1420 { | 1352 for (size_t i = 0; i < parameters.size(); i++) |
1421 printf(" %d = '%s'\n", i, parameters[i].c_str()); | 1353 { |
1422 s.BindString(i, parameters[i]); | 1354 printf(" %lu = '%s'\n", i, parameters[i].c_str()); |
1423 } | 1355 s.BindString(i, parameters[i]); |
1424 | 1356 } |
1425 patientsId.clear(); | 1357 |
1426 | 1358 s.Run(); |
1427 while (s.Step()) | 1359 } |
1428 { | 1360 |
1429 std::string publicId = s.ColumnString(0); | 1361 { |
1430 patientsId.push_back(publicId); | 1362 SQLite::Statement s |
1431 printf("** [%s]\n", publicId.c_str()); | 1363 (db_, "SELECT patient.publicId, instances.publicID FROM Lookup AS patient " |
1364 "INNER JOIN Resources studies ON patient.internalId=studies.parentId " | |
1365 "INNER JOIN Resources series ON studies.internalId=series.parentId " | |
1366 "INNER JOIN Resources instances ON series.internalId=instances.parentId " | |
1367 "GROUP BY patient.publicId"); | |
1368 | |
1369 patientsId.clear(); | |
1370 | |
1371 while (s.Step()) | |
1372 { | |
1373 const std::string patient = s.ColumnString(0); | |
1374 const std::string instance = s.ColumnString(1); | |
1375 patientsId.push_back(patient); | |
1376 instancesId.push_back(instance); | |
1377 printf("** [%s] [%s]\n", patient.c_str(), instance.c_str()); | |
1378 } | |
1432 } | 1379 } |
1433 | 1380 |
1434 throw OrthancException(ErrorCode_NotImplemented); | 1381 throw OrthancException(ErrorCode_NotImplemented); |
1435 } | 1382 } |
1436 | 1383 |
1437 | 1384 |
1438 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId, | 1385 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId, |
1386 std::vector<std::string>& instancesId, | |
1439 const DatabaseLookup& lookup, | 1387 const DatabaseLookup& lookup, |
1440 ResourceType queryLevel, | 1388 ResourceType queryLevel, |
1441 size_t limit) | 1389 size_t limit) |
1442 { | 1390 { |
1443 printf("ICI 2\n"); | 1391 printf("ICI 2\n"); |