Mercurial > hg > orthanc-databases
annotate Framework/PostgreSQL/PostgreSQLStatement.cpp @ 580:35d2df9572b1 find-refactoring tip
count-resources
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 15 Oct 2024 15:52:39 +0200 |
parents | c49136b34891 |
children |
rev | line source |
---|---|
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 | |
507
54d518dcd74a
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
460
diff
changeset
|
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
54d518dcd74a
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
460
diff
changeset
|
6 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
459
ecd0b719cff5
update year to 2024
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
389
diff
changeset
|
7 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 8 * |
9 * This program is free software: you can redistribute it and/or | |
10 * modify it under the terms of the GNU Affero General Public License | |
11 * as published by the Free Software Foundation, either version 3 of | |
12 * the License, or (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, but | |
15 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 * Affero General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU Affero General Public License | |
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 **/ | |
22 | |
23 | |
107
5765cc5fd268
reverted fix for OS X that breaks other targets
Sebastien Jodogne <s.jodogne@orthanc-labs.com>
parents:
105
diff
changeset
|
24 #include "PostgreSQLIncludes.h" // Must be the first |
105 | 25 #include "PostgreSQLStatement.h" |
0 | 26 |
27 #include "../Common/BinaryStringValue.h" | |
244
02cd7254c949
separating class InputFileValue from FileValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
237
diff
changeset
|
28 #include "../Common/InputFileValue.h" |
522
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
29 #include "../Common/Integer32Value.h" |
0 | 30 #include "../Common/Integer64Value.h" |
31 #include "../Common/NullValue.h" | |
32 #include "../Common/ResultBase.h" | |
33 #include "../Common/Utf8StringValue.h" | |
34 #include "PostgreSQLResult.h" | |
35 | |
157
275e14f57f1e
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
152
diff
changeset
|
36 #include <Compatibility.h> // For std::unique_ptr<> |
152 | 37 #include <Logging.h> |
38 #include <OrthancException.h> | |
39 #include <Toolbox.h> | |
40 #include <Endianness.h> | |
0 | 41 |
42 #include <cassert> | |
43 | |
44 | |
45 namespace OrthancDatabases | |
46 { | |
47 class PostgreSQLStatement::Inputs : public boost::noncopyable | |
48 { | |
49 private: | |
50 std::vector<char*> values_; | |
51 std::vector<int> sizes_; | |
52 | |
53 static char* Allocate(const void* source, int size) | |
54 { | |
55 if (size == 0) | |
56 { | |
57 return NULL; | |
58 } | |
59 else | |
60 { | |
61 char* ptr = reinterpret_cast<char*>(malloc(size)); | |
62 | |
63 if (source != NULL) | |
64 { | |
65 memcpy(ptr, source, size); | |
66 } | |
67 | |
68 return ptr; | |
69 } | |
70 } | |
71 | |
72 void Resize(size_t size) | |
73 { | |
74 // Shrinking of the vector | |
75 for (size_t i = size; i < values_.size(); i++) | |
76 { | |
77 if (values_[i] != NULL) | |
78 free(values_[i]); | |
79 } | |
80 | |
81 values_.resize(size, NULL); | |
82 sizes_.resize(size, 0); | |
83 } | |
84 | |
85 void EnlargeForIndex(size_t index) | |
86 { | |
87 if (index >= values_.size()) | |
88 { | |
89 // The vector is too small | |
90 Resize(index + 1); | |
91 } | |
92 } | |
93 | |
94 public: | |
95 Inputs() | |
96 { | |
97 } | |
98 | |
99 ~Inputs() | |
100 { | |
101 Resize(0); | |
102 } | |
103 | |
104 void SetItem(size_t pos, const void* source, int size) | |
105 { | |
106 EnlargeForIndex(pos); | |
107 | |
108 if (sizes_[pos] == size) | |
109 { | |
110 if (source && size != 0) | |
111 { | |
112 memcpy(values_[pos], source, size); | |
113 } | |
114 } | |
115 else | |
116 { | |
117 if (values_[pos] != NULL) | |
118 { | |
119 free(values_[pos]); | |
120 } | |
121 | |
122 values_[pos] = Allocate(source, size); | |
123 sizes_[pos] = size; | |
124 } | |
125 } | |
126 | |
127 void SetItem(size_t pos, int size) | |
128 { | |
129 SetItem(pos, NULL, size); | |
130 } | |
131 | |
132 void* GetItem(size_t pos) const | |
133 { | |
134 if (pos >= values_.size()) | |
135 { | |
136 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
137 } | |
138 | |
139 return values_[pos]; | |
140 } | |
141 | |
142 const std::vector<char*>& GetValues() const | |
143 { | |
144 return values_; | |
145 } | |
146 | |
147 const std::vector<int>& GetSizes() const | |
148 { | |
149 return sizes_; | |
150 } | |
151 }; | |
152 | |
153 | |
154 void PostgreSQLStatement::Prepare() | |
155 { | |
156 if (id_.size() > 0) | |
157 { | |
158 // Already prepared | |
159 return; | |
160 } | |
161 | |
162 for (size_t i = 0; i < oids_.size(); i++) | |
163 { | |
164 if (oids_[i] == 0) | |
165 { | |
166 // The type of an input parameter was not set | |
167 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
168 } | |
169 } | |
170 | |
171 id_ = Orthanc::Toolbox::GenerateUuid(); | |
172 | |
173 const unsigned int* tmp = oids_.size() ? &oids_[0] : NULL; | |
174 | |
175 PGresult* result = PQprepare(reinterpret_cast<PGconn*>(database_.pg_), | |
176 id_.c_str(), sql_.c_str(), oids_.size(), tmp); | |
177 | |
178 if (result == NULL) | |
179 { | |
180 id_.clear(); | |
181 database_.ThrowException(true); | |
182 } | |
183 | |
184 bool ok = (PQresultStatus(result) == PGRES_COMMAND_OK); | |
185 if (ok) | |
186 { | |
187 PQclear(result); | |
188 } | |
189 else | |
190 { | |
191 std::string message = PQresultErrorMessage(result); | |
192 PQclear(result); | |
193 id_.clear(); | |
194 LOG(ERROR) << "PostgreSQL error: " << message; | |
195 database_.ThrowException(false); | |
196 } | |
197 } | |
198 | |
199 | |
200 void PostgreSQLStatement::Unprepare() | |
201 { | |
202 if (id_.size() > 0) | |
203 { | |
204 // "Although there is no libpq function for deleting a | |
205 // prepared statement, the SQL DEALLOCATE statement can be | |
206 // used for that purpose." | |
237
35598014f140
refactoring to remove GlobalProperties.cpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
235
diff
changeset
|
207 database_.ExecuteMultiLines("DEALLOCATE \"" + id_ + "\""); |
0 | 208 } |
209 | |
210 id_.clear(); | |
211 } | |
212 | |
213 | |
214 void PostgreSQLStatement::DeclareInputInternal(unsigned int param, | |
215 unsigned int /*Oid*/ type) | |
216 { | |
217 Unprepare(); | |
218 | |
219 if (oids_.size() <= param) | |
220 { | |
221 oids_.resize(param + 1, 0); | |
222 binary_.resize(param + 1); | |
223 } | |
224 | |
225 oids_[param] = type; | |
226 binary_[param] = (type == TEXTOID || type == BYTEAOID || type == OIDOID) ? 0 : 1; | |
227 } | |
228 | |
229 | |
230 void PostgreSQLStatement::DeclareInputInteger(unsigned int param) | |
231 { | |
232 DeclareInputInternal(param, INT4OID); | |
233 } | |
234 | |
235 | |
236 void PostgreSQLStatement::DeclareInputInteger64(unsigned int param) | |
237 { | |
238 DeclareInputInternal(param, INT8OID); | |
239 } | |
240 | |
241 | |
242 void PostgreSQLStatement::DeclareInputString(unsigned int param) | |
243 { | |
244 DeclareInputInternal(param, TEXTOID); | |
245 } | |
246 | |
247 | |
248 void PostgreSQLStatement::DeclareInputBinary(unsigned int param) | |
249 { | |
250 DeclareInputInternal(param, BYTEAOID); | |
251 } | |
252 | |
253 | |
254 void PostgreSQLStatement::DeclareInputLargeObject(unsigned int param) | |
255 { | |
256 DeclareInputInternal(param, OIDOID); | |
257 } | |
258 | |
259 | |
260 void* /* PGresult* */ PostgreSQLStatement::Execute() | |
261 { | |
262 Prepare(); | |
263 | |
264 PGresult* result; | |
265 | |
266 if (oids_.size() == 0) | |
267 { | |
268 // No parameter | |
269 result = PQexecPrepared(reinterpret_cast<PGconn*>(database_.pg_), | |
270 id_.c_str(), 0, NULL, NULL, NULL, 1); | |
271 } | |
272 else | |
273 { | |
274 // At least 1 parameter | |
275 result = PQexecPrepared(reinterpret_cast<PGconn*>(database_.pg_), | |
276 id_.c_str(), | |
277 oids_.size(), | |
278 &inputs_->GetValues()[0], | |
279 &inputs_->GetSizes()[0], | |
280 &binary_[0], | |
281 1); | |
282 } | |
283 | |
234
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
284 if (PQtransactionStatus(reinterpret_cast<PGconn*>(database_.pg_)) == PQTRANS_INERROR) |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
285 { |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
286 if (result != NULL) |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
287 { |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
288 PQclear(result); |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
289 } |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
290 |
235
f2b32d31fc99
fix lsb build, fix backward compatibility with SDK <= 1.9.1
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
234
diff
changeset
|
291 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) |
445
cec6a0cd399f
now logging DatabaseCannotSerialize as a warning only with the details (Orthanc will log it as an error after all retries)
Alain Mazy <am@osimis.io>
parents:
429
diff
changeset
|
292 std::string errorString(PQresultErrorMessage(result)); |
cec6a0cd399f
now logging DatabaseCannotSerialize as a warning only with the details (Orthanc will log it as an error after all retries)
Alain Mazy <am@osimis.io>
parents:
429
diff
changeset
|
293 throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseCannotSerialize, errorString, false); // don't log here, it is handled at higher level |
235
f2b32d31fc99
fix lsb build, fix backward compatibility with SDK <= 1.9.1
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
234
diff
changeset
|
294 #else |
f2b32d31fc99
fix lsb build, fix backward compatibility with SDK <= 1.9.1
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
234
diff
changeset
|
295 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Collision between multiple writers"); |
f2b32d31fc99
fix lsb build, fix backward compatibility with SDK <= 1.9.1
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
234
diff
changeset
|
296 #endif |
234
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
297 } |
d1b124d116c1
PostgreSQL index plugin handles retries for collisions between multiple writers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
298 else if (result == NULL) |
0 | 299 { |
300 database_.ThrowException(true); | |
301 } | |
302 | |
303 return result; | |
304 } | |
305 | |
306 | |
307 PostgreSQLStatement::PostgreSQLStatement(PostgreSQLDatabase& database, | |
214
ab96698c73a3
removed useless information about read-only in ITransaction and IPrecompiledStatement
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
193
diff
changeset
|
308 const std::string& sql) : |
0 | 309 database_(database), |
310 sql_(sql), | |
311 inputs_(new Inputs), | |
312 formatter_(Dialect_PostgreSQL) | |
313 { | |
429
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
314 if (database.IsVerboseEnabled()) |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
315 { |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
316 LOG(TRACE) << "PostgreSQL: " << sql; |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
317 } |
0 | 318 } |
319 | |
320 | |
321 PostgreSQLStatement::PostgreSQLStatement(PostgreSQLDatabase& database, | |
322 const Query& query) : | |
323 database_(database), | |
324 inputs_(new Inputs), | |
325 formatter_(Dialect_PostgreSQL) | |
326 { | |
327 query.Format(sql_, formatter_); | |
429
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
328 |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
329 if (database.IsVerboseEnabled()) |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
330 { |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
331 LOG(TRACE) << "PostgreSQL: " << sql_; |
dbf811b1bb43
new configuration 'EnableVerboseLogs' to log SQL statements being executed
Alain Mazy <am@osimis.io>
parents:
389
diff
changeset
|
332 } |
0 | 333 |
334 for (size_t i = 0; i < formatter_.GetParametersCount(); i++) | |
335 { | |
336 switch (formatter_.GetParameterType(i)) | |
337 { | |
338 case ValueType_Integer64: | |
339 DeclareInputInteger64(i); | |
340 break; | |
341 | |
522
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
342 case ValueType_Integer32: |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
343 DeclareInputInteger(i); |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
344 break; |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
345 |
0 | 346 case ValueType_Utf8String: |
347 DeclareInputString(i); | |
348 break; | |
349 | |
350 case ValueType_BinaryString: | |
351 DeclareInputBinary(i); | |
352 break; | |
353 | |
244
02cd7254c949
separating class InputFileValue from FileValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
237
diff
changeset
|
354 case ValueType_InputFile: |
0 | 355 DeclareInputLargeObject(i); |
356 break; | |
357 | |
358 case ValueType_Null: | |
359 default: | |
360 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
361 } | |
362 } | |
363 } | |
364 | |
365 | |
46
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
366 PostgreSQLStatement::~PostgreSQLStatement() |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
367 { |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
368 try |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
369 { |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
370 Unprepare(); |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
371 } |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
372 catch (Orthanc::OrthancException&) |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
373 { |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
374 // Ignore possible exceptions due to connection loss |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
375 } |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
376 } |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
377 |
6a574d810b98
Compatibility with MySQL 8.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
23
diff
changeset
|
378 |
0 | 379 void PostgreSQLStatement::Run() |
380 { | |
381 PGresult* result = reinterpret_cast<PGresult*>(Execute()); | |
382 assert(result != NULL); // An exception would have been thrown otherwise | |
383 | |
384 bool ok = (PQresultStatus(result) == PGRES_COMMAND_OK || | |
385 PQresultStatus(result) == PGRES_TUPLES_OK); | |
386 if (ok) | |
387 { | |
388 PQclear(result); | |
389 } | |
390 else | |
391 { | |
392 std::string error = PQresultErrorMessage(result); | |
393 PQclear(result); | |
394 LOG(ERROR) << "PostgreSQL error: " << error; | |
395 database_.ThrowException(false); | |
396 } | |
397 } | |
398 | |
399 | |
400 void PostgreSQLStatement::BindNull(unsigned int param) | |
401 { | |
402 if (param >= oids_.size()) | |
403 { | |
404 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
405 } | |
406 | |
407 inputs_->SetItem(param, 0); | |
408 } | |
409 | |
410 | |
411 void PostgreSQLStatement::BindInteger(unsigned int param, | |
412 int value) | |
413 { | |
414 if (param >= oids_.size()) | |
415 { | |
416 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
417 } | |
418 | |
419 if (oids_[param] != INT4OID) | |
420 { | |
421 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); | |
422 } | |
423 | |
424 assert(sizeof(int32_t) == 4); | |
425 int32_t v = htobe32(static_cast<int32_t>(value)); | |
426 inputs_->SetItem(param, &v, sizeof(int32_t)); | |
427 } | |
428 | |
429 | |
430 void PostgreSQLStatement::BindInteger64(unsigned int param, | |
431 int64_t value) | |
432 { | |
433 if (param >= oids_.size()) | |
434 { | |
435 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
436 } | |
437 | |
438 if (oids_[param] != INT8OID) | |
439 { | |
440 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); | |
441 } | |
442 | |
443 assert(sizeof(int64_t) == 8); | |
444 int64_t v = htobe64(value); | |
445 inputs_->SetItem(param, &v, sizeof(int64_t)); | |
446 } | |
447 | |
448 | |
449 void PostgreSQLStatement::BindString(unsigned int param, | |
450 const std::string& value) | |
451 { | |
452 if (param >= oids_.size()) | |
453 { | |
454 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
455 } | |
456 | |
457 if (oids_[param] != TEXTOID && oids_[param] != BYTEAOID) | |
458 { | |
459 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); | |
460 } | |
461 | |
462 if (value.size() == 0) | |
463 { | |
464 inputs_->SetItem(param, "", 1 /* end-of-string character */); | |
465 } | |
466 else | |
467 { | |
468 inputs_->SetItem(param, value.c_str(), | |
469 value.size() + 1); // "+1" for end-of-string character | |
470 } | |
471 } | |
472 | |
473 | |
474 void PostgreSQLStatement::BindLargeObject(unsigned int param, | |
475 const PostgreSQLLargeObject& value) | |
476 { | |
477 if (param >= oids_.size()) | |
478 { | |
479 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
480 } | |
481 | |
482 if (oids_[param] != OIDOID) | |
483 { | |
484 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); | |
485 } | |
486 | |
487 inputs_->SetItem(param, value.GetOid().c_str(), | |
488 value.GetOid().size() + 1); // "+1" for end-of-string character | |
489 } | |
490 | |
491 | |
492 class PostgreSQLStatement::ResultWrapper : public ResultBase | |
493 { | |
494 private: | |
157
275e14f57f1e
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
152
diff
changeset
|
495 std::unique_ptr<PostgreSQLResult> result_; |
0 | 496 |
497 protected: | |
498 virtual IValue* FetchField(size_t index) | |
499 { | |
500 return result_->GetValue(index); | |
501 } | |
502 | |
503 public: | |
186 | 504 explicit ResultWrapper(PostgreSQLStatement& statement) : |
0 | 505 result_(new PostgreSQLResult(statement)) |
506 { | |
507 SetFieldsCount(result_->GetColumnsCount()); | |
508 FetchFields(); | |
509 } | |
510 | |
511 virtual void Next() | |
512 { | |
513 result_->Next(); | |
514 FetchFields(); | |
515 } | |
516 | |
517 virtual bool IsDone() const | |
518 { | |
519 return result_->IsDone(); | |
520 } | |
521 }; | |
522 | |
523 | |
23
b2ff1cd2907a
handling of implicit transactions in DatabaseManager
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
524 IResult* PostgreSQLStatement::Execute(ITransaction& transaction, |
0 | 525 const Dictionary& parameters) |
526 { | |
527 for (size_t i = 0; i < formatter_.GetParametersCount(); i++) | |
528 { | |
529 const std::string& name = formatter_.GetParameterName(i); | |
530 | |
531 switch (formatter_.GetParameterType(i)) | |
532 { | |
533 case ValueType_Integer64: | |
534 BindInteger64(i, dynamic_cast<const Integer64Value&>(parameters.GetValue(name)).GetValue()); | |
535 break; | |
536 | |
522
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
537 case ValueType_Integer32: |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
538 BindInteger(i, dynamic_cast<const Integer32Value&>(parameters.GetValue(name)).GetValue()); |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
539 break; |
c49136b34891
use a prepared statement for InsertOrUpdateMetadata
Alain Mazy <am@orthanc.team>
parents:
507
diff
changeset
|
540 |
0 | 541 case ValueType_Null: |
542 BindNull(i); | |
543 break; | |
544 | |
545 case ValueType_Utf8String: | |
546 BindString(i, dynamic_cast<const Utf8StringValue&> | |
547 (parameters.GetValue(name)).GetContent()); | |
548 break; | |
549 | |
550 case ValueType_BinaryString: | |
551 BindString(i, dynamic_cast<const BinaryStringValue&> | |
552 (parameters.GetValue(name)).GetContent()); | |
553 break; | |
554 | |
244
02cd7254c949
separating class InputFileValue from FileValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
237
diff
changeset
|
555 case ValueType_InputFile: |
0 | 556 { |
244
02cd7254c949
separating class InputFileValue from FileValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
237
diff
changeset
|
557 const InputFileValue& blob = |
02cd7254c949
separating class InputFileValue from FileValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
237
diff
changeset
|
558 dynamic_cast<const InputFileValue&>(parameters.GetValue(name)); |
0 | 559 |
560 PostgreSQLLargeObject largeObject(database_, blob.GetContent()); | |
561 BindLargeObject(i, largeObject); | |
562 break; | |
563 } | |
564 | |
565 default: | |
566 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
567 } | |
568 } | |
569 | |
570 return new ResultWrapper(*this); | |
571 } | |
572 | |
573 | |
23
b2ff1cd2907a
handling of implicit transactions in DatabaseManager
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
574 void PostgreSQLStatement::ExecuteWithoutResult(ITransaction& transaction, |
0 | 575 const Dictionary& parameters) |
576 { | |
157
275e14f57f1e
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
152
diff
changeset
|
577 std::unique_ptr<IResult> dummy(Execute(transaction, parameters)); |
0 | 578 } |
579 } |