summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/sqlite')
-rw-r--r--ml/dlib/dlib/sqlite/sqlite.h625
-rw-r--r--ml/dlib/dlib/sqlite/sqlite_abstract.h506
-rw-r--r--ml/dlib/dlib/sqlite/sqlite_tools.h189
-rw-r--r--ml/dlib/dlib/sqlite/sqlite_tools_abstract.h164
4 files changed, 1484 insertions, 0 deletions
diff --git a/ml/dlib/dlib/sqlite/sqlite.h b/ml/dlib/dlib/sqlite/sqlite.h
new file mode 100644
index 000000000..7eefbb21a
--- /dev/null
+++ b/ml/dlib/dlib/sqlite/sqlite.h
@@ -0,0 +1,625 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_SQLiTE_H_
+#define DLIB_SQLiTE_H_
+
+#include "sqlite_abstract.h"
+
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include "../algs.h"
+#include <sqlite3.h>
+#include "../serialize.h"
+
+
+// --------------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+// --------------------------------------------------------------------------------------------
+
+ struct sqlite_error : public error
+ {
+ sqlite_error(const std::string& message): error(message) {}
+ };
+
+// --------------------------------------------------------------------------------------------
+
+ namespace impl
+ {
+ struct db_deleter
+ {
+ void operator()(
+ sqlite3* db
+ )const
+ {
+ sqlite3_close(db);
+ }
+ };
+ }
+
+// --------------------------------------------------------------------------------------------
+
+ class database : noncopyable
+ {
+ public:
+ database(
+ )
+ {
+ }
+
+ database (
+ const std::string& file
+ )
+ {
+ open(file);
+ }
+
+ bool is_open (
+ ) const
+ {
+ return db.get() != 0;
+ }
+
+ void open (
+ const std::string& file
+ )
+ {
+ filename = file;
+ sqlite3* ptr = 0;
+ int status = sqlite3_open(file.c_str(), &ptr);
+ db.reset(ptr, impl::db_deleter());
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ const std::string& get_database_filename (
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_open() == true,
+ "\t std::string database::get_database_filename()"
+ << "\n\t The database must be opened before calling this routine."
+ << "\n\t this: " << this
+ );
+
+ return filename;
+ }
+
+ inline void exec (
+ const std::string& sql_statement
+ );
+
+ int64 last_insert_rowid (
+ ) const
+ {
+ return sqlite3_last_insert_rowid(db.get());
+ }
+
+ private:
+
+ friend class statement;
+
+ std::string filename;
+ std::shared_ptr<sqlite3> db;
+ };
+
+// --------------------------------------------------------------------------------------------
+
+ class statement : noncopyable
+ {
+ public:
+ statement (
+ database& db_,
+ const std::string sql_statement
+ ) :
+ needs_reset(false),
+ step_status(SQLITE_DONE),
+ at_first_step(true),
+ db(db_.db),
+ stmt(0),
+ sql_string(sql_statement)
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(db_.is_open() == true,
+ "\t statement::statement()"
+ << "\n\t The database must be opened before calling this routine."
+ << "\n\t this: " << this
+ );
+
+ int status = sqlite3_prepare_v2(db.get(),
+ sql_string.c_str(),
+ sql_string.size()+1,
+ &stmt,
+ NULL);
+
+ if (status != SQLITE_OK)
+ {
+ sqlite3_finalize(stmt);
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ if (stmt == 0)
+ {
+ throw sqlite_error("Invalid SQL statement");
+ }
+ }
+
+ ~statement(
+ )
+ {
+ sqlite3_finalize(stmt);
+ }
+
+ void exec(
+ )
+ {
+ reset();
+
+ step_status = sqlite3_step(stmt);
+ needs_reset = true;
+ if (step_status != SQLITE_DONE && step_status != SQLITE_ROW)
+ {
+ if (step_status == SQLITE_ERROR)
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ else if (step_status == SQLITE_BUSY)
+ throw sqlite_error("statement::exec() failed. SQLITE_BUSY returned");
+ else
+ throw sqlite_error("statement::exec() failed.");
+ }
+ }
+
+ bool move_next (
+ )
+ {
+ if (step_status == SQLITE_ROW)
+ {
+ if (at_first_step)
+ {
+ at_first_step = false;
+ return true;
+ }
+ else
+ {
+ step_status = sqlite3_step(stmt);
+ if (step_status == SQLITE_DONE)
+ {
+ return false;
+ }
+ else if (step_status == SQLITE_ROW)
+ {
+ return true;
+ }
+ else
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ unsigned long get_num_columns(
+ ) const
+ {
+ if( (at_first_step==false) && (step_status==SQLITE_ROW))
+ {
+ return sqlite3_column_count(stmt);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ const std::string& get_sql_string (
+ ) const
+ {
+ return sql_string;
+ }
+
+ template <typename T>
+ typename enable_if_c<std::numeric_limits<T>::is_integer>::type get_column (
+ unsigned long idx,
+ T& item
+ ) const
+ {
+ // unsigned ints won't fit into int all the time so put those into 64bit ints.
+ if (sizeof(T) < sizeof(int) || (sizeof(T)==sizeof(int) && is_signed_type<T>::value))
+ item = get_column_as_int(idx);
+ else
+ item = get_column_as_int64(idx);
+ }
+
+ void get_column(unsigned long idx, std::string& item) const { item = get_column_as_text(idx); }
+ void get_column(unsigned long idx, float& item ) const { item = get_column_as_double(idx); }
+ void get_column(unsigned long idx, double& item ) const { item = get_column_as_double(idx); }
+ void get_column(unsigned long idx, long double& item) const { item = get_column_as_double(idx); }
+
+ template <typename T>
+ typename disable_if_c<std::numeric_limits<T>::is_integer>::type get_column (
+ unsigned long idx,
+ T& item
+ ) const
+ {
+ get_column_as_object(idx, item);
+ }
+
+ const std::vector<char> get_column_as_blob (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t std::vector<char> statement::get_column_as_blob()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ const char* data = static_cast<const char*>(sqlite3_column_blob(stmt, idx));
+ const int size = sqlite3_column_bytes(stmt, idx);
+
+ return std::vector<char>(data, data+size);
+ }
+
+ template <typename T>
+ void get_column_as_object (
+ unsigned long idx,
+ T& item
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t void statement::get_column_as_object()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ const char* data = static_cast<const char*>(sqlite3_column_blob(stmt, idx));
+ const int size = sqlite3_column_bytes(stmt, idx);
+ std::istringstream sin(std::string(data,size));
+ deserialize(item, sin);
+ }
+
+ const std::string get_column_as_text (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t std::string statement::get_column_as_text()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ const char* data = reinterpret_cast<const char*>(sqlite3_column_text(stmt, idx));
+ if (data != 0)
+ return std::string(data);
+ else
+ return std::string();
+ }
+
+ double get_column_as_double (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t double statement::get_column_as_double()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ return sqlite3_column_double(stmt, idx);
+ }
+
+ int get_column_as_int (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t int statement::get_column_as_int()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ return sqlite3_column_int(stmt, idx);
+ }
+
+ int64 get_column_as_int64 (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t int64 statement::get_column_as_int64()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ return sqlite3_column_int64(stmt, idx);
+ }
+
+ const std::string get_column_name (
+ unsigned long idx
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(idx < get_num_columns(),
+ "\t std::string statement::get_column_name()"
+ << "\n\t Invalid column index."
+ << "\n\t idx: " << idx
+ << "\n\t this: " << this
+ );
+
+ return std::string(sqlite3_column_name(stmt,idx));
+ }
+
+ unsigned long get_max_parameter_id (
+ ) const
+ {
+ return sqlite3_limit(db.get(), SQLITE_LIMIT_VARIABLE_NUMBER, -1);
+ }
+
+ unsigned long get_parameter_id (
+ const std::string& name
+ ) const
+ {
+ return sqlite3_bind_parameter_index(stmt, name.c_str());
+ }
+
+ template <typename T>
+ typename enable_if_c<std::numeric_limits<T>::is_integer>::type bind (
+ unsigned long idx,
+ const T& item
+ )
+ {
+ // unsigned ints won't fit into int all the time so put those into 64bit ints.
+ if (sizeof(T) < sizeof(int) || (sizeof(T)==sizeof(int) && is_signed_type<T>::value))
+ bind_int(idx, item);
+ else
+ bind_int64(idx, item);
+ }
+
+ void bind(unsigned long idx, const std::string& item) { bind_text(idx, item); }
+ void bind(unsigned long idx, const float& item ) { bind_double(idx, item); }
+ void bind(unsigned long idx, const double& item ) { bind_double(idx, item); }
+ void bind(unsigned long idx, const long double& item) { bind_double(idx, item); }
+
+ template <typename T>
+ typename disable_if_c<std::numeric_limits<T>::is_integer>::type bind (
+ unsigned long idx,
+ const T& item
+ )
+ {
+ bind_object(idx, item);
+ }
+
+ void bind_blob (
+ unsigned long parameter_id,
+ const std::vector<char>& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_blob()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_blob(stmt, parameter_id, &item[0], item.size(), SQLITE_TRANSIENT);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ template <typename T>
+ void bind_object (
+ unsigned long parameter_id,
+ const T& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_object()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ std::ostringstream sout;
+ serialize(item, sout);
+ const std::string& str = sout.str();
+ int status = sqlite3_bind_blob(stmt, parameter_id, str.data(), str.size(), SQLITE_TRANSIENT);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ void bind_double (
+ unsigned long parameter_id,
+ const double& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_double()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_double(stmt, parameter_id, item);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ void bind_int (
+ unsigned long parameter_id,
+ const int& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_int()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_int(stmt, parameter_id, item);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ void bind_int64 (
+ unsigned long parameter_id,
+ const int64& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_int64()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_int64(stmt, parameter_id, item);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ void bind_null (
+ unsigned long parameter_id
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_null()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_null(stmt, parameter_id);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ void bind_text (
+ unsigned long parameter_id,
+ const std::string& item
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(1 <= parameter_id && parameter_id <= get_max_parameter_id(),
+ "\t void statement::bind_text()"
+ << "\n\t Invalid parameter id."
+ << "\n\t parameter_id: " << parameter_id
+ << "\n\t get_max_parameter_id(): " << get_max_parameter_id()
+ << "\n\t this: " << this
+ );
+
+ reset();
+ int status = sqlite3_bind_text(stmt, parameter_id, item.c_str(), -1, SQLITE_TRANSIENT);
+
+ if (status != SQLITE_OK)
+ {
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ }
+
+ private:
+
+ void reset()
+ {
+ if (needs_reset)
+ {
+ if (sqlite3_reset(stmt) != SQLITE_OK)
+ {
+ step_status = SQLITE_DONE;
+ throw sqlite_error(sqlite3_errmsg(db.get()));
+ }
+ needs_reset = false;
+ step_status = SQLITE_DONE;
+ at_first_step = true;
+ }
+ }
+
+ bool needs_reset; // true if sqlite3_step() has been called more recently than sqlite3_reset()
+ int step_status;
+ bool at_first_step;
+
+ std::shared_ptr<sqlite3> db;
+ sqlite3_stmt* stmt;
+ std::string sql_string;
+ };
+
+// --------------------------------------------------------------------------------------------
+
+ void database::
+ exec (
+ const std::string& sql_statement
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_open() == true,
+ "\t void database::exec()"
+ << "\n\t The database must be opened before calling this routine."
+ << "\n\t this: " << this
+ );
+
+ statement(*this, sql_statement).exec();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SQLiTE_H_
+
diff --git a/ml/dlib/dlib/sqlite/sqlite_abstract.h b/ml/dlib/dlib/sqlite/sqlite_abstract.h
new file mode 100644
index 000000000..7372162d8
--- /dev/null
+++ b/ml/dlib/dlib/sqlite/sqlite_abstract.h
@@ -0,0 +1,506 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_SQLiTE_ABSTRACT_H_
+#ifdef DLIB_SQLiTE_ABSTRACT_H_
+
+
+#include <iostream>
+#include <vector>
+#include "../algs.h"
+#include <sqlite3.h>
+#include "../smart_pointers.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ struct sqlite_error : public error
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This is the exception object used by the SQLite tools to indicate
+ that an error has occurred. Any of the functions defined in this
+ file might throw this exception.
+ !*/
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class database : noncopyable
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is a C++ wrapper around a SQLite database connection
+ handle and therefore represents a SQLite database file.
+
+ Note that this wrapper is targeted at SQLite Version 3.
+
+ Note also that whenever SQLite indicates an error has occurred
+ this object will throw the sqlite_error exception.
+ !*/
+
+ public:
+ database(
+ );
+ /*!
+ ensures
+ - #is_open() == false
+ !*/
+
+ database (
+ const std::string& file
+ );
+ /*!
+ ensures
+ - opens the indicated database file or creates a new
+ database with the given name if one doesn't already exist.
+ - #get_database_filename() == file
+ - #is_open() == true
+ !*/
+
+ ~database (
+ );
+ /*!
+ ensures
+ - safely disposes of any SQLite database connection. If
+ any statement objects still exist which reference this database
+ then the SQLite database connection won't be fully closed
+ until those statement objects are also destroyed. This allows
+ for any destruction order between database and statement objects.
+ !*/
+
+ void open (
+ const std::string& file
+ );
+ /*!
+ ensures
+ - opens the indicated database file or creates a new
+ database with the given name if one doesn't already exist.
+ - #get_database_filename() == file
+ - #is_open() == true
+ - safely disposes of any previous SQLite database connection. If
+ any statement objects still exist which reference this database
+ then the SQLite database connection won't be fully closed
+ until those statement objects are also destroyed.
+ !*/
+
+ bool is_open (
+ ) const;
+ /*!
+ ensures
+ - if (this object has an open connection to a SQLite database) then
+ - returns true
+ - else
+ - returns false
+ !*/
+
+ const std::string& get_database_filename (
+ ) const;
+ /*!
+ requires
+ - is_open() == true
+ ensures
+ - returns the name of the SQLite database file this object
+ currently has open.
+ !*/
+
+ void exec (
+ const std::string& sql_statement
+ );
+ /*!
+ requires
+ - is_open() == true
+ ensures
+ - executes the supplied SQL statement against this database
+ !*/
+
+ int64 last_insert_rowid (
+ ) const;
+ /*!
+ requires
+ - is_open() == true
+ ensures
+ - Each element in a database table has a rowid which uniquely identifies
+ it. Therefore, this routine returns the rowid of the most recent
+ successful INSERT into the database via this database instance.
+ - If an INSERT has not been performed on the current database instance then
+ the return value is 0. This is true even if the database is not empty.
+ - See the sqlite documentation for the full details on how this function
+ behaves: http://www.sqlite.org/c3ref/last_insert_rowid.html
+ !*/
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class statement : noncopyable
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a SQL statement which can be executed
+ against a database object. In particular, this object is a
+ C++ wrapper around a SQLite prepared statement.
+
+
+ Note that whenever SQLite indicates an error has occurred this
+ object will throw the sqlite_error exception.
+
+ BINDABLE SQL PARAMETERS
+ Sometimes you want to execute a bunch of very similar SQL statements.
+ For example, you might need to execute many insert statements where each
+ statement changes only the value of a field. Since it is somewhat
+ costly to construct a statement object for each SQL operation, SQLite
+ supports defining bindable parameters for a statement object. This allows
+ you to reuse the same statement object.
+
+ Therefore, in SQL statements used with SQLite, wherever it is valid to
+ include a string literal, one can use a parameter in one of the following
+ forms:
+
+ ?
+ ?NNN
+ :AAA
+ $AAA
+ @AAA
+
+ In the examples above, NNN is an integer value and AAA is an identifier. A
+ parameter initially has a value of NULL. You can use the bind_*() routines
+ to attach values to the parameters. Each call to a bind_*() routine overrides
+ prior bindings on the same parameter.
+
+ Each SQL parameter has a numeric ID which is used to reference it when invoking
+ a bind_*() routine. The leftmost SQL parameter in a statement has an index of 1,
+ the next parameter has an index of 2, and so on, except when the following rules
+ apply. When the same named SQL parameter is used more than once, second and
+ subsequent occurrences have the same index as the first occurrence. The index
+ for named parameters can be looked up using the get_parameter_id() method if desired.
+ The index for "?NNN" parameters is the value of NNN. The NNN value must be between
+ 1 and get_max_parameter_id().
+ !*/
+
+ public:
+ statement (
+ database& db,
+ const std::string sql_statement
+ );
+ /*!
+ requires
+ - db.is_open() == true
+ ensures
+ - The given SQL statement can be executed against the given
+ database by calling exec().
+ - #get_sql_string() == sql_statement
+ !*/
+
+ ~statement(
+ );
+ /*!
+ ensures
+ - any resources associated with this object have been freed.
+ !*/
+
+ const std::string& get_sql_string (
+ ) const;
+ /*!
+ ensures
+ - returns a copy of the SQL statement used to create this statement object.
+ !*/
+
+ void exec(
+ );
+ /*!
+ ensures
+ - #get_num_columns() == 0
+ - executes the SQL statement get_sql_string() against the database
+ given to this object's constructor.
+ - If this was a select statement then you can obtain the resulting
+ rows by calling move_next() and using the get_column_as_*() member
+ functions.
+ !*/
+
+ // ----------------------------
+
+ bool move_next (
+ );
+ /*!
+ ensures
+ - if (there is a result row for this query) then
+ - #get_num_columns() == the number of columns in the result row.
+ - The get_column_as_*() routines can be used to access the elements
+ of the row data.
+ - returns true
+ - else
+ - returns false
+ - #get_num_columns() == 0
+ !*/
+
+ unsigned long get_num_columns(
+ ) const;
+ /*!
+ ensures
+ - returns the number of columns of data available via the get_column_as_*()
+ routines.
+ !*/
+
+ template <
+ typename T
+ >
+ void get_column (
+ unsigned long idx,
+ T& item
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - This function automatically selects how to extract the column data based
+ on the type of item given. In particular:
+ - if (T is a 32bit or smaller built in integer type) then
+ - #item == get_column_as_int(idx)
+ - else if (T is a 64bit built in integer type) then
+ - #item == get_column_as_int64(idx)
+ - else if (T is float, double, or long double) then
+ - #item == get_column_as_double(idx)
+ - else if (T is std::string) then
+ - #item == get_column_as_text(idx)
+ - else
+ - invokes: get_column_as_object(idx, item)
+ !*/
+
+ const std::vector<char> get_column_as_blob (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the contents of the idx-th column as a binary BLOB.
+ !*/
+
+ template <
+ typename T
+ >
+ void get_column_as_object (
+ unsigned long idx,
+ T& item
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ - item is deserializable
+ (i.e. Calling deserialize(item, some_input_stream) reads an item
+ of type T from the some_input_stream stream)
+ ensures
+ - gets the contents of the idx-th column as a binary BLOB and then
+ deserializes it into item.
+ !*/
+
+ const std::string get_column_as_text (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the contents of the idx-th column as a text string.
+ !*/
+
+ double get_column_as_double (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the contents of the idx-th column as a double.
+ !*/
+
+ int get_column_as_int (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the contents of the idx-th column as an int.
+ !*/
+
+ int64 get_column_as_int64 (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the contents of the idx-th column as a 64bit int.
+ !*/
+
+ const std::string get_column_name (
+ unsigned long idx
+ ) const;
+ /*!
+ requires
+ - idx < get_num_columns()
+ ensures
+ - returns the name of the idx-th column. In particular:
+ The name of a result column is the value of the "AS" clause for
+ that column, if there is an AS clause. If there is no AS clause
+ then the name of the column is unspecified and may change from
+ one release of SQLite to the next.
+ !*/
+
+ // ----------------------------
+
+ unsigned long get_max_parameter_id (
+ ) const;
+ /*!
+ ensures
+ - returns the max parameter ID value which can be used with the
+ bind_() member functions defined below.
+ - In SQLite, the default value of this limit is usually 999.
+ !*/
+
+ unsigned long get_parameter_id (
+ const std::string& name
+ ) const;
+ /*!
+ ensures
+ - if (This SQL statement contains a SQL parameter with the given name) then
+ - returns the parameter_id number which can be used in the bind_*()
+ member functions defined below.
+ - else
+ - returns 0
+ !*/
+
+ template <
+ typename T
+ >
+ void bind (
+ unsigned long parameter_id,
+ const T& item
+ ) const;
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - This function automatically selects how to bind item to a statement based
+ on the type of item given. In particular:
+ - if (T is a 32bit or smaller built in integer type) then
+ - invokes: bind_int(parameter_id, item)
+ - else if (T is a 64bit built in integer type) then
+ - invokes: bind_int64(parameter_id, item)
+ - else if (T is float, double, or long double) then
+ - invokes: bind_double(parameter_id, item)
+ - else if (T is std::string) then
+ - invokes: bind_text(parameter_id, item)
+ - else
+ - invokes: bind_object(parameter_id, item)
+ !*/
+
+ void bind_blob (
+ unsigned long parameter_id,
+ const std::vector<char>& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id.
+ !*/
+
+ template <
+ typename T
+ >
+ void bind_object (
+ unsigned long parameter_id,
+ const T& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ - item is serializable
+ (i.e. Calling serialize(item, some_output_stream) writes an item
+ of type T to the some_output_stream stream)
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id. This is performed by serializing item and then
+ binding it as a binary BLOB.
+ !*/
+
+ void bind_double (
+ unsigned long parameter_id,
+ const double& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id.
+ !*/
+
+ void bind_int (
+ unsigned long parameter_id,
+ const int& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id.
+ !*/
+
+ void bind_int64 (
+ unsigned long parameter_id,
+ const int64& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id.
+ !*/
+
+ void bind_null (
+ unsigned long parameter_id
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds a NULL to the SQL parameter indicated by parameter_id.
+ !*/
+
+ void bind_text (
+ unsigned long parameter_id,
+ const std::string& item
+ );
+ /*!
+ requires
+ - 1 <= parameter_id <= get_max_parameter_id()
+ ensures
+ - #get_num_columns() == 0
+ - binds the value of item into the SQL parameter indicated by
+ parameter_id.
+ !*/
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SQLiTE_ABSTRACT_H_
+
+
diff --git a/ml/dlib/dlib/sqlite/sqlite_tools.h b/ml/dlib/dlib/sqlite/sqlite_tools.h
new file mode 100644
index 000000000..062a6b2c8
--- /dev/null
+++ b/ml/dlib/dlib/sqlite/sqlite_tools.h
@@ -0,0 +1,189 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_SQLiTE_TOOLS_H_
+#define DLIB_SQLiTE_TOOLS_H_
+
+
+#include "sqlite_tools_abstract.h"
+#include "sqlite.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+ class transaction : noncopyable
+ {
+ public:
+ transaction (
+ database& db_
+ ) :
+ db(db_),
+ committed(false)
+ {
+ db.exec("begin transaction");
+ }
+
+ void commit ()
+ {
+ if (!committed)
+ {
+ committed = true;
+ db.exec("commit");
+ }
+ }
+
+ ~transaction() throw (std::exception)
+ {
+ if (!committed)
+ db.exec("rollback");
+ }
+
+ private:
+ database& db;
+ bool committed;
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+
+ template <
+ typename T
+ >
+ void query_object (
+ database& db,
+ const std::string& query,
+ T& item
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ st.get_column_as_object(0,item);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline std::string query_text (
+ database& db,
+ const std::string& query
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ const std::string& temp = st.get_column_as_text(0);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ return temp;
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline double query_double (
+ database& db,
+ const std::string& query
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ double temp = st.get_column_as_double(0);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ return temp;
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline int query_int (
+ database& db,
+ const std::string& query
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ int temp = st.get_column_as_int(0);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ return temp;
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline int64 query_int64 (
+ database& db,
+ const std::string& query
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ int64 temp = st.get_column_as_int64(0);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ return temp;
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const std::vector<char> query_blob (
+ database& db,
+ const std::string& query
+ )
+ {
+ statement st(db, query);
+ st.exec();
+ if (st.move_next() && st.get_num_columns() == 1)
+ {
+ const std::vector<char>& temp = st.get_column_as_blob(0);
+ if (st.move_next())
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ return temp;
+ }
+ else
+ {
+ throw sqlite_error("query doesn't result in exactly 1 element");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SQLiTE_TOOLS_H_
+
diff --git a/ml/dlib/dlib/sqlite/sqlite_tools_abstract.h b/ml/dlib/dlib/sqlite/sqlite_tools_abstract.h
new file mode 100644
index 000000000..c13a09265
--- /dev/null
+++ b/ml/dlib/dlib/sqlite/sqlite_tools_abstract.h
@@ -0,0 +1,164 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_SQLiTE_TOOLS_ABSTRACT_H_
+#ifdef DLIB_SQLiTE_TOOLS_ABSTRACT_H_
+
+
+#include "sqlite_abstract.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+ class transaction : noncopyable
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is a tool for creating exception safe
+ database transactions.
+ !*/
+
+ public:
+ transaction (
+ database& db
+ );
+ /*!
+ ensures
+ - Begins a database transaction which will be rolled back
+ if commit() isn't called eventually.
+ - In particular, performs: db.exec("begin transaction");
+ !*/
+
+ void commit (
+ );
+ /*!
+ ensures
+ - if (commit() hasn't already been called) then
+ - Commits all changes made during this database transaction.
+ - In particular, performs: db.exec("commit");
+ - else
+ - does nothing
+ !*/
+
+ ~transaction(
+ );
+ /*!
+ ensures
+ - if (commit() was never called) then
+ - rolls back any changes made to the database during this transaction.
+ - In particular, performs: db.exec("rollback");
+ - else
+ - does nothing
+ !*/
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ void query_object (
+ database& db,
+ const std::string& query,
+ T& item
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ interpreted as a binary BLOB and deserialized into item.
+ throws
+ - sqlite_error or serialization_error if an error occurs which prevents
+ this operation from succeeding.
+
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ std::string query_text (
+ database& db,
+ const std::string& query
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ converted to text and returned.
+ throws
+ - sqlite_error if an error occurs which prevents this operation from
+ succeeding.
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ double query_double (
+ database& db,
+ const std::string& query
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ converted to a double and returned.
+ throws
+ - sqlite_error if an error occurs which prevents this operation from
+ succeeding.
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ int query_int (
+ database& db,
+ const std::string& query
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ converted to an int and returned.
+ throws
+ - sqlite_error if an error occurs which prevents this operation from
+ succeeding.
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ int64 query_int64 (
+ database& db,
+ const std::string& query
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ converted to an int64 and returned.
+ throws
+ - sqlite_error if an error occurs which prevents this operation from
+ succeeding.
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ const std::vector<char> query_blob (
+ database& db,
+ const std::string& query
+ );
+ /*!
+ ensures
+ - executes the given SQL query against db. If the query results in a
+ single row and column being returned then the data in the column is
+ returned as a binary BLOB.
+ throws
+ - sqlite_error if an error occurs which prevents this operation from
+ succeeding.
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SQLiTE_TOOLS_H_
+
+