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");