comparison OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.cpp @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.cpp@94f4a18a79cc
children cd363608551a
comparison
equal deleted inserted replaced
4043:6c6239aec462 4044:d25f4c0fa160
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "PrecompiledHeadersServer.h"
35 #include "DatabaseWrapperBase.h"
36
37 #include <stdio.h>
38 #include <memory>
39
40 namespace Orthanc
41 {
42 void DatabaseWrapperBase::SetGlobalProperty(GlobalProperty property,
43 const std::string& value)
44 {
45 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)");
46 s.BindInt(0, property);
47 s.BindString(1, value);
48 s.Run();
49 }
50
51 bool DatabaseWrapperBase::LookupGlobalProperty(std::string& target,
52 GlobalProperty property)
53 {
54 SQLite::Statement s(db_, SQLITE_FROM_HERE,
55 "SELECT value FROM GlobalProperties WHERE property=?");
56 s.BindInt(0, property);
57
58 if (!s.Step())
59 {
60 return false;
61 }
62 else
63 {
64 target = s.ColumnString(0);
65 return true;
66 }
67 }
68
69 int64_t DatabaseWrapperBase::CreateResource(const std::string& publicId,
70 ResourceType type)
71 {
72 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)");
73 s.BindInt(0, type);
74 s.BindString(1, publicId);
75 s.Run();
76 return db_.GetLastInsertRowId();
77 }
78
79 bool DatabaseWrapperBase::LookupResource(int64_t& id,
80 ResourceType& type,
81 const std::string& publicId)
82 {
83 SQLite::Statement s(db_, SQLITE_FROM_HERE,
84 "SELECT internalId, resourceType FROM Resources WHERE publicId=?");
85 s.BindString(0, publicId);
86
87 if (!s.Step())
88 {
89 return false;
90 }
91 else
92 {
93 id = s.ColumnInt(0);
94 type = static_cast<ResourceType>(s.ColumnInt(1));
95
96 // Check whether there is a single resource with this public id
97 assert(!s.Step());
98
99 return true;
100 }
101 }
102
103 ErrorCode DatabaseWrapperBase::LookupParent(bool& found,
104 int64_t& parentId,
105 int64_t resourceId)
106 {
107 SQLite::Statement s(db_, SQLITE_FROM_HERE,
108 "SELECT parentId FROM Resources WHERE internalId=?");
109 s.BindInt64(0, resourceId);
110
111 if (!s.Step())
112 {
113 return ErrorCode_UnknownResource;
114 }
115
116 if (s.ColumnIsNull(0))
117 {
118 found = false;
119 }
120 else
121 {
122 found = true;
123 parentId = s.ColumnInt(0);
124 }
125
126 return ErrorCode_Success;
127 }
128
129 bool DatabaseWrapperBase::GetPublicId(std::string& result,
130 int64_t resourceId)
131 {
132 SQLite::Statement s(db_, SQLITE_FROM_HERE,
133 "SELECT publicId FROM Resources WHERE internalId=?");
134 s.BindInt64(0, resourceId);
135
136 if (!s.Step())
137 {
138 return false;
139 }
140 else
141 {
142 result = s.ColumnString(0);
143 return true;
144 }
145 }
146
147
148 ErrorCode DatabaseWrapperBase::GetResourceType(ResourceType& result,
149 int64_t resourceId)
150 {
151 SQLite::Statement s(db_, SQLITE_FROM_HERE,
152 "SELECT resourceType FROM Resources WHERE internalId=?");
153 s.BindInt64(0, resourceId);
154
155 if (s.Step())
156 {
157 result = static_cast<ResourceType>(s.ColumnInt(0));
158 return ErrorCode_Success;
159 }
160 else
161 {
162 return ErrorCode_UnknownResource;
163 }
164 }
165
166
167 void DatabaseWrapperBase::AttachChild(int64_t parent,
168 int64_t child)
169 {
170 SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?");
171 s.BindInt64(0, parent);
172 s.BindInt64(1, child);
173 s.Run();
174 }
175
176
177 void DatabaseWrapperBase::SetMetadata(int64_t id,
178 MetadataType type,
179 const std::string& value)
180 {
181 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)");
182 s.BindInt64(0, id);
183 s.BindInt(1, type);
184 s.BindString(2, value);
185 s.Run();
186 }
187
188 void DatabaseWrapperBase::DeleteMetadata(int64_t id,
189 MetadataType type)
190 {
191 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Metadata WHERE id=? and type=?");
192 s.BindInt64(0, id);
193 s.BindInt(1, type);
194 s.Run();
195 }
196
197 bool DatabaseWrapperBase::LookupMetadata(std::string& target,
198 int64_t id,
199 MetadataType type)
200 {
201 SQLite::Statement s(db_, SQLITE_FROM_HERE,
202 "SELECT value FROM Metadata WHERE id=? AND type=?");
203 s.BindInt64(0, id);
204 s.BindInt(1, type);
205
206 if (!s.Step())
207 {
208 return false;
209 }
210 else
211 {
212 target = s.ColumnString(0);
213 return true;
214 }
215 }
216
217 void DatabaseWrapperBase::ListAvailableMetadata(std::list<MetadataType>& target,
218 int64_t id)
219 {
220 target.clear();
221
222 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT type FROM Metadata WHERE id=?");
223 s.BindInt64(0, id);
224
225 while (s.Step())
226 {
227 target.push_back(static_cast<MetadataType>(s.ColumnInt(0)));
228 }
229 }
230
231
232 void DatabaseWrapperBase::AddAttachment(int64_t id,
233 const FileInfo& attachment)
234 {
235 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
236 s.BindInt64(0, id);
237 s.BindInt(1, attachment.GetContentType());
238 s.BindString(2, attachment.GetUuid());
239 s.BindInt64(3, attachment.GetCompressedSize());
240 s.BindInt64(4, attachment.GetUncompressedSize());
241 s.BindInt(5, attachment.GetCompressionType());
242 s.BindString(6, attachment.GetUncompressedMD5());
243 s.BindString(7, attachment.GetCompressedMD5());
244 s.Run();
245 }
246
247
248 void DatabaseWrapperBase::DeleteAttachment(int64_t id,
249 FileContentType attachment)
250 {
251 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM AttachedFiles WHERE id=? AND fileType=?");
252 s.BindInt64(0, id);
253 s.BindInt(1, attachment);
254 s.Run();
255 }
256
257
258
259 void DatabaseWrapperBase::ListAvailableAttachments(std::list<FileContentType>& target,
260 int64_t id)
261 {
262 target.clear();
263
264 SQLite::Statement s(db_, SQLITE_FROM_HERE,
265 "SELECT fileType FROM AttachedFiles WHERE id=?");
266 s.BindInt64(0, id);
267
268 while (s.Step())
269 {
270 target.push_back(static_cast<FileContentType>(s.ColumnInt(0)));
271 }
272 }
273
274 bool DatabaseWrapperBase::LookupAttachment(FileInfo& attachment,
275 int64_t id,
276 FileContentType contentType)
277 {
278 SQLite::Statement s(db_, SQLITE_FROM_HERE,
279 "SELECT uuid, uncompressedSize, compressionType, compressedSize, uncompressedMD5, compressedMD5 FROM AttachedFiles WHERE id=? AND fileType=?");
280 s.BindInt64(0, id);
281 s.BindInt(1, contentType);
282
283 if (!s.Step())
284 {
285 return false;
286 }
287 else
288 {
289 attachment = FileInfo(s.ColumnString(0),
290 contentType,
291 s.ColumnInt64(1),
292 s.ColumnString(4),
293 static_cast<CompressionType>(s.ColumnInt(2)),
294 s.ColumnInt64(3),
295 s.ColumnString(5));
296 return true;
297 }
298 }
299
300
301 void DatabaseWrapperBase::ClearMainDicomTags(int64_t id)
302 {
303 {
304 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM DicomIdentifiers WHERE id=?");
305 s.BindInt64(0, id);
306 s.Run();
307 }
308
309 {
310 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM MainDicomTags WHERE id=?");
311 s.BindInt64(0, id);
312 s.Run();
313 }
314 }
315
316
317 void DatabaseWrapperBase::SetMainDicomTag(int64_t id,
318 const DicomTag& tag,
319 const std::string& value)
320 {
321 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)");
322 s.BindInt64(0, id);
323 s.BindInt(1, tag.GetGroup());
324 s.BindInt(2, tag.GetElement());
325 s.BindString(3, value);
326 s.Run();
327 }
328
329
330 void DatabaseWrapperBase::SetIdentifierTag(int64_t id,
331 const DicomTag& tag,
332 const std::string& value)
333 {
334 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)");
335 s.BindInt64(0, id);
336 s.BindInt(1, tag.GetGroup());
337 s.BindInt(2, tag.GetElement());
338 s.BindString(3, value);
339 s.Run();
340 }
341
342
343 void DatabaseWrapperBase::GetMainDicomTags(DicomMap& map,
344 int64_t id)
345 {
346 map.Clear();
347
348 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?");
349 s.BindInt64(0, id);
350 while (s.Step())
351 {
352 map.SetValue(s.ColumnInt(1),
353 s.ColumnInt(2),
354 s.ColumnString(3), false);
355 }
356 }
357
358
359
360 void DatabaseWrapperBase::GetChildrenPublicId(std::list<std::string>& target,
361 int64_t id)
362 {
363 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b "
364 "WHERE a.parentId = b.internalId AND b.internalId = ?");
365 s.BindInt64(0, id);
366
367 target.clear();
368
369 while (s.Step())
370 {
371 target.push_back(s.ColumnString(0));
372 }
373 }
374
375
376 void DatabaseWrapperBase::GetChildrenInternalId(std::list<int64_t>& target,
377 int64_t id)
378 {
379 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.internalId FROM Resources AS a, Resources AS b "
380 "WHERE a.parentId = b.internalId AND b.internalId = ?");
381 s.BindInt64(0, id);
382
383 target.clear();
384
385 while (s.Step())
386 {
387 target.push_back(s.ColumnInt64(0));
388 }
389 }
390
391
392 void DatabaseWrapperBase::LogChange(int64_t internalId,
393 const ServerIndexChange& change)
394 {
395 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Changes VALUES(NULL, ?, ?, ?, ?)");
396 s.BindInt(0, change.GetChangeType());
397 s.BindInt64(1, internalId);
398 s.BindInt(2, change.GetResourceType());
399 s.BindString(3, change.GetDate());
400 s.Run();
401 }
402
403
404 ErrorCode DatabaseWrapperBase::GetChangesInternal(std::list<ServerIndexChange>& target,
405 bool& done,
406 SQLite::Statement& s,
407 uint32_t maxResults)
408 {
409 target.clear();
410
411 while (target.size() < maxResults && s.Step())
412 {
413 int64_t seq = s.ColumnInt64(0);
414 ChangeType changeType = static_cast<ChangeType>(s.ColumnInt(1));
415 ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(3));
416 const std::string& date = s.ColumnString(4);
417
418 int64_t internalId = s.ColumnInt64(2);
419 std::string publicId;
420 if (!GetPublicId(publicId, internalId))
421 {
422 return ErrorCode_UnknownResource;
423 }
424
425 target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date));
426 }
427
428 done = !(target.size() == maxResults && s.Step());
429 return ErrorCode_Success;
430 }
431
432
433 ErrorCode DatabaseWrapperBase::GetChanges(std::list<ServerIndexChange>& target,
434 bool& done,
435 int64_t since,
436 uint32_t maxResults)
437 {
438 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?");
439 s.BindInt64(0, since);
440 s.BindInt(1, maxResults + 1);
441 return GetChangesInternal(target, done, s, maxResults);
442 }
443
444 ErrorCode DatabaseWrapperBase::GetLastChange(std::list<ServerIndexChange>& target)
445 {
446 bool done; // Ignored
447 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1");
448 return GetChangesInternal(target, done, s, 1);
449 }
450
451
452 void DatabaseWrapperBase::LogExportedResource(const ExportedResource& resource)
453 {
454 SQLite::Statement s(db_, SQLITE_FROM_HERE,
455 "INSERT INTO ExportedResources VALUES(NULL, ?, ?, ?, ?, ?, ?, ?, ?)");
456
457 s.BindInt(0, resource.GetResourceType());
458 s.BindString(1, resource.GetPublicId());
459 s.BindString(2, resource.GetModality());
460 s.BindString(3, resource.GetPatientId());
461 s.BindString(4, resource.GetStudyInstanceUid());
462 s.BindString(5, resource.GetSeriesInstanceUid());
463 s.BindString(6, resource.GetSopInstanceUid());
464 s.BindString(7, resource.GetDate());
465 s.Run();
466 }
467
468
469 void DatabaseWrapperBase::GetExportedResourcesInternal(std::list<ExportedResource>& target,
470 bool& done,
471 SQLite::Statement& s,
472 uint32_t maxResults)
473 {
474 target.clear();
475
476 while (target.size() < maxResults && s.Step())
477 {
478 int64_t seq = s.ColumnInt64(0);
479 ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(1));
480 std::string publicId = s.ColumnString(2);
481
482 ExportedResource resource(seq,
483 resourceType,
484 publicId,
485 s.ColumnString(3), // modality
486 s.ColumnString(8), // date
487 s.ColumnString(4), // patient ID
488 s.ColumnString(5), // study instance UID
489 s.ColumnString(6), // series instance UID
490 s.ColumnString(7)); // sop instance UID
491
492 target.push_back(resource);
493 }
494
495 done = !(target.size() == maxResults && s.Step());
496 }
497
498
499 void DatabaseWrapperBase::GetExportedResources(std::list<ExportedResource>& target,
500 bool& done,
501 int64_t since,
502 uint32_t maxResults)
503 {
504 SQLite::Statement s(db_, SQLITE_FROM_HERE,
505 "SELECT * FROM ExportedResources WHERE seq>? ORDER BY seq LIMIT ?");
506 s.BindInt64(0, since);
507 s.BindInt(1, maxResults + 1);
508 GetExportedResourcesInternal(target, done, s, maxResults);
509 }
510
511
512 void DatabaseWrapperBase::GetLastExportedResource(std::list<ExportedResource>& target)
513 {
514 bool done; // Ignored
515 SQLite::Statement s(db_, SQLITE_FROM_HERE,
516 "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1");
517 GetExportedResourcesInternal(target, done, s, 1);
518 }
519
520
521
522 uint64_t DatabaseWrapperBase::GetTotalCompressedSize()
523 {
524 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(compressedSize) FROM AttachedFiles");
525 s.Run();
526 return static_cast<uint64_t>(s.ColumnInt64(0));
527 }
528
529
530 uint64_t DatabaseWrapperBase::GetTotalUncompressedSize()
531 {
532 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(uncompressedSize) FROM AttachedFiles");
533 s.Run();
534 return static_cast<uint64_t>(s.ColumnInt64(0));
535 }
536
537 void DatabaseWrapperBase::GetAllInternalIds(std::list<int64_t>& target,
538 ResourceType resourceType)
539 {
540 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT internalId FROM Resources WHERE resourceType=?");
541 s.BindInt(0, resourceType);
542
543 target.clear();
544 while (s.Step())
545 {
546 target.push_back(s.ColumnInt64(0));
547 }
548 }
549
550
551 void DatabaseWrapperBase::GetAllPublicIds(std::list<std::string>& target,
552 ResourceType resourceType)
553 {
554 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=?");
555 s.BindInt(0, resourceType);
556
557 target.clear();
558 while (s.Step())
559 {
560 target.push_back(s.ColumnString(0));
561 }
562 }
563
564 void DatabaseWrapperBase::GetAllPublicIds(std::list<std::string>& target,
565 ResourceType resourceType,
566 size_t since,
567 size_t limit)
568 {
569 if (limit == 0)
570 {
571 target.clear();
572 return;
573 }
574
575 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=? LIMIT ? OFFSET ?");
576 s.BindInt(0, resourceType);
577 s.BindInt64(1, limit);
578 s.BindInt64(2, since);
579
580 target.clear();
581 while (s.Step())
582 {
583 target.push_back(s.ColumnString(0));
584 }
585 }
586
587
588 uint64_t DatabaseWrapperBase::GetResourceCount(ResourceType resourceType)
589 {
590 SQLite::Statement s(db_, SQLITE_FROM_HERE,
591 "SELECT COUNT(*) FROM Resources WHERE resourceType=?");
592 s.BindInt(0, resourceType);
593
594 if (!s.Step())
595 {
596 return 0;
597 }
598 else
599 {
600 int64_t c = s.ColumnInt(0);
601 assert(!s.Step());
602 return c;
603 }
604 }
605
606
607 bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId)
608 {
609 SQLite::Statement s(db_, SQLITE_FROM_HERE,
610 "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1");
611
612 if (!s.Step())
613 {
614 // No patient remaining or all the patients are protected
615 return false;
616 }
617 else
618 {
619 internalId = s.ColumnInt(0);
620 return true;
621 }
622 }
623
624 bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId,
625 int64_t patientIdToAvoid)
626 {
627 SQLite::Statement s(db_, SQLITE_FROM_HERE,
628 "SELECT patientId FROM PatientRecyclingOrder "
629 "WHERE patientId != ? ORDER BY seq ASC LIMIT 1");
630 s.BindInt64(0, patientIdToAvoid);
631
632 if (!s.Step())
633 {
634 // No patient remaining or all the patients are protected
635 return false;
636 }
637 else
638 {
639 internalId = s.ColumnInt(0);
640 return true;
641 }
642 }
643
644 bool DatabaseWrapperBase::IsProtectedPatient(int64_t internalId)
645 {
646 SQLite::Statement s(db_, SQLITE_FROM_HERE,
647 "SELECT * FROM PatientRecyclingOrder WHERE patientId = ?");
648 s.BindInt64(0, internalId);
649 return !s.Step();
650 }
651
652 void DatabaseWrapperBase::SetProtectedPatient(int64_t internalId,
653 bool isProtected)
654 {
655 if (isProtected)
656 {
657 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM PatientRecyclingOrder WHERE patientId=?");
658 s.BindInt64(0, internalId);
659 s.Run();
660 }
661 else if (IsProtectedPatient(internalId))
662 {
663 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO PatientRecyclingOrder VALUES(NULL, ?)");
664 s.BindInt64(0, internalId);
665 s.Run();
666 }
667 else
668 {
669 // Nothing to do: The patient is already unprotected
670 }
671 }
672
673
674
675 bool DatabaseWrapperBase::IsExistingResource(int64_t internalId)
676 {
677 SQLite::Statement s(db_, SQLITE_FROM_HERE,
678 "SELECT * FROM Resources WHERE internalId=?");
679 s.BindInt64(0, internalId);
680 return s.Step();
681 }
682
683
684
685 void DatabaseWrapperBase::LookupIdentifier(std::list<int64_t>& target,
686 ResourceType level,
687 const DicomTag& tag,
688 IdentifierConstraintType type,
689 const std::string& value)
690 {
691 static const char* COMMON = ("SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE "
692 "d.id = r.internalId AND r.resourceType=? AND "
693 "d.tagGroup=? AND d.tagElement=? AND ");
694
695 std::auto_ptr<SQLite::Statement> s;
696
697 switch (type)
698 {
699 case IdentifierConstraintType_GreaterOrEqual:
700 s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value>=?"));
701 break;
702
703 case IdentifierConstraintType_SmallerOrEqual:
704 s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value<=?"));
705 break;
706
707 case IdentifierConstraintType_Wildcard:
708 s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value GLOB ?"));
709 break;
710
711 case IdentifierConstraintType_Equal:
712 default:
713 s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value=?"));
714 break;
715 }
716
717 assert(s.get() != NULL);
718
719 s->BindInt(0, level);
720 s->BindInt(1, tag.GetGroup());
721 s->BindInt(2, tag.GetElement());
722 s->BindString(3, value);
723
724 target.clear();
725
726 while (s->Step())
727 {
728 target.push_back(s->ColumnInt64(0));
729 }
730 }
731
732
733 void DatabaseWrapperBase::LookupIdentifierRange(std::list<int64_t>& target,
734 ResourceType level,
735 const DicomTag& tag,
736 const std::string& start,
737 const std::string& end)
738 {
739 SQLite::Statement statement(db_, SQLITE_FROM_HERE,
740 "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE "
741 "d.id = r.internalId AND r.resourceType=? AND "
742 "d.tagGroup=? AND d.tagElement=? AND d.value>=? AND d.value<=?");
743
744 statement.BindInt(0, level);
745 statement.BindInt(1, tag.GetGroup());
746 statement.BindInt(2, tag.GetElement());
747 statement.BindString(3, start);
748 statement.BindString(4, end);
749
750 target.clear();
751
752 while (statement.Step())
753 {
754 target.push_back(statement.ColumnInt64(0));
755 }
756 }
757 }