summaryrefslogtreecommitdiff
path: root/odb/odb/relational/oracle/common.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/odb/relational/oracle/common.cxx')
-rw-r--r--odb/odb/relational/oracle/common.cxx522
1 files changed, 522 insertions, 0 deletions
diff --git a/odb/odb/relational/oracle/common.cxx b/odb/odb/relational/oracle/common.cxx
new file mode 100644
index 0000000..7caafc9
--- /dev/null
+++ b/odb/odb/relational/oracle/common.cxx
@@ -0,0 +1,522 @@
+// file : odb/relational/oracle/common.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <cassert>
+
+#include <odb/relational/oracle/common.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace oracle
+ {
+ //
+ // member_base
+ //
+
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
+ {
+ return parse_sql_type (column_type (m, key_prefix_), m);
+ }
+
+ void member_base::
+ traverse_simple (member_info& mi)
+ {
+ switch (mi.st->type)
+ {
+ // Numeric types.
+ //
+ case sql_type::NUMBER:
+ {
+ const sql_type& st (*mi.st);
+
+ if (st.prec)
+ {
+ unsigned short r (st.prec_value);
+
+ if (!st.scale)
+ {
+ if (r <= 10)
+ traverse_int32 (mi);
+ // Only OCI versions 11.2 and later support insertion and
+ // extraction into a 64 bit integer.
+ //
+ else if (
+ (options.oracle_client_version () >= oracle_version (11, 2)) &&
+ (r <= 19 || (r == 20 && unsigned_integer (mi.t))))
+ traverse_int64 (mi);
+ else
+ traverse_big_int (mi);
+ }
+ else
+ {
+ // We can calculate the decimal exponent of the normalised
+ // floating point equivalent of the fixed point number using
+ // e = p - s, where p is the precision, s is the scale, and
+ // e the exponent. We can then use this to determine whether
+ // or not a value of Oracle SQL type NUMBER can be completely
+ // stored in the native floating point type.
+ //
+
+ // The maximum decimal precision of a float is 7 significant
+ // digits. The minimum and maximum decimal exponents
+ // representable by a float are -37 and 38 respectively.
+ //
+ if (r <= 7)
+ {
+ int e = r - st.scale_value;
+
+ if (e >= -37 && e <= 38)
+ traverse_float (mi);
+ else
+ traverse_double (mi);
+ }
+
+ // The maximum decimal precision of a double is 15 significant
+ // digits. The minimum and maximum decimal exponent representable
+ // by a double exceeds that of the Oracle NUMBER type.
+ //
+ else if (r <= 15)
+ traverse_double (mi);
+ else
+ traverse_big_float (mi);
+ }
+ }
+ else
+ // If there is no precision, then this is a floating-point number.
+ //
+ traverse_double (mi);
+
+ break;
+ }
+ case sql_type::FLOAT:
+ {
+ // We map FLOAT types based exclusively on their binary precision
+ // seeing that in 99% of cases it is the precision that is the
+ // limiting factor and not the exponent.
+ //
+ if (mi.st->prec_value <= 24)
+ traverse_float (mi);
+ else if (mi.st->prec_value <= 53)
+ traverse_double (mi);
+ else
+ traverse_big_float (mi);
+
+ break;
+ }
+ case sql_type::BINARY_FLOAT:
+ {
+ traverse_float (mi);
+ break;
+ }
+ case sql_type::BINARY_DOUBLE:
+ {
+ traverse_double (mi);
+ break;
+ }
+ // Data-time types.
+ //
+ case sql_type::DATE:
+ {
+ traverse_date (mi);
+ break;
+ }
+ case sql_type::TIMESTAMP:
+ {
+ traverse_timestamp (mi);
+ break;
+ }
+ case sql_type::INTERVAL_YM:
+ {
+ traverse_interval_ym (mi);
+ break;
+ }
+ case sql_type::INTERVAL_DS:
+ {
+ traverse_interval_ds (mi);
+ break;
+ }
+ // String and binary types.
+ //
+ case sql_type::CHAR:
+ case sql_type::NCHAR:
+ case sql_type::VARCHAR2:
+ case sql_type::NVARCHAR2:
+ case sql_type::RAW:
+ {
+ traverse_string (mi);
+ break;
+ }
+ case sql_type::BLOB:
+ case sql_type::CLOB:
+ case sql_type::NCLOB:
+ {
+ traverse_lob (mi);
+ break;
+ }
+ case sql_type::invalid:
+ {
+ assert (false);
+ break;
+ }
+ }
+ }
+
+ //
+ // member_image_type
+ //
+
+ member_image_type::
+ member_image_type (base const& x)
+ : member_base::base (x), // virtual base
+ base (x) {}
+
+ member_image_type::
+ member_image_type ()
+ : relational::member_base (0, 0, string (), string ()) {}
+
+ member_image_type::
+ member_image_type (semantics::type* type,
+ const custom_cxx_type* ct,
+ string const& fq_type,
+ string const& key_prefix)
+ : relational::member_base (type, ct, fq_type, key_prefix) {}
+
+ string member_image_type::
+ image_type (semantics::data_member& m)
+ {
+ type_.clear ();
+ member_base::traverse (m, true);
+ return type_;
+ }
+
+ void member_image_type::
+ traverse_composite (member_info& mi)
+ {
+ type_ = "composite_value_traits< " + mi.fq_type () +
+ ", id_oracle >::image_type";
+ }
+
+ void member_image_type::
+ traverse_int32 (member_info& mi)
+ {
+ if (unsigned_integer (mi.t))
+ type_ = "unsigned int";
+ else
+ type_ = "int";
+ }
+
+ void member_image_type::
+ traverse_int64 (member_info& mi)
+ {
+ if (unsigned_integer (mi.t))
+ type_ = "unsigned long long";
+ else
+ type_ = "long long";
+ }
+
+ void member_image_type::
+ traverse_big_int (member_info&)
+ {
+ type_ = "char*";
+ }
+
+ void member_image_type::
+ traverse_float (member_info&)
+ {
+ type_ = "float";
+ }
+
+ void member_image_type::
+ traverse_double (member_info&)
+ {
+ type_ = "double";
+ }
+
+ void member_image_type::
+ traverse_big_float (member_info&)
+ {
+ type_ = "char*";
+ }
+
+ void member_image_type::
+ traverse_date (member_info&)
+ {
+ type_ = "char*";
+ }
+
+ void member_image_type::
+ traverse_timestamp (member_info&)
+ {
+ type_ = "oracle::datetime";
+ }
+
+ void member_image_type::
+ traverse_interval_ym (member_info&)
+ {
+ type_ = "oracle::interval_ym";
+ }
+
+ void member_image_type::
+ traverse_interval_ds (member_info&)
+ {
+ type_ = "oracle::interval_ds";
+ }
+
+ void member_image_type::
+ traverse_string (member_info&)
+ {
+ type_ = "char*";
+ }
+
+ void member_image_type::
+ traverse_lob (member_info&)
+ {
+ type_ = "oracle::lob_callback";
+ }
+
+ entry<member_image_type> member_image_type_;
+
+ //
+ // member_database_type
+ //
+
+ namespace
+ {
+ const char* string_bin_database_id[] =
+ {
+ "id_string", // CHAR
+ "id_nstring", // NCHAR
+ "id_string", // VARCHAR2
+ "id_nstring", // NVARCHAR2
+ "id_raw" // RAW
+ };
+
+ const char* lob_database_id[] =
+ {
+ "id_blob",
+ "id_clob",
+ "id_nclob"
+ };
+ }
+
+ member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x) {}
+
+ member_database_type_id::
+ member_database_type_id ()
+ : member_base::base (0, 0, string (), string ()), // virtual base
+ base (0, 0, string (), string ()) {}
+
+ member_database_type_id::
+ member_database_type_id (semantics::type* type,
+ const custom_cxx_type* ct,
+ string const& fq_type,
+ string const& key_prefix)
+ : member_base::base (type, ct, fq_type, key_prefix), // virtual base
+ base (type, ct, fq_type, key_prefix) {}
+
+ string member_database_type_id::
+ database_type_id (type& m)
+ {
+ type_id_.clear ();
+ member_base::traverse (m, true);
+ return type_id_;
+ }
+
+ void member_database_type_id::
+ traverse_composite (member_info&)
+ {
+ assert (false);
+ }
+
+ void member_database_type_id::
+ traverse_int32 (member_info&)
+ {
+ type_id_ = "oracle::id_int32";
+ }
+
+ void member_database_type_id::
+ traverse_int64 (member_info&)
+ {
+ type_id_ = "oracle::id_int64";
+ }
+
+ void member_database_type_id::
+ traverse_big_int (member_info&)
+ {
+ type_id_ = "oracle::id_big_int";
+ }
+
+ void member_database_type_id::
+ traverse_float (member_info&)
+ {
+ type_id_ = "oracle::id_float";
+ }
+
+ void member_database_type_id::
+ traverse_double (member_info&)
+ {
+ type_id_ = "oracle::id_double";
+ }
+
+ void member_database_type_id::
+ traverse_big_float (member_info&)
+ {
+ type_id_ = "oracle::id_big_float";
+ }
+
+ void member_database_type_id::
+ traverse_date (member_info&)
+ {
+ type_id_ = "oracle::id_date";
+ }
+
+ void member_database_type_id::
+ traverse_timestamp (member_info&)
+ {
+ type_id_ = "oracle::id_timestamp";
+ }
+
+ void member_database_type_id::
+ traverse_interval_ym (member_info&)
+ {
+ type_id_ = "oracle::id_interval_ym";
+ }
+
+ void member_database_type_id::
+ traverse_interval_ds (member_info&)
+ {
+ type_id_ = "oracle::id_interval_ds";
+ }
+
+ void member_database_type_id::
+ traverse_string (member_info& mi)
+ {
+ type_id_ = string ("oracle::") +
+ string_bin_database_id[mi.st->type - sql_type::CHAR];
+ }
+
+ void member_database_type_id::
+ traverse_lob (member_info& mi)
+ {
+ type_id_ = string ("oracle::") +
+ lob_database_id[mi.st->type - sql_type::BLOB];
+ }
+
+ entry<member_database_type_id> member_database_type_id_;
+
+ //
+ // query_columns
+ //
+
+ struct query_columns: relational::query_columns, context
+ {
+ query_columns (base const& x): base_impl (x) {}
+
+ void
+ column_ctor (string const& type, string const& name, string const& base)
+ {
+ os << name << " (";
+
+ if (multi_dynamic)
+ os << "odb::query_column< " << type << " >& qc," << endl;
+
+ os << "const char* t," << endl
+ << "const char* c," << endl
+ << "const char* conv," << endl
+ << "unsigned short p = 0xFFF," << endl
+ << "short s = 0xFFF)" << endl
+ << " : " << base << " (" << (multi_dynamic ? "qc, " : "") <<
+ "t, c, conv, p, s)"
+ << "{"
+ << "}";
+ }
+
+ virtual void
+ column_ctor_args_extra (semantics::data_member& m)
+ {
+ // For some types we need to pass precision and scale.
+ //
+ sql_type const& st (parse_sql_type (column_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)
+ {
+ return member_database_type_id_.database_type_id (m);
+ }
+
+ private:
+ member_database_type_id member_database_type_id_;
+ };
+ entry<query_columns> query_columns_;
+ }
+}