summaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-07-22 14:49:29 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-07-22 17:57:00 +0200
commit81ea37904e4959414b53b225b4b5e56e1b561bdc (patch)
tree6ae70d4adb9c0c3ed57679873de8061d5b9c5b19 /odb/relational
parent246b1557bf84082cc72ec2cbe089262b21c8bc97 (diff)
Add pragma for setting type's or member's default value
New pragma: default. New test: default.
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/mysql/schema.cxx79
-rw-r--r--odb/relational/pgsql/schema.cxx37
-rw-r--r--odb/relational/schema.cxx122
-rw-r--r--odb/relational/schema.hxx57
-rw-r--r--odb/relational/sqlite/schema.cxx26
5 files changed, 318 insertions, 3 deletions
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
index 3848c75..4a7171f 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/relational/mysql/schema.cxx
@@ -58,6 +58,85 @@ namespace relational
}
virtual void
+ default_bool (semantics::data_member&, bool v)
+ {
+ // MySQL has TRUE and FALSE as just aliases for 1 and 0. Still
+ // use them for self-documentation.
+ //
+ os << " DEFAULT " << (v ? "TRUE" : "FALSE");
+ }
+
+ virtual void
+ default_enum (semantics::data_member& m, tree en, string const& name)
+ {
+ // Make sure the column is mapped to an ENUM or integer type.
+ //
+ sql_type const& t (column_sql_type (m));
+
+ switch (t.type)
+ {
+ case sql_type::ENUM:
+ case sql_type::TINYINT:
+ case sql_type::SMALLINT:
+ case sql_type::MEDIUMINT:
+ case sql_type::INT:
+ case sql_type::BIGINT:
+ break;
+ default:
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: column with default value specified as C++ "
+ << "enumerator must map to MySQL ENUM or integer type"
+ << endl;
+
+ throw generation_failed ();
+ }
+ }
+
+ using semantics::enum_;
+ using semantics::enumerator;
+
+ enumerator& er (dynamic_cast<enumerator&> (*unit.find (en)));
+ enum_& e (er.enum_ ());
+
+ if (t.type == sql_type::ENUM)
+ {
+ // Assuming the enumerators in the C++ enum and MySQL ENUM are
+ // in the same order, calculate the poistion of the C++
+ // enumerator and use that as an index in the MySQL ENUM.
+ //
+ size_t pos (0);
+
+ for (enum_::enumerates_iterator i (e.enumerates_begin ()),
+ end (e.enumerates_end ()); i != end; ++i)
+ {
+ if (&i->enumerator () == &er)
+ break;
+
+ pos++;
+ }
+
+ if (pos < t.enumerators.size ())
+ os << " DEFAULT " << t.enumerators[pos];
+ else
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: unable to map C++ enumerator '" << name
+ << "' to MySQL ENUM value" << endl;
+
+ throw generation_failed ();
+ }
+ }
+ else
+ {
+ if (e.unsigned_ ())
+ os << " DEFAULT " << er.value ();
+ else
+ os << " DEFAULT " << static_cast<long long> (er.value ());
+ }
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
base::constraints (m);
diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx
index b7901e5..6530e82 100644
--- a/odb/relational/pgsql/schema.cxx
+++ b/odb/relational/pgsql/schema.cxx
@@ -77,6 +77,43 @@ namespace relational
}
virtual void
+ default_bool (semantics::data_member&, bool v)
+ {
+ os << " DEFAULT " << (v ? "TRUE" : "FALSE");
+ }
+
+ virtual void
+ default_enum (semantics::data_member& m, tree en, string const&)
+ {
+ // Make sure the column is mapped to an integer type.
+ //
+ switch (column_sql_type (m).type)
+ {
+ case sql_type::SMALLINT:
+ case sql_type::INTEGER:
+ case sql_type::BIGINT:
+ break;
+ default:
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: column with default value specified as C++ "
+ << "enumerator must map to PostgreSQL integer type" << endl;
+
+ throw generation_failed ();
+ }
+ }
+
+ using semantics::enumerator;
+
+ enumerator& e (dynamic_cast<enumerator&> (*unit.find (en)));
+
+ if (e.enum_ ().unsigned_ ())
+ os << " DEFAULT " << e.value ();
+ else
+ os << " DEFAULT " << static_cast<long long> (e.value ());
+ }
+
+ virtual void
reference (semantics::data_member&)
{
}
diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx
index 6acb6dc..a347d49 100644
--- a/odb/relational/schema.cxx
+++ b/odb/relational/schema.cxx
@@ -3,6 +3,12 @@
// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
+#include <cassert>
+#include <limits>
+#include <sstream>
+
#include <odb/emitter.hxx>
#include <odb/relational/schema.hxx>
@@ -14,6 +20,122 @@ namespace relational
{
namespace schema
{
+ // object_columns
+ //
+ void object_columns::
+ default_ (semantics::data_member& m)
+ {
+ string s;
+ tree n (0);
+
+ semantics::type& t (m.type ());
+
+ if (m.count ("default"))
+ {
+ s = m.get<string> ("default");
+
+ // Empty string is a default value override which means
+ // there is no default value.
+ //
+ if (s.empty ())
+ return;
+
+ if (m.count ("default-node"))
+ n = m.get<tree> ("default-node");
+ }
+ else if (t.count ("default"))
+ {
+ s = t.get<string> ("default");
+
+ if (s.empty ())
+ return;
+
+ if (t.count ("default-node"))
+ n = t.get<tree> ("default-node");
+ }
+ else
+ return; // No default value for this column.
+
+ // The first letter in the default value string identifies
+ // the type of the value. See pragma.cxx for details.
+ //
+ switch (s[0])
+ {
+ case 'n':
+ {
+ default_null (m);
+ break;
+ }
+ case 't':
+ case 'f':
+ {
+ default_bool (m, s[0] == 't');
+ break;
+ }
+ case '+':
+ case '-':
+ {
+ switch (TREE_CODE (n))
+ {
+ case INTEGER_CST:
+ {
+ HOST_WIDE_INT hwl (TREE_INT_CST_LOW (n));
+ HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (n));
+
+ unsigned long long l (hwl);
+ unsigned long long h (hwh);
+ unsigned short width (HOST_BITS_PER_WIDE_INT);
+
+ unsigned long long v ((h << width) + l);
+
+ default_integer (m, v, s[0] == '-');
+ break;
+ }
+ case REAL_CST:
+ {
+ double v;
+
+ REAL_VALUE_TYPE d (TREE_REAL_CST (n));
+
+ if (REAL_VALUE_ISINF (d))
+ v = numeric_limits<double>::infinity ();
+ else if (REAL_VALUE_ISNAN (d))
+ v = numeric_limits<double>::quiet_NaN ();
+ else
+ {
+ char tmp[256];
+ real_to_decimal (tmp, &d, sizeof (tmp), 0, true);
+ istringstream is (tmp);
+ is >> v;
+ }
+
+ if (s[0] == '-')
+ v = -v;
+
+ default_float (m, v);
+ break;
+ }
+ default:
+ assert (false);
+ }
+ break;
+ }
+
+ case 's':
+ {
+ default_string (m, string (s, 1, string::npos));
+ break;
+ }
+ case 'e':
+ {
+ default_enum (m, n, string (s, 1, string::npos));
+ break;
+ }
+ default:
+ assert (false);
+ }
+ }
+
struct schema_emitter: emitter, context
{
virtual void
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index b218c2b..6ada960 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -190,8 +190,11 @@ namespace relational
type (m);
null (m);
- constraints (m);
- reference (m);
+
+ // An id member cannot have a default value.
+ //
+ if (!m.count ("id"))
+ default_ (m);
// If we have options, add them.
//
@@ -200,6 +203,9 @@ namespace relational
if (!o.empty ())
os << " " << o;
+ constraints (m);
+ reference (m);
+
return true;
}
@@ -217,6 +223,49 @@ namespace relational
}
virtual void
+ default_null (semantics::data_member&)
+ {
+ os << " DEFAULT NULL";
+ }
+
+ virtual void
+ default_bool (semantics::data_member&, bool v)
+ {
+ // Most databases do not support boolean literals. Those that
+ // do should override this.
+ //
+ os << " DEFAULT " << (v ? "1" : "0");
+ }
+
+ virtual void
+ default_integer (semantics::data_member&, unsigned long long v, bool neg)
+ {
+ os << " DEFAULT " << (neg ? "-" : "") << v;
+ }
+
+ virtual void
+ default_float (semantics::data_member&, double v)
+ {
+ os << " DEFAULT " << v;
+ }
+
+ virtual void
+ default_string (semantics::data_member&, string const& v)
+ {
+ os << " DEFAULT " << quote_string (v);
+ }
+
+ virtual void
+ default_enum (semantics::data_member&,
+ tree /*enumerator*/,
+ string const& /*name*/)
+ {
+ // Has to be implemented by the database-specific override.
+ //
+ assert (false);
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
if (m.count ("id"))
@@ -234,6 +283,10 @@ namespace relational
}
protected:
+ void
+ default_ (semantics::data_member&);
+
+ protected:
string prefix_;
};
diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx
index 195a71e..253772d 100644
--- a/odb/relational/sqlite/schema.cxx
+++ b/odb/relational/sqlite/schema.cxx
@@ -19,11 +19,35 @@ namespace relational
//
// Create.
//
- struct object_columns: relational::object_columns
+ struct object_columns: relational::object_columns, context
{
object_columns (base const& x): base (x) {}
virtual void
+ default_enum (semantics::data_member& m, tree en, string const&)
+ {
+ // Make sure the column is mapped to INTEGER.
+ //
+ if (column_sql_type (m).type != sql_type::INTEGER)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: column with default value specified as C++ "
+ << "enumerator must map to SQLite INTEGER" << endl;
+
+ throw generation_failed ();
+ }
+
+ using semantics::enumerator;
+
+ enumerator& e (dynamic_cast<enumerator&> (*unit.find (en)));
+
+ if (e.enum_ ().unsigned_ ())
+ os << " DEFAULT " << e.value ();
+ else
+ os << " DEFAULT " << static_cast<long long> (e.value ());
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
base::constraints (m);