diff options
Diffstat (limited to 'ml/dlib/dlib/sqlite')
-rw-r--r-- | ml/dlib/dlib/sqlite/sqlite.h | 625 | ||||
-rw-r--r-- | ml/dlib/dlib/sqlite/sqlite_abstract.h | 506 | ||||
-rw-r--r-- | ml/dlib/dlib/sqlite/sqlite_tools.h | 189 | ||||
-rw-r--r-- | ml/dlib/dlib/sqlite/sqlite_tools_abstract.h | 164 |
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_ + + |