aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-07-22 14:33:21 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-07-22 14:33:21 +0200
commitcea6fb57ac8c9a893c0f404fef6c1469f0b6222b (patch)
treefed8b6ffa8ea2cb6347ece69c0cb81003d0ccbf6
parent5f71c55a1c24c23af1eeb0d664922497a0e5c071 (diff)
Next chunk of functionality
Add SQL language lexer. Implement MySQL type declaration parser. Create sub-directories for databases, currently mysql and tracer. Create MySQL-specific context.
-rw-r--r--odb/context.cxx77
-rw-r--r--odb/context.hxx33
-rw-r--r--odb/generator.cxx85
-rw-r--r--odb/makefile23
-rw-r--r--odb/mysql/common.cxx12
-rw-r--r--odb/mysql/common.hxx16
-rw-r--r--odb/mysql/context.cxx429
-rw-r--r--odb/mysql/context.hxx47
-rw-r--r--odb/mysql/header.cxx155
-rw-r--r--odb/mysql/header.hxx17
-rw-r--r--odb/mysql/inline.cxx76
-rw-r--r--odb/mysql/inline.hxx17
-rw-r--r--odb/mysql/schema.cxx (renamed from odb/mysql-schema.cxx)71
-rw-r--r--odb/mysql/schema.hxx (renamed from odb/mysql-schema.hxx)11
-rw-r--r--odb/mysql/source.cxx106
-rw-r--r--odb/mysql/source.hxx17
-rw-r--r--odb/sql-lexer.cxx240
-rw-r--r--odb/sql-lexer.hxx128
-rw-r--r--odb/sql-lexer.ixx86
-rw-r--r--odb/sql-token.hxx79
-rw-r--r--odb/sql-token.ixx46
-rw-r--r--odb/tracer/header.cxx (renamed from odb/header.cxx)51
-rw-r--r--odb/tracer/header.hxx (renamed from odb/header.hxx)15
-rw-r--r--odb/tracer/inline.cxx (renamed from odb/inline.cxx)37
-rw-r--r--odb/tracer/inline.hxx (renamed from odb/inline.hxx)15
-rw-r--r--odb/tracer/source.cxx (renamed from odb/source.cxx)57
-rw-r--r--odb/tracer/source.hxx (renamed from odb/source.hxx)15
27 files changed, 1745 insertions, 216 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index eb0aa5d..15d1adb 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -87,79 +87,21 @@ namespace
"xor",
"xor_eq"
};
-
- struct type_map_entry
- {
- const char* const cxx_type;
- const char* const db_type;
- };
-
- type_map_entry mysql_type_map[] =
- {
- {"bool", "TINYINT(1)"},
-
- {"char", "TINYINT"},
- {"signed char", "TINYINT"},
- {"unsigned char", "TINYINT UNSIGNED"},
-
- {"short int", "SMALLINT"},
- {"short unsigned int", "SMALLINT UNSIGNED"},
-
- {"int", "INT"},
- {"unsigned int", "INT UNSIGNED"},
-
- {"long int", "BIGINT"},
- {"long unsigned int", "BIGINT UNSIGNED"},
-
- {"long long int", "BIGINT"},
- {"long long unsigned int", "BIGINT UNSIGNED"},
-
- {"float", "FLOAT"},
- {"double", "DOUBLE"},
-
- {"::std::string", "TEXT"}
- };
}
context::
context (ostream& os_,
- semantics::unit& unit_,
- options_type const& ops)
- : data_ (new (shared) data),
+ semantics::unit& u,
+ options_type const& ops,
+ data_ptr d)
+ : data_ (d ? d : data_ptr (new (shared) data)),
os (os_),
- unit (unit_),
+ unit (u),
options (ops),
keyword_set (data_->keyword_set_)
{
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
-
- // Populate the C++ type to DB type map.
- //
- {
- size_t n;
- type_map_entry* p;
-
- switch (options.database ())
- {
- case database::mysql:
- {
- p = mysql_type_map;
- n = sizeof (mysql_type_map) / sizeof (type_map_entry);
- break;
- }
- default:
- {
- p = 0;
- n = 0;
- break;
- }
- }
-
- for (size_t i (0); i < n; ++i)
- data_->type_map_.insert (
- type_map_type::value_type (p[i].cxx_type, p[i].db_type));
- }
}
context::
@@ -172,6 +114,11 @@ context (context& c)
{
}
+context::
+~context ()
+{
+}
+
string context::
table_name (semantics::type& t) const
{
@@ -209,7 +156,7 @@ column_name (semantics::data_member& m) const
}
string context::
-db_type (semantics::data_member& m) const
+column_type (semantics::data_member& m) const
{
if (m.count ("type"))
return m.get<string> ("type");
@@ -218,7 +165,7 @@ db_type (semantics::data_member& m) const
type_map_type::const_iterator i (data_->type_map_.find (name));
if (i != data_->type_map_.end ())
- return i->second;
+ return m.count ("id") ? i->second.id_type : i->second.type;
cerr << m.file () << ":" << m.line () << ":" << m.column ()
<< " error: unable to map C++ type '" << name << "' used in "
diff --git a/odb/context.hxx b/odb/context.hxx
index 700e604..9f5723a 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -42,7 +42,7 @@ public:
column_name (semantics::data_member&) const;
string
- db_type (semantics::data_member&) const;
+ column_type (semantics::data_member&) const;
public:
// Escape C++ keywords, reserved names, and illegal characters.
@@ -50,9 +50,10 @@ public:
string
escape (string const&) const;
-private:
+protected:
struct data;
- cutl::shared_ptr<data> data_;
+ typedef cutl::shared_ptr<data> data_ptr;
+ data_ptr data_;
public:
std::ostream& os;
@@ -62,19 +63,39 @@ public:
typedef std::set<string> keyword_set_type;
keyword_set_type const& keyword_set;
- typedef std::map<string, string> type_map_type;
+ struct db_type_type
+ {
+ db_type_type () {}
+ db_type_type (string const& t, string const& it)
+ : type (t), id_type (it)
+ {
+ }
+
+ string type;
+ string id_type;
+ };
-private:
+ typedef std::map<string, db_type_type> type_map_type;
+
+protected:
struct data
{
+ virtual ~data () {}
+
keyword_set_type keyword_set_;
type_map_type type_map_;
};
public:
- context (std::ostream&, semantics::unit&, options_type const&);
+ context (std::ostream&,
+ semantics::unit&,
+ options_type const&,
+ data_ptr = data_ptr ());
context (context&);
+ virtual
+ ~context ();
+
private:
context&
operator= (context const&);
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 0d4e0c9..ce5b1cb 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -5,6 +5,7 @@
#include <cctype> // std::toupper, std::is{alpha,upper,lower}
#include <string>
+#include <memory> // std::auto_ptr
#include <fstream>
#include <iostream>
@@ -16,11 +17,15 @@
#include <odb/context.hxx>
#include <odb/generator.hxx>
-#include <odb/header.hxx>
-#include <odb/inline.hxx>
-#include <odb/source.hxx>
+#include <odb/tracer/header.hxx>
+#include <odb/tracer/inline.hxx>
+#include <odb/tracer/source.hxx>
-#include <odb/mysql-schema.hxx>
+#include <odb/mysql/context.hxx>
+#include <odb/mysql/schema.hxx>
+#include <odb/mysql/header.hxx>
+#include <odb/mysql/inline.hxx>
+#include <odb/mysql/source.hxx>
using namespace std;
using namespace cutl;
@@ -188,9 +193,23 @@ generate (options const& ops, semantics::unit& unit, path const& p)
//
{
cxx_filter filt (hxx);
- context ctx (hxx, unit, ops);
+ auto_ptr<context> ctx;
- string guard (make_guard (gp + hxx_name, ctx));
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ ctx.reset (new mysql::context (hxx, unit, ops));
+ break;
+ }
+ case database::tracer:
+ {
+ ctx.reset (new context (hxx, unit, ops));
+ break;
+ }
+ }
+
+ string guard (make_guard (gp + hxx_name, *ctx));
hxx << "#ifndef " << guard << endl
<< "#define " << guard << endl
@@ -200,7 +219,19 @@ generate (options const& ops, semantics::unit& unit, path const& p)
(br ? '>' : '"') << endl
<< endl;
- generate_header (ctx);
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ mysql::generate_header (static_cast<mysql::context&> (*ctx.get ()));
+ break;
+ }
+ case database::tracer:
+ {
+ tracer::generate_header (*ctx);
+ break;
+ }
+ }
hxx << "#include " << (br ? '<' : '"') << ip << ixx_name <<
(br ? '>' : '"') << endl
@@ -213,34 +244,60 @@ generate (options const& ops, semantics::unit& unit, path const& p)
//
{
cxx_filter filt (ixx);
- context ctx (ixx, unit, ops);
- generate_inline (ctx);
+
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ mysql::context ctx (ixx, unit, ops);
+ mysql::generate_inline (ctx);
+ break;
+ }
+ case database::tracer:
+ {
+ context ctx (ixx, unit, ops);
+ tracer::generate_inline (ctx);
+ break;
+ }
+ }
}
// CXX
//
{
cxx_filter filt (cxx);
- context ctx (cxx, unit, ops);
cxx << "#include " << (br ? '<' : '"') << ip << hxx_name <<
(br ? '>' : '"') << endl
<< endl;
- generate_source (ctx);
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ mysql::context ctx (cxx, unit, ops);
+ mysql::generate_source (ctx);
+ break;
+ }
+ case database::tracer:
+ {
+ context ctx (cxx, unit, ops);
+ tracer::generate_source (ctx);
+ break;
+ }
+ }
}
// SQL
//
if (ops.generate_schema ())
{
- context ctx (sql, unit, ops);
-
switch (ops.database ())
{
case database::mysql:
{
- generate_mysql_schema (ctx);
+ mysql::context ctx (sql, unit, ops);
+ mysql::generate_schema (ctx);
break;
}
case database::tracer:
diff --git a/odb/makefile b/odb/makefile
index f6da371..1fb240d 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -8,15 +8,28 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
# Plugin units.
#
cxx_ptun := \
+sql-lexer.cxx \
context.cxx \
generator.cxx \
parser.cxx \
plugin.cxx \
-pragma.cxx \
-header.cxx \
-inline.cxx \
-source.cxx \
-mysql-schema.cxx
+pragma.cxx
+
+# Tracer
+#
+cxx_ptun += \
+tracer/header.cxx \
+tracer/inline.cxx \
+tracer/source.cxx
+
+# MySQL
+#
+cxx_ptun += \
+mysql/context.cxx \
+mysql/schema.cxx \
+mysql/header.cxx \
+mysql/inline.cxx \
+mysql/source.cxx
cxx_ptun += \
semantics/class.cxx \
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
new file mode 100644
index 0000000..cd572d6
--- /dev/null
+++ b/odb/mysql/common.cxx
@@ -0,0 +1,12 @@
+// file : odb/mysql/common.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/mysql/common.hxx>
+
+using namespace std;
+
+namespace mysql
+{
+}
diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx
new file mode 100644
index 0000000..cd4d27f
--- /dev/null
+++ b/odb/mysql/common.hxx
@@ -0,0 +1,16 @@
+// file : odb/mysql/common.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_COMMON_HXX
+#define ODB_MYSQL_COMMON_HXX
+
+#include <odb/common.hxx>
+#include <odb/mysql/context.hxx>
+
+namespace mysql
+{
+}
+
+#endif // ODB_MYSQL_COMMON_HXX
diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx
new file mode 100644
index 0000000..668ecf4
--- /dev/null
+++ b/odb/mysql/context.cxx
@@ -0,0 +1,429 @@
+// file : odb/mysql/context.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <sstream>
+
+#include <odb/sql-token.hxx>
+#include <odb/sql-lexer.hxx>
+
+#include <odb/mysql/context.hxx>
+
+using namespace std;
+
+namespace mysql
+{
+ namespace
+ {
+ struct type_map_entry
+ {
+ const char* const cxx_type;
+ const char* const db_type;
+ const char* const db_id_type;
+ };
+
+ type_map_entry type_map[] =
+ {
+ {"bool", "TINYINT(1)", 0},
+
+ {"char", "TINYINT", 0},
+ {"signed char", "TINYINT", 0},
+ {"unsigned char", "TINYINT UNSIGNED", 0},
+
+ {"short int", "SMALLINT", 0},
+ {"short unsigned int", "SMALLINT UNSIGNED", 0},
+
+ {"int", "INT", 0},
+ {"unsigned int", "INT UNSIGNED", 0},
+
+ {"long int", "BIGINT", 0},
+ {"long unsigned int", "BIGINT UNSIGNED", 0},
+
+ {"long long int", "BIGINT", 0},
+ {"long long unsigned int", "BIGINT UNSIGNED", 0},
+
+ {"float", "FLOAT", 0},
+ {"double", "DOUBLE", 0},
+
+ {"::std::string", "TEXT", "VARCHAR(255)"}
+ };
+ }
+
+ context::
+ context (ostream& os, semantics::unit& u, options_type const& ops)
+ : base_context (os, u, ops, data_ptr (new (shared) data)),
+ data_ (static_cast<data*> (base_context::data_.get ()))
+ {
+ // 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));
+
+ data_->type_map_.insert (v);
+ }
+ }
+
+ context::
+ context (context& c)
+ : base_context (c),
+ data_ (c.data_)
+ {
+ }
+
+ static sql_type
+ parse_sql_type (semantics::data_member& m, std::string const& sql);
+
+ sql_type const& context::
+ db_type (semantics::data_member& m)
+ {
+ if (!m.count ("db-type"))
+ m.set ("db-type", parse_sql_type (m, column_type (m)));
+
+ return m.get<sql_type> ("db-type");
+ }
+
+ static sql_type
+ parse_sql_type (semantics::data_member& m, string const& sql)
+ {
+ try
+ {
+ sql_type r;
+ sql_lexer l (sql);
+
+ // While most type names use single identifier, there are
+ // a couple of exceptions to this rule:
+ //
+ // NATIONAL CHAR|VARCHAR
+ // CHAR BYTE (BINARY)
+ // CHARACTER VARYING (VARCHAR)
+ // LONG VARBINARY (MEDIUMBLOB)
+ // LONG VARCHAR (MEDIUMTEXT)
+ //
+ //
+ enum state
+ {
+ parse_prefix,
+ parse_name,
+ parse_bounds,
+ parse_sign
+ };
+
+ state s (parse_prefix);
+
+ for (sql_token t (l.next ());
+ t.type () != sql_token::t_eos; t = l.next ())
+ {
+ sql_token::token_type tt (t.type ());
+
+ switch (s)
+ {
+ case parse_prefix:
+ {
+ if (tt == sql_token::t_identifier)
+ {
+ string const& id (t.identifier ());
+
+ if (id == "NATIONAL" ||
+ id == "CHAR" ||
+ id == "CHARACTER" ||
+ id == "LONG")
+ {
+ r.type = id;
+ continue;
+ }
+ }
+
+ // Fall through.
+ //
+ s = parse_prefix;
+ }
+ case parse_name:
+ {
+ if (tt == sql_token::t_identifier)
+ {
+ bool match (true);
+ string const& id (t.identifier ());
+
+ // Numeric types.
+ //
+ if (id == "BIT")
+ {
+ r.type = "BIT";
+ }
+ else if (id == "TINYINT" || id == "INT1")
+ {
+ r.type = "TINYINT";
+ }
+ else if (id == "BOOL" || id == "BOOLEAN")
+ {
+ r.type = "TINYINT";
+ r.bounds = true;
+ r.bounds_value = 1;
+ }
+ else if (id == "SMALLINT" || id == "INT2")
+ {
+ r.type = "SMALLINT";
+ }
+ else if (id == "MEDIUMINT" || id == "INT3" || id == "MIDDLEINT")
+ {
+ r.type = "MEDIUMINT";
+ }
+ else if (id == "INT" || id == "INTEGER" || id == "INT4")
+ {
+ r.type = "INT";
+ }
+ else if (id == "BIGINT" || id == "INT8")
+ {
+ r.type = "BIGINT";
+ }
+ else if (id == "SERIAL")
+ {
+ r.type = "BIGINT";
+ r.unsign = true;
+ }
+ else if (id == "FLOAT" || id == "FLOAT4")
+ {
+ r.type = "FLOAT";
+ }
+ else if (id == "DOUBLE" || id == "FLOAT8")
+ {
+ r.type = "DOUBLE";
+ }
+ else if (id == "DECIMAL" ||
+ id == "DEC" ||
+ id == "NUMERIC" ||
+ id == "FIXED")
+ {
+ r.type = "DECIMAL";
+ }
+ //
+ // Date-time types.
+ //
+ else if (id == "DATE")
+ {
+ r.type = "DATE";
+ }
+ else if (id == "TIME")
+ {
+ r.type = "TIME";
+ }
+ else if (id == "DATETIME")
+ {
+ r.type = "DATETIME";
+ }
+ else if (id == "TIMESTAMP")
+ {
+ r.type = "TIMESTAMP";
+ }
+ else if (id == "YEAR")
+ {
+ r.type = "YEAR";
+ }
+ //
+ // String and binary types.
+ //
+ else if (id == "NCHAR")
+ {
+ r.type = "CHAR";
+ }
+ else if (id == "VARCHAR")
+ {
+ r.type = r.type == "LONG" ? "MEDIUMTEXT" : "VARCHAR";
+ }
+ else if (id == "NVARCHAR")
+ {
+ r.type = "VARCHAR";
+ }
+ else if (id == "VARYING" && r.type == "CHARACTER")
+ {
+ r.type = "VARCHAR";
+ }
+ else if (id == "BINARY")
+ {
+ r.type = "BINARY";
+ }
+ else if (id == "BYTE" && r.type == "CHAR")
+ {
+ r.type = "BINARY";
+ }
+ else if (id == "VARBINARY")
+ {
+ r.type = r.type == "LONG" ? "MEDIUMBLOB" : "VARBINARY";
+ }
+ else if (id == "TINYBLOB")
+ {
+ r.type = "TINYBLOB";
+ }
+ else if (id == "TINYTEXT")
+ {
+ r.type = "TINYTEXT";
+ }
+ else if (id == "BLOB")
+ {
+ r.type = "BLOB";
+ }
+ else if (id == "TEXT")
+ {
+ r.type = "TEXT";
+ }
+ else if (id == "MEDIUMBLOB")
+ {
+ r.type = "MEDIUMBLOB";
+ }
+ else if (id == "MEDIUMTEXT")
+ {
+ r.type = "MEDIUMTEXT";
+ }
+ else if (id == "LONGBLOB")
+ {
+ r.type = "LONGBLOB";
+ }
+ else if (id == "LONGTEXT")
+ {
+ r.type = "LONGTEXT";
+ }
+ else if (id == "ENUM")
+ {
+ r.type = "ENUM";
+ }
+ else if (id == "SET")
+ {
+ r.type = "SET";
+ }
+ else
+ match = false;
+
+ if (match)
+ {
+ s = parse_bounds;
+ continue;
+ }
+ }
+
+ bool match (false);
+
+ // Some prefixes can also be type names if not followed
+ // by the actual type name.
+ //
+ if (!r.type.empty ())
+ {
+ if (r.type == "CHAR")
+ match = true;
+ else if (r.type == "CHARACTER")
+ {
+ r.type = "CHAR";
+ match = true;
+ }
+ else if (r.type == "LONG")
+ {
+ r.type = "MEDIUMTEXT";
+ match = true;
+ }
+ }
+
+ if (!match)
+ {
+ 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;
+
+ throw generation_failed ();
+ }
+
+ // Fall through.
+ //
+ s = parse_bounds;
+ }
+ case parse_bounds:
+ {
+ if (t.punctuation () == sql_token::p_lparen)
+ {
+ t = l.next ();
+
+ if (t.type () != sql_token::t_int_lit)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << " error: integer bounds 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 bounds value '" << t.literal ()
+ << "'in MySQL type declaration" << endl;
+
+ throw generation_failed ();
+ }
+
+ r.bounds = true;
+ r.bounds_value = v;
+
+ t = l.next ();
+
+ if (t.punctuation () == sql_token::p_comma)
+ {
+ // We have the second bounds 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 ();
+ }
+
+ s = parse_sign;
+ continue;
+ }
+
+ // Fall through.
+ //
+ s = parse_sign;
+ }
+ case parse_sign:
+ {
+ if (tt == sql_token::t_identifier && t.identifier () == "UNSIGNED")
+ {
+ r.unsign = true;
+ }
+
+ return r;
+ }
+ }
+ }
+
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << " error: empty MySQL type declaration" << endl;
+
+ throw generation_failed ();
+ }
+ catch (sql_lexer::invalid_input const& e)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << " error: invalid MySQL type declaration: " << e.message << endl;
+
+ throw generation_failed ();
+ }
+ }
+}
diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx
new file mode 100644
index 0000000..7c075b2
--- /dev/null
+++ b/odb/mysql/context.hxx
@@ -0,0 +1,47 @@
+// file : odb/mysql/context.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_CONTEXT_HXX
+#define ODB_MYSQL_CONTEXT_HXX
+
+#include <string>
+
+#include <odb/context.hxx>
+
+namespace mysql
+{
+ struct sql_type
+ {
+ sql_type () : unsign (false), bounds (false) {}
+
+ std::string type;
+ bool unsign;
+ bool bounds;
+ unsigned int bounds_value; // MySQL max value is 2^32 - 1 (LONGBLOG/TEXT).
+ };
+
+ class context: public ::context
+ {
+ private:
+ typedef ::context base_context;
+
+ struct data: base_context::data
+ {
+ };
+
+ private:
+ data* data_;
+
+ public:
+ sql_type const&
+ db_type (semantics::data_member&);
+
+ public:
+ context (std::ostream&, semantics::unit&, options_type const&);
+ context (context&);
+ };
+}
+
+#endif // ODB_MYSQL_CONTEXT_HXX
diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx
new file mode 100644
index 0000000..a4111ec
--- /dev/null
+++ b/odb/mysql/header.cxx
@@ -0,0 +1,155 @@
+// file : odb/mysql/header.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/mysql/common.hxx>
+#include <odb/mysql/header.hxx>
+
+namespace
+{
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+
+ // Find the id member and type.
+ //
+ id_member t (*this);
+ t.traverse (c);
+
+ if (t.member () == 0)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " error: no data member designated as object id" << endl;
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " info: use '#pragma odb id' to specify object id member"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ semantics::data_member& id (*t.member ());
+ semantics::type& id_type (id.type ());
+
+ if (id_type.anonymous ())
+ {
+ // Can be a template-id (which we should handle eventually) or an
+ // anonymous type in member declaration (e.g., struct {...} m_;).
+ //
+ cerr << id.file () << ":" << id.line () << ":" << id.column ()
+ << " error: unnamed type in data member declaration" << endl;
+
+ cerr << id.file () << ":" << id.line () << ":" << id.column ()
+ << " info: use 'typedef' to name this type"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ os << "template <>" << endl
+ << "class access::object_traits< " << type << " >: " << endl
+ << " public access::object_memory< " << type << " >," << endl
+ << " public access::object_factory< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ // object_type & shared_ptr
+ //
+ os << "typedef " << type << " object_type;";
+
+ // id_type
+ //
+ os << "typedef " << id_type.fq_name () << " id_type;"
+ << endl;
+
+ // id_source
+ //
+ os << "static const odb::id_source id_source = odb::ids_assigned;"
+ << endl;
+
+ // id ()
+ //
+ os << "static id_type" << endl
+ << "id (const object_type&);"
+ << endl;
+
+ // persist ()
+ //
+ os << "static void" << endl
+ << "persist (database&, object_type&);"
+ << endl;
+
+ // store ()
+ //
+ os << "static void" << endl
+ << "store (database&, object_type&);"
+ << endl;
+
+ // erase ()
+ //
+ os << "static void" << endl
+ << "erase (database&, const id_type&);"
+ << endl;
+
+ // find ()
+ //
+ os << "static pointer_type" << endl
+ << "find (database&, const id_type&);"
+ << endl;
+
+ os << "static bool" << endl
+ << "find (database&, const id_type&, object_type&);";
+
+ os << "};";
+ }
+ };
+}
+
+namespace mysql
+{
+ void
+ generate_header (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "#include <odb/core.hxx>" << endl
+ << "#include <odb/traits.hxx>" << endl
+ << endl;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+ }
+}
diff --git a/odb/mysql/header.hxx b/odb/mysql/header.hxx
new file mode 100644
index 0000000..a31281e
--- /dev/null
+++ b/odb/mysql/header.hxx
@@ -0,0 +1,17 @@
+// file : odb/mysql/header.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_HEADER_HXX
+#define ODB_MYSQL_HEADER_HXX
+
+#include <odb/mysql/context.hxx>
+
+namespace mysql
+{
+ void
+ generate_header (context&);
+}
+
+#endif // ODB_MYSQL_HEADER_HXX
diff --git a/odb/mysql/inline.cxx b/odb/mysql/inline.cxx
new file mode 100644
index 0000000..44cf9d0
--- /dev/null
+++ b/odb/mysql/inline.cxx
@@ -0,0 +1,76 @@
+// file : odb/mysql/inline.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/mysql/common.hxx>
+#include <odb/mysql/inline.hxx>
+
+namespace
+{
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+ string traits ("access::object_traits< " + type + " >");
+
+ id_member t (*this);
+ t.traverse (c);
+ semantics::data_member& id (*t.member ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << endl;
+
+ // id ()
+ //
+ os << "inline" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
+ << "id (const object_type& obj)"
+ << "{"
+ << "return obj." << id.name () << ";" << endl
+ << "}";
+ }
+ };
+}
+
+namespace mysql
+{
+ void
+ generate_inline (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+ }
+}
diff --git a/odb/mysql/inline.hxx b/odb/mysql/inline.hxx
new file mode 100644
index 0000000..2d76274
--- /dev/null
+++ b/odb/mysql/inline.hxx
@@ -0,0 +1,17 @@
+// file : odb/mysql/inline.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_INLINE_HXX
+#define ODB_MYSQL_INLINE_HXX
+
+#include <odb/mysql/context.hxx>
+
+namespace mysql
+{
+ void
+ generate_inline (context&);
+}
+
+#endif // ODB_MYSQL_INLINE_HXX
diff --git a/odb/mysql-schema.cxx b/odb/mysql/schema.cxx
index ea3fece..a38729e 100644
--- a/odb/mysql-schema.cxx
+++ b/odb/mysql/schema.cxx
@@ -1,9 +1,9 @@
-// file : odb/mysql-schema.cxx
+// file : odb/mysql/schema.cxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-#include <odb/mysql-schema.hxx>
+#include <odb/mysql/schema.hxx>
namespace
{
@@ -22,7 +22,7 @@ namespace
else
os << "," << endl;
- os << " `" << column_name (m) << "` " << db_type (m) <<
+ os << " `" << column_name (m) << "` " << column_type (m) <<
" NOT NULL";
if (m.count ("id"))
@@ -96,46 +96,49 @@ static char const file_header[] =
" * compiler for C++.\n"
" */\n\n";
-void
-generate_mysql_schema (context& ctx)
+namespace mysql
{
- ctx.os << file_header;
-
- // Drop.
- //
+ void
+ generate_schema (context& ctx)
{
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- class_drop c (ctx);
+ ctx.os << file_header;
+
+ // Drop.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_drop c (ctx);
- unit >> unit_defines >> ns;
- unit_defines >> c;
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
- traversal::defines ns_defines;
+ traversal::defines ns_defines;
- ns >> ns_defines >> ns;
- ns_defines >> c;
- unit.dispatch (ctx.unit);
- }
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ unit.dispatch (ctx.unit);
+ }
- ctx.os << endl;
+ ctx.os << endl;
- // Create.
- //
- {
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- class_create c (ctx);
+ // Create.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_create c (ctx);
- unit >> unit_defines >> ns;
- unit_defines >> c;
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
- traversal::defines ns_defines;
+ traversal::defines ns_defines;
- ns >> ns_defines >> ns;
- ns_defines >> c;
- unit.dispatch (ctx.unit);
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ unit.dispatch (ctx.unit);
+ }
}
}
diff --git a/odb/mysql-schema.hxx b/odb/mysql/schema.hxx
index f4a7996..99699d3 100644
--- a/odb/mysql-schema.hxx
+++ b/odb/mysql/schema.hxx
@@ -1,4 +1,4 @@
-// file : odb/mysql-schema.hxx
+// file : odb/mysql/schema.hxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
@@ -6,9 +6,12 @@
#ifndef ODB_MYSQL_SCHEMA_HXX
#define ODB_MYSQL_SCHEMA_HXX
-#include <odb/context.hxx>
+#include <odb/mysql/context.hxx>
-void
-generate_mysql_schema (context&);
+namespace mysql
+{
+ void
+ generate_schema (context&);
+}
#endif // ODB_MYSQL_SCHEMA_HXX
diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx
new file mode 100644
index 0000000..0f117ec
--- /dev/null
+++ b/odb/mysql/source.cxx
@@ -0,0 +1,106 @@
+// file : odb/mysql/source.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/mysql/common.hxx>
+#include <odb/mysql/source.hxx>
+
+namespace
+{
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+ string traits ("access::object_traits< " + type + " >");
+
+ id_member t (*this);
+ t.traverse (c);
+ semantics::data_member& id (*t.member ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << endl;
+
+ // persist ()
+ //
+ os << "void " << traits << "::" << endl
+ << "persist (database&, object_type& obj)"
+ << "{"
+ << "}";
+
+ // store ()
+ //
+ os << "void " << traits << "::" << endl
+ << "store (database&, object_type& obj)"
+ << "{"
+ << "}";
+
+ // erase ()
+ //
+ os << "void " << traits << "::" << endl
+ << "erase (database&, const id_type& id)"
+ << "{"
+ << "}";
+
+ // find ()
+ //
+ os << traits << "::pointer_type" << endl
+ << traits << "::" << endl
+ << "find (database&, const id_type& id)"
+ << "{"
+ << "return 0;"
+ << "}";
+
+ os << "bool " << traits << "::" << endl
+ << "find (database&, const id_type& id, object_type& obj)"
+ << "{"
+ << "return false;"
+ << "}";
+ }
+ };
+}
+
+namespace mysql
+{
+ void
+ generate_source (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "#include <odb/mysql/database.hxx>" << endl
+ << "#include <odb/mysql/exceptions.hxx>" << endl
+ << endl;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+ }
+}
diff --git a/odb/mysql/source.hxx b/odb/mysql/source.hxx
new file mode 100644
index 0000000..6a79479
--- /dev/null
+++ b/odb/mysql/source.hxx
@@ -0,0 +1,17 @@
+// file : odb/mysql/source.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_SOURCE_HXX
+#define ODB_MYSQL_SOURCE_HXX
+
+#include <odb/mysql/context.hxx>
+
+namespace mysql
+{
+ void
+ generate_source (context&);
+}
+
+#endif // ODB_MYSQL_SOURCE_HXX
diff --git a/odb/sql-lexer.cxx b/odb/sql-lexer.cxx
new file mode 100644
index 0000000..e5b1693
--- /dev/null
+++ b/odb/sql-lexer.cxx
@@ -0,0 +1,240 @@
+// file : odb/sql-lexer.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <iostream>
+
+#include <odb/sql-lexer.hxx>
+
+using namespace std;
+
+sql_lexer::
+sql_lexer (std::string const& sql)
+ : loc_ ("C"),
+ is_ (sql),
+ l_ (1),
+ c_(1),
+ eos_ (false),
+ buf_ (0, 0, 0),
+ unget_ (false)
+{
+}
+
+sql_lexer::xchar sql_lexer::
+peek ()
+{
+ if (unget_)
+ return buf_;
+ else
+ {
+ if (eos_)
+ return xchar (xchar::traits_type::eof (), l_, c_);
+ else
+ {
+ xchar::int_type i (is_.peek ());
+
+ if (i == xchar::traits_type::eof ())
+ eos_ = true;
+
+ return xchar (i, l_, c_);
+ }
+ }
+}
+
+sql_lexer::xchar sql_lexer::
+get ()
+{
+ if (unget_)
+ {
+ unget_ = false;
+ return buf_;
+ }
+ else
+ {
+ // When is_.get () returns eof, the failbit is also set (stupid,
+ // isn't?) which may trigger an exception. To work around this
+ // we will call peek() first and only call get() if it is not
+ // eof. But we can only call peek() on eof once; any subsequent
+ // calls will spoil the failbit (even more stupid).
+ //
+ xchar c (peek ());
+
+ if (!is_eos (c))
+ {
+ is_.get ();
+
+ if (c == '\n')
+ {
+ l_++;
+ c_ = 1;
+ }
+ else
+ c_++;
+ }
+
+ return c;
+ }
+}
+
+void sql_lexer::
+unget (xchar c)
+{
+ // Because iostream::unget cannot work once eos is reached,
+ // we have to provide our own implementation.
+ //
+ buf_ = c;
+ unget_ = true;
+}
+
+sql_token sql_lexer::
+next ()
+{
+ skip_spaces ();
+
+ xchar c (get ());
+
+ if (is_eos (c))
+ return sql_token ();
+
+ switch (c)
+ {
+ case '\'':
+ {
+ return string_literal (c);
+ }
+ case '\"':
+ {
+ return string_literal (c);
+ }
+ case '`':
+ {
+ return string_literal (c);
+ }
+ case ';':
+ {
+ return sql_token (sql_token::p_semi);
+ }
+ case ',':
+ {
+ return sql_token (sql_token::p_comma);
+ }
+ case '(':
+ {
+ return sql_token (sql_token::p_lparen);
+ }
+ case ')':
+ {
+ return sql_token (sql_token::p_rparen);
+ }
+ case '=':
+ {
+ return sql_token (sql_token::p_eq);
+ }
+ case '-':
+ {
+ return int_literal (get (), true);
+ }
+ case '+':
+ {
+ return int_literal (get (), false);
+ }
+ }
+
+ if (is_alpha (c) || c == '_')
+ {
+ return identifier (c);
+ }
+
+ if (is_dec_digit (c))
+ {
+ return int_literal (c);
+ }
+
+ ostringstream msg;
+ msg << "unexpected character '" << c << "'";
+ throw invalid_input (c.line (), c.column (), msg.str ());
+}
+
+void sql_lexer::
+skip_spaces ()
+{
+ for (xchar c (peek ());; c = peek ())
+ {
+ if (is_eos (c) || !is_space (c))
+ break;
+
+ get ();
+ }
+}
+
+sql_token sql_lexer::
+identifier (xchar c)
+{
+ size_t ln (c.line ()), cl (c.column ());
+ string lexeme;
+ lexeme += c;
+
+ for (c = peek ();
+ !is_eos (c) && (is_alnum (c) || c == '_');
+ c = peek ())
+ {
+ get ();
+ lexeme += c;
+ }
+
+ return sql_token (sql_token::t_identifier, lexeme);
+}
+
+sql_token sql_lexer::
+int_literal (xchar c, bool neg, size_t ml, size_t mc)
+{
+ //size_t ln (neg ? ml : c.line ()), cl (neg ? mc : c.column ());
+ string lexeme;
+
+ if (neg)
+ lexeme += '-';
+
+ lexeme += c;
+
+ for (c = peek (); !is_eos (c) && is_dec_digit (c); c = peek ())
+ {
+ get ();
+ lexeme += c;
+ }
+
+ return sql_token (sql_token::t_int_lit, lexeme);
+}
+
+sql_token sql_lexer::
+string_literal (xchar c)
+{
+ //size_t ln (c.line ()), cl (c.column ());
+ char q (c), p ('\0');
+ string lexeme;
+ lexeme += c;
+
+ while (true)
+ {
+ xchar c = get ();
+
+ if (is_eos (c))
+ throw invalid_input (
+ c.line (), c.column (), "unterminated quoted string");
+
+ lexeme += c;
+
+ if (c == q && p != '\\')
+ break;
+
+ // We need to keep track of \\ escapings so we don't confuse
+ // them with \", as in "\\".
+ //
+ if (c == '\\' && p == '\\')
+ p = '\0';
+ else
+ p = c;
+ }
+
+ return sql_token (sql_token::t_string_lit, lexeme);
+}
diff --git a/odb/sql-lexer.hxx b/odb/sql-lexer.hxx
new file mode 100644
index 0000000..f650dc4
--- /dev/null
+++ b/odb/sql-lexer.hxx
@@ -0,0 +1,128 @@
+// file : odb/sql-lexer.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SQL_LEXER_HXX
+#define ODB_SQL_LEXER_HXX
+
+#include <string>
+#include <locale>
+#include <cstddef> // std::size_t
+#include <sstream>
+
+#include <odb/sql-token.hxx>
+
+class sql_lexer
+{
+public:
+ sql_lexer (std::string const& sql);
+
+ struct invalid_input
+ {
+ invalid_input (std::size_t l, std::size_t c, std::string const& m)
+ : line (l), column (c), message (m)
+ {
+ }
+
+ std::size_t line;
+ std::size_t column;
+ std::string const message;
+ };
+
+ sql_token
+ next ();
+
+protected:
+ class xchar
+ {
+ public:
+ typedef std::char_traits<char> traits_type;
+ typedef traits_type::int_type int_type;
+ typedef traits_type::char_type char_type;
+
+ xchar (int_type v, std::size_t l, std::size_t c);
+
+ operator char_type () const;
+
+ int_type
+ value () const;
+
+ std::size_t
+ line () const;
+
+ std::size_t
+ column () const;
+
+ private:
+ int_type v_;
+ std::size_t l_;
+ std::size_t c_;
+ };
+
+ xchar
+ peek ();
+
+ xchar
+ get ();
+
+ void
+ unget (xchar);
+
+protected:
+ void
+ skip_spaces ();
+
+ sql_token
+ identifier (xchar);
+
+ sql_token
+ int_literal (xchar,
+ bool neg = false,
+ std::size_t ml = 0,
+ std::size_t mc = 0);
+
+ sql_token
+ string_literal (xchar);
+
+protected:
+ bool
+ is_alpha (char c) const;
+
+ bool
+ is_oct_digit (char c) const;
+
+ bool
+ is_dec_digit (char c) const;
+
+ bool
+ is_hex_digit (char c) const;
+
+ bool
+ is_alnum (char c) const;
+
+ bool
+ is_space (char c) const;
+
+ bool
+ is_eos (xchar const& c) const;
+
+ char
+ to_upper (char c) const;
+
+private:
+ std::locale loc_;
+ std::istringstream is_;
+ std::size_t l_;
+ std::size_t c_;
+
+ bool eos_;
+ bool include_;
+
+ xchar buf_;
+ bool unget_;
+};
+
+#include <odb/sql-lexer.ixx>
+
+#endif // ODB_SQL_LEXER_HXX
diff --git a/odb/sql-lexer.ixx b/odb/sql-lexer.ixx
new file mode 100644
index 0000000..96deed1
--- /dev/null
+++ b/odb/sql-lexer.ixx
@@ -0,0 +1,86 @@
+// file : odb/sql-lexer.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// sql_lexer::xchar
+//
+inline sql_lexer::xchar::
+xchar (int_type v, std::size_t l, std::size_t c)
+ : v_ (v), l_ (l), c_ (c)
+{
+}
+
+inline sql_lexer::xchar::
+operator char_type () const
+{
+ return traits_type::to_char_type (v_);
+}
+
+inline sql_lexer::xchar::int_type sql_lexer::xchar::
+value () const
+{
+ return v_;
+}
+
+inline std::size_t sql_lexer::xchar::
+line () const
+{
+ return l_;
+}
+
+inline std::size_t sql_lexer::xchar::
+column () const
+{
+ return c_;
+}
+
+// lexer
+//
+inline bool sql_lexer::
+is_alpha (char c) const
+{
+ return std::isalpha (c, loc_);
+}
+
+inline bool sql_lexer::
+is_oct_digit (char c) const
+{
+ return std::isdigit (c, loc_) && c != '8' && c != '9';
+}
+
+inline bool sql_lexer::
+is_dec_digit (char c) const
+{
+ return std::isdigit (c, loc_);
+}
+
+inline bool sql_lexer::
+is_hex_digit (char c) const
+{
+ return std::isxdigit (c, loc_);
+}
+
+inline bool sql_lexer::
+is_alnum (char c) const
+{
+ return std::isalnum (c, loc_);
+}
+
+inline bool sql_lexer::
+is_space (char c) const
+{
+ return std::isspace (c, loc_);
+}
+
+inline bool sql_lexer::
+is_eos (xchar const& c) const
+{
+ return c.value () == xchar::traits_type::eof ();
+}
+
+inline char sql_lexer::
+to_upper (char c) const
+{
+ return std::toupper (c, loc_);
+}
diff --git a/odb/sql-token.hxx b/odb/sql-token.hxx
new file mode 100644
index 0000000..464c9a5
--- /dev/null
+++ b/odb/sql-token.hxx
@@ -0,0 +1,79 @@
+// file : odb/sql-token.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SQL_TOKEN_HXX
+#define ODB_SQL_TOKEN_HXX
+
+#include <string>
+#include <cstddef> // std::size_t
+
+class sql_token
+{
+public:
+ enum token_type
+ {
+ t_eos,
+ t_identifier,
+ t_punctuation,
+ t_string_lit,
+ t_int_lit,
+ t_float_lit,
+ };
+
+ token_type
+ type () const;
+
+ // Identifier
+ //
+public:
+ std::string const&
+ identifier () const;
+
+ // Punctuation
+ //
+public:
+ enum punctuation_type
+ {
+ p_semi,
+ p_comma,
+ p_lparen,
+ p_rparen,
+ p_eq,
+ p_invalid
+ };
+
+ // Return the punctuation id if type is t_punctuation and p_invalid
+ // otherwise.
+ //
+ punctuation_type
+ punctuation () const;
+
+ // Literals.
+ //
+public:
+ std::string const&
+ literal () const;
+
+ // C-tors.
+ //
+public:
+ // EOS and punctuations.
+ //
+ sql_token ();
+ sql_token (punctuation_type p);
+
+ // Identifier and literals.
+ //
+ sql_token (token_type t, std::string const& s);
+
+private:
+ token_type type_;
+ punctuation_type punctuation_;
+ std::string str_;
+};
+
+#include <odb/sql-token.ixx>
+
+#endif // ODB_SQL_TOKEN_HXX
diff --git a/odb/sql-token.ixx b/odb/sql-token.ixx
new file mode 100644
index 0000000..43f522f
--- /dev/null
+++ b/odb/sql-token.ixx
@@ -0,0 +1,46 @@
+// file : odb/sql-token.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+inline sql_token::token_type sql_token::
+type () const
+{
+ return type_;
+}
+
+inline std::string const& sql_token::
+identifier () const
+{
+ return str_;
+}
+
+inline sql_token::punctuation_type sql_token::
+punctuation () const
+{
+ return type_ == t_punctuation ? punctuation_ : p_invalid;
+}
+
+inline std::string const& sql_token::
+literal () const
+{
+ return str_;
+}
+
+inline sql_token::
+sql_token ()
+ : type_ (t_eos)
+{
+}
+
+inline sql_token::
+sql_token (punctuation_type p)
+ : type_ (t_punctuation), punctuation_ (p)
+{
+}
+
+inline sql_token::
+sql_token (token_type t, std::string const& s)
+ : type_ (t), str_ (s)
+{
+}
diff --git a/odb/header.cxx b/odb/tracer/header.cxx
index 5b302af..c023e58 100644
--- a/odb/header.cxx
+++ b/odb/tracer/header.cxx
@@ -1,10 +1,10 @@
-// file : odb/header.cxx
+// file : odb/tracer/header.cxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
#include <odb/common.hxx>
-#include <odb/header.hxx>
+#include <odb/tracer/header.hxx>
namespace
{
@@ -97,16 +97,16 @@ namespace
<< "id (const object_type&);"
<< endl;
- // insert ()
+ // persist ()
//
os << "static void" << endl
- << "insert (database&, object_type&);"
+ << "persist (database&, object_type&);"
<< endl;
- // update ()
+ // store ()
//
os << "static void" << endl
- << "update (database&, object_type&);"
+ << "store (database&, object_type&);"
<< endl;
// erase ()
@@ -129,30 +129,33 @@ namespace
};
}
-void
-generate_header (context& ctx)
+namespace tracer
{
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- class_ c (ctx);
+ void
+ generate_header (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
- unit >> unit_defines >> ns;
- unit_defines >> c;
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
- traversal::defines ns_defines;
+ traversal::defines ns_defines;
- ns >> ns_defines >> ns;
- ns_defines >> c;
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
- ctx.os << "#include <odb/core.hxx>" << endl
- << "#include <odb/traits.hxx>" << endl
- << endl;
+ ctx.os << "#include <odb/core.hxx>" << endl
+ << "#include <odb/traits.hxx>" << endl
+ << endl;
- ctx.os << "namespace odb"
- << "{";
+ ctx.os << "namespace odb"
+ << "{";
- unit.dispatch (ctx.unit);
+ unit.dispatch (ctx.unit);
- ctx.os << "}";
+ ctx.os << "}";
+ }
}
diff --git a/odb/header.hxx b/odb/tracer/header.hxx
index f7f3a34..0e67712 100644
--- a/odb/header.hxx
+++ b/odb/tracer/header.hxx
@@ -1,14 +1,17 @@
-// file : odb/header.hxx
+// file : odb/tracer/header.hxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-#ifndef ODB_HEADER_HXX
-#define ODB_HEADER_HXX
+#ifndef ODB_TRACER_HEADER_HXX
+#define ODB_TRACER_HEADER_HXX
#include <odb/context.hxx>
-void
-generate_header (context&);
+namespace tracer
+{
+ void
+ generate_header (context&);
+}
-#endif // ODB_HEADER_HXX
+#endif // ODB_TRACER_HEADER_HXX
diff --git a/odb/inline.cxx b/odb/tracer/inline.cxx
index bf0aec9..6beb8a8 100644
--- a/odb/inline.cxx
+++ b/odb/tracer/inline.cxx
@@ -1,10 +1,10 @@
-// file : odb/inline.cxx
+// file : odb/tracer/inline.cxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
#include <odb/common.hxx>
-#include <odb/inline.hxx>
+#include <odb/tracer/inline.hxx>
namespace
{
@@ -48,26 +48,29 @@ namespace
};
}
-void
-generate_inline (context& ctx)
+namespace tracer
{
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- class_ c (ctx);
+ void
+ generate_inline (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
- unit >> unit_defines >> ns;
- unit_defines >> c;
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
- traversal::defines ns_defines;
+ traversal::defines ns_defines;
- ns >> ns_defines >> ns;
- ns_defines >> c;
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
- ctx.os << "namespace odb"
- << "{";
+ ctx.os << "namespace odb"
+ << "{";
- unit.dispatch (ctx.unit);
+ unit.dispatch (ctx.unit);
- ctx.os << "}";
+ ctx.os << "}";
+ }
}
diff --git a/odb/inline.hxx b/odb/tracer/inline.hxx
index 77a2d56..2b01589 100644
--- a/odb/inline.hxx
+++ b/odb/tracer/inline.hxx
@@ -1,14 +1,17 @@
-// file : odb/inline.hxx
+// file : odb/tracer/inline.hxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-#ifndef ODB_INLINE_HXX
-#define ODB_INLINE_HXX
+#ifndef ODB_TRACER_INLINE_HXX
+#define ODB_TRACER_INLINE_HXX
#include <odb/context.hxx>
-void
-generate_inline (context&);
+namespace tracer
+{
+ void
+ generate_inline (context&);
+}
-#endif // ODB_INLINE_HXX
+#endif // ODB_TRACER_INLINE_HXX
diff --git a/odb/source.cxx b/odb/tracer/source.cxx
index 168dfae..e70adf1 100644
--- a/odb/source.cxx
+++ b/odb/tracer/source.cxx
@@ -1,10 +1,10 @@
-// file : odb/source.cxx
+// file : odb/tracer/source.cxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
#include <odb/common.hxx>
-#include <odb/source.hxx>
+#include <odb/tracer/source.hxx>
namespace
{
@@ -43,10 +43,10 @@ namespace
<< "return \"" << type << "\";"
<< "}";
- // insert ()
+ // persist ()
//
os << "void " << traits << "::" << endl
- << "insert (database&, object_type& obj)"
+ << "persist (database&, object_type& obj)"
<< "{"
<< "std::cout << \"insert \" << type_name () << \" id \" << " <<
"id (obj) << std::endl;"
@@ -55,10 +55,10 @@ namespace
<< "throw object_already_persistent ();"
<< "}";
- // update ()
+ // store ()
//
os << "void " << traits << "::" << endl
- << "update (database&, object_type& obj)"
+ << "store (database&, object_type& obj)"
<< "{"
<< "std::cout << \"update \" << type_name () << \" id \" << " <<
"id (obj) << std::endl;"
@@ -113,36 +113,35 @@ namespace
};
}
-void
-generate_source (context& ctx)
+namespace tracer
{
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- class_ c (ctx);
-
- unit >> unit_defines >> ns;
- unit_defines >> c;
+ void
+ generate_source (context& ctx)
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
- traversal::defines ns_defines;
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
- ns >> ns_defines >> ns;
- ns_defines >> c;
+ traversal::defines ns_defines;
- ctx.os << "#include <iostream>" << endl
- << endl;
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
- ctx.os << "#include <odb/exceptions.hxx>" << endl
- << endl;
+ ctx.os << "#include <iostream>" << endl
+ << endl;
- //ctx.os << "#include <odb/tracer/database.hxx>" << endl
- // << "#include <odb/tracer/exceptions.hxx>" << endl
- // << endl;
+ ctx.os << "#include <odb/exceptions.hxx>" << endl
+ << endl;
- ctx.os << "namespace odb"
- << "{";
+ ctx.os << "namespace odb"
+ << "{";
- unit.dispatch (ctx.unit);
+ unit.dispatch (ctx.unit);
- ctx.os << "}";
+ ctx.os << "}";
+ }
}
diff --git a/odb/source.hxx b/odb/tracer/source.hxx
index 2db3fe2..2c82f3a 100644
--- a/odb/source.hxx
+++ b/odb/tracer/source.hxx
@@ -1,14 +1,17 @@
-// file : odb/source.hxx
+// file : odb/tracer/source.hxx
// author : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-#ifndef ODB_SOURCE_HXX
-#define ODB_SOURCE_HXX
+#ifndef ODB_TRACER_SOURCE_HXX
+#define ODB_TRACER_SOURCE_HXX
#include <odb/context.hxx>
-void
-generate_source (context&);
+namespace tracer
+{
+ void
+ generate_source (context&);
+}
-#endif // ODB_SOURCE_HXX
+#endif // ODB_TRACER_SOURCE_HXX