diff --git a/Patches/CppDB/Patch.cmake b/Patches/CppDB/Patch.cmake index 9217569c..34fe1ad2 100644 --- a/Patches/CppDB/Patch.cmake +++ b/Patches/CppDB/Patch.cmake @@ -5,3 +5,7 @@ file(COPY ${CppDB_patch}/CMakeLists.txt ${CppDB_patch}/FindSQLite.cmake DESTINATION ${CppDB_source} ) + +file(COPY ${CppDB_patch}/cppdb/frontend.h + DESTINATION ${CppDB_source}/cppdb +) diff --git a/Patches/CppDB/cppdb/frontend.h b/Patches/CppDB/cppdb/frontend.h new file mode 100644 index 00000000..1481209b --- /dev/null +++ b/Patches/CppDB/cppdb/frontend.h @@ -0,0 +1,1281 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) +// +// Distributed under: +// +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// or (at your opinion) under: +// +// The MIT License +// (See accompanying file MIT.txt or a copy at +// http://www.opensource.org/licenses/mit-license.php) +// +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPDB_FRONTEND_H +#define CPPDB_FRONTEND_H +#include +#include +#include + +#include +#include +#include +#include +#include + +/// +/// The namespace of all data related to the cppdb api +/// + +namespace cppdb { + + class result; + class statement; + class session; + class connection_info; + class connection_specific_data; + + /// + /// Get CppDB Version String. It consists of "A.B.C", where A + /// is a major version number, B is a minor version number and + /// C is patch version + /// + CPPDB_API char const *version_string(); + /// + /// Return CppDB version as a number as a sum A * 10000 + B * 100 + C + /// where A is a major version number, B is a minor version number and + /// C is patch version + /// + CPPDB_API int version_number(); + + namespace backend { + class result; + class statement; + class connection; + } + + /// + /// Null value marker + /// + typedef enum { + null_value, ///< The value is null value + not_null_value ///< The valus is not a null value + } null_tag_type; + + /// \cond INTERNAL + namespace tags { + template + struct into_tag { + T &value; + null_tag_type &tag; + into_tag(T &v, null_tag_type &t) : value(v),tag(t) {} + }; + + template + struct use_tag { + T value; + null_tag_type tag; + use_tag(T v,null_tag_type t) : value(v),tag(t) {} + }; + + } // tags + /// \endcond + + /// + /// \brief Create a pair of value and tag for fetching a value from row. + /// + /// The fetched + /// value will be stored in \a value if the column is not null and the flag + /// if the value is null or not saved in \a tag + /// + template + tags::into_tag into(T &value,null_tag_type &tag) + { + return tags::into_tag(value,tag); + } + + /// + /// \brief Create a pair of a string value and tag for storing it to DB + /// + + inline tags::use_tag use(std::string const &v,null_tag_type tag) + { + return tags::use_tag(v,tag); + } + + /// + /// \brief Create a pair of a string value and tag for storing it to DB + /// + + inline tags::use_tag use(char const *v,null_tag_type tag) + { + return tags::use_tag(v,tag); + } + + /// + /// \brief Create a pair of value and tag for storing it to DB + /// + template + tags::use_tag use(T value,null_tag_type tag) + { + return tags::use_tag(value,tag); + } + + /// \cond INTERNAL + namespace details { + template + class functor { + public: + functor(functor const &other) : + functor_(other.functor_), + wrapper_(other.wrapper_) + { + } + functor const &operator=(functor const &other) + { + functor_ = other.functor_; + wrapper_ = other.wrapper_; + return *this; + } + functor(void (*func)(Object &)) + { + functor_ = reinterpret_cast(reinterpret_cast(func)); + wrapper_ = &functor::call_func; + + } + template + functor(RealFunctor const &f) + { + // The usual casts are not enough for all compilers + functor_ = reinterpret_cast(&f); + wrapper_ = &functor::template call_it; + } + void operator()(Object &p) const + { + wrapper_(functor_,p); + } + private: + static void call_func(void const *pointer,Object ¶meter) + { + typedef void function_type(Object &); + function_type *f = reinterpret_cast(reinterpret_cast((pointer))); + f(parameter); + } + template + static void call_it(void const *pointer,Object ¶meter) + { + Functor const *f_ptr = reinterpret_cast(pointer); + Functor const &f=*f_ptr; + f(parameter); + } + void const *functor_; + void (*wrapper_)(void const *,Object &); + }; + } // details + /// \endcond + + #ifdef CPPDB_DOXYGEN + /// + /// Special object that can be constructed from generic function like object \a f. + /// + /// So once_functor(f) can be created if f can be used like f(s) where s is \ref cppdb::session + /// + typedef unspecified_class_type once_functor; + #else + typedef details::functor once_functor; + #endif + + /// + /// \brief This object represents query result. + /// + /// This object and it is generally created by statement::query() call, default constructor + /// is provided for consistency, but access to any member function with exception of empty() would + /// throw an exception. + /// + class CPPDB_API result { + public: + /// + /// Create an empty result, it is not useful except for having default constructor + /// + result(); + /// + /// Destroys the result, note, if the result of statement is not destroyed, it would + /// not be returned to statements cache. + /// + ~result(); + /// + /// Copy result, note it only keeps the reference to actual object so copy is just + /// copy of the reference + /// + result(result const &); + /// + /// Assign result, note it only keeps the reference to actual object so assignment is just + /// copy of the reference + /// + result const &operator=(result const &); + + /// + /// Return the number of columns in the result + /// + int cols(); + /// + /// Move forward to next row, returns false if no more rows available. + /// + /// Notes: + /// + /// - You should call next() at least once before you use fetch() functions + /// - You must not call fetch() functions if next() returned false, it would cause empty_row_access exception. + /// + bool next(); + + /// + /// Convert column name \a n to its index, throws invalid_column if the name is not valid. + /// + int index(std::string const &n); + /// + /// Convert column name \a n to its index, returns -1 if the name is not valid. + /// + int find_column(std::string const &name); + + /// + /// Convert column index to column name, throws invalid_column if col is not in range 0<= col < cols() + /// + std::string name(int col); + + /// + /// Return true if the column number \a col (starting from 0) has NULL value + /// + bool is_null(int col); + /// + /// Return true if the column named \a n has NULL value + /// + bool is_null(std::string const &n); + + /// + /// Clears the result, no further use of the result should be done until it is assigned again with a new statement result. + /// + /// It is useful when you want to release all data and return the statement to cache + /// + void clear(); + /// + /// Reset current column index, so fetch without column index can be used once again + /// + void rewind_column(); + /// + /// Check if the current row is empty, it is in 3 cases: + /// + /// -# Empty result + /// -# next() wasn't called first time + /// -# next() returned false; + /// + bool empty(); + + + /// + /// Fetch a value from column \a col (starting from 0) into \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same it tries to cast the data, if casting fails or the + /// data is out of the type range, throws bad_value_cast(). + /// + bool fetch(int col,short &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,unsigned short &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,int &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,unsigned &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,long &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,unsigned long &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,long long &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,unsigned long long &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,float &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,double &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,long double &v); + /// + /// Fetch a textual value from column \a col (starting from 0) into \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same, if possible it converts it into textual representation. + /// + bool fetch(int col,std::string &v); + /// + /// \copydoc fetch(int,short&) + /// + bool fetch(int col,std::tm &v); + /// + /// Fetch a binary large object value from column \a col (starting from 0) into a stream \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not blob, it may throw bad_value_cast() + /// + bool fetch(int col,std::ostream &v); + + /// + /// Fetch a value from column named \a n into \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same it tries to cast the data, if casting fails or the + /// data is out of the type range, throws bad_value_cast(). + /// + /// If the \a n value is invalid throws invalid_column exception + /// + bool fetch(std::string const &n,short &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,unsigned short &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,int &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,unsigned &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,long &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,unsigned long &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,long long &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,unsigned long long &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,float &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,double &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,long double &v); + /// + /// Fetch a textual value from column named \a n into \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same, if possible it converts it into textual representation. If + /// the \a n value is invalid throws invalid_column exception + /// + bool fetch(std::string const &n,std::string &v); + /// + /// \copydoc fetch(std::string const &,short&) + /// + bool fetch(std::string const &n,std::tm &v); + /// + /// Fetch a binary large object value from column named \a name into a stream \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not blob, it may throw bad_value_cast(). If + /// the \a n value is invalid throws invalid_column exception + /// + bool fetch(std::string const &n,std::ostream &v); + + + /// + /// Fetch a value from the next column in the row starting from the first one. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same it tries to cast the data, if casting fails or the + /// data is out of the type range, throws bad_value_cast(). + /// + /// If fetch was called more times then cols() it throws invalid_column exception, to use + /// it once again from the beginning on the same row call rewind_column() member function. + /// It is not required to call rewind_column() after calling next() as column index is reset + /// automatically. + /// + bool fetch(short &v); + /// \copydoc fetch(short&) + bool fetch(unsigned short &v); + /// \copydoc fetch(short&) + bool fetch(int &v); + /// \copydoc fetch(short&) + bool fetch(unsigned &v); + /// \copydoc fetch(short&) + bool fetch(long &v); + /// \copydoc fetch(short&) + bool fetch(unsigned long &v); + /// \copydoc fetch(short&) + bool fetch(long long &v); + /// \copydoc fetch(short&) + bool fetch(unsigned long long &v); + /// \copydoc fetch(short&) + bool fetch(float &v); + /// \copydoc fetch(short&) + bool fetch(double &v); + /// \copydoc fetch(short&) + bool fetch(long double &v); + /// + /// Fetch a textual value from the next column in the row starting from the first one. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not same, if possible it converts it into textual representation. + /// + /// If fetch was called more times then cols() it throws invalid_column exception, to use + /// it once again from the beginning on the same row call rewind_column() member function. + /// It is not required to call rewind_column() after calling next() as column index is reset + /// automatically. + /// + bool fetch(std::string &v); + /// \copydoc fetch(short&) + bool fetch(std::tm &v); + /// + /// Fetch a blob value from the next column in the row starting from the first one into stream \a v. Returns false + /// if the value in NULL and \a v is not updated, otherwise returns true. + /// + /// If the data type is not blob, it may throw bad_value_cast(). + /// + /// If fetch was called more times then cols() it throws invalid_column exception, to use + /// it once again from the beginning on the same row call rewind_column() member function. + /// It is not required to call rewind_column() after calling next() as column index is reset + /// automatically. + /// + bool fetch(std::ostream &v); + + /// + /// Get a value of type \a T from column named \a name. If the column + /// is null throws null_value_fetch(), if the column \a name is invalid throws invalid_column, + /// if the column value cannot be converted to type T (see fetch functions) it throws bad_value_cast. + /// + + template + T get(std::string const &name) + { + T v=T(); + if(!fetch(name,v)) + throw null_value_fetch(); + return v; + } + + /// + /// Get a value of type \a T from column named \a name. If the column + /// is null returns \a def, if the column \a name is invalid throws invalid_column, + /// if the column value cannot be converted to type T (see fetch functions) it throws bad_value_cast. + /// + template + T get(std::string const &name, T const &def) + { + T v=T(); + if(!fetch(name,v)) + return def; + return v; + } + + /// + /// Get a value of type \a T from column \a col (starting from 0). If the column + /// is null throws null_value_fetch(), if the column index is invalid throws invalid_column, + /// if the column value cannot be converted to type T (see fetch functions) it throws bad_value_cast. + /// + template + T get(int col) + { + T v=T(); + if(!fetch(col,v)) + throw null_value_fetch(); + return v; + } + + /// + /// Get a value of type \a T from column \a col (starting from 0). If the column + /// is null returns \a def, if the column index is invalid throws invalid_column, + /// if the column value cannot be converted to type T (see fetch functions) it throws bad_value_cast. + /// + template + T get(int col, T const &def) + { + T v=T(); + if(!fetch(col,v)) + return def; + return v; + } + + /// + /// Syntactic sugar, used together with into() function. + /// + /// res << into(x,y) is same as + /// + /// \code + /// y = res.fetch(x) ? not_null_value : null_value + /// \endcode + /// + template + result &operator>>(tags::into_tag ref) + { + if(fetch(ref.value)) + ref.tag = not_null_value; + else + ref.tag = null_value; + return *this; + } + + /// + /// Syntactic sugar, same as fetch(\a value) + /// + template + result &operator>>(T &value) + { + fetch(value); + return *this; + } + + + private: + result( ref_ptr res, + ref_ptr stat, + ref_ptr conn); + + void check(); + + friend class statement; + + struct data; + + std::unique_ptr d; + + bool eof_; + bool fetched_; + int current_col_; + ref_ptr res_; + ref_ptr stat_; + ref_ptr conn_; + }; + + /// + /// \brief This class represents a prepared (or ordinary) statement that can be executed. + /// + /// This object is usually created via session::prepare() function. + /// + class CPPDB_API statement { + public: + /// + /// Default constructor, provided for convenience, access to any member function + /// of empty statement will cause an exception being thrown. + /// + statement(); + /// + /// Destructor, it releases prepared statement and if the statements cache is enabled + /// it returns it into the cache. + /// + /// Note: if result object created by this statement is alive, the underlying backned::statement would + /// be on hold until result object is destroyed and only then the statement would be put back + /// into cache. + /// + ~statement(); + /// + /// Copy statement. + /// + /// Please note it copies only the reference to underlying statement object, so copies + /// of same statement represent same object and it is strongly not recommended to access the underlying + /// backend::statement by two different statement objects. + /// + statement(statement const &); + /// + /// Assign a statement. + /// + /// Please note it copies only the reference to underlying statement object, so copies + /// of same statement represent same object and it is strongly not recommended to access the underlying + /// backend::statement by two different statement objects. + /// + statement const &operator=(statement const &); + + /// + /// Reset the statement - remove all bindings and return it into initial state so query() or exec() + /// functions can be called once again. + /// + /// You must use it if you use the same statement multiple times. + /// + /// Note, it is different from clear() where the statement is fully released and access to + /// it would throw an exception + /// + void reset(); + + /// + /// Clear the statement, removes it, any access to statement object would throw an exception till it would + /// be assigned once again + /// + + void clear(); + + /// + /// Check if the statement is empty, it is empty when created with default constructor or when cleared + /// with clear() member function. + /// + bool empty() const; + + /// + /// Bind a value \a v to the next placeholder (starting from the first) marked with '?' marker in the query. + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind(int v); + /// \copydoc bind(int) + statement &bind(unsigned v); + /// \copydoc bind(int) + statement &bind(long v); + /// \copydoc bind(int) + statement &bind(unsigned long v); + /// \copydoc bind(int) + statement &bind(long long v); + /// \copydoc bind(int) + statement &bind(unsigned long long v); + /// \copydoc bind(int) + statement &bind(double v); + /// \copydoc bind(int) + statement &bind(long double v); + /// + /// Bind a string value \a v to the next placeholder marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind(std::string const &v); + /// + /// Bind a null terminated string value \a s to the next placeholder marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind(char const *s); + /// + /// Bind a string value in range [\a b, \a e ) to the next placeholder marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind(char const *b,char const *e); + /// \copydoc bind(int) + statement &bind(std::tm const &v); + /// + /// Bind a BLOB value \a v to the next placeholder marked with '?' marker in the query. + /// + /// Note: the reference to the stream MUST remain valid until the statement is queried or executed! + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind(std::istream &v); + /// + /// Bind a NULL value to the next placeholder marked with '?' marker in the query. + /// + /// If number of calls is higher then the number placeholders is the statement it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + statement &bind_null(); + + + /// + /// Bind a value \a v to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind(int col,int v); + /// \copydoc bind(int,int) + void bind(int col,unsigned v); + /// \copydoc bind(int,int) + void bind(int col,long v); + /// \copydoc bind(int,int) + void bind(int col,unsigned long v); + /// \copydoc bind(int,int) + void bind(int col,long long v); + /// \copydoc bind(int,int) + void bind(int col,unsigned long long v); + /// \copydoc bind(int,int) + void bind(int col,double v); + /// \copydoc bind(int,int) + void bind(int col,long double v); + /// + /// Bind a string value \a v to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind(int col,std::string const &v); + /// + /// Bind a null terminated string value \a s to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind(int col,char const *s); + /// + /// Bind a string value in range [\a b, \a e ) to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// Note: the reference to the string MUST remain valid until the statement is queried or executed! + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind(int col,char const *b,char const *e); + /// \copydoc bind(int,int) + void bind(int col,std::tm const &v); + /// + /// Bind a BLOB value \a v to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// Note: the reference to the stream MUST remain valid until the statement is queried or executed! + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind(int col,std::istream &v); + /// + /// Bind a NULL value to the placeholder number \a col (starting from 1) marked with '?' marker in the query. + /// + /// If \a cols is invalid (less then 1 or higher then the number of the placeholders is the statement) it + /// may throw invalid_placeholder exception. + /// + /// If placeholder was not binded the behavior is undefined and may vary between different backends. + /// + void bind_null(int col); + + /// + /// Get last insert id from the last executed statement, note, it is the same as sequence_last(""). + /// + /// Some backends requires explicit sequence name so you should use sequence_last("sequence_name") in such + /// case. + /// + /// If the statement is actually query, the behavior is undefined and may vary between backends. + /// + long long last_insert_id(); + /// + /// Get last created sequence value from the last executed statement. + /// + /// If the backend does not support named sequences but rather supports "auto increment" columns (like MySQL, Sqlite3), + /// the \a seq parameter is ignored. + /// + /// + /// If the statement is actually query, the behavior is undefined and may vary between backends. + /// + long long sequence_last(std::string const &seq); + /// + /// Get the number of affected rows by the last statement, + /// + /// + /// If the statement is actually query, the behavior is undefined and may vary between backends. + /// + unsigned long long affected(); + + /// + /// Fetch a single row from the query. Unlike query(), you should not call result::next() + /// function as it is already called. You may check if the data was fetched using result::empty() + /// function. + /// + /// If the result set consists of more then one row it throws multiple_rows_query exception, however some backends + /// may ignore this. + /// + /// If the statement is not query statement (like SELECT) it would likely + /// throw an exception, however the behavior may vary between backends that may ignore this error. + /// + result row(); + /// + /// Fetch a result of the query, if the statement is not query statement (like SELECT) it would likely + /// throw an exception, however the behavior may vary between backends that may ignore this error. + /// + result query(); + /// + /// Same as query() - syntactic sugar + /// + operator result(); + + /// + /// Execute a statement, of the statement is actually SELECT like operator, it throws cppdb_error exception, + /// however the behavior may vary between backends that may ignore this error. + /// + void exec(); + + /// + /// Same as bind(v); + /// + statement &operator<<(std::string const &v); + /// + /// Same as bind(s); + /// + statement &operator<<(char const *s); + /// + /// Same as bind(v); + /// + statement &operator<<(std::tm const &v); + /// + /// Same as bind(v); + /// + statement &operator<<(std::istream &v); + /// + /// Apply manipulator on the statement, same as manipulator(*this). + /// + statement &operator<<(void (*manipulator)(statement &st)); + /// + /// Apply manipulator on the statement, same as manipulator(*this). + /// + result operator<<(result (*manipulator)(statement &st)); + + /// + /// Used together with use() function. + /// + /// The call st< + statement &operator<<(tags::use_tag const &val) + { + if(val.tag == null_value) + return bind_null(); + else + return bind(val.value); + } + + /// + /// Same as bind(v); + /// + template + statement &operator<<(T v) + { + return bind(v); + } + + private: + statement(ref_ptr stat,ref_ptr conn); + + friend class session; + + int placeholder_; + ref_ptr stat_; + ref_ptr conn_; + struct data; + std::unique_ptr d; + }; + + /// + /// \brief Manipulator that causes statement execution. Used as: + /// + /// \code + /// sql << "delete from test" << cppdb::exec; + /// \endcode + /// + inline void exec(statement &st) + { + st.exec(); + } + + /// + /// \brief Manipulator that binds null value. Used as: + /// + /// \code + /// sql << "insert into foo values(?,?,?)" << x << cppdb::null << y << cppdb::exec; + /// \endcode + /// + inline void null(statement &st) + { + st.bind_null(); + } + + /// + /// \brief Manipulator that fetches a single row. Used as: + /// + /// \code + /// cppdb::result r = sql << "SELECT name where uid=?" << id << cppdb::row; + /// if(!r.empty()) { + /// ... + /// } + /// \endcode + /// + /// Or: + /// + /// \code + /// sql << "SELECT name where uid=?" << id << cppdb::row >> name; + /// \endcode + /// + /// Which would throw empty_row_access exception on attempt to fetch name if the result is empty. + /// + inline result row(statement &st) + { + return st.row(); + } + + /// + /// \brief SQL session object that represents a single connection and is the gateway to SQL database + /// + /// It is the main class that is used for access to the DB, it uses various singleton classes to + /// load drivers open connections and cache them. + /// + class CPPDB_API session { + public: + + /// + /// Create an empty session object, it should not be used until it is opened with calling open() function. + /// + session(); + /// + /// Copy a session object, note - it copies only the reference to the underlying connection, so you should + /// be very careful when you do it. + /// + session(session const &); + /// + /// Assign a session object, note - it copies only the reference to the underlying connection, so you should + /// be very careful when you do it. + /// + session const &operator=(session const &); + /// + /// Destroys the session object, if connection pool is used it returns the object to connection pool. + /// + /// Note: the connection would not be returned to the pool until all statement and result objects + /// created using this session are not destroyed. + /// + ~session(); + + /// + /// Create a session using a parsed connection string \a ci + /// + /// \copydetails cppdb::parse_connection_string(std::string const&,std::string&,std::map&); + /// + session(connection_info const &ci); + /// + /// Create a session using a connection string \a cs. + /// + /// \copydetails cppdb::parse_connection_string(std::string const&,std::string&,std::map&); + /// + session(std::string const &cs); + /// + /// Create a session using a parsed connection string \a ci and call \a f if + /// a \ref once() was not called yet. + /// + /// It is useful for setting session specific options for new + /// connection, not reused from the pool one. + /// + /// Requirements: \ref once_functor is an object that can be created from generic + /// function like object func, such that func(*this) is valid expression + /// + /// \copydetails cppdb::parse_connection_string(std::string const&,std::string&,std::map&); + /// + session(connection_info const &ci,once_functor const &f); + /// + /// Create a session using a connection string \a cs and call \a f if + /// a \ref once() was not called yet. + /// + /// It is useful for setting session specific options for new + /// connection, not reused from the pool one. + /// + /// Requirements: \ref once_functor is an object that can be created from generic + /// function like object func, such that func(*this) is valid expression + /// + /// \copydetails cppdb::parse_connection_string(std::string const&,std::string&,std::map&); + /// + session(std::string const &cs,once_functor const &f); + /// + /// Create a session using a pointer to backend::connection and call \a f if + /// a \ref once() was not called yet. + /// + /// It is useful for setting session specific options for new + /// connection, not reused from the pool one. + /// + /// Requirements: \ref once_functor is an object that can be created from generic + /// function like object func, such that func(*this) is valid expression + /// + /// + session(ref_ptr conn,once_functor const &f); + /// + /// Create a session using a pointer to backend::connection. + /// + session(ref_ptr conn); + + /// + /// Open a session using a connection_info object - parsed connection string \a ci. + /// + void open(connection_info const &ci); + /// + /// Open a session using a connection string \a cs. + /// + /// \copydetails cppdb::parse_connection_string(std::string const&,std::string&,std::map&); + /// + void open(std::string const &cs); + /// + /// Close current connection, note, if connection pooling is used the connection is not actually become closed but + /// rather recycled for future use. + /// + void close(); + /// + /// Check if the session was opened. + /// + bool is_open(); + + /// + /// Create a new statement, by default is creates prepared statement - create_prepared_statement() unless \@use_prepared connection string + /// property is set to off, then it uses normal statements by calling create_statement() + /// + /// This is the most convenient function to create statements with. + /// + statement prepare(std::string const &query); + /// + /// Syntactic sugar, same as prepare(q) + /// + statement operator<<(std::string const &q); + /// + /// Syntactic sugar, same as prepare(s) + /// + statement operator<<(char const *s); + + + /// + /// Create ordinary statement it generally unprepared statement and it is never cached. It should + /// be used when such statement is executed rarely or very customized. + /// + statement create_statement(std::string const &q); + /// + /// Create prepared statement that will be cached for next calls. + /// + statement create_prepared_statement(std::string const &q); + /// + /// Create prepared statement however don't use statements cache and for it. Useful for creation + /// of custom or rarely executed statements that should be executed several times at this point in program. + /// + statement create_prepared_uncached_statement(std::string const &q); + + /// + /// Remove all statements from the cache. + /// + void clear_cache(); + + /// + /// Clear connections pool associated with this session's connection. + /// + /// Automatically calls clear_cache(); + /// + void clear_pool(); + + /// + /// Begin a transaction. Don't use it directly for RAII reasons. Use transaction class instead. + /// + void begin(); + /// + /// Commit a transaction. Don't use it directly for RAII reasons. Use transaction class instead. + /// + void commit(); + /// + /// Rollback a transaction. Don't use it directly for RAII reasons. Use transaction class instead. + /// + void rollback(); + + /// + /// Escape a string in range [\a b,\a e) for inclusion in SQL statement. It does not add quotation marks at beginning and end. + /// It is designed to be used with text, don't use it with generic binary data. + /// + /// Some backends (odbc) may not support this. + /// + std::string escape(char const *b,char const *e); + /// + /// Escape a NULL terminated string \a s for inclusion in SQL statement. It does not add quotation marks at beginning and end. + /// It is designed to be used with text, don't use it with generic binary data. + /// + /// Some backends (odbc) may not support this. + /// + std::string escape(char const *s); + /// + /// Escape a string \a s for inclusion in SQL statement. It does not add quotation marks at beginning and end. + /// It is designed to be used with text, don't use it with generic binary data. + /// + /// Some backends (odbc) may not support this. + /// + std::string escape(std::string const &s); + /// + /// Get the driver name, as mysql, postgresql, odbc, sqlite3. + /// + std::string driver(); + /// + /// Get an SQL engine name, it may be not the same as driver name for multiple engine drivers like odbc. + /// + std::string engine(); + /// + /// Check if this session's connection can be recycled for reuse in a pool. + /// + /// If an exception is thrown during operation on DB this flag is reset + /// to false by the front-end classes result, statement, session. + /// + /// Default is true + /// + bool recyclable(); + + /// + /// Set recyclable state of the session. If some problem occurs on connection + /// that prevents its reuse it should be called with false parameter. + /// + void recyclable(bool value); + + /// + /// Returns true of session specific initialization is done, otherwise returns false + /// + bool once_called(); + /// + /// Set flag to true if session specific initialization is done, otherwise set it to false + /// + void once_called(bool state); + /// + /// Call the functional \a f on the connection only once. If the connection + /// created first time then f would be called. If the connection is created + /// from connection pool and thus setup functor was called, f would not be called. + /// + /// Requirements: \ref once_functor is an object that can be created from generic + /// function like object func, such that func(*this) is valid expression + /// + void once(once_functor const &f); + + + /// + /// Get connection specific object by its type \a t, returns 0 if not installed yet + /// + connection_specific_data *get_specific(std::type_info const &t); + /// + /// Transfers ownership on the connection specific object of type \a t, returns 0 if not installed yet + /// + connection_specific_data *release_specific(std::type_info const &t); + /// + /// Deletes connection specific object of type \a t, and sets a new one \a p (if not NULL) + /// + void reset_specific(std::type_info const &t,connection_specific_data *p=0); + + /// + /// Get connection specific object by its type \a T, returns 0 if not installed yet + /// + template + T *get_specific() + { + return static_cast(get_specific(typeid(T))); + } + /// + /// Transfers ownership on the connection specific object of type \a T, returns 0 if not installed yet + /// + template + T *release_specific() + { + return static_cast(release_specific(typeid(T))); + } + /// + /// Deletes connection specific object of type \a T, and sets a new one \a p (if not NULL) + /// + template + void reset_specific(T *p=0) + { + reset_specific(typeid(T),p); + } + + private: + struct data; + std::unique_ptr d; + ref_ptr conn_; + }; + + /// + /// \brief The transaction guard + /// + /// This class is RAII transaction guard that causes automatic transaction rollback on stack unwind, unless + /// the transaction is committed + /// + class CPPDB_API transaction { + transaction(transaction const &); + void operator=(transaction const &); + public: + /// + /// Begin a transaction on session \a s, calls s.begin() + /// + transaction(session &s); + /// + /// If the transaction wasn't committed or rolled back calls session::rollback() for the session it was created with. + /// + ~transaction(); + /// + /// Commit a transaction on the session. Calls session::commit() for the session it was created with. + /// + void commit(); + /// + /// Rollback a transaction on the session. Calls session::rollback() for the session it was created with. + /// + void rollback(); + private: + + struct data; + session *s_; + bool commited_; + std::unique_ptr d; + }; + + +} // cppdb + +#endif