comparison OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp @ 5553:28cc06e4859a large-queries

Added ExtendedApiV1: /changes
author Alain Mazy <am@orthanc.team>
date Thu, 11 Apr 2024 19:02:20 +0200
parents 0d0f8788884a
children 3765085693e5
comparison
equal deleted inserted replaced
5549:dcbf0c776945 5553:28cc06e4859a
231 231
232 232
233 void GetChangesInternal(std::list<ServerIndexChange>& target, 233 void GetChangesInternal(std::list<ServerIndexChange>& target,
234 bool& done, 234 bool& done,
235 SQLite::Statement& s, 235 SQLite::Statement& s,
236 uint32_t limit) 236 uint32_t limit,
237 bool returnFirstResults) // the statement usually returns limit+1 results while we only need the limit results -> we need to know which ones to return, the firsts or the lasts
237 { 238 {
238 target.clear(); 239 target.clear();
239 240
240 while (target.size() < limit && s.Step()) 241 while (s.Step())
241 { 242 {
242 int64_t seq = s.ColumnInt64(0); 243 int64_t seq = s.ColumnInt64(0);
243 ChangeType changeType = static_cast<ChangeType>(s.ColumnInt(1)); 244 ChangeType changeType = static_cast<ChangeType>(s.ColumnInt(1));
244 ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(3)); 245 ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(3));
245 const std::string& date = s.ColumnString(4); 246 const std::string& date = s.ColumnString(4);
248 std::string publicId = GetPublicId(internalId); 249 std::string publicId = GetPublicId(internalId);
249 250
250 target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date)); 251 target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date));
251 } 252 }
252 253
253 done = !(target.size() == limit && s.Step()); 254 done = target.size() <= limit; // 'done' means "there are no more other changes of this type in that direction (depending on since/to)"
255
256 // if we have retrieved more changes than requested -> cleanup
257 if (target.size() > limit)
258 {
259 assert(target.size() == limit+1); // the statement should only request 1 element more
260
261 if (returnFirstResults)
262 {
263 target.pop_back();
264 }
265 else
266 {
267 target.pop_front();
268 }
269 }
254 } 270 }
255 271
256 272
257 void GetExportedResourcesInternal(std::list<ExportedResource>& target, 273 void GetExportedResourcesInternal(std::list<ExportedResource>& target,
258 bool& done, 274 bool& done,
538 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/, 554 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/,
539 bool& done /*out*/, 555 bool& done /*out*/,
540 int64_t since, 556 int64_t since,
541 uint32_t limit) ORTHANC_OVERRIDE 557 uint32_t limit) ORTHANC_OVERRIDE
542 { 558 {
543 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?"); 559 GetChanges2(target, done, since, -1, limit, ChangeType_INTERNAL_All);
544 s.BindInt64(0, since); 560 }
545 s.BindInt(1, limit + 1); 561
546 GetChangesInternal(target, done, s, limit); 562 virtual void GetChanges2(std::list<ServerIndexChange>& target /*out*/,
563 bool& done /*out*/,
564 int64_t since,
565 int64_t to,
566 uint32_t limit,
567 ChangeType filterType) ORTHANC_OVERRIDE
568 {
569 std::vector<std::string> filters;
570 bool hasSince = false;
571 bool hasTo = false;
572 bool hasFilterType = false;
573
574 if (since > 0)
575 {
576 hasSince = true;
577 filters.push_back("seq>?");
578 }
579 if (to != -1)
580 {
581 hasTo = true;
582 filters.push_back("seq<=?");
583 }
584 if (filterType != ChangeType_INTERNAL_All)
585 {
586 hasFilterType = true;
587 filters.push_back("changeType=?");
588 }
589
590 std::string filtersString;
591 if (filters.size() > 0)
592 {
593 Toolbox::JoinStrings(filtersString, filters, " AND ");
594 filtersString = "WHERE " + filtersString;
595 }
596
597 std::string sql;
598 bool returnFirstResults;
599 if (hasTo && !hasSince)
600 {
601 // in this case, we want the largest values in the LIMIT clause but we want them ordered in ascending order
602 sql = "SELECT * FROM (SELECT * FROM Changes " + filtersString + " ORDER BY seq DESC LIMIT ?) ORDER BY seq ASC";
603 returnFirstResults = false;
604 }
605 else
606 {
607 // default query: we want the smallest values ordered in ascending order
608 sql = "SELECT * FROM Changes " + filtersString + " ORDER BY seq ASC LIMIT ?";
609 returnFirstResults = true;
610 }
611
612 SQLite::Statement s(db_, SQLITE_FROM_HERE_DYNAMIC(sql), sql);
613
614 int paramCounter = 0;
615 if (hasSince)
616 {
617 s.BindInt64(paramCounter++, since);
618 }
619 if (hasTo)
620 {
621 s.BindInt64(paramCounter++, to);
622 }
623 if (hasFilterType)
624 {
625 s.BindInt(paramCounter++, filterType);
626 }
627 s.BindInt(paramCounter++, limit + 1); // we take limit+1 because we use the +1 to know if "Done" must be set to true
628 GetChangesInternal(target, done, s, limit, returnFirstResults);
547 } 629 }
548 630
549 631
550 virtual void GetChildrenMetadata(std::list<std::string>& target, 632 virtual void GetChildrenMetadata(std::list<std::string>& target,
551 int64_t resourceId, 633 int64_t resourceId,
602 684
603 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE 685 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE
604 { 686 {
605 bool done; // Ignored 687 bool done; // Ignored
606 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"); 688 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1");
607 GetChangesInternal(target, done, s, 1); 689 GetChangesInternal(target, done, s, 1, true);
608 } 690 }
609 691
610 692
611 int64_t GetLastChangeIndex() ORTHANC_OVERRIDE 693 int64_t GetLastChangeIndex() ORTHANC_OVERRIDE
612 { 694 {
1325 version_(0) 1407 version_(0)
1326 { 1408 {
1327 // TODO: implement revisions in SQLite 1409 // TODO: implement revisions in SQLite
1328 dbCapabilities_.SetFlushToDisk(true); 1410 dbCapabilities_.SetFlushToDisk(true);
1329 dbCapabilities_.SetLabelsSupport(true); 1411 dbCapabilities_.SetLabelsSupport(true);
1412 dbCapabilities_.SetHasExtendedApiV1(true);
1330 db_.Open(path); 1413 db_.Open(path);
1331 } 1414 }
1332 1415
1333 1416
1334 SQLiteDatabaseWrapper::SQLiteDatabaseWrapper() : 1417 SQLiteDatabaseWrapper::SQLiteDatabaseWrapper() :
1337 version_(0) 1420 version_(0)
1338 { 1421 {
1339 // TODO: implement revisions in SQLite 1422 // TODO: implement revisions in SQLite
1340 dbCapabilities_.SetFlushToDisk(true); 1423 dbCapabilities_.SetFlushToDisk(true);
1341 dbCapabilities_.SetLabelsSupport(true); 1424 dbCapabilities_.SetLabelsSupport(true);
1425 dbCapabilities_.SetHasExtendedApiV1(true);
1342 db_.OpenInMemory(); 1426 db_.OpenInMemory();
1343 } 1427 }
1344 1428
1345 SQLiteDatabaseWrapper::~SQLiteDatabaseWrapper() 1429 SQLiteDatabaseWrapper::~SQLiteDatabaseWrapper()
1346 { 1430 {