aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-01-24 15:10:22 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-01-24 15:10:22 +0200
commitce03afff5ef2e8da677def73079864c31c6618d8 (patch)
treef0dd5ace26fcfb5c16dee9930a70cf274a80cfc0
parent7c9d4543838490670b632c7049bea53d58d78487 (diff)
Add support for mapping char[N] to CHAR/VARCHAR database types
Also improve query support for arrays (decaying).
-rw-r--r--odb/context.cxx23
-rw-r--r--odb/context.hxx12
-rw-r--r--odb/relational/mssql/context.cxx47
-rw-r--r--odb/relational/mssql/context.hxx2
-rw-r--r--odb/relational/mysql/context.cxx37
-rw-r--r--odb/relational/mysql/context.hxx2
-rw-r--r--odb/relational/oracle/context.cxx51
-rw-r--r--odb/relational/oracle/context.hxx2
-rw-r--r--odb/relational/pgsql/context.cxx39
-rw-r--r--odb/relational/pgsql/context.hxx2
-rw-r--r--odb/relational/processor.cxx23
-rw-r--r--odb/relational/sqlite/context.cxx25
-rw-r--r--odb/relational/sqlite/context.hxx2
13 files changed, 222 insertions, 45 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 46116f6..515e9a8 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -720,13 +720,6 @@ null (semantics::data_member& m) const
}
else
pt = &t;
-
- // See if this is one of the types with built-in mapping.
- //
- type_map_type::const_iterator i (data_->type_map_.find (*pt, hint));
-
- if (i != data_->type_map_.end ())
- return i->second.null;
}
}
@@ -811,13 +804,6 @@ null (semantics::data_member& m, string const& kp) const
}
else
pt = &t;
-
- // See if this is one of the types with built-in mapping.
- //
- type_map_type::const_iterator i (data_->type_map_.find (*pt, hint));
-
- if (i != data_->type_map_.end ())
- return i->second.null;
}
}
}
@@ -1749,12 +1735,19 @@ find (semantics::type& t, semantics::names* hint)
}
string context::
-database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
type_map_type::const_iterator i (data_->type_map_.find (t, hint));
if (i != data_->type_map_.end ())
+ {
+ if (null != 0)
+ *null = i->second.null;
return id ? i->second.id_type : i->second.type;
+ }
else
return string ();
}
diff --git a/odb/context.hxx b/odb/context.hxx
index 83d0747..aa604e4 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -1088,19 +1088,23 @@ public:
//
protected:
// Return empty string if there is no mapping. The type passed is
- // already cvr-unqualified.
+ // already cvr-unqualified. The null out argument indicates whether
+ // the column should allow NULL values by default.
//
string
- database_type (semantics::type& t, semantics::names* hint, bool id)
+ database_type (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null = 0)
{
- return current ().database_type_impl (t, hint, id);
+ return current ().database_type_impl (t, hint, id, null);
}
// The default implementation uses the type map (populated by the database-
// specific context implementation) to come up with a mapping.
//
virtual string
- database_type_impl (semantics::type&, semantics::names*, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
typedef context root_context;
diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx
index c64ae57..d615a1c 100644
--- a/odb/relational/mssql/context.cxx
+++ b/odb/relational/mssql/context.cxx
@@ -30,7 +30,8 @@ namespace relational
{
{"bool", "BIT", 0, false},
- {"char", "TINYINT", 0, false},
+ {"char", "CHAR(1)", 0, false},
+ {"wchar_t", "NCHAR(1)", 0, false},
{"signed char", "TINYINT", 0, false},
{"unsigned char", "TINYINT", 0, false},
@@ -145,17 +146,57 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+ database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
- string r (base_context::database_type_impl (t, hint, id));
+ string r (base_context::database_type_impl (t, hint, id, null));
if (!r.empty ())
return r;
using semantics::enum_;
+ using semantics::array;
+ // Enum mapping.
+ //
if (t.is_a<semantics::enum_> ())
+ {
r = "INT";
+ }
+ // char[N] mapping.
+ //
+ else if (array* a = dynamic_cast<array*> (&t))
+ {
+ semantics::type& bt (a->base_type ());
+ bool c (bt.is_a<semantics::fund_char> ());
+
+ if (c || bt.is_a<semantics::fund_wchar> ())
+ {
+ unsigned long long n (a->size ());
+
+ if (n == 0)
+ return r;
+ if (n == 1)
+ r = c ? "CHAR(" : "NCHAR(";
+ else
+ {
+ r = c ? "VARCHAR(" : "NVARCHAR(";
+ n--;
+ }
+
+ if (n > (c ? 8000 : 4000))
+ r += "max)";
+ else
+ {
+ ostringstream ostr;
+ ostr << n;
+ r += ostr.str ();
+ r += ')';
+ }
+ }
+ }
return r;
}
diff --git a/odb/relational/mssql/context.hxx b/odb/relational/mssql/context.hxx
index ea451dc..e845b86 100644
--- a/odb/relational/mssql/context.hxx
+++ b/odb/relational/mssql/context.hxx
@@ -127,7 +127,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&, semantics::names*, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
virtual
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index ba22733..4045f9c 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -31,7 +31,7 @@ namespace relational
{
{"bool", "TINYINT(1)", 0, false},
- {"char", "TINYINT", 0, false},
+ {"char", "CHAR(1)", 0, false},
{"signed char", "TINYINT", 0, false},
{"unsigned char", "TINYINT UNSIGNED", 0, false},
@@ -269,16 +269,22 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+ database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
- string r (base_context::database_type_impl (t, hint, id));
+ string r (base_context::database_type_impl (t, hint, id, null));
if (!r.empty ())
return r;
using semantics::enum_;
using semantics::enumerator;
+ using semantics::array;
+ // Enum mapping.
+ //
if (enum_* e = dynamic_cast<enum_*> (&t))
{
// We can only map to ENUM if the C++ enumeration is contiguous
@@ -321,6 +327,31 @@ namespace relational
r += " UNSIGNED";
}
}
+ // char[N] mapping.
+ //
+ else if (array* a = dynamic_cast<array*> (&t))
+ {
+ semantics::type& bt (a->base_type ());
+ if (bt.is_a<semantics::fund_char> ())
+ {
+ unsigned long long n (a->size ());
+
+ if (n == 0)
+ return r;
+ else if (n == 1)
+ r = "CHAR(";
+ else
+ {
+ r = "VARCHAR(";
+ n--;
+ }
+
+ ostringstream ostr;
+ ostr << n;
+ r += ostr.str ();
+ r += ')';
+ }
+ }
return r;
}
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
index 0d76b04..fdcc8f6 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/relational/mysql/context.hxx
@@ -127,7 +127,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&, semantics::names*, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
virtual
diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx
index df62ce8..7602dda 100644
--- a/odb/relational/oracle/context.cxx
+++ b/odb/relational/oracle/context.cxx
@@ -30,7 +30,7 @@ namespace relational
{
{"bool", "NUMBER(1)", 0, false},
- {"char", "NUMBER(3)", 0, false},
+ {"char", "CHAR(1)", 0, false},
{"signed char", "NUMBER(3)", 0, false},
{"unsigned char", "NUMBER(3)", 0, false},
@@ -142,17 +142,62 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+ database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
- string r (base_context::database_type_impl (t, hint, id));
+ string r (base_context::database_type_impl (t, hint, id, null));
if (!r.empty ())
return r;
using semantics::enum_;
+ using semantics::array;
+ // Enum mapping.
+ //
if (t.is_a<semantics::enum_> ())
+ {
r = "NUMBER(10)";
+ }
+ // char[N] mapping.
+ //
+ else if (array* a = dynamic_cast<array*> (&t))
+ {
+ semantics::type& bt (a->base_type ());
+ if (bt.is_a<semantics::fund_char> ())
+ {
+ unsigned long long n (a->size ());
+
+ if (n == 0)
+ return r;
+ else if (n == 1)
+ r = "CHAR";
+ else
+ {
+ r = "VARCHAR2";
+ n--;
+ }
+
+ // Oracle VARCHAR2 limit is 4000 bytes. Since there are no good
+ // alternatives (CLOB?), let the user specify the mapping.
+ //
+ if (n > 4000)
+ return "";
+
+ // Allow empty VARCHAR2 values.
+ //
+ if (null != 0 && r == "VARCHAR2")
+ *null = true;
+
+ ostringstream ostr;
+ ostr << n;
+ r += '(';
+ r += ostr.str ();
+ r += ')';
+ }
+ }
return r;
}
diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx
index 0008724..a53e25d 100644
--- a/odb/relational/oracle/context.hxx
+++ b/odb/relational/oracle/context.hxx
@@ -121,7 +121,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&, semantics::names*, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
virtual
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 0f68281..95b30b0 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -31,7 +31,7 @@ namespace relational
{
{"bool", "BOOLEAN", 0, false},
- {"char", "SMALLINT", 0, false},
+ {"char", "CHAR(1)", 0, false},
{"signed char", "SMALLINT", 0, false},
{"unsigned char", "SMALLINT", 0, false},
@@ -230,17 +230,50 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+ database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
- string r (base_context::database_type_impl (t, hint, id));
+ string r (base_context::database_type_impl (t, hint, id, null));
if (!r.empty ())
return r;
using semantics::enum_;
+ using semantics::array;
+ // Enum mapping.
+ //
if (t.is_a<semantics::enum_> ())
+ {
r = "INTEGER";
+ }
+ // char[N] mapping.
+ //
+ else if (array* a = dynamic_cast<array*> (&t))
+ {
+ semantics::type& bt (a->base_type ());
+ if (bt.is_a<semantics::fund_char> ())
+ {
+ unsigned long long n (a->size ());
+
+ if (n == 0)
+ return r;
+ else if (n == 1)
+ r = "CHAR(";
+ else
+ {
+ r = "VARCHAR(";
+ n--;
+ }
+
+ ostringstream ostr;
+ ostr << n;
+ r += ostr.str ();
+ r += ')';
+ }
+ }
return r;
}
diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx
index e757b30..f607d54 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/relational/pgsql/context.hxx
@@ -113,7 +113,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type& t, semantics::names* hint, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
virtual
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 3888b1e..6c36e61 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -144,19 +144,24 @@ namespace relational
if (id_type.empty ())
id_type = database_type (t, hint, true);
- if (type.empty ())
- type = database_type (t, hint, false);
-
if (id_type.empty () && wt != 0)
id_type = database_type (*wt, whint, true);
+ bool null (false);
+ if (type.empty ())
+ type = database_type (t, hint, false, &null);
+
if (type.empty () && wt != 0)
- type = database_type (*wt, whint, false);
+ type = database_type (*wt, whint, false, &null);
// Use id mapping for discriminators.
//
if (id (m) || discriminator (m))
type = id_type;
+ // Allow NULL if requested by the default mapping.
+ //
+ else if (null && !m.count ("not-null"))
+ m.set ("null", true);
}
if (kind == unknown && !type.empty ())
@@ -333,11 +338,17 @@ namespace relational
if (type.empty () && wt != 0 && wt->count ("type"))
type = wt->get<string> ("type");
+ bool null (false);
if (type.empty ())
- type = database_type (t, hint, false);
+ type = database_type (t, hint, false, &null);
if (type.empty () && wt != 0)
- type = database_type (*wt, wh, false);
+ type = database_type (*wt, wh, false, &null);
+
+ // Allow NULL if requested by the default mapping.
+ //
+ if (null && !m.count (prefix + "-not-null"))
+ m.set (prefix + "-null", true);
}
if (!type.empty ())
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index 5e46c77..bb3d548 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -32,7 +32,7 @@ namespace relational
{
{"bool", "INTEGER", 0, false},
- {"char", "INTEGER", 0, false},
+ {"char", "TEXT", 0, false},
{"signed char", "INTEGER", 0, false},
{"unsigned char", "INTEGER", 0, false},
@@ -219,17 +219,36 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t, semantics::names* hint, bool id)
+ database_type_impl (semantics::type& t,
+ semantics::names* hint,
+ bool id,
+ bool* null)
{
- string r (base_context::database_type_impl (t, hint, id));
+ string r (base_context::database_type_impl (t, hint, id, null));
if (!r.empty ())
return r;
using semantics::enum_;
+ using semantics::array;
+ // Enum mapping.
+ //
if (t.is_a<semantics::enum_> ())
+ {
r = "INTEGER";
+ }
+ // char[N] mapping.
+ //
+ else if (array* a = dynamic_cast<array*> (&t))
+ {
+ semantics::type& bt (a->base_type ());
+ if (bt.is_a<semantics::fund_char> ())
+ {
+ if (a->size () != 0)
+ r = "TEXT";
+ }
+ }
return r;
}
diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx
index 6da5b9b..ebba734 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/relational/sqlite/context.hxx
@@ -77,7 +77,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&, semantics::names*, bool);
+ database_type_impl (semantics::type&, semantics::names*, bool, bool*);
public:
virtual