Mercurial > hg > orthanc-databases
comparison Framework/Common/DatabaseManager.cpp @ 70:e6c13ddd26d9 db-changes
all integration tests passing with LookupResources extension
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 03 Jan 2019 14:04:46 +0100 |
parents | 714c5d2bee76 |
children | 569e17419eae |
comparison
equal
deleted
inserted
replaced
69:19764fc60ade | 70:e6c13ddd26d9 |
---|---|
277 } | 277 } |
278 } | 278 } |
279 } | 279 } |
280 | 280 |
281 | 281 |
282 IResult& DatabaseManager::CachedStatement::GetResult() const | |
283 { | |
284 if (result_.get() == NULL) | |
285 { | |
286 LOG(ERROR) << "Accessing the results of a statement without having executed it"; | |
287 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
288 } | |
289 | |
290 return *result_; | |
291 } | |
292 | |
293 | |
294 void DatabaseManager::CachedStatement::Setup(const char* sql) | |
295 { | |
296 statement_ = manager_.LookupCachedStatement(location_); | |
297 | |
298 if (statement_ == NULL) | |
299 { | |
300 query_.reset(new Query(sql)); | |
301 } | |
302 else | |
303 { | |
304 LOG(TRACE) << "Reusing cached statement from " | |
305 << location_.GetFile() << ":" << location_.GetLine(); | |
306 } | |
307 } | |
308 | |
309 | |
310 DatabaseManager::Transaction::Transaction(DatabaseManager& manager) : | 282 DatabaseManager::Transaction::Transaction(DatabaseManager& manager) : |
311 lock_(manager.mutex_), | 283 lock_(manager.mutex_), |
312 manager_(manager), | 284 manager_(manager), |
313 database_(manager.GetDatabase()), | 285 database_(manager.GetDatabase()), |
314 committed_(false) | 286 committed_(false) |
345 manager_.CommitTransaction(); | 317 manager_.CommitTransaction(); |
346 committed_ = true; | 318 committed_ = true; |
347 } | 319 } |
348 } | 320 } |
349 | 321 |
322 | |
323 IResult& DatabaseManager::StatementBase::GetResult() const | |
324 { | |
325 if (result_.get() == NULL) | |
326 { | |
327 LOG(ERROR) << "Accessing the results of a statement without having executed it"; | |
328 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
329 } | |
330 | |
331 return *result_; | |
332 } | |
333 | |
334 | |
335 void DatabaseManager::StatementBase::SetQuery(Query* query) | |
336 { | |
337 std::auto_ptr<Query> protection(query); | |
338 | |
339 if (query_.get() != NULL) | |
340 { | |
341 LOG(ERROR) << "Cannot set twice a query"; | |
342 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
343 } | |
344 | |
345 if (query == NULL) | |
346 { | |
347 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
348 } | |
349 | |
350 query_.reset(protection.release()); | |
351 } | |
352 | |
353 | |
354 void DatabaseManager::StatementBase::SetResult(IResult* result) | |
355 { | |
356 std::auto_ptr<IResult> protection(result); | |
357 | |
358 if (result_.get() != NULL) | |
359 { | |
360 LOG(ERROR) << "Cannot execute twice a statement"; | |
361 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
362 } | |
363 | |
364 if (result == NULL) | |
365 { | |
366 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
367 } | |
368 | |
369 result_.reset(protection.release()); | |
370 } | |
371 | |
372 | |
373 DatabaseManager::StatementBase::StatementBase(DatabaseManager& manager) : | |
374 manager_(manager), | |
375 lock_(manager_.mutex_), | |
376 transaction_(manager_.GetTransaction()) | |
377 { | |
378 } | |
379 | |
380 | |
381 DatabaseManager::StatementBase::~StatementBase() | |
382 { | |
383 manager_.ReleaseImplicitTransaction(); | |
384 } | |
385 | |
386 | |
387 void DatabaseManager::StatementBase::SetReadOnly(bool readOnly) | |
388 { | |
389 if (query_.get() != NULL) | |
390 { | |
391 query_->SetReadOnly(readOnly); | |
392 } | |
393 } | |
394 | |
395 | |
396 void DatabaseManager::StatementBase::SetParameterType(const std::string& parameter, | |
397 ValueType type) | |
398 { | |
399 if (query_.get() != NULL) | |
400 { | |
401 query_->SetType(parameter, type); | |
402 } | |
403 } | |
404 | |
405 bool DatabaseManager::StatementBase::IsDone() const | |
406 { | |
407 try | |
408 { | |
409 return GetResult().IsDone(); | |
410 } | |
411 catch (Orthanc::OrthancException& e) | |
412 { | |
413 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
414 throw; | |
415 } | |
416 } | |
417 | |
418 | |
419 void DatabaseManager::StatementBase::Next() | |
420 { | |
421 try | |
422 { | |
423 GetResult().Next(); | |
424 } | |
425 catch (Orthanc::OrthancException& e) | |
426 { | |
427 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
428 throw; | |
429 } | |
430 } | |
431 | |
432 | |
433 size_t DatabaseManager::StatementBase::GetResultFieldsCount() const | |
434 { | |
435 try | |
436 { | |
437 return GetResult().GetFieldsCount(); | |
438 } | |
439 catch (Orthanc::OrthancException& e) | |
440 { | |
441 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
442 throw; | |
443 } | |
444 } | |
445 | |
446 | |
447 void DatabaseManager::StatementBase::SetResultFieldType(size_t field, | |
448 ValueType type) | |
449 { | |
450 try | |
451 { | |
452 if (!GetResult().IsDone()) | |
453 { | |
454 GetResult().SetExpectedType(field, type); | |
455 } | |
456 } | |
457 catch (Orthanc::OrthancException& e) | |
458 { | |
459 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
460 throw; | |
461 } | |
462 } | |
463 | |
464 | |
465 const IValue& DatabaseManager::StatementBase::GetResultField(size_t index) const | |
466 { | |
467 try | |
468 { | |
469 return GetResult().GetField(index); | |
470 } | |
471 catch (Orthanc::OrthancException& e) | |
472 { | |
473 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
474 throw; | |
475 } | |
476 } | |
477 | |
350 | 478 |
351 DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location, | 479 DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location, |
352 DatabaseManager& manager, | 480 DatabaseManager& manager, |
353 const char* sql) : | 481 const std::string& sql) : |
354 manager_(manager), | 482 StatementBase(manager), |
355 lock_(manager_.mutex_), | 483 location_(location) |
356 database_(manager_.GetDatabase()), | 484 { |
357 location_(location), | 485 statement_ = GetManager().LookupCachedStatement(location_); |
358 transaction_(manager_.GetTransaction()) | 486 |
359 { | 487 if (statement_ == NULL) |
360 Setup(sql); | 488 { |
361 } | 489 SetQuery(new Query(sql)); |
362 | 490 } |
363 | 491 else |
364 DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location, | 492 { |
365 Transaction& transaction, | 493 LOG(TRACE) << "Reusing cached statement from " |
366 const char* sql) : | 494 << location_.GetFile() << ":" << location_.GetLine(); |
367 manager_(transaction.GetManager()), | 495 } |
368 lock_(manager_.mutex_), | 496 } |
369 database_(manager_.GetDatabase()), | 497 |
370 location_(location), | 498 |
371 transaction_(manager_.GetTransaction()) | |
372 { | |
373 Setup(sql); | |
374 } | |
375 | |
376 | |
377 DatabaseManager::CachedStatement::~CachedStatement() | |
378 { | |
379 manager_.ReleaseImplicitTransaction(); | |
380 } | |
381 | |
382 | |
383 void DatabaseManager::CachedStatement::SetReadOnly(bool readOnly) | |
384 { | |
385 if (query_.get() != NULL) | |
386 { | |
387 query_->SetReadOnly(readOnly); | |
388 } | |
389 } | |
390 | |
391 | |
392 void DatabaseManager::CachedStatement::SetParameterType(const std::string& parameter, | |
393 ValueType type) | |
394 { | |
395 if (query_.get() != NULL) | |
396 { | |
397 query_->SetType(parameter, type); | |
398 } | |
399 } | |
400 | |
401 | |
402 void DatabaseManager::CachedStatement::Execute() | |
403 { | |
404 Dictionary parameters; | |
405 Execute(parameters); | |
406 } | |
407 | |
408 | |
409 void DatabaseManager::CachedStatement::Execute(const Dictionary& parameters) | 499 void DatabaseManager::CachedStatement::Execute(const Dictionary& parameters) |
410 { | 500 { |
411 if (result_.get() != NULL) | 501 try |
412 { | 502 { |
413 LOG(ERROR) << "Cannot execute twice a statement"; | 503 std::auto_ptr<Query> query(ReleaseQuery()); |
414 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 504 |
415 } | 505 if (query.get() != NULL) |
416 | |
417 try | |
418 { | |
419 if (query_.get() != NULL) | |
420 { | 506 { |
421 // Register the newly-created statement | 507 // Register the newly-created statement |
422 assert(statement_ == NULL); | 508 assert(statement_ == NULL); |
423 statement_ = &manager_.CacheStatement(location_, *query_); | 509 statement_ = &GetManager().CacheStatement(location_, *query); |
424 query_.reset(NULL); | |
425 } | 510 } |
426 | 511 |
427 assert(statement_ != NULL); | 512 assert(statement_ != NULL); |
428 result_.reset(transaction_.Execute(*statement_, parameters)); | 513 SetResult(GetTransaction().Execute(*statement_, parameters)); |
429 } | 514 } |
430 catch (Orthanc::OrthancException& e) | 515 catch (Orthanc::OrthancException& e) |
431 { | 516 { |
432 manager_.CloseIfUnavailable(e.GetErrorCode()); | 517 GetManager().CloseIfUnavailable(e.GetErrorCode()); |
433 throw; | 518 throw; |
434 } | 519 } |
435 } | 520 } |
436 | 521 |
437 | 522 |
438 bool DatabaseManager::CachedStatement::IsDone() const | 523 DatabaseManager::StandaloneStatement::StandaloneStatement(DatabaseManager& manager, |
439 { | 524 const std::string& sql) : |
440 try | 525 StatementBase(manager) |
441 { | 526 { |
442 return GetResult().IsDone(); | 527 SetQuery(new Query(sql)); |
443 } | 528 } |
444 catch (Orthanc::OrthancException& e) | 529 |
445 { | 530 |
446 manager_.CloseIfUnavailable(e.GetErrorCode()); | 531 DatabaseManager::StandaloneStatement::~StandaloneStatement() |
447 throw; | 532 { |
448 } | 533 // The result must be removed before the statement, cf. (*) |
449 } | 534 ClearResult(); |
450 | 535 statement_.reset(); |
451 | 536 } |
452 void DatabaseManager::CachedStatement::Next() | 537 |
453 { | 538 |
454 try | 539 void DatabaseManager::StandaloneStatement::Execute(const Dictionary& parameters) |
455 { | 540 { |
456 GetResult().Next(); | 541 try |
457 } | 542 { |
458 catch (Orthanc::OrthancException& e) | 543 std::auto_ptr<Query> query(ReleaseQuery()); |
459 { | 544 assert(query.get() != NULL); |
460 manager_.CloseIfUnavailable(e.GetErrorCode()); | 545 |
461 throw; | 546 // The "statement_" object must be kept as long as the "IResult" |
462 } | 547 // is not destroyed, as the "IResult" can make calls to the |
463 } | 548 // statement (this is the case for SQLite and MySQL) - (*) |
464 | 549 statement_.reset(GetManager().GetDatabase().Compile(*query)); |
465 | 550 assert(statement_.get() != NULL); |
466 size_t DatabaseManager::CachedStatement::GetResultFieldsCount() const | 551 |
467 { | 552 SetResult(GetTransaction().Execute(*statement_, parameters)); |
468 try | 553 } |
469 { | 554 catch (Orthanc::OrthancException& e) |
470 return GetResult().GetFieldsCount(); | 555 { |
471 } | 556 GetManager().CloseIfUnavailable(e.GetErrorCode()); |
472 catch (Orthanc::OrthancException& e) | |
473 { | |
474 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
475 throw; | |
476 } | |
477 } | |
478 | |
479 | |
480 void DatabaseManager::CachedStatement::SetResultFieldType(size_t field, | |
481 ValueType type) | |
482 { | |
483 try | |
484 { | |
485 if (!GetResult().IsDone()) | |
486 { | |
487 GetResult().SetExpectedType(field, type); | |
488 } | |
489 } | |
490 catch (Orthanc::OrthancException& e) | |
491 { | |
492 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
493 throw; | |
494 } | |
495 } | |
496 | |
497 | |
498 const IValue& DatabaseManager::CachedStatement::GetResultField(size_t index) const | |
499 { | |
500 try | |
501 { | |
502 return GetResult().GetField(index); | |
503 } | |
504 catch (Orthanc::OrthancException& e) | |
505 { | |
506 manager_.CloseIfUnavailable(e.GetErrorCode()); | |
507 throw; | 557 throw; |
508 } | 558 } |
509 } | 559 } |
510 } | 560 } |