Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp @ 5796:16ce3c920f71 find-refactoring tip
rewrote SQLite find using CTEs instead of temporary tables
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Thu, 19 Sep 2024 17:50:20 +0200 |
parents | a3d283f61304 |
children |
comparison
equal
deleted
inserted
replaced
5795:9990b4140c1c | 5796:16ce3c920f71 |
---|---|
41 #include <stdio.h> | 41 #include <stdio.h> |
42 #include <boost/lexical_cast.hpp> | 42 #include <boost/lexical_cast.hpp> |
43 | 43 |
44 namespace Orthanc | 44 namespace Orthanc |
45 { | 45 { |
46 static std::string JoinRequestedMetadata(const FindRequest::ChildrenSpecification& childrenSpec) | |
47 { | |
48 std::set<std::string> metadataTypes; | |
49 for (std::set<MetadataType>::const_iterator it = childrenSpec.GetMetadata().begin(); it != childrenSpec.GetMetadata().end(); ++it) | |
50 { | |
51 metadataTypes.insert(boost::lexical_cast<std::string>(*it)); | |
52 } | |
53 std::string joinedMetadataTypes; | |
54 Orthanc::Toolbox::JoinStrings(joinedMetadataTypes, metadataTypes, ", "); | |
55 | |
56 return joinedMetadataTypes; | |
57 } | |
58 | |
59 static std::string JoinRequestedTags(const FindRequest::ChildrenSpecification& childrenSpec) | |
60 { | |
61 // note: SQLite does not seem to support (tagGroup, tagElement) in ((x, y), (z, w)) in complex subqueries. | |
62 // Therefore, since we expect the requested tag list to be short, we write it as | |
63 // ((tagGroup = x AND tagElement = y ) OR (tagGroup = z AND tagElement = w)) | |
64 | |
65 std::string sql = " ("; | |
66 std::set<std::string> tags; | |
67 for (std::set<DicomTag>::const_iterator it = childrenSpec.GetMainDicomTags().begin(); it != childrenSpec.GetMainDicomTags().end(); ++it) | |
68 { | |
69 tags.insert("(tagGroup = " + boost::lexical_cast<std::string>(it->GetGroup()) | |
70 + " AND tagElement = " + boost::lexical_cast<std::string>(it->GetElement()) + ")"); | |
71 } | |
72 std::string joinedTags; | |
73 Orthanc::Toolbox::JoinStrings(joinedTags, tags, " OR "); | |
74 | |
75 sql += joinedTags + ") "; | |
76 return sql; | |
77 } | |
78 | |
46 class SQLiteDatabaseWrapper::LookupFormatter : public ISqlLookupFormatter | 79 class SQLiteDatabaseWrapper::LookupFormatter : public ISqlLookupFormatter |
47 { | 80 { |
48 private: | 81 private: |
49 std::list<std::string> values_; | 82 std::list<std::string> values_; |
50 | 83 |
388 LookupFormatter formatter; | 421 LookupFormatter formatter; |
389 | 422 |
390 std::string sql; | 423 std::string sql; |
391 LookupFormatter::Apply(sql, formatter, lookup, queryLevel, labels, labelsConstraint, limit); | 424 LookupFormatter::Apply(sql, formatter, lookup, queryLevel, labels, labelsConstraint, limit); |
392 | 425 |
393 sql = "CREATE TEMPORARY TABLE Lookup AS " + sql; | 426 sql = "CREATE TEMPORARY TABLE Lookup AS " + sql; // TODO-FIND: use a CTE (or is this method obsolete ?) |
394 | 427 |
395 { | 428 { |
396 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup"); | 429 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup"); |
397 s.Run(); | 430 s.Run(); |
398 } | 431 } |
418 resourcesId.push_back(s.ColumnString(0)); | 451 resourcesId.push_back(s.ColumnString(0)); |
419 } | 452 } |
420 } | 453 } |
421 } | 454 } |
422 | 455 |
456 #define C0_QUERY_ID 0 | |
457 #define C1_INTERNAL_ID 1 | |
458 #define C2_ROW_NUMBER 2 | |
459 #define C3_STRING_1 3 | |
460 #define C4_STRING_2 4 | |
461 #define C5_STRING_3 5 | |
462 #define C6_INT_1 6 | |
463 #define C7_INT_2 7 | |
464 #define C8_BIG_INT_1 8 | |
465 #define C9_BIG_INT_2 9 | |
466 | |
467 #define QUERY_LOOKUP 1 | |
468 #define QUERY_MAIN_DICOM_TAGS 2 | |
469 #define QUERY_ATTACHMENTS 3 | |
470 #define QUERY_METADATA 4 | |
471 #define QUERY_LABELS 5 | |
472 #define QUERY_PARENT_MAIN_DICOM_TAGS 10 | |
473 #define QUERY_PARENT_IDENTIFIER 11 | |
474 #define QUERY_PARENT_METADATA 12 | |
475 #define QUERY_GRAND_PARENT_MAIN_DICOM_TAGS 15 | |
476 #define QUERY_GRAND_PARENT_METADATA 16 | |
477 #define QUERY_CHILDREN_IDENTIFIERS 20 | |
478 #define QUERY_CHILDREN_MAIN_DICOM_TAGS 21 | |
479 #define QUERY_CHILDREN_METADATA 22 | |
480 #define QUERY_GRAND_CHILDREN_IDENTIFIERS 30 | |
481 #define QUERY_GRAND_CHILDREN_MAIN_DICOM_TAGS 31 | |
482 #define QUERY_GRAND_CHILDREN_METADATA 32 | |
483 #define QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS 40 | |
484 #define QUERY_ONE_INSTANCE_IDENTIFIER 50 | |
485 #define QUERY_ONE_INSTANCE_METADATA 51 | |
486 #define QUERY_ONE_INSTANCE_ATTACHMENTS 52 | |
487 | |
488 #define STRINGIFY(x) #x | |
489 #define TOSTRING(x) STRINGIFY(x) | |
490 | |
491 | |
423 virtual void ExecuteFind(FindResponse& response, | 492 virtual void ExecuteFind(FindResponse& response, |
424 const FindRequest& request, | 493 const FindRequest& request, |
425 const Capabilities& capabilities) ORTHANC_OVERRIDE | 494 const Capabilities& capabilities) ORTHANC_OVERRIDE |
426 { | 495 { |
496 LookupFormatter formatter; | |
497 std::string sql; | |
427 const ResourceType requestLevel = request.GetLevel(); | 498 const ResourceType requestLevel = request.GetLevel(); |
428 std::string sql; | 499 |
429 | 500 std::string lookupSql; |
430 { | 501 LookupFormatter::Apply(lookupSql, formatter, request); |
431 // clean previous lookup table | 502 |
432 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup"); | 503 // base query, retrieve the ordered internalId and publicId of the selected resources |
433 s.Run(); | 504 sql = "WITH Lookup AS (" + lookupSql + ") "; |
434 } | 505 |
435 | 506 // in SQLite, all CTEs must be created at the beginning of the query, you can not define local CTE inside subqueries |
436 { | 507 // need one instance info ? (part 1: create the CTE) |
437 // extract the resource id of interest by executing the lookup | 508 if (request.GetLevel() != ResourceType_Instance && |
438 LookupFormatter formatter; | 509 request.IsRetrieveOneInstanceMetadataAndAttachments()) |
439 LookupFormatter::Apply(sql, formatter, request); | 510 { |
440 | 511 // Here, we create a nested CTE 'OneInstance' with one instance ID to join with metadata and main |
441 sql = "CREATE TEMPORARY TABLE Lookup AS " + sql; // TODO-FIND: use a CTE | 512 sql += ", OneInstance AS"; |
442 | 513 |
443 SQLite::Statement statement(db_, sql); | 514 switch (requestLevel) |
444 formatter.Bind(statement); | |
445 statement.Run(); | |
446 | |
447 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId, internalId FROM Lookup"); | |
448 while (s.Step()) | |
449 { | 515 { |
450 response.Add(new FindResponse::Resource(requestLevel, s.ColumnInt64(1), s.ColumnString(0))); | 516 case ResourceType_Series: |
517 { | |
518 sql+= " (SELECT Lookup.internalId AS parentInternalId, childLevel.publicId AS instancePublicId, childLevel.internalId AS instanceInternalId" | |
519 " FROM Resources AS childLevel " | |
520 " INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId) "; | |
521 break; | |
522 } | |
523 | |
524 case ResourceType_Study: | |
525 { | |
526 sql+= " (SELECT Lookup.internalId AS parentInternalId, grandChildLevel.publicId AS instancePublicId, grandChildLevel.internalId AS instanceInternalId" | |
527 " FROM Resources AS grandChildLevel " | |
528 " INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
529 " INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId) "; | |
530 break; | |
531 } | |
532 | |
533 case ResourceType_Patient: | |
534 { | |
535 sql+= " (SELECT Lookup.internalId AS parentInternalId, grandGrandChildLevel.publicId AS instancePublicId, grandGrandChildLevel.internalId AS instanceInternalId" | |
536 " FROM Resources AS grandGrandChildLevel " | |
537 " INNER JOIN Resources grandChildLevel ON grandGrandChildLevel.parentId = grandChildLevel.internalId " | |
538 " INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
539 " INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId) "; | |
540 break; | |
541 } | |
542 | |
543 default: | |
544 throw OrthancException(ErrorCode_InternalError); | |
451 } | 545 } |
546 } | |
547 | |
548 sql += "SELECT " | |
549 " " TOSTRING(QUERY_LOOKUP) " AS c0_queryId, " | |
550 " Lookup.internalId AS c1_internalId, " | |
551 " Lookup.rowNumber AS c2_rowNumber, " | |
552 " Lookup.publicId AS c3_string1, " | |
553 " NULL AS c4_string2, " | |
554 " NULL AS c5_string3, " | |
555 " NULL AS c6_int1, " | |
556 " NULL AS c7_int2, " | |
557 " NULL AS c8_big_int1, " | |
558 " NULL AS c9_big_int2 " | |
559 " FROM Lookup "; | |
560 | |
561 // need one instance info ? (part 2: execute the queries) | |
562 if (request.GetLevel() != ResourceType_Instance && | |
563 request.IsRetrieveOneInstanceMetadataAndAttachments()) | |
564 { | |
565 sql += " UNION SELECT" | |
566 " " TOSTRING(QUERY_ONE_INSTANCE_IDENTIFIER) " AS c0_queryId, " | |
567 " parentInternalId AS c1_internalId, " | |
568 " NULL AS c2_rowNumber, " | |
569 " instancePublicId AS c3_string1, " | |
570 " NULL AS c4_string2, " | |
571 " NULL AS c5_string3, " | |
572 " NULL AS c6_int1, " | |
573 " NULL AS c7_int2, " | |
574 " instanceInternalId AS c8_big_int1, " | |
575 " NULL AS c9_big_int2 " | |
576 " FROM OneInstance "; | |
577 | |
578 sql += " UNION SELECT" | |
579 " " TOSTRING(QUERY_ONE_INSTANCE_METADATA) " AS c0_queryId, " | |
580 " parentInternalId AS c1_internalId, " | |
581 " NULL AS c2_rowNumber, " | |
582 " Metadata.value AS c3_string1, " | |
583 " NULL AS c4_string2, " | |
584 " NULL AS c5_string3, " | |
585 " Metadata.type AS c6_int1, " | |
586 " NULL AS c7_int2, " | |
587 " NULL AS c8_big_int1, " | |
588 " NULL AS c9_big_int2 " | |
589 " FROM Metadata " | |
590 " INNER JOIN OneInstance ON Metadata.id = OneInstance.instanceInternalId "; | |
591 | |
592 sql += " UNION SELECT" | |
593 " " TOSTRING(QUERY_ONE_INSTANCE_ATTACHMENTS) " AS c0_queryId, " | |
594 " parentInternalId AS c1_internalId, " | |
595 " NULL AS c2_rowNumber, " | |
596 " uuid AS c3_string1, " | |
597 " uncompressedMD5 AS c4_string2, " | |
598 " compressedMD5 AS c5_string3, " | |
599 " fileType AS c6_int1, " | |
600 " compressionType AS c7_int2, " | |
601 " compressedSize AS c8_big_int1, " | |
602 " uncompressedSize AS c9_big_int2 " | |
603 " FROM AttachedFiles " | |
604 " INNER JOIN OneInstance ON AttachedFiles.id = OneInstance.instanceInternalId "; | |
605 | |
452 } | 606 } |
453 | 607 |
454 // need MainDicomTags from resource ? | 608 // need MainDicomTags from resource ? |
455 if (request.IsRetrieveMainDicomTags()) | 609 if (request.IsRetrieveMainDicomTags()) |
456 { | 610 { |
457 sql = "SELECT id, tagGroup, tagElement, value " | 611 sql += "UNION SELECT " |
458 "FROM MainDicomTags " | 612 " " TOSTRING(QUERY_MAIN_DICOM_TAGS) " AS c0_queryId, " |
459 "INNER JOIN Lookup ON MainDicomTags.id = Lookup.internalId"; | 613 " Lookup.internalId AS c1_internalId, " |
460 | 614 " NULL AS c2_rowNumber, " |
461 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 615 " value AS c3_string1, " |
462 while (s.Step()) | 616 " NULL AS c4_string2, " |
463 { | 617 " NULL AS c5_string3, " |
464 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 618 " tagGroup AS c6_int1, " |
465 res.AddStringDicomTag(requestLevel, | 619 " tagElement AS c7_int2, " |
466 static_cast<uint16_t>(s.ColumnInt(1)), | 620 " NULL AS c8_big_int1, " |
467 static_cast<uint16_t>(s.ColumnInt(2)), | 621 " NULL AS c9_big_int2 " |
468 s.ColumnString(3)); | 622 "FROM MainDicomTags " |
469 } | 623 "INNER JOIN Lookup ON MainDicomTags.id = Lookup.internalId "; |
470 } | 624 } |
471 | 625 |
472 | 626 // need resource metadata ? |
627 if (request.IsRetrieveMetadata()) | |
628 { | |
629 sql += "UNION SELECT " | |
630 " " TOSTRING(QUERY_METADATA) " AS c0_queryId, " | |
631 " Lookup.internalId AS c1_internalId, " | |
632 " NULL AS c2_rowNumber, " | |
633 " value AS c3_string1, " | |
634 " NULL AS c4_string2, " | |
635 " NULL AS c5_string3, " | |
636 " type AS c6_int1, " | |
637 " NULL AS c7_int2, " | |
638 " NULL AS c8_big_int1, " | |
639 " NULL AS c9_big_int2 " | |
640 "FROM Metadata " | |
641 "INNER JOIN Lookup ON Metadata.id = Lookup.internalId "; | |
642 } | |
643 | |
644 // need resource attachments ? | |
645 if (request.IsRetrieveAttachments()) | |
646 { | |
647 sql += "UNION SELECT " | |
648 " " TOSTRING(QUERY_ATTACHMENTS) " AS c0_queryId, " | |
649 " Lookup.internalId AS c1_internalId, " | |
650 " NULL AS c2_rowNumber, " | |
651 " uuid AS c3_string1, " | |
652 " uncompressedMD5 AS c4_string2, " | |
653 " compressedMD5 AS c5_string3, " | |
654 " fileType AS c6_int1, " | |
655 " compressionType AS c7_int2, " | |
656 " compressedSize AS c8_big_int1, " | |
657 " uncompressedSize AS c9_big_int2 " | |
658 "FROM AttachedFiles " | |
659 "INNER JOIN Lookup ON AttachedFiles.id = Lookup.internalId "; | |
660 } | |
661 | |
662 | |
663 // need resource labels ? | |
664 if (request.IsRetrieveLabels()) | |
665 { | |
666 sql += "UNION SELECT " | |
667 " " TOSTRING(QUERY_LABELS) " AS c0_queryId, " | |
668 " Lookup.internalId AS c1_internalId, " | |
669 " NULL AS c2_rowNumber, " | |
670 " label AS c3_string1, " | |
671 " NULL AS c4_string2, " | |
672 " NULL AS c5_string3, " | |
673 " NULL AS c6_int1, " | |
674 " NULL AS c7_int2, " | |
675 " NULL AS c8_big_int1, " | |
676 " NULL AS c9_big_int2 " | |
677 "FROM Labels " | |
678 "INNER JOIN Lookup ON Labels.id = Lookup.internalId "; | |
679 } | |
680 | |
473 if (requestLevel > ResourceType_Patient) | 681 if (requestLevel > ResourceType_Patient) |
474 { | 682 { |
475 // need MainDicomTags from parent ? | 683 // need MainDicomTags from parent ? |
476 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 1)).IsRetrieveMainDicomTags()) | 684 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 1)).IsRetrieveMainDicomTags()) |
477 { | 685 { |
478 sql = "SELECT currentLevel.internalId, tagGroup, tagElement, value " | 686 sql += "UNION SELECT " |
479 "FROM MainDicomTags " | 687 " " TOSTRING(QUERY_PARENT_MAIN_DICOM_TAGS) " AS c0_queryId, " |
480 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | 688 " Lookup.internalId AS c1_internalId, " |
481 "INNER JOIN Lookup ON MainDicomTags.id = currentLevel.parentId"; | 689 " NULL AS c2_rowNumber, " |
482 | 690 " value AS c3_string1, " |
483 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 691 " NULL AS c4_string2, " |
484 while (s.Step()) | 692 " NULL AS c5_string3, " |
485 { | 693 " tagGroup AS c6_int1, " |
486 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 694 " tagElement AS c7_int2, " |
487 res.AddStringDicomTag(static_cast<ResourceType>(requestLevel - 1), | 695 " NULL AS c8_big_int1, " |
488 static_cast<uint16_t>(s.ColumnInt(1)), | 696 " NULL AS c9_big_int2 " |
489 static_cast<uint16_t>(s.ColumnInt(2)), | 697 "FROM Lookup " |
490 s.ColumnString(3)); | 698 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " |
491 } | 699 "INNER JOIN MainDicomTags ON MainDicomTags.id = currentLevel.parentId "; |
492 } | 700 } |
493 | 701 |
494 // need metadata from parent ? | 702 // need metadata from parent ? |
495 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 1)).IsRetrieveMetadata()) | 703 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 1)).IsRetrieveMetadata()) |
496 { | 704 { |
497 sql = "SELECT currentLevel.internalId, type, value " | 705 sql += "UNION SELECT " |
498 "FROM Metadata " | 706 " " TOSTRING(QUERY_PARENT_METADATA) " AS c0_queryId, " |
499 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | 707 " Lookup.internalId AS c1_internalId, " |
500 "INNER JOIN Lookup ON Metadata.id = currentLevel.parentId"; | 708 " NULL AS c2_rowNumber, " |
501 | 709 " value AS c3_string1, " |
502 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 710 " NULL AS c4_string2, " |
503 while (s.Step()) | 711 " NULL AS c5_string3, " |
712 " type AS c6_int1, " | |
713 " NULL AS c7_int2, " | |
714 " NULL AS c8_big_int1, " | |
715 " NULL AS c9_big_int2 " | |
716 "FROM Lookup " | |
717 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | |
718 "INNER JOIN Metadata ON Metadata.id = currentLevel.parentId "; | |
719 } | |
720 | |
721 if (requestLevel > ResourceType_Study) | |
722 { | |
723 // need MainDicomTags from grandparent ? | |
724 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 2)).IsRetrieveMainDicomTags()) | |
504 { | 725 { |
505 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 726 sql += "UNION SELECT " |
506 res.AddMetadata(static_cast<ResourceType>(requestLevel - 1), | 727 " " TOSTRING(QUERY_GRAND_PARENT_MAIN_DICOM_TAGS) " AS c0_queryId, " |
507 static_cast<MetadataType>(s.ColumnInt(1)), | 728 " Lookup.internalId AS c1_internalId, " |
508 s.ColumnString(2)); | 729 " NULL AS c2_rowNumber, " |
730 " value AS c3_string1, " | |
731 " NULL AS c4_string2, " | |
732 " NULL AS c5_string3, " | |
733 " tagGroup AS c6_int1, " | |
734 " tagElement AS c7_int2, " | |
735 " NULL AS c8_big_int1, " | |
736 " NULL AS c9_big_int2 " | |
737 "FROM Lookup " | |
738 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | |
739 "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " | |
740 "INNER JOIN MainDicomTags ON MainDicomTags.id = parentLevel.parentId "; | |
741 } | |
742 | |
743 // need metadata from grandparent ? | |
744 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 2)).IsRetrieveMetadata()) | |
745 { | |
746 sql += "UNION SELECT " | |
747 " " TOSTRING(QUERY_GRAND_PARENT_METADATA) " AS c0_queryId, " | |
748 " Lookup.internalId AS c1_internalId, " | |
749 " NULL AS c2_rowNumber, " | |
750 " value AS c3_string1, " | |
751 " NULL AS c4_string2, " | |
752 " NULL AS c5_string3, " | |
753 " type AS c6_int1, " | |
754 " NULL AS c7_int2, " | |
755 " NULL AS c8_big_int1, " | |
756 " NULL AS c9_big_int2 " | |
757 "FROM Lookup " | |
758 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | |
759 "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " | |
760 "INNER JOIN Metadata ON Metadata.id = parentLevel.parentId "; | |
509 } | 761 } |
510 } | 762 } |
511 } | 763 } |
512 | 764 |
513 if (requestLevel > ResourceType_Study) | |
514 { | |
515 // need MainDicomTags from grandparent ? | |
516 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 2)).IsRetrieveMainDicomTags()) | |
517 { | |
518 sql = "SELECT currentLevel.internalId, tagGroup, tagElement, value " | |
519 "FROM MainDicomTags " | |
520 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | |
521 "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " | |
522 "INNER JOIN Lookup ON MainDicomTags.id = parentLevel.parentId"; | |
523 | |
524 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
525 while (s.Step()) | |
526 { | |
527 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
528 res.AddStringDicomTag(static_cast<ResourceType>(requestLevel - 2), | |
529 static_cast<uint16_t>(s.ColumnInt(1)), | |
530 static_cast<uint16_t>(s.ColumnInt(2)), | |
531 s.ColumnString(3)); | |
532 } | |
533 } | |
534 | |
535 // need metadata from grandparent ? | |
536 if (request.GetParentSpecification(static_cast<ResourceType>(requestLevel - 2)).IsRetrieveMetadata()) | |
537 { | |
538 sql = "SELECT currentLevel.internalId, type, value " | |
539 "FROM Metadata " | |
540 "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " | |
541 "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " | |
542 "INNER JOIN Lookup ON Metadata.id = parentLevel.parentId"; | |
543 | |
544 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
545 while (s.Step()) | |
546 { | |
547 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
548 res.AddMetadata(static_cast<ResourceType>(requestLevel - 2), | |
549 static_cast<MetadataType>(s.ColumnInt(1)), | |
550 s.ColumnString(2)); | |
551 } | |
552 } | |
553 } | |
554 | |
555 // need MainDicomTags from children ? | 765 // need MainDicomTags from children ? |
556 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMainDicomTags().size() > 0) | 766 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMainDicomTags().size() > 0) |
557 { | 767 { |
558 sql = "SELECT Lookup.internalId, tagGroup, tagElement, value " | 768 sql += "UNION SELECT " |
559 "FROM MainDicomTags " | 769 " " TOSTRING(QUERY_CHILDREN_MAIN_DICOM_TAGS) " AS c0_queryId, " |
560 "INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " | 770 " Lookup.internalId AS c1_internalId, " |
561 "INNER JOIN Lookup ON MainDicomTags.id = childLevel.internalId "; | 771 " NULL AS c2_rowNumber, " |
562 | 772 " value AS c3_string1, " |
563 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 773 " NULL AS c4_string2, " |
564 while (s.Step()) | 774 " NULL AS c5_string3, " |
565 { | 775 " tagGroup AS c6_int1, " |
566 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 776 " tagElement AS c7_int2, " |
567 res.AddChildrenMainDicomTagValue(static_cast<ResourceType>(requestLevel + 1), | 777 " NULL AS c8_big_int1, " |
568 DicomTag(static_cast<uint16_t>(s.ColumnInt(1)), | 778 " NULL AS c9_big_int2 " |
569 static_cast<uint16_t>(s.ColumnInt(2))), | 779 "FROM Lookup " |
570 s.ColumnString(3)); | 780 " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " |
571 } | 781 " INNER JOIN MainDicomTags ON MainDicomTags.id = childLevel.internalId AND " + JoinRequestedTags(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1))); |
572 } | 782 } |
573 | 783 |
574 // need MainDicomTags from grandchildren ? | 784 // need MainDicomTags from grandchildren ? |
575 if (requestLevel <= ResourceType_Study && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2)).GetMainDicomTags().size() > 0) | 785 if (requestLevel <= ResourceType_Study && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2)).GetMainDicomTags().size() > 0) |
576 { | 786 { |
577 sql = "SELECT Lookup.internalId, tagGroup, tagElement, value " | 787 sql += "UNION SELECT " |
578 "FROM MainDicomTags " | 788 " " TOSTRING(QUERY_GRAND_CHILDREN_MAIN_DICOM_TAGS) " AS c0_queryId, " |
579 "INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " | 789 " Lookup.internalId AS c1_internalId, " |
580 "INNER JOIN Resources grandChildLevel ON childLevel.parentId = Lookup.internalId " | 790 " NULL AS c2_rowNumber, " |
581 "INNER JOIN Lookup ON MainDicomTags.id = grandChildLevel.internalId "; | 791 " value AS c3_string1, " |
582 | 792 " NULL AS c4_string2, " |
583 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 793 " NULL AS c5_string3, " |
584 while (s.Step()) | 794 " tagGroup AS c6_int1, " |
585 { | 795 " tagElement AS c7_int2, " |
586 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 796 " NULL AS c8_big_int1, " |
587 res.AddChildrenMainDicomTagValue(static_cast<ResourceType>(requestLevel + 2), | 797 " NULL AS c9_big_int2 " |
588 DicomTag(static_cast<uint16_t>(s.ColumnInt(1)), | 798 "FROM Lookup " |
589 static_cast<uint16_t>(s.ColumnInt(2))), | 799 " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " |
590 s.ColumnString(3)); | 800 " INNER JOIN Resources grandChildLevel ON childLevel.parentId = Lookup.internalId " |
591 } | 801 " INNER JOIN MainDicomTags ON MainDicomTags.id = grandChildLevel.internalId AND " + JoinRequestedTags(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2))); |
592 } | 802 } |
593 | 803 |
594 // need parent identifier ? | 804 // need parent identifier ? |
595 if (request.IsRetrieveParentIdentifier()) | 805 if (request.IsRetrieveParentIdentifier()) |
596 { | 806 { |
597 sql = "SELECT currentLevel.internalId, parentLevel.publicId " | 807 sql += "UNION SELECT " |
598 "FROM Resources AS currentLevel " | 808 " " TOSTRING(QUERY_PARENT_IDENTIFIER) " AS c0_queryId, " |
599 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 809 " Lookup.internalId AS c1_internalId, " |
600 "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId "; | 810 " NULL AS c2_rowNumber, " |
601 | 811 " parentLevel.publicId AS c3_string1, " |
602 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 812 " NULL AS c4_string2, " |
603 while (s.Step()) | 813 " NULL AS c5_string3, " |
604 { | 814 " NULL AS c6_int1, " |
605 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 815 " NULL AS c7_int2, " |
606 res.SetParentIdentifier(s.ColumnString(1)); | 816 " NULL AS c8_big_int1, " |
607 } | 817 " NULL AS c9_big_int2 " |
608 } | 818 "FROM Resources AS currentLevel " |
609 | 819 " INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " |
610 // need resource metadata ? | 820 " INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId "; |
611 if (request.IsRetrieveMetadata()) | |
612 { | |
613 sql = "SELECT id, type, value " | |
614 "FROM Metadata " | |
615 "INNER JOIN Lookup ON Metadata.id = Lookup.internalId"; | |
616 | |
617 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
618 while (s.Step()) | |
619 { | |
620 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
621 res.AddMetadata(requestLevel, | |
622 static_cast<MetadataType>(s.ColumnInt(1)), | |
623 s.ColumnString(2)); | |
624 } | |
625 } | |
626 | |
627 // need resource labels ? | |
628 if (request.IsRetrieveLabels()) | |
629 { | |
630 sql = "SELECT Lookup.internalId, label " | |
631 "FROM Labels " | |
632 "INNER JOIN Lookup ON Labels.id = Lookup.internalId"; | |
633 | |
634 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
635 while (s.Step()) | |
636 { | |
637 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
638 res.AddLabel(s.ColumnString(1)); | |
639 } | |
640 } | |
641 | |
642 // need one instance info ? | |
643 if (request.GetLevel() != ResourceType_Instance && | |
644 request.IsRetrieveOneInstanceMetadataAndAttachments()) | |
645 { | |
646 { | |
647 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS OneInstance"); // TODO-FIND: use a CTE | |
648 s.Run(); | |
649 } | |
650 | |
651 switch (requestLevel) | |
652 { | |
653 case ResourceType_Patient: | |
654 { | |
655 SQLite::Statement s( | |
656 db_, SQLITE_FROM_HERE, | |
657 "CREATE TEMPORARY TABLE OneInstance AS " | |
658 "SELECT Lookup.internalId AS parentInternalId, grandGrandChildLevel.publicId AS instancePublicId, grandGrandChildLevel.internalId AS instanceInternalId " | |
659 "FROM Resources AS grandGrandChildLevel " | |
660 "INNER JOIN Resources grandChildLevel ON grandGrandChildLevel.parentId = grandChildLevel.internalId " | |
661 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
662 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
663 s.Run(); | |
664 break; | |
665 } | |
666 | |
667 case ResourceType_Study: | |
668 { | |
669 SQLite::Statement s( | |
670 db_, SQLITE_FROM_HERE, | |
671 "CREATE TEMPORARY TABLE OneInstance AS " | |
672 "SELECT Lookup.internalId AS parentInternalId, grandChildLevel.publicId AS instancePublicId, grandChildLevel.internalId AS instanceInternalId " | |
673 "FROM Resources AS grandChildLevel " | |
674 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
675 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
676 s.Run(); | |
677 break; | |
678 } | |
679 | |
680 case ResourceType_Series: | |
681 { | |
682 SQLite::Statement s( | |
683 db_, SQLITE_FROM_HERE, | |
684 "CREATE TEMPORARY TABLE OneInstance AS " | |
685 "SELECT Lookup.internalId AS parentInternalId, childLevel.publicId AS instancePublicId, childLevel.internalId AS instanceInternalId " | |
686 "FROM Resources AS childLevel " | |
687 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
688 s.Run(); | |
689 break; | |
690 } | |
691 | |
692 default: | |
693 throw OrthancException(ErrorCode_InternalError); | |
694 } | |
695 | |
696 { | |
697 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT parentInternalId, instancePublicId FROM OneInstance"); | |
698 while (s.Step()) | |
699 { | |
700 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
701 res.SetOneInstancePublicId(s.ColumnString(1)); | |
702 } | |
703 } | |
704 | |
705 { | |
706 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT OneInstance.parentInternalId, Metadata.type, Metadata.value " | |
707 "FROM Metadata INNER JOIN OneInstance ON Metadata.id = OneInstance.instanceInternalId"); | |
708 while (s.Step()) | |
709 { | |
710 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
711 res.AddOneInstanceMetadata(static_cast<MetadataType>(s.ColumnInt(1)), s.ColumnString(2)); | |
712 } | |
713 } | |
714 | |
715 { | |
716 SQLite::Statement s(db_, SQLITE_FROM_HERE, | |
717 "SELECT OneInstance.parentInternalId, AttachedFiles.fileType, AttachedFiles.uuid, " | |
718 "AttachedFiles.uncompressedSize, AttachedFiles.compressedSize, " | |
719 "AttachedFiles.compressionType, AttachedFiles.uncompressedMD5, AttachedFiles.compressedMD5 " | |
720 "FROM AttachedFiles INNER JOIN OneInstance ON AttachedFiles.id = OneInstance.instanceInternalId"); | |
721 while (s.Step()) | |
722 { | |
723 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
724 res.AddOneInstanceAttachment( | |
725 FileInfo(s.ColumnString(2), static_cast<FileContentType>(s.ColumnInt(1)), | |
726 s.ColumnInt64(3), s.ColumnString(6), | |
727 static_cast<CompressionType>(s.ColumnInt(5)), | |
728 s.ColumnInt64(4), s.ColumnString(7))); | |
729 } | |
730 } | |
731 } | 821 } |
732 | 822 |
733 // need children metadata ? | 823 // need children metadata ? |
734 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMetadata().size() > 0) | 824 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMetadata().size() > 0) |
735 { | 825 { |
736 sql = "SELECT Lookup.internalId, type, value " | 826 sql += "UNION SELECT " |
737 "FROM Metadata " | 827 " " TOSTRING(QUERY_CHILDREN_METADATA) " AS c0_queryId, " |
738 "INNER JOIN Lookup ON Lookup.internalId = childLevel.parentId " | 828 " Lookup.internalId AS c1_internalId, " |
739 "INNER JOIN Resources childLevel ON childLevel.internalId = Metadata.id"; | 829 " NULL AS c2_rowNumber, " |
740 | 830 " value AS c3_string1, " |
741 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 831 " NULL AS c4_string2, " |
742 while (s.Step()) | 832 " NULL AS c5_string3, " |
743 { | 833 " type AS c6_int1, " |
744 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 834 " NULL AS c7_int2, " |
745 res.AddChildrenMetadataValue(static_cast<ResourceType>(requestLevel + 1), | 835 " NULL AS c8_big_int1, " |
746 static_cast<MetadataType>(s.ColumnInt(1)), | 836 " NULL AS c9_big_int2 " |
747 s.ColumnString(2)); | 837 "FROM Lookup " |
748 } | 838 " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " |
839 " INNER JOIN Metadata ON Metadata.id = childLevel.internalId AND Metadata.type IN (" + JoinRequestedMetadata(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1))) + ") "; | |
749 } | 840 } |
750 | 841 |
751 // need grandchildren metadata ? | 842 // need grandchildren metadata ? |
752 if (requestLevel <= ResourceType_Study && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2)).GetMetadata().size() > 0) | 843 if (requestLevel <= ResourceType_Study && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2)).GetMetadata().size() > 0) |
753 { | 844 { |
754 sql = "SELECT Lookup.internalId, type, value " | 845 sql += "UNION SELECT " |
755 "FROM Metadata " | 846 " " TOSTRING(QUERY_GRAND_CHILDREN_METADATA) " AS c0_queryId, " |
756 "INNER JOIN Lookup ON Lookup.internalId = childLevel.parentId " | 847 " Lookup.internalId AS c1_internalId, " |
757 "INNER JOIN Resources childLevel ON childLevel.internalId = grandChildLevel.parentId " | 848 " NULL AS c2_rowNumber, " |
758 "INNER JOIN Resources grandChildLevel ON grandChildLevel.internalId = Metadata.id"; | 849 " value AS c3_string1, " |
759 | 850 " NULL AS c4_string2, " |
760 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 851 " NULL AS c5_string3, " |
761 while (s.Step()) | 852 " type AS c6_int1, " |
762 { | 853 " NULL AS c7_int2, " |
763 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 854 " NULL AS c8_big_int1, " |
764 res.AddChildrenMetadataValue(static_cast<ResourceType>(requestLevel + 2), | 855 " NULL AS c9_big_int2 " |
765 static_cast<MetadataType>(s.ColumnInt(1)), | 856 "FROM Lookup " |
766 s.ColumnString(2)); | 857 " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " |
767 } | 858 " INNER JOIN Resources grandChildLevel ON childLevel.parentId = Lookup.internalId " |
859 " INNER JOIN Metadata ON Metadata.id = grandChildLevel.internalId AND Metadata.type IN (" + JoinRequestedMetadata(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2))) + ") "; | |
768 } | 860 } |
769 | 861 |
770 // need children identifiers ? | 862 // need children identifiers ? |
771 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Study).IsRetrieveIdentifiers()) || | 863 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Study).IsRetrieveIdentifiers()) || |
772 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || | 864 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || |
773 (requestLevel == ResourceType_Series && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) | 865 (requestLevel == ResourceType_Series && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) |
774 { | 866 { |
775 sql = "SELECT Lookup.internalId, childLevel.publicId " | 867 sql += "UNION SELECT " |
776 "FROM Resources AS currentLevel " | 868 " " TOSTRING(QUERY_CHILDREN_IDENTIFIERS) " AS c0_queryId, " |
777 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 869 " Lookup.internalId AS c1_internalId, " |
778 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId "; | 870 " NULL AS c2_rowNumber, " |
779 | 871 " childLevel.publicId AS c3_string1, " |
780 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 872 " NULL AS c4_string2, " |
781 while (s.Step()) | 873 " NULL AS c5_string3, " |
782 { | 874 " NULL AS c6_int1, " |
783 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 875 " NULL AS c7_int2, " |
784 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1), s.ColumnString(1)); | 876 " NULL AS c8_big_int1, " |
785 } | 877 " NULL AS c9_big_int2 " |
878 "FROM Resources AS currentLevel " | |
879 " INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | |
880 " INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId "; | |
786 } | 881 } |
787 | 882 |
788 // need grandchildren identifiers ? | 883 // need grandchildren identifiers ? |
789 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || | 884 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || |
790 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) | 885 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) |
791 { | 886 { |
792 sql = "SELECT Lookup.internalId, grandChildLevel.publicId " | 887 sql += "UNION SELECT " |
888 " " TOSTRING(QUERY_GRAND_CHILDREN_IDENTIFIERS) " AS c0_queryId, " | |
889 " Lookup.internalId AS c1_internalId, " | |
890 " NULL AS c2_rowNumber, " | |
891 " grandChildLevel.publicId AS c3_string1, " | |
892 " NULL AS c4_string2, " | |
893 " NULL AS c5_string3, " | |
894 " NULL AS c6_int1, " | |
895 " NULL AS c7_int2, " | |
896 " NULL AS c8_big_int1, " | |
897 " NULL AS c9_big_int2 " | |
793 "FROM Resources AS currentLevel " | 898 "FROM Resources AS currentLevel " |
794 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 899 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " |
795 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " | 900 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " |
796 "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId "; | 901 "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId "; |
797 | |
798 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
799 while (s.Step()) | |
800 { | |
801 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
802 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2), s.ColumnString(1)); | |
803 } | |
804 } | 902 } |
805 | 903 |
806 // need grandgrandchildren identifiers ? | 904 // need grandgrandchildren identifiers ? |
807 if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers()) | 905 if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers()) |
808 { | 906 { |
809 sql = "SELECT Lookup.internalId, grandGrandChildLevel.publicId " | 907 sql += "UNION SELECT " |
908 " " TOSTRING(QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS) " AS c0_queryId, " | |
909 " Lookup.internalId AS c1_internalId, " | |
910 " NULL AS c2_rowNumber, " | |
911 " grandGrandChildLevel.publicId AS c3_string1, " | |
912 " NULL AS c4_string2, " | |
913 " NULL AS c5_string3, " | |
914 " NULL AS c6_int1, " | |
915 " NULL AS c7_int2, " | |
916 " NULL AS c8_big_int1, " | |
917 " NULL AS c9_big_int2 " | |
810 "FROM Resources AS currentLevel " | 918 "FROM Resources AS currentLevel " |
811 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 919 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " |
812 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " | 920 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " |
813 "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId " | 921 "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId " |
814 "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId "; | 922 "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId "; |
815 | 923 } |
816 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 924 |
817 while (s.Step()) | 925 |
926 sql += " ORDER BY c0_queryId, c2_rowNumber"; // this is really important to make sure that the Lookup query is the first one to provide results since we use it to create the responses element ! | |
927 | |
928 SQLite::Statement s(db_, SQLITE_FROM_HERE_DYNAMIC(sql), sql); | |
929 formatter.Bind(s); | |
930 | |
931 while (s.Step()) | |
932 { | |
933 int queryId = s.ColumnInt(C0_QUERY_ID); | |
934 int64_t internalId = s.ColumnInt64(C1_INTERNAL_ID); | |
935 | |
936 // LOG(INFO) << queryId << ": " << internalId; | |
937 // continue; | |
938 | |
939 assert(queryId == QUERY_LOOKUP || response.HasResource(internalId)); // the QUERY_LOOKUP must be read first and must create the response before any other query tries to populate the fields | |
940 | |
941 switch (queryId) | |
818 { | 942 { |
819 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 943 case QUERY_LOOKUP: |
820 res.AddChildIdentifier(ResourceType_Instance, s.ColumnString(1)); | 944 response.Add(new FindResponse::Resource(requestLevel, internalId, s.ColumnString(C3_STRING_1))); |
945 break; | |
946 | |
947 case QUERY_LABELS: | |
948 { | |
949 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
950 res.AddLabel(s.ColumnString(C3_STRING_1)); | |
951 }; break; | |
952 | |
953 case QUERY_ATTACHMENTS: | |
954 { | |
955 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
956 FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)), | |
957 s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C4_STRING_2), | |
958 static_cast<CompressionType>(s.ColumnInt(C7_INT_2)), | |
959 s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C5_STRING_3)); | |
960 res.AddAttachment(file); | |
961 }; break; | |
962 | |
963 case QUERY_MAIN_DICOM_TAGS: | |
964 { | |
965 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
966 res.AddStringDicomTag(requestLevel, | |
967 static_cast<uint16_t>(s.ColumnInt(C6_INT_1)), | |
968 static_cast<uint16_t>(s.ColumnInt(C7_INT_2)), | |
969 s.ColumnString(C3_STRING_1)); | |
970 }; break; | |
971 | |
972 case QUERY_PARENT_MAIN_DICOM_TAGS: | |
973 { | |
974 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
975 res.AddStringDicomTag(static_cast<ResourceType>(requestLevel - 1), | |
976 static_cast<uint16_t>(s.ColumnInt(C6_INT_1)), | |
977 static_cast<uint16_t>(s.ColumnInt(C7_INT_2)), | |
978 s.ColumnString(C3_STRING_1)); | |
979 }; break; | |
980 | |
981 case QUERY_GRAND_PARENT_MAIN_DICOM_TAGS: | |
982 { | |
983 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
984 res.AddStringDicomTag(static_cast<ResourceType>(requestLevel - 2), | |
985 static_cast<uint16_t>(s.ColumnInt(C6_INT_1)), | |
986 static_cast<uint16_t>(s.ColumnInt(C7_INT_2)), | |
987 s.ColumnString(C3_STRING_1)); | |
988 }; break; | |
989 | |
990 case QUERY_CHILDREN_MAIN_DICOM_TAGS: | |
991 { | |
992 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
993 res.AddChildrenMainDicomTagValue(static_cast<ResourceType>(requestLevel + 1), | |
994 DicomTag(static_cast<uint16_t>(s.ColumnInt(C6_INT_1)), static_cast<uint16_t>(s.ColumnInt(C7_INT_2))), | |
995 s.ColumnString(C3_STRING_1)); | |
996 }; break; | |
997 | |
998 case QUERY_GRAND_CHILDREN_MAIN_DICOM_TAGS: | |
999 { | |
1000 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1001 res.AddChildrenMainDicomTagValue(static_cast<ResourceType>(requestLevel + 2), | |
1002 DicomTag(static_cast<uint16_t>(s.ColumnInt(C6_INT_1)), static_cast<uint16_t>(s.ColumnInt(C7_INT_2))), | |
1003 s.ColumnString(C3_STRING_1)); | |
1004 }; break; | |
1005 | |
1006 case QUERY_METADATA: | |
1007 { | |
1008 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1009 res.AddMetadata(static_cast<ResourceType>(requestLevel), | |
1010 static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), | |
1011 s.ColumnString(C3_STRING_1)); | |
1012 }; break; | |
1013 | |
1014 case QUERY_PARENT_METADATA: | |
1015 { | |
1016 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1017 res.AddMetadata(static_cast<ResourceType>(requestLevel - 1), | |
1018 static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), | |
1019 s.ColumnString(C3_STRING_1)); | |
1020 }; break; | |
1021 | |
1022 case QUERY_GRAND_PARENT_METADATA: | |
1023 { | |
1024 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1025 res.AddMetadata(static_cast<ResourceType>(requestLevel - 2), | |
1026 static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), | |
1027 s.ColumnString(C3_STRING_1)); | |
1028 }; break; | |
1029 | |
1030 case QUERY_CHILDREN_METADATA: | |
1031 { | |
1032 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1033 res.AddChildrenMetadataValue(static_cast<ResourceType>(requestLevel + 1), | |
1034 static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), | |
1035 s.ColumnString(C3_STRING_1)); | |
1036 }; break; | |
1037 | |
1038 case QUERY_GRAND_CHILDREN_METADATA: | |
1039 { | |
1040 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1041 res.AddChildrenMetadataValue(static_cast<ResourceType>(requestLevel + 2), | |
1042 static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), | |
1043 s.ColumnString(C3_STRING_1)); | |
1044 }; break; | |
1045 | |
1046 case QUERY_PARENT_IDENTIFIER: | |
1047 { | |
1048 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1049 res.SetParentIdentifier(s.ColumnString(C3_STRING_1)); | |
1050 }; break; | |
1051 | |
1052 case QUERY_CHILDREN_IDENTIFIERS: | |
1053 { | |
1054 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1055 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1), | |
1056 s.ColumnString(C3_STRING_1)); | |
1057 }; break; | |
1058 | |
1059 case QUERY_GRAND_CHILDREN_IDENTIFIERS: | |
1060 { | |
1061 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1062 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2), | |
1063 s.ColumnString(C3_STRING_1)); | |
1064 }; break; | |
1065 | |
1066 case QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS: | |
1067 { | |
1068 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1069 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 3), | |
1070 s.ColumnString(C3_STRING_1)); | |
1071 }; break; | |
1072 | |
1073 case QUERY_ONE_INSTANCE_IDENTIFIER: | |
1074 { | |
1075 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1076 res.SetOneInstancePublicId(s.ColumnString(C3_STRING_1)); | |
1077 }; break; | |
1078 | |
1079 case QUERY_ONE_INSTANCE_METADATA: | |
1080 { | |
1081 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1082 res.AddOneInstanceMetadata(static_cast<MetadataType>(s.ColumnInt(C6_INT_1)), s.ColumnString(C3_STRING_1)); | |
1083 }; break; | |
1084 | |
1085 case QUERY_ONE_INSTANCE_ATTACHMENTS: | |
1086 { | |
1087 FindResponse::Resource& res = response.GetResourceByInternalId(internalId); | |
1088 FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)), | |
1089 s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C4_STRING_2), | |
1090 static_cast<CompressionType>(s.ColumnInt(C7_INT_2)), | |
1091 s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C5_STRING_3)); | |
1092 res.AddOneInstanceAttachment(file); | |
1093 }; break; | |
1094 | |
1095 default: | |
1096 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
821 } | 1097 } |
822 } | 1098 } |
823 | 1099 } |
824 // need resource attachments ? | |
825 if (request.IsRetrieveAttachments()) | |
826 { | |
827 sql = "SELECT Lookup.internalId, fileType, uuid, uncompressedSize, compressedSize, compressionType, uncompressedMD5, compressedMD5 " | |
828 "FROM AttachedFiles " | |
829 "INNER JOIN Lookup ON AttachedFiles.id = Lookup.internalId"; | |
830 | |
831 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
832 while (s.Step()) | |
833 { | |
834 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
835 FileInfo file(s.ColumnString(2), static_cast<FileContentType>(s.ColumnInt(1)), | |
836 s.ColumnInt64(3), s.ColumnString(6), | |
837 static_cast<CompressionType>(s.ColumnInt(5)), | |
838 s.ColumnInt64(4), s.ColumnString(7)); | |
839 res.AddAttachment(file); | |
840 } | |
841 | |
842 } | |
843 } | |
844 | |
845 | |
846 | 1100 |
847 // From the "ICreateInstance" interface | 1101 // From the "ICreateInstance" interface |
848 virtual void AttachChild(int64_t parent, | 1102 virtual void AttachChild(int64_t parent, |
849 int64_t child) ORTHANC_OVERRIDE | 1103 int64_t child) ORTHANC_OVERRIDE |
850 { | 1104 { |