comparison OrthancServer/SQLiteDatabaseWrapper.cpp @ 3031:18a2d196414b db-changes

simplification
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 19 Dec 2018 13:08:04 +0100
parents 25afa7b8cb51
children 5da6d1063d8f
comparison
equal deleted inserted replaced
3030:25afa7b8cb51 3031:18a2d196414b
1226 throw OrthancException(ErrorCode_InternalError); 1226 throw OrthancException(ErrorCode_InternalError);
1227 } 1227 }
1228 } 1228 }
1229 1229
1230 1230
1231 static void FormatJoin(std::string& target,
1232 const DatabaseConstraint& constraint,
1233 size_t index)
1234 {
1235 std::string tag = "t" + boost::lexical_cast<std::string>(index);
1236
1237 if (constraint.IsMandatory())
1238 {
1239 target = " INNER JOIN ";
1240 }
1241 else
1242 {
1243 target = " LEFT JOIN ";
1244 }
1245
1246 if (constraint.IsIdentifier())
1247 {
1248 target += "DicomIdentifiers ";
1249 }
1250 else
1251 {
1252 target += "MainDicomTags ";
1253 }
1254
1255 target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) +
1256 ".internalId AND " + tag + ".tagGroup = " +
1257 boost::lexical_cast<std::string>(constraint.GetTag().GetGroup()) +
1258 " AND " + tag + ".tagElement = " +
1259 boost::lexical_cast<std::string>(constraint.GetTag().GetElement()));
1260 }
1261
1262
1263 static bool FormatComparison(std::string& target, 1231 static bool FormatComparison(std::string& target,
1264 const DatabaseConstraint& constraint, 1232 const DatabaseConstraint& constraint,
1265 size_t index, 1233 size_t index,
1266 std::vector<std::string>& parameters) 1234 std::vector<std::string>& parameters)
1267 { 1235 {
1342 } 1310 }
1343 1311
1344 case ConstraintType_Wildcard: 1312 case ConstraintType_Wildcard:
1345 { 1313 {
1346 const std::string value = constraint.GetSingleValue(); 1314 const std::string value = constraint.GetSingleValue();
1347 std::string escaped; 1315
1348 escaped.reserve(value.size()); 1316 if (value == "*")
1349
1350 for (size_t i = 0; i < value.size(); i++)
1351 { 1317 {
1352 if (value[i] == '*') 1318 if (!constraint.IsMandatory())
1353 { 1319 {
1354 escaped += "%"; 1320 // Universal constraint on an optional tag, ignore it
1321 return false;
1355 } 1322 }
1356 else if (value[i] == '?') 1323 }
1324 else
1325 {
1326 std::string escaped;
1327 escaped.reserve(value.size());
1328
1329 for (size_t i = 0; i < value.size(); i++)
1357 { 1330 {
1358 escaped += "_"; 1331 if (value[i] == '*')
1332 {
1333 escaped += "%";
1334 }
1335 else if (value[i] == '?')
1336 {
1337 escaped += "_";
1338 }
1339 else if (value[i] == '%')
1340 {
1341 escaped += "\\%";
1342 }
1343 else if (value[i] == '_')
1344 {
1345 escaped += "\\_";
1346 }
1347 else if (value[i] == '\\')
1348 {
1349 escaped += "\\\\";
1350 }
1351 else
1352 {
1353 escaped += value[i];
1354 }
1359 } 1355 }
1360 else if (value[i] == '%') 1356
1357 parameters.push_back(escaped);
1358
1359 if (constraint.IsCaseSensitive())
1361 { 1360 {
1362 escaped += "\\%"; 1361 comparison = tag + ".value LIKE ? ESCAPE '\\'";
1363 }
1364 else if (value[i] == '_')
1365 {
1366 escaped += "\\_";
1367 }
1368 else if (value[i] == '\\')
1369 {
1370 escaped += "\\\\";
1371 } 1362 }
1372 else 1363 else
1373 { 1364 {
1374 escaped += value[i]; 1365 comparison = "lower(" + tag + ".value) LIKE lower(?) ESCAPE '\\'";
1375 } 1366 }
1376 }
1377
1378 parameters.push_back(escaped);
1379
1380 if (constraint.IsCaseSensitive())
1381 {
1382 comparison = tag + ".value LIKE ? ESCAPE '\\'";
1383 }
1384 else
1385 {
1386 comparison = "lower(" + tag + ".value) LIKE lower(?) ESCAPE '\\'";
1387 } 1367 }
1388 1368
1389 break; 1369 break;
1390 } 1370 }
1391 1371
1394 return false; 1374 return false;
1395 } 1375 }
1396 1376
1397 if (constraint.IsMandatory()) 1377 if (constraint.IsMandatory())
1398 { 1378 {
1399 target += comparison; 1379 target = comparison;
1380 }
1381 else if (comparison.empty())
1382 {
1383 target = tag + ".value IS NULL";
1400 } 1384 }
1401 else 1385 else
1402 { 1386 {
1403 target += tag + ".value IS NULL OR " + comparison; 1387 target = tag + ".value IS NULL OR " + comparison;
1404 } 1388 }
1405 1389
1406 return true; 1390 return true;
1407 } 1391 }
1408 1392
1409 1393
1410 static void PrepareLookup(SQLite::Connection& db) 1394 static void FormatJoin(std::string& target,
1411 { 1395 const DatabaseConstraint& constraint,
1412 SQLite::Statement s(db, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup"); 1396 size_t index)
1413 s.Run(); 1397 {
1414 } 1398 std::string tag = "t" + boost::lexical_cast<std::string>(index);
1415 1399
1400 if (constraint.IsMandatory())
1401 {
1402 target = " INNER JOIN ";
1403 }
1404 else
1405 {
1406 target = " LEFT JOIN ";
1407 }
1408
1409 if (constraint.IsIdentifier())
1410 {
1411 target += "DicomIdentifiers ";
1412 }
1413 else
1414 {
1415 target += "MainDicomTags ";
1416 }
1417
1418 target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) +
1419 ".internalId AND " + tag + ".tagGroup = " +
1420 boost::lexical_cast<std::string>(constraint.GetTag().GetGroup()) +
1421 " AND " + tag + ".tagElement = " +
1422 boost::lexical_cast<std::string>(constraint.GetTag().GetElement()));
1423 }
1424
1416 1425
1417 static void AnswerLookup(std::vector<std::string>& resourcesId, 1426 static void AnswerLookup(std::vector<std::string>& resourcesId,
1418 std::vector<std::string>& instancesId, 1427 std::vector<std::string>& instancesId,
1419 SQLite::Connection& db, 1428 SQLite::Connection& db,
1420 ResourceType level) 1429 ResourceType level)
1486 instancesId.push_back(statement->ColumnString(1)); 1495 instancesId.push_back(statement->ColumnString(1));
1487 } 1496 }
1488 } 1497 }
1489 1498
1490 1499
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
1515
1516
1517 void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId,
1518 std::vector<std::string>& instancesId,
1519 const std::vector<DatabaseConstraint>& lookup,
1520 size_t limit)
1521 {
1522 PrepareLookup(db_);
1523
1524 std::string joins, comparisons;
1525 std::vector<std::string> parameters;
1526 FormatConstraints(joins, comparisons, parameters, lookup);
1527
1528 {
1529 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS "
1530 "SELECT patients.publicId, patients.internalId FROM Resources AS patients" +
1531 joins + " WHERE patients.resourceType = " +
1532 boost::lexical_cast<std::string>(ResourceType_Patient) + comparisons);
1533
1534 if (limit != 0)
1535 {
1536 sql += " LIMIT " + boost::lexical_cast<std::string>(limit);
1537 }
1538
1539 printf("[%s]\n", sql.c_str());
1540
1541 SQLite::Statement s(db_, sql);
1542
1543 for (size_t i = 0; i < parameters.size(); i++)
1544 {
1545 s.BindString(i, parameters[i]);
1546 }
1547
1548 s.Run();
1549 }
1550
1551 AnswerLookup(patientsId, instancesId, db_, ResourceType_Patient);
1552 }
1553
1554
1555 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId, 1500 void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId,
1556 std::vector<std::string>& instancesId, 1501 std::vector<std::string>& instancesId,
1557 const std::vector<DatabaseConstraint>& lookup, 1502 const std::vector<DatabaseConstraint>& lookup,
1558 ResourceType queryLevel, 1503 ResourceType queryLevel,
1559 size_t limit) 1504 size_t limit)
1560 { 1505 {
1506 for (size_t i = 0; i < lookup.size(); i++)
1507 {
1508 std::cout << i << ": " << lookup[i].GetTag() << " - " << EnumerationToString(lookup[i].GetLevel());
1509 std::cout << std::endl;
1510 }
1511
1561 assert(ResourceType_Patient < ResourceType_Study && 1512 assert(ResourceType_Patient < ResourceType_Study &&
1562 ResourceType_Study < ResourceType_Series && 1513 ResourceType_Study < ResourceType_Series &&
1563 ResourceType_Series < ResourceType_Instance); 1514 ResourceType_Series < ResourceType_Instance);
1564 1515
1565 ResourceType upperLevel = queryLevel; 1516 ResourceType upperLevel = queryLevel;
1580 } 1531 }
1581 } 1532 }
1582 1533
1583 printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel)); 1534 printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel));
1584 1535
1585 PrepareLookup(db_); 1536 {
1537 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup");
1538 s.Run();
1539 }
1586 1540
1587 std::string joins, comparisons; 1541 std::string joins, comparisons;
1588 std::vector<std::string> parameters; 1542 std::vector<std::string> parameters;
1589 FormatConstraints(joins, comparisons, parameters, lookup); 1543
1544 size_t count = 0;
1545
1546 for (size_t i = 0; i < lookup.size(); i++)
1547 {
1548 std::string comparison;
1549
1550 if (FormatComparison(comparison, lookup[i], count, parameters))
1551 {
1552 std::string join;
1553 FormatJoin(join, lookup[i], count);
1554 joins += join;
1555
1556 if (!comparison.empty())
1557 {
1558 comparisons += " AND " + comparison;
1559 }
1560
1561 count ++;
1562 }
1563 }
1590 1564
1591 { 1565 {
1592 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS SELECT " + 1566 std::string sql = ("CREATE TEMPORARY TABLE Lookup AS SELECT " +
1593 FormatLevel(queryLevel) + ".publicId, " + 1567 FormatLevel(queryLevel) + ".publicId, " +
1594 FormatLevel(queryLevel) + ".internalId" + 1568 FormatLevel(queryLevel) + ".internalId" +
1603 } 1577 }
1604 1578
1605 for (int level = queryLevel + 1; level <= lowerLevel; level++) 1579 for (int level = queryLevel + 1; level <= lowerLevel; level++)
1606 { 1580 {
1607 sql += (" INNER JOIN Resources " + 1581 sql += (" INNER JOIN Resources " +
1608 FormatLevel(static_cast<ResourceType>(level - 1)) + " ON " + 1582 FormatLevel(static_cast<ResourceType>(level)) + " ON " +
1609 FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" + 1583 FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" +
1610 FormatLevel(static_cast<ResourceType>(level)) + ".parentId"); 1584 FormatLevel(static_cast<ResourceType>(level)) + ".parentId");
1611 } 1585 }
1612 1586
1613 sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " + 1587 sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " +