1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU 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 "PostgreSQLTransaction.h" 23 24 #include "PostgreSQLStatement.h" 25 26 #include <Compatibility.h> // For std::unique_ptr<> 27 #include <Logging.h> 28 #include <OrthancException.h> 29 30 namespace OrthancDatabases 31 { PostgreSQLTransaction(PostgreSQLDatabase & database,TransactionType type)32 PostgreSQLTransaction::PostgreSQLTransaction(PostgreSQLDatabase& database, 33 TransactionType type) : 34 database_(database), 35 isOpen_(false) 36 { 37 Begin(type); 38 } 39 40 ~PostgreSQLTransaction()41 PostgreSQLTransaction::~PostgreSQLTransaction() 42 { 43 if (isOpen_) 44 { 45 LOG(INFO) << "PostgreSQL: An active PostgreSQL transaction was dismissed"; 46 47 try 48 { 49 database_.ExecuteMultiLines("ABORT"); 50 } 51 catch (Orthanc::OrthancException&) 52 { 53 // Ignore possible exceptions due to connection loss 54 } 55 } 56 } 57 58 Begin(TransactionType type)59 void PostgreSQLTransaction::Begin(TransactionType type) 60 { 61 if (isOpen_) 62 { 63 LOG(ERROR) << "PostgreSQL: Beginning a transaction twice!"; 64 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 65 } 66 67 database_.ExecuteMultiLines("BEGIN"); 68 69 switch (type) 70 { 71 case TransactionType_ReadWrite: 72 database_.ExecuteMultiLines("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ WRITE"); 73 break; 74 75 case TransactionType_ReadOnly: 76 database_.ExecuteMultiLines("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY"); 77 break; 78 79 default: 80 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 81 } 82 83 isOpen_ = true; 84 } 85 86 Rollback()87 void PostgreSQLTransaction::Rollback() 88 { 89 if (!isOpen_) 90 { 91 LOG(ERROR) << "PostgreSQL: Attempting to rollback a nonexistent transaction. " 92 << "Did you remember to call Begin()?"; 93 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 94 } 95 96 database_.ExecuteMultiLines("ABORT"); 97 isOpen_ = false; 98 } 99 100 Commit()101 void PostgreSQLTransaction::Commit() 102 { 103 if (!isOpen_) 104 { 105 LOG(ERROR) << "PostgreSQL: Attempting to roll back a nonexistent transaction. " 106 << "Did you remember to call Begin()?"; 107 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 108 } 109 110 database_.ExecuteMultiLines("COMMIT"); 111 isOpen_ = false; 112 } 113 114 Execute(IPrecompiledStatement & statement,const Dictionary & parameters)115 IResult* PostgreSQLTransaction::Execute(IPrecompiledStatement& statement, 116 const Dictionary& parameters) 117 { 118 return dynamic_cast<PostgreSQLStatement&>(statement).Execute(*this, parameters); 119 } 120 121 ExecuteWithoutResult(IPrecompiledStatement & statement,const Dictionary & parameters)122 void PostgreSQLTransaction::ExecuteWithoutResult(IPrecompiledStatement& statement, 123 const Dictionary& parameters) 124 { 125 dynamic_cast<PostgreSQLStatement&>(statement).ExecuteWithoutResult(*this, parameters); 126 } 127 } 128