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