/* * call-seq: * onum * other -> number * * Returns the product of <i>onum</i> and <i>other</i>. */ static VALUE onum_mul(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; switch (rboci8_type(rhs)) { case T_FIXNUM: case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberMul(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberMul(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_mul_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_mul_op); }
/* * call-seq: * onum / integer -> oranumber * onum / numeric -> numeric * * Returns the result of dividing <i>onum</i> by <i>other</i>. */ static VALUE onum_div(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; switch (rboci8_type(rhs)) { case T_FIXNUM: if (rhs == INT2FIX(0)) { rb_num_zerodiv(); } case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberIsZero(errhp, _NUMBER(rhs), &is_zero)); if (is_zero) { rb_num_zerodiv(); } chkerr(OCINumberDiv(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_div_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_div_op); }
static VALUE onum_initialize_copy(VALUE lhs, VALUE rhs) { if (!RTEST(rb_obj_is_instance_of(rhs, CLASS_OF(lhs)))) { rb_raise(rb_eTypeError, "invalid type: expected %s but %s", rb_class2name(CLASS_OF(lhs)), rb_class2name(CLASS_OF(rhs))); } chkerr(OCINumberAssign(oci8_errhp, _NUMBER(rhs), _NUMBER(lhs))); return lhs; }
/* * call-seq: * onum.to_char(fmt = nil, nls_params = nil) -> string * * Returns a string containing a representation of self. * <i>fmt</i> and <i>nls_params</i> are same meanings with * <code>TO_CHAR</code> of Oracle function. */ static VALUE onum_to_char(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE fmt; VALUE nls_params; char buf[512]; ub4 buf_size = sizeof(buf); oratext *fmt_ptr; oratext *nls_params_ptr; ub4 fmt_len; ub4 nls_params_len; sword rv; rb_scan_args(argc, argv, "02", &fmt /* nil */, &nls_params /* nil */); if (NIL_P(fmt)) { rv = oranumber_to_str(_NUMBER(self), buf, sizeof(buf)); if (rv > 0) { return rb_usascii_str_new(buf, rv); } oranumber_dump(_NUMBER(self), buf); rb_raise(eOCIException, "Invalid internal number format: %s", buf); } StringValue(fmt); fmt_ptr = RSTRING_ORATEXT(fmt); fmt_len = RSTRING_LEN(fmt); if (NIL_P(nls_params)) { nls_params_ptr = NULL; nls_params_len = 0; } else { StringValue(nls_params); nls_params_ptr = RSTRING_ORATEXT(nls_params); nls_params_len = RSTRING_LEN(nls_params); } rv = OCINumberToText(errhp, _NUMBER(self), fmt_ptr, fmt_len, nls_params_ptr, nls_params_len, &buf_size, TO_ORATEXT(buf)); if (rv == OCI_ERROR) { sb4 errcode; OCIErrorGet(errhp, 1, NULL, &errcode, NULL, 0, OCI_HTYPE_ERROR); if (errcode == 22065) { /* OCI-22065: number to text translation for the given format causes overflow */ if (NIL_P(fmt)) /* implicit conversion */ return rb_usascii_str_new_cstr("overflow"); } chkerr(rv); } return rb_usascii_str_new(buf, buf_size); }
static VALUE onum_initialize(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE val; VALUE fmt; VALUE nls_params; if (rb_scan_args(argc, argv, "03", &val /* 0 */, &fmt /* nil */, &nls_params /* nil */) == 0) { OCINumberSetZero(errhp, _NUMBER(self)); } else if (RTEST(rb_obj_is_kind_of(val, rb_cNumeric))) { set_oci_number_from_num(_NUMBER(self), val, 1, errhp); } else { set_oci_number_from_str(_NUMBER(self), val, fmt, nls_params, errhp); } return Qnil; }
/* * call-seq: * onum.to_r -> rational * * Return the value as a <code>Rational</code>. * */ static VALUE onum_to_r(VALUE self) { VALUE x, y; int nshift = 0; OCINumber onum[2]; int current = 0; boolean is_int; chkerr(OCINumberAssign(oci8_errhp, _NUMBER(self), &onum[0])); for (;;) { chkerr(OCINumberIsInt(oci8_errhp, &onum[current], &is_int)); if (is_int) { break; } nshift++; chkerr(OCINumberShift(oci8_errhp, &onum[current], 1, &onum[1 - current])); current = 1 - current; } x = oci8_make_integer(&onum[current], oci8_errhp); if (nshift == 0) { y = INT2FIX(1); } else { y = rb_funcall(INT2FIX(10), rb_intern("**"), 1, INT2FIX(nshift)); } #ifdef T_RATIONAL return rb_Rational(x, y); #else if (!cRational) { rb_require("rational"); cRational = rb_const_get(rb_cObject, id_Rational); } return rb_funcall(rb_cObject, id_Rational, 2, x, y); #endif }
/* * call-seq: * onum ** other -> oranumber * * Raises <i>onum</i> the <i>other</i> power. */ static VALUE onum_power(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; if (FIXNUM_P(rhs)) { chkerr(OCINumberIntPower(errhp, _NUMBER(lhs), FIX2INT(rhs), &r)); } else { /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, id_power); chkerr(OCINumberPower(errhp, _NUMBER(lhs), &n, &r)); } return oci8_make_ocinumber(&r, errhp); }
OCINumber *oci8_get_ocinumber(VALUE num) { if (!rb_obj_is_kind_of(num, cOCINumber)) { rb_raise(rb_eTypeError, "invalid argument %s (expect a subclass of %s)", rb_class2name(CLASS_OF(num)), rb_class2name(cOCINumber)); } return _NUMBER(num); }
/* * call-seq: * onum.shift(fixnum) -> oranumber * * Returns <i>onum</i> * 10**<i>fixnum</i> * This method is available on Oracle 8.1 client or upper. */ static VALUE onum_shift(VALUE self, VALUE exp) { OCIError *errhp = oci8_errhp; OCINumber result; chkerr(OCINumberShift(errhp, _NUMBER(self), NUM2INT(exp), &result)); return oci8_make_ocinumber(&result, errhp); }
/* * call-seq: * onum.floor -> integer * * Returns the largest <code>Integer</code> less than or equal to <i>onum</i>. */ static VALUE onum_floor(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber r; oci_lc(OCINumberFloor(errhp, _NUMBER(self), &r)); return oci8_make_integer(&r, errhp); }
/* * call-seq: * onum.zero? -> true or false * * Returns <code>true</code> if <i>onum</i> is zero. * */ static VALUE onum_zero_p(VALUE self) { OCIError *errhp = oci8_errhp; boolean result; chkerr(OCINumberIsZero(errhp, _NUMBER(self), &result)); return result ? Qtrue : Qfalse; }
/* * call-seq: * onum.has_decimal_part? -> true or false * * Returns +true+ if <i>self</i> has a decimal part. * * OraNumber(10).has_decimal_part? # => false * OraNumber(10.1).has_decimal_part? # => true */ static VALUE onum_has_decimal_part_p(VALUE self) { OCIError *errhp = oci8_errhp; boolean result; chkerr(OCINumberIsInt(errhp, _NUMBER(self), &result)); return result ? Qfalse : Qtrue; }
/* * call-seq: * onum.to_i -> integer * * Returns <i>onum</i> truncated to an <code>Integer</code>. */ static VALUE onum_to_i(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber num; chkerr(OCINumberTrunc(errhp, _NUMBER(self), 0, &num)); return oci8_make_integer(&num, errhp); }
/* * call-seq: * onum.round_prec(digits) -> oranumber * * Rounds <i>onum</i> to a specified number of decimal digits. * This method is available on Oracle 8.1 client or upper. * * OraNumber.new(1.234).round_prec(2) #=> 1.2 * OraNumber.new(12.34).round_prec(2) #=> 12 * OraNumber.new(123.4).round_prec(2) #=> 120 */ static VALUE onum_round_prec(VALUE self, VALUE ndigs) { OCIError *errhp = oci8_errhp; OCINumber r; chkerr(OCINumberPrec(errhp, _NUMBER(self), NUM2INT(ndigs), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.abs -> oranumber * * Returns the absolute value of <i>onum</i>. * */ static VALUE onum_abs(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber result; chkerr(OCINumberAbs(errhp, _NUMBER(self), &result)); return oci8_make_ocinumber(&result, errhp); }
/* * call-seq: * onum.ceil -> integer * * Returns the smallest <code>Integer</code> greater than or equal to * <i>onum</i>. */ static VALUE onum_ceil(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber r; chkerr(OCINumberCeil(errhp, _NUMBER(self), &r)); return oci8_make_integer(&r, errhp); }
/* * call-seq: * -onum -> oranumber * * Returns a negated <code>OraNumber</code>. */ static VALUE onum_neg(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber r; chkerr(OCINumberNeg(errhp, _NUMBER(self), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.to_f -> float * * Return the value as a <code>Float</code>. * */ 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); }
/* * call-seq: * onum.truncate -> integer * onum.truncate(decplace) -> oranumber * * Truncates <i>onum</i> to the <code>Integer</code> when no argument. * Truncates <i>onum</i> to a specified decimal place <i>decplace</i> when one argument. */ static VALUE onum_trunc(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE decplace; OCINumber r; rb_scan_args(argc, argv, "01", &decplace /* 0 */); chkerr(OCINumberTrunc(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.round -> integer * onum.round(decplace) -> oranumber * * Rounds <i>onum</i> to the nearest <code>Integer</code> when no argument. * Rounds <i>onum</i> to a specified decimal place <i>decplace</i> when one argument. * * OraNumber.new(1.234).round(1) #=> 1.2 * OraNumber.new(1.234).round(2) #=> 1.23 * OraNumber.new(1.234).round(3) #=> 1.234 */ static VALUE onum_round(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE decplace; OCINumber r; rb_scan_args(argc, argv, "01", &decplace /* 0 */); chkerr(OCINumberRound(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r)); if (argc == 0) { return oci8_make_integer(&r, errhp); } else { return oci8_make_ocinumber(&r, errhp); } }
/* * call-seq: * onum % other -> oranumber * * Returns the modulo after division of <i>onum</i> by <i>other</i>. */ static VALUE onum_mod(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, '%'); /* check whether argument is not zero. */ chkerr(OCINumberIsZero(errhp, &n, &is_zero)); if (is_zero) rb_num_zerodiv(); /* modulo */ chkerr(OCINumberMod(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum <=> other -> -1, 0, +1 * * Returns -1, 0, or +1 depending on whether <i>onum</i> is less than, * equal to, or greater than <i>other</i>. This is the basis for the * tests in <code>Comparable</code>. */ static VALUE onum_cmp(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; sword r; /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_cmp(lhs, rhs, id_cmp); /* compare */ chkerr(OCINumberCmp(errhp, _NUMBER(lhs), &n, &r)); if (r > 0) { return INT2FIX(1); } else if (r == 0) { return INT2FIX(0); } else { return INT2FIX(-1); } }
/* * call-seq: * onum.to_f -> float * * Return the value as a <code>Float</code>. * */ static VALUE onum_to_f(VALUE self) { return rb_float_new(oci8_onum_to_dbl(_NUMBER(self), oci8_errhp)); }
/* * call-seq: * onum.to_d -> bigdecimal * * Return the value as a <code>BigDecimal</code>. * */ static VALUE onum_to_d(VALUE self) { return onum_to_d_real(_NUMBER(self), oci8_errhp); }
/* * call-seq: * onum.dump -> string * * Returns internal representation whose format is same with * the return value of Oracle SQL function DUMP(). * * OraNumber.new(100).dump #=> "Typ=2 Len=2: 194,2" * OraNumber.new(123).dump #=> "Typ=2 Len=3: 194,2,24" * OraNumber.new(0.1).dump #=> "Typ=2 Len=2: 192,11" */ static VALUE onum_dump(VALUE self) { char buf[ORANUMBER_DUMP_BUF_SIZ]; int rv = oranumber_dump(_NUMBER(self), buf); return rb_usascii_str_new(buf, rv); }