summaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-09-04 11:22:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-09-04 11:22:07 +0200
commitc1877f84f3596f67245abe6658b08c050bd1e686 (patch)
tree57ae8ba5818a752abc763b1510b296a4a46d1ad4 /odb/relational
parente288ee241317773c77d954c8c286f53a963e7c19 (diff)
NULL handling improvements
Add support for specifying NULL-ness for types with built-in mapping. Handle Oracle [N]VARCHAR2 and SQLite FLOAT oddities using this mechanism instead of overriding it at the schema generation level. Also use the is_null argument that is passed to value_traits::init_image() to indicate whether the value can be NULL.
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/mssql/context.cxx48
-rw-r--r--odb/relational/mysql/context.cxx44
-rw-r--r--odb/relational/oracle/context.cxx46
-rw-r--r--odb/relational/oracle/schema.cxx44
-rw-r--r--odb/relational/pgsql/context.cxx44
-rw-r--r--odb/relational/source.hxx6
-rw-r--r--odb/relational/sqlite/context.cxx42
7 files changed, 124 insertions, 150 deletions
diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx
index efd8f2f..df6d6fc 100644
--- a/odb/relational/mssql/context.cxx
+++ b/odb/relational/mssql/context.cxx
@@ -20,43 +20,44 @@ namespace relational
{
struct type_map_entry
{
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
+ char const* const cxx_type;
+ char const* const db_type;
+ char const* const db_id_type;
+ bool const null;
};
type_map_entry type_map[] =
{
- {"bool", "BIT", 0},
+ {"bool", "BIT", 0, false},
- {"char", "TINYINT", 0},
- {"signed char", "TINYINT", 0},
- {"unsigned char", "TINYINT", 0},
+ {"char", "TINYINT", 0, false},
+ {"signed char", "TINYINT", 0, false},
+ {"unsigned char", "TINYINT", 0, false},
- {"short int", "SMALLINT", 0},
- {"short unsigned int", "SMALLINT", 0},
+ {"short int", "SMALLINT", 0, false},
+ {"short unsigned int", "SMALLINT", 0, false},
- {"int", "INT", 0},
- {"unsigned int", "INT", 0},
+ {"int", "INT", 0, false},
+ {"unsigned int", "INT", 0, false},
- {"long int", "BIGINT", 0},
- {"long unsigned int", "BIGINT", 0},
+ {"long int", "BIGINT", 0, false},
+ {"long unsigned int", "BIGINT", 0, false},
- {"long long int", "BIGINT", 0},
- {"long long unsigned int", "BIGINT", 0},
+ {"long long int", "BIGINT", 0, false},
+ {"long long unsigned int", "BIGINT", 0, false},
- {"float", "REAL", 0},
- {"double", "FLOAT", 0},
+ {"float", "REAL", 0, false},
+ {"double", "FLOAT", 0, false},
- {"::std::string", "VARCHAR(512)", "VARCHAR(256)"},
- {"::std::wstring", "NVARCHAR(512)", "NVARCHAR(256)"},
+ {"::std::string", "VARCHAR(512)", "VARCHAR(256)", false},
+ {"::std::wstring", "NVARCHAR(512)", "NVARCHAR(256)", false},
- {"::size_t", "BIGINT", 0},
- {"::std::size_t", "BIGINT", 0},
+ {"::size_t", "BIGINT", 0, false},
+ {"::std::size_t", "BIGINT", 0, false},
// Windows GUID/UUID (typedef struct _GUID {...} GUID, UUID;).
//
- {"::_GUID", "UNIQUEIDENTIFIER", 0}
+ {"::_GUID", "UNIQUEIDENTIFIER", 0, false}
};
}
@@ -97,7 +98,8 @@ namespace relational
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));
+ db_type_type (
+ e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
data_->type_map_.insert (v);
}
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index 1e44b34..8bf700e 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -21,38 +21,39 @@ namespace relational
{
struct type_map_entry
{
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
+ char const* const cxx_type;
+ char const* const db_type;
+ char const* const db_id_type;
+ bool const null;
};
type_map_entry type_map[] =
{
- {"bool", "TINYINT(1)", 0},
+ {"bool", "TINYINT(1)", 0, false},
- {"char", "TINYINT", 0},
- {"signed char", "TINYINT", 0},
- {"unsigned char", "TINYINT UNSIGNED", 0},
+ {"char", "TINYINT", 0, false},
+ {"signed char", "TINYINT", 0, false},
+ {"unsigned char", "TINYINT UNSIGNED", 0, false},
- {"short int", "SMALLINT", 0},
- {"short unsigned int", "SMALLINT UNSIGNED", 0},
+ {"short int", "SMALLINT", 0, false},
+ {"short unsigned int", "SMALLINT UNSIGNED", 0, false},
- {"int", "INT", 0},
- {"unsigned int", "INT UNSIGNED", 0},
+ {"int", "INT", 0, false},
+ {"unsigned int", "INT UNSIGNED", 0, false},
- {"long int", "BIGINT", 0},
- {"long unsigned int", "BIGINT UNSIGNED", 0},
+ {"long int", "BIGINT", 0, false},
+ {"long unsigned int", "BIGINT UNSIGNED", 0, false},
- {"long long int", "BIGINT", 0},
- {"long long unsigned int", "BIGINT UNSIGNED", 0},
+ {"long long int", "BIGINT", 0, false},
+ {"long long unsigned int", "BIGINT UNSIGNED", 0, false},
- {"float", "FLOAT", 0},
- {"double", "DOUBLE", 0},
+ {"float", "FLOAT", 0, false},
+ {"double", "DOUBLE", 0, false},
- {"::std::string", "TEXT", "VARCHAR(255)"},
+ {"::std::string", "TEXT", "VARCHAR(255)", false},
- {"::size_t", "BIGINT UNSIGNED", 0},
- {"::std::size_t", "BIGINT UNSIGNED", 0}
+ {"::size_t", "BIGINT UNSIGNED", 0, false},
+ {"::std::size_t", "BIGINT UNSIGNED", 0, false}
};
}
@@ -94,7 +95,8 @@ namespace relational
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));
+ db_type_type (
+ e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
data_->type_map_.insert (v);
}
diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx
index 01b690a..4ba8659 100644
--- a/odb/relational/oracle/context.cxx
+++ b/odb/relational/oracle/context.cxx
@@ -20,38 +20,41 @@ namespace relational
{
struct type_map_entry
{
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
+ char const* const cxx_type;
+ char const* const db_type;
+ char const* const db_id_type;
+ bool const null;
};
type_map_entry type_map[] =
{
- {"bool", "NUMBER(1)", 0},
+ {"bool", "NUMBER(1)", 0, false},
- {"char", "NUMBER(3)", 0},
- {"signed char", "NUMBER(3)", 0},
- {"unsigned char", "NUMBER(3)", 0},
+ {"char", "NUMBER(3)", 0, false},
+ {"signed char", "NUMBER(3)", 0, false},
+ {"unsigned char", "NUMBER(3)", 0, false},
- {"short int", "NUMBER(5)", 0},
- {"short unsigned int", "NUMBER(5)", 0},
+ {"short int", "NUMBER(5)", 0, false},
+ {"short unsigned int", "NUMBER(5)", 0, false},
- {"int", "NUMBER(10)", 0},
- {"unsigned int", "NUMBER(10)", 0},
+ {"int", "NUMBER(10)", 0, false},
+ {"unsigned int", "NUMBER(10)", 0, false},
- {"long int", "NUMBER(19)", 0},
- {"long unsigned int", "NUMBER(20)", 0},
+ {"long int", "NUMBER(19)", 0, false},
+ {"long unsigned int", "NUMBER(20)", 0, false},
- {"long long int", "NUMBER(19)", 0},
- {"long long unsigned int", "NUMBER(20)", 0},
+ {"long long int", "NUMBER(19)", 0, false},
+ {"long long unsigned int", "NUMBER(20)", 0, false},
- {"float", "BINARY_FLOAT", 0},
- {"double", "BINARY_DOUBLE", 0},
+ {"float", "BINARY_FLOAT", 0, false},
+ {"double", "BINARY_DOUBLE", 0, false},
- {"::std::string", "VARCHAR2(512)", 0},
+ // Oracle treats empty VARCHAR2 (and NVARCHAR2) strings as NULL.
+ //
+ {"::std::string", "VARCHAR2(512)", 0, true},
- {"::size_t", "NUMBER(20)", 0},
- {"::std::size_t", "NUMBER(20)", 0}
+ {"::size_t", "NUMBER(20)", 0, false},
+ {"::std::size_t", "NUMBER(20)", 0, false}
};
}
@@ -92,7 +95,8 @@ namespace relational
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));
+ db_type_type (
+ e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
data_->type_map_.insert (v);
}
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx
index 29c1130..f07e0d6 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/relational/oracle/schema.cxx
@@ -159,50 +159,6 @@ namespace relational
};
entry<create_table> create_table_;
- struct create_column: relational::create_column, context
- {
- create_column (base const& x): base (x) {}
-
- virtual void
- null (sema_rel::column& c)
- {
- // Oracle interprets empty VARCHAR2 and NVARCHAR2 strings as
- // NULL. As an empty string is valid within the C++ context,
- // VARCHAR2 and NVARCHAR2 columns are always specified as
- // nullable, except when are a part of a primary key.
- //
- if (!c.null ())
- {
- // This should never fail since we have already parsed this.
- //
- sql_type const& t (parse_sql_type (c.type ()));
-
- if (t.type == sql_type::VARCHAR2 || t.type == sql_type::NVARCHAR2)
- {
- // See if this column is a part of a primary key.
- //
- bool pk (false);
-
- for (sema_rel::column::contained_iterator i (
- c.contained_begin ()); i != c.contained_end (); ++i)
- {
- if (i->key ().is_a<sema_rel::primary_key> ())
- {
- pk = true;
- break;
- }
- }
-
- if (!pk)
- return;
- }
- }
-
- base::null (c);
- }
- };
- entry<create_column> create_column_;
-
struct create_foreign_key: relational::create_foreign_key, context
{
create_foreign_key (schema_format f, relational::create_table& ct)
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index bed0d1a..391c65e 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -21,38 +21,39 @@ namespace relational
{
struct type_map_entry
{
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
+ char const* const cxx_type;
+ char const* const db_type;
+ char const* const db_id_type;
+ bool const null;
};
type_map_entry type_map[] =
{
- {"bool", "BOOLEAN", 0},
+ {"bool", "BOOLEAN", 0, false},
- {"char", "SMALLINT", 0},
- {"signed char", "SMALLINT", 0},
- {"unsigned char", "SMALLINT", 0},
+ {"char", "SMALLINT", 0, false},
+ {"signed char", "SMALLINT", 0, false},
+ {"unsigned char", "SMALLINT", 0, false},
- {"short int", "SMALLINT", 0},
- {"short unsigned int", "SMALLINT", 0},
+ {"short int", "SMALLINT", 0, false},
+ {"short unsigned int", "SMALLINT", 0, false},
- {"int", "INTEGER", 0},
- {"unsigned int", "INTEGER", 0},
+ {"int", "INTEGER", 0, false},
+ {"unsigned int", "INTEGER", 0, false},
- {"long int", "BIGINT", 0},
- {"long unsigned int", "BIGINT", 0},
+ {"long int", "BIGINT", 0, false},
+ {"long unsigned int", "BIGINT", 0, false},
- {"long long int", "BIGINT", 0},
- {"long long unsigned int", "BIGINT", 0},
+ {"long long int", "BIGINT", 0, false},
+ {"long long unsigned int", "BIGINT", 0, false},
- {"float", "REAL", 0},
- {"double", "DOUBLE PRECISION", 0},
+ {"float", "REAL", 0, false},
+ {"double", "DOUBLE PRECISION", 0, false},
- {"::std::string", "TEXT", 0},
+ {"::std::string", "TEXT", 0, false},
- {"::size_t", "BIGINT", 0},
- {"::std::size_t", "BIGINT", 0}
+ {"::size_t", "BIGINT", 0, false},
+ {"::std::size_t", "BIGINT", 0, false}
};
}
@@ -94,7 +95,8 @@ namespace relational
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));
+ db_type_type (
+ e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
data_->type_map_.insert (v);
}
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 3ad463b..21954e0 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1298,7 +1298,11 @@ namespace relational
else
{
type = mi.fq_type ();
- os << "bool is_null;";
+
+ // Indicate to the value_traits whether this column can be NULL.
+ //
+ os << "bool is_null (" <<
+ (null (mi.m, key_prefix_) ? "true" : "false") << ");";
}
if (comp)
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index faaa3b5..52c7751 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -22,35 +22,38 @@ namespace relational
{
struct type_map_entry
{
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
+ char const* const cxx_type;
+ char const* const db_type;
+ char const* const db_id_type;
+ bool const null;
};
type_map_entry type_map[] =
{
- {"bool", "INTEGER", 0},
+ {"bool", "INTEGER", 0, false},
- {"char", "INTEGER", 0},
- {"signed char", "INTEGER", 0},
- {"unsigned char", "INTEGER", 0},
+ {"char", "INTEGER", 0, false},
+ {"signed char", "INTEGER", 0, false},
+ {"unsigned char", "INTEGER", 0, false},
- {"short int", "INTEGER", 0},
- {"short unsigned int", "INTEGER", 0},
+ {"short int", "INTEGER", 0, false},
+ {"short unsigned int", "INTEGER", 0, false},
- {"int", "INTEGER", 0},
- {"unsigned int", "INTEGER", 0},
+ {"int", "INTEGER", 0, false},
+ {"unsigned int", "INTEGER", 0, false},
- {"long int", "INTEGER", 0},
- {"long unsigned int", "INTEGER", 0},
+ {"long int", "INTEGER", 0, false},
+ {"long unsigned int", "INTEGER", 0, false},
- {"long long int", "INTEGER", 0},
- {"long long unsigned int", "INTEGER", 0},
+ {"long long int", "INTEGER", 0, false},
+ {"long long unsigned int", "INTEGER", 0, false},
- {"float", "REAL", 0},
- {"double", "REAL", 0},
+ // SQLite stores NaN as NULL.
+ //
+ {"float", "REAL", 0, true},
+ {"double", "REAL", 0, true},
- {"::std::string", "TEXT", 0}
+ {"::std::string", "TEXT", 0, false}
};
}
@@ -92,7 +95,8 @@ namespace relational
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));
+ db_type_type (
+ e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
data_->type_map_.insert (v);
}