1/*
2 * Copyright (c) 2008 Apple Computer, Inc. All Rights Reserved.
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
35namespace Security {
36namespace SQLite3 {
37
38class Database;
39class Statement;
40
41typedef sqlite3_int64 int64;
42typedef sqlite3_uint64 uint64;
43
44
45//
46// An sqlite3 error
47//
48class Error : public CommonError {
49public:
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//
69class Database {
70	friend class Statement;
71public:
72	Database(const char *path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, bool lenient = false);
73	virtual ~Database();
74
75	bool isOpen() const { return mDb != NULL; }
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
110private:
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//
123class Value {
124public:
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
140private:
141	sqlite3_value *mValue;
142};
143
144
145//
146// A Transaction proxy.
147//
148class Transaction {
149public:
150	enum Type {
151		deferred,
152		immediate,
153		exclusive
154	};
155
156public:
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
166protected:
167	void xactCommand(const std::string &s);
168
169private:
170	std::string mName;
171};
172
173
174//
175// A (prepared) statement.
176//
177class Statement : private StLock<Mutex> {
178	class Binding;
179
180public:
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
213private:
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
241public:
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
264private:
265	sqlite3_stmt *mStmt;
266};
267
268
269template <class RType>
270RType 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
285