comparison OrthancServer/SQLiteDatabaseWrapper.cpp @ 3030:25afa7b8cb51 db-changes

SQLiteDatabaseWrapper::ApplyLookupResources()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 19 Dec 2018 11:18:39 +0100
parents ea653ec47f31
children 18a2d196414b
comparison
equal deleted inserted replaced
3029:ea653ec47f31 3030:25afa7b8cb51
1204 { 1204 {
1205 return GetTotalCompressedSize() > threshold; 1205 return GetTotalCompressedSize() > threshold;
1206 } 1206 }
1207 1207
1208 1208
1209 static std::string FormatLevel(ResourceType level)
1210 {
1211 switch (level)
1212 {
1213 case ResourceType_Patient:
1214 return "patients";
1215
1216 case ResourceType_Study:
1217 return "studies";
1218
1219 case ResourceType_Series:
1220 return "series";
1221
1222 case ResourceType_Instance:
1223 return "instances";
1224
1225 default:
1226 throw OrthancException(ErrorCode_InternalError);
1227 }
1228 }
1229
1230
1209 static void FormatJoin(std::string& target, 1231 static void FormatJoin(std::string& target,
1210 const DatabaseConstraint& constraint, 1232 const DatabaseConstraint& constraint,
1211 size_t index) 1233 size_t index)
1212 { 1234 {
1213 std::string tag = "t" + boost::lexical_cast<std::string>(index); 1235 std::string tag = "t" + boost::lexical_cast<std::string>(index);
1228 else 1250 else
1229 { 1251 {
1230 target += "MainDicomTags "; 1252 target += "MainDicomTags ";
1231 } 1253 }
1232 1254
1233 target += tag + " ON " + tag + ".id = "; 1255 target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) +
1234 1256 ".internalId AND " + tag + ".tagGroup = " +
1235 switch (constraint.GetLevel())
1236 {
1237 case ResourceType_Patient:
1238 target += "patient";
1239 break;
1240
1241 case ResourceType_Study:
1242 target += "study";
1243 break;
1244
1245 case ResourceType_Series:
1246 target += "series";
1247 break;
1248
1249 case ResourceType_Instance:
1250 target += "instance";
1251 break;
1252
1253 default:
1254 throw OrthancException(ErrorCode_InternalError);
1255 }
1256
1257 target += (".internalId AND " + tag + ".tagGroup = " +
1258 boost::lexical_cast<std::string>(constraint.GetTag().GetGroup()) + 1257 boost::lexical_cast<std::string>(constraint.GetTag().GetGroup()) +
1259 " AND " + tag + ".tagElement = " + 1258 " AND " + tag + ".tagElement = " +
1260 boost::lexical_cast<std::string>(constraint.GetTag().GetElement())); 1259 boost::lexical_cast<std::string>(constraint.GetTag().GetElement()));
1261 } 1260 }
1262 1261
1389 1388
1390 break; 1389 break;
1391 } 1390 }
1392 1391
1393 default: 1392 default:
1394 // Don't modify "parameters"! 1393 // Don't modify "parameters" in this case!
1395 return false; 1394 return false;
1396 } 1395 }
1397 1396
1398 if (constraint.IsMandatory()) 1397 if (constraint.IsMandatory())
1399 { 1398 {
1404 target += tag + ".value IS NULL OR " + comparison; 1403 target += tag + ".value IS NULL OR " + comparison;
1405 } 1404 }
1406 1405
1407 return true; 1406 return true;
1408 } 1407 }
1408
1409
1410 static void PrepareLookup(SQLite::Connection& db)
1411 {
1412 SQLite::Statement s(db, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup");
1413 s.Run();
1414 }
1415
1416
1417 static void AnswerLookup(std::vector<std::string>& resourcesId,
1418 std::vector<std::string>& instancesId,
1419 SQLite::Connection& db,
1420 ResourceType level)
1421 {
1422 resourcesId.clear();
1423 instancesId.clear();
1424
1425 std::auto_ptr<SQLite::Statement> statement;
1426
1427 switch (level)
1428 {
1429 case ResourceType_Patient:
1430 {
1431 statement.reset(
1432 new SQLite::Statement(
1433 db, SQLITE_FROM_HERE,
1434 "SELECT patients.publicId, instances.publicID FROM Lookup AS patients "
1435 "INNER JOIN Resources studies ON patients.internalId=studies.parentId "
1436 "INNER JOIN Resources series ON studies.internalId=series.parentId "
1437 "INNER JOIN Resources instances ON series.internalId=instances.parentId "
1438 "GROUP BY patients.publicId"));
1439
1440 break;
1441 }
1442
1443 case ResourceType_Study:
1444 {
1445 statement.reset(
1446 new SQLite::Statement(
1447 db, SQLITE_FROM_HERE,
1448 "SELECT studies.publicId, instances.publicID FROM Lookup AS studies "
1449 "INNER JOIN Resources series ON studies.internalId=series.parentId "
1450 "INNER JOIN Resources instances ON series.internalId=instances.parentId "
1451 "GROUP BY studies.publicId"));
1452
1453 break;
1454 }
1455
1456 case ResourceType_Series:
1457 {
1458 statement.reset(
1459 new SQLite::Statement(
1460 db, SQLITE_FROM_HERE,
1461 "SELECT series.publicId, instances.publicID FROM Lookup AS series "
1462 "INNER JOIN Resources instances ON series.internalId=instances.parentId "
1463 "GROUP BY series.publicId"));
1464
1465 break;
1466 }
1467
1468 case ResourceType_Instance:
1469 {
1470 statement.reset(
1471 new SQLite::Statement(
1472 db, SQLITE_FROM_HERE, "SELECT publicId, publicId FROM Lookup"));
1473
1474 break;
1475 }
1476
1477 default:
1478 throw OrthancException(ErrorCode_InternalError);
1479 }
1480
1481 assert(statement.get() != NULL);
1482
1483 while (statement->Step())
1484 {
1485 resourcesId.push_back(statement->ColumnString(0));
1486 instancesId.push_back(statement->ColumnString(1));
1487 }
1488 }
1489
1490
1491 static void FormatConstraints(std::string& joins,
1492 std::string& comparisons,
1493 std::vector<std::string>& parameters,
1494 const std::vector<DatabaseConstraint>& lookup)
1495 {
1496 size_t count = 0;
1497
1498 for (size_t i = 0; i < lookup.size(); i++)
1499 {
1500 std::string comparison;
1501
1502 if (FormatComparison(comparison, lookup[i], count, parameters))
1503 {
1504 std::string join;
1505 FormatJoin(join, lookup[i], count);
1506 joins += join;
1507
1508 comparisons += " AND (" + comparison + ")";
1509
1510 count ++;
1511 }
1512 }
1513 }
1514
1409 1515
1410 1516
1411 void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId, 1517 void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId,
1412 std::vector<std::string>& instancesId, 1518 std::vector<std::string>& instancesId,
1413 const std::vector<DatabaseConstraint>& lookup, 1519 const std::vector<DatabaseConstraint>& lookup,
1414 size_t limit) 1520 size_t limit)
1415 { 1521 {
1416 printf("ICI 1\n"); 1522 PrepareLookup(db_);
1417
1418 {
1419 SQLite::Statement s(db_, "DROP TABLE IF EXISTS Lookup");
1420 s.Run();
1421 }
1422 1523
1423 std::string joins, comparisons; 1524 std::string joins, comparisons;
1424 std::vector<std::string> parameters; 1525 std::vector<std::string> parameters;
1425 1526 FormatConstraints(joins, comparisons, parameters, lookup);
1426 size_t count = 0;
1427
1428 for (size_t i = 0; i < lookup.size(); i++)
1429 {
1430 std::string comparison;
1431
1432 if (FormatComparison(comparison, lookup[i], count, parameters))
1433 {
1434 std::string join;
1435 FormatJoin(join, lookup[i], count);
1436 joins += join;
1437
1438 comparisons += " AND (" + comparison + ")";
1439
1440 count ++;
1441 }
1442 }
1443 1527
1444 { 1528 {
1445 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS " 1529 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS "
1446 "SELECT patient.publicId, patient.internalId FROM Resources AS patient" + 1530 "SELECT patients.publicId, patients.internalId FROM Resources AS patients" +
1447 joins + " WHERE patient.resourceType = " + 1531 joins + " WHERE patients.resourceType = " +
1448 boost::lexical_cast<std::string>(ResourceType_Patient) + comparisons); 1532 boost::lexical_cast<std::string>(ResourceType_Patient) + comparisons);
1449 1533
1450 if (limit != 0) 1534 if (limit != 0)
1451 { 1535 {
1452 sql += " LIMIT " + boost::lexical_cast<std::string>(limit); 1536 sql += " LIMIT " + boost::lexical_cast<std::string>(limit);
1456 1540
1457 SQLite::Statement s(db_, sql); 1541 SQLite::Statement s(db_, sql);
1458 1542
1459 for (size_t i = 0; i < parameters.size(); i++) 1543 for (size_t i = 0; i < parameters.size(); i++)
1460 { 1544 {
1461 printf(" %lu = '%s'\n", i, parameters[i].c_str());
1462 s.BindString(i, parameters[i]); 1545 s.BindString(i, parameters[i]);
1463 } 1546 }
1464 1547
1465 s.Run(); 1548 s.Run();
1466 } 1549 }
1467 1550
1468 { 1551 AnswerLookup(patientsId, instancesId, db_, ResourceType_Patient);
1469 SQLite::Statement s 1552 }
1470 (db_, "SELECT patient.publicId, instances.publicID FROM Lookup AS patient " 1553
1471 "INNER JOIN Resources studies ON patient.internalId=studies.parentId "
1472 "INNER JOIN Resources series ON studies.internalId=series.parentId "
1473 "INNER JOIN Resources instances ON series.internalId=instances.parentId "
1474 "GROUP BY patient.publicId");
1475
1476 patientsId.clear();
1477
1478 while (s.Step())
1479 {
1480 const std::string patient = s.ColumnString(0);
1481 const std::string instance = s.ColumnString(1);
1482 patientsId.push_back(patient);
1483 instancesId.push_back(instance);
1484 printf("** [%s] [%s]\n", patient.c_str(), instance.c_str());
1485 }
1486 }
1487 }
1488
1489 1554
1490 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId, 1555 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId,
1491 std::vector<std::string>& instancesId, 1556 std::vector<std::string>& instancesId,
1492 const std::vector<DatabaseConstraint>& lookup, 1557 const std::vector<DatabaseConstraint>& lookup,
1493 ResourceType queryLevel, 1558 ResourceType queryLevel,
1494 size_t limit) 1559 size_t limit)
1495 { 1560 {
1561 assert(ResourceType_Patient < ResourceType_Study &&
1562 ResourceType_Study < ResourceType_Series &&
1563 ResourceType_Series < ResourceType_Instance);
1564
1496 ResourceType upperLevel = queryLevel; 1565 ResourceType upperLevel = queryLevel;
1497 ResourceType lowerLevel = queryLevel; 1566 ResourceType lowerLevel = queryLevel;
1498 1567
1499 for (size_t i = 0; i < lookup.size(); i++) 1568 for (size_t i = 0; i < lookup.size(); i++)
1500 { 1569 {
1501 if (!IsResourceLevelAboveOrEqual(upperLevel, lookup[i].GetLevel())) 1570 ResourceType level = lookup[i].GetLevel();
1502 { 1571
1503 upperLevel = lookup[i].GetLevel(); 1572 if (level < upperLevel)
1504 } 1573 {
1505 1574 upperLevel = level;
1506 if (!IsResourceLevelAboveOrEqual(lookup[i].GetLevel(), lowerLevel)) 1575 }
1507 { 1576
1508 lowerLevel = lookup[i].GetLevel(); 1577 if (level > lowerLevel)
1578 {
1579 lowerLevel = level;
1509 } 1580 }
1510 } 1581 }
1511 1582
1512 printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel)); 1583 printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel));
1513 1584
1514 throw OrthancException(ErrorCode_NotImplemented); 1585 PrepareLookup(db_);
1586
1587 std::string joins, comparisons;
1588 std::vector<std::string> parameters;
1589 FormatConstraints(joins, comparisons, parameters, lookup);
1590
1591 {
1592 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS SELECT " +
1593 FormatLevel(queryLevel) + ".publicId, " +
1594 FormatLevel(queryLevel) + ".internalId" +
1595 " FROM Resources AS " + FormatLevel(queryLevel));
1596
1597 for (int level = queryLevel - 1; level >= upperLevel; level--)
1598 {
1599 sql += (" INNER JOIN Resources " +
1600 FormatLevel(static_cast<ResourceType>(level)) + " ON " +
1601 FormatLevel(static_cast<ResourceType>(level)) + ".internalId=" +
1602 FormatLevel(static_cast<ResourceType>(level + 1)) + ".parentId");
1603 }
1604
1605 for (int level = queryLevel + 1; level <= lowerLevel; level++)
1606 {
1607 sql += (" INNER JOIN Resources " +
1608 FormatLevel(static_cast<ResourceType>(level - 1)) + " ON " +
1609 FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" +
1610 FormatLevel(static_cast<ResourceType>(level)) + ".parentId");
1611 }
1612
1613 sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " +
1614 boost::lexical_cast<std::string>(queryLevel) + comparisons);
1615
1616 if (limit != 0)
1617 {
1618 sql += " LIMIT " + boost::lexical_cast<std::string>(limit);
1619 }
1620
1621 printf("[%s]\n", sql.c_str());
1622
1623 SQLite::Statement s(db_, sql);
1624
1625 for (size_t i = 0; i < parameters.size(); i++)
1626 {
1627 printf(" %lu = '%s'\n", i, parameters[i].c_str());
1628 s.BindString(i, parameters[i]);
1629 }
1630
1631 s.Run();
1632 }
1633
1634 AnswerLookup(resourcesId, instancesId, db_, queryLevel);
1515 } 1635 }
1516 } 1636 }