0
|
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-2018 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 Affero General Public License
|
|
9 * as published by the Free Software Foundation, either version 3 of
|
|
10 * the License, or (at your option) any later version.
|
|
11 *
|
|
12 * This program is distributed in the hope that it will be useful, but
|
|
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15 * Affero General Public License for more details.
|
|
16 *
|
|
17 * You should have received a copy of the GNU Affero General Public License
|
|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19 **/
|
|
20
|
|
21
|
|
22 #include "IndexBackend.h"
|
|
23
|
|
24 #include "../Common/BinaryStringValue.h"
|
|
25 #include "../Common/Integer64Value.h"
|
|
26 #include "../Common/Utf8StringValue.h"
|
|
27 #include "GlobalProperties.h"
|
|
28
|
|
29 #include <Core/Logging.h>
|
|
30 #include <Core/OrthancException.h>
|
|
31 #include <OrthancServer/ServerEnumerations.h>
|
|
32
|
|
33
|
|
34 namespace OrthancDatabases
|
|
35 {
|
|
36 static std::string ConvertWildcardToLike(const std::string& query)
|
|
37 {
|
|
38 std::string s = query;
|
|
39
|
|
40 for (size_t i = 0; i < s.size(); i++)
|
|
41 {
|
|
42 if (s[i] == '*')
|
|
43 {
|
|
44 s[i] = '%';
|
|
45 }
|
|
46 else if (s[i] == '?')
|
|
47 {
|
|
48 s[i] = '_';
|
|
49 }
|
|
50 }
|
|
51
|
|
52 return s;
|
|
53 }
|
|
54
|
|
55
|
|
56 int64_t IndexBackend::ReadInteger64(const DatabaseManager::CachedStatement& statement,
|
|
57 size_t field)
|
|
58 {
|
|
59 if (statement.IsDone())
|
|
60 {
|
|
61 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
|
|
62 }
|
|
63
|
|
64 const IValue& value = statement.GetResultField(field);
|
|
65
|
|
66 switch (value.GetType())
|
|
67 {
|
|
68 case ValueType_Integer64:
|
|
69 return dynamic_cast<const Integer64Value&>(value).GetValue();
|
|
70
|
|
71 default:
|
|
72 //LOG(ERROR) << value.Format();
|
|
73 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
74 }
|
|
75 }
|
|
76
|
|
77
|
|
78 int32_t IndexBackend::ReadInteger32(const DatabaseManager::CachedStatement& statement,
|
|
79 size_t field)
|
|
80 {
|
|
81 if (statement.IsDone())
|
|
82 {
|
|
83 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
|
|
84 }
|
|
85
|
|
86 int64_t value = ReadInteger64(statement, field);
|
|
87
|
|
88 if (value != static_cast<int64_t>(static_cast<int32_t>(value)))
|
|
89 {
|
|
90 LOG(ERROR) << "Integer overflow";
|
|
91 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
92 }
|
|
93 else
|
|
94 {
|
|
95 return static_cast<int32_t>(value);
|
|
96 }
|
|
97 }
|
|
98
|
|
99
|
|
100 std::string IndexBackend::ReadString(const DatabaseManager::CachedStatement& statement,
|
|
101 size_t field)
|
|
102 {
|
|
103 const IValue& value = statement.GetResultField(field);
|
|
104
|
|
105 switch (value.GetType())
|
|
106 {
|
|
107 case ValueType_BinaryString:
|
|
108 return dynamic_cast<const BinaryStringValue&>(value).GetContent();
|
|
109
|
|
110 case ValueType_Utf8String:
|
|
111 return dynamic_cast<const Utf8StringValue&>(value).GetContent();
|
|
112
|
|
113 default:
|
|
114 //LOG(ERROR) << value.Format();
|
|
115 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
116 }
|
|
117 }
|
|
118
|
|
119
|
|
120 template <typename T>
|
|
121 void IndexBackend::ReadListOfIntegers(std::list<T>& target,
|
|
122 DatabaseManager::CachedStatement& statement,
|
|
123 const Dictionary& args)
|
|
124 {
|
|
125 statement.Execute(args);
|
|
126
|
|
127 target.clear();
|
|
128
|
|
129 if (!statement.IsDone())
|
|
130 {
|
|
131 if (statement.GetResultFieldsCount() != 1)
|
|
132 {
|
|
133 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
134 }
|
|
135
|
|
136 statement.SetResultFieldType(0, ValueType_Integer64);
|
|
137
|
|
138 while (!statement.IsDone())
|
|
139 {
|
|
140 target.push_back(static_cast<T>(ReadInteger64(statement, 0)));
|
|
141 statement.Next();
|
|
142 }
|
|
143 }
|
|
144 }
|
|
145
|
|
146
|
|
147 void IndexBackend::ReadListOfStrings(std::list<std::string>& target,
|
|
148 DatabaseManager::CachedStatement& statement,
|
|
149 const Dictionary& args)
|
|
150 {
|
|
151 statement.Execute(args);
|
|
152
|
|
153 target.clear();
|
|
154
|
|
155 if (!statement.IsDone())
|
|
156 {
|
|
157 if (statement.GetResultFieldsCount() != 1)
|
|
158 {
|
|
159 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
160 }
|
|
161
|
|
162 while (!statement.IsDone())
|
|
163 {
|
|
164 target.push_back(ReadString(statement, 0));
|
|
165 statement.Next();
|
|
166 }
|
|
167 }
|
|
168 }
|
|
169
|
|
170
|
|
171 void IndexBackend::ReadChangesInternal(bool& done,
|
|
172 DatabaseManager::CachedStatement& statement,
|
|
173 const Dictionary& args,
|
|
174 uint32_t maxResults)
|
|
175 {
|
|
176 statement.Execute(args);
|
|
177
|
|
178 uint32_t count = 0;
|
|
179
|
|
180 while (count < maxResults &&
|
|
181 !statement.IsDone())
|
|
182 {
|
|
183 GetOutput().AnswerChange(
|
|
184 ReadInteger64(statement, 0),
|
|
185 ReadInteger32(statement, 1),
|
|
186 static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 3)),
|
|
187 GetPublicId(ReadInteger64(statement, 2)),
|
|
188 ReadString(statement, 4));
|
|
189
|
|
190 statement.Next();
|
|
191 count++;
|
|
192 }
|
|
193
|
|
194 done = (count < maxResults ||
|
|
195 statement.IsDone());
|
|
196 }
|
|
197
|
|
198
|
|
199 void IndexBackend::ReadExportedResourcesInternal(bool& done,
|
|
200 DatabaseManager::CachedStatement& statement,
|
|
201 const Dictionary& args,
|
|
202 uint32_t maxResults)
|
|
203 {
|
|
204 statement.Execute(args);
|
|
205
|
|
206 uint32_t count = 0;
|
|
207
|
|
208 while (count < maxResults &&
|
|
209 !statement.IsDone())
|
|
210 {
|
|
211 int64_t seq = ReadInteger64(statement, 0);
|
|
212 OrthancPluginResourceType resourceType =
|
|
213 static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 1));
|
|
214 std::string publicId = ReadString(statement, 2);
|
|
215
|
|
216 GetOutput().AnswerExportedResource(seq,
|
|
217 resourceType,
|
|
218 publicId,
|
|
219 ReadString(statement, 3), // modality
|
|
220 ReadString(statement, 8), // date
|
|
221 ReadString(statement, 4), // patient ID
|
|
222 ReadString(statement, 5), // study instance UID
|
|
223 ReadString(statement, 6), // series instance UID
|
|
224 ReadString(statement, 7)); // sop instance UID
|
|
225
|
|
226 statement.Next();
|
|
227 count++;
|
|
228 }
|
|
229
|
|
230 done = (count < maxResults ||
|
|
231 statement.IsDone());
|
|
232 }
|
|
233
|
|
234
|
|
235 void IndexBackend::ClearDeletedFiles()
|
|
236 {
|
|
237 DatabaseManager::CachedStatement statement(
|
|
238 STATEMENT_FROM_HERE, manager_,
|
|
239 "DELETE FROM DeletedFiles");
|
|
240
|
|
241 statement.Execute();
|
|
242 }
|
|
243
|
|
244
|
|
245 void IndexBackend::ClearDeletedResources()
|
|
246 {
|
|
247 DatabaseManager::CachedStatement statement(
|
|
248 STATEMENT_FROM_HERE, manager_,
|
|
249 "DELETE FROM DeletedResources");
|
|
250
|
|
251 statement.Execute();
|
|
252 }
|
|
253
|
|
254
|
|
255 void IndexBackend::SignalDeletedFiles()
|
|
256 {
|
|
257 DatabaseManager::CachedStatement statement(
|
|
258 STATEMENT_FROM_HERE, manager_,
|
|
259 "SELECT * FROM DeletedFiles");
|
|
260
|
|
261 statement.SetReadOnly(true);
|
|
262 statement.Execute();
|
|
263
|
|
264 while (!statement.IsDone())
|
|
265 {
|
|
266 std::string a = ReadString(statement, 0);
|
|
267 std::string b = ReadString(statement, 5);
|
|
268 std::string c = ReadString(statement, 6);
|
|
269
|
|
270 GetOutput().SignalDeletedAttachment(a.c_str(),
|
|
271 ReadInteger32(statement, 1),
|
|
272 ReadInteger64(statement, 3),
|
|
273 b.c_str(),
|
|
274 ReadInteger32(statement, 4),
|
|
275 ReadInteger64(statement, 2),
|
|
276 c.c_str());
|
|
277
|
|
278 statement.Next();
|
|
279 }
|
|
280 }
|
|
281
|
|
282
|
|
283 void IndexBackend::SignalDeletedResources()
|
|
284 {
|
|
285 DatabaseManager::CachedStatement statement(
|
|
286 STATEMENT_FROM_HERE, manager_,
|
|
287 "SELECT * FROM DeletedResources");
|
|
288
|
|
289 statement.SetReadOnly(true);
|
|
290 statement.Execute();
|
|
291
|
|
292 while (!statement.IsDone())
|
|
293 {
|
|
294 GetOutput().SignalDeletedResource(
|
|
295 ReadString(statement, 1),
|
|
296 static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 0)));
|
|
297
|
|
298 statement.Next();
|
|
299 }
|
|
300 }
|
|
301
|
|
302
|
|
303 IndexBackend::IndexBackend(IDatabaseFactory* factory) :
|
|
304 manager_(factory)
|
|
305 {
|
|
306 }
|
|
307
|
|
308
|
|
309 void IndexBackend::AddAttachment(int64_t id,
|
|
310 const OrthancPluginAttachment& attachment)
|
|
311 {
|
|
312 DatabaseManager::CachedStatement statement(
|
|
313 STATEMENT_FROM_HERE, manager_,
|
|
314 "INSERT INTO AttachedFiles VALUES(${id}, ${type}, ${uuid}, "
|
|
315 "${compressed}, ${uncompressed}, ${compression}, ${hash}, ${hash-compressed})");
|
|
316
|
|
317 statement.SetParameterType("id", ValueType_Integer64);
|
|
318 statement.SetParameterType("type", ValueType_Integer64);
|
|
319 statement.SetParameterType("uuid", ValueType_Utf8String);
|
|
320 statement.SetParameterType("compressed", ValueType_Integer64);
|
|
321 statement.SetParameterType("uncompressed", ValueType_Integer64);
|
|
322 statement.SetParameterType("compression", ValueType_Integer64);
|
|
323 statement.SetParameterType("hash", ValueType_Utf8String);
|
|
324 statement.SetParameterType("hash-compressed", ValueType_Utf8String);
|
|
325
|
|
326 Dictionary args;
|
|
327 args.SetIntegerValue("id", id);
|
|
328 args.SetIntegerValue("type", attachment.contentType);
|
|
329 args.SetUtf8Value("uuid", attachment.uuid);
|
|
330 args.SetIntegerValue("compressed", attachment.compressedSize);
|
|
331 args.SetIntegerValue("uncompressed", attachment.uncompressedSize);
|
|
332 args.SetIntegerValue("compression", attachment.compressionType);
|
|
333 args.SetUtf8Value("hash", attachment.uncompressedHash);
|
|
334 args.SetUtf8Value("hash-compressed", attachment.compressedHash);
|
|
335
|
|
336 statement.Execute(args);
|
|
337 }
|
|
338
|
|
339
|
|
340 void IndexBackend::AttachChild(int64_t parent,
|
|
341 int64_t child)
|
|
342 {
|
|
343 DatabaseManager::CachedStatement statement(
|
|
344 STATEMENT_FROM_HERE, manager_,
|
|
345 "UPDATE Resources SET parentId = ${parent} WHERE internalId = ${child}");
|
|
346
|
|
347 statement.SetParameterType("parent", ValueType_Integer64);
|
|
348 statement.SetParameterType("child", ValueType_Integer64);
|
|
349
|
|
350 Dictionary args;
|
|
351 args.SetIntegerValue("parent", parent);
|
|
352 args.SetIntegerValue("child", child);
|
|
353
|
|
354 statement.Execute(args);
|
|
355 }
|
|
356
|
|
357
|
|
358 void IndexBackend::ClearChanges()
|
|
359 {
|
|
360 DatabaseManager::CachedStatement statement(
|
|
361 STATEMENT_FROM_HERE, manager_,
|
|
362 "DELETE FROM Changes");
|
|
363
|
|
364 statement.Execute();
|
|
365 }
|
|
366
|
|
367
|
|
368 void IndexBackend::ClearExportedResources()
|
|
369 {
|
|
370 DatabaseManager::CachedStatement statement(
|
|
371 STATEMENT_FROM_HERE, manager_,
|
|
372 "DELETE FROM ExportedResources");
|
|
373
|
|
374 statement.Execute();
|
|
375 }
|
|
376
|
|
377
|
|
378 void IndexBackend::DeleteAttachment(int64_t id,
|
|
379 int32_t attachment)
|
|
380 {
|
|
381 ClearDeletedFiles();
|
|
382
|
|
383 {
|
|
384 DatabaseManager::CachedStatement statement(
|
|
385 STATEMENT_FROM_HERE, manager_,
|
|
386 "DELETE FROM AttachedFiles WHERE id=${id} AND fileType=${type}");
|
|
387
|
|
388 statement.SetParameterType("id", ValueType_Integer64);
|
|
389 statement.SetParameterType("type", ValueType_Integer64);
|
|
390
|
|
391 Dictionary args;
|
|
392 args.SetIntegerValue("id", id);
|
|
393 args.SetIntegerValue("type", static_cast<int>(attachment));
|
|
394
|
|
395 statement.Execute(args);
|
|
396 }
|
|
397
|
|
398 SignalDeletedFiles();
|
|
399 }
|
|
400
|
|
401
|
|
402 void IndexBackend::DeleteMetadata(int64_t id,
|
|
403 int32_t metadataType)
|
|
404 {
|
|
405 DatabaseManager::CachedStatement statement(
|
|
406 STATEMENT_FROM_HERE, manager_,
|
|
407 "DELETE FROM Metadata WHERE id=${id} and type=${type}");
|
|
408
|
|
409 statement.SetParameterType("id", ValueType_Integer64);
|
|
410 statement.SetParameterType("type", ValueType_Integer64);
|
|
411
|
|
412 Dictionary args;
|
|
413 args.SetIntegerValue("id", id);
|
|
414 args.SetIntegerValue("type", static_cast<int>(metadataType));
|
|
415
|
|
416 statement.Execute(args);
|
|
417 }
|
|
418
|
|
419
|
|
420 void IndexBackend::DeleteResource(int64_t id)
|
|
421 {
|
|
422 assert(GetDialect() != Dialect_MySQL);
|
|
423
|
|
424 ClearDeletedFiles();
|
|
425 ClearDeletedResources();
|
|
426
|
|
427 {
|
|
428 DatabaseManager::CachedStatement statement(
|
|
429 STATEMENT_FROM_HERE, GetManager(),
|
|
430 "DELETE FROM RemainingAncestor");
|
|
431
|
|
432 statement.Execute();
|
|
433 }
|
|
434
|
|
435 {
|
|
436 DatabaseManager::CachedStatement statement(
|
|
437 STATEMENT_FROM_HERE, GetManager(),
|
|
438 "DELETE FROM Resources WHERE internalId=${id}");
|
|
439
|
|
440 statement.SetParameterType("id", ValueType_Integer64);
|
|
441
|
|
442 Dictionary args;
|
|
443 args.SetIntegerValue("id", id);
|
|
444
|
|
445 statement.Execute(args);
|
|
446 }
|
|
447
|
|
448
|
|
449 {
|
|
450 DatabaseManager::CachedStatement statement(
|
|
451 STATEMENT_FROM_HERE, GetManager(),
|
|
452 "SELECT * FROM RemainingAncestor");
|
|
453
|
|
454 statement.Execute();
|
|
455
|
|
456 if (!statement.IsDone())
|
|
457 {
|
|
458 GetOutput().SignalRemainingAncestor(
|
|
459 ReadString(statement, 1),
|
|
460 static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 0)));
|
|
461
|
|
462 // There is at most 1 remaining ancestor
|
|
463 assert((statement.Next(), statement.IsDone()));
|
|
464 }
|
|
465 }
|
|
466
|
|
467 SignalDeletedFiles();
|
|
468 SignalDeletedResources();
|
|
469 }
|
|
470
|
|
471
|
|
472 void IndexBackend::GetAllInternalIds(std::list<int64_t>& target,
|
|
473 OrthancPluginResourceType resourceType)
|
|
474 {
|
|
475 DatabaseManager::CachedStatement statement(
|
|
476 STATEMENT_FROM_HERE, manager_,
|
|
477 "SELECT internalId FROM Resources WHERE resourceType=${type}");
|
|
478
|
|
479 statement.SetReadOnly(true);
|
|
480 statement.SetParameterType("type", ValueType_Integer64);
|
|
481
|
|
482 Dictionary args;
|
|
483 args.SetIntegerValue("type", static_cast<int>(resourceType));
|
|
484
|
|
485 ReadListOfIntegers<int64_t>(target, statement, args);
|
|
486 }
|
|
487
|
|
488
|
|
489 void IndexBackend::GetAllPublicIds(std::list<std::string>& target,
|
|
490 OrthancPluginResourceType resourceType)
|
|
491 {
|
|
492 DatabaseManager::CachedStatement statement(
|
|
493 STATEMENT_FROM_HERE, manager_,
|
|
494 "SELECT publicId FROM Resources WHERE resourceType=${type}");
|
|
495
|
|
496 statement.SetReadOnly(true);
|
|
497 statement.SetParameterType("type", ValueType_Integer64);
|
|
498
|
|
499 Dictionary args;
|
|
500 args.SetIntegerValue("type", static_cast<int>(resourceType));
|
|
501
|
|
502 ReadListOfStrings(target, statement, args);
|
|
503 }
|
|
504
|
|
505
|
|
506 void IndexBackend::GetAllPublicIds(std::list<std::string>& target,
|
|
507 OrthancPluginResourceType resourceType,
|
|
508 uint64_t since,
|
|
509 uint64_t limit)
|
|
510 {
|
|
511 DatabaseManager::CachedStatement statement(
|
|
512 STATEMENT_FROM_HERE, manager_,
|
|
513 "SELECT publicId FROM (SELECT publicId FROM Resources "
|
|
514 "WHERE resourceType=${type}) AS tmp "
|
|
515 "ORDER BY tmp.publicId LIMIT ${limit} OFFSET ${since}");
|
|
516
|
|
517 statement.SetReadOnly(true);
|
|
518 statement.SetParameterType("type", ValueType_Integer64);
|
|
519 statement.SetParameterType("limit", ValueType_Integer64);
|
|
520 statement.SetParameterType("since", ValueType_Integer64);
|
|
521
|
|
522 Dictionary args;
|
|
523 args.SetIntegerValue("type", static_cast<int>(resourceType));
|
|
524 args.SetIntegerValue("limit", limit);
|
|
525 args.SetIntegerValue("since", since);
|
|
526
|
|
527 ReadListOfStrings(target, statement, args);
|
|
528 }
|
|
529
|
|
530
|
|
531 /* Use GetOutput().AnswerChange() */
|
|
532 void IndexBackend::GetChanges(bool& done /*out*/,
|
|
533 int64_t since,
|
|
534 uint32_t maxResults)
|
|
535 {
|
|
536 DatabaseManager::CachedStatement statement(
|
|
537 STATEMENT_FROM_HERE, manager_,
|
|
538 "SELECT * FROM Changes WHERE seq>${since} ORDER BY seq LIMIT ${limit}");
|
|
539
|
|
540 statement.SetReadOnly(true);
|
|
541 statement.SetParameterType("limit", ValueType_Integer64);
|
|
542 statement.SetParameterType("since", ValueType_Integer64);
|
|
543
|
|
544 Dictionary args;
|
|
545 args.SetIntegerValue("limit", maxResults + 1);
|
|
546 args.SetIntegerValue("since", since);
|
|
547
|
|
548 ReadChangesInternal(done, statement, args, maxResults);
|
|
549 }
|
|
550
|
|
551
|
|
552 void IndexBackend::GetChildrenInternalId(std::list<int64_t>& target /*out*/,
|
|
553 int64_t id)
|
|
554 {
|
|
555 DatabaseManager::CachedStatement statement(
|
|
556 STATEMENT_FROM_HERE, manager_,
|
|
557 "SELECT a.internalId FROM Resources AS a, Resources AS b "
|
|
558 "WHERE a.parentId = b.internalId AND b.internalId = ${id}");
|
|
559
|
|
560 statement.SetReadOnly(true);
|
|
561 statement.SetParameterType("id", ValueType_Integer64);
|
|
562
|
|
563 Dictionary args;
|
|
564 args.SetIntegerValue("id", id);
|
|
565
|
|
566 ReadListOfIntegers<int64_t>(target, statement, args);
|
|
567 }
|
|
568
|
|
569
|
|
570 void IndexBackend::GetChildrenPublicId(std::list<std::string>& target /*out*/,
|
|
571 int64_t id)
|
|
572 {
|
|
573 DatabaseManager::CachedStatement statement(
|
|
574 STATEMENT_FROM_HERE, manager_,
|
|
575 "SELECT a.publicId FROM Resources AS a, Resources AS b "
|
|
576 "WHERE a.parentId = b.internalId AND b.internalId = ${id}");
|
|
577
|
|
578 statement.SetReadOnly(true);
|
|
579 statement.SetParameterType("id", ValueType_Integer64);
|
|
580
|
|
581 Dictionary args;
|
|
582 args.SetIntegerValue("id", id);
|
|
583
|
|
584 ReadListOfStrings(target, statement, args);
|
|
585 }
|
|
586
|
|
587
|
|
588 /* Use GetOutput().AnswerExportedResource() */
|
|
589 void IndexBackend::GetExportedResources(bool& done /*out*/,
|
|
590 int64_t since,
|
|
591 uint32_t maxResults)
|
|
592 {
|
|
593 DatabaseManager::CachedStatement statement(
|
|
594 STATEMENT_FROM_HERE, manager_,
|
|
595 "SELECT * FROM ExportedResources WHERE seq>${since} ORDER BY seq LIMIT ${limit}");
|
|
596
|
|
597 statement.SetReadOnly(true);
|
|
598 statement.SetParameterType("limit", ValueType_Integer64);
|
|
599 statement.SetParameterType("since", ValueType_Integer64);
|
|
600
|
|
601 Dictionary args;
|
|
602 args.SetIntegerValue("limit", maxResults + 1);
|
|
603 args.SetIntegerValue("since", since);
|
|
604
|
|
605 ReadExportedResourcesInternal(done, statement, args, maxResults);
|
|
606 }
|
|
607
|
|
608
|
|
609 /* Use GetOutput().AnswerChange() */
|
|
610 void IndexBackend::GetLastChange()
|
|
611 {
|
|
612 DatabaseManager::CachedStatement statement(
|
|
613 STATEMENT_FROM_HERE, manager_,
|
|
614 "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1");
|
|
615
|
|
616 statement.SetReadOnly(true);
|
|
617
|
|
618 Dictionary args;
|
|
619
|
|
620 bool done; // Ignored
|
|
621 ReadChangesInternal(done, statement, args, 1);
|
|
622 }
|
|
623
|
|
624
|
|
625 /* Use GetOutput().AnswerExportedResource() */
|
|
626 void IndexBackend::GetLastExportedResource()
|
|
627 {
|
|
628 DatabaseManager::CachedStatement statement(
|
|
629 STATEMENT_FROM_HERE, manager_,
|
|
630 "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1");
|
|
631
|
|
632 statement.SetReadOnly(true);
|
|
633
|
|
634 Dictionary args;
|
|
635
|
|
636 bool done; // Ignored
|
|
637 ReadExportedResourcesInternal(done, statement, args, 1);
|
|
638 }
|
|
639
|
|
640
|
|
641 /* Use GetOutput().AnswerDicomTag() */
|
|
642 void IndexBackend::GetMainDicomTags(int64_t id)
|
|
643 {
|
|
644 DatabaseManager::CachedStatement statement(
|
|
645 STATEMENT_FROM_HERE, manager_,
|
|
646 "SELECT * FROM MainDicomTags WHERE id=${id}");
|
|
647
|
|
648 statement.SetReadOnly(true);
|
|
649 statement.SetParameterType("id", ValueType_Integer64);
|
|
650
|
|
651 Dictionary args;
|
|
652 args.SetIntegerValue("id", id);
|
|
653
|
|
654 statement.Execute(args);
|
|
655
|
|
656 while (!statement.IsDone())
|
|
657 {
|
|
658 GetOutput().AnswerDicomTag(static_cast<uint16_t>(ReadInteger64(statement, 1)),
|
|
659 static_cast<uint16_t>(ReadInteger64(statement, 2)),
|
|
660 ReadString(statement, 3));
|
|
661 statement.Next();
|
|
662 }
|
|
663 }
|
|
664
|
|
665
|
|
666 std::string IndexBackend::GetPublicId(int64_t resourceId)
|
|
667 {
|
|
668 DatabaseManager::CachedStatement statement(
|
|
669 STATEMENT_FROM_HERE, manager_,
|
|
670 "SELECT publicId FROM Resources WHERE internalId=${id}");
|
|
671
|
|
672 statement.SetReadOnly(true);
|
|
673 statement.SetParameterType("id", ValueType_Integer64);
|
|
674
|
|
675 Dictionary args;
|
|
676 args.SetIntegerValue("id", resourceId);
|
|
677
|
|
678 statement.Execute(args);
|
|
679
|
|
680 if (statement.IsDone())
|
|
681 {
|
|
682 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
|
|
683 }
|
|
684 else
|
|
685 {
|
|
686 return ReadString(statement, 0);
|
|
687 }
|
|
688 }
|
|
689
|
|
690
|
|
691 uint64_t IndexBackend::GetResourceCount(OrthancPluginResourceType resourceType)
|
|
692 {
|
|
693 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
694
|
|
695 switch (GetDialect())
|
|
696 {
|
|
697 case Dialect_MySQL:
|
|
698 statement.reset(new DatabaseManager::CachedStatement(
|
|
699 STATEMENT_FROM_HERE, GetManager(),
|
|
700 "SELECT CAST(COUNT(*) AS UNSIGNED INT) FROM Resources WHERE resourceType=${type}"));
|
|
701 break;
|
|
702
|
|
703 case Dialect_PostgreSQL:
|
|
704 statement.reset(new DatabaseManager::CachedStatement(
|
|
705 STATEMENT_FROM_HERE, GetManager(),
|
|
706 "SELECT CAST(COUNT(*) AS BIGINT) FROM Resources WHERE resourceType=${type}"));
|
|
707 break;
|
|
708
|
|
709 case Dialect_SQLite:
|
|
710 statement.reset(new DatabaseManager::CachedStatement(
|
|
711 STATEMENT_FROM_HERE, GetManager(),
|
|
712 "SELECT COUNT(*) FROM Resources WHERE resourceType=${type}"));
|
|
713 break;
|
|
714
|
|
715 default:
|
|
716 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
717 }
|
|
718
|
|
719 statement->SetReadOnly(true);
|
|
720 statement->SetParameterType("type", ValueType_Integer64);
|
|
721
|
|
722 Dictionary args;
|
|
723 args.SetIntegerValue("type", resourceType);
|
|
724
|
|
725 statement->Execute(args);
|
|
726
|
|
727 return static_cast<uint64_t>(ReadInteger64(*statement, 0));
|
|
728 }
|
|
729
|
|
730
|
|
731 OrthancPluginResourceType IndexBackend::GetResourceType(int64_t resourceId)
|
|
732 {
|
|
733 DatabaseManager::CachedStatement statement(
|
|
734 STATEMENT_FROM_HERE, manager_,
|
|
735 "SELECT resourceType FROM Resources WHERE internalId=${id}");
|
|
736
|
|
737 statement.SetReadOnly(true);
|
|
738 statement.SetParameterType("id", ValueType_Integer64);
|
|
739
|
|
740 Dictionary args;
|
|
741 args.SetIntegerValue("id", resourceId);
|
|
742
|
|
743 statement.Execute(args);
|
|
744
|
|
745 if (statement.IsDone())
|
|
746 {
|
|
747 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
|
|
748 }
|
|
749 else
|
|
750 {
|
|
751 return static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 0));
|
|
752 }
|
|
753 }
|
|
754
|
|
755
|
|
756 uint64_t IndexBackend::GetTotalCompressedSize()
|
|
757 {
|
|
758 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
759
|
|
760 // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty
|
|
761
|
|
762 switch (GetDialect())
|
|
763 {
|
|
764 case Dialect_MySQL:
|
|
765 statement.reset(new DatabaseManager::CachedStatement(
|
|
766 STATEMENT_FROM_HERE, GetManager(),
|
|
767 "SELECT CAST(COALESCE(SUM(compressedSize), 0) AS UNSIGNED INTEGER) FROM AttachedFiles"));
|
|
768 break;
|
|
769
|
|
770 case Dialect_PostgreSQL:
|
|
771 statement.reset(new DatabaseManager::CachedStatement(
|
|
772 STATEMENT_FROM_HERE, GetManager(),
|
|
773 "SELECT CAST(COALESCE(SUM(compressedSize), 0) AS BIGINT) FROM AttachedFiles"));
|
|
774 break;
|
|
775
|
|
776 case Dialect_SQLite:
|
|
777 statement.reset(new DatabaseManager::CachedStatement(
|
|
778 STATEMENT_FROM_HERE, GetManager(),
|
|
779 "SELECT COALESCE(SUM(compressedSize), 0) FROM AttachedFiles"));
|
|
780 break;
|
|
781
|
|
782 default:
|
|
783 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
784 }
|
|
785
|
|
786 statement->SetReadOnly(true);
|
|
787 statement->Execute();
|
|
788
|
|
789 return static_cast<uint64_t>(ReadInteger64(*statement, 0));
|
|
790 }
|
|
791
|
|
792
|
|
793 uint64_t IndexBackend::GetTotalUncompressedSize()
|
|
794 {
|
|
795 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
796
|
|
797 // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty
|
|
798
|
|
799 switch (GetDialect())
|
|
800 {
|
|
801 case Dialect_MySQL:
|
|
802 statement.reset(new DatabaseManager::CachedStatement(
|
|
803 STATEMENT_FROM_HERE, GetManager(),
|
|
804 "SELECT CAST(COALESCE(SUM(uncompressedSize), 0) AS UNSIGNED INTEGER) FROM AttachedFiles"));
|
|
805 break;
|
|
806
|
|
807 case Dialect_PostgreSQL:
|
|
808 statement.reset(new DatabaseManager::CachedStatement(
|
|
809 STATEMENT_FROM_HERE, GetManager(),
|
|
810 "SELECT CAST(COALESCE(SUM(uncompressedSize), 0) AS BIGINT) FROM AttachedFiles"));
|
|
811 break;
|
|
812
|
|
813 case Dialect_SQLite:
|
|
814 statement.reset(new DatabaseManager::CachedStatement(
|
|
815 STATEMENT_FROM_HERE, GetManager(),
|
|
816 "SELECT COALESCE(SUM(uncompressedSize), 0) FROM AttachedFiles"));
|
|
817 break;
|
|
818
|
|
819 default:
|
|
820 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
821 }
|
|
822
|
|
823 statement->SetReadOnly(true);
|
|
824 statement->Execute();
|
|
825
|
|
826 return static_cast<uint64_t>(ReadInteger64(*statement, 0));
|
|
827 }
|
|
828
|
|
829
|
|
830 bool IndexBackend::IsExistingResource(int64_t internalId)
|
|
831 {
|
|
832 DatabaseManager::CachedStatement statement(
|
|
833 STATEMENT_FROM_HERE, manager_,
|
|
834 "SELECT * FROM Resources WHERE internalId=${id}");
|
|
835
|
|
836 statement.SetReadOnly(true);
|
|
837 statement.SetParameterType("id", ValueType_Integer64);
|
|
838
|
|
839 Dictionary args;
|
|
840 args.SetIntegerValue("id", internalId);
|
|
841
|
|
842 statement.Execute(args);
|
|
843
|
|
844 return !statement.IsDone();
|
|
845 }
|
|
846
|
|
847
|
|
848 bool IndexBackend::IsProtectedPatient(int64_t internalId)
|
|
849 {
|
|
850 DatabaseManager::CachedStatement statement(
|
|
851 STATEMENT_FROM_HERE, manager_,
|
|
852 "SELECT * FROM PatientRecyclingOrder WHERE patientId = ${id}");
|
|
853
|
|
854 statement.SetReadOnly(true);
|
|
855 statement.SetParameterType("id", ValueType_Integer64);
|
|
856
|
|
857 Dictionary args;
|
|
858 args.SetIntegerValue("id", internalId);
|
|
859
|
|
860 statement.Execute(args);
|
|
861
|
|
862 return statement.IsDone();
|
|
863 }
|
|
864
|
|
865
|
|
866 void IndexBackend::ListAvailableMetadata(std::list<int32_t>& target /*out*/,
|
|
867 int64_t id)
|
|
868 {
|
|
869 DatabaseManager::CachedStatement statement(
|
|
870 STATEMENT_FROM_HERE, manager_,
|
|
871 "SELECT type FROM Metadata WHERE id=${id}");
|
|
872
|
|
873 statement.SetReadOnly(true);
|
|
874 statement.SetParameterType("id", ValueType_Integer64);
|
|
875
|
|
876 Dictionary args;
|
|
877 args.SetIntegerValue("id", id);
|
|
878
|
|
879 ReadListOfIntegers<int32_t>(target, statement, args);
|
|
880 }
|
|
881
|
|
882
|
|
883 void IndexBackend::ListAvailableAttachments(std::list<int32_t>& target /*out*/,
|
|
884 int64_t id)
|
|
885 {
|
|
886 DatabaseManager::CachedStatement statement(
|
|
887 STATEMENT_FROM_HERE, manager_,
|
|
888 "SELECT fileType FROM AttachedFiles WHERE id=${id}");
|
|
889
|
|
890 statement.SetReadOnly(true);
|
|
891 statement.SetParameterType("id", ValueType_Integer64);
|
|
892
|
|
893 Dictionary args;
|
|
894 args.SetIntegerValue("id", id);
|
|
895
|
|
896 ReadListOfIntegers<int32_t>(target, statement, args);
|
|
897 }
|
|
898
|
|
899
|
|
900 void IndexBackend::LogChange(const OrthancPluginChange& change)
|
|
901 {
|
|
902 int64_t id;
|
|
903 OrthancPluginResourceType type;
|
|
904 if (!LookupResource(id, type, change.publicId) ||
|
|
905 type != change.resourceType)
|
|
906 {
|
|
907 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
|
|
908 }
|
|
909
|
|
910 DatabaseManager::CachedStatement statement(
|
|
911 STATEMENT_FROM_HERE, manager_,
|
|
912 "INSERT INTO Changes VALUES(${}, ${changeType}, ${id}, ${resourceType}, ${date})");
|
|
913
|
|
914 statement.SetParameterType("changeType", ValueType_Integer64);
|
|
915 statement.SetParameterType("id", ValueType_Integer64);
|
|
916 statement.SetParameterType("resourceType", ValueType_Integer64);
|
|
917 statement.SetParameterType("date", ValueType_Utf8String);
|
|
918
|
|
919 Dictionary args;
|
|
920 args.SetIntegerValue("changeType", change.changeType);
|
|
921 args.SetIntegerValue("id", id);
|
|
922 args.SetIntegerValue("resourceType", change.resourceType);
|
|
923 args.SetUtf8Value("date", change.date);
|
|
924
|
|
925 statement.Execute(args);
|
|
926 }
|
|
927
|
|
928
|
|
929 void IndexBackend::LogExportedResource(const OrthancPluginExportedResource& resource)
|
|
930 {
|
|
931 DatabaseManager::CachedStatement statement(
|
|
932 STATEMENT_FROM_HERE, manager_,
|
|
933 "INSERT INTO ExportedResources VALUES(${}, ${type}, ${publicId}, "
|
|
934 "${modality}, ${patient}, ${study}, ${series}, ${instance}, ${date})");
|
|
935
|
|
936 statement.SetParameterType("type", ValueType_Integer64);
|
|
937 statement.SetParameterType("publicId", ValueType_Utf8String);
|
|
938 statement.SetParameterType("modality", ValueType_Utf8String);
|
|
939 statement.SetParameterType("patient", ValueType_Utf8String);
|
|
940 statement.SetParameterType("study", ValueType_Utf8String);
|
|
941 statement.SetParameterType("series", ValueType_Utf8String);
|
|
942 statement.SetParameterType("instance", ValueType_Utf8String);
|
|
943 statement.SetParameterType("date", ValueType_Utf8String);
|
|
944
|
|
945 Dictionary args;
|
|
946 args.SetIntegerValue("type", resource.resourceType);
|
|
947 args.SetUtf8Value("publicId", resource.publicId);
|
|
948 args.SetUtf8Value("modality", resource.modality);
|
|
949 args.SetUtf8Value("patient", resource.patientId);
|
|
950 args.SetUtf8Value("study", resource.studyInstanceUid);
|
|
951 args.SetUtf8Value("series", resource.seriesInstanceUid);
|
|
952 args.SetUtf8Value("instance", resource.sopInstanceUid);
|
|
953 args.SetUtf8Value("date", resource.date);
|
|
954
|
|
955 statement.Execute(args);
|
|
956 }
|
|
957
|
|
958
|
|
959 /* Use GetOutput().AnswerAttachment() */
|
|
960 bool IndexBackend::LookupAttachment(int64_t id,
|
|
961 int32_t contentType)
|
|
962 {
|
|
963 DatabaseManager::CachedStatement statement(
|
|
964 STATEMENT_FROM_HERE, manager_,
|
|
965 "SELECT uuid, uncompressedSize, compressionType, compressedSize, "
|
|
966 "uncompressedHash, compressedHash FROM AttachedFiles WHERE id=${id} AND fileType=${type}");
|
|
967
|
|
968 statement.SetReadOnly(true);
|
|
969 statement.SetParameterType("id", ValueType_Integer64);
|
|
970 statement.SetParameterType("type", ValueType_Integer64);
|
|
971
|
|
972 Dictionary args;
|
|
973 args.SetIntegerValue("id", id);
|
|
974 args.SetIntegerValue("type", static_cast<int>(contentType));
|
|
975
|
|
976 statement.Execute(args);
|
|
977
|
|
978 if (statement.IsDone())
|
|
979 {
|
|
980 return false;
|
|
981 }
|
|
982 else
|
|
983 {
|
|
984 GetOutput().AnswerAttachment(ReadString(statement, 0),
|
|
985 contentType,
|
|
986 ReadInteger64(statement, 1),
|
|
987 ReadString(statement, 4),
|
|
988 ReadInteger32(statement, 2),
|
|
989 ReadInteger64(statement, 3),
|
|
990 ReadString(statement, 5));
|
|
991 return true;
|
|
992 }
|
|
993 }
|
|
994
|
|
995
|
|
996 bool IndexBackend::LookupGlobalProperty(std::string& target /*out*/,
|
|
997 int32_t property)
|
|
998 {
|
|
999 return ::OrthancDatabases::LookupGlobalProperty(target, manager_, static_cast<Orthanc::GlobalProperty>(property));
|
|
1000 }
|
|
1001
|
|
1002
|
|
1003 void IndexBackend::LookupIdentifier(std::list<int64_t>& target /*out*/,
|
|
1004 OrthancPluginResourceType resourceType,
|
|
1005 uint16_t group,
|
|
1006 uint16_t element,
|
|
1007 OrthancPluginIdentifierConstraint constraint,
|
|
1008 const char* value)
|
|
1009 {
|
|
1010 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
1011
|
|
1012 std::string header =
|
|
1013 "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE "
|
|
1014 "d.id = r.internalId AND r.resourceType=${type} AND d.tagGroup=${group} "
|
|
1015 "AND d.tagElement=${element} AND ";
|
|
1016
|
|
1017 switch (constraint)
|
|
1018 {
|
|
1019 case OrthancPluginIdentifierConstraint_Equal:
|
|
1020 header += "d.value = ${value}";
|
|
1021 statement.reset(new DatabaseManager::CachedStatement(
|
|
1022 STATEMENT_FROM_HERE, manager_, header.c_str()));
|
|
1023 break;
|
|
1024
|
|
1025 case OrthancPluginIdentifierConstraint_SmallerOrEqual:
|
|
1026 header += "d.value <= ${value}";
|
|
1027 statement.reset(new DatabaseManager::CachedStatement(
|
|
1028 STATEMENT_FROM_HERE, manager_, header.c_str()));
|
|
1029 break;
|
|
1030
|
|
1031 case OrthancPluginIdentifierConstraint_GreaterOrEqual:
|
|
1032 header += "d.value >= ${value}";
|
|
1033 statement.reset(new DatabaseManager::CachedStatement(
|
|
1034 STATEMENT_FROM_HERE, manager_, header.c_str()));
|
|
1035 break;
|
|
1036
|
|
1037 case OrthancPluginIdentifierConstraint_Wildcard:
|
|
1038 header += "d.value LIKE ${value}";
|
|
1039 statement.reset(new DatabaseManager::CachedStatement(
|
|
1040 STATEMENT_FROM_HERE, manager_, header.c_str()));
|
|
1041 break;
|
|
1042
|
|
1043 default:
|
|
1044 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
|
|
1045 }
|
|
1046
|
|
1047 statement->SetReadOnly(true);
|
|
1048 statement->SetParameterType("type", ValueType_Integer64);
|
|
1049 statement->SetParameterType("group", ValueType_Integer64);
|
|
1050 statement->SetParameterType("element", ValueType_Integer64);
|
|
1051 statement->SetParameterType("value", ValueType_Utf8String);
|
|
1052
|
|
1053 Dictionary args;
|
|
1054 args.SetIntegerValue("type", resourceType);
|
|
1055 args.SetIntegerValue("group", group);
|
|
1056 args.SetIntegerValue("element", element);
|
|
1057
|
|
1058 if (constraint == OrthancPluginIdentifierConstraint_Wildcard)
|
|
1059 {
|
|
1060 args.SetUtf8Value("value", ConvertWildcardToLike(value));
|
|
1061 }
|
|
1062 else
|
|
1063 {
|
|
1064 args.SetUtf8Value("value", value);
|
|
1065 }
|
|
1066
|
|
1067 statement->Execute(args);
|
|
1068
|
|
1069 target.clear();
|
|
1070 while (!statement->IsDone())
|
|
1071 {
|
|
1072 target.push_back(ReadInteger64(*statement, 0));
|
|
1073 statement->Next();
|
|
1074 }
|
|
1075 }
|
|
1076
|
|
1077
|
|
1078 void IndexBackend::LookupIdentifierRange(std::list<int64_t>& target /*out*/,
|
|
1079 OrthancPluginResourceType resourceType,
|
|
1080 uint16_t group,
|
|
1081 uint16_t element,
|
|
1082 const char* start,
|
|
1083 const char* end)
|
|
1084 {
|
|
1085 DatabaseManager::CachedStatement statement(
|
|
1086 STATEMENT_FROM_HERE, manager_,
|
|
1087 "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE "
|
|
1088 "d.id = r.internalId AND r.resourceType=${type} AND d.tagGroup=${group} "
|
|
1089 "AND d.tagElement=${element} AND d.value>=${start} AND d.value<=${end}");
|
|
1090
|
|
1091 statement.SetReadOnly(true);
|
|
1092 statement.SetParameterType("type", ValueType_Integer64);
|
|
1093 statement.SetParameterType("group", ValueType_Integer64);
|
|
1094 statement.SetParameterType("element", ValueType_Integer64);
|
|
1095 statement.SetParameterType("start", ValueType_Utf8String);
|
|
1096 statement.SetParameterType("end", ValueType_Utf8String);
|
|
1097
|
|
1098 Dictionary args;
|
|
1099 args.SetIntegerValue("type", resourceType);
|
|
1100 args.SetIntegerValue("group", group);
|
|
1101 args.SetIntegerValue("element", element);
|
|
1102 args.SetUtf8Value("start", start);
|
|
1103 args.SetUtf8Value("end", end);
|
|
1104
|
|
1105 statement.Execute(args);
|
|
1106
|
|
1107 target.clear();
|
|
1108 while (!statement.IsDone())
|
|
1109 {
|
|
1110 target.push_back(ReadInteger64(statement, 0));
|
|
1111 statement.Next();
|
|
1112 }
|
|
1113 }
|
|
1114
|
|
1115
|
|
1116 bool IndexBackend::LookupMetadata(std::string& target /*out*/,
|
|
1117 int64_t id,
|
|
1118 int32_t metadataType)
|
|
1119 {
|
|
1120 DatabaseManager::CachedStatement statement(
|
|
1121 STATEMENT_FROM_HERE, manager_,
|
|
1122 "SELECT value FROM Metadata WHERE id=${id} and type=${type}");
|
|
1123
|
|
1124 statement.SetReadOnly(true);
|
|
1125 statement.SetParameterType("id", ValueType_Integer64);
|
|
1126 statement.SetParameterType("type", ValueType_Integer64);
|
|
1127
|
|
1128 Dictionary args;
|
|
1129 args.SetIntegerValue("id", id);
|
|
1130 args.SetIntegerValue("type", metadataType);
|
|
1131
|
|
1132 statement.Execute(args);
|
|
1133
|
|
1134 if (statement.IsDone())
|
|
1135 {
|
|
1136 return false;
|
|
1137 }
|
|
1138 else
|
|
1139 {
|
|
1140 target = ReadString(statement, 0);
|
|
1141 return true;
|
|
1142 }
|
|
1143 }
|
|
1144
|
|
1145
|
|
1146 bool IndexBackend::LookupParent(int64_t& parentId /*out*/,
|
|
1147 int64_t resourceId)
|
|
1148 {
|
|
1149 DatabaseManager::CachedStatement statement(
|
|
1150 STATEMENT_FROM_HERE, manager_,
|
|
1151 "SELECT parentId FROM Resources WHERE internalId=${id}");
|
|
1152
|
|
1153 statement.SetReadOnly(true);
|
|
1154 statement.SetParameterType("id", ValueType_Integer64);
|
|
1155
|
|
1156 Dictionary args;
|
|
1157 args.SetIntegerValue("id", resourceId);
|
|
1158
|
|
1159 statement.Execute(args);
|
|
1160
|
|
1161 if (statement.IsDone() ||
|
|
1162 statement.GetResultField(0).GetType() == ValueType_Null)
|
|
1163 {
|
|
1164 return false;
|
|
1165 }
|
|
1166 else
|
|
1167 {
|
|
1168 parentId = ReadInteger64(statement, 0);
|
|
1169 return true;
|
|
1170 }
|
|
1171 }
|
|
1172
|
|
1173
|
|
1174 bool IndexBackend::LookupResource(int64_t& id /*out*/,
|
|
1175 OrthancPluginResourceType& type /*out*/,
|
|
1176 const char* publicId)
|
|
1177 {
|
|
1178 DatabaseManager::CachedStatement statement(
|
|
1179 STATEMENT_FROM_HERE, manager_,
|
|
1180 "SELECT internalId, resourceType FROM Resources WHERE publicId=${id}");
|
|
1181
|
|
1182 statement.SetReadOnly(true);
|
|
1183 statement.SetParameterType("id", ValueType_Utf8String);
|
|
1184
|
|
1185 Dictionary args;
|
|
1186 args.SetUtf8Value("id", publicId);
|
|
1187
|
|
1188 statement.Execute(args);
|
|
1189
|
|
1190 if (statement.IsDone())
|
|
1191 {
|
|
1192 return false;
|
|
1193 }
|
|
1194 else
|
|
1195 {
|
|
1196 id = ReadInteger64(statement, 0);
|
|
1197 type = static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 1));
|
|
1198 return true;
|
|
1199 }
|
|
1200 }
|
|
1201
|
|
1202
|
|
1203 bool IndexBackend::SelectPatientToRecycle(int64_t& internalId /*out*/)
|
|
1204 {
|
|
1205 DatabaseManager::CachedStatement statement(
|
|
1206 STATEMENT_FROM_HERE, manager_,
|
|
1207 "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1");
|
|
1208
|
|
1209 statement.SetReadOnly(true);
|
|
1210 statement.Execute();
|
|
1211
|
|
1212 if (statement.IsDone())
|
|
1213 {
|
|
1214 return false;
|
|
1215 }
|
|
1216 else
|
|
1217 {
|
|
1218 internalId = ReadInteger64(statement, 0);
|
|
1219 return true;
|
|
1220 }
|
|
1221 }
|
|
1222
|
|
1223
|
|
1224 bool IndexBackend::SelectPatientToRecycle(int64_t& internalId /*out*/,
|
|
1225 int64_t patientIdToAvoid)
|
|
1226 {
|
|
1227 DatabaseManager::CachedStatement statement(
|
|
1228 STATEMENT_FROM_HERE, manager_,
|
|
1229 "SELECT patientId FROM PatientRecyclingOrder "
|
|
1230 "WHERE patientId != ${id} ORDER BY seq ASC LIMIT 1");
|
|
1231
|
|
1232 statement.SetReadOnly(true);
|
|
1233 statement.SetParameterType("id", ValueType_Integer64);
|
|
1234
|
|
1235 Dictionary args;
|
|
1236 args.SetIntegerValue("id", patientIdToAvoid);
|
|
1237
|
|
1238 statement.Execute(args);
|
|
1239
|
|
1240 if (statement.IsDone())
|
|
1241 {
|
|
1242 return false;
|
|
1243 }
|
|
1244 else
|
|
1245 {
|
|
1246 internalId = ReadInteger64(statement, 0);
|
|
1247 return true;
|
|
1248 }
|
|
1249 }
|
|
1250
|
|
1251
|
|
1252 void IndexBackend::SetGlobalProperty(int32_t property,
|
|
1253 const char* value)
|
|
1254 {
|
|
1255 return ::OrthancDatabases::SetGlobalProperty(manager_, static_cast<Orthanc::GlobalProperty>(property), value);
|
|
1256 }
|
|
1257
|
|
1258
|
|
1259 static void ExecuteSetTag(DatabaseManager::CachedStatement& statement,
|
|
1260 int64_t id,
|
|
1261 uint16_t group,
|
|
1262 uint16_t element,
|
|
1263 const char* value)
|
|
1264 {
|
|
1265 statement.SetParameterType("id", ValueType_Integer64);
|
|
1266 statement.SetParameterType("group", ValueType_Integer64);
|
|
1267 statement.SetParameterType("element", ValueType_Integer64);
|
|
1268 statement.SetParameterType("value", ValueType_Utf8String);
|
|
1269
|
|
1270 Dictionary args;
|
|
1271 args.SetIntegerValue("id", id);
|
|
1272 args.SetIntegerValue("group", group);
|
|
1273 args.SetIntegerValue("element", element);
|
|
1274 args.SetUtf8Value("value", value);
|
|
1275
|
|
1276 statement.Execute(args);
|
|
1277 }
|
|
1278
|
|
1279
|
|
1280 void IndexBackend::SetMainDicomTag(int64_t id,
|
|
1281 uint16_t group,
|
|
1282 uint16_t element,
|
|
1283 const char* value)
|
|
1284 {
|
|
1285 DatabaseManager::CachedStatement statement(
|
|
1286 STATEMENT_FROM_HERE, manager_,
|
|
1287 "INSERT INTO MainDicomTags VALUES(${id}, ${group}, ${element}, ${value})");
|
|
1288
|
|
1289 ExecuteSetTag(statement, id, group, element, value);
|
|
1290 }
|
|
1291
|
|
1292
|
|
1293 void IndexBackend::SetIdentifierTag(int64_t id,
|
|
1294 uint16_t group,
|
|
1295 uint16_t element,
|
|
1296 const char* value)
|
|
1297 {
|
|
1298 DatabaseManager::CachedStatement statement(
|
|
1299 STATEMENT_FROM_HERE, manager_,
|
|
1300 "INSERT INTO DicomIdentifiers VALUES(${id}, ${group}, ${element}, ${value})");
|
|
1301
|
|
1302 ExecuteSetTag(statement, id, group, element, value);
|
|
1303 }
|
|
1304
|
|
1305
|
|
1306 void IndexBackend::SetMetadata(int64_t id,
|
|
1307 int32_t metadataType,
|
|
1308 const char* value)
|
|
1309 {
|
|
1310 if (GetDialect() == Dialect_SQLite)
|
|
1311 {
|
|
1312 DatabaseManager::CachedStatement statement(
|
|
1313 STATEMENT_FROM_HERE, manager_,
|
|
1314 "INSERT OR REPLACE INTO Metadata VALUES (${id}, ${type}, ${value})");
|
|
1315
|
|
1316 statement.SetParameterType("id", ValueType_Integer64);
|
|
1317 statement.SetParameterType("type", ValueType_Integer64);
|
|
1318 statement.SetParameterType("value", ValueType_Utf8String);
|
|
1319
|
|
1320 Dictionary args;
|
|
1321 args.SetIntegerValue("id", id);
|
|
1322 args.SetIntegerValue("type", metadataType);
|
|
1323 args.SetUtf8Value("value", value);
|
|
1324
|
|
1325 statement.Execute(args);
|
|
1326 }
|
|
1327 else
|
|
1328 {
|
|
1329 {
|
|
1330 DatabaseManager::CachedStatement statement(
|
|
1331 STATEMENT_FROM_HERE, manager_,
|
|
1332 "DELETE FROM Metadata WHERE id=${id} AND type=${type}");
|
|
1333
|
|
1334 statement.SetParameterType("id", ValueType_Integer64);
|
|
1335 statement.SetParameterType("type", ValueType_Integer64);
|
|
1336
|
|
1337 Dictionary args;
|
|
1338 args.SetIntegerValue("id", id);
|
|
1339 args.SetIntegerValue("type", metadataType);
|
|
1340
|
|
1341 statement.Execute(args);
|
|
1342 }
|
|
1343
|
|
1344 {
|
|
1345 DatabaseManager::CachedStatement statement(
|
|
1346 STATEMENT_FROM_HERE, manager_,
|
|
1347 "INSERT INTO Metadata VALUES (${id}, ${type}, ${value})");
|
|
1348
|
|
1349 statement.SetParameterType("id", ValueType_Integer64);
|
|
1350 statement.SetParameterType("type", ValueType_Integer64);
|
|
1351 statement.SetParameterType("value", ValueType_Utf8String);
|
|
1352
|
|
1353 Dictionary args;
|
|
1354 args.SetIntegerValue("id", id);
|
|
1355 args.SetIntegerValue("type", metadataType);
|
|
1356 args.SetUtf8Value("value", value);
|
|
1357
|
|
1358 statement.Execute(args);
|
|
1359 }
|
|
1360 }
|
|
1361 }
|
|
1362
|
|
1363
|
|
1364 void IndexBackend::SetProtectedPatient(int64_t internalId,
|
|
1365 bool isProtected)
|
|
1366 {
|
|
1367 if (isProtected)
|
|
1368 {
|
|
1369 DatabaseManager::CachedStatement statement(
|
|
1370 STATEMENT_FROM_HERE, manager_,
|
|
1371 "DELETE FROM PatientRecyclingOrder WHERE patientId=${id}");
|
|
1372
|
|
1373 statement.SetParameterType("id", ValueType_Integer64);
|
|
1374
|
|
1375 Dictionary args;
|
|
1376 args.SetIntegerValue("id", internalId);
|
|
1377
|
|
1378 statement.Execute(args);
|
|
1379 }
|
|
1380 else if (IsProtectedPatient(internalId))
|
|
1381 {
|
|
1382 DatabaseManager::CachedStatement statement(
|
|
1383 STATEMENT_FROM_HERE, manager_,
|
|
1384 "INSERT INTO PatientRecyclingOrder VALUES(${}, ${id})");
|
|
1385
|
|
1386 statement.SetParameterType("id", ValueType_Integer64);
|
|
1387
|
|
1388 Dictionary args;
|
|
1389 args.SetIntegerValue("id", internalId);
|
|
1390
|
|
1391 statement.Execute(args);
|
|
1392 }
|
|
1393 else
|
|
1394 {
|
|
1395 // Nothing to do: The patient is already unprotected
|
|
1396 }
|
|
1397 }
|
|
1398
|
|
1399
|
|
1400 uint32_t IndexBackend::GetDatabaseVersion()
|
|
1401 {
|
|
1402 std::string version = "unknown";
|
|
1403
|
|
1404 if (LookupGlobalProperty(version, Orthanc::GlobalProperty_DatabaseSchemaVersion))
|
|
1405 {
|
|
1406 try
|
|
1407 {
|
|
1408 return boost::lexical_cast<unsigned int>(version);
|
|
1409 }
|
|
1410 catch (boost::bad_lexical_cast&)
|
|
1411 {
|
|
1412 }
|
|
1413 }
|
|
1414
|
|
1415 LOG(ERROR) << "The database is corrupted. Drop it manually for Orthanc to recreate it";
|
|
1416 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
|
|
1417 }
|
|
1418
|
|
1419
|
|
1420 /**
|
|
1421 * Upgrade the database to the specified version of the database
|
|
1422 * schema. The upgrade script is allowed to make calls to
|
|
1423 * OrthancPluginReconstructMainDicomTags().
|
|
1424 **/
|
|
1425 void IndexBackend::UpgradeDatabase(uint32_t targetVersion,
|
|
1426 OrthancPluginStorageArea* storageArea)
|
|
1427 {
|
|
1428 LOG(ERROR) << "Upgrading database is not implemented by this plugin";
|
|
1429 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
1430 }
|
|
1431
|
|
1432
|
|
1433 void IndexBackend::ClearMainDicomTags(int64_t internalId)
|
|
1434 {
|
|
1435 {
|
|
1436 DatabaseManager::CachedStatement statement(
|
|
1437 STATEMENT_FROM_HERE, manager_,
|
|
1438 "DELETE FROM MainDicomTags WHERE id=${id}");
|
|
1439
|
|
1440 statement.SetParameterType("id", ValueType_Integer64);
|
|
1441
|
|
1442 Dictionary args;
|
|
1443 args.SetIntegerValue("id", internalId);
|
|
1444
|
|
1445 statement.Execute(args);
|
|
1446 }
|
|
1447
|
|
1448 {
|
|
1449 DatabaseManager::CachedStatement statement(
|
|
1450 STATEMENT_FROM_HERE, manager_,
|
|
1451 "DELETE FROM DicomIdentifiers WHERE id=${id}");
|
|
1452
|
|
1453 statement.SetParameterType("id", ValueType_Integer64);
|
|
1454
|
|
1455 Dictionary args;
|
|
1456 args.SetIntegerValue("id", internalId);
|
|
1457
|
|
1458 statement.Execute(args);
|
|
1459 }
|
|
1460 }
|
|
1461
|
|
1462
|
|
1463 // For unit testing only!
|
|
1464 uint64_t IndexBackend::GetResourcesCount()
|
|
1465 {
|
|
1466 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
1467
|
|
1468 switch (GetDialect())
|
|
1469 {
|
|
1470 case Dialect_MySQL:
|
|
1471 statement.reset(new DatabaseManager::CachedStatement(
|
|
1472 STATEMENT_FROM_HERE, GetManager(),
|
|
1473 "SELECT CAST(COUNT(*) AS UNSIGNED INT) FROM Resources"));
|
|
1474 break;
|
|
1475
|
|
1476 case Dialect_PostgreSQL:
|
|
1477 statement.reset(new DatabaseManager::CachedStatement(
|
|
1478 STATEMENT_FROM_HERE, GetManager(),
|
|
1479 "SELECT CAST(COUNT(*) AS BIGINT) FROM Resources"));
|
|
1480 break;
|
|
1481
|
|
1482 case Dialect_SQLite:
|
|
1483 statement.reset(new DatabaseManager::CachedStatement(
|
|
1484 STATEMENT_FROM_HERE, GetManager(),
|
|
1485 "SELECT COUNT(*) FROM Resources"));
|
|
1486 break;
|
|
1487
|
|
1488 default:
|
|
1489 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
1490 }
|
|
1491
|
|
1492 statement->SetReadOnly(true);
|
|
1493 statement->Execute();
|
|
1494
|
|
1495 return static_cast<uint64_t>(ReadInteger64(*statement, 0));
|
|
1496 }
|
|
1497
|
|
1498
|
|
1499 // For unit testing only!
|
|
1500 uint64_t IndexBackend::GetUnprotectedPatientsCount()
|
|
1501 {
|
|
1502 std::auto_ptr<DatabaseManager::CachedStatement> statement;
|
|
1503
|
|
1504 switch (GetDialect())
|
|
1505 {
|
|
1506 case Dialect_MySQL:
|
|
1507 statement.reset(new DatabaseManager::CachedStatement(
|
|
1508 STATEMENT_FROM_HERE, GetManager(),
|
|
1509 "SELECT CAST(COUNT(*) AS UNSIGNED INT) FROM PatientRecyclingOrder"));
|
|
1510 break;
|
|
1511
|
|
1512 case Dialect_PostgreSQL:
|
|
1513 statement.reset(new DatabaseManager::CachedStatement(
|
|
1514 STATEMENT_FROM_HERE, GetManager(),
|
|
1515 "SELECT CAST(COUNT(*) AS BIGINT) FROM PatientRecyclingOrder"));
|
|
1516 break;
|
|
1517
|
|
1518 case Dialect_SQLite:
|
|
1519 statement.reset(new DatabaseManager::CachedStatement(
|
|
1520 STATEMENT_FROM_HERE, GetManager(),
|
|
1521 "SELECT COUNT(*) FROM PatientRecyclingOrder"));
|
|
1522 break;
|
|
1523
|
|
1524 default:
|
|
1525 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
|
|
1526 }
|
|
1527
|
|
1528 statement->SetReadOnly(true);
|
|
1529 statement->Execute();
|
|
1530
|
|
1531 return static_cast<uint64_t>(ReadInteger64(*statement, 0));
|
|
1532 }
|
|
1533
|
|
1534
|
|
1535 // For unit testing only!
|
|
1536 bool IndexBackend::GetParentPublicId(std::string& target,
|
|
1537 int64_t id)
|
|
1538 {
|
|
1539 DatabaseManager::CachedStatement statement(
|
|
1540 STATEMENT_FROM_HERE, GetManager(),
|
|
1541 "SELECT a.publicId FROM Resources AS a, Resources AS b "
|
|
1542 "WHERE a.internalId = b.parentId AND b.internalId = ${id}");
|
|
1543
|
|
1544 statement.SetReadOnly(true);
|
|
1545 statement.SetParameterType("id", ValueType_Integer64);
|
|
1546
|
|
1547 Dictionary args;
|
|
1548 args.SetIntegerValue("id", id);
|
|
1549
|
|
1550 statement.Execute(args);
|
|
1551
|
|
1552 if (statement.IsDone())
|
|
1553 {
|
|
1554 return false;
|
|
1555 }
|
|
1556 else
|
|
1557 {
|
|
1558 target = ReadString(statement, 0);
|
|
1559 return true;
|
|
1560 }
|
|
1561 }
|
|
1562
|
|
1563
|
|
1564 // For unit tests only!
|
|
1565 void IndexBackend::GetChildren(std::list<std::string>& childrenPublicIds,
|
|
1566 int64_t id)
|
|
1567 {
|
|
1568 DatabaseManager::CachedStatement statement(
|
|
1569 STATEMENT_FROM_HERE, GetManager(),
|
|
1570 "SELECT publicId FROM Resources WHERE parentId=${id}");
|
|
1571
|
|
1572 statement.SetReadOnly(true);
|
|
1573 statement.SetParameterType("id", ValueType_Integer64);
|
|
1574
|
|
1575 Dictionary args;
|
|
1576 args.SetIntegerValue("id", id);
|
|
1577
|
|
1578 ReadListOfStrings(childrenPublicIds, statement, args);
|
|
1579 }
|
|
1580 }
|