]>
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 | #ifndef _H_SQLITEPP | |
27 | #define _H_SQLITEPP | |
28 | ||
29 | #include <sqlite3.h> | |
30 | #include <security_utilities/errors.h> | |
31 | #include <security_utilities/threading.h> | |
32 | #include <CoreFoundation/CFData.h> | |
33 | ||
34 | ||
35 | namespace Security { | |
36 | namespace SQLite3 { | |
37 | ||
38 | class Database; | |
39 | class Statement; | |
40 | ||
41 | typedef sqlite3_int64 int64; | |
42 | typedef sqlite3_uint64 uint64; | |
43 | ||
44 | ||
45 | // | |
46 | // An sqlite3 error | |
47 | // | |
48 | class Error : public CommonError { | |
49 | public: | |
50 | Error(Database &db); | |
51 | Error(int err) : error(err) { } | |
52 | Error(int err, const char *msg) : error(err), message(msg) { } | |
53 | ~Error() throw () { } | |
54 | const int error; | |
55 | const std::string message; | |
56 | ||
57 | const char *what() const throw () { return message.c_str(); } | |
58 | OSStatus osStatus() const; | |
59 | int unixError() const; | |
60 | ||
61 | static void check(int err); | |
62 | static void throwMe(int err) __attribute__((noreturn)); | |
63 | }; | |
64 | ||
65 | ||
66 | // | |
67 | // An sqlite3 database "connection" | |
68 | // | |
69 | class Database { | |
70 | friend class Statement; | |
71 | public: | |
427c49bc | 72 | Database(const char *path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, bool lenient = false); |
b1ab9ed8 A |
73 | virtual ~Database(); |
74 | ||
427c49bc | 75 | bool isOpen() const { return mDb != NULL; } |
b1ab9ed8 A |
76 | void close(); |
77 | ||
78 | // open flags | |
79 | int openFlags() const { return mOpenFlags; } | |
80 | ||
81 | // last error condition encountered | |
82 | int errcode(); | |
83 | const char *errmsg(); | |
84 | ||
85 | bool inTransaction(); | |
86 | int64 lastInsert(); | |
87 | int changes(); | |
88 | ||
89 | void interrupt(); | |
90 | ||
91 | int execute(const char *text, bool strict = true); | |
92 | int execute(const std::string &text, bool strict = true) | |
93 | { return execute(text.c_str(), strict); } | |
94 | ||
95 | bool empty(); | |
96 | ||
97 | template <class RType> RType value(const char *text, RType defaultResult = RType()); | |
98 | template <class RType> RType value(const std::string &text, RType defaultResult = RType()) | |
99 | { return value(text.c_str(), defaultResult); } | |
100 | ||
101 | double julianNow() | |
102 | { return this->value<double>("SELECT JULIANDAY('now');"); } | |
103 | ||
104 | void busyDelay(int ms); | |
105 | ||
106 | void check(int err); | |
107 | ||
108 | sqlite3 *sql() const { return mDb; } | |
109 | ||
110 | private: | |
111 | sqlite3 *mDb; | |
112 | Mutex mMutex; | |
113 | int mOpenFlags; | |
114 | }; | |
115 | ||
116 | ||
117 | // | |
118 | // An sqlite column value. | |
119 | // These are definitely not first-class API objects; in particular, | |
120 | // there doesn't seem to be API to actually *make* one - you can only | |
121 | // get them out of sqlite. | |
122 | // | |
123 | class Value { | |
124 | public: | |
125 | Value(sqlite3_value *v) : mValue(v) { } | |
126 | ||
127 | operator int () const { return ::sqlite3_value_int(mValue); } | |
128 | operator sqlite3_int64 () const { return ::sqlite3_value_int64(mValue); } | |
129 | operator const char * () const { return (const char *)::sqlite3_value_text(mValue); } | |
130 | operator double () const { return ::sqlite3_value_double(mValue); } | |
131 | ||
132 | int type() const { return ::sqlite3_value_type(mValue); } | |
133 | int numericType() const { return ::sqlite3_value_numeric_type(mValue); } | |
134 | ||
135 | operator bool () const { return type() != SQLITE_NULL; } | |
136 | bool operator ! () const { return type() == SQLITE_NULL; } | |
137 | ||
138 | sqlite3_value *sql() const { return mValue; } | |
139 | ||
140 | private: | |
141 | sqlite3_value *mValue; | |
142 | }; | |
143 | ||
144 | ||
145 | // | |
146 | // A Transaction proxy. | |
147 | // | |
148 | class Transaction { | |
149 | public: | |
150 | enum Type { | |
151 | deferred, | |
152 | immediate, | |
153 | exclusive | |
154 | }; | |
155 | ||
156 | public: | |
157 | Transaction(Database &db, Type type = deferred, const char *name = NULL); | |
158 | virtual ~Transaction(); | |
159 | ||
160 | void commit(); | |
161 | void abort(); | |
162 | void rollback() { this->abort(); } | |
163 | ||
164 | Database &database; | |
165 | ||
166 | protected: | |
167 | void xactCommand(const std::string &s); | |
168 | ||
169 | private: | |
170 | std::string mName; | |
171 | }; | |
172 | ||
173 | ||
174 | // | |
175 | // A (prepared) statement. | |
176 | // | |
177 | class Statement : private StLock<Mutex> { | |
178 | class Binding; | |
179 | ||
180 | public: | |
181 | Statement(Database &db, const char *text); // ready to serve | |
182 | Statement(Database &db); // quiescent; call query(text) to activate it | |
183 | virtual ~Statement(); | |
184 | ||
185 | Database &database; | |
186 | ||
187 | operator bool () const { return mStmt != NULL; } // active | |
188 | ||
189 | void query(const char *text); // activate statement with query text | |
190 | void query(const std::string &text) | |
191 | { query(text.c_str()); } | |
192 | void close(); // close up active statement | |
193 | ||
194 | Binding bind(int ix) const { return Binding(*this, ix); } | |
195 | Binding bind(const char *name) const; | |
196 | unsigned int bindings() const { return ::sqlite3_bind_parameter_count(mStmt); } | |
197 | void unbind(); | |
198 | ||
199 | int step(); | |
200 | void execute(); | |
201 | bool nextRow(); | |
202 | bool operator () () { return nextRow(); } | |
203 | ||
204 | void reset(); | |
205 | ||
206 | class Result; | |
207 | Result operator [] (int ix) { return Result(*this, ix); } | |
208 | unsigned int count() const { return ::sqlite3_column_count(mStmt); } | |
209 | ||
210 | void check(int err) const { database.check(err); } | |
211 | sqlite3_stmt *sql() const { return mStmt; } | |
212 | ||
213 | private: | |
214 | class Column { | |
215 | public: | |
216 | Column(const Statement &st, int ix) : statement(st), index(ix) { } | |
217 | ||
218 | const Statement &statement; | |
219 | const int index; | |
220 | }; | |
221 | ||
222 | class Binding : public Column { | |
223 | public: | |
224 | Binding(const Statement &st, int ix) : Column(st, ix) { } | |
225 | ||
226 | const char *name() const; | |
227 | ||
228 | void null(); | |
229 | void operator = (int value); | |
230 | void operator = (sqlite3_int64 value); | |
231 | void operator = (double value); | |
232 | void operator = (const char *value); | |
233 | void operator = (const std::string &value); | |
234 | void operator = (const Value &value); | |
235 | void integer(sqlite3_int64 value); | |
236 | void blob(const void *data, size_t length, bool shared = false); | |
237 | void operator = (CFDataRef data); | |
238 | void operator = (CFStringRef value); | |
239 | }; | |
240 | ||
241 | public: | |
242 | class Result : public Column { | |
243 | public: | |
244 | Result(const Statement &st, int ix) : Column(st, ix) { } | |
245 | ||
246 | const char *name() const; | |
247 | ||
248 | operator int () const { return ::sqlite3_column_int(statement.sql(), index); } | |
249 | operator sqlite3_int64 () const { return ::sqlite3_column_int64(statement.sql(), index); } | |
250 | operator double () const { return ::sqlite3_column_double(statement.sql(), index); } | |
251 | const char *string() const { return (const char *)::sqlite3_column_text(statement.sql(), index); } | |
252 | operator const char *() const { return this->string(); } | |
253 | const void *blob() const { return ::sqlite3_column_blob(statement.sql(), index); } | |
254 | int length() const { return ::sqlite3_column_bytes(statement.sql(), index); } | |
255 | CFDataRef data() const; | |
256 | ||
257 | int type() const { return ::sqlite3_column_type(statement.sql(), index); } | |
258 | const char *declType() const { return ::sqlite3_column_decltype(statement.sql(), index); } | |
259 | ||
260 | operator bool () const { return type() != SQLITE_NULL; } | |
261 | bool operator ! () const { return type() == SQLITE_NULL; } | |
262 | }; | |
263 | ||
264 | private: | |
265 | sqlite3_stmt *mStmt; | |
266 | }; | |
267 | ||
268 | ||
269 | template <class RType> | |
270 | RType Database::value(const char *text, RType defaultResult) | |
271 | { | |
272 | Statement stmt(*this, text); | |
273 | if (stmt()) | |
274 | return RType(stmt[0]); | |
275 | else | |
276 | return defaultResult; | |
277 | } | |
278 | ||
279 | ||
280 | ||
281 | } // SQLite3 | |
282 | } // Security | |
283 | ||
284 | #endif //_H_SQLITEPP |