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 "Statement.h"
43 #include "Connection.h"
44 
45 #include <string.h>
46 #include <stdio.h>
47 #include <algorithm>
48 
49 #if (ORTHANC_SQLITE_STANDALONE == 1)
50 // Trace logging is disabled if this SQLite wrapper is used
51 // independently of Orthanc
52 #  define LOG_CREATE(message);
53 #  define LOG_APPLY(message);
54 #elif defined(NDEBUG)
55 // Trace logging is disabled in release builds
56 #  include "../Logging.h"
57 #  define LOG_CREATE(message);
58 #  define LOG_APPLY(message);
59 #else
60 // Trace logging is enabled in debug builds
61 #  include "../Logging.h"
62 #  define LOG_CREATE(message)  CLOG(TRACE, SQLITE) << "SQLite::Statement create: " << message;
63 #  define LOG_APPLY(message);  // CLOG(TRACE, SQLITE) << "SQLite::Statement apply: " << message;
64 #endif
65 
66 #include "sqlite3.h"
67 
68 #if defined(_MSC_VER)
69 #define snprintf _snprintf
70 #endif
71 
72 
73 namespace Orthanc
74 {
75   namespace SQLite
76   {
CheckError(int err,ErrorCode code) const77     int Statement::CheckError(int err, ErrorCode code) const
78     {
79       bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
80       if (!succeeded)
81       {
82 #if ORTHANC_SQLITE_STANDALONE != 1
83         char buffer[128];
84         snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err);
85         LOG(ERROR) << buffer;
86 #endif
87 
88         throw OrthancSQLiteException(code);
89       }
90 
91       return err;
92     }
93 
CheckOk(int err,ErrorCode code) const94     void Statement::CheckOk(int err, ErrorCode code) const
95     {
96       if (err == SQLITE_RANGE)
97       {
98         // Binding to a non-existent variable is evidence of a serious error.
99         throw OrthancSQLiteException(ErrorCode_SQLiteBindOutOfRange);
100       }
101       else if (err != SQLITE_OK)
102       {
103 #if ORTHANC_SQLITE_STANDALONE != 1
104         char buffer[128];
105         snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err);
106         LOG(ERROR) << buffer;
107 #endif
108 
109         throw OrthancSQLiteException(code);
110       }
111     }
112 
113 
Statement(Connection & database,const StatementId & id,const std::string & sql)114     Statement::Statement(Connection& database,
115                          const StatementId& id,
116                          const std::string& sql) :
117       reference_(database.GetCachedStatement(id, sql.c_str()))
118     {
119       Reset(true);
120       LOG_CREATE(sql);
121     }
122 
123 
Statement(Connection & database,const StatementId & id,const char * sql)124     Statement::Statement(Connection& database,
125                          const StatementId& id,
126                          const char* sql) :
127       reference_(database.GetCachedStatement(id, sql))
128     {
129       Reset(true);
130       LOG_CREATE(sql);
131     }
132 
~Statement()133     Statement::~Statement()
134     {
135       Reset();
136     }
137 
138 
Statement(Connection & database,const std::string & sql)139     Statement::Statement(Connection& database,
140                          const std::string& sql) :
141       reference_(database.GetWrappedObject(), sql.c_str())
142     {
143       LOG_CREATE(sql);
144     }
145 
146 
Statement(Connection & database,const char * sql)147     Statement::Statement(Connection& database,
148                          const char* sql) :
149       reference_(database.GetWrappedObject(), sql)
150     {
151       LOG_CREATE(sql);
152     }
153 
154 
Run()155     bool Statement::Run()
156     {
157       LOG_APPLY(sqlite3_sql(GetStatement()));
158 
159       return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotRun) == SQLITE_DONE;
160     }
161 
Step()162     bool Statement::Step()
163     {
164       LOG_APPLY(sqlite3_sql(GetStatement()));
165 
166       return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotStep) == SQLITE_ROW;
167     }
168 
Reset(bool clear_bound_vars)169     void Statement::Reset(bool clear_bound_vars)
170     {
171       // We don't call CheckError() here because sqlite3_reset() returns
172       // the last error that Step() caused thereby generating a second
173       // spurious error callback.
174       if (clear_bound_vars)
175         sqlite3_clear_bindings(GetStatement());
176       //CLOG(TRACE, SQLITE) << "SQLite::Statement::Reset";
177       sqlite3_reset(GetStatement());
178     }
179 
GetOriginalSQLStatement()180     std::string Statement::GetOriginalSQLStatement()
181     {
182       return std::string(sqlite3_sql(GetStatement()));
183     }
184 
185 
BindNull(int col)186     void Statement::BindNull(int col)
187     {
188       CheckOk(sqlite3_bind_null(GetStatement(), col + 1),
189               ErrorCode_BadParameterType);
190     }
191 
BindBool(int col,bool val)192     void Statement::BindBool(int col, bool val)
193     {
194       BindInt(col, val ? 1 : 0);
195     }
196 
BindInt(int col,int val)197     void Statement::BindInt(int col, int val)
198     {
199       CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val),
200               ErrorCode_BadParameterType);
201     }
202 
BindInt64(int col,int64_t val)203     void Statement::BindInt64(int col, int64_t val)
204     {
205       CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val),
206               ErrorCode_BadParameterType);
207     }
208 
BindDouble(int col,double val)209     void Statement::BindDouble(int col, double val)
210     {
211       CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val),
212               ErrorCode_BadParameterType);
213     }
214 
BindCString(int col,const char * val)215     void Statement::BindCString(int col, const char* val)
216     {
217       CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT),
218               ErrorCode_BadParameterType);
219     }
220 
BindString(int col,const std::string & val)221     void Statement::BindString(int col, const std::string& val)
222     {
223       CheckOk(sqlite3_bind_text(GetStatement(),
224                                 col + 1,
225                                 val.data(),
226                                 static_cast<int>(val.size()),
227                                 SQLITE_TRANSIENT),
228               ErrorCode_BadParameterType);
229     }
230 
231     /*void Statement::BindString16(int col, const string16& value)
232       {
233       BindString(col, UTF16ToUTF8(value));
234       }*/
235 
BindBlob(int col,const void * val,int val_len)236     void Statement::BindBlob(int col, const void* val, int val_len)
237     {
238       CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT),
239               ErrorCode_BadParameterType);
240     }
241 
242 
ColumnCount() const243     int Statement::ColumnCount() const
244     {
245       return sqlite3_column_count(GetStatement());
246     }
247 
248 
GetColumnType(int col) const249     ColumnType Statement::GetColumnType(int col) const
250     {
251       // Verify that our enum matches sqlite's values.
252       assert(COLUMN_TYPE_INTEGER == SQLITE_INTEGER);
253       assert(COLUMN_TYPE_FLOAT == SQLITE_FLOAT);
254       assert(COLUMN_TYPE_TEXT == SQLITE_TEXT);
255       assert(COLUMN_TYPE_BLOB == SQLITE_BLOB);
256       assert(COLUMN_TYPE_NULL == SQLITE_NULL);
257 
258       return static_cast<ColumnType>(sqlite3_column_type(GetStatement(), col));
259     }
260 
GetDeclaredColumnType(int col) const261     ColumnType Statement::GetDeclaredColumnType(int col) const
262     {
263       std::string column_type(sqlite3_column_decltype(GetStatement(), col));
264       std::transform(column_type.begin(), column_type.end(), column_type.begin(), tolower);
265 
266       if (column_type == "integer")
267         return COLUMN_TYPE_INTEGER;
268       else if (column_type == "float")
269         return COLUMN_TYPE_FLOAT;
270       else if (column_type == "text")
271         return COLUMN_TYPE_TEXT;
272       else if (column_type == "blob")
273         return COLUMN_TYPE_BLOB;
274 
275       return COLUMN_TYPE_NULL;
276     }
277 
ColumnIsNull(int col) const278     bool Statement::ColumnIsNull(int col) const
279     {
280       return sqlite3_column_type(GetStatement(), col) == SQLITE_NULL;
281     }
282 
ColumnBool(int col) const283     bool Statement::ColumnBool(int col) const
284     {
285       return !!ColumnInt(col);
286     }
287 
ColumnInt(int col) const288     int Statement::ColumnInt(int col) const
289     {
290       return sqlite3_column_int(GetStatement(), col);
291     }
292 
ColumnInt64(int col) const293     int64_t Statement::ColumnInt64(int col) const
294     {
295       return sqlite3_column_int64(GetStatement(), col);
296     }
297 
ColumnDouble(int col) const298     double Statement::ColumnDouble(int col) const
299     {
300       return sqlite3_column_double(GetStatement(), col);
301     }
302 
ColumnString(int col) const303     std::string Statement::ColumnString(int col) const
304     {
305       const char* str = reinterpret_cast<const char*>(
306         sqlite3_column_text(GetStatement(), col));
307       int len = sqlite3_column_bytes(GetStatement(), col);
308 
309       std::string result;
310       if (str && len > 0)
311         result.assign(str, len);
312       return result;
313     }
314 
315     /*string16 Statement::ColumnString16(int col) const
316       {
317       std::string s = ColumnString(col);
318       return !s.empty() ? UTF8ToUTF16(s) : string16();
319       }*/
320 
ColumnByteLength(int col) const321     int Statement::ColumnByteLength(int col) const
322     {
323       return sqlite3_column_bytes(GetStatement(), col);
324     }
325 
ColumnBlob(int col) const326     const void* Statement::ColumnBlob(int col) const
327     {
328       return sqlite3_column_blob(GetStatement(), col);
329     }
330 
ColumnBlobAsString(int col,std::string * blob)331     bool Statement::ColumnBlobAsString(int col, std::string* blob)
332     {
333       const void* p = ColumnBlob(col);
334       size_t len = ColumnByteLength(col);
335       blob->resize(len);
336       if (blob->size() != len) {
337         return false;
338       }
339       blob->assign(reinterpret_cast<const char*>(p), len);
340       return true;
341     }
342 
343     /*bool Statement::ColumnBlobAsString16(int col, string16* val) const
344       {
345       const void* data = ColumnBlob(col);
346       size_t len = ColumnByteLength(col) / sizeof(char16);
347       val->resize(len);
348       if (val->size() != len)
349       return false;
350       val->assign(reinterpret_cast<const char16*>(data), len);
351       return true;
352       }*/
353 
354     /*bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const
355     {
356       val->clear();
357 
358       const void* data = sqlite3_column_blob(GetStatement(), col);
359       int len = sqlite3_column_bytes(GetStatement(), col);
360       if (data && len > 0) {
361         val->resize(len);
362         memcpy(&(*val)[0], data, len);
363       }
364       return true;
365       }*/
366 
367     /*bool Statement::ColumnBlobAsVector(
368       int col,
369       std::vector<unsigned char>* val) const
370     {
371       return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val));
372       }*/
373 
374   }
375 }
376