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-2021 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 "../../../Sources/PrecompiledHeadersServer.h"
35 #include "DatabaseWrapperBase.h"
36 
37 #include <stdio.h>
38 #include <memory>
39 
40 namespace Orthanc
41 {
SetGlobalProperty(GlobalProperty property,const std::string & value)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 
LookupGlobalProperty(std::string & target,GlobalProperty property)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 
CreateResource(const std::string & publicId,ResourceType type)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 
LookupResource(int64_t & id,ResourceType & type,const std::string & publicId)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 
LookupParent(bool & found,int64_t & parentId,int64_t resourceId)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 
GetPublicId(std::string & result,int64_t resourceId)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 
GetResourceType(ResourceType & result,int64_t resourceId)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 
AttachChild(int64_t parent,int64_t child)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 
SetMetadata(int64_t id,MetadataType type,const std::string & value)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 
DeleteMetadata(int64_t id,MetadataType type)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 
LookupMetadata(std::string & target,int64_t id,MetadataType type)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 
ListAvailableMetadata(std::list<MetadataType> & target,int64_t id)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 
AddAttachment(int64_t id,const FileInfo & attachment)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 
DeleteAttachment(int64_t id,FileContentType attachment)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 
ListAvailableAttachments(std::list<FileContentType> & target,int64_t id)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 
LookupAttachment(FileInfo & attachment,int64_t id,FileContentType contentType)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 
ClearMainDicomTags(int64_t id)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 
SetMainDicomTag(int64_t id,const DicomTag & tag,const std::string & value)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 
SetIdentifierTag(int64_t id,const DicomTag & tag,const std::string & value)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 
GetMainDicomTags(DicomMap & map,int64_t id)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 
GetChildrenPublicId(std::list<std::string> & target,int64_t id)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 
GetChildrenInternalId(std::list<int64_t> & target,int64_t id)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 
LogChange(int64_t internalId,const ServerIndexChange & change)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 
GetChangesInternal(std::list<ServerIndexChange> & target,bool & done,SQLite::Statement & s,uint32_t maxResults)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 
GetChanges(std::list<ServerIndexChange> & target,bool & done,int64_t since,uint32_t maxResults)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 
GetLastChange(std::list<ServerIndexChange> & target)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 
LogExportedResource(const ExportedResource & resource)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 
GetExportedResourcesInternal(std::list<ExportedResource> & target,bool & done,SQLite::Statement & s,uint32_t maxResults)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 
GetExportedResources(std::list<ExportedResource> & target,bool & done,int64_t since,uint32_t maxResults)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 
GetLastExportedResource(std::list<ExportedResource> & target)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 
GetTotalCompressedSize()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 
GetTotalUncompressedSize()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 
GetAllInternalIds(std::list<int64_t> & target,ResourceType resourceType)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 
GetAllPublicIds(std::list<std::string> & target,ResourceType resourceType)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 
GetAllPublicIds(std::list<std::string> & target,ResourceType resourceType,size_t since,size_t limit)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 
GetResourceCount(ResourceType resourceType)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 
SelectPatientToRecycle(int64_t & internalId)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 
SelectPatientToRecycle(int64_t & internalId,int64_t patientIdToAvoid)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 
IsProtectedPatient(int64_t internalId)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 
SetProtectedPatient(int64_t internalId,bool isProtected)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 
IsExistingResource(int64_t internalId)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 
LookupIdentifier(std::list<int64_t> & target,ResourceType level,const DicomTag & tag,IdentifierConstraintType type,const std::string & value)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 
LookupIdentifierRange(std::list<int64_t> & target,ResourceType level,const DicomTag & tag,const std::string & start,const std::string & end)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 }
758