[ruby-oci8-commit] [441] trunk/ruby-oci8: Decimal to float and float to decimal conversions are done as exactly ruby does by default .
nobody at rubyforge.org
nobody at rubyforge.org
Fri Aug 19 09:19:36 EDT 2011
Revision: 441
Author: kubo
Date: 2011-08-19 09:19:35 -0400 (Fri, 19 Aug 2011)
Log Message:
-----------
Decimal to float and float to decimal conversions are done as exactly ruby does by default.
The behavior is customizable by OCI8.properties[:float_conversion_type].
Modified Paths:
--------------
trunk/ruby-oci8/.gitignore
trunk/ruby-oci8/ChangeLog
trunk/ruby-oci8/ext/oci8/bind.c
trunk/ruby-oci8/ext/oci8/oci8.c
trunk/ruby-oci8/ext/oci8/oci8.h
trunk/ruby-oci8/ext/oci8/ocinumber.c
trunk/ruby-oci8/lib/oci8/properties.rb
Modified: trunk/ruby-oci8/.gitignore
===================================================================
--- trunk/ruby-oci8/.gitignore 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/.gitignore 2011-08-19 13:19:35 UTC (rev 441)
@@ -5,4 +5,7 @@
ext/oci8/depend
ext/oci8/extconf.h
ext/oci8/mkmf.log
+ext/oci8/*.o
+ext/oci8/*.so
+ext/oci8/*.obj
lib/oci8.rb
Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/ChangeLog 2011-08-19 13:19:35 UTC (rev 441)
@@ -1,4 +1,10 @@
2011-08-19 KUBO Takehiro <kubo at jiubao.org>
+ * ext/oci8/bind.c, ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/ocinumber.c,
+ lib/oci8/properties.rb: Decimal to float and float to decimal conversions
+ are done as exactly ruby does by default. The behavior is customizable by
+ OCI8.properties[:float_conversion_type].
+
+2011-08-19 KUBO Takehiro <kubo at jiubao.org>
* ext/oci8/oraconf.rb: fix a bug not to find the OCI library location listed in
'ldconfig -p' when LD_LIBRARY_PATH is set.
(Reported by Edgars Beigarts.)
Modified: trunk/ruby-oci8/ext/oci8/bind.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/bind.c 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/ext/oci8/bind.c 2011-08-19 13:19:35 UTC (rev 441)
@@ -2,7 +2,7 @@
/*
* bind.c
*
- * Copyright (C) 2002-2010 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
*/
#include "oci8.h"
@@ -298,41 +298,25 @@
#endif /* USE_DYNAMIC_FETCH */
/*
- * bind_float
+ * bind_binary_double
*/
-static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
+static VALUE bind_binary_double_get(oci8_bind_t *obind, void *data, void *null_struct)
{
return rb_float_new(*(double*)data);
}
-static void bind_float_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
+static void bind_binary_double_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
{
/* val is converted to Float if it isn't Float. */
*(double*)data = RFLOAT_VALUE(rb_Float(val));
}
-static void bind_float_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
+static void bind_binary_double_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
{
obind->value_sz = sizeof(double);
obind->alloc_sz = sizeof(double);
}
-static const oci8_bind_class_t bind_float_class = {
- {
- NULL,
- oci8_bind_free,
- sizeof(oci8_bind_t)
- },
- bind_float_get,
- bind_float_set,
- bind_float_init,
- NULL,
- NULL,
- NULL,
- NULL,
- SQLT_FLT
-};
-
#ifndef SQLT_BDOUBLE
#define SQLT_BDOUBLE 22
#endif
@@ -342,9 +326,9 @@
oci8_bind_free,
sizeof(oci8_bind_t)
},
- bind_float_get,
- bind_float_set,
- bind_float_init,
+ bind_binary_double_get,
+ bind_binary_double_set,
+ bind_binary_double_init,
NULL,
NULL,
NULL,
@@ -516,7 +500,6 @@
oci8_define_bind_class("Long", &bind_long_class);
oci8_define_bind_class("LongRaw", &bind_long_raw_class);
#endif /* USE_DYNAMIC_FETCH */
- oci8_define_bind_class("Float", &bind_float_class);
if (oracle_client_version >= ORAVER_10_1) {
oci8_define_bind_class("BinaryDouble", &bind_binary_double_class);
}
Modified: trunk/ruby-oci8/ext/oci8/oci8.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.c 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/ext/oci8/oci8.c 2011-08-19 13:19:35 UTC (rev 441)
@@ -2,7 +2,7 @@
/*
* oci8.c - part of ruby-oci8
*
- * Copyright (C) 2002-2010 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
*
*/
#include "oci8.h"
@@ -124,6 +124,27 @@
return oracle_client_vernum;
}
+static VALUE oci8_s_set_property(VALUE klass, VALUE name, VALUE val)
+{
+ const char *name_str;
+
+ Check_Type(name, T_SYMBOL);
+ name_str = rb_id2name(SYM2ID(name));
+ if (strcmp(name_str, "float_conversion_type") == 0) {
+ const char *val_str;
+ Check_Type(val, T_SYMBOL);
+ val_str = rb_id2name(SYM2ID(val));
+ if (strcmp(val_str, "ruby") == 0) {
+ oci8_float_conversion_type_is_ruby = 1;
+ } else if (strcmp(val_str, "oracle") == 0) {
+ oci8_float_conversion_type_is_ruby = 0;
+ } else {
+ rb_raise(rb_eArgError, "float_conversion_type's value should be either :ruby or :oracle.");
+ }
+ }
+ return Qnil;
+}
+
/*
* call-seq:
* OCI8.error_message(message_no) -> string
@@ -1016,6 +1037,7 @@
rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
+ rb_define_singleton_method_nodoc(cOCI8, "__set_property", oci8_s_set_property, 2);
if (have_OCIMessageOpen && have_OCIMessageGet) {
rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
}
Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/ext/oci8/oci8.h 2011-08-19 13:19:35 UTC (rev 441)
@@ -490,6 +490,7 @@
void Init_ora_date(void);
/* ocinumber.c */
+extern int oci8_float_conversion_type_is_ruby;
void Init_oci_number(VALUE mOCI, OCIError *errhp);
OCINumber *oci8_get_ocinumber(VALUE num);
VALUE oci8_make_ocinumber(OCINumber *s, OCIError *errhp);
@@ -497,6 +498,8 @@
VALUE oci8_make_float(OCINumber *s, OCIError *errhp);
OCINumber *oci8_set_ocinumber(OCINumber *result, VALUE self, OCIError *errhp);
OCINumber *oci8_set_integer(OCINumber *result, VALUE self, OCIError *errhp);
+double oci8_onum_to_dbl(OCINumber *s, OCIError *errhp);
+OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp);
/* ocidatetim.c */
void Init_oci_datetime(void);
Modified: trunk/ruby-oci8/ext/oci8/ocinumber.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/ocinumber.c 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/ext/oci8/ocinumber.c 2011-08-19 13:19:35 UTC (rev 441)
@@ -2,12 +2,13 @@
/*
* ocinumber.c
*
- * Copyright (C) 2005-2009 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2005-2011 KUBO Takehiro <kubo at jiubao.org>
*
*/
#include "oci8.h"
#include <orl.h>
#include <errno.h>
+#include <math.h>
#include "oranumber_util.h"
#ifndef RB_NUM_COERCE_FUNCS_NEED_OPID
@@ -16,6 +17,12 @@
#define rb_num_coerce_bin(x, y, id) rb_num_coerce_bin((x), (y))
#endif
+int oci8_float_conversion_type_is_ruby = 1;
+
+#ifndef INFINITY
+#define INFINITY (1.0/+0.0)
+#endif
+
static ID id_power; /* rb_intern("**") */
static ID id_cmp; /* rb_intern("<=>") */
static ID id_finite_p;
@@ -136,10 +143,7 @@
VALUE oci8_make_float(OCINumber *s, OCIError *errhp)
{
- double dbl;
-
- oci_lc(OCINumberToReal(errhp, s, sizeof(double), &dbl));
- return rb_float_new(dbl);
+ return rb_float_new(oci8_onum_to_dbl(s, errhp));
}
/* fill C structure (OCINumber) from a string. */
@@ -191,7 +195,6 @@
static int set_oci_number_from_num(OCINumber *result, VALUE num, int force, OCIError *errhp)
{
signed long sl;
- double dbl;
if (!RTEST(rb_obj_is_kind_of(num, rb_cNumeric)))
rb_raise(rb_eTypeError, "expect Numeric but %s", rb_class2name(CLASS_OF(num)));
@@ -206,8 +209,7 @@
return 1;
case T_FLOAT:
/* set from double. */
- dbl = NUM2DBL(num);
- oci_lc(OCINumberFromReal(errhp, &dbl, sizeof(dbl), result));
+ oci8_dbl_to_onum(result, NUM2DBL(num), errhp);
return 1;
case T_BIGNUM:
/* change via string. */
@@ -313,6 +315,68 @@
return result;
}
+double oci8_onum_to_dbl(OCINumber *s, OCIError *errhp)
+{
+ if (oci8_float_conversion_type_is_ruby) {
+ char buf[256];
+ sword rv;
+
+ double dbl;
+
+ oci_lc(OCINumberToReal(errhp, s, sizeof(double), &dbl));
+
+ rv = oranumber_to_str(s, buf, sizeof(buf));
+ if (rv <= 0) {
+ char buf[ORANUMBER_DUMP_BUF_SIZ];
+
+ oranumber_dump(s, buf);
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
+ }
+ if (strcmp(buf, "~") == 0) {
+ return INFINITY;
+ } else if (strcmp(buf, "-~") == 0) {
+ return -INFINITY;
+ }
+ return rb_cstr_to_dbl(buf, Qtrue);
+ } else {
+ double dbl;
+
+ oci_lc(OCINumberToReal(errhp, s, sizeof(double), &dbl));
+ return dbl;
+ }
+}
+
+OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp)
+{
+ switch (fpclassify(dbl)) {
+ case FP_NAN:
+ rb_raise(rb_eFloatDomainError, "NaN");
+ /* never reach here */
+ break;
+ case FP_INFINITE:
+ if (dbl > 0.0) {
+ oranumber_from_str(result, "~", 1);
+ } else {
+ oranumber_from_str(result, "-~", 2);
+ }
+ return result;
+ }
+
+ if (oci8_float_conversion_type_is_ruby) {
+ VALUE str;
+ sword rv;
+
+ str = rb_obj_as_string(rb_float_new(dbl));
+ rv = oranumber_from_str(result, RSTRING_PTR(str), RSTRING_LEN(str));
+ if (rv != 0) {
+ oci8_raise_by_msgno(rv, NULL);
+ }
+ } else {
+ oci_lc(OCINumberFromReal(errhp, &dbl, sizeof(dbl), result));
+ }
+ return result;
+}
+
/*
* call-seq:
* OCI8::Math.atan2(y, x) -> oranumber
@@ -1107,11 +1171,7 @@
*/
static VALUE onum_to_f(VALUE self)
{
- OCIError *errhp = oci8_errhp;
- double dbl;
-
- oci_lc(OCINumberToReal(errhp, _NUMBER(self), sizeof(dbl), &dbl));
- return rb_float_new(dbl);
+ return rb_float_new(oci8_onum_to_dbl(_NUMBER(self), oci8_errhp));
}
/*
@@ -1363,6 +1423,11 @@
return oci8_make_integer((OCINumber*)data, oci8_errhp);
}
+static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
+{
+ return oci8_make_float((OCINumber*)data, oci8_errhp);
+}
+
static void bind_ocinumber_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
{
set_oci_number_from_num((OCINumber*)data, val, 1, oci8_errhp);
@@ -1425,6 +1490,22 @@
SQLT_VNU,
};
+static const oci8_bind_class_t bind_float_class = {
+ {
+ NULL,
+ oci8_bind_free,
+ sizeof(oci8_bind_t)
+ },
+ bind_float_get,
+ bind_ocinumber_set,
+ bind_ocinumber_init,
+ bind_ocinumber_init_elem,
+ NULL,
+ NULL,
+ NULL,
+ SQLT_VNU,
+};
+
void
Init_oci_number(VALUE cOCI8, OCIError *errhp)
{
@@ -1544,6 +1625,7 @@
oci8_define_bind_class("OraNumber", &bind_ocinumber_class);
oci8_define_bind_class("Integer", &bind_integer_class);
+ oci8_define_bind_class("Float", &bind_float_class);
}
OCINumber *oci8_get_ocinumber(VALUE num)
Modified: trunk/ruby-oci8/lib/oci8/properties.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/properties.rb 2011-08-19 08:13:31 UTC (rev 440)
+++ trunk/ruby-oci8/lib/oci8/properties.rb 2011-08-19 13:19:35 UTC (rev 441)
@@ -1,11 +1,12 @@
# properties.rb -- implements OCI8.properties
#
-# Copyright (C) 2010 KUBO Takehiro <kubo at jiubao.org>
+# Copyright (C) 2010-2011 KUBO Takehiro <kubo at jiubao.org>
class OCI8
@@properties = {
:bind_string_as_nchar => false,
+ :float_conversion_type => :ruby,
}
def @@properties.[](name)
@@ -18,6 +19,9 @@
case name
when :bind_string_as_nchar
val = val ? true : false
+ when :float_conversion_type
+ # handled by native code in oci8lib_xx.so.
+ OCI8.__set_property(name, val)
end
super(name, val)
end
@@ -44,6 +48,14 @@
# [:bind_string_as_nchar]
# +true+ when string bind variables are bound as NCHAR,
# otherwise +false+. The default value is +false+.
+ #
+ # [:float_conversion_type]
+ # (new in 2.1.0)
+ # Specifies who converts decimal to float and vice versa.
+ # It should be either +:ruby+ or +:oracle+. The default value
+ # is +:ruby+.
+ # See: http://rubyforge.org/forum/forum.php?thread_id=50030&forum_id=1078
+ #
def self.properties
@@properties
end
More information about the ruby-oci8-commit
mailing list