aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-06-20 19:48:54 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-07-05 14:43:38 +0200
commit4f488f4ea93849cc5b2178c89cd365e2ca1f83f4 (patch)
treef55e6499af779535c7a025ae292a17977a1d0b56
parentb5ea1bff659db653a9ede58bd8989f83a318bc22 (diff)
Add PostgreSQL source generation implementation
-rw-r--r--odb/makefile3
-rw-r--r--odb/relational/pgsql/source.cxx801
2 files changed, 803 insertions, 1 deletions
diff --git a/odb/makefile b/odb/makefile
index d40c5b6..24c83e2 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -57,7 +57,8 @@ cxx_ptun += \
relational/pgsql/common.cxx \
relational/pgsql/context.cxx \
relational/pgsql/header.cxx \
-relational/pgsql/schema.cxx
+relational/pgsql/schema.cxx \
+relational/pgsql/source.cxx
# Relational/SQLite
#
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
new file mode 100644
index 0000000..6625f84
--- /dev/null
+++ b/odb/relational/pgsql/source.cxx
@@ -0,0 +1,801 @@
+// file : odb/relational/pgsql/source.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <sstream>
+
+#include <odb/relational/source.hxx>
+
+#include <odb/relational/pgsql/common.hxx>
+#include <odb/relational/pgsql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace pgsql
+ {
+ namespace source
+ {
+ namespace relational = relational::source;
+
+ struct query_parameters: context
+ {
+ query_parameters ()
+ : i_ (0)
+ {
+ }
+
+ virtual string
+ next ()
+ {
+ ostringstream ss ("$");
+ ss << ++i_;
+
+ return ss.str ();
+ }
+
+ private:
+ size_t i_;
+ };
+
+ namespace
+ {
+ const char* integer_buffer_types[] =
+ {
+ "pgsql::bind::boolean",
+ "pgsql::bind::smallint",
+ "pgsql::bind::integer",
+ "pgsql::bind::bigint",
+ };
+
+ const char* float_buffer_types[] =
+ {
+ "pgsql::bind::real",
+ "pgsql::bind::double_",
+ };
+
+ // @@ Complete once date-time format is known.
+ //
+ // const char* date_time_buffer_types[] =
+ // {
+ // };
+
+ const char* char_bin_buffer_types[] =
+ {
+ "pgsql::bind::text", // CHAR
+ "pgsql::bind::text", // VARCHAR
+ "pgsql::bind::text", // TEXT
+ "pgsql::bind::bytea", // BYTEA
+ };
+ }
+
+ //
+ // bind
+ //
+
+ struct bind_member: relational::bind_member, member_base
+ {
+ bind_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ ostringstream ostr;
+ ostr << "b[n]";
+ b = ostr.str ();
+
+ arg = arg_override_.empty () ? string ("i") : arg_override_;
+
+ if (var_override_.empty ())
+ {
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
+
+ if (inverse (mi.m, key_prefix_))
+ os << "if (out)"
+ << "{";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (var_override_.empty ())
+ {
+ if (semantics::class_* c = comp_value (mi.t))
+ os << "n += " << in_column_count (*c) << "UL;";
+ else
+ os << "n++;";
+
+ if (inverse (mi.m, key_prefix_))
+ os << "}";
+ else
+ os << endl;
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "composite_value_traits< " << mi.fq_type () <<
+ " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ }
+
+ virtual void
+ traverse_integer (member_info& mi)
+ {
+ os << b << ".type = " <<
+ integer_buffer_types[mi.st->type - sql_type::BOOLEAN] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_float (member_info& mi)
+ {
+ os << b << ".type = " <<
+ float_buffer_types[mi.st->type - sql_type::REAL] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_numeric (member_info& mi)
+ {
+ os << b << ".type = pgsql::bind::numeric;"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".capacity = " << endl
+ << arg << "." << mi.var << "value.capacity ();"
+ << b << ".size = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_date_time (member_info&)
+ {
+ // @@ Complete once date-time format is known.
+ //
+ }
+
+ virtual void
+ traverse_string (member_info& mi)
+ {
+ os << b << ".type = " <<
+ char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".capacity = " << endl
+ << arg << "." << mi.var << "value.capacity ();"
+ << b << ".size = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ os << b << ".type = pgsql::bind::bit;"
+ << b << ".buffer = " << arg << "." << mi.var << "value;"
+ << b << ".capacity = sizeof (" << endl
+ << arg << "." << mi.var << "value);"
+ << b << ".size = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_varbit (member_info& mi)
+ {
+ os << b << ".type = pgsql::bind::varbit;"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".capacity = " << endl
+ << arg << "." << mi.var << "value.capacity ();"
+ << b << ".size = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_uuid (member_info& mi)
+ {
+ os << b << ".type = pgsql::bind::uuid;"
+ << b << ".buffer = " << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ private:
+ string b;
+ string arg;
+ };
+ entry<bind_member> bind_member_;
+
+ //
+ // grow
+ //
+
+ struct grow_member: relational::grow_member, member_base
+ {
+ grow_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ ostringstream ostr;
+ ostr << "t[" << index_ << "UL]";
+ e = ostr.str ();
+
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (semantics::class_* c = comp_value (mi.t))
+ index_ += in_column_count (*c);
+ else
+ index_++;
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "if (composite_value_traits< " << mi.fq_type () <<
+ " >::grow (" << endl
+ << "i." << mi.var << "value, t + " << index_ << "UL))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_integer (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_numeric (member_info& mi)
+ {
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_date_time (member_info&)
+ {
+ // @@ Complete once date-time format is known.
+ //
+ }
+
+ 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_bit (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_varbit (member_info& mi)
+ {
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_uuid (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ private:
+ string e;
+ };
+ entry<grow_member> grow_member_;
+
+ //
+ // init image
+ //
+
+ struct init_image_member: relational::init_image_member, member_base
+ {
+ init_image_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x),
+ member_database_type_id_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ // Ignore containers (they get their own table) and inverse
+ // object pointers (they are not present in the 'in' binding).
+ //
+ if (container (mi.t) || inverse (mi.m, key_prefix_))
+ return false;
+
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+
+ if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
+ else
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
+ {
+ type = "obj_traits::id_type";
+ db_type_id = member_database_type_id_.database_type_id (mi.m);
+
+ // Handle NULL pointers and extract the id.
+ //
+ os << "{"
+ << "typedef object_traits< " << c->fq_name () <<
+ " > obj_traits;";
+
+ if (weak_pointer (mt))
+ {
+ os << "typedef pointer_traits< " << mi.fq_type () <<
+ " > wptr_traits;"
+ << "typedef pointer_traits< wptr_traits::" <<
+ "strong_pointer_type > ptr_traits;"
+ << endl
+ << "wptr_traits::strong_pointer_type sp (" <<
+ "wptr_traits::lock (" << member << "));";
+
+ member = "sp";
+ }
+ else
+ os << "typedef pointer_traits< " << mi.fq_type () <<
+ " > ptr_traits;"
+ << endl;
+
+ os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
+ << "if (!is_null)"
+ << "{"
+ << "const " << type << "& id (" << endl;
+
+ if (lazy_pointer (mt))
+ os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
+ member << ")";
+ else
+ os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
+
+ os << ");"
+ << endl;
+
+ member = "id";
+ }
+ else
+ {
+ type = mi.fq_type ();
+ db_type_id = member_database_type_id_.database_type_id (mi.m);
+
+ os << "{"
+ << "bool is_null;";
+ }
+
+ traits = "mysql::value_traits<\n "
+ + type + ",\n "
+ + db_type_id + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (!comp_value (mi.t))
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ if (object_pointer (member_type (mi.m, key_prefix_)))
+ {
+ os << "}";
+
+ if (!null_pointer (mi.m, key_prefix_))
+ os << "else" << endl
+ << "throw null_pointer ();";
+ }
+
+ os << "i." << mi.var << "null = is_null;"
+ << "}";
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "if (" << traits << "::init (i." << mi.var << "value, " <<
+ member << "))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ 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_numeric (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 = size;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_date_time (member_info&)
+ {
+ // @@ Complete once date-time format is known.
+ //
+ }
+
+ virtual void
+ traverse_string (member_info& mi)
+ {
+ 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 = size;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ 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 = size;";
+ }
+
+ virtual void
+ traverse_varbit (member_info& mi)
+ {
+ 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 = size;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_uuid (member_info& mi)
+ {
+ os << traits << "::set_image (" << endl
+ << "i." << mi.var << "value, is_null, " << member << ");";
+ }
+
+ private:
+ string type;
+ string db_type_id;
+ string member;
+ string traits;
+
+ member_database_type_id member_database_type_id_;
+ };
+ entry<init_image_member> init_image_member_;
+
+ //
+ // init value
+ //
+
+ struct init_value_member: relational::init_value_member, member_base
+ {
+ init_value_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x),
+ member_database_type_id_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+
+ if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
+ else
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
+ {
+ type = "obj_traits::id_type";
+ db_type_id = member_database_type_id_.database_type_id (mi.m);
+
+ // Handle NULL pointers and extract the id.
+ //
+ os << "{"
+ << "typedef object_traits< " << c->fq_name () <<
+ " > obj_traits;"
+ << "typedef pointer_traits< " << mi.fq_type () <<
+ " > ptr_traits;"
+ << endl
+ << "if (i." << mi.var << "null)" << endl;
+
+ if (null_pointer (mi.m, key_prefix_))
+ os << member << " = ptr_traits::pointer_type ();";
+ else
+ os << "throw null_pointer ();";
+
+ os << "else"
+ << "{"
+ << type << " id;";
+
+ member = "id";
+ }
+ else
+ {
+ type = mi.fq_type ();
+ db_type_id = member_database_type_id_.database_type_id (mi.m);
+ }
+
+ traits = "mysql::value_traits<\n "
+ + type + ",\n "
+ + db_type_id + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (comp_value (mi.t))
+ return;
+
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (object_pointer (mt))
+ {
+ member = member_override_.empty ()
+ ? "o." + mi.m.name ()
+ : member_override_;
+
+ if (lazy_pointer (mt))
+ os << member << " = ptr_traits::pointer_type (db, id);";
+ else
+ os << "// If a compiler error points to the line below, then" << endl
+ << "// it most likely means that a pointer used in a member" << endl
+ << "// cannot be initialized from an object pointer." << endl
+ << "//" << endl
+ << member << " = ptr_traits::pointer_type (" << endl
+ << "db.load< ptr_traits::element_type > (id));";
+
+ os << "}"
+ << "}";
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << traits << "::init (" << member << ", i." <<
+ mi.var << "value, db);"
+ << endl;
+ }
+
+ virtual void
+ 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_numeric (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&)
+ {
+ // @@ Complete once date-time format is known.
+ //
+ }
+
+ 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_bit (member_info& mi)
+ {
+ // Presented as byte.
+ //
+ 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_varbit (member_info& mi)
+ {
+ // Presented as bytea.
+ //
+ 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_uuid (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
+ << endl;
+ }
+
+ private:
+ string type;
+ string db_type_id;
+ string traits;
+ string member;
+
+ member_database_type_id member_database_type_id_;
+ };
+ entry<init_value_member> init_value_member_;
+
+ struct class_: relational::class_, context
+ {
+ class_ (base const& x): base (x) {}
+
+ virtual void
+ init_auto_id (semantics::data_member&, string const& im)
+ {
+ os << im << "value = 0;";
+ }
+ };
+ entry<class_> class_entry_;
+
+ }
+ }
+}