From f14743ef28248ea8a8ad9bae1c7c3d6a354da257 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 14 Mar 2011 16:36:58 +0200 Subject: Add support for SQLite type system, adjust code generators --- odb/context.cxx | 28 +-- odb/makefile | 1 + odb/relational/mysql/context.cxx | 6 +- odb/relational/sqlite/common.cxx | 246 ++----------------- odb/relational/sqlite/common.hxx | 72 +----- odb/relational/sqlite/context.cxx | 490 ++++++++++---------------------------- odb/relational/sqlite/context.hxx | 50 +--- odb/relational/sqlite/header.cxx | 93 +------- odb/relational/sqlite/source.cxx | 401 +++---------------------------- odb/sql-token.cxx | 44 ++++ odb/sql-token.hxx | 6 + 11 files changed, 264 insertions(+), 1173 deletions(-) create mode 100644 odb/sql-token.cxx diff --git a/odb/context.cxx b/odb/context.cxx index 28d6749..090b13c 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -135,6 +135,20 @@ context () context* context::current_; +string context:: +upcase (string const& s) +{ + string r; + string::size_type n (s.size ()); + + r.reserve (n); + + for (string::size_type i (0); i < n; ++i) + r.push_back (toupper (s[i])); + + return r; +} + void context:: diverge (streambuf* sb) { @@ -163,20 +177,6 @@ member_type (semantics::data_member& m, string const& key_prefix) return *indirect_value (m.type (), key); } -string context:: -upcase (string const& s) -{ - string r; - string::size_type n (s.size ()); - - r.reserve (n); - - for (string::size_type i (0); i < n; ++i) - r.push_back (toupper (s[i])); - - return r; -} - bool context:: comp_value_ (semantics::class_& c) { diff --git a/odb/makefile b/odb/makefile index af3d882..dc80ff9 100644 --- a/odb/makefile +++ b/odb/makefile @@ -9,6 +9,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make # cxx_ptun := \ cxx-lexer.cxx \ +sql-token.cxx \ sql-lexer.cxx \ context.cxx \ common.cxx \ diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx index e241691..660f616 100644 --- a/odb/relational/mysql/context.cxx +++ b/odb/relational/mysql/context.cxx @@ -289,7 +289,7 @@ namespace relational { if (tt == sql_token::t_identifier) { - string const& id (t.identifier ()); + string const& id (context::upcase (t.identifier ())); if (id == "NATIONAL" || id == "CHAR" || @@ -311,7 +311,7 @@ namespace relational if (tt == sql_token::t_identifier) { bool match (true); - string const& id (t.identifier ()); + string const& id (context::upcase (t.identifier ())); // Numeric types. // @@ -581,7 +581,7 @@ namespace relational case parse_sign: { if (tt == sql_token::t_identifier && - t.identifier () == "UNSIGNED") + context::upcase (t.identifier ()) == "UNSIGNED") { r.unsign = true; } diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx index 31f0aad..c8169a7 100644 --- a/odb/relational/sqlite/common.cxx +++ b/odb/relational/sqlite/common.cxx @@ -85,99 +85,24 @@ namespace relational { switch (mi.st->type) { - // Integral types. - // - case sql_type::TINYINT: - case sql_type::SMALLINT: - case sql_type::MEDIUMINT: - case sql_type::INT: - case sql_type::BIGINT: + case sql_type::INTEGER: { traverse_integer (mi); break; } - - // Float types. - // - case sql_type::FLOAT: - case sql_type::DOUBLE: - { - traverse_float (mi); - break; - } - case sql_type::DECIMAL: - { - traverse_decimal (mi); - break; - } - - // Data-time types. - // - case sql_type::DATE: - case sql_type::TIME: - case sql_type::DATETIME: - case sql_type::TIMESTAMP: - case sql_type::YEAR: + case sql_type::REAL: { - traverse_date_time (mi); + traverse_real (mi); break; } - - // String and binary types. - // - case sql_type::CHAR: - case sql_type::VARCHAR: - case sql_type::TINYTEXT: case sql_type::TEXT: - case sql_type::MEDIUMTEXT: - case sql_type::LONGTEXT: - { - // For string types the limit is in characters rather - // than in bytes. The fixed-length pre-allocated buffer - // optimization can only be used for 1-byte encodings. - // To support this we will need the character encoding - // in sql_type. - // - traverse_long_string (mi); - break; - } - case sql_type::BINARY: - case sql_type::TINYBLOB: { - // BINARY's range is always 255 or less from MySQL 5.0.3. - // TINYBLOB can only store up to 255 bytes. - // - traverse_short_string (mi); + traverse_text (mi); break; } - case sql_type::VARBINARY: case sql_type::BLOB: - case sql_type::MEDIUMBLOB: - case sql_type::LONGBLOB: - { - if (mi.st->range && mi.st->range_value <= 255) - traverse_short_string (mi); - else - traverse_long_string (mi); - - break; - } - - // Other types. - // - case sql_type::BIT: - { - traverse_bit (mi); - break; - } - case sql_type::ENUM: { - traverse_enum (mi); - break; - } - case sql_type::SET: - { - traverse_set (mi); + traverse_blob (mi); break; } case sql_type::invalid: @@ -192,24 +117,6 @@ namespace relational // member_image_type // - namespace - { - const char* integer_types[] = - { - "char", - "short", - "int", - "int", - "long long" - }; - - const char* float_types[] = - { - "float", - "double" - }; - } - member_image_type:: member_image_type (semantics::type* type, string const& fq_type, @@ -233,35 +140,15 @@ namespace relational } void member_image_type:: - traverse_integer (member_info& mi) - { - if (mi.st->unsign) - type_ = "unsigned "; - else if (mi.st->type == sql_type::TINYINT) - type_ = "signed "; - - type_ += integer_types[mi.st->type - sql_type::TINYINT]; - } - - void member_image_type:: - traverse_float (member_info& mi) - { - type_ = float_types[mi.st->type - sql_type::FLOAT]; - } - - void member_image_type:: - traverse_decimal (member_info&) + traverse_integer (member_info&) { - type_ = "details::buffer"; + type_ = "long long"; } void member_image_type:: - traverse_date_time (member_info& mi) + traverse_real (member_info&) { - if (mi.st->type == sql_type::YEAR) - type_ = "short"; - else - type_ = "MYSQL_TIME"; + type_ = "double"; } void member_image_type:: @@ -270,80 +157,10 @@ namespace relational type_ = "details::buffer"; } - void member_image_type:: - traverse_bit (member_info&) - { - type_ = "unsigned char*"; - } - - void member_image_type:: - traverse_enum (member_info&) - { - // Represented as string. - // - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_set (member_info&) - { - // Represented as string. - // - type_ = "details::buffer"; - } - // // member_database_type // - namespace - { - const char* integer_database_id[] = - { - "id_tiny", - "id_utiny", - "id_short", - "id_ushort", - "id_long", // INT24 - "id_ulong", // INT24 UNSIGNED - "id_long", - "id_ulong", - "id_longlong", - "id_ulonglong" - }; - - const char* float_database_id[] = - { - "id_float", - "id_double" - }; - - const char* date_time_database_id[] = - { - "id_date", - "id_time", - "id_datetime", - "id_timestamp", - "id_year" - }; - - const char* char_bin_database_id[] = - { - "id_string", // CHAR - "id_blob", // BINARY, - "id_string", // VARCHAR - "id_blob", // VARBINARY - "id_string", // TINYTEXT - "id_blob", // TINYBLOB - "id_string", // TEXT - "id_blob", // BLOB - "id_string", // MEDIUMTEXT - "id_blob", // MEDIUMBLOB - "id_string", // LONGTEXT - "id_blob" // LONGBLOB - }; - } - member_database_type_id:: member_database_type_id (semantics::type* type, string const& fq_type, @@ -367,56 +184,27 @@ namespace relational } void member_database_type_id:: - traverse_integer (member_info& mi) - { - size_t i ( - (mi.st->type - sql_type::TINYINT) * 2 + (mi.st->unsign ? 1 : 0)); - type_id_ = string ("mysql::") + integer_database_id[i]; - } - - void member_database_type_id:: - traverse_float (member_info& mi) - { - type_id_ = string ("mysql::") + - float_database_id[mi.st->type - sql_type::FLOAT]; - } - - void member_database_type_id:: - traverse_decimal (member_info&) - { - type_id_ = "mysql::id_decimal"; - } - - void member_database_type_id:: - traverse_date_time (member_info& mi) - { - type_id_ = string ("mysql::") + - date_time_database_id[mi.st->type - sql_type::DATE]; - } - - void member_database_type_id:: - traverse_string (member_info& mi) + traverse_integer (member_info&) { - type_id_ = string ("mysql::") + - char_bin_database_id[mi.st->type - sql_type::CHAR]; + type_id_ = "sqlite::id_integer"; } void member_database_type_id:: - traverse_bit (member_info&) + traverse_real (member_info&) { - type_id_ = "mysql::id_bit"; + type_id_ = "sqlite::id_real"; } void member_database_type_id:: - traverse_enum (member_info&) + traverse_text (member_info&) { - type_id_ = "mysql::id_enum"; + type_id_ = "sqlite::id_text"; } void member_database_type_id:: - traverse_set (member_info&) + traverse_blob (member_info&) { - type_id_ = "mysql::id_set"; + type_id_ = "sqlite::id_blob"; } // diff --git a/odb/relational/sqlite/common.hxx b/odb/relational/sqlite/common.hxx index f5009a0..0c9aae0 100644 --- a/odb/relational/sqlite/common.hxx +++ b/odb/relational/sqlite/common.hxx @@ -97,51 +97,28 @@ namespace relational } virtual void - traverse_float (member_info&) + traverse_real (member_info&) { } virtual void - traverse_decimal (member_info&) + traverse_text (member_info& m) { + traverse_string (m); } virtual void - traverse_date_time (member_info&) + traverse_blob (member_info& m) { + traverse_string (m); } + // String covers both text and blob. + // virtual void traverse_string (member_info&) { } - - virtual void - traverse_short_string (member_info& mi) - { - traverse_string (mi); - } - - virtual void - traverse_long_string (member_info& mi) - { - traverse_string (mi); - } - - virtual void - traverse_bit (member_info&) - { - } - - virtual void - traverse_enum (member_info&) - { - } - - virtual void - traverse_set (member_info&) - { - } }; struct member_image_type: member_base @@ -159,26 +136,11 @@ namespace relational traverse_integer (member_info&); virtual void - traverse_float (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_date_time (member_info&); + traverse_real (member_info&); virtual void traverse_string (member_info&); - virtual void - traverse_bit (member_info&); - - virtual void - traverse_enum (member_info&); - - virtual void - traverse_set (member_info&); - private: string type_; }; @@ -198,25 +160,13 @@ namespace relational traverse_integer (member_info&); virtual void - traverse_float (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_date_time (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_bit (member_info&); + traverse_real (member_info&); virtual void - traverse_enum (member_info&); + traverse_text (member_info&); virtual void - traverse_set (member_info&); + traverse_blob (member_info&); private: string type_id_; diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx index 37588e9..a15e2be 100644 --- a/odb/relational/sqlite/context.cxx +++ b/odb/relational/sqlite/context.cxx @@ -3,6 +3,7 @@ // copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file +#include #include #include @@ -220,413 +221,176 @@ namespace relational // SQL type parsing. // - static sql_type - parse_sql_type (semantics::data_member& m, std::string const& sql); - - sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) - { - string key (kp.empty () - ? string ("sqlite-column-sql-type") - : "sqlite-" + kp + "-column-sql-type"); - - if (!m.count (key)) - m.set (key, parse_sql_type (m, column_type (m, kp))); - - return m.get (key); - } - - static sql_type - parse_sql_type (semantics::data_member& m, string const& sql) + namespace { - try + struct sql_parser { - sql_type r; - sql_lexer l (sql); + sql_parser (semantics::data_member& m, std::string const& sql) + : m_ (m), l_ (sql) + { + } - // While most type names use single identifier, there are - // a couple of exceptions to this rule: + // Issues diagnostics and throws generation_failed in case of + // an error. // - // NATIONAL CHAR|VARCHAR - // CHAR BYTE (BINARY) - // CHARACTER VARYING (VARCHAR) - // LONG VARBINARY (MEDIUMBLOB) - // LONG VARCHAR (MEDIUMTEXT) - // - // - enum state - { - parse_prefix, - parse_name, - parse_range, - parse_sign, - parse_done - }; - - state s (parse_prefix); - string prefix; - - for (sql_token t (l.next ()); - s != parse_done && t.type () != sql_token::t_eos; - t = l.next ()) + sql_type + parse () { - sql_token::token_type tt (t.type ()); - - switch (s) + try { - case parse_prefix: + for (sql_token t (l_.next ()); t.type () != sql_token::t_eos;) { - if (tt == sql_token::t_identifier) - { - string const& id (t.identifier ()); - - if (id == "NATIONAL" || - id == "CHAR" || - id == "CHARACTER" || - id == "LONG") - { - prefix = id; - s = parse_name; - continue; - } - } + sql_token::token_type tt (t.type ()); - // Fall through. - // - s = parse_name; - } - case parse_name: - { if (tt == sql_token::t_identifier) { - bool match (true); - string const& id (t.identifier ()); + string const& id (context::upcase (t.identifier ())); - // Numeric types. - // - if (id == "BIT") - { - r.type = sql_type::BIT; - } - else if (id == "TINYINT" || id == "INT1") - { - r.type = sql_type::TINYINT; - } - else if (id == "BOOL" || id == "BOOLEAN") - { - r.type = sql_type::TINYINT; - r.range = true; - r.range_value = 1; - } - else if (id == "SMALLINT" || id == "INT2") - { - r.type = sql_type::SMALLINT; - } - else if (id == "MEDIUMINT" || - id == "INT3" || - id == "MIDDLEINT") - { - r.type = sql_type::MEDIUMINT; - } - else if (id == "INT" || id == "INTEGER" || id == "INT4") - { - r.type = sql_type::INT; - } - else if (id == "BIGINT" || id == "INT8") - { - r.type = sql_type::BIGINT; - } - else if (id == "SERIAL") - { - r.type = sql_type::BIGINT; - r.unsign = true; - } - else if (id == "FLOAT" || id == "FLOAT4") - { - r.type = sql_type::FLOAT; - } - else if (id == "DOUBLE" || id == "FLOAT8") - { - r.type = sql_type::DOUBLE; - } - else if (id == "DECIMAL" || - id == "DEC" || - id == "NUMERIC" || - id == "FIXED") - { - r.type = sql_type::DECIMAL; - } - // - // Date-time types. + // Column constraints start with one of the following + // keywords. Use them to determine when to stop parsing. // - else if (id == "DATE") - { - r.type = sql_type::DATE; - } - else if (id == "TIME") - { - r.type = sql_type::TIME; - } - else if (id == "DATETIME") - { - r.type = sql_type::DATETIME; - } - else if (id == "TIMESTAMP") - { - r.type = sql_type::TIMESTAMP; - } - else if (id == "YEAR") - { - r.type = sql_type::YEAR; - } - // - // String and binary types. - // - else if (id == "NCHAR") - { - r.type = sql_type::CHAR; - } - else if (id == "VARCHAR") - { - r.type = prefix == "LONG" - ? sql_type::MEDIUMTEXT - : sql_type::VARCHAR; - } - else if (id == "NVARCHAR") - { - r.type = sql_type::VARCHAR; - } - else if (id == "VARYING" && prefix == "CHARACTER") - { - r.type = sql_type::VARCHAR; - } - else if (id == "BINARY") - { - r.type = sql_type::BINARY; - } - else if (id == "BYTE" && prefix == "CHAR") - { - r.type = sql_type::BINARY; - } - else if (id == "VARBINARY") - { - r.type = prefix == "LONG" - ? sql_type::MEDIUMBLOB - : sql_type::VARBINARY; - } - else if (id == "TINYBLOB") - { - r.type = sql_type::TINYBLOB; - } - else if (id == "TINYTEXT") - { - r.type = sql_type::TINYTEXT; - } - else if (id == "BLOB") + if (id == "CONSTRAINT" || + id == "PRIMARY" || + id == "NOT" || + id == "UNIQUE" || + id == "CHECK" || + id == "DEFAULT" || + id == "COLLATE" || + id == "REFERENCES") { - r.type = sql_type::BLOB; + break; } - else if (id == "TEXT") - { - r.type = sql_type::TEXT; - } - else if (id == "MEDIUMBLOB") - { - r.type = sql_type::MEDIUMBLOB; - } - else if (id == "MEDIUMTEXT") - { - r.type = sql_type::MEDIUMTEXT; - } - else if (id == "LONGBLOB") - { - r.type = sql_type::LONGBLOB; - } - else if (id == "LONGTEXT") - { - r.type = sql_type::LONGTEXT; - } - else if (id == "ENUM") - { - r.type = sql_type::ENUM; - } - else if (id == "SET") - { - r.type = sql_type::SET; - } - else - match = false; - if (match) - { - s = parse_range; - continue; - } - } + ids_.push_back (id); + t = l_.next (); - // Some prefixes can also be type names if not followed - // by the actual type name. - // - if (!prefix.empty ()) - { - if (prefix == "CHAR" || prefix == "CHARACTER") + if (t.punctuation () == sql_token::p_lparen) { - r.type = sql_type::CHAR; - } - else if (prefix == "LONG") - { - r.type = sql_type::MEDIUMTEXT; + parse_range (); + t = l_.next (); } } - - if (r.type == sql_type::invalid) + else { - cerr << m.file () << ":" << m.line () << ":" << - m.column () << ":"; - - if (tt == sql_token::t_identifier) - cerr << " error: unknown MySQL type '" << - t.identifier () << "'" << endl; - else - cerr << " error: expected MySQL type name" << endl; - + cerr << m_.file () << ":" << m_.line () << ":" << m_.column () + << ": error: expected SQLite type name instead of '" + << t << "'" << endl; throw generation_failed (); } - - // Fall through. - // - s = parse_range; } - case parse_range: - { - if (t.punctuation () == sql_token::p_lparen) - { - t = l.next (); - - // ENUM and SET have a list of members instead of the range. - // - if (r.type == sql_type::ENUM || r.type == sql_type::SET) - { - // Skip tokens until we get the closing paren. - // - while (t.type () != sql_token::t_eos && - t.punctuation () != sql_token::p_rparen) - t = l.next (); - } - else - { - if (t.type () != sql_token::t_int_lit) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: integer range expected in MySQL type " - << "declaration" << endl; - - throw generation_failed (); - } - - unsigned int v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: invalid range value '" << t.literal () - << "'in MySQL type declaration" << endl; - - throw generation_failed (); - } - - r.range = true; - r.range_value = v; - - t = l.next (); - - if (t.punctuation () == sql_token::p_comma) - { - // We have the second range value. Skip it. - // - l.next (); - t = l.next (); - } - } - - if (t.punctuation () != sql_token::p_rparen) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: expected ')' in MySQL type declaration" - << endl; - - throw generation_failed (); - } + } + catch (sql_lexer::invalid_input const& e) + { + cerr << m_.file () << ":" << m_.line () << ":" << m_.column () + << ": error: invalid SQLite type declaration: " << e.message + << endl; + throw generation_failed (); + } - s = parse_sign; - continue; - } + if (ids_.empty ()) + { + cerr << m_.file () << ":" << m_.line () << ":" << m_.column () + << ": error: expected SQLite type name" << endl; + throw generation_failed (); + } - // Fall through. - // - s = parse_sign; - } - case parse_sign: - { - if (tt == sql_token::t_identifier && - t.identifier () == "UNSIGNED") - { - r.unsign = true; - } + sql_type r; - s = parse_done; - break; - } - case parse_done: + // Apply the first four rules of the SQLite type to affinity + // conversion algorithm. + // + 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 { - assert (false); - break; + cerr << m_.file () << ":" << m_.line () << ":" << m_.column () + << " error: unknown SQLite type '" << id << "'" << endl; + throw generation_failed (); } } + + return r; } - if (s == parse_name && !prefix.empty ()) + void + parse_range () { - // Some prefixes can also be type names if not followed - // by the actual type name. + // Skip tokens until we get the closing paren. // - if (prefix == "CHAR" || prefix == "CHARACTER") + for (sql_token t (l_.next ());; t = l_.next ()) { - r.type = sql_type::CHAR; - } - else if (prefix == "LONG") - { - r.type = sql_type::MEDIUMTEXT; + if (t.punctuation () == sql_token::p_rparen) + break; + + if (t.type () != sql_token::t_eos) + { + cerr << m_.file () << ":" << m_.line () << ":" << m_.column () + << ": error: missing ')' in SQLite type declaration" + << endl; + throw generation_failed (); + } } } - if (r.type == sql_type::invalid) + bool + find (string const& str) const { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: incomplete MySQL type declaration" << endl; + for (identifiers::const_iterator i (ids_.begin ()); + i != ids_.end (); ++i) + { + if (i->find (str) != string::npos) + return true; + } - throw generation_failed (); + return false; } - // If range is omitted for CHAR or BIT types, it defaults to 1. - // - if ((r.type == sql_type::CHAR || r.type == sql_type::BIT) && !r.range) - { - r.range = true; - r.range_value = 1; - } + private: + typedef vector identifiers; - return r; - } - catch (sql_lexer::invalid_input const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: invalid MySQL type declaration: " << e.message - << endl; + private: + semantics::data_member& m_; + sql_lexer l_; + identifiers ids_; + }; + } + + sql_type const& context:: + column_sql_type (semantics::data_member& m, string const& kp) + { + string key (kp.empty () + ? string ("sqlite-column-sql-type") + : "sqlite-" + kp + "-column-sql-type"); - throw generation_failed (); + if (!m.count (key)) + { + sql_parser p (m, column_type (m, kp)); + m.set (key, p.parse ()); } + + return m.get (key); } } } diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx index 0aff8f5..1aa18af 100644 --- a/odb/relational/sqlite/context.hxx +++ b/odb/relational/sqlite/context.hxx @@ -18,60 +18,16 @@ namespace relational // enum core_type { - // Integral types. - // - TINYINT, - SMALLINT, - MEDIUMINT, - INT, - BIGINT, - - // Float types. - // - FLOAT, - DOUBLE, - DECIMAL, - - // Data-time types. - // - DATE, - TIME, - DATETIME, - TIMESTAMP, - YEAR, - - // String and binary types. - // - CHAR, - BINARY, - VARCHAR, - VARBINARY, - TINYTEXT, - TINYBLOB, + INTEGER, + REAL, TEXT, BLOB, - MEDIUMTEXT, - MEDIUMBLOB, - LONGTEXT, - LONGBLOB, - - // Other types. - // - BIT, - ENUM, - SET, - - // Invalid type. - // invalid }; - sql_type () : type (invalid), unsign (false), range (false) {} + sql_type (): type (invalid) {} core_type type; - bool unsign; - bool range; - unsigned int range_value; // MySQL max value is 2^32 - 1 (LONGBLOG/TEXT). }; class context: public virtual relational::context diff --git a/odb/relational/sqlite/header.cxx b/odb/relational/sqlite/header.cxx index 1ca038d..87faf20 100644 --- a/odb/relational/sqlite/header.cxx +++ b/odb/relational/sqlite/header.cxx @@ -54,110 +54,29 @@ namespace relational traverse_integer (member_info& mi) { os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" + << "bool " << mi.var << "null;" << endl; } virtual void - traverse_float (member_info& mi) + traverse_real (member_info& mi) { os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" + << "bool " << mi.var << "null;" << endl; } virtual void - traverse_decimal (member_info& mi) + traverse_string (member_info& mi) { - // Exchanged as strings. Can have up to 65 digits not counting - // '-' and '.'. If range is not specified, the default is 10. - // - - /* - @@ Disabled. - os << "char " << mi.var << "value[" << - (t.range ? t.range_value : 10) + 3 << "];" - */ - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" - << endl; - - } - - virtual void - traverse_short_string (member_info& mi) - { - // If range is not specified, the default buffer size is 255. - // - /* - @@ Disabled. - os << "char " << mi.var << "value[" << - (t.range ? t.range_value : 255) + 1 << "];" - */ - - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_bit (member_info& mi) - { - // Valid range is 1 to 64. - // - unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0)); - - os << "unsigned char " << mi.var << "value[" << n << "];" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as string. - // - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as string. - // - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" + << "std::size_t " << mi.var << "size;" + << "bool " << mi.var << "null;" << endl; } private: string image_type; - member_image_type member_image_type_; }; entry image_member_; diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx index 9390a99..f8510a2 100644 --- a/odb/relational/sqlite/source.cxx +++ b/odb/relational/sqlite/source.cxx @@ -18,49 +18,6 @@ namespace relational { namespace relational = relational::source; - namespace - { - const char* integer_buffer_types[] = - { - "MYSQL_TYPE_TINY", - "MYSQL_TYPE_SHORT", - "MYSQL_TYPE_LONG", // *_bind_param() doesn't support INT24. - "MYSQL_TYPE_LONG", - "MYSQL_TYPE_LONGLONG" - }; - - const char* float_buffer_types[] = - { - "MYSQL_TYPE_FLOAT", - "MYSQL_TYPE_DOUBLE" - }; - - const char* date_time_buffer_types[] = - { - "MYSQL_TYPE_DATE", - "MYSQL_TYPE_TIME", - "MYSQL_TYPE_DATETIME", - "MYSQL_TYPE_TIMESTAMP", - "MYSQL_TYPE_SHORT" - }; - - const char* char_bin_buffer_types[] = - { - "MYSQL_TYPE_STRING", // CHAR - "MYSQL_TYPE_BLOB", // BINARY, - "MYSQL_TYPE_STRING", // VARCHAR - "MYSQL_TYPE_BLOB", // VARBINARY - "MYSQL_TYPE_STRING", // TINYTEXT - "MYSQL_TYPE_BLOB", // TINYBLOB - "MYSQL_TYPE_STRING", // TEXT - "MYSQL_TYPE_BLOB", // BLOB - "MYSQL_TYPE_STRING", // MEDIUMTEXT - "MYSQL_TYPE_BLOB", // MEDIUMBLOB - "MYSQL_TYPE_STRING", // LONGTEXT - "MYSQL_TYPE_BLOB" // LONGBLOB - }; - } - // // bind // @@ -126,116 +83,38 @@ namespace relational virtual void traverse_integer (member_info& mi) { - // While the is_unsigned should indicate whether the - // buffer variable is unsigned, rather than whether the - // database type is unsigned, in case of the image types, - // this is the same. - // - os << b << ".buffer_type = " << - integer_buffer_types[mi.st->type - sql_type::TINYINT] << ";" - << b << ".is_unsigned = " << (mi.st->unsign ? "1" : "0") << ";" + os << b << ".type = sqlite::binding::integer;" << b << ".buffer = &" << arg << "." << mi.var << "value;" << b << ".is_null = &" << arg << "." << mi.var << "null;"; } virtual void - traverse_float (member_info& mi) + traverse_real (member_info& mi) { - os << b << ".buffer_type = " << - float_buffer_types[mi.st->type - sql_type::FLOAT] << ";" + os << b << ".type = sqlite::binding::real;" << b << ".buffer = &" << arg << "." << mi.var << "value;" << b << ".is_null = &" << arg << "." << mi.var << "null;"; } virtual void - traverse_decimal (member_info& mi) + traverse_text (member_info& mi) { - os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;" + os << b << ".type = sqlite::binding::text;" << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << "" << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".size = &" << arg << "." << mi.var << "size;" + << b << ".capacity = " << arg << "." << mi.var << + "value.capacity ());" << b << ".is_null = &" << arg << "." << mi.var << "null;"; } virtual void - traverse_date_time (member_info& mi) + traverse_blob (member_info& mi) { - os << b << ".buffer_type = " << - date_time_buffer_types[mi.st->type - sql_type::DATE] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;"; - - if (mi.st->type == sql_type::YEAR) - os << b << ".is_unsigned = 0;"; - - os << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_short_string (member_info& mi) - { - // MySQL documentation is quite confusing about the use of - // buffer_length and length when it comes to input parameters. - // Source code, however, tells us that it uses buffer_length - // only if length is NULL. - // - os << b << ".buffer_type = " << - char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << "" << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << b << ".buffer_type = " << - char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" + os << b << ".type = sqlite::binding::blob;" << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << "" << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_bit (member_info& mi) - { - // Treated as a BLOB. - // - os << b << ".buffer_type = MYSQL_TYPE_BLOB;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".buffer_length = static_cast (" << endl - << "sizeof (" << arg << "." << mi.var << "value));" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as a string. - // - os << b << ".buffer_type = MYSQL_TYPE_STRING;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << "" << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << b << ".buffer_type = MYSQL_TYPE_STRING;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << "" << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".size = &" << arg << "." << mi.var << "size;" + << b << ".capacity = " << arg << "." << mi.var << + "value.capacity ());" << b << ".is_null = &" << arg << "." << mi.var << "null;"; } @@ -298,82 +177,20 @@ namespace relational virtual void traverse_integer (member_info&) { - os << e << " = 0;" + os << e << " = false;" << endl; } virtual void - traverse_float (member_info&) + traverse_real (member_info&) { - os << e << " = 0;" + os << e << " = false;" << endl; } virtual void - traverse_decimal (member_info& mi) + traverse_string (member_info& mi) { - // @@ Optimization disabled. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_date_time (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_short_string (member_info& mi) - { - // @@ Optimization disabled. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_bit (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as a string. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // os << "if (" << e << ")" << endl << "{" << "i." << mi.var << "value.capacity (i." << mi.var << "size);" @@ -485,11 +302,10 @@ namespace relational image_type = member_image_type_.image_type (mi.m); db_type_id = member_database_type_id_.database_type_id (mi.m); - os << "{" - << "bool is_null;"; + os << "{"; } - traits = "mysql::value_traits<\n " + traits = "sqlite::value_traits<\n " + type + ",\n " + image_type + ",\n " + db_type_id + " >"; @@ -515,8 +331,7 @@ namespace relational << "throw null_pointer ();"; } - os << "i." << mi.var << "null = is_null;" - << "}"; + os << "}"; } } @@ -534,113 +349,29 @@ namespace relational traverse_integer (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; - } - - virtual void - traverse_decimal (member_info& mi) - { - // @@ Optimization: can remove growth check if buffer is fixed. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; + << "i." << mi.var << "null," << endl + << member << ");"; } virtual void - traverse_date_time (member_info& mi) + traverse_real (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; - } - - virtual void - traverse_short_string (member_info& mi) - { - // @@ Optimization: can remove growth check if buffer is fixed. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; + << "i." << mi.var << "null," << endl + << member << ");"; } virtual void - traverse_long_string (member_info& mi) + traverse_string (member_info& mi) { - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" + os << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_bit (member_info& mi) - { - // Represented as a BLOB. - // - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size = static_cast (size);"; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as a string. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null," << endl << member << ");" - << "i." << mi.var << "size = static_cast (size);" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -735,7 +466,7 @@ namespace relational db_type_id = member_database_type_id_.database_type_id (mi.m); } - traits = "mysql::value_traits<\n " + traits = "sqlite::value_traits<\n " + type + ",\n " + image_type + ",\n " + db_type_id + " >"; @@ -788,93 +519,25 @@ namespace relational traverse_integer (member_info& mi) { os << traits << "::set_value (" << endl - << member << ", i." << mi.var << "value, " << - "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << ", i." << mi.var << "value, " << - "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_decimal (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_date_time (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << ", i." << mi.var << "value, " << - "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_short_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_long_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_bit (member_info& mi) - { - // Represented as a BLOB. - // - 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_enum (member_info& mi) + traverse_real (member_info& mi) { - // Represented as a string. - // 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_set (member_info& mi) + traverse_string (member_info& mi) { - // Represented as a string. - // os << traits << "::set_value (" << endl << member << "," << endl << "i." << mi.var << "value," << endl diff --git a/odb/sql-token.cxx b/odb/sql-token.cxx new file mode 100644 index 0000000..fe6b836 --- /dev/null +++ b/odb/sql-token.cxx @@ -0,0 +1,44 @@ +// file : odb/sql-token.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include + +#include + +using namespace std; + +static char punctuation_literals[] = {';', ',', '(', ')', '='}; + +ostream& +operator<< (ostream& os, sql_token const& t) +{ + switch (t.type ()) + { + case sql_token::t_eos: + { + os << ""; + break; + } + case sql_token::t_identifier: + { + os << t.identifier (); + break; + } + case sql_token::t_punctuation: + { + os << punctuation_literals[t.punctuation ()]; + break; + } + case sql_token::t_string_lit: + case sql_token::t_int_lit: + case sql_token::t_float_lit: + { + os << t.literal (); + break; + } + } + + return os; +} diff --git a/odb/sql-token.hxx b/odb/sql-token.hxx index fabcc99..4d9c7a1 100644 --- a/odb/sql-token.hxx +++ b/odb/sql-token.hxx @@ -7,6 +7,7 @@ #define ODB_SQL_TOKEN_HXX #include +#include #include // std::size_t class sql_token @@ -36,6 +37,8 @@ public: public: enum punctuation_type { + // Keep synched with punctuation_literals in source file. + // p_semi, p_comma, p_lparen, @@ -74,6 +77,9 @@ private: std::string str_; }; +std::ostream& +operator<< (std::ostream&, sql_token const&); + #include #endif // ODB_SQL_TOKEN_HXX -- cgit v1.1