aboutsummaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-07-19 13:42:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-07-19 13:42:18 +0200
commit73c98a67ef4ed605cf69e0d212934c4dc1f3eb8e (patch)
tree8645cd8d06f218ff5d945b1b3b94a58a127753c4 /odb/relational
parent12d0d9bbd0f5b7295c50fd5b223e538afe1abbf7 (diff)
New design for NULL semantics
Now, instead of being specified as part of the SQL type with the type pragma, there are separate null and not_null pragmas. The not_null pragma was used to control NULL-ness of object pointers. Now the two pragmas are used consistently for object pointers and simple values (and in the future will work for composite values and containers).
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/mysql/context.cxx10
-rw-r--r--odb/relational/mysql/context.hxx5
-rw-r--r--odb/relational/mysql/schema.cxx18
-rw-r--r--odb/relational/mysql/source.cxx4
-rw-r--r--odb/relational/pgsql/context.cxx12
-rw-r--r--odb/relational/pgsql/context.hxx5
-rw-r--r--odb/relational/pgsql/source.cxx4
-rw-r--r--odb/relational/schema.hxx8
-rw-r--r--odb/relational/sqlite/context.cxx12
-rw-r--r--odb/relational/sqlite/context.hxx6
-rw-r--r--odb/relational/sqlite/source.cxx4
-rw-r--r--odb/relational/type-processor.cxx93
12 files changed, 110 insertions, 71 deletions
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index e9446c2..431470a 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -234,12 +234,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -290,9 +287,6 @@ namespace relational
if (e->unsigned_ ())
r += " UNSIGNED";
}
-
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
}
return r;
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
index 019b878..00ebe57 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/relational/mysql/context.hxx
@@ -97,10 +97,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&,
- semantics::names*,
- semantics::context&,
- column_type_flags);
+ database_type_impl (semantics::type&, semantics::names*, bool);
public:
virtual
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
index 0b44c53..3848c75 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/relational/mysql/schema.cxx
@@ -37,11 +37,27 @@ namespace relational
}
};
- struct object_columns: relational::object_columns
+ struct object_columns: relational::object_columns, context
{
object_columns (base const& x): base (x) {}
virtual void
+ null (semantics::data_member& m)
+ {
+ if (!context::null (m, prefix_))
+ os << " NOT NULL";
+ else
+ {
+ // MySQL TIMESTAMP is by default NOT NULL. If we want it
+ // to contain NULL values, we need to explicitly declare
+ // the column as NULL.
+ //
+ if (column_sql_type (m, prefix_).type == sql_type::TIMESTAMP)
+ os << " NULL";
+ }
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
base::constraints (m);
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
index 17bffdc..d3b4129 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/relational/mysql/source.cxx
@@ -588,7 +588,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -786,7 +786,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 5a6b158..6c6c5a0 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -211,12 +211,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -224,13 +221,8 @@ namespace relational
using semantics::enum_;
if (t.is_a<semantics::enum_> ())
- {
r = "INTEGER";
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
- }
-
return r;
}
diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx
index 66d9318..a4fbc00 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/relational/pgsql/context.hxx
@@ -85,10 +85,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f);
+ database_type_impl (semantics::type& t, semantics::names* hint, bool);
public:
virtual
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 0ed6890..3b7664d 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -502,7 +502,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -674,7 +674,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index b9243df..9d64276 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -189,6 +189,7 @@ namespace relational
os << " " << quote_id (name) << " ";
type (m);
+ null (m);
constraints (m);
reference (m);
@@ -202,6 +203,13 @@ namespace relational
}
virtual void
+ null (semantics::data_member& m)
+ {
+ if (!context::null (m, prefix_))
+ os << " NOT NULL";
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
if (m.count ("id"))
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index b026822..4d00621 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -197,12 +197,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -210,13 +207,8 @@ namespace relational
using semantics::enum_;
if (t.is_a<semantics::enum_> ())
- {
r = "INTEGER";
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
- }
-
return r;
}
diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx
index c625069..b5c3d85 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/relational/sqlite/context.hxx
@@ -49,10 +49,8 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&,
- semantics::names*,
- semantics::context&,
- column_type_flags);
+ database_type_impl (semantics::type&, semantics::names*, bool);
+
public:
virtual
~context ();
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 35a3246..6a99fc8 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -321,7 +321,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -437,7 +437,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/type-processor.cxx b/odb/relational/type-processor.cxx
index f7b0b2a..0f1c1d2 100644
--- a/odb/relational/type-processor.cxx
+++ b/odb/relational/type-processor.cxx
@@ -131,14 +131,7 @@ namespace relational
type = idt.get<string> ("type");
if (type.empty ())
- {
- column_type_flags f (ctf_none);
-
- if (null_pointer (m))
- f |= ctf_default_null;
-
- type = database_type (idt, id.belongs ().hint (), id, f);
- }
+ type = database_type (idt, id.belongs ().hint (), true);
}
else
{
@@ -149,12 +142,22 @@ namespace relational
type = t.get<string> ("type");
if (type.empty ())
- type = database_type (t, m.belongs ().hint (), m, ctf_none);
+ type = database_type (t, m.belongs ().hint (), m.count ("id"));
}
if (!type.empty ())
{
m.set ("column-type", type);
+
+ // Issue a warning if we are relaxing null-ness.
+ //
+ if (m.count ("null") && m.type ().count ("not-null"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " warning: data member declared null while its type is "
+ << "declared not null" << endl;
+ }
+
return;
}
@@ -221,14 +224,7 @@ namespace relational
type = idt.get<string> ("type");
if (type.empty ())
- {
- column_type_flags f (ctf_none);
-
- if (null_pointer (m, prefix))
- f |= ctf_default_null;
-
- type = database_type (idt, id.belongs ().hint (), id, f);
- }
+ type = database_type (idt, id.belongs ().hint (), true);
}
else
{
@@ -236,7 +232,7 @@ namespace relational
type = t.get<string> ("type");
if (type.empty ())
- type = database_type (t, hint, m, ctf_none);
+ type = database_type (t, hint, false);
}
if (!type.empty ())
@@ -366,6 +362,10 @@ namespace relational
t.set ("container-kind", ck);
+ // Mark id column as not null.
+ //
+ t.set ("id-not-null", string ());
+
// Get the value type.
//
try
@@ -404,6 +404,33 @@ namespace relational
t.set ("value-tree-type", vt);
t.set ("value-tree-hint", vh);
+ // If we have a set container, automatically mark the value
+ // column as not null. If we already have an explicit null for
+ // this column, issue an error.
+ //
+ if (ck == ck_set)
+ {
+ if (t.count ("value-null"))
+ {
+ os << t.file () << ":" << t.line () << ":" << t.column () << ":"
+ << " error: set container cannot contain null values" << endl;
+
+ throw generation_failed ();
+ }
+ else
+ t.set ("value-not-null", string ());
+ }
+
+ // Issue a warning if we are relaxing null-ness in the
+ // container type.
+ //
+ if (t.count ("value-null") && vt->count ("not-null"))
+ {
+ os << t.file () << ":" << t.line () << ":" << t.column () << ":"
+ << " warning: container value declared null while its type "
+ << "is declared not null" << endl;
+ }
+
// Get the index type for ordered containers.
//
if (ck == ck_ordered)
@@ -443,6 +470,7 @@ namespace relational
t.set ("index-tree-type", it);
t.set ("index-tree-hint", ih);
+ t.set ("index-not-null", string ());
}
// Get the key type for maps.
@@ -484,6 +512,7 @@ namespace relational
t.set ("key-tree-type", kt);
t.set ("key-tree-hint", kh);
+ t.set ("key-not-null", string ());
}
}
@@ -507,6 +536,28 @@ namespace relational
if (ck == ck_ordered && m.count ("value-inverse"))
m.set ("unordered", string ()); // Keep compatible with pragma.
+ // Issue an error if we have a null column in a set container.
+ // This can only happen if the value is declared as null in
+ // the member.
+ //
+ if (ck == ck_set && m.count ("value-null"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: set container cannot contain null values" << endl;
+
+ throw generation_failed ();
+ }
+
+ // Issue a warning if we are relaxing null-ness in the member.
+ //
+ if (m.count ("value-null") &&
+ (t.count ("value-not-null") || vt->count ("not-null")))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " warning: container value declared null while the container "
+ << "type or value type declares it as not null" << endl;
+ }
+
return true;
}
@@ -729,12 +780,6 @@ namespace relational
throw generation_failed ();
}
- if (m.count ("not-null") && !kp.empty ())
- {
- m.remove ("not-null");
- m.set (kp + "-not-null", string ()); // Keep compatible with pragma.
- }
-
// See if this is the inverse side of a bidirectional relationship.
// If so, then resolve the member and cache it in the context.
//