comparison Framework/Plugins/IndexBackend.cpp @ 501:594859656a06 large-queries

Added support for ExtendedApiV1: /changes
author Alain Mazy <am@orthanc.team>
date Thu, 11 Apr 2024 18:52:42 +0200
parents f0976163dbe1
children 2ab3d45c0b3c
comparison
equal deleted inserted replaced
500:c27071770c04 501:594859656a06
114 void IndexBackend::ReadChangesInternal(IDatabaseBackendOutput& output, 114 void IndexBackend::ReadChangesInternal(IDatabaseBackendOutput& output,
115 bool& done, 115 bool& done,
116 DatabaseManager& manager, 116 DatabaseManager& manager,
117 DatabaseManager::CachedStatement& statement, 117 DatabaseManager::CachedStatement& statement,
118 const Dictionary& args, 118 const Dictionary& args,
119 uint32_t limit) 119 uint32_t limit,
120 { 120 bool returnFirstResults)
121 {
122 struct Change
123 {
124 int64_t seq_;
125 int32_t changeType_;
126 OrthancPluginResourceType resourceType_;
127 std::string publicId_;
128 std::string changeDate_;
129
130 Change(int64_t seq, int32_t changeType, OrthancPluginResourceType resourceType, const std::string& publicId, const std::string& changeDate)
131 : seq_(seq), changeType_(changeType), resourceType_(resourceType), publicId_(publicId), changeDate_(changeDate)
132 {
133 }
134 };
135
121 statement.Execute(args); 136 statement.Execute(args);
122 137
123 uint32_t count = 0; 138 std::list<Change> changes;
124 139 while (!statement.IsDone())
125 while (count < limit && 140 {
126 !statement.IsDone()) 141 changes.push_back(Change(
127 {
128 output.AnswerChange(
129 statement.ReadInteger64(0), 142 statement.ReadInteger64(0),
130 statement.ReadInteger32(1), 143 statement.ReadInteger32(1),
131 static_cast<OrthancPluginResourceType>(statement.ReadInteger32(2)), 144 static_cast<OrthancPluginResourceType>(statement.ReadInteger32(2)),
132 statement.ReadString(3), 145 statement.ReadString(3),
133 statement.ReadString(4)); 146 statement.ReadString(4)
147 ));
134 148
135 statement.Next(); 149 statement.Next();
136 count++; 150 }
137 } 151
138 152 done = changes.size() <= limit; // 'done' means we have returned all requested changes
139 done = (count < limit || 153
140 statement.IsDone()); 154 // if we have retrieved more changes than requested -> cleanup
155 if (changes.size() > limit)
156 {
157 assert(changes.size() == limit+1); // the statement should only request 1 element more
158
159 if (returnFirstResults)
160 {
161 changes.pop_back();
162 }
163 else
164 {
165 changes.pop_front();
166 }
167 }
168
169 for (std::list<Change>::const_iterator it = changes.begin(); it != changes.end(); ++it)
170 {
171 output.AnswerChange(it->seq_, it->changeType_, it->resourceType_, it->publicId_, it->changeDate_);
172 }
141 } 173 }
142 174
143 175
144 void IndexBackend::ReadExportedResourcesInternal(IDatabaseBackendOutput& output, 176 void IndexBackend::ReadExportedResourcesInternal(IDatabaseBackendOutput& output,
145 bool& done, 177 bool& done,
551 args.SetIntegerValue("since", since); 583 args.SetIntegerValue("since", since);
552 584
553 ReadListOfStrings(target, statement, args); 585 ReadListOfStrings(target, statement, args);
554 } 586 }
555 587
556
557 /* Use GetOutput().AnswerChange() */
558 void IndexBackend::GetChanges(IDatabaseBackendOutput& output, 588 void IndexBackend::GetChanges(IDatabaseBackendOutput& output,
559 bool& done /*out*/, 589 bool& done /*out*/,
560 DatabaseManager& manager, 590 DatabaseManager& manager,
561 int64_t since, 591 int64_t since,
562 uint32_t limit) 592 uint32_t limit)
563 { 593 {
564 std::string suffix; 594 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 13, 0)
595 GetChanges2(output, done, manager, since, -1, _OrthancPluginChangeType_All, limit);
596 #else
597 GetChanges2(output, done, manager, since, -1, 65535, limit);
598 #endif
599 }
600
601 /* Use GetOutput().AnswerChange() */
602 void IndexBackend::GetChanges2(IDatabaseBackendOutput& output,
603 bool& done /*out*/,
604 DatabaseManager& manager,
605 int64_t since,
606 int64_t to,
607 int32_t changeType,
608 uint32_t limit)
609 {
610 std::string limitSuffix;
565 if (manager.GetDialect() == Dialect_MSSQL) 611 if (manager.GetDialect() == Dialect_MSSQL)
566 { 612 {
567 suffix = "OFFSET 0 ROWS FETCH FIRST ${limit} ROWS ONLY"; 613 limitSuffix = "OFFSET 0 ROWS FETCH FIRST ${limit} ROWS ONLY";
568 } 614 }
569 else 615 else
570 { 616 {
571 suffix = "LIMIT ${limit}"; 617 limitSuffix = "LIMIT ${limit}";
572 } 618 }
573 619
574 DatabaseManager::CachedStatement statement( 620 std::vector<std::string> filters;
575 STATEMENT_FROM_HERE, manager, 621 bool hasSince = false;
576 "SELECT Changes.seq, Changes.changeType, Changes.resourceType, Resources.publicId, " 622 bool hasTo = false;
577 "Changes.date FROM Changes INNER JOIN Resources " 623 bool hasFilterType = false;
578 "ON Changes.internalId = Resources.internalId WHERE seq>${since} ORDER BY seq " + suffix); 624
579 625 if (since > 0)
626 {
627 hasSince = true;
628 filters.push_back("seq>${since}");
629 }
630 if (to != -1)
631 {
632 hasTo = true;
633 filters.push_back("seq<=${to}");
634 }
635 if (changeType != _OrthancPluginChangeType_All)
636 {
637 hasFilterType = true;
638 filters.push_back("changeType=${changeType}");
639 }
640
641 std::string filtersString;
642 if (filters.size() > 0)
643 {
644 Orthanc::Toolbox::JoinStrings(filtersString, filters, " AND ");
645 filtersString = "WHERE " + filtersString;
646 }
647
648 std::string sql;
649 bool returnFirstResults;
650 if (hasTo && !hasSince)
651 {
652 // in this case, we want the largest values but we want them ordered in ascending order
653 sql = "SELECT * FROM (SELECT Changes.seq, Changes.changeType, Changes.resourceType, Resources.publicId, Changes.date "
654 "FROM Changes INNER JOIN Resources "
655 "ON Changes.internalId = Resources.internalId " + filtersString + " ORDER BY seq DESC " + limitSuffix +
656 ") AS FilteredChanges ORDER BY seq ASC";
657
658 returnFirstResults = false;
659 }
660 else
661 {
662 // default query: we want the smallest values ordered in ascending order
663 sql = "SELECT Changes.seq, Changes.changeType, Changes.resourceType, Resources.publicId, "
664 "Changes.date FROM Changes INNER JOIN Resources "
665 "ON Changes.internalId = Resources.internalId " + filtersString + " ORDER BY seq ASC " + limitSuffix;
666 returnFirstResults = true;
667 }
668
669 DatabaseManager::CachedStatement statement(STATEMENT_FROM_HERE_DYNAMIC(sql), manager, sql);
580 statement.SetReadOnly(true); 670 statement.SetReadOnly(true);
671 Dictionary args;
672
581 statement.SetParameterType("limit", ValueType_Integer64); 673 statement.SetParameterType("limit", ValueType_Integer64);
582 statement.SetParameterType("since", ValueType_Integer64); 674 args.SetIntegerValue("limit", limit + 1); // we take limit+1 because we use the +1 to know if "Done" must be set to true
583 675
584 Dictionary args; 676 if (hasSince)
585 args.SetIntegerValue("limit", limit + 1); 677 {
586 args.SetIntegerValue("since", since); 678 statement.SetParameterType("since", ValueType_Integer64);
587 679 args.SetIntegerValue("since", since);
588 ReadChangesInternal(output, done, manager, statement, args, limit); 680 }
681
682 if (hasTo)
683 {
684 statement.SetParameterType("to", ValueType_Integer64);
685 args.SetIntegerValue("to", to);
686 }
687
688 if (hasFilterType)
689 {
690 statement.SetParameterType("changeType", ValueType_Integer64);
691 args.SetIntegerValue("changeType", changeType);
692 }
693
694 ReadChangesInternal(output, done, manager, statement, args, limit, returnFirstResults);
589 } 695 }
590 696
591 697
592 void IndexBackend::GetChildrenInternalId(std::list<int64_t>& target /*out*/, 698 void IndexBackend::GetChildrenInternalId(std::list<int64_t>& target /*out*/,
593 DatabaseManager& manager, 699 DatabaseManager& manager,
683 statement.SetReadOnly(true); 789 statement.SetReadOnly(true);
684 790
685 Dictionary args; 791 Dictionary args;
686 792
687 bool done; // Ignored 793 bool done; // Ignored
688 ReadChangesInternal(output, done, manager, statement, args, 1); 794 ReadChangesInternal(output, done, manager, statement, args, 1, true);
689 } 795 }
690 796
691 797
692 /* Use GetOutput().AnswerExportedResource() */ 798 /* Use GetOutput().AnswerExportedResource() */
693 void IndexBackend::GetLastExportedResource(IDatabaseBackendOutput& output, 799 void IndexBackend::GetLastExportedResource(IDatabaseBackendOutput& output,