Mercurial > hg > orthanc
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 } |