]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2008,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | // | |
24 | // sqlite++ - C++ interface to SQLite3 | |
25 | // | |
26 | #include "sqlite++.h" | |
27 | #include <stdexcept> | |
28 | #include <security_utilities/cfutilities.h> | |
866f8763 | 29 | #include <security_utilities/debugging_internal.h> |
b1ab9ed8 A |
30 | |
31 | ||
32 | //@@@ | |
33 | // From cssmapple.h - layering break | |
34 | // Where should this go? | |
35 | //@@@ | |
36 | #define errSecErrnoBase 100000 | |
37 | #define errSecErrnoLimit 100255 | |
38 | ||
39 | ||
40 | namespace Security { | |
41 | namespace SQLite3 { | |
42 | ||
43 | ||
44 | // | |
45 | // Our exception object | |
46 | // | |
47 | void Error::check(int err) | |
48 | { | |
49 | if (err != SQLITE_OK) | |
50 | throw Error(err); | |
51 | } | |
52 | ||
53 | Error::Error(Database &db) | |
54 | : error(db.errcode()), message(db.errmsg()) | |
55 | { | |
fa7225c8 A |
56 | SECURITY_EXCEPTION_THROW_SQLITE(this, error, (char*)message.c_str()); |
57 | secnotice("security_exception", "sqlite: %d %s",error, (char*)message.c_str()); | |
b1ab9ed8 | 58 | } |
fa7225c8 | 59 | |
b1ab9ed8 A |
60 | void Error::throwMe(int err) |
61 | { | |
62 | throw Error(err); | |
63 | } | |
64 | ||
65 | OSStatus Error::osStatus() const | |
66 | { | |
67 | return unixError() + errSecErrnoBase; | |
68 | } | |
69 | ||
70 | int Error::unixError() const | |
71 | { | |
72 | switch (error) { | |
73 | case SQLITE_PERM: | |
74 | case SQLITE_READONLY: | |
75 | case SQLITE_AUTH: | |
76 | return EACCES; | |
77 | case SQLITE_BUSY: | |
78 | return EAGAIN; | |
79 | case SQLITE_NOMEM: | |
80 | return ENOMEM; | |
81 | case SQLITE_IOERR: | |
82 | return EIO; | |
83 | case SQLITE_FULL: | |
84 | return ENOSPC; | |
85 | case SQLITE_TOOBIG: | |
86 | return EFBIG; | |
87 | case SQLITE_MISMATCH: | |
88 | case SQLITE_MISUSE: | |
89 | return EINVAL; | |
90 | case SQLITE_NOLFS: | |
91 | return ENOTSUP; | |
92 | case SQLITE_RANGE: | |
93 | return EDOM; | |
94 | default: | |
95 | return -1; | |
96 | } | |
97 | } | |
98 | ||
99 | ||
100 | // | |
101 | // Database objects | |
102 | // | |
427c49bc | 103 | Database::Database(const char *path, int flags, bool lenient /* = false */) |
b1ab9ed8 A |
104 | : mMutex(Mutex::recursive) |
105 | { | |
106 | try { | |
427c49bc A |
107 | int rc = ::sqlite3_open_v2(path, &mDb, flags, NULL); |
108 | if (rc != SQLITE_OK && lenient) { // silent open failure | |
109 | sqlite3_close(mDb); // ditch useless Db object | |
110 | mDb = NULL; // indicate failure | |
111 | return; | |
112 | } | |
113 | check(rc); | |
b1ab9ed8 A |
114 | check(::sqlite3_extended_result_codes(mDb, true)); |
115 | mOpenFlags = flags; | |
116 | } catch (...) { | |
117 | sqlite3_close(mDb); // allocated even if open fails(!) | |
118 | throw; | |
119 | } | |
120 | } | |
121 | ||
122 | Database::~Database() | |
123 | { | |
124 | this->close(); | |
125 | } | |
126 | ||
127 | void Database::close() | |
128 | { | |
129 | if (mDb) | |
130 | check(::sqlite3_close(mDb)); | |
131 | } | |
132 | ||
133 | ||
134 | int Database::execute(const char *text, bool strict /* = true */) | |
135 | { | |
136 | StLock<Mutex> _(mMutex); | |
137 | ||
138 | int rc = ::sqlite3_exec(mDb, text, NULL, NULL, NULL); | |
139 | if (strict) | |
140 | check(rc); | |
141 | return rc; | |
142 | } | |
143 | ||
144 | ||
145 | void Database::busyDelay(int ms) | |
146 | { | |
147 | StLock<Mutex> _(mMutex); | |
148 | ||
149 | check(::sqlite3_busy_timeout(mDb, ms)); | |
150 | } | |
151 | ||
152 | ||
153 | void Database::check(int err) | |
154 | { | |
155 | if (err) | |
156 | throw Error(*this); | |
157 | } | |
158 | ||
159 | ||
160 | bool Database::empty() | |
161 | { | |
162 | return value("select count(*) from sqlite_master;", 0) == 0; | |
163 | } | |
164 | ||
165 | ||
166 | int Database::errcode() | |
167 | { | |
168 | StLock<Mutex> _(mMutex); | |
169 | ||
170 | return sqlite3_errcode(mDb); | |
171 | } | |
172 | ||
173 | ||
174 | ||
175 | const char *Database::errmsg() | |
176 | { | |
177 | StLock<Mutex> _(mMutex); | |
178 | ||
179 | return sqlite3_errmsg(mDb); | |
180 | } | |
181 | ||
182 | ||
183 | ||
184 | bool Database::inTransaction() | |
185 | { | |
186 | StLock<Mutex> _(mMutex); | |
187 | ||
188 | return !::sqlite3_get_autocommit(mDb); | |
189 | } | |
190 | ||
191 | ||
192 | ||
193 | int64 Database::lastInsert() | |
194 | { | |
195 | StLock<Mutex> _(mMutex); | |
196 | ||
197 | return ::sqlite3_last_insert_rowid(mDb); | |
198 | } | |
199 | ||
200 | int Database::changes() | |
201 | { | |
202 | StLock<Mutex> _(mMutex); | |
203 | ||
204 | return ::sqlite3_changes(mDb); | |
205 | } | |
206 | ||
207 | void Database::interrupt() | |
208 | { | |
209 | StLock<Mutex> _(mMutex); | |
210 | ||
211 | ::sqlite3_interrupt(mDb); | |
212 | } | |
213 | ||
214 | // | |
215 | // Transaction managers | |
216 | // | |
217 | Transaction::Transaction(Database &db, Type type, const char *name) | |
218 | : database(db), mName(name ? name : "") | |
219 | { | |
220 | switch (type) { | |
221 | case deferred: xactCommand("BEGIN DEFERRED"); break; | |
222 | case immediate: xactCommand("BEGIN IMMEDIATE"); break; | |
223 | case exclusive: xactCommand("BEGIN EXCLUSIVE"); break; | |
224 | } | |
225 | } | |
226 | ||
227 | Transaction::~Transaction() | |
228 | { | |
5c19dc3a A |
229 | if (database.inTransaction()) { |
230 | // request rollback but ignore any errors | |
231 | database.execute("ROLLBACK TRANSACTION", false); | |
232 | } | |
b1ab9ed8 A |
233 | } |
234 | ||
235 | void Transaction::commit() | |
236 | { | |
237 | xactCommand("COMMIT"); | |
238 | } | |
239 | ||
240 | void Transaction::abort() | |
241 | { | |
242 | xactCommand("ROLLBACK"); | |
243 | } | |
244 | ||
245 | void Transaction::xactCommand(const string &cmd) | |
246 | { | |
247 | database.execute(cmd + " TRANSACTION " + mName + ";"); | |
248 | } | |
249 | ||
250 | ||
251 | // | |
252 | // Statement objects | |
253 | // | |
254 | Statement::Statement(Database &db, const char *text) | |
255 | : StLock<Mutex>(db.mMutex), database(db), mStmt(NULL) | |
256 | { | |
257 | this->query(text); | |
258 | } | |
259 | ||
260 | Statement::Statement(Database &db) | |
261 | : StLock<Mutex>(db.mMutex), database(db), mStmt(NULL) | |
262 | { } | |
263 | ||
264 | void Statement::query(const char *text) | |
265 | { | |
266 | this->close(); | |
267 | const char *tail; | |
268 | check(::sqlite3_prepare_v2(database.sql(), text, -1, &mStmt, &tail)); | |
269 | if (*tail) | |
270 | throw std::logic_error("multiple statements"); | |
271 | } | |
272 | ||
273 | void Statement::close() | |
274 | { | |
275 | // Sqlite3_finalize will return an error if the Statement (executed and) failed. | |
276 | // So we eat any error code here, since we can't tell "genuine" errors apart from | |
277 | // errors inherited from the Statement execution. | |
278 | if (mStmt) | |
279 | ::sqlite3_finalize(mStmt); | |
280 | mStmt = NULL; | |
281 | } | |
282 | ||
283 | Statement::~Statement() | |
284 | { | |
285 | this->close(); | |
286 | } | |
287 | ||
288 | ||
289 | void Statement::unbind() | |
290 | { | |
291 | check(::sqlite3_clear_bindings(mStmt)); | |
292 | } | |
293 | ||
294 | void Statement::reset() | |
295 | { | |
296 | check(::sqlite3_reset(mStmt)); | |
297 | } | |
298 | ||
299 | ||
300 | int Statement::step() | |
301 | { | |
302 | return ::sqlite3_step(mStmt); | |
303 | } | |
304 | ||
305 | void Statement::execute() | |
306 | { | |
307 | switch (int rc = this->step()) { | |
308 | case SQLITE_DONE: | |
309 | case SQLITE_OK: | |
310 | break; | |
311 | default: | |
312 | check(rc); | |
313 | } | |
314 | } | |
315 | ||
316 | bool Statement::nextRow() | |
317 | { | |
318 | switch (int rc = this->step()) { | |
319 | case SQLITE_ROW: | |
320 | return true; | |
321 | case SQLITE_DONE: | |
322 | return false; | |
323 | default: | |
324 | check(rc); | |
325 | return false; | |
326 | } | |
327 | } | |
328 | ||
329 | ||
330 | // | |
331 | // Binding gluons. | |
332 | // | |
333 | Statement::Binding Statement::bind(const char *name) const | |
334 | { | |
335 | if (int ix = ::sqlite3_bind_parameter_index(mStmt, name)) | |
336 | return Binding(*this, ix); | |
337 | else | |
338 | throw std::logic_error("unknown parameter name"); | |
339 | } | |
340 | ||
341 | void Statement::Binding::null() | |
342 | { | |
343 | statement.check(::sqlite3_bind_null(statement.sql(), index)); | |
344 | } | |
345 | ||
346 | void Statement::Binding::operator = (const Value &value) | |
347 | { | |
348 | statement.check(::sqlite3_bind_value(statement.sql(), index, value.sql())); | |
349 | } | |
350 | ||
351 | void Statement::Binding::operator = (int value) | |
352 | { | |
353 | statement.check(::sqlite3_bind_int(statement.sql(), index, value)); | |
354 | } | |
355 | ||
356 | void Statement::Binding::operator = (sqlite3_int64 value) | |
357 | { | |
358 | statement.check(::sqlite3_bind_int64(statement.sql(), index, value)); | |
359 | } | |
360 | ||
361 | void Statement::Binding::integer(sqlite3_int64 value) | |
362 | { | |
363 | statement.check(::sqlite3_bind_int64(statement.sql(), index, value)); | |
364 | } | |
365 | ||
366 | void Statement::Binding::operator = (double value) | |
367 | { | |
368 | statement.check(::sqlite3_bind_double(statement.sql(), index, value)); | |
369 | } | |
370 | ||
371 | void Statement::Binding::operator = (const char *value) | |
372 | { | |
313fa17b A |
373 | if (value == NULL) |
374 | this->null(); | |
375 | else | |
376 | statement.check(::sqlite3_bind_text(statement.sql(), index, | |
377 | ::strdup(value), -1, ::free)); | |
b1ab9ed8 A |
378 | } |
379 | ||
380 | void Statement::Binding::operator = (const std::string &value) | |
381 | { | |
382 | statement.check(::sqlite3_bind_text(statement.sql(), index, | |
383 | ::strdup(value.c_str()), -1, ::free)); | |
384 | } | |
385 | ||
386 | void Statement::Binding::blob(const void *data, size_t length, bool shared /* = false */) | |
387 | { | |
388 | if (data == NULL) | |
389 | this->null(); | |
390 | else if (shared) { | |
427c49bc | 391 | statement.check(::sqlite3_bind_blob(statement.sql(), index, data, (int)length, NULL)); |
b1ab9ed8 A |
392 | } else if (void *copy = ::malloc(length)) { |
393 | ::memcpy(copy, data, length); | |
394 | statement.check(::sqlite3_bind_blob(statement.sql(), index, | |
427c49bc | 395 | copy, (int)length, ::free)); |
b1ab9ed8 A |
396 | } else |
397 | throw std::bad_alloc(); | |
398 | } | |
399 | ||
400 | void Statement::Binding::operator = (CFDataRef data) | |
401 | { | |
402 | if (data) | |
403 | this->blob(CFDataGetBytePtr(data), CFDataGetLength(data)); | |
404 | else | |
405 | this->null(); | |
406 | } | |
407 | ||
408 | void Statement::Binding::operator = (CFStringRef value) | |
409 | { | |
410 | if (value) | |
411 | *this = cfString(value).c_str(); | |
412 | else | |
413 | this->null(); | |
414 | } | |
415 | ||
416 | const char *Statement::Binding::name() const | |
417 | { | |
418 | return sqlite3_bind_parameter_name(statement.sql(), index); | |
419 | } | |
420 | ||
421 | ||
422 | // | |
423 | // Row/column results | |
424 | // | |
425 | const char *Statement::Result::name() const | |
426 | { | |
427 | return sqlite3_column_name(statement.sql(), index); | |
428 | } | |
429 | ||
430 | CFDataRef Statement::Result::data() const | |
431 | { | |
432 | switch (this->type()) { | |
433 | case SQLITE_NULL: | |
434 | return NULL; | |
435 | case SQLITE_BLOB: | |
436 | return makeCFData(this->blob(), this->length()); | |
437 | default: | |
438 | throw Error(SQLITE_MISMATCH, "Retrieving data() of non-Blob"); | |
439 | } | |
440 | } | |
441 | ||
442 | ||
443 | } // SQLite3 | |
444 | } // Security |