--- /dev/null
+/*
+ * Copyright (c) 2008 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+// sqlite++ - C++ interface to SQLite3
+//
+#ifndef _H_SQLITEPP
+#define _H_SQLITEPP
+
+#include <sqlite3.h>
+#include <security_utilities/errors.h>
+#include <security_utilities/threading.h>
+#include <CoreFoundation/CFData.h>
+
+
+namespace Security {
+namespace SQLite3 {
+
+class Database;
+class Statement;
+
+typedef sqlite3_int64 int64;
+typedef sqlite3_uint64 uint64;
+
+
+//
+// An sqlite3 error
+//
+class Error : public CommonError {
+public:
+ Error(Database &db);
+ Error(int err) : error(err) { }
+ Error(int err, const char *msg) : error(err), message(msg) { }
+ ~Error() throw () { }
+ const int error;
+ const std::string message;
+
+ const char *what() const throw () { return message.c_str(); }
+ OSStatus osStatus() const;
+ int unixError() const;
+
+ static void check(int err);
+ static void throwMe(int err) __attribute__((noreturn));
+};
+
+
+//
+// An sqlite3 database "connection"
+//
+class Database {
+ friend class Statement;
+public:
+ Database(const char *path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+ virtual ~Database();
+
+ void close();
+
+ // open flags
+ int openFlags() const { return mOpenFlags; }
+
+ // last error condition encountered
+ int errcode();
+ const char *errmsg();
+
+ bool inTransaction();
+ int64 lastInsert();
+ int changes();
+
+ void interrupt();
+
+ int execute(const char *text, bool strict = true);
+ int execute(const std::string &text, bool strict = true)
+ { return execute(text.c_str(), strict); }
+
+ bool empty();
+
+ template <class RType> RType value(const char *text, RType defaultResult = RType());
+ template <class RType> RType value(const std::string &text, RType defaultResult = RType())
+ { return value(text.c_str(), defaultResult); }
+
+ double julianNow()
+ { return this->value<double>("SELECT JULIANDAY('now');"); }
+
+ void busyDelay(int ms);
+
+ void check(int err);
+
+ sqlite3 *sql() const { return mDb; }
+
+private:
+ sqlite3 *mDb;
+ Mutex mMutex;
+ int mOpenFlags;
+};
+
+
+//
+// An sqlite column value.
+// These are definitely not first-class API objects; in particular,
+// there doesn't seem to be API to actually *make* one - you can only
+// get them out of sqlite.
+//
+class Value {
+public:
+ Value(sqlite3_value *v) : mValue(v) { }
+
+ operator int () const { return ::sqlite3_value_int(mValue); }
+ operator sqlite3_int64 () const { return ::sqlite3_value_int64(mValue); }
+ operator const char * () const { return (const char *)::sqlite3_value_text(mValue); }
+ operator double () const { return ::sqlite3_value_double(mValue); }
+
+ int type() const { return ::sqlite3_value_type(mValue); }
+ int numericType() const { return ::sqlite3_value_numeric_type(mValue); }
+
+ operator bool () const { return type() != SQLITE_NULL; }
+ bool operator ! () const { return type() == SQLITE_NULL; }
+
+ sqlite3_value *sql() const { return mValue; }
+
+private:
+ sqlite3_value *mValue;
+};
+
+
+//
+// A Transaction proxy.
+//
+class Transaction {
+public:
+ enum Type {
+ deferred,
+ immediate,
+ exclusive
+ };
+
+public:
+ Transaction(Database &db, Type type = deferred, const char *name = NULL);
+ virtual ~Transaction();
+
+ void commit();
+ void abort();
+ void rollback() { this->abort(); }
+
+ Database &database;
+
+protected:
+ void xactCommand(const std::string &s);
+
+private:
+ std::string mName;
+};
+
+
+//
+// A (prepared) statement.
+//
+class Statement : private StLock<Mutex> {
+ class Binding;
+
+public:
+ Statement(Database &db, const char *text); // ready to serve
+ Statement(Database &db); // quiescent; call query(text) to activate it
+ virtual ~Statement();
+
+ Database &database;
+
+ operator bool () const { return mStmt != NULL; } // active
+
+ void query(const char *text); // activate statement with query text
+ void query(const std::string &text)
+ { query(text.c_str()); }
+ void close(); // close up active statement
+
+ Binding bind(int ix) const { return Binding(*this, ix); }
+ Binding bind(const char *name) const;
+ unsigned int bindings() const { return ::sqlite3_bind_parameter_count(mStmt); }
+ void unbind();
+
+ int step();
+ void execute();
+ bool nextRow();
+ bool operator () () { return nextRow(); }
+
+ void reset();
+
+ class Result;
+ Result operator [] (int ix) { return Result(*this, ix); }
+ unsigned int count() const { return ::sqlite3_column_count(mStmt); }
+
+ void check(int err) const { database.check(err); }
+ sqlite3_stmt *sql() const { return mStmt; }
+
+private:
+ class Column {
+ public:
+ Column(const Statement &st, int ix) : statement(st), index(ix) { }
+
+ const Statement &statement;
+ const int index;
+ };
+
+ class Binding : public Column {
+ public:
+ Binding(const Statement &st, int ix) : Column(st, ix) { }
+
+ const char *name() const;
+
+ void null();
+ void operator = (int value);
+ void operator = (sqlite3_int64 value);
+ void operator = (double value);
+ void operator = (const char *value);
+ void operator = (const std::string &value);
+ void operator = (const Value &value);
+ void integer(sqlite3_int64 value);
+ void blob(const void *data, size_t length, bool shared = false);
+ void operator = (CFDataRef data);
+ void operator = (CFStringRef value);
+ };
+
+public:
+ class Result : public Column {
+ public:
+ Result(const Statement &st, int ix) : Column(st, ix) { }
+
+ const char *name() const;
+
+ operator int () const { return ::sqlite3_column_int(statement.sql(), index); }
+ operator sqlite3_int64 () const { return ::sqlite3_column_int64(statement.sql(), index); }
+ operator double () const { return ::sqlite3_column_double(statement.sql(), index); }
+ const char *string() const { return (const char *)::sqlite3_column_text(statement.sql(), index); }
+ operator const char *() const { return this->string(); }
+ const void *blob() const { return ::sqlite3_column_blob(statement.sql(), index); }
+ int length() const { return ::sqlite3_column_bytes(statement.sql(), index); }
+ CFDataRef data() const;
+
+ int type() const { return ::sqlite3_column_type(statement.sql(), index); }
+ const char *declType() const { return ::sqlite3_column_decltype(statement.sql(), index); }
+
+ operator bool () const { return type() != SQLITE_NULL; }
+ bool operator ! () const { return type() == SQLITE_NULL; }
+ };
+
+private:
+ sqlite3_stmt *mStmt;
+};
+
+
+template <class RType>
+RType Database::value(const char *text, RType defaultResult)
+{
+ Statement stmt(*this, text);
+ if (stmt())
+ return RType(stmt[0]);
+ else
+ return defaultResult;
+}
+
+
+
+} // SQLite3
+} // Security
+
+#endif //_H_SQLITEPP