Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp @ 5774:f96abfe08946 find-refactoring
implementation of specialized SQL commands in SQLiteDatabaseWrapper
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 12 Sep 2024 08:25:41 +0200 |
parents | 093a8693ba16 |
children | de33982a0bf4 |
comparison
equal
deleted
inserted
replaced
5773:3b7dce0e43c6 | 5774:f96abfe08946 |
---|---|
66 } | 66 } |
67 | 67 |
68 virtual std::string FormatLimits(uint64_t since, uint64_t count) ORTHANC_OVERRIDE | 68 virtual std::string FormatLimits(uint64_t since, uint64_t count) ORTHANC_OVERRIDE |
69 { | 69 { |
70 std::string sql; | 70 std::string sql; |
71 | |
71 if (count > 0) | 72 if (count > 0) |
72 { | 73 { |
73 sql += " LIMIT " + boost::lexical_cast<std::string>(count); | 74 sql += " LIMIT " + boost::lexical_cast<std::string>(count); |
74 } | 75 } |
76 | |
75 if (since > 0) | 77 if (since > 0) |
76 { | 78 { |
79 if (count == 0) | |
80 { | |
81 sql += " LIMIT -1"; // In SQLite, "OFFSET" cannot appear without "LIMIT" | |
82 } | |
83 | |
77 sql += " OFFSET " + boost::lexical_cast<std::string>(since); | 84 sql += " OFFSET " + boost::lexical_cast<std::string>(since); |
78 } | 85 } |
79 | 86 |
80 return sql; | 87 return sql; |
81 } | 88 } |
586 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 593 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); |
587 res.AddLabel(s.ColumnString(1)); | 594 res.AddLabel(s.ColumnString(1)); |
588 } | 595 } |
589 } | 596 } |
590 | 597 |
591 if (request.IsRetrieveOneInstanceMetadataAndAttachments()) | 598 if (request.GetLevel() != ResourceType_Instance && |
592 { | 599 request.IsRetrieveOneInstanceMetadataAndAttachments()) |
593 throw OrthancException(ErrorCode_NotImplemented); | 600 { |
594 | 601 { |
595 #if 0 | 602 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS OneInstance"); |
596 // need one instance identifier ? TODO: it might be actually more interesting to retrieve directly the attachment ids .... | 603 s.Run(); |
597 if (requestLevel == ResourceType_Series) | 604 } |
598 { | 605 |
599 sql = "SELECT Lookup.internalId, childLevel.publicId " | 606 switch (requestLevel) |
600 "FROM Resources AS childLevel " | 607 { |
601 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId "; | 608 case ResourceType_Patient: |
602 | 609 { |
603 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 610 SQLite::Statement s( |
611 db_, SQLITE_FROM_HERE, | |
612 "CREATE TEMPORARY TABLE OneInstance AS " | |
613 "SELECT Lookup.internalId AS parentInternalId, grandGrandChildLevel.publicId AS instancePublicId, grandGrandChildLevel.internalId AS instanceInternalId " | |
614 "FROM Resources AS grandGrandChildLevel " | |
615 "INNER JOIN Resources grandChildLevel ON grandGrandChildLevel.parentId = grandChildLevel.internalId " | |
616 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
617 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
618 s.Run(); | |
619 break; | |
620 } | |
621 | |
622 case ResourceType_Study: | |
623 { | |
624 SQLite::Statement s( | |
625 db_, SQLITE_FROM_HERE, | |
626 "CREATE TEMPORARY TABLE OneInstance AS " | |
627 "SELECT Lookup.internalId AS parentInternalId, grandChildLevel.publicId AS instancePublicId, grandChildLevel.internalId AS instanceInternalId " | |
628 "FROM Resources AS grandChildLevel " | |
629 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
630 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
631 s.Run(); | |
632 break; | |
633 } | |
634 | |
635 case ResourceType_Series: | |
636 { | |
637 SQLite::Statement s( | |
638 db_, SQLITE_FROM_HERE, | |
639 "CREATE TEMPORARY TABLE OneInstance AS " | |
640 "SELECT Lookup.internalId AS parentInternalId, childLevel.publicId AS instancePublicId, childLevel.internalId AS instanceInternalId " | |
641 "FROM Resources AS childLevel " | |
642 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId GROUP BY Lookup.internalId"); | |
643 s.Run(); | |
644 break; | |
645 } | |
646 | |
647 default: | |
648 throw OrthancException(ErrorCode_InternalError); | |
649 } | |
650 | |
651 { | |
652 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT parentInternalId, instancePublicId FROM OneInstance"); | |
604 while (s.Step()) | 653 while (s.Step()) |
605 { | 654 { |
606 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 655 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); |
607 res.AddChildIdentifier(ResourceType_Instance, s.ColumnString(1)); | 656 res.SetOneInstancePublicId(s.ColumnString(1)); |
608 } | 657 } |
609 } | 658 } |
610 else if (requestLevel == ResourceType_Study) | 659 |
611 { | 660 { |
612 sql = "SELECT Lookup.internalId, grandChildLevel.publicId " | 661 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT OneInstance.parentInternalId, Metadata.type, Metadata.value " |
613 "FROM Resources AS grandChildLevel " | 662 "FROM Metadata INNER JOIN OneInstance ON Metadata.id = OneInstance.instanceInternalId"); |
614 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | |
615 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId "; | |
616 | |
617 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
618 while (s.Step()) | 663 while (s.Step()) |
619 { | 664 { |
620 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 665 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); |
621 res.AddChildIdentifier(ResourceType_Instance, s.ColumnString(1)); | 666 res.AddOneInstanceMetadata(static_cast<MetadataType>(s.ColumnInt(1)), s.ColumnString(2)); |
622 } | 667 } |
623 } | 668 } |
624 else if (requestLevel == ResourceType_Patient) | 669 |
625 { | 670 { |
626 sql = "SELECT Lookup.internalId, grandGrandChildLevel.publicId " | 671 SQLite::Statement s(db_, SQLITE_FROM_HERE, |
627 "FROM Resources AS grandGrandChildLevel " | 672 "SELECT OneInstance.parentInternalId, AttachedFiles.fileType, AttachedFiles.uuid, " |
628 "INNER JOIN Resources grandChildLevel ON grandGrandChildLevel.parentId = grandChildLevel.internalId " | 673 "AttachedFiles.uncompressedSize, AttachedFiles.compressedSize, " |
629 "INNER JOIN Resources childLevel ON grandChildLevel.parentId = childLevel.internalId " | 674 "AttachedFiles.compressionType, AttachedFiles.uncompressedMD5, AttachedFiles.compressedMD5 " |
630 "INNER JOIN Lookup ON childLevel.parentId = Lookup.internalId "; | 675 "FROM AttachedFiles INNER JOIN OneInstance ON AttachedFiles.id = OneInstance.instanceInternalId"); |
631 | |
632 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
633 while (s.Step()) | 676 while (s.Step()) |
634 { | 677 { |
635 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 678 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); |
636 res.AddChildIdentifier(ResourceType_Instance, s.ColumnString(1)); | 679 res.AddOneInstanceAttachment( |
680 FileInfo(s.ColumnString(2), static_cast<FileContentType>(s.ColumnInt(1)), | |
681 s.ColumnInt64(3), s.ColumnString(6), | |
682 static_cast<CompressionType>(s.ColumnInt(5)), | |
683 s.ColumnInt64(4), s.ColumnString(7))); | |
637 } | 684 } |
638 } | 685 } |
639 else | |
640 { | |
641 throw OrthancException(ErrorCode_InternalError); | |
642 } | |
643 #endif | |
644 } | 686 } |
645 | 687 |
646 // need children metadata ? | 688 // need children metadata ? |
647 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMetadata().size() > 0) | 689 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).GetMetadata().size() > 0) |
648 { | 690 { |
679 s.ColumnString(2)); | 721 s.ColumnString(2)); |
680 } | 722 } |
681 } | 723 } |
682 | 724 |
683 // need children identifiers ? | 725 // need children identifiers ? |
684 if (requestLevel <= ResourceType_Series && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1)).IsRetrieveIdentifiers()) | 726 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Study).IsRetrieveIdentifiers()) || |
727 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || | |
728 (requestLevel == ResourceType_Series && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) | |
685 { | 729 { |
686 sql = "SELECT Lookup.internalId, childLevel.publicId " | 730 sql = "SELECT Lookup.internalId, childLevel.publicId " |
687 "FROM Resources AS currentLevel " | 731 "FROM Resources AS currentLevel " |
688 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 732 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " |
689 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId "; | 733 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId "; |
695 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1), s.ColumnString(1)); | 739 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1), s.ColumnString(1)); |
696 } | 740 } |
697 } | 741 } |
698 | 742 |
699 // need grandchildren identifiers ? | 743 // need grandchildren identifiers ? |
700 if (requestLevel <= ResourceType_Study && request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 2)).IsRetrieveIdentifiers()) | 744 if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || |
745 (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())) | |
701 { | 746 { |
702 sql = "SELECT Lookup.internalId, grandChildLevel.publicId " | 747 sql = "SELECT Lookup.internalId, grandChildLevel.publicId " |
703 "FROM Resources AS currentLevel " | 748 "FROM Resources AS currentLevel " |
704 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | 749 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " |
705 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " | 750 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " |
708 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | 753 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); |
709 while (s.Step()) | 754 while (s.Step()) |
710 { | 755 { |
711 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | 756 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); |
712 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2), s.ColumnString(1)); | 757 res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2), s.ColumnString(1)); |
758 } | |
759 } | |
760 | |
761 // need grandgrandchildren identifiers ? | |
762 if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers()) | |
763 { | |
764 sql = "SELECT Lookup.internalId, grandGrandChildLevel.publicId " | |
765 "FROM Resources AS currentLevel " | |
766 "INNER JOIN Lookup ON currentLevel.internalId = Lookup.internalId " | |
767 "INNER JOIN Resources childLevel ON currentLevel.internalId = childLevel.parentId " | |
768 "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId " | |
769 "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId "; | |
770 | |
771 SQLite::Statement s(db_, SQLITE_FROM_HERE, sql); | |
772 while (s.Step()) | |
773 { | |
774 FindResponse::Resource& res = response.GetResourceByInternalId(s.ColumnInt64(0)); | |
775 res.AddChildIdentifier(ResourceType_Instance, s.ColumnString(1)); | |
713 } | 776 } |
714 } | 777 } |
715 | 778 |
716 // need resource attachments ? | 779 // need resource attachments ? |
717 if (request.IsRetrieveAttachments()) | 780 if (request.IsRetrieveAttachments()) |
867 virtual void GetAllPublicIds(std::list<std::string>& target, | 930 virtual void GetAllPublicIds(std::list<std::string>& target, |
868 ResourceType resourceType, | 931 ResourceType resourceType, |
869 int64_t since, | 932 int64_t since, |
870 uint32_t limit) ORTHANC_OVERRIDE | 933 uint32_t limit) ORTHANC_OVERRIDE |
871 { | 934 { |
872 if (limit == 0) | |
873 { | |
874 target.clear(); | |
875 return; | |
876 } | |
877 | |
878 SQLite::Statement s(db_, SQLITE_FROM_HERE, | 935 SQLite::Statement s(db_, SQLITE_FROM_HERE, |
879 "SELECT publicId FROM Resources WHERE " | 936 "SELECT publicId FROM Resources WHERE " |
880 "resourceType=? LIMIT ? OFFSET ?"); | 937 "resourceType=? LIMIT ? OFFSET ?"); |
881 s.BindInt(0, resourceType); | 938 s.BindInt(0, resourceType); |
882 s.BindInt64(1, limit); | 939 s.BindInt64(1, limit == 0 ? -1 : limit); // In SQLite, setting "LIMIT" to "-1" means "no limit" |
883 s.BindInt64(2, since); | 940 s.BindInt64(2, since); |
884 | 941 |
885 target.clear(); | 942 target.clear(); |
886 while (s.Step()) | 943 while (s.Step()) |
887 { | 944 { |