From 94d00afa2896a0a418da029aee1e5354c49759dd Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 22 Jan 2012 17:43:56 +0200 Subject: Pass precision and scale to Oracle query_param --- odb/relational/oracle/common.cxx | 84 ++++++++++++++++++++++++++++++++++++++- odb/relational/oracle/context.cxx | 16 ++++++-- odb/relational/oracle/header.cxx | 23 +++++------ 3 files changed, 105 insertions(+), 18 deletions(-) (limited to 'odb/relational/oracle') diff --git a/odb/relational/oracle/common.cxx b/odb/relational/oracle/common.cxx index 708c4e7..3b1c1b6 100644 --- a/odb/relational/oracle/common.cxx +++ b/odb/relational/oracle/common.cxx @@ -215,7 +215,6 @@ namespace relational { traverse_interval_ym (mi); break; - } case sql_type::INTERVAL_DS: { @@ -479,6 +478,89 @@ namespace relational { query_columns (base const& x): base (x) {} + virtual void + column_ctor (string const& type, string const& base) + { + os << type << " (const char* t," << endl + << "const char* c," << endl + << "unsigned short p = 0xFFF," << endl + << "short s = 0xFFF)" << endl + << " : " << base << " (t, c, p, s)" + << "{" + << "}"; + } + + virtual void + column_ctor_extra (semantics::data_member& m) + { + // For some types we need to pass precision and scale. + // + sql_type const& st (column_sql_type (m)); + + switch (st.type) + { + case sql_type::NUMBER: + { + if (st.prec) + { + os << ", " << st.prec_value; + + if (st.scale) + os << ", " << st.scale_value; + } + break; + } + case sql_type::FLOAT: + { + os << ", " << st.prec_value; + break; + } + case sql_type::TIMESTAMP: + { + os << ", " << st.prec_value; + break; + } + case sql_type::INTERVAL_YM: + { + os << ", " << st.prec_value; + break; + } + case sql_type::INTERVAL_DS: + { + // INTERVAL DAY TO SECOND has two precisions. + // + os << ", " << st.prec_value << ", " << st.scale_value; + break; + } + case sql_type::CHAR: + case sql_type::NCHAR: + case sql_type::VARCHAR2: + case sql_type::NVARCHAR2: + case sql_type::RAW: + { + // The same logic as in header.cxx. + // + size_t n (st.prec ? st.prec_value : 1); + + if (!st.byte_semantics) + n *= 4; + + if (st.type == sql_type::VARCHAR2 || + st.type == sql_type::NVARCHAR2) + n = n > 4000 ? 4000 : n; + else + n = n > 2000 ? 2000 : n; + + os << ", " << n; + break; + } + default: + { + break; + } + } + } + virtual string database_type_id (semantics::data_member& m) { diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx index 0f9bae1..d477a19 100644 --- a/odb/relational/oracle/context.cxx +++ b/odb/relational/oracle/context.cxx @@ -400,11 +400,13 @@ namespace relational // However, this may change in future versions. // r.type = sql_type::VARCHAR2; + r.byte_semantics = true; s = parse_prec; } else if (id == "NVARCHAR2") { r.type = sql_type::NVARCHAR2; + r.byte_semantics = false; s = parse_prec; } else if (id == "VARYING") @@ -412,11 +414,17 @@ namespace relational // VARYING always appears at the end of an identifier. // if (prefix == "CHAR" || prefix == "CHARACTER") + { r.type = sql_type::VARCHAR2; + r.byte_semantics = true; + } else if (prefix == "NCHAR" || prefix == "NATIONAL CHAR" || prefix == "NATIONAL CHARACTER") + { r.type = sql_type::NVARCHAR2; + r.byte_semantics = false; + } s = parse_prec; } @@ -473,18 +481,18 @@ namespace relational if (prefix == "CHAR" || prefix == "CHARACTER") { r.type = sql_type::CHAR; + r.byte_semantics = true; r.prec = true; r.prec_value = 1; - r.byte_semantics = true; } else if (prefix == "NCHAR" || prefix == "NATIONAL CHAR" || prefix == "NATIONAL CHARACTER") { r.type = sql_type::NCHAR; + r.byte_semantics = false; r.prec = true; r.prec_value = 1; - r.byte_semantics = false; } else if (prefix == "TIMESTAMP") { @@ -643,18 +651,18 @@ namespace relational if (prefix == "CHAR" || prefix == "CHARACTER") { r.type = sql_type::CHAR; + r.byte_semantics = true; r.prec = true; r.prec_value = 1; - r.byte_semantics = true; } else if (prefix == "NCHAR" || prefix == "NATIONAL CHAR" || prefix == "NATIONAL CHARACTER") { r.type = sql_type::NCHAR; + r.byte_semantics = false; r.prec = true; r.prec_value = 1; - r.byte_semantics = false; } else if (prefix == "TIMESTAMP") { diff --git a/odb/relational/oracle/header.cxx b/odb/relational/oracle/header.cxx index c302a82..8b9b93e 100644 --- a/odb/relational/oracle/header.cxx +++ b/odb/relational/oracle/header.cxx @@ -184,23 +184,20 @@ namespace relational { size_t n (mi.st->prec ? mi.st->prec_value : 1); - // National characters can be either UTF-8 or UTF-16 encoded, both - // of which have a maximum character encoding size of 4 bytes. - // Assume the database character set uses a single byte fixed width - // encoding. + // National characters can be either UTF-8 or UTF-16 encoded, + // both of which have a maximum character encoding size of 4 + // bytes. Database character set can also be UTF-8 so if the + // size is specified in characters, then conservatively assume + // each character can take up to 4 bytes. // - sql_type::core_type t (mi.st->type); - - if ((t == sql_type::NCHAR || t == sql_type::NVARCHAR2) && - !mi.st->byte_semantics) + if (!mi.st->byte_semantics) // N*CHAR always has CHAR semantics. n *= 4; - if (t == sql_type::CHAR || - t == sql_type::NCHAR || - t == sql_type::RAW) - n = n > 2000 ? 2000 : n; - else if (t == sql_type::VARCHAR2 || t == sql_type::NVARCHAR2) + if (mi.st->type == sql_type::VARCHAR2 || + mi.st->type == sql_type::NVARCHAR2) n = n > 4000 ? 4000 : n; + else + n = n > 2000 ? 2000 : n; os << "char " << mi.var << "value[" << n << "];" << "ub2 " << mi.var << "size;" -- cgit v1.1