1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * 4 * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, 5 * Medical Physics Department, CHU of Liege, Belgium 6 * 7 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are 11 * met: 12 * 13 * * Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * * Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following disclaimer 17 * in the documentation and/or other materials provided with the 18 * distribution. 19 * * Neither the name of Google Inc., the name of the CHU of Liege, 20 * nor the names of its contributors may be used to endorse or promote 21 * products derived from this software without specific prior written 22 * permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 **/ 36 37 38 #if ORTHANC_SQLITE_STANDALONE != 1 39 #include "../PrecompiledHeaders.h" 40 #endif 41 42 #include "Connection.h" 43 #include "OrthancSQLiteException.h" 44 45 #include <memory> 46 #include <cassert> 47 #include <string.h> 48 49 #if ORTHANC_SQLITE_STANDALONE != 1 50 #include "../Logging.h" 51 #endif 52 53 #include "sqlite3.h" 54 55 56 namespace Orthanc 57 { 58 namespace SQLite 59 { Connection()60 Connection::Connection() : 61 db_(NULL), 62 transactionNesting_(0), 63 needsRollback_(false) 64 { 65 } 66 67 ~Connection()68 Connection::~Connection() 69 { 70 Close(); 71 } 72 73 CheckIsOpen() const74 void Connection::CheckIsOpen() const 75 { 76 if (!db_) 77 { 78 throw OrthancSQLiteException(ErrorCode_SQLiteNotOpened); 79 } 80 } 81 Open(const std::string & path)82 void Connection::Open(const std::string& path) 83 { 84 if (db_) 85 { 86 throw OrthancSQLiteException(ErrorCode_SQLiteAlreadyOpened); 87 } 88 89 int err = sqlite3_open(path.c_str(), &db_); 90 if (err != SQLITE_OK) 91 { 92 Close(); 93 db_ = NULL; 94 throw OrthancSQLiteException(ErrorCode_SQLiteCannotOpen); 95 } 96 97 // Execute PRAGMAs at this point 98 // http://www.sqlite.org/pragma.html 99 Execute("PRAGMA FOREIGN_KEYS=ON;"); 100 Execute("PRAGMA RECURSIVE_TRIGGERS=ON;"); 101 } 102 OpenInMemory()103 void Connection::OpenInMemory() 104 { 105 Open(":memory:"); 106 } 107 Close()108 void Connection::Close() 109 { 110 ClearCache(); 111 112 if (db_) 113 { 114 sqlite3_close(db_); 115 db_ = NULL; 116 } 117 } 118 ClearCache()119 void Connection::ClearCache() 120 { 121 for (CachedStatements::iterator 122 it = cachedStatements_.begin(); 123 it != cachedStatements_.end(); ++it) 124 { 125 delete it->second; 126 } 127 128 cachedStatements_.clear(); 129 } 130 131 GetCachedStatement(const StatementId & id,const char * sql)132 StatementReference& Connection::GetCachedStatement(const StatementId& id, 133 const char* sql) 134 { 135 CachedStatements::iterator i = cachedStatements_.find(id); 136 if (i != cachedStatements_.end()) 137 { 138 if (i->second->GetReferenceCount() >= 1) 139 { 140 throw OrthancSQLiteException(ErrorCode_SQLiteStatementAlreadyUsed); 141 } 142 143 return *i->second; 144 } 145 else 146 { 147 StatementReference* statement = new StatementReference(db_, sql); 148 cachedStatements_[id] = statement; 149 return *statement; 150 } 151 } 152 153 Execute(const char * sql)154 bool Connection::Execute(const char* sql) 155 { 156 #if ORTHANC_SQLITE_STANDALONE != 1 157 CLOG(TRACE, SQLITE) << "SQLite::Connection::Execute " << sql; 158 #endif 159 160 CheckIsOpen(); 161 162 int error = sqlite3_exec(db_, sql, NULL, NULL, NULL); 163 if (error == SQLITE_ERROR) 164 { 165 #if ORTHANC_SQLITE_STANDALONE != 1 166 LOG(ERROR) << "SQLite execute error: " << sqlite3_errmsg(db_) 167 << " (" << sqlite3_extended_errcode(db_) << ")"; 168 #endif 169 170 throw OrthancSQLiteException(ErrorCode_SQLiteExecute); 171 } 172 else 173 { 174 return error == SQLITE_OK; 175 } 176 } 177 Execute(const std::string & sql)178 bool Connection::Execute(const std::string &sql) 179 { 180 return Execute(sql.c_str()); 181 } 182 183 // Info querying ------------------------------------------------------------- 184 IsSQLValid(const char * sql)185 bool Connection::IsSQLValid(const char* sql) 186 { 187 sqlite3_stmt* stmt = NULL; 188 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) 189 return false; 190 191 sqlite3_finalize(stmt); 192 return true; 193 } 194 DoesTableOrIndexExist(const char * name,const char * type) const195 bool Connection::DoesTableOrIndexExist(const char* name, 196 const char* type) const 197 { 198 // Our SQL is non-mutating, so this cast is OK. 199 Statement statement(const_cast<Connection&>(*this), 200 "SELECT name FROM sqlite_master WHERE type=? AND name=?"); 201 statement.BindString(0, type); 202 statement.BindString(1, name); 203 return statement.Step(); // Table exists if any row was returned. 204 } 205 DoesTableExist(const char * table_name) const206 bool Connection::DoesTableExist(const char* table_name) const 207 { 208 return DoesTableOrIndexExist(table_name, "table"); 209 } 210 DoesIndexExist(const char * index_name) const211 bool Connection::DoesIndexExist(const char* index_name) const 212 { 213 return DoesTableOrIndexExist(index_name, "index"); 214 } 215 DoesColumnExist(const char * table_name,const char * column_name) const216 bool Connection::DoesColumnExist(const char* table_name, const char* column_name) const 217 { 218 std::string sql("PRAGMA TABLE_INFO("); 219 sql.append(table_name); 220 sql.append(")"); 221 222 // Our SQL is non-mutating, so this cast is OK. 223 Statement statement(const_cast<Connection&>(*this), sql.c_str()); 224 225 while (statement.Step()) { 226 if (!statement.ColumnString(1).compare(column_name)) 227 return true; 228 } 229 return false; 230 } 231 GetLastInsertRowId() const232 int64_t Connection::GetLastInsertRowId() const 233 { 234 return sqlite3_last_insert_rowid(db_); 235 } 236 GetLastChangeCount() const237 int Connection::GetLastChangeCount() const 238 { 239 return sqlite3_changes(db_); 240 } 241 GetErrorCode() const242 int Connection::GetErrorCode() const 243 { 244 return sqlite3_errcode(db_); 245 } 246 GetLastErrno() const247 int Connection::GetLastErrno() const 248 { 249 int err = 0; 250 if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err)) 251 return -2; 252 253 return err; 254 } 255 GetErrorMessage() const256 const char* Connection::GetErrorMessage() const 257 { 258 return sqlite3_errmsg(db_); 259 } 260 261 ExecuteAndReturnErrorCode(const char * sql)262 int Connection::ExecuteAndReturnErrorCode(const char* sql) 263 { 264 CheckIsOpen(); 265 return sqlite3_exec(db_, sql, NULL, NULL, NULL); 266 } 267 HasCachedStatement(const StatementId & id) const268 bool Connection::HasCachedStatement(const StatementId &id) const 269 { 270 return cachedStatements_.find(id) != cachedStatements_.end(); 271 } 272 GetTransactionNesting() const273 int Connection::GetTransactionNesting() const 274 { 275 return transactionNesting_; 276 } 277 BeginTransaction()278 bool Connection::BeginTransaction() 279 { 280 if (needsRollback_) 281 { 282 assert(transactionNesting_ > 0); 283 284 // When we're going to rollback, fail on this begin and don't actually 285 // mark us as entering the nested transaction. 286 return false; 287 } 288 289 bool success = true; 290 if (!transactionNesting_) 291 { 292 needsRollback_ = false; 293 294 Statement begin(*this, SQLITE_FROM_HERE, "BEGIN TRANSACTION"); 295 if (!begin.Run()) 296 return false; 297 } 298 transactionNesting_++; 299 return success; 300 } 301 RollbackTransaction()302 void Connection::RollbackTransaction() 303 { 304 if (!transactionNesting_) 305 { 306 throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction); 307 } 308 309 transactionNesting_--; 310 311 if (transactionNesting_ > 0) 312 { 313 // Mark the outermost transaction as needing rollback. 314 needsRollback_ = true; 315 return; 316 } 317 318 DoRollback(); 319 } 320 CommitTransaction()321 bool Connection::CommitTransaction() 322 { 323 if (!transactionNesting_) 324 { 325 throw OrthancSQLiteException(ErrorCode_SQLiteCommitWithoutTransaction); 326 } 327 transactionNesting_--; 328 329 if (transactionNesting_ > 0) 330 { 331 // Mark any nested transactions as failing after we've already got one. 332 return !needsRollback_; 333 } 334 335 if (needsRollback_) 336 { 337 DoRollback(); 338 return false; 339 } 340 341 Statement commit(*this, SQLITE_FROM_HERE, "COMMIT"); 342 return commit.Run(); 343 } 344 DoRollback()345 void Connection::DoRollback() 346 { 347 Statement rollback(*this, SQLITE_FROM_HERE, "ROLLBACK"); 348 rollback.Run(); 349 needsRollback_ = false; 350 } 351 352 353 354 355 356 ScalarFunctionCaller(sqlite3_context * rawContext,int argc,sqlite3_value ** argv)357 static void ScalarFunctionCaller(sqlite3_context* rawContext, 358 int argc, 359 sqlite3_value** argv) 360 { 361 FunctionContext context(rawContext, argc, argv); 362 363 void* payload = sqlite3_user_data(rawContext); 364 assert(payload != NULL); 365 366 IScalarFunction& func = *reinterpret_cast<IScalarFunction*>(payload); 367 func.Compute(context); 368 } 369 370 ScalarFunctionDestroyer(void * payload)371 static void ScalarFunctionDestroyer(void* payload) 372 { 373 assert(payload != NULL); 374 delete reinterpret_cast<IScalarFunction*>(payload); 375 } 376 377 Register(IScalarFunction * func)378 IScalarFunction* Connection::Register(IScalarFunction* func) 379 { 380 int err = sqlite3_create_function_v2(db_, 381 func->GetName(), 382 func->GetCardinality(), 383 SQLITE_UTF8, 384 func, 385 ScalarFunctionCaller, 386 NULL, 387 NULL, 388 ScalarFunctionDestroyer); 389 390 if (err != SQLITE_OK) 391 { 392 delete func; 393 throw OrthancSQLiteException(ErrorCode_SQLiteRegisterFunction); 394 } 395 396 return func; 397 } 398 399 FlushToDisk()400 void Connection::FlushToDisk() 401 { 402 #if ORTHANC_SQLITE_STANDALONE != 1 403 CLOG(TRACE, SQLITE) << "SQLite::Connection::FlushToDisk"; 404 #endif 405 406 int err = sqlite3_wal_checkpoint(db_, NULL); 407 408 if (err != SQLITE_OK) 409 { 410 throw OrthancSQLiteException(ErrorCode_SQLiteFlush); 411 } 412 } 413 } 414 } 415