comparison OrthancServer/DatabaseWrapper.cpp @ 183:baada606da3c

databasewrapper
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 12 Nov 2012 14:52:30 +0100
parents
children 8e673a65564d
comparison
equal deleted inserted replaced
182:93ff5babcaf8 183:baada606da3c
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012 Medical Physics Department, CHU of Liege,
4 * Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "DatabaseWrapper.h"
34
35 #include "../Core/DicomFormat/DicomArray.h"
36 #include "EmbeddedResources.h"
37
38 #include <glog/logging.h>
39 #include <stdio.h>
40
41 namespace Orthanc
42 {
43
44 namespace Internals
45 {
46 class SignalFileDeleted : public SQLite::IScalarFunction
47 {
48 private:
49 IServerIndexListener& listener_;
50
51 public:
52 SignalFileDeleted(IServerIndexListener& listener) :
53 listener_(listener)
54 {
55 }
56
57 virtual const char* GetName() const
58 {
59 return "SignalFileDeleted";
60 }
61
62 virtual unsigned int GetCardinality() const
63 {
64 return 1;
65 }
66
67 virtual void Compute(SQLite::FunctionContext& context)
68 {
69 listener_.SignalFileDeleted(context.GetStringValue(0));
70 }
71 };
72
73 class SignalRemainingAncestor : public SQLite::IScalarFunction
74 {
75 private:
76 bool hasRemainingAncestor_;
77 std::string remainingPublicId_;
78 ResourceType remainingType_;
79
80 public:
81 void Reset()
82 {
83 hasRemainingAncestor_ = false;
84 }
85
86 virtual const char* GetName() const
87 {
88 return "SignalRemainingAncestor";
89 }
90
91 virtual unsigned int GetCardinality() const
92 {
93 return 2;
94 }
95
96 virtual void Compute(SQLite::FunctionContext& context)
97 {
98 VLOG(1) << "There exists a remaining ancestor with public ID \""
99 << context.GetStringValue(0)
100 << "\" of type "
101 << context.GetIntValue(1);
102
103 if (!hasRemainingAncestor_ ||
104 remainingType_ >= context.GetIntValue(1))
105 {
106 hasRemainingAncestor_ = true;
107 remainingPublicId_ = context.GetStringValue(0);
108 remainingType_ = static_cast<ResourceType>(context.GetIntValue(1));
109 }
110 }
111
112 bool HasRemainingAncestor() const
113 {
114 return hasRemainingAncestor_;
115 }
116
117 const std::string& GetRemainingAncestorId() const
118 {
119 assert(hasRemainingAncestor_);
120 return remainingPublicId_;
121 }
122
123 ResourceType GetRemainingAncestorType() const
124 {
125 assert(hasRemainingAncestor_);
126 return remainingType_;
127 }
128 };
129 }
130
131
132
133 void DatabaseWrapper::SetGlobalProperty(const std::string& name,
134 const std::string& value)
135 {
136 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)");
137 s.BindString(0, name);
138 s.BindString(1, value);
139 s.Run();
140 }
141
142 bool DatabaseWrapper::FindGlobalProperty(std::string& target,
143 const std::string& name)
144 {
145 SQLite::Statement s(db_, SQLITE_FROM_HERE,
146 "SELECT value FROM GlobalProperties WHERE name=?");
147 s.BindString(0, name);
148
149 if (!s.Step())
150 {
151 return false;
152 }
153 else
154 {
155 target = s.ColumnString(0);
156 return true;
157 }
158 }
159
160 std::string DatabaseWrapper::GetGlobalProperty(const std::string& name,
161 const std::string& defaultValue)
162 {
163 std::string s;
164 if (FindGlobalProperty(s, name))
165 {
166 return s;
167 }
168 else
169 {
170 return defaultValue;
171 }
172 }
173
174 int64_t DatabaseWrapper::CreateResource(const std::string& publicId,
175 ResourceType type)
176 {
177 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)");
178 s.BindInt(0, type);
179 s.BindString(1, publicId);
180 s.Run();
181 return db_.GetLastInsertRowId();
182 }
183
184 bool DatabaseWrapper::FindResource(const std::string& publicId,
185 int64_t& id,
186 ResourceType& type)
187 {
188 SQLite::Statement s(db_, SQLITE_FROM_HERE,
189 "SELECT internalId, resourceType FROM Resources WHERE publicId=?");
190 s.BindString(0, publicId);
191
192 if (!s.Step())
193 {
194 return false;
195 }
196 else
197 {
198 id = s.ColumnInt(0);
199 type = static_cast<ResourceType>(s.ColumnInt(1));
200
201 // Check whether there is a single resource with this public id
202 assert(!s.Step());
203
204 return true;
205 }
206 }
207
208 void DatabaseWrapper::AttachChild(int64_t parent,
209 int64_t child)
210 {
211 SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?");
212 s.BindInt(0, parent);
213 s.BindInt(1, child);
214 s.Run();
215 }
216
217 void DatabaseWrapper::DeleteResource(int64_t id)
218 {
219 signalRemainingAncestor_->Reset();
220
221 SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Resources WHERE internalId=?");
222 s.BindInt(0, id);
223 s.Run();
224
225 if (signalRemainingAncestor_->HasRemainingAncestor())
226 {
227 listener_.SignalRemainingAncestor(signalRemainingAncestor_->GetRemainingAncestorType(),
228 signalRemainingAncestor_->GetRemainingAncestorId());
229 }
230 }
231
232 void DatabaseWrapper::SetMetadata(int64_t id,
233 MetadataType type,
234 const std::string& value)
235 {
236 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)");
237 s.BindInt(0, id);
238 s.BindInt(1, type);
239 s.BindString(2, value);
240 s.Run();
241 }
242
243 bool DatabaseWrapper::FindMetadata(std::string& target,
244 int64_t id,
245 MetadataType type)
246 {
247 SQLite::Statement s(db_, SQLITE_FROM_HERE,
248 "SELECT value FROM Metadata WHERE id=? AND type=?");
249 s.BindInt(0, id);
250 s.BindInt(1, type);
251
252 if (!s.Step())
253 {
254 return false;
255 }
256 else
257 {
258 target = s.ColumnString(0);
259 return true;
260 }
261 }
262
263 std::string DatabaseWrapper::GetMetadata(int64_t id,
264 MetadataType type,
265 const std::string& defaultValue)
266 {
267 std::string s;
268 if (FindMetadata(s, id, type))
269 {
270 return s;
271 }
272 else
273 {
274 return defaultValue;
275 }
276 }
277
278 void DatabaseWrapper::AttachFile(int64_t id,
279 const std::string& name,
280 const std::string& fileUuid,
281 size_t compressedSize,
282 size_t uncompressedSize,
283 CompressionType compressionType)
284 {
285 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?)");
286 s.BindInt(0, id);
287 s.BindString(1, name);
288 s.BindString(2, fileUuid);
289 s.BindInt(3, compressedSize);
290 s.BindInt(4, uncompressedSize);
291 s.BindInt(5, compressionType);
292 s.Run();
293 }
294
295 bool DatabaseWrapper::FindFile(int64_t id,
296 const std::string& name,
297 std::string& fileUuid,
298 size_t& compressedSize,
299 size_t& uncompressedSize,
300 CompressionType& compressionType)
301 {
302 SQLite::Statement s(db_, SQLITE_FROM_HERE,
303 "SELECT uuid, compressedSize, uncompressedSize, compressionType FROM AttachedFiles WHERE id=? AND name=?");
304 s.BindInt(0, id);
305 s.BindString(1, name);
306
307 if (!s.Step())
308 {
309 return false;
310 }
311 else
312 {
313 fileUuid = s.ColumnString(0);
314 compressedSize = s.ColumnInt(1);
315 uncompressedSize = s.ColumnInt(2);
316 compressionType = static_cast<CompressionType>(s.ColumnInt(3));
317 return true;
318 }
319 }
320
321 void DatabaseWrapper::SetMainDicomTags(int64_t id,
322 const DicomMap& tags)
323 {
324 DicomArray flattened(tags);
325 for (size_t i = 0; i < flattened.GetSize(); i++)
326 {
327 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)");
328 s.BindInt(0, id);
329 s.BindInt(1, flattened.GetElement(i).GetTag().GetGroup());
330 s.BindInt(2, flattened.GetElement(i).GetTag().GetElement());
331 s.BindString(3, flattened.GetElement(i).GetValue().AsString());
332 s.Run();
333 }
334 }
335
336 void DatabaseWrapper::GetMainDicomTags(DicomMap& map,
337 int64_t id)
338 {
339 map.Clear();
340
341 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?");
342 s.BindInt(0, id);
343 while (s.Step())
344 {
345 map.SetValue(s.ColumnInt(1),
346 s.ColumnInt(2),
347 s.ColumnString(3));
348 }
349 }
350
351
352 bool DatabaseWrapper::GetParentPublicId(std::string& result,
353 int64_t id)
354 {
355 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b "
356 "WHERE a.internalId = b.parentId AND b.internalId = ?");
357 s.BindInt(0, id);
358
359 if (s.Step())
360 {
361 result = s.ColumnString(0);
362 return true;
363 }
364 else
365 {
366 return false;
367 }
368 }
369
370
371 void DatabaseWrapper::GetChildrenPublicId(std::list<std::string>& result,
372 int64_t id)
373 {
374 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b "
375 "WHERE a.parentId = b.internalId AND b.internalId = ?");
376 s.BindInt(0, id);
377
378 result.clear();
379
380 while (s.Step())
381 {
382 result.push_back(s.ColumnString(0));
383 }
384 }
385
386
387 void DatabaseWrapper::LogChange(ChangeType changeType,
388 const std::string& publicId,
389 ResourceType resourceType,
390 const boost::posix_time::ptime& date)
391 {
392 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Changes VALUES(NULL, ?, ?, ?, ?)");
393 s.BindInt(0, changeType);
394 s.BindString(1, publicId);
395 s.BindInt(2, resourceType);
396 s.BindString(3, boost::posix_time::to_iso_string(date));
397 s.Run();
398 }
399
400
401 void DatabaseWrapper::LogExportedInstance(const std::string& remoteModality,
402 DicomInstanceHasher& hasher,
403 const boost::posix_time::ptime& date)
404 {
405 SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO ExportedInstances VALUES(NULL, ?, ?, ?, ?, ?, ?)");
406 s.BindString(0, remoteModality);
407 s.BindString(1, hasher.HashInstance());
408 s.BindString(2, hasher.GetPatientId());
409 s.BindString(3, hasher.GetStudyUid());
410 s.BindString(4, hasher.GetSeriesUid());
411 s.BindString(5, hasher.GetInstanceUid());
412 s.BindString(6, boost::posix_time::to_iso_string(date));
413 s.Run();
414 }
415
416
417 int64_t DatabaseWrapper::GetTableRecordCount(const std::string& table)
418 {
419 char buf[128];
420 sprintf(buf, "SELECT COUNT(*) FROM %s", table.c_str());
421 SQLite::Statement s(db_, buf);
422
423 assert(s.Step());
424 int64_t c = s.ColumnInt(0);
425 assert(!s.Step());
426
427 return c;
428 }
429
430
431 uint64_t DatabaseWrapper::GetTotalCompressedSize()
432 {
433 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(compressedSize) FROM AttachedFiles");
434 s.Run();
435 return static_cast<uint64_t>(s.ColumnInt64(0));
436 }
437
438
439 uint64_t DatabaseWrapper::GetTotalUncompressedSize()
440 {
441 SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(uncompressedSize) FROM AttachedFiles");
442 s.Run();
443 return static_cast<uint64_t>(s.ColumnInt64(0));
444 }
445
446
447 DatabaseWrapper::DatabaseWrapper(const std::string& path,
448 IServerIndexListener& listener) :
449 listener_(listener)
450 {
451 db_.Open(path);
452 Open();
453 }
454
455 DatabaseWrapper::DatabaseWrapper(IServerIndexListener& listener) :
456 listener_(listener)
457 {
458 db_.OpenInMemory();
459 Open();
460 }
461
462 void DatabaseWrapper::Open()
463 {
464 if (!db_.DoesTableExist("GlobalProperties"))
465 {
466 LOG(INFO) << "Creating the database";
467 std::string query;
468 EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE_2);
469 db_.Execute(query);
470 }
471
472 signalRemainingAncestor_ = new Internals::SignalRemainingAncestor;
473 db_.Register(signalRemainingAncestor_);
474 db_.Register(new Internals::SignalFileDeleted(listener_));
475 }
476 }