diff options
Diffstat (limited to 'odb/relational/sqlite')
-rw-r--r-- | odb/relational/sqlite/common.cxx | 217 | ||||
-rw-r--r-- | odb/relational/sqlite/common.hxx | 147 | ||||
-rw-r--r-- | odb/relational/sqlite/context.cxx | 490 | ||||
-rw-r--r-- | odb/relational/sqlite/context.hxx | 146 | ||||
-rw-r--r-- | odb/relational/sqlite/header.cxx | 63 | ||||
-rw-r--r-- | odb/relational/sqlite/inline.cxx | 42 | ||||
-rw-r--r-- | odb/relational/sqlite/model.cxx | 91 | ||||
-rw-r--r-- | odb/relational/sqlite/schema.cxx | 455 | ||||
-rw-r--r-- | odb/relational/sqlite/source.cxx | 470 |
9 files changed, 0 insertions, 2121 deletions
diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx deleted file mode 100644 index 03a3599..0000000 --- a/odb/relational/sqlite/common.cxx +++ /dev/null @@ -1,217 +0,0 @@ -// file : odb/relational/sqlite/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <cassert> - -#include <odb/relational/sqlite/common.hxx> - -using namespace std; - -namespace relational -{ - namespace sqlite - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - switch (mi.st->type) - { - case sql_type::INTEGER: - { - traverse_integer (mi); - break; - } - case sql_type::REAL: - { - traverse_real (mi); - break; - } - case sql_type::TEXT: - { - if (mi.st->stream) - traverse_text_stream (mi); - else - traverse_text (mi); - break; - } - case sql_type::BLOB: - { - if (mi.st->stream) - traverse_blob_stream (mi); - else - traverse_blob (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_sqlite >::image_type"; - } - - void member_image_type:: - traverse_integer (member_info&) - { - type_ = "long long"; - } - - void member_image_type:: - traverse_real (member_info&) - { - type_ = "double"; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_stream (member_info&) - { - type_ = "sqlite::stream_buffers"; - } - - entry<member_image_type> member_image_type_; - - // - // member_database_type - // - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) {} - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) {} - - string member_database_type_id:: - database_type_id (type& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_integer (member_info&) - { - type_id_ = "sqlite::id_integer"; - } - - void member_database_type_id:: - traverse_real (member_info&) - { - type_id_ = "sqlite::id_real"; - } - - void member_database_type_id:: - traverse_text (member_info&) - { - type_id_ = "sqlite::id_text"; - } - - void member_database_type_id:: - traverse_blob (member_info&) - { - type_id_ = "sqlite::id_blob"; - } - - void member_database_type_id:: - traverse_text_stream (member_info&) - { - type_id_ = "sqlite::id_text_stream"; - } - - void member_database_type_id:: - traverse_blob_stream (member_info&) - { - type_id_ = "sqlite::id_blob_stream"; - } - - entry<member_database_type_id> member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - private: - member_database_type_id member_database_type_id_; - }; - entry<query_columns> query_columns_; - } -} diff --git a/odb/relational/sqlite/common.hxx b/odb/relational/sqlite/common.hxx deleted file mode 100644 index 4d6089e..0000000 --- a/odb/relational/sqlite/common.hxx +++ /dev/null @@ -1,147 +0,0 @@ -// file : odb/relational/sqlite/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SQLITE_COMMON_HXX -#define ODB_RELATIONAL_SQLITE_COMMON_HXX - -#include <odb/relational/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -namespace relational -{ - namespace sqlite - { - struct member_base: virtual relational::member_base_impl<sql_type>, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the sqlite namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_integer (member_info&) - { - } - - virtual void - traverse_real (member_info&) - { - } - - virtual void - traverse_text (member_info& m) - { - traverse_string (m); - } - - virtual void - traverse_blob (member_info& m) - { - traverse_string (m); - } - - // String covers both text and blob. - // - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_text_stream (member_info& m) - { - traverse_stream (m); - } - - virtual void - traverse_blob_stream (member_info& m) - { - traverse_stream (m); - } - - virtual void - traverse_stream (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_real (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_stream (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (type&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_real (member_info&); - - virtual void - traverse_text (member_info&); - - virtual void - traverse_blob (member_info&); - - virtual void - traverse_text_stream (member_info&); - - virtual void - traverse_blob_stream (member_info&); - - private: - string type_id_; - }; - } -} -#endif // ODB_RELATIONAL_SQLITE_COMMON_HXX diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx deleted file mode 100644 index 9a4369f..0000000 --- a/odb/relational/sqlite/context.cxx +++ /dev/null @@ -1,490 +0,0 @@ -// file : odb/relational/sqlite/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <vector> -#include <cassert> -#include <sstream> - -#include <odb/sql-token.hxx> -#include <odb/sql-lexer.hxx> - -#include <odb/relational/sqlite/context.hxx> -#include <odb/relational/sqlite/common.hxx> - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "INTEGER", 0, false}, - - {"char", "TEXT", 0, false}, - {"wchar_t", "TEXT", 0, false}, - {"signed char", "INTEGER", 0, false}, - {"unsigned char", "INTEGER", 0, false}, - - {"short int", "INTEGER", 0, false}, - {"short unsigned int", "INTEGER", 0, false}, - - {"int", "INTEGER", 0, false}, - {"unsigned int", "INTEGER", 0, false}, - - {"long int", "INTEGER", 0, false}, - {"long unsigned int", "INTEGER", 0, false}, - - {"long long int", "INTEGER", 0, false}, - {"long long unsigned int", "INTEGER", 0, false}, - - // SQLite stores NaN as NULL. - // - {"float", "REAL", 0, true}, - {"double", "REAL", 0, true}, - - {"::std::string", "TEXT", 0, false}, - {"::std::wstring", "TEXT", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast<data*> (root_context::data_.get ()), m), - data_ (static_cast<data*> (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = true; - need_alias_as = true; - insert_send_auto_id = true; - delay_freeing_statement_result = false; - need_image_clone = false; - generate_bulk = false; - global_index = true; - global_fkey = false; - data_->bind_vector_ = "sqlite::bind*"; - data_->truncated_vector_ = "bool*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - namespace - { - struct has_grow: traversal::class_ - { - has_grow (bool& r, user_section* s) - : r_ (r), section_ (s) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - // Ignore transient bases. - // - if (!(context::object (c) || context::composite (c))) - return; - - if (section_ == 0 && c.count ("sqlite-grow")) - r_ = c.get<bool> ("sqlite-grow"); - else - { - // r_ should be false. - // - inherits (c); - - if (!r_) - names (c); - - if (section_ == 0) - c.set ("sqlite-grow", r_); - } - } - - private: - bool& r_; - user_section* section_; - traversal::inherits inherits_; - }; - - struct has_grow_member: member_base - { - has_grow_member (bool& r, user_section* section = 0) - : relational::member_base (0, 0, string (), string (), section), - r_ (r) {} - - has_grow_member (bool& r, - user_section* section, - semantics::type* t, - const custom_cxx_type* ct, - string const& key_prefix = string ()) - : relational::member_base (t, ct, string (), key_prefix, section), - r_ (r) {} - - virtual bool - pre (member_info& mi) - { - // If we have a key prefix (container), then it can't be in a - // section (while mi.m can). The same for top-level -- if we got - // called, then we shouldn't ignore it. - // - return !key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)); - } - - virtual void - traverse_composite (member_info& mi) - { - // By calling grow() instead of recursing, we reset any overrides. - // We also don't pass section since they don't apply inside - // composites. - // - r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t)); - } - - virtual void - traverse_string (member_info&) - { - r_ = true; - } - - private: - bool& r_; - }; - } - - bool context:: - grow_impl (semantics::class_& c, user_section* section) - { - if (section == 0 && c.count ("sqlite-grow")) - return c.get<bool> ("sqlite-grow"); - - bool r (false); - has_grow ct (r, section); - has_grow_member mt (r, section); - traversal::names names; - ct >> names >> mt; - ct.traverse (c); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m) - { - bool r (false); - has_grow_member mt (r); - mt.traverse (m, true); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m, - semantics::type& t, - const custom_cxx_type* ct, - string const& kp) - { - bool r (false); - has_grow_member mt (r, 0, &t, ct, kp); - mt.traverse (m, true); - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - - using semantics::array; - - // char[N] mapping. - // - if (array* a = dynamic_cast<array*> (&t)) - { - semantics::type& bt (a->base_type ()); - if (bt.is_a<semantics::fund_char> () || - bt.is_a<semantics::fund_wchar> ()) - { - if (a->size () != 0) - r = "TEXT"; - } - } - - return r; - } - - // - // SQL type parsing. - // - - namespace - { - struct sql_parser - { - typedef context::invalid_sql_type invalid_sql_type; - - sql_parser (custom_db_types const* ct): ct_ (ct) {} - - sql_type - parse (string sql) - { - sql_type r; - - // First run the type through the custom mapping, if requested. - // - if (ct_ != 0) - { - for (custom_db_types::const_iterator i (ct_->begin ()); - i != ct_->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sql)) - { - r.to = t.type.replace (sql, t.to); - r.from = t.type.replace (sql, t.from); - sql = t.type.replace (sql, t.as); - break; - } - } - } - - // Parse the type into a sequence of identifiers. - // - try - { - l_.lex (sql); - - for (sql_token t (l_.next ()); t.type () != sql_token::t_eos;) - { - sql_token::token_type tt (t.type ()); - - if (tt == sql_token::t_identifier) - { - ids_.push_back (context::upcase (t.identifier ())); - t = l_.next (); - - if (t.punctuation () == sql_token::p_lparen) - { - if (!parse_range ()) - return error (m_); - - t = l_.next (); - } - } - else - return error ("expected SQLite type name instead of '" + - t.string () + "'"); - } - } - catch (sql_lexer::invalid_input const& e) - { - return error ("invalid SQLite type declaration: " + e.message); - } - - if (ids_.empty ()) - return error ("expected SQLite type name"); - - // First check our own types. - // - if (ids_.size () == 2 && ids_[0] == "TEXT" && ids_[1] == "STREAM") - { - r.type = sql_type::TEXT; - r.stream = true; - } - if (ids_.size () == 2 && ids_[0] == "BLOB" && ids_[1] == "STREAM") - { - r.type = sql_type::BLOB; - r.stream = true; - } - // - // Apply the first four rules of the SQLite type to affinity - // conversion algorithm. - // - else if (find ("INT")) - r.type = sql_type::INTEGER; - else if (find ("TEXT") || find ("CHAR") || find ("CLOB")) - r.type = sql_type::TEXT; - else if (find ("BLOB")) - r.type = sql_type::BLOB; - else if (find ("REAL") || find ("FLOA") || find ("DOUB")) - r.type = sql_type::REAL; - else - { - // Instead of the fifth rule which maps everything else - // to NUMERICAL (which we don't have), map some commonly - // used type names to one of the above types. - // - string const& id (ids_[0]); - - if (id == "NUMERIC") - r.type = sql_type::REAL; - else if (id == "DECIMAL") - r.type = sql_type::TEXT; - else if (id == "BOOLEAN" || id == "BOOL") - r.type = sql_type::INTEGER; - else if (id == "DATE" || id == "TIME" || id == "DATETIME") - r.type = sql_type::TEXT; - else - return error ("unknown SQLite type '" + id + "'"); - } - - return r; - } - - bool - parse_range () - { - // Skip tokens until we get the closing paren. - // - for (sql_token t (l_.next ());; t = l_.next ()) - { - if (t.punctuation () == sql_token::p_rparen) - break; - - if (t.type () == sql_token::t_eos) - { - m_ = "missing ')' in SQLite type declaration"; - return false; - } - } - - return true; - } - - private: - sql_type - error (string const& m) - { - if (ct_ == 0) - return sql_type (); - else - throw invalid_sql_type (m); - } - - bool - find (string const& str) const - { - for (identifiers::const_iterator i (ids_.begin ()); - i != ids_.end (); ++i) - { - if (i->find (str) != string::npos) - return true; - } - - return false; - } - - private: - custom_db_types const* ct_; - sql_lexer l_; - string m_; // Error message. - - typedef vector<string> identifiers; - identifiers ids_; - }; - } - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get<custom_db_types> ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - sql_type context:: - parse_sql_type (string const& sqlt, custom_db_types const* ct) - { - sql_parser p (ct); - return p.parse (sqlt); - } - } -} diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx deleted file mode 100644 index 777998b..0000000 --- a/odb/relational/sqlite/context.hxx +++ /dev/null @@ -1,146 +0,0 @@ -// file : odb/relational/sqlite/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SQLITE_CONTEXT_HXX -#define ODB_RELATIONAL_SQLITE_CONTEXT_HXX - -#include <map> - -#include <odb/relational/context.hxx> - -namespace relational -{ - namespace sqlite - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - INTEGER, - REAL, - TEXT, - BLOB, - invalid - }; - - sql_type (): type (invalid), stream (false) {} - - core_type type; - bool stream; // TEXT or BLOB via sqlite3_blob_open(). - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string const&, custom_db_types const* = 0); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual bool - grow_impl (semantics::class_&, user_section*); - - virtual bool - grow_impl (semantics::data_member&); - - virtual bool - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&); - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type& f, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map<string, sql_type_cache_entry> sql_type_cache; - sql_type_cache sql_type_cache_; - }; - - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_SQLITE_CONTEXT_HXX diff --git a/odb/relational/sqlite/header.cxx b/odb/relational/sqlite/header.cxx deleted file mode 100644 index 1aafe7a..0000000 --- a/odb/relational/sqlite/header.cxx +++ /dev/null @@ -1,63 +0,0 @@ -// file : odb/relational/sqlite/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <odb/relational/header.hxx> - -#include <odb/relational/sqlite/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -namespace relational -{ - namespace sqlite - { - namespace header - { - namespace relational = relational::header; - - struct image_member: relational::image_member_impl<sql_type>, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_real (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_stream (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - }; - entry<image_member> image_member_; - } - } -} diff --git a/odb/relational/sqlite/inline.cxx b/odb/relational/sqlite/inline.cxx deleted file mode 100644 index dd3274f..0000000 --- a/odb/relational/sqlite/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/sqlite/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <odb/relational/inline.hxx> - -#include <odb/relational/sqlite/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl<sql_type>, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "null;"; - else - os << "i." << mi.var << "null = true;"; - } - }; - entry<null_member> null_member_; - } - } -} diff --git a/odb/relational/sqlite/model.cxx b/odb/relational/sqlite/model.cxx deleted file mode 100644 index da16ded..0000000 --- a/odb/relational/sqlite/model.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// file : odb/relational/sqlite/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <sstream> - -#include <odb/relational/model.hxx> - -#include <odb/relational/sqlite/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual string - type (semantics::data_member& m) - { - // Translate BLOB|TEXT STREAM to just BLOB|TEXT. - // - string r (relational::object_columns::type (m)); - - sql_type const& t (parse_sql_type (r, m, false)); - if (t.stream) - { - switch (t.type) - { - case sql_type::BLOB: r = "BLOB"; break; - case sql_type::TEXT: r = "TEXT"; break; - default: break; - } - } - - return r; - } - - virtual bool - null (semantics::data_member& m) - { - return options.sqlite_override_null () || base::null (m); - } - - virtual string - default_enum (semantics::data_member& m, tree en, string const&) - { - // Make sure the column is mapped to INTEGER. - // - sql_type const& t (parse_sql_type (column_type (), m, false)); - if (t.type != sql_type::INTEGER) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to SQLite INTEGER" << endl; - - throw operation_failed (); - } - - using semantics::enumerator; - - enumerator& e (dynamic_cast<enumerator&> (*unit.find (en))); - - ostringstream ostr; - - if (e.enum_ ().unsigned_ ()) - ostr << e.value (); - else - ostr << static_cast<long long> (e.value ()); - - return ostr.str (); - } - - virtual void - primary_key (sema_rel::primary_key& pk) - { - if (pk.auto_ () && options.sqlite_lax_auto_id ()) - pk.extra ()["lax"] = "true"; - } - }; - entry<object_columns> object_columns_; - } - } -} diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx deleted file mode 100644 index f5549b4..0000000 --- a/odb/relational/sqlite/schema.cxx +++ /dev/null @@ -1,455 +0,0 @@ -// file : odb/relational/sqlite/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <odb/relational/schema.hxx> - -#include <odb/relational/sqlite/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -namespace relational -{ - namespace sqlite - { - namespace schema - { - namespace relational = relational::schema; - - // - // Drop. - // - - struct drop_column: trav_rel::drop_column, relational::common - { - drop_column (relational::common const& c) - : relational::common (c), first_ (true) {} - - virtual void - traverse (sema_rel::drop_column& dc) - { - // SQLite does not support dropping columns. If this column is - // not NULLable, then there is nothing we can do. Otherwise, do - // a logical DROP by setting all the values to NULL. - // - sema_rel::column& c (find<sema_rel::column> (dc)); - - if (!c.null ()) - { - cerr << "error: SQLite does not support dropping of columns" << - endl; - cerr << "info: first dropped column is '" << dc.name () << - "' in table '" << dc.table ().name () << "'" << endl; - cerr << "info: could have performed logical drop if the column " << - "allowed NULL values" << endl; - throw operation_failed (); - } - - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (dc.name ()) << " = NULL"; - } - - private: - bool first_; - }; - // Not registered as an override. - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In SQLite, index names can be qualified with the database. - // - sema_rel::table& t (static_cast<sema_rel::table&> (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - }; - entry<drop_index> drop_index_; - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // In SQLite there is no way to drop foreign keys except as part - // of the table. - // - if (pass_ != 2) - return; - - // Polymorphic base cleanup code. Because we cannot drop foreign - // keys, we will trigger cascade deletion. The only way to work - // around this problem is to delete from the root table and rely - // on the cascade to clean up the rest. - // - if (migration && t.extra ()["kind"] == "polymorphic derived object") - { - using sema_rel::model; - using sema_rel::table; - using sema_rel::primary_key; - using sema_rel::foreign_key; - - model& m (dynamic_cast<model&> (t.scope ())); - - table* p (&t); - do - { - // The polymorphic link is the first primary key. - // - for (table::names_iterator i (p->names_begin ()); - i != p->names_end (); ++i) - { - if (foreign_key* fk = dynamic_cast<foreign_key*> ( - &i->nameable ())) - { - p = m.find<table> (fk->referenced_table ()); - assert (p != 0); // Base table should be there. - break; - } - } - } - while (p->extra ()["kind"] != "polymorphic root object"); - - primary_key& rkey (*p->find<primary_key> ("")); - primary_key& dkey (*t.find<primary_key> ("")); - assert (rkey.contains_size () == dkey.contains_size ()); - delete_ (p->name (), t.name (), rkey, dkey); - } - - drop (t, migration); - } - }; - entry<drop_table> drop_table_; - - // - // Create. - // - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::add_column& ac) - { - using sema_rel::alter_table; - using sema_rel::add_column; - using sema_rel::add_foreign_key; - - alter_table& at (static_cast<alter_table&> (ac.scope ())); - - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD COLUMN "; - - // In SQLite it is impossible to alter a column later, so unless - // it has a default value, we add it as NULL. Without this, it - // will be impossible to add a column to a table that contains - // some rows. - // - create (ac); - - // SQLite doesn't support adding foreign keys other than inline - // via a column definition. See if we can handle any. - // - add_foreign_key* afk (0); - - for (add_column::contained_iterator i (ac.contained_begin ()); - i != ac.contained_end (); - ++i) - { - if ((afk = dynamic_cast<add_foreign_key*> (&i->key ()))) - { - // Check that it is a single-column foreign key. Also make - // sure the column and foreign key are from the same changeset. - // - if (afk->contains_size () != 1 || &ac.scope () != &afk->scope ()) - afk = 0; - else - break; - } - } - - if (afk != 0) - { - os << " CONSTRAINT " << quote_id (afk->name ()) << " REFERENCES " << - quote_id (afk->referenced_table ().uname ()) << " (" << - quote_id (afk->referenced_columns ()[0]) << ")"; - - bool del (afk->on_delete () != sema_rel::foreign_key::no_action); - bool def (!afk->not_deferrable ()); - - if (del || def) - { - instance<relational::create_foreign_key> cfk (*this); - - if (del) - cfk->on_delete (afk->on_delete ()); - - if (def) - cfk->deferrable (afk->deferrable ()); - } - - afk->set ("sqlite-fk-defined", true); // Mark it as defined. - } - - os << endl; - post_statement (); - } - - virtual void - auto_ (sema_rel::primary_key& pk) - { - if (pk.extra ().count ("lax")) - os << " /*AUTOINCREMENT*/"; - else - os << " AUTOINCREMENT"; - } - }; - entry<create_column> create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - virtual void - traverse (sema_rel::foreign_key& fk) - { - // In SQLite, all constraints are defined as part of a table. - // - os << "," << endl - << " CONSTRAINT "; - - create (fk); - } - - virtual string - table_name (sema_rel::foreign_key& fk) - { - // In SQLite, the referenced table cannot be qualified with the - // database name (it has to be in the same database anyway). - // - return quote_id (fk.referenced_table ().uname ()); - } - }; - entry<create_foreign_key> create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In SQLite, index names can be qualified with the database. - // - sema_rel::table& t (static_cast<sema_rel::table&> (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - - virtual string - table_name (sema_rel::index& in) - { - // In SQLite, the index table cannot be qualified with the - // database name (it has to be in the same database). - // - return quote_id ( - static_cast<sema_rel::table&> (in.scope ()).name ().uname ()); - } - }; - entry<create_index> create_index_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - void - traverse (sema_rel::table& t) - { - // For SQLite we do everything in a single pass since there - // is no way to add constraints later. - // - if (pass_ == 1) - create (t); - } - }; - entry<create_table> create_table_; - - // - // Alter. - // - - struct alter_table_pre: relational::alter_table_pre, context - { - alter_table_pre (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // SQLite can only add a single column per ALTER TABLE statement. - // - instance<create_column> cc (*this); - trav_rel::unames n (*cc); - names (at, n); - - // SQLite does not support altering columns. - // - if (sema_rel::alter_column* ac = check<sema_rel::alter_column> (at)) - { - cerr << "error: SQLite does not support altering of columns" - << endl; - cerr << "info: first altered column is '" << ac->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - - // SQLite does not support dropping constraints. We are going to - // ignore this if the column is NULL'able since in most cases - // the constraint is going to be dropped as a result of the - // column drop (e.g., an object pointer member got deleted). - // If we were not to allow this, then it would be impossible - // to do logical drop for pointer columns. - // - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::foreign_key; - using sema_rel::drop_foreign_key; - - drop_foreign_key* dfk ( - dynamic_cast<drop_foreign_key*> (&i->nameable ())); - - if (dfk == 0) - continue; - - foreign_key& fk (find<foreign_key> (*dfk)); - - for (foreign_key::contains_iterator j (fk.contains_begin ()); - j != fk.contains_end (); ++j) - { - if (j->column ().null ()) - continue; - - cerr << "error: SQLite does not support dropping of foreign " << - "keys" << endl; - cerr << "info: first dropped foreign key is '" << dfk->name () << - "' in table '" << at.name () << "'" << endl; - cerr << "info: could have ignored it if the contained " << - "column(s) allowed NULL values" << endl; - throw operation_failed (); - } - } - } - }; - entry<alter_table_pre> alter_table_pre_; - - struct alter_table_post: relational::alter_table_post, context - { - alter_table_post (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // SQLite does not support altering columns (we have to do this - // in both alter_table_pre/post because of the - // check_alter_column_null() test in the common code). - // - if (sema_rel::alter_column* ac = check<sema_rel::alter_column> (at)) - { - cerr << "error: SQLite does not support altering of columns" - << endl; - cerr << "info: first altered column is '" << ac->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - - // Try to do logical column drop. - // - if (check<sema_rel::drop_column> (at)) - { - pre_statement (); - - os << "UPDATE " << quote_id (at.name ()) << endl - << " SET "; - - drop_column dc (*this); - trav_rel::unames n (dc); - names (at, n); - os << endl; - - post_statement (); - } - - // SQLite doesn't support adding foreign keys other than inline - // via a column definition. See if there are any that we couldn't - // handle that way. - // - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - sema_rel::add_foreign_key* afk ( - dynamic_cast<sema_rel::add_foreign_key*> (&i->nameable ())); - - if (afk == 0 || afk->count ("sqlite-fk-defined")) - continue; - - cerr << "error: SQLite does not support adding foreign keys" - << endl; - cerr << "info: first added foreign key is '" << afk->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - } - }; - entry<alter_table_post> alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x): base (x) {} - - virtual void - create_table () - { - pre_statement (); - - os << "CREATE TABLE IF NOT EXISTS " << qt_ << " (" << endl - << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " INTEGER NOT NULL," << endl - << " " << qm_ << " INTEGER NOT NULL)" << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "INSERT OR IGNORE INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry<version_table> version_table_; - } - } -} diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx deleted file mode 100644 index 2624af2..0000000 --- a/odb/relational/sqlite/source.cxx +++ /dev/null @@ -1,470 +0,0 @@ -// file : odb/relational/sqlite/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <odb/relational/source.hxx> - -#include <odb/relational/sqlite/common.hxx> -#include <odb/relational/sqlite/context.hxx> - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace source - { - namespace relational = relational::source; - - struct query_parameters: relational::query_parameters, context - { - query_parameters (base const& x): base (x) {} - - virtual string - next (semantics::data_member& m, - const string& column, - const string& sqlt) - { - // Handle stream columns. Specifically, we somehow need to - // pass the column name to the code that runs in the - // statement. So what we are going to do is encode it - // in the parameter name. - // - if (sk_ == statement_insert || sk_ == statement_update) - { - const sql_type& t (parse_sql_type (sqlt, m, false)); - if (t.stream) - { - // The column name is quoted. - // - string r (column); - r[0] = '$'; // Replace leading '"'. - r.resize (r.size () - 1); // Remove trailing '"'. - - // Verify it only contains allowed characters. - // - for (size_t i (1); i != r.size (); ++i) - { - char c (r[i]); - if (c != '_' && - (c < '0' || c > '9') && - (c < 'a' || c > 'z') && - (c < 'A' || c > 'Z')) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: unsupported character '" << c << "' in " - << sqlt << " column name " << column << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: STREAM column can contain alpha-numeric " - << "characters plus '_'" << endl; - - throw operation_failed (); - } - } - - // For TEXT columns, since we use the *_bind_zeroblob() - // function (there is no *_bind_zerotext()), the value - // that will be stored is BLOB, not TEXT, unless we - // explicitly CAST it. The user better make sure the - // encoding of raw TEXT data they are going to write - // matches the database encoding. - // - if (t.type == sql_type::TEXT) - r = "CAST(" + r + " AS TEXT)"; - - return r; - } - } - - return "?"; - } - }; - entry<query_parameters> query_parameters_; - - // - // bind - // - - struct bind_member: relational::bind_member_impl<sql_type>, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_integer (member_info& mi) - { - os << b << ".type = sqlite::bind::integer;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_real (member_info& mi) - { - os << b << ".type = sqlite::bind::real;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_text (member_info& mi) - { - os << b << ".type = sqlite::image_traits<" << endl - << " " << mi.fq_type () << "," << endl - << " sqlite::id_text>::bind_value;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_blob (member_info& mi) - { - os << b << ".type = sqlite::bind::blob;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_stream (member_info& mi) - { - os << b << ".type = sqlite::bind::stream;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - }; - entry<bind_member> bind_member_; - - // - // grow - // - - struct grow_member: relational::grow_member_impl<sql_type>, - member_base - { - grow_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info&) - { - os << e << " = false;" - << endl; - } - - virtual void - traverse_real (member_info&) - { - os << e << " = false;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_stream (member_info&) - { - os << e << " = false;" - << endl; - } - }; - entry<grow_member> grow_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl<sql_type>, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "null = true;"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_real (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_stream (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - }; - entry<init_image_member> init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl<sql_type>, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "null"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_real (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_stream (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - }; - entry<init_value_member> init_value_member_; - - struct statement_columns_common: context - { - void - process (relational::statement_columns& cs, statement_kind sk) - { - using relational::statement_columns; - - // For SELECT statements, add _ROWID_ "follow-up" column to - // each stream column. The reason we need both, and not just - // ROWID is the NULL value. Let's hope that SELECT'ing a BLOB - // but not actually reading it with sqlite3_result_blob() is - // as fast as not SELECT'ing it. - // - if (sk != statement_select) - return; - - for (statement_columns::iterator i (cs.begin ()); - i != cs.end (); ++i) - { - if (parse_sql_type (i->type, *i->member).stream) - { - // Column is already table-qualified and quoted. Do some - // surgery to replace it with _ROWID_. That is, we want to - // transform "table"."column" to "table"."_ROWID_". - // - string c (i->column); - string::size_type n (c.size ()), p (c.rfind ('"', n - 2)); - assert (p != string::npos); - string as (c, p + 1, n - p - 2); - c.resize (p); - c += "\"_ROWID_\""; - - // We are going to pack this "tightly", without any newlines, - // so that the statement processing code treats them as a - // single column. - // - i->column += ','; - i->column += c; - } - } - } - }; - - struct container_traits: relational::container_traits, - statement_columns_common - { - container_traits (base const& x): base (x) {} - - virtual void - cache_result (string const&) - { - // Caching is not necessary since SQLite can execute several - // interleaving statements. - // - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool) - { - statement_columns_common::process (cols, sk); - } - }; - entry<container_traits> container_traits_; - - struct section_traits: relational::section_traits, - statement_columns_common - { - section_traits (base const& x): base (x) {} - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk) - { - statement_columns_common::process (cols, sk); - } - }; - entry<section_traits> section_traits_; - - struct class_: relational::class_, statement_columns_common - { - class_ (base const& x): base (x) {} - - virtual void - init_auto_id (semantics::data_member& m, string const& im) - { - // Don't set the id value to NULL if this is a nullable wrapper. - // This will allow the user to control whether the value is auto or - // manually assigned by using something like this: - // - // #pragma db auto - // odb::nullable<int64_t> id; - // - semantics::type& t (utype (m)); - if (wrapper (t) && t.template get<bool> ("wrapper-null-handler")) - return; - - os << im << "null = true;" - << endl; - } - - virtual string - select_trailer (type&) - { - // SQLite has not support for FOR UPDATE and since this is an - // optimization, we simply ignore it. - // - return ""; - } - - virtual string - join_syntax (view_object const& vo) - { - const char* n (0); - - if (vo.join == view_object::full) - n = "FULL OUTER JOIN"; - else if (vo.join == view_object::right) - n = "RIGHT OUTER JOIN"; - - if (n != 0) - { - error (vo.loc) << n << " is not supported by SQLite" << endl; - throw operation_failed (); - } - - return base::join_syntax (vo); - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool) - { - statement_columns_common::process (cols, sk); - } - }; - entry<class_> class_entry_; - } - } -} |