ruby-oci8-master 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/ChangeLog +2321 -0
  2. data/Makefile +88 -0
  3. data/NEWS +303 -0
  4. data/README +76 -0
  5. data/VERSION +1 -0
  6. data/dist-files +83 -0
  7. data/doc/api.en.html +527 -0
  8. data/doc/api.en.rd +554 -0
  9. data/doc/api.ja.html +525 -0
  10. data/doc/api.ja.rd +557 -0
  11. data/doc/manual.css +35 -0
  12. data/ext/oci8/.document +18 -0
  13. data/ext/oci8/MANIFEST +18 -0
  14. data/ext/oci8/apiwrap.c.tmpl +182 -0
  15. data/ext/oci8/apiwrap.h.tmpl +61 -0
  16. data/ext/oci8/apiwrap.rb +91 -0
  17. data/ext/oci8/apiwrap.yml +1455 -0
  18. data/ext/oci8/attr.c +105 -0
  19. data/ext/oci8/bind.c +366 -0
  20. data/ext/oci8/connection_pool.c +199 -0
  21. data/ext/oci8/encoding.c +289 -0
  22. data/ext/oci8/env.c +178 -0
  23. data/ext/oci8/error.c +378 -0
  24. data/ext/oci8/extconf.rb +179 -0
  25. data/ext/oci8/lob.c +805 -0
  26. data/ext/oci8/metadata.c +232 -0
  27. data/ext/oci8/object.c +727 -0
  28. data/ext/oci8/oci8.c +1156 -0
  29. data/ext/oci8/oci8.h +574 -0
  30. data/ext/oci8/oci8lib.c +527 -0
  31. data/ext/oci8/ocidatetime.c +484 -0
  32. data/ext/oci8/ocihandle.c +751 -0
  33. data/ext/oci8/ocinumber.c +1612 -0
  34. data/ext/oci8/oraconf.rb +1119 -0
  35. data/ext/oci8/oradate.c +611 -0
  36. data/ext/oci8/oranumber_util.c +352 -0
  37. data/ext/oci8/oranumber_util.h +24 -0
  38. data/ext/oci8/post-config.rb +5 -0
  39. data/ext/oci8/stmt.c +673 -0
  40. data/ext/oci8/thread_util.c +85 -0
  41. data/ext/oci8/thread_util.h +30 -0
  42. data/ext/oci8/win32.c +137 -0
  43. data/lib/.document +1 -0
  44. data/lib/dbd/OCI8.rb +591 -0
  45. data/lib/oci8.rb.in +94 -0
  46. data/lib/oci8/.document +8 -0
  47. data/lib/oci8/bindtype.rb +349 -0
  48. data/lib/oci8/compat.rb +113 -0
  49. data/lib/oci8/connection_pool.rb +99 -0
  50. data/lib/oci8/datetime.rb +611 -0
  51. data/lib/oci8/encoding-init.rb +74 -0
  52. data/lib/oci8/encoding.yml +537 -0
  53. data/lib/oci8/metadata.rb +2132 -0
  54. data/lib/oci8/object.rb +581 -0
  55. data/lib/oci8/oci8.rb +721 -0
  56. data/lib/oci8/ocihandle.rb +425 -0
  57. data/lib/oci8/oracle_version.rb +144 -0
  58. data/lib/oci8/properties.rb +73 -0
  59. data/metaconfig +142 -0
  60. data/pre-distclean.rb +7 -0
  61. data/ruby-oci8.gemspec +63 -0
  62. data/setup.rb +1331 -0
  63. data/test/README +4 -0
  64. data/test/config.rb +122 -0
  65. data/test/test_all.rb +51 -0
  66. data/test/test_appinfo.rb +63 -0
  67. data/test/test_array_dml.rb +333 -0
  68. data/test/test_bind_raw.rb +46 -0
  69. data/test/test_bind_time.rb +178 -0
  70. data/test/test_break.rb +96 -0
  71. data/test/test_clob.rb +82 -0
  72. data/test/test_connstr.rb +81 -0
  73. data/test/test_datetime.rb +582 -0
  74. data/test/test_dbi.rb +366 -0
  75. data/test/test_dbi_clob.rb +53 -0
  76. data/test/test_encoding.rb +100 -0
  77. data/test/test_error.rb +88 -0
  78. data/test/test_metadata.rb +1399 -0
  79. data/test/test_oci8.rb +434 -0
  80. data/test/test_oracle_version.rb +70 -0
  81. data/test/test_oradate.rb +256 -0
  82. data/test/test_oranumber.rb +746 -0
  83. data/test/test_rowid.rb +33 -0
  84. metadata +137 -0
@@ -0,0 +1,1612 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * ocinumber.c
4
+ *
5
+ * Copyright (C) 2005-2011 KUBO Takehiro <kubo@jiubao.org>
6
+ *
7
+ */
8
+ #include "oci8.h"
9
+ #include <orl.h>
10
+ #include <errno.h>
11
+ #include <math.h>
12
+ #include "oranumber_util.h"
13
+
14
+ #ifndef RB_NUM_COERCE_FUNCS_NEED_OPID
15
+ /* ruby 1.8 */
16
+ #define rb_num_coerce_cmp(x, y, id) rb_num_coerce_cmp((x), (y))
17
+ #define rb_num_coerce_bin(x, y, id) rb_num_coerce_bin((x), (y))
18
+ #endif
19
+
20
+ int oci8_float_conversion_type_is_ruby = 1;
21
+
22
+ #ifndef INFINITY
23
+ #define INFINITY (1.0/+0.0)
24
+ #endif
25
+
26
+ static ID id_power; /* rb_intern("**") */
27
+ static ID id_cmp; /* rb_intern("<=>") */
28
+ static ID id_finite_p;
29
+ static ID id_split;
30
+ static ID id_numerator;
31
+ static ID id_denominator;
32
+ static ID id_Rational;
33
+ static ID id_BigDecimal;
34
+
35
+ #ifndef T_RATIONAL
36
+ static VALUE cRational;
37
+ #endif
38
+ static VALUE cBigDecimal;
39
+
40
+ static VALUE cOCINumber;
41
+ static OCINumber const_p1; /* +1 */
42
+ static OCINumber const_p10; /* +10 */
43
+ static OCINumber const_m1; /* -1 */
44
+ static OCINumber const_PI2; /* +PI/2 */
45
+ static OCINumber const_mPI2; /* -PI/2 */
46
+
47
+ #define _NUMBER(val) ((OCINumber *)DATA_PTR(val)) /* dangerous macro */
48
+
49
+ #ifndef T_MASK
50
+ #define T_MASK 0x100 /* TODO: rboci8_type() should be changed to be more portable. */
51
+ #endif
52
+ #define RBOCI8_T_ORANUMBER (T_MASK + 1)
53
+ #define RBOCI8_T_BIGDECIMAL (T_MASK + 2)
54
+ #ifdef T_RATIONAL
55
+ #define RBOCI8_T_RATIONAL T_RATIONAL
56
+ #else
57
+ #define RBOCI8_T_RATIONAL (T_MASK + 3)
58
+ #endif
59
+
60
+ static int rboci8_type(VALUE obj)
61
+ {
62
+ int type = TYPE(obj);
63
+ VALUE klass;
64
+
65
+ switch (type) {
66
+ #ifndef T_RATIONAL
67
+ case T_OBJECT:
68
+ klass = CLASS_OF(obj);
69
+ if (cRational != 0) {
70
+ if (klass == cRational) {
71
+ return RBOCI8_T_RATIONAL;
72
+ }
73
+ } else {
74
+ if (strcmp(rb_class2name(klass), "Rational") == 0) {
75
+ cRational = rb_const_get(rb_cObject, id_Rational);
76
+ return RBOCI8_T_RATIONAL;
77
+ }
78
+ }
79
+ break;
80
+ #endif
81
+ case T_DATA:
82
+ klass = CLASS_OF(obj);
83
+ if (klass == cOCINumber) {
84
+ return RBOCI8_T_ORANUMBER;
85
+ }
86
+ if (cBigDecimal != 0) {
87
+ if (klass == cBigDecimal) {
88
+ return RBOCI8_T_BIGDECIMAL;
89
+ }
90
+ } else {
91
+ if (strcmp(rb_class2name(klass), "BigDecimal") == 0) {
92
+ cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
93
+ return RBOCI8_T_BIGDECIMAL;
94
+ }
95
+ }
96
+ }
97
+ return type;
98
+ }
99
+
100
+ static VALUE onum_to_f(VALUE self);
101
+ static VALUE onum_to_r(VALUE self);
102
+ static VALUE onum_to_d(VALUE self);
103
+ static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp);
104
+
105
+ static VALUE onum_s_alloc(VALUE klass)
106
+ {
107
+ VALUE obj;
108
+ OCINumber *d;
109
+
110
+ obj = Data_Make_Struct(klass, OCINumber, NULL, xfree, d);
111
+ OCINumberSetZero(oci8_errhp, d);
112
+ return obj;
113
+ }
114
+
115
+ /* construct an ruby object(OCI::Number) from C structure (OCINumber). */
116
+ VALUE oci8_make_ocinumber(OCINumber *s, OCIError *errhp)
117
+ {
118
+ VALUE obj;
119
+ OCINumber *d;
120
+
121
+ obj = Data_Make_Struct(cOCINumber, OCINumber, NULL, xfree, d);
122
+ chkerr(OCINumberAssign(errhp, s, d));
123
+ return obj;
124
+ }
125
+
126
+ VALUE oci8_make_integer(OCINumber *s, OCIError *errhp)
127
+ {
128
+ signed long sl;
129
+ char buf[512];
130
+ sword rv;
131
+
132
+ if (OCINumberToInt(errhp, s, sizeof(sl), OCI_NUMBER_SIGNED, &sl) == OCI_SUCCESS) {
133
+ return LONG2NUM(sl);
134
+ }
135
+ /* convert to Integer via String */
136
+ rv = oranumber_to_str(s, buf, sizeof(buf));
137
+ if (rv > 0) {
138
+ return rb_cstr2inum(buf, 10);
139
+ }
140
+ oranumber_dump(s, buf);
141
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
142
+ }
143
+
144
+ VALUE oci8_make_float(OCINumber *s, OCIError *errhp)
145
+ {
146
+ return rb_float_new(oci8_onum_to_dbl(s, errhp));
147
+ }
148
+
149
+ /* fill C structure (OCINumber) from a string. */
150
+ static void set_oci_number_from_str(OCINumber *result, VALUE str, VALUE fmt, VALUE nls_params, OCIError *errhp)
151
+ {
152
+ oratext *fmt_ptr;
153
+ oratext *nls_params_ptr;
154
+ ub4 fmt_len;
155
+ ub4 nls_params_len;
156
+
157
+ StringValue(str);
158
+ /* set from string. */
159
+ if (NIL_P(fmt)) {
160
+ int rv = oranumber_from_str(result, RSTRING_PTR(str), RSTRING_LEN(str));
161
+ if (rv == ORANUMBER_SUCCESS) {
162
+ return; /* success */
163
+ } else {
164
+ const char *default_msg = NULL;
165
+ switch (rv) {
166
+ case ORANUMBER_INVALID_NUMBER:
167
+ default_msg = "invalid number";
168
+ break;
169
+ case ORANUMBER_NUMERIC_OVERFLOW:
170
+ default_msg = "numeric overflow";
171
+ break;
172
+ }
173
+ oci8_raise_by_msgno(rv, default_msg);
174
+ }
175
+ }
176
+ StringValue(fmt);
177
+ fmt_ptr = RSTRING_ORATEXT(fmt);
178
+ fmt_len = RSTRING_LEN(fmt);
179
+ if (NIL_P(nls_params)) {
180
+ nls_params_ptr = NULL;
181
+ nls_params_len = 0;
182
+ } else {
183
+ StringValue(nls_params);
184
+ nls_params_ptr = RSTRING_ORATEXT(nls_params);
185
+ nls_params_len = RSTRING_LEN(nls_params);
186
+ }
187
+ chkerr(OCINumberFromText(errhp,
188
+ RSTRING_ORATEXT(str), RSTRING_LEN(str),
189
+ fmt_ptr, fmt_len, nls_params_ptr, nls_params_len,
190
+ result));
191
+ }
192
+
193
+ /* fill C structure (OCINumber) from a numeric object. */
194
+ /* 1 - success, 0 - error */
195
+ static int set_oci_number_from_num(OCINumber *result, VALUE num, int force, OCIError *errhp)
196
+ {
197
+ signed long sl;
198
+
199
+ if (!RTEST(rb_obj_is_kind_of(num, rb_cNumeric)))
200
+ rb_raise(rb_eTypeError, "expect Numeric but %s", rb_class2name(CLASS_OF(num)));
201
+ if (rb_respond_to(num, id_finite_p) && !RTEST(rb_funcall(num, id_finite_p, 0))) {
202
+ rb_raise(rb_eTypeError, "cannot accept number which isn't finite.");
203
+ }
204
+ switch (rb_type(num)) {
205
+ case T_FIXNUM:
206
+ /* set from long. */
207
+ sl = NUM2LONG(num);
208
+ chkerr(OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, result));
209
+ return 1;
210
+ case T_FLOAT:
211
+ /* set from double. */
212
+ oci8_dbl_to_onum(result, NUM2DBL(num), errhp);
213
+ return 1;
214
+ case T_BIGNUM:
215
+ /* change via string. */
216
+ num = rb_big2str(num, 10);
217
+ set_oci_number_from_str(result, num, Qnil, Qnil, errhp);
218
+ return 1;
219
+ }
220
+ if (RTEST(rb_obj_is_instance_of(num, cOCINumber))) {
221
+ /* OCI::Number */
222
+ chkerr(OCINumberAssign(errhp, DATA_PTR(num), result));
223
+ return 1;
224
+ }
225
+ if (rb_respond_to(num, id_split)) {
226
+ /* BigDecimal */
227
+ VALUE split = rb_funcall(num, id_split, 0);
228
+
229
+ if (TYPE(split) == T_ARRAY && RARRAY_LEN(split) == 4) {
230
+ /*
231
+ * sign, significant_digits, base, exponent = num.split
232
+ * onum = sign * "0.#{significant_digits}".to_f * (base ** exponent)
233
+ */
234
+ VALUE *ary = RARRAY_PTR(split);
235
+ int sign;
236
+ OCINumber digits;
237
+ int exponent;
238
+ int digits_len;
239
+ OCINumber work;
240
+
241
+ /* check sign */
242
+ if (TYPE(ary[0]) != T_FIXNUM) {
243
+ goto is_not_big_decimal;
244
+ }
245
+ sign = FIX2INT(ary[0]);
246
+ /* check digits */
247
+ StringValue(ary[1]);
248
+ digits_len = RSTRING_LEN(ary[1]);
249
+ set_oci_number_from_str(&digits, ary[1], Qnil, Qnil, errhp);
250
+ /* check base */
251
+ if (TYPE(ary[2]) != T_FIXNUM || FIX2LONG(ary[2]) != 10) {
252
+ goto is_not_big_decimal;
253
+ }
254
+ /* check exponent */
255
+ if (TYPE(ary[3]) != T_FIXNUM) {
256
+ goto is_not_big_decimal;
257
+ }
258
+ exponent = FIX2INT(ary[3]);
259
+
260
+ chkerr(OCINumberShift(errhp, &digits, exponent - digits_len, &work));
261
+ if (sign >= 0) {
262
+ chkerr(OCINumberAssign(errhp, &work, result));
263
+ } else {
264
+ chkerr(OCINumberNeg(errhp, &work, result));
265
+ }
266
+ return 1;
267
+ }
268
+ }
269
+ is_not_big_decimal:
270
+ if (rb_respond_to(num, id_numerator) && rb_respond_to(num, id_denominator)) {
271
+ /* Rational */
272
+ OCINumber numerator;
273
+ OCINumber denominator;
274
+
275
+ if (set_oci_number_from_num(&numerator, rb_funcall(num, id_numerator, 0), 0, errhp) &&
276
+ set_oci_number_from_num(&denominator, rb_funcall(num, id_denominator, 0), 0, errhp)) {
277
+ chkerr(OCINumberDiv(errhp, &numerator, &denominator, result));
278
+ return 1;
279
+ }
280
+ }
281
+ if (force) {
282
+ /* change via string as a last resort. */
283
+ /* TODO: if error, raise TypeError instead of OCI::Error */
284
+ set_oci_number_from_str(result, num, Qnil, Qnil, errhp);
285
+ return 1;
286
+ }
287
+ return 0;
288
+ }
289
+
290
+ OCINumber *oci8_set_ocinumber(OCINumber *result, VALUE self, OCIError *errhp)
291
+ {
292
+ set_oci_number_from_num(result, self, 1, errhp);
293
+ return result;
294
+ }
295
+ #define TO_OCINUM oci8_set_ocinumber
296
+
297
+ OCINumber *oci8_set_integer(OCINumber *result, VALUE self, OCIError *errhp)
298
+ {
299
+ OCINumber work;
300
+
301
+ set_oci_number_from_num(&work, self, 1, errhp);
302
+ chkerr(OCINumberTrunc(errhp, &work, 0, result));
303
+ return result;
304
+ }
305
+
306
+ double oci8_onum_to_dbl(OCINumber *s, OCIError *errhp)
307
+ {
308
+ if (oci8_float_conversion_type_is_ruby) {
309
+ char buf[256];
310
+ sword rv;
311
+
312
+ rv = oranumber_to_str(s, buf, sizeof(buf));
313
+ if (rv <= 0) {
314
+ char buf[ORANUMBER_DUMP_BUF_SIZ];
315
+
316
+ oranumber_dump(s, buf);
317
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
318
+ }
319
+ if (strcmp(buf, "~") == 0) {
320
+ return INFINITY;
321
+ } else if (strcmp(buf, "-~") == 0) {
322
+ return -INFINITY;
323
+ }
324
+ return rb_cstr_to_dbl(buf, Qtrue);
325
+ } else {
326
+ double dbl;
327
+
328
+ chkerr(OCINumberToReal(errhp, s, sizeof(double), &dbl));
329
+ return dbl;
330
+ }
331
+ }
332
+
333
+ OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp)
334
+ {
335
+ switch (fpclassify(dbl)) {
336
+ case FP_NAN:
337
+ rb_raise(rb_eFloatDomainError, "NaN");
338
+ /* never reach here */
339
+ break;
340
+ case FP_INFINITE:
341
+ if (dbl > 0.0) {
342
+ oranumber_from_str(result, "~", 1);
343
+ } else {
344
+ oranumber_from_str(result, "-~", 2);
345
+ }
346
+ return result;
347
+ }
348
+
349
+ if (oci8_float_conversion_type_is_ruby) {
350
+ VALUE str;
351
+ sword rv;
352
+
353
+ str = rb_obj_as_string(rb_float_new(dbl));
354
+ rv = oranumber_from_str(result, RSTRING_PTR(str), RSTRING_LEN(str));
355
+ if (rv != 0) {
356
+ oci8_raise_by_msgno(rv, NULL);
357
+ }
358
+ } else {
359
+ chkerr(OCINumberFromReal(errhp, &dbl, sizeof(dbl), result));
360
+ }
361
+ return result;
362
+ }
363
+
364
+ /*
365
+ * call-seq:
366
+ * OCI8::Math.atan2(y, x) -> oranumber
367
+ *
368
+ * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
369
+ * -PI..PI.
370
+ */
371
+ static VALUE omath_atan2(VALUE self, VALUE Ycoordinate, VALUE Xcoordinate)
372
+ {
373
+ OCIError *errhp = oci8_errhp;
374
+ OCINumber nY;
375
+ OCINumber nX;
376
+ OCINumber rv;
377
+ boolean is_zero;
378
+ sword sign;
379
+
380
+ set_oci_number_from_num(&nX, Xcoordinate, 1, errhp);
381
+ set_oci_number_from_num(&nY, Ycoordinate, 1, errhp);
382
+ /* check zero */
383
+ chkerr(OCINumberIsZero(errhp, &nX, &is_zero));
384
+ if (is_zero) {
385
+ chkerr(OCINumberSign(errhp, &nY, &sign));
386
+ switch (sign) {
387
+ case 0:
388
+ return INT2FIX(0); /* atan2(0, 0) => 0 or ERROR? */
389
+ case 1:
390
+ return oci8_make_ocinumber(&const_PI2, errhp); /* atan2(positive, 0) => PI/2 */
391
+ case -1:
392
+ return oci8_make_ocinumber(&const_mPI2, errhp); /* atan2(negative, 0) => -PI/2 */
393
+ }
394
+ }
395
+ /* atan2 */
396
+ chkerr(OCINumberArcTan2(errhp, &nY, &nX, &rv));
397
+ return oci8_make_ocinumber(&rv, errhp);
398
+ }
399
+
400
+ /*
401
+ * call-seq:
402
+ * OCI8::Math.cos(x) -> oranumber
403
+ *
404
+ * Computes the cosine of <i>x</i> (expressed in radians). Returns
405
+ * -1..1.
406
+ */
407
+ static VALUE omath_cos(VALUE obj, VALUE radian)
408
+ {
409
+ OCIError *errhp = oci8_errhp;
410
+ OCINumber r;
411
+ OCINumber rv;
412
+
413
+ chkerr(OCINumberCos(errhp, TO_OCINUM(&r, radian, errhp), &rv));
414
+ return oci8_make_ocinumber(&rv, errhp);
415
+ }
416
+
417
+ /*
418
+ * call-seq:
419
+ * OCI8::Math.sin(x) -> oranumber
420
+ *
421
+ * Computes the sine of <i>x</i> (expressed in radians). Returns
422
+ * -1..1.
423
+ */
424
+ static VALUE omath_sin(VALUE obj, VALUE radian)
425
+ {
426
+ OCIError *errhp = oci8_errhp;
427
+ OCINumber r;
428
+ OCINumber rv;
429
+
430
+ chkerr(OCINumberSin(errhp, TO_OCINUM(&r, radian, errhp), &rv));
431
+ return oci8_make_ocinumber(&rv, errhp);
432
+ }
433
+
434
+ /*
435
+ * call-seq:
436
+ * OCI8::Math.tan(x) -> oranumber
437
+ *
438
+ * Returns the tangent of <i>x</i> (expressed in radians).
439
+ */
440
+ static VALUE omath_tan(VALUE obj, VALUE radian)
441
+ {
442
+ OCIError *errhp = oci8_errhp;
443
+ OCINumber r;
444
+ OCINumber rv;
445
+
446
+ chkerr(OCINumberTan(errhp, TO_OCINUM(&r, radian, errhp), &rv));
447
+ return oci8_make_ocinumber(&rv, errhp);
448
+ }
449
+
450
+ /*
451
+ * call-seq:
452
+ * OCI8::Math.acos(x) -> oranumber
453
+ *
454
+ * Computes the arc cosine of <i>x</i>. Returns 0..PI.
455
+ */
456
+ static VALUE omath_acos(VALUE obj, VALUE num)
457
+ {
458
+ OCIError *errhp = oci8_errhp;
459
+ OCINumber n;
460
+ OCINumber r;
461
+ sword sign;
462
+
463
+ set_oci_number_from_num(&n, num, 1, errhp);
464
+ /* check upper bound */
465
+ chkerr(OCINumberCmp(errhp, &n, &const_p1, &sign));
466
+ if (sign > 0)
467
+ rb_raise(rb_eRangeError, "out of range for acos");
468
+ /* check lower bound */
469
+ chkerr(OCINumberCmp(errhp, &n, &const_m1, &sign));
470
+ if (sign < 0)
471
+ rb_raise(rb_eRangeError, "out of range for acos");
472
+ /* acos */
473
+ chkerr(OCINumberArcCos(errhp, &n, &r));
474
+ return oci8_make_ocinumber(&r, errhp);
475
+ }
476
+
477
+ /*
478
+ * call-seq:
479
+ * OCI8::Math.asin(x) -> oranumber
480
+ *
481
+ * Computes the arc sine of <i>x</i>. Returns 0..PI.
482
+ */
483
+ static VALUE omath_asin(VALUE obj, VALUE num)
484
+ {
485
+ OCIError *errhp = oci8_errhp;
486
+ OCINumber n;
487
+ OCINumber r;
488
+ sword sign;
489
+
490
+ set_oci_number_from_num(&n, num, 1, errhp);
491
+ /* check upper bound */
492
+ chkerr(OCINumberCmp(errhp, &n, &const_p1, &sign));
493
+ if (sign > 0)
494
+ rb_raise(rb_eRangeError, "out of range for asin");
495
+ /* check lower bound */
496
+ chkerr(OCINumberCmp(errhp, &n, &const_m1, &sign));
497
+ if (sign < 0)
498
+ rb_raise(rb_eRangeError, "out of range for asin");
499
+ /* asin */
500
+ chkerr(OCINumberArcSin(errhp, &n, &r));
501
+ return oci8_make_ocinumber(&r, errhp);
502
+ }
503
+
504
+ /*
505
+ * call-seq:
506
+ * OCI8::Math.atan(x) -> oranumber
507
+ *
508
+ * Computes the arc tangent of <i>x</i>. Returns -{PI/2} .. {PI/2}.
509
+ */
510
+ static VALUE omath_atan(VALUE obj, VALUE num)
511
+ {
512
+ OCIError *errhp = oci8_errhp;
513
+ OCINumber n;
514
+ OCINumber r;
515
+
516
+ chkerr(OCINumberArcTan(errhp, TO_OCINUM(&n, num, errhp), &r));
517
+ return oci8_make_ocinumber(&r, errhp);
518
+ }
519
+
520
+ /*
521
+ * call-seq:
522
+ * OCI8::Math.cosh(x) -> oranumber
523
+ *
524
+ * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
525
+ */
526
+ static VALUE omath_cosh(VALUE obj, VALUE num)
527
+ {
528
+ OCIError *errhp = oci8_errhp;
529
+ OCINumber n;
530
+ OCINumber r;
531
+
532
+ chkerr(OCINumberHypCos(errhp, TO_OCINUM(&n, num, errhp), &r));
533
+ return oci8_make_ocinumber(&r, errhp);
534
+ }
535
+
536
+ /*
537
+ * call-seq:
538
+ * OCI8::Math.sinh(x) -> oranumber
539
+ *
540
+ * Computes the hyperbolic sine of <i>x</i> (expressed in
541
+ * radians).
542
+ */
543
+ static VALUE omath_sinh(VALUE obj, VALUE num)
544
+ {
545
+ OCIError *errhp = oci8_errhp;
546
+ OCINumber n;
547
+ OCINumber r;
548
+
549
+ chkerr(OCINumberHypSin(errhp, TO_OCINUM(&n, num, errhp), &r));
550
+ return oci8_make_ocinumber(&r, errhp);
551
+ }
552
+
553
+ /*
554
+ * call-seq:
555
+ * OCI8::Math.tanh() -> oranumber
556
+ *
557
+ * Computes the hyperbolic tangent of <i>x</i> (expressed in
558
+ * radians).
559
+ */
560
+ static VALUE omath_tanh(VALUE obj, VALUE num)
561
+ {
562
+ OCIError *errhp = oci8_errhp;
563
+ OCINumber n;
564
+ OCINumber r;
565
+
566
+ chkerr(OCINumberHypTan(errhp, TO_OCINUM(&n, num, errhp), &r));
567
+ return oci8_make_ocinumber(&r, errhp);
568
+ }
569
+
570
+ /*
571
+ * call-seq:
572
+ * OCI8::Math.exp(x) -> oranumber
573
+ *
574
+ * Returns e**x.
575
+ */
576
+ static VALUE omath_exp(VALUE obj, VALUE num)
577
+ {
578
+ OCIError *errhp = oci8_errhp;
579
+ OCINumber n;
580
+ OCINumber r;
581
+
582
+ chkerr(OCINumberExp(errhp, TO_OCINUM(&n, num, errhp), &r));
583
+ return oci8_make_ocinumber(&r, errhp);
584
+ }
585
+
586
+ /*
587
+ * call-seq:
588
+ * OCI8::Math.log(numeric) -> oranumber
589
+ * OCI8::Math.log(numeric, base_num) -> oranumber
590
+ *
591
+ * Returns the natural logarithm of <i>numeric</i> for one argument.
592
+ * Returns the base <i>base_num</i> logarithm of <i>numeric</i> for two arguments.
593
+ */
594
+ static VALUE omath_log(int argc, VALUE *argv, VALUE obj)
595
+ {
596
+ OCIError *errhp = oci8_errhp;
597
+ VALUE num, base;
598
+ OCINumber n;
599
+ OCINumber b;
600
+ OCINumber r;
601
+ sword sign;
602
+
603
+ rb_scan_args(argc, argv, "11", &num, &base);
604
+ set_oci_number_from_num(&n, num, 1, errhp);
605
+ chkerr(OCINumberSign(errhp, &n, &sign));
606
+ if (sign <= 0)
607
+ rb_raise(rb_eRangeError, "nonpositive value for log");
608
+ if (NIL_P(base)) {
609
+ chkerr(OCINumberLn(errhp, &n, &r));
610
+ } else {
611
+ set_oci_number_from_num(&b, base, 1, errhp);
612
+ chkerr(OCINumberSign(errhp, &b, &sign));
613
+ if (sign <= 0)
614
+ rb_raise(rb_eRangeError, "nonpositive value for the base of log");
615
+ chkerr(OCINumberCmp(errhp, &b, &const_p1, &sign));
616
+ if (sign == 0)
617
+ rb_raise(rb_eRangeError, "base 1 for log");
618
+ chkerr(OCINumberLog(errhp, &b, &n, &r));
619
+ }
620
+ return oci8_make_ocinumber(&r, errhp);
621
+ }
622
+
623
+ /*
624
+ * call-seq:
625
+ * OCI8::Math.log10(numeric) -> oranumber
626
+ *
627
+ * Returns the base 10 logarithm of <i>numeric</i>.
628
+ */
629
+ static VALUE omath_log10(VALUE obj, VALUE num)
630
+ {
631
+ OCIError *errhp = oci8_errhp;
632
+ OCINumber n;
633
+ OCINumber r;
634
+ sword sign;
635
+
636
+ set_oci_number_from_num(&n, num, 1, errhp);
637
+ chkerr(OCINumberSign(errhp, &n, &sign));
638
+ if (sign <= 0)
639
+ rb_raise(rb_eRangeError, "nonpositive value for log10");
640
+ chkerr(OCINumberLog(errhp, &const_p10, &n, &r));
641
+ return oci8_make_ocinumber(&r, errhp);
642
+ }
643
+
644
+ /*
645
+ * call-seq:
646
+ * OCI8::Math.sqrt(numeric) -> oranumber
647
+ *
648
+ * Returns the non-negative square root of <i>numeric</i>.
649
+ */
650
+ static VALUE omath_sqrt(VALUE obj, VALUE num)
651
+ {
652
+ OCIError *errhp = oci8_errhp;
653
+ OCINumber n;
654
+ OCINumber r;
655
+ sword sign;
656
+
657
+ set_oci_number_from_num(&n, num, 1, errhp);
658
+ /* check whether num is negative */
659
+ chkerr(OCINumberSign(errhp, &n, &sign));
660
+ if (sign < 0) {
661
+ errno = EDOM;
662
+ rb_sys_fail("sqrt");
663
+ }
664
+ chkerr(OCINumberSqrt(errhp, &n, &r));
665
+ return oci8_make_ocinumber(&r, errhp);
666
+ }
667
+
668
+
669
+ /*
670
+ * call-seq:
671
+ * OraNumber(obj) -> oranumber
672
+ *
673
+ * Returns a new <code>OraNumber</code>.
674
+ */
675
+ static VALUE onum_f_new(int argc, VALUE *argv, VALUE self)
676
+ {
677
+ VALUE obj = rb_obj_alloc(cOCINumber);
678
+ rb_obj_call_init(obj, argc, argv);
679
+ return obj;
680
+ }
681
+
682
+ static VALUE onum_initialize(int argc, VALUE *argv, VALUE self)
683
+ {
684
+ OCIError *errhp = oci8_errhp;
685
+ VALUE val;
686
+ VALUE fmt;
687
+ VALUE nls_params;
688
+
689
+ if (rb_scan_args(argc, argv, "03", &val /* 0 */, &fmt /* nil */, &nls_params /* nil */) == 0) {
690
+ OCINumberSetZero(errhp, _NUMBER(self));
691
+ } else if (RTEST(rb_obj_is_kind_of(val, rb_cNumeric))) {
692
+ set_oci_number_from_num(_NUMBER(self), val, 1, errhp);
693
+ } else {
694
+ set_oci_number_from_str(_NUMBER(self), val, fmt, nls_params, errhp);
695
+ }
696
+ return Qnil;
697
+ }
698
+
699
+ static VALUE onum_initialize_copy(VALUE lhs, VALUE rhs)
700
+ {
701
+ if (!RTEST(rb_obj_is_instance_of(rhs, CLASS_OF(lhs)))) {
702
+ rb_raise(rb_eTypeError, "invalid type: expected %s but %s",
703
+ rb_class2name(CLASS_OF(lhs)), rb_class2name(CLASS_OF(rhs)));
704
+ }
705
+ chkerr(OCINumberAssign(oci8_errhp, _NUMBER(rhs), _NUMBER(lhs)));
706
+ return lhs;
707
+ }
708
+
709
+ static VALUE onum_coerce(VALUE self, VALUE other)
710
+ {
711
+ signed long sl;
712
+ OCINumber n;
713
+
714
+ switch(rboci8_type(other)) {
715
+ case T_FIXNUM:
716
+ sl = NUM2LONG(other);
717
+ chkerr(OCINumberFromInt(oci8_errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &n));
718
+ return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self);
719
+ case T_BIGNUM:
720
+ /* change via string. */
721
+ other = rb_big2str(other, 10);
722
+ set_oci_number_from_str(&n, other, Qnil, Qnil, oci8_errhp);
723
+ return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self);
724
+ case T_FLOAT:
725
+ return rb_assoc_new(other, onum_to_f(self));
726
+ case RBOCI8_T_RATIONAL:
727
+ return rb_assoc_new(other, onum_to_r(self));
728
+ case RBOCI8_T_BIGDECIMAL:
729
+ return rb_assoc_new(other, onum_to_d(self));
730
+ }
731
+ rb_raise(rb_eTypeError, "Can't coerce %s to %s",
732
+ rb_class2name(CLASS_OF(other)), rb_class2name(cOCINumber));
733
+ }
734
+
735
+ /*
736
+ * call-seq:
737
+ * -onum -> oranumber
738
+ *
739
+ * Returns a negated <code>OraNumber</code>.
740
+ */
741
+ static VALUE onum_neg(VALUE self)
742
+ {
743
+ OCIError *errhp = oci8_errhp;
744
+ OCINumber r;
745
+
746
+ chkerr(OCINumberNeg(errhp, _NUMBER(self), &r));
747
+ return oci8_make_ocinumber(&r, errhp);
748
+ }
749
+
750
+
751
+ /*
752
+ * call-seq:
753
+ * onum + other -> number
754
+ *
755
+ * Returns the sum of <i>onum</i> and <i>other</i>.
756
+ */
757
+ static VALUE onum_add(VALUE lhs, VALUE rhs)
758
+ {
759
+ OCIError *errhp = oci8_errhp;
760
+ OCINumber n;
761
+ OCINumber r;
762
+
763
+ switch (rboci8_type(rhs)) {
764
+ case T_FIXNUM:
765
+ case T_BIGNUM:
766
+ if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
767
+ chkerr(OCINumberAdd(errhp, _NUMBER(lhs), &n, &r));
768
+ return oci8_make_ocinumber(&r, errhp);
769
+ }
770
+ break;
771
+ case RBOCI8_T_ORANUMBER:
772
+ chkerr(OCINumberAdd(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
773
+ return oci8_make_ocinumber(&r, errhp);
774
+ case T_FLOAT:
775
+ return rb_funcall(onum_to_f(lhs), oci8_id_add_op, 1, rhs);
776
+ case RBOCI8_T_RATIONAL:
777
+ return rb_funcall(onum_to_r(lhs), oci8_id_add_op, 1, rhs);
778
+ case RBOCI8_T_BIGDECIMAL:
779
+ return rb_funcall(onum_to_d(lhs), oci8_id_add_op, 1, rhs);
780
+ }
781
+ return rb_num_coerce_bin(lhs, rhs, oci8_id_add_op);
782
+ }
783
+
784
+ /*
785
+ * call-seq:
786
+ * onum - integer -> oranumber
787
+ * onum - numeric -> numeric
788
+ *
789
+ * Returns the difference of <i>onum</i> and <i>other</i>.
790
+ */
791
+ static VALUE onum_sub(VALUE lhs, VALUE rhs)
792
+ {
793
+ OCIError *errhp = oci8_errhp;
794
+ OCINumber n;
795
+ OCINumber r;
796
+
797
+ switch (rboci8_type(rhs)) {
798
+ case T_FIXNUM:
799
+ case T_BIGNUM:
800
+ if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
801
+ chkerr(OCINumberSub(errhp, _NUMBER(lhs), &n, &r));
802
+ return oci8_make_ocinumber(&r, errhp);
803
+ }
804
+ break;
805
+ case RBOCI8_T_ORANUMBER:
806
+ chkerr(OCINumberSub(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
807
+ return oci8_make_ocinumber(&r, errhp);
808
+ case T_FLOAT:
809
+ return rb_funcall(onum_to_f(lhs), oci8_id_sub_op, 1, rhs);
810
+ case RBOCI8_T_RATIONAL:
811
+ return rb_funcall(onum_to_r(lhs), oci8_id_sub_op, 1, rhs);
812
+ case RBOCI8_T_BIGDECIMAL:
813
+ return rb_funcall(onum_to_d(lhs), oci8_id_sub_op, 1, rhs);
814
+ }
815
+ return rb_num_coerce_bin(lhs, rhs, oci8_id_sub_op);
816
+ }
817
+
818
+ /*
819
+ * call-seq:
820
+ * onum * other -> number
821
+ *
822
+ * Returns the product of <i>onum</i> and <i>other</i>.
823
+ */
824
+ static VALUE onum_mul(VALUE lhs, VALUE rhs)
825
+ {
826
+ OCIError *errhp = oci8_errhp;
827
+ OCINumber n;
828
+ OCINumber r;
829
+
830
+ switch (rboci8_type(rhs)) {
831
+ case T_FIXNUM:
832
+ case T_BIGNUM:
833
+ if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
834
+ chkerr(OCINumberMul(errhp, _NUMBER(lhs), &n, &r));
835
+ return oci8_make_ocinumber(&r, errhp);
836
+ }
837
+ break;
838
+ case RBOCI8_T_ORANUMBER:
839
+ chkerr(OCINumberMul(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
840
+ return oci8_make_ocinumber(&r, errhp);
841
+ case T_FLOAT:
842
+ return rb_funcall(onum_to_f(lhs), oci8_id_mul_op, 1, rhs);
843
+ case RBOCI8_T_RATIONAL:
844
+ return rb_funcall(onum_to_r(lhs), oci8_id_mul_op, 1, rhs);
845
+ case RBOCI8_T_BIGDECIMAL:
846
+ return rb_funcall(onum_to_d(lhs), oci8_id_mul_op, 1, rhs);
847
+ }
848
+ return rb_num_coerce_bin(lhs, rhs, oci8_id_mul_op);
849
+ }
850
+
851
+ /*
852
+ * call-seq:
853
+ * onum / integer -> oranumber
854
+ * onum / numeric -> numeric
855
+ *
856
+ * Returns the result of dividing <i>onum</i> by <i>other</i>.
857
+ */
858
+ static VALUE onum_div(VALUE lhs, VALUE rhs)
859
+ {
860
+ OCIError *errhp = oci8_errhp;
861
+ OCINumber n;
862
+ OCINumber r;
863
+ boolean is_zero;
864
+
865
+ switch (rboci8_type(rhs)) {
866
+ case T_FIXNUM:
867
+ if (rhs == INT2FIX(0)) {
868
+ rb_num_zerodiv();
869
+ }
870
+ case T_BIGNUM:
871
+ if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
872
+ chkerr(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r));
873
+ return oci8_make_ocinumber(&r, errhp);
874
+ }
875
+ break;
876
+ case RBOCI8_T_ORANUMBER:
877
+ chkerr(OCINumberIsZero(errhp, _NUMBER(rhs), &is_zero));
878
+ if (is_zero) {
879
+ rb_num_zerodiv();
880
+ }
881
+ chkerr(OCINumberDiv(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
882
+ return oci8_make_ocinumber(&r, errhp);
883
+ case T_FLOAT:
884
+ return rb_funcall(onum_to_f(lhs), oci8_id_div_op, 1, rhs);
885
+ case RBOCI8_T_RATIONAL:
886
+ return rb_funcall(onum_to_r(lhs), oci8_id_div_op, 1, rhs);
887
+ case RBOCI8_T_BIGDECIMAL:
888
+ return rb_funcall(onum_to_d(lhs), oci8_id_div_op, 1, rhs);
889
+ }
890
+ return rb_num_coerce_bin(lhs, rhs, oci8_id_div_op);
891
+ }
892
+
893
+ /*
894
+ * call-seq:
895
+ * onum % other -> oranumber
896
+ *
897
+ * Returns the modulo after division of <i>onum</i> by <i>other</i>.
898
+ */
899
+ static VALUE onum_mod(VALUE lhs, VALUE rhs)
900
+ {
901
+ OCIError *errhp = oci8_errhp;
902
+ OCINumber n;
903
+ OCINumber r;
904
+ boolean is_zero;
905
+
906
+ /* change to OCINumber */
907
+ if (!set_oci_number_from_num(&n, rhs, 0, errhp))
908
+ return rb_num_coerce_bin(lhs, rhs, '%');
909
+ /* check whether argument is not zero. */
910
+ chkerr(OCINumberIsZero(errhp, &n, &is_zero));
911
+ if (is_zero)
912
+ rb_num_zerodiv();
913
+ /* modulo */
914
+ chkerr(OCINumberMod(errhp, _NUMBER(lhs), &n, &r));
915
+ return oci8_make_ocinumber(&r, errhp);
916
+ }
917
+
918
+ /*
919
+ * call-seq:
920
+ * onum ** other -> oranumber
921
+ *
922
+ * Raises <i>onum</i> the <i>other</i> power.
923
+ */
924
+ static VALUE onum_power(VALUE lhs, VALUE rhs)
925
+ {
926
+ OCIError *errhp = oci8_errhp;
927
+ OCINumber n;
928
+ OCINumber r;
929
+
930
+ if (FIXNUM_P(rhs)) {
931
+ chkerr(OCINumberIntPower(errhp, _NUMBER(lhs), FIX2INT(rhs), &r));
932
+ } else {
933
+ /* change to OCINumber */
934
+ if (!set_oci_number_from_num(&n, rhs, 0, errhp))
935
+ return rb_num_coerce_bin(lhs, rhs, id_power);
936
+ chkerr(OCINumberPower(errhp, _NUMBER(lhs), &n, &r));
937
+ }
938
+ return oci8_make_ocinumber(&r, errhp);
939
+ }
940
+
941
+ /*
942
+ * call-seq:
943
+ * onum <=> other -> -1, 0, +1
944
+ *
945
+ * Returns -1, 0, or +1 depending on whether <i>onum</i> is less than,
946
+ * equal to, or greater than <i>other</i>. This is the basis for the
947
+ * tests in <code>Comparable</code>.
948
+ */
949
+ static VALUE onum_cmp(VALUE lhs, VALUE rhs)
950
+ {
951
+ OCIError *errhp = oci8_errhp;
952
+ OCINumber n;
953
+ sword r;
954
+
955
+ /* change to OCINumber */
956
+ if (!set_oci_number_from_num(&n, rhs, 0, errhp))
957
+ return rb_num_coerce_cmp(lhs, rhs, id_cmp);
958
+ /* compare */
959
+ chkerr(OCINumberCmp(errhp, _NUMBER(lhs), &n, &r));
960
+ if (r > 0) {
961
+ return INT2FIX(1);
962
+ } else if (r == 0) {
963
+ return INT2FIX(0);
964
+ } else {
965
+ return INT2FIX(-1);
966
+ }
967
+ }
968
+
969
+ /*
970
+ * call-seq:
971
+ * onum.floor -> integer
972
+ *
973
+ * Returns the largest <code>Integer</code> less than or equal to <i>onum</i>.
974
+ */
975
+ static VALUE onum_floor(VALUE self)
976
+ {
977
+ OCIError *errhp = oci8_errhp;
978
+ OCINumber r;
979
+
980
+ chkerr(OCINumberFloor(errhp, _NUMBER(self), &r));
981
+ return oci8_make_integer(&r, errhp);
982
+ }
983
+
984
+ /*
985
+ * call-seq:
986
+ * onum.ceil -> integer
987
+ *
988
+ * Returns the smallest <code>Integer</code> greater than or equal to
989
+ * <i>onum</i>.
990
+ */
991
+ static VALUE onum_ceil(VALUE self)
992
+ {
993
+ OCIError *errhp = oci8_errhp;
994
+ OCINumber r;
995
+
996
+ chkerr(OCINumberCeil(errhp, _NUMBER(self), &r));
997
+ return oci8_make_integer(&r, errhp);
998
+ }
999
+
1000
+ /*
1001
+ * call-seq:
1002
+ * onum.round -> integer
1003
+ * onum.round(decplace) -> oranumber
1004
+ *
1005
+ * Rounds <i>onum</i> to the nearest <code>Integer</code> when no argument.
1006
+ * Rounds <i>onum</i> to a specified decimal place <i>decplace</i> when one argument.
1007
+ *
1008
+ * OraNumber.new(1.234).round(1) #=> 1.2
1009
+ * OraNumber.new(1.234).round(2) #=> 1.23
1010
+ * OraNumber.new(1.234).round(3) #=> 1.234
1011
+ */
1012
+ static VALUE onum_round(int argc, VALUE *argv, VALUE self)
1013
+ {
1014
+ OCIError *errhp = oci8_errhp;
1015
+ VALUE decplace;
1016
+ OCINumber r;
1017
+
1018
+ rb_scan_args(argc, argv, "01", &decplace /* 0 */);
1019
+ chkerr(OCINumberRound(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r));
1020
+ if (argc == 0) {
1021
+ return oci8_make_integer(&r, errhp);
1022
+ } else {
1023
+ return oci8_make_ocinumber(&r, errhp);
1024
+ }
1025
+ }
1026
+
1027
+ /*
1028
+ * call-seq:
1029
+ * onum.truncate -> integer
1030
+ * onum.truncate(decplace) -> oranumber
1031
+ *
1032
+ * Truncates <i>onum</i> to the <code>Integer</code> when no argument.
1033
+ * Truncates <i>onum</i> to a specified decimal place <i>decplace</i> when one argument.
1034
+ */
1035
+ static VALUE onum_trunc(int argc, VALUE *argv, VALUE self)
1036
+ {
1037
+ OCIError *errhp = oci8_errhp;
1038
+ VALUE decplace;
1039
+ OCINumber r;
1040
+
1041
+ rb_scan_args(argc, argv, "01", &decplace /* 0 */);
1042
+ chkerr(OCINumberTrunc(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r));
1043
+ return oci8_make_ocinumber(&r, errhp);
1044
+ }
1045
+
1046
+ /*
1047
+ * call-seq:
1048
+ * onum.round_prec(digits) -> oranumber
1049
+ *
1050
+ * Rounds <i>onum</i> to a specified number of decimal digits.
1051
+ * This method is available on Oracle 8.1 client or upper.
1052
+ *
1053
+ * OraNumber.new(1.234).round_prec(2) #=> 1.2
1054
+ * OraNumber.new(12.34).round_prec(2) #=> 12
1055
+ * OraNumber.new(123.4).round_prec(2) #=> 120
1056
+ */
1057
+ static VALUE onum_round_prec(VALUE self, VALUE ndigs)
1058
+ {
1059
+ OCIError *errhp = oci8_errhp;
1060
+ OCINumber r;
1061
+
1062
+ chkerr(OCINumberPrec(errhp, _NUMBER(self), NUM2INT(ndigs), &r));
1063
+ return oci8_make_ocinumber(&r, errhp);
1064
+ }
1065
+
1066
+ /*
1067
+ * call-seq:
1068
+ * onum.to_char(fmt = nil, nls_params = nil) -> string
1069
+ *
1070
+ * Returns a string containing a representation of self.
1071
+ * <i>fmt</i> and <i>nls_params</i> are same meanings with
1072
+ * <code>TO_CHAR</code> of Oracle function.
1073
+ */
1074
+ static VALUE onum_to_char(int argc, VALUE *argv, VALUE self)
1075
+ {
1076
+ OCIError *errhp = oci8_errhp;
1077
+ VALUE fmt;
1078
+ VALUE nls_params;
1079
+ char buf[512];
1080
+ ub4 buf_size = sizeof(buf);
1081
+ oratext *fmt_ptr;
1082
+ oratext *nls_params_ptr;
1083
+ ub4 fmt_len;
1084
+ ub4 nls_params_len;
1085
+ sword rv;
1086
+
1087
+ rb_scan_args(argc, argv, "02", &fmt /* nil */, &nls_params /* nil */);
1088
+ if (NIL_P(fmt)) {
1089
+ rv = oranumber_to_str(_NUMBER(self), buf, sizeof(buf));
1090
+ if (rv > 0) {
1091
+ return rb_usascii_str_new(buf, rv);
1092
+ }
1093
+ oranumber_dump(_NUMBER(self), buf);
1094
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
1095
+ }
1096
+ StringValue(fmt);
1097
+ fmt_ptr = RSTRING_ORATEXT(fmt);
1098
+ fmt_len = RSTRING_LEN(fmt);
1099
+ if (NIL_P(nls_params)) {
1100
+ nls_params_ptr = NULL;
1101
+ nls_params_len = 0;
1102
+ } else {
1103
+ StringValue(nls_params);
1104
+ nls_params_ptr = RSTRING_ORATEXT(nls_params);
1105
+ nls_params_len = RSTRING_LEN(nls_params);
1106
+ }
1107
+ rv = OCINumberToText(errhp, _NUMBER(self),
1108
+ fmt_ptr, fmt_len, nls_params_ptr, nls_params_len,
1109
+ &buf_size, TO_ORATEXT(buf));
1110
+ if (rv == OCI_ERROR) {
1111
+ sb4 errcode;
1112
+ OCIErrorGet(errhp, 1, NULL, &errcode, NULL, 0, OCI_HTYPE_ERROR);
1113
+ if (errcode == 22065) {
1114
+ /* OCI-22065: number to text translation for the given format causes overflow */
1115
+ if (NIL_P(fmt)) /* implicit conversion */
1116
+ return rb_usascii_str_new_cstr("overflow");
1117
+ }
1118
+ chkerr(rv);
1119
+ }
1120
+ return rb_usascii_str_new(buf, buf_size);
1121
+ }
1122
+
1123
+ /*
1124
+ * call-seq:
1125
+ * onum.to_s -> string
1126
+ *
1127
+ * Returns a string containing a representation of self.
1128
+ */
1129
+ static VALUE onum_to_s(VALUE self)
1130
+ {
1131
+ return onum_to_char(0, NULL, self);
1132
+ }
1133
+
1134
+ /*
1135
+ * call-seq:
1136
+ * onum.to_i -> integer
1137
+ *
1138
+ * Returns <i>onum</i> truncated to an <code>Integer</code>.
1139
+ */
1140
+ static VALUE onum_to_i(VALUE self)
1141
+ {
1142
+ OCIError *errhp = oci8_errhp;
1143
+ OCINumber num;
1144
+
1145
+ chkerr(OCINumberTrunc(errhp, _NUMBER(self), 0, &num));
1146
+ return oci8_make_integer(&num, errhp);
1147
+ }
1148
+
1149
+ /*
1150
+ * call-seq:
1151
+ * onum.to_f -> float
1152
+ *
1153
+ * Return the value as a <code>Float</code>.
1154
+ *
1155
+ */
1156
+ static VALUE onum_to_f(VALUE self)
1157
+ {
1158
+ return rb_float_new(oci8_onum_to_dbl(_NUMBER(self), oci8_errhp));
1159
+ }
1160
+
1161
+ /*
1162
+ * call-seq:
1163
+ * onum.to_r -> rational
1164
+ *
1165
+ * Return the value as a <code>Rational</code>.
1166
+ *
1167
+ */
1168
+ static VALUE onum_to_r(VALUE self)
1169
+ {
1170
+ VALUE x, y;
1171
+ int nshift = 0;
1172
+ OCINumber onum[2];
1173
+ int current = 0;
1174
+ boolean is_int;
1175
+
1176
+ chkerr(OCINumberAssign(oci8_errhp, _NUMBER(self), &onum[0]));
1177
+
1178
+ for (;;) {
1179
+ chkerr(OCINumberIsInt(oci8_errhp, &onum[current], &is_int));
1180
+ if (is_int) {
1181
+ break;
1182
+ }
1183
+ nshift++;
1184
+ chkerr(OCINumberShift(oci8_errhp, &onum[current], 1, &onum[1 - current]));
1185
+ current = 1 - current;
1186
+ }
1187
+ x = oci8_make_integer(&onum[current], oci8_errhp);
1188
+ if (nshift == 0) {
1189
+ y = INT2FIX(1);
1190
+ } else {
1191
+ y = rb_funcall(INT2FIX(10), rb_intern("**"), 1, INT2FIX(nshift));
1192
+ }
1193
+ #ifdef T_RATIONAL
1194
+ return rb_Rational(x, y);
1195
+ #else
1196
+ if (!cRational) {
1197
+ rb_require("rational");
1198
+ cRational = rb_const_get(rb_cObject, id_Rational);
1199
+ }
1200
+ return rb_funcall(rb_cObject, id_Rational, 2, x, y);
1201
+ #endif
1202
+ }
1203
+
1204
+ /*
1205
+ * call-seq:
1206
+ * onum.to_d -> bigdecimal
1207
+ *
1208
+ * Return the value as a <code>BigDecimal</code>.
1209
+ *
1210
+ */
1211
+ static VALUE onum_to_d(VALUE self)
1212
+ {
1213
+ return onum_to_d_real(_NUMBER(self), oci8_errhp);
1214
+ }
1215
+
1216
+ /* Converts to BigDecimal via number in scientific notation */
1217
+ static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp)
1218
+ {
1219
+ char buf[64];
1220
+ ub4 buf_size = sizeof(buf);
1221
+ const char *fmt = "FM9.99999999999999999999999999999999999999EEEE";
1222
+
1223
+ if (!cBigDecimal) {
1224
+ rb_require("bigdecimal");
1225
+ cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
1226
+ }
1227
+ chkerr(OCINumberToText(errhp, num, (const oratext *)fmt, strlen(fmt),
1228
+ NULL, 0, &buf_size, TO_ORATEXT(buf)));
1229
+ return rb_funcall(rb_cObject, id_BigDecimal, 1, rb_usascii_str_new(buf, buf_size));
1230
+ }
1231
+
1232
+ /*
1233
+ * call-seq:
1234
+ * onum.has_decimal_part? -> true or false
1235
+ *
1236
+ * Returns +true+ if <i>self</i> has a decimal part.
1237
+ *
1238
+ * OraNumber(10).has_decimal_part? # => false
1239
+ * OraNumber(10.1).has_decimal_part? # => true
1240
+ */
1241
+ static VALUE onum_has_decimal_part_p(VALUE self)
1242
+ {
1243
+ OCIError *errhp = oci8_errhp;
1244
+ boolean result;
1245
+
1246
+ chkerr(OCINumberIsInt(errhp, _NUMBER(self), &result));
1247
+ return result ? Qfalse : Qtrue;
1248
+ }
1249
+
1250
+ /*
1251
+ * call-seq:
1252
+ * onum.to_onum -> oranumber
1253
+ *
1254
+ * Returns self.
1255
+ *
1256
+ */
1257
+ static VALUE onum_to_onum(VALUE self)
1258
+ {
1259
+ return self;
1260
+ }
1261
+
1262
+ /*
1263
+ * call-seq:
1264
+ * onum.zero? -> true or false
1265
+ *
1266
+ * Returns <code>true</code> if <i>onum</i> is zero.
1267
+ *
1268
+ */
1269
+ static VALUE onum_zero_p(VALUE self)
1270
+ {
1271
+ OCIError *errhp = oci8_errhp;
1272
+ boolean result;
1273
+
1274
+ chkerr(OCINumberIsZero(errhp, _NUMBER(self), &result));
1275
+ return result ? Qtrue : Qfalse;
1276
+ }
1277
+
1278
+ /*
1279
+ * call-seq:
1280
+ * onum.abs -> oranumber
1281
+ *
1282
+ * Returns the absolute value of <i>onum</i>.
1283
+ *
1284
+ */
1285
+ static VALUE onum_abs(VALUE self)
1286
+ {
1287
+ OCIError *errhp = oci8_errhp;
1288
+ OCINumber result;
1289
+
1290
+ chkerr(OCINumberAbs(errhp, _NUMBER(self), &result));
1291
+ return oci8_make_ocinumber(&result, errhp);
1292
+ }
1293
+
1294
+ /*
1295
+ * call-seq:
1296
+ * onum.shift(fixnum) -> oranumber
1297
+ *
1298
+ * Returns <i>onum</i> * 10**<i>fixnum</i>
1299
+ * This method is available on Oracle 8.1 client or upper.
1300
+ */
1301
+ static VALUE onum_shift(VALUE self, VALUE exp)
1302
+ {
1303
+ OCIError *errhp = oci8_errhp;
1304
+ OCINumber result;
1305
+
1306
+ chkerr(OCINumberShift(errhp, _NUMBER(self), NUM2INT(exp), &result));
1307
+ return oci8_make_ocinumber(&result, errhp);
1308
+ }
1309
+
1310
+ /*
1311
+ * call-seq:
1312
+ * onum.dump -> string
1313
+ *
1314
+ * Returns internal representation whose format is same with
1315
+ * the return value of Oracle SQL function DUMP().
1316
+ *
1317
+ * OraNumber.new(100).dump #=> "Typ=2 Len=2: 194,2"
1318
+ * OraNumber.new(123).dump #=> "Typ=2 Len=3: 194,2,24"
1319
+ * OraNumber.new(0.1).dump #=> "Typ=2 Len=2: 192,11"
1320
+ */
1321
+ static VALUE onum_dump(VALUE self)
1322
+ {
1323
+ char buf[ORANUMBER_DUMP_BUF_SIZ];
1324
+ int rv = oranumber_dump(_NUMBER(self), buf);
1325
+ return rb_usascii_str_new(buf, rv);
1326
+ }
1327
+
1328
+ static VALUE onum_hash(VALUE self)
1329
+ {
1330
+ char *c = DATA_PTR(self);
1331
+ int size = c[0] + 1;
1332
+ long i, hash;
1333
+
1334
+ /* assert(size <= 22); ?*/
1335
+ if (size > 22)
1336
+ size = 22;
1337
+
1338
+ for (hash = 0, i = 1; i< size; i++) {
1339
+ hash += c[i] * 971;
1340
+ }
1341
+ if (hash < 0) hash = -hash;
1342
+ return INT2FIX(hash);
1343
+ }
1344
+
1345
+ static VALUE onum_inspect(VALUE self)
1346
+ {
1347
+ const char *name = rb_class2name(CLASS_OF(self));
1348
+ volatile VALUE s = onum_to_s(self);
1349
+ size_t len = strlen(name) + RSTRING_LEN(s) + 5;
1350
+ char *str = ALLOCA_N(char, len);
1351
+
1352
+ snprintf(str, len, "#<%s:%s>", name, RSTRING_PTR(s));
1353
+ str[len - 1] = '\0';
1354
+ return rb_usascii_str_new_cstr(str);
1355
+ }
1356
+
1357
+ /*
1358
+ * call-seq:
1359
+ * onum._dump -> string
1360
+ *
1361
+ * Dump <i>onum</i> for marshaling.
1362
+ */
1363
+ static VALUE onum__dump(int argc, VALUE *argv, VALUE self)
1364
+ {
1365
+ char *c = DATA_PTR(self);
1366
+ int size = c[0] + 1;
1367
+ VALUE dummy;
1368
+
1369
+ rb_scan_args(argc, argv, "01", &dummy);
1370
+ return rb_str_new(c, size);
1371
+ }
1372
+
1373
+ /*
1374
+ * call-seq:
1375
+ * OraNumber._load(string) -> oranumber
1376
+ *
1377
+ * Unmarshal a dumped <code>OraNumber</code> object.
1378
+ */
1379
+ static VALUE
1380
+ onum_s_load(VALUE klass, VALUE str)
1381
+ {
1382
+ unsigned char *c;
1383
+ int size;
1384
+ OCINumber num;
1385
+
1386
+ Check_Type(str, T_STRING);
1387
+ c = RSTRING_ORATEXT(str);
1388
+ size = RSTRING_LEN(str);
1389
+ if (size == 0 || size != c[0] + 1 || size > sizeof(num)) {
1390
+ rb_raise(rb_eTypeError, "marshaled OCI::Number format differ");
1391
+ }
1392
+ memset(&num, 0, sizeof(num));
1393
+ memcpy(&num, c, size);
1394
+ return oci8_make_ocinumber(&num, oci8_errhp);
1395
+ }
1396
+
1397
+ /*
1398
+ * bind_ocinumber
1399
+ */
1400
+ static VALUE bind_ocinumber_get(oci8_bind_t *obind, void *data, void *null_struct)
1401
+ {
1402
+ return oci8_make_ocinumber((OCINumber*)data, oci8_errhp);
1403
+ }
1404
+
1405
+ static VALUE bind_integer_get(oci8_bind_t *obind, void *data, void *null_struct)
1406
+ {
1407
+ return oci8_make_integer((OCINumber*)data, oci8_errhp);
1408
+ }
1409
+
1410
+ static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
1411
+ {
1412
+ return oci8_make_float((OCINumber*)data, oci8_errhp);
1413
+ }
1414
+
1415
+ static void bind_ocinumber_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
1416
+ {
1417
+ set_oci_number_from_num((OCINumber*)data, val, 1, oci8_errhp);
1418
+ }
1419
+
1420
+ static void bind_integer_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
1421
+ {
1422
+ OCIError *errhp = oci8_errhp;
1423
+ OCINumber num;
1424
+
1425
+ set_oci_number_from_num(&num, val, 1, errhp);
1426
+ chker2(OCINumberTrunc(errhp, &num, 0, (OCINumber*)data),
1427
+ &obind->base);
1428
+ }
1429
+
1430
+ static void bind_ocinumber_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
1431
+ {
1432
+ obind->value_sz = sizeof(OCINumber);
1433
+ obind->alloc_sz = sizeof(OCINumber);
1434
+ }
1435
+
1436
+ static void bind_ocinumber_init_elem(oci8_bind_t *obind, VALUE svc)
1437
+ {
1438
+ OCIError *errhp = oci8_errhp;
1439
+ ub4 idx = 0;
1440
+
1441
+ do {
1442
+ OCINumberSetZero(errhp, (OCINumber*)obind->valuep + idx);
1443
+ } while (++idx < obind->maxar_sz);
1444
+ }
1445
+
1446
+ static const oci8_bind_vtable_t bind_ocinumber_vtable = {
1447
+ {
1448
+ NULL,
1449
+ oci8_bind_free,
1450
+ sizeof(oci8_bind_t)
1451
+ },
1452
+ bind_ocinumber_get,
1453
+ bind_ocinumber_set,
1454
+ bind_ocinumber_init,
1455
+ bind_ocinumber_init_elem,
1456
+ NULL,
1457
+ SQLT_VNU,
1458
+ };
1459
+
1460
+ static const oci8_bind_vtable_t bind_integer_vtable = {
1461
+ {
1462
+ NULL,
1463
+ oci8_bind_free,
1464
+ sizeof(oci8_bind_t)
1465
+ },
1466
+ bind_integer_get,
1467
+ bind_integer_set,
1468
+ bind_ocinumber_init,
1469
+ bind_ocinumber_init_elem,
1470
+ NULL,
1471
+ SQLT_VNU,
1472
+ };
1473
+
1474
+ static const oci8_bind_vtable_t bind_float_vtable = {
1475
+ {
1476
+ NULL,
1477
+ oci8_bind_free,
1478
+ sizeof(oci8_bind_t)
1479
+ },
1480
+ bind_float_get,
1481
+ bind_ocinumber_set,
1482
+ bind_ocinumber_init,
1483
+ bind_ocinumber_init_elem,
1484
+ NULL,
1485
+ SQLT_VNU,
1486
+ };
1487
+
1488
+ void
1489
+ Init_oci_number(VALUE cOCI8, OCIError *errhp)
1490
+ {
1491
+ VALUE mMath;
1492
+ OCINumber num1, num2;
1493
+ VALUE obj_PI;
1494
+ signed long sl;
1495
+
1496
+ id_power = rb_intern("**");
1497
+ id_cmp = rb_intern("<=>");
1498
+ id_finite_p = rb_intern("finite?");
1499
+ id_split = rb_intern("split");
1500
+ id_numerator = rb_intern("numerator");
1501
+ id_denominator = rb_intern("denominator");
1502
+ id_Rational = rb_intern("Rational");
1503
+ id_BigDecimal = rb_intern("BigDecimal");
1504
+
1505
+ cOCINumber = rb_define_class("OraNumber", rb_cNumeric);
1506
+ mMath = rb_define_module_under(cOCI8, "Math");
1507
+
1508
+ /* constants for internal use. */
1509
+ /* set const_p1 */
1510
+ sl = 1;
1511
+ OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_p1);
1512
+ /* set const_p10 */
1513
+ sl = 10;
1514
+ OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_p10);
1515
+ /* set const_m1 */
1516
+ sl = -1;
1517
+ OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_m1);
1518
+ /* set const_PI2 */
1519
+ sl = 2;
1520
+ OCINumberSetPi(errhp, &num1);
1521
+ OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &num2);
1522
+ OCINumberDiv(errhp, &num1 /* PI */, &num2 /* 2 */, &const_PI2);
1523
+ /* set const_mPI2 */
1524
+ OCINumberNeg(errhp, &const_PI2 /* PI/2 */, &const_mPI2);
1525
+
1526
+ /* PI */
1527
+ OCINumberSetPi(errhp, &num1);
1528
+ obj_PI = oci8_make_ocinumber(&num1, errhp);
1529
+
1530
+ /* The ratio of the circumference of a circle to its diameter. */
1531
+ rb_define_const(mMath, "PI", obj_PI);
1532
+
1533
+ /*
1534
+ * module functions of OCI::Math.
1535
+ */
1536
+ rb_define_module_function(mMath, "atan2", omath_atan2, 2);
1537
+
1538
+ rb_define_module_function(mMath, "cos", omath_cos, 1);
1539
+ rb_define_module_function(mMath, "sin", omath_sin, 1);
1540
+ rb_define_module_function(mMath, "tan", omath_tan, 1);
1541
+
1542
+ rb_define_module_function(mMath, "acos", omath_acos, 1);
1543
+ rb_define_module_function(mMath, "asin", omath_asin, 1);
1544
+ rb_define_module_function(mMath, "atan", omath_atan, 1);
1545
+
1546
+ rb_define_module_function(mMath, "cosh", omath_cosh, 1);
1547
+ rb_define_module_function(mMath, "sinh", omath_sinh, 1);
1548
+ rb_define_module_function(mMath, "tanh", omath_tanh, 1);
1549
+
1550
+ rb_define_module_function(mMath, "exp", omath_exp, 1);
1551
+ rb_define_module_function(mMath, "log", omath_log, -1);
1552
+ rb_define_module_function(mMath, "log10", omath_log10, 1);
1553
+ rb_define_module_function(mMath, "sqrt", omath_sqrt, 1);
1554
+
1555
+ rb_define_alloc_func(cOCINumber, onum_s_alloc);
1556
+
1557
+ /* methods of OCI::Number */
1558
+ rb_define_method(rb_cObject, "OraNumber", onum_f_new, -1);
1559
+ rb_define_method_nodoc(cOCINumber, "initialize", onum_initialize, -1);
1560
+ rb_define_method_nodoc(cOCINumber, "initialize_copy", onum_initialize_copy, 1);
1561
+ rb_define_method_nodoc(cOCINumber, "coerce", onum_coerce, 1);
1562
+
1563
+ rb_include_module(cOCINumber, rb_mComparable);
1564
+
1565
+ rb_define_method(cOCINumber, "-@", onum_neg, 0);
1566
+ rb_define_method(cOCINumber, "+", onum_add, 1);
1567
+ rb_define_method(cOCINumber, "-", onum_sub, 1);
1568
+ rb_define_method(cOCINumber, "*", onum_mul, 1);
1569
+ rb_define_method(cOCINumber, "/", onum_div, 1);
1570
+ rb_define_method(cOCINumber, "%", onum_mod, 1);
1571
+ rb_define_method(cOCINumber, "**", onum_power, 1);
1572
+ rb_define_method(cOCINumber, "<=>", onum_cmp, 1);
1573
+
1574
+ rb_define_method(cOCINumber, "floor", onum_floor, 0);
1575
+ rb_define_method(cOCINumber, "ceil", onum_ceil, 0);
1576
+ rb_define_method(cOCINumber, "round", onum_round, -1);
1577
+ rb_define_method(cOCINumber, "truncate", onum_trunc, -1);
1578
+ rb_define_method(cOCINumber, "round_prec", onum_round_prec, 1);
1579
+
1580
+ rb_define_method(cOCINumber, "to_s", onum_to_s, 0);
1581
+ rb_define_method(cOCINumber, "to_char", onum_to_char, -1);
1582
+ rb_define_method(cOCINumber, "to_i", onum_to_i, 0);
1583
+ rb_define_method(cOCINumber, "to_f", onum_to_f, 0);
1584
+ rb_define_method(cOCINumber, "to_r", onum_to_r, 0);
1585
+ rb_define_method(cOCINumber, "to_d", onum_to_d, 0);
1586
+ rb_define_method(cOCINumber, "has_decimal_part?", onum_has_decimal_part_p, 0);
1587
+ rb_define_method_nodoc(cOCINumber, "to_onum", onum_to_onum, 0);
1588
+
1589
+ rb_define_method(cOCINumber, "zero?", onum_zero_p, 0);
1590
+ rb_define_method(cOCINumber, "abs", onum_abs, 0);
1591
+ rb_define_method(cOCINumber, "shift", onum_shift, 1);
1592
+ rb_define_method(cOCINumber, "dump", onum_dump, 0);
1593
+
1594
+ rb_define_method_nodoc(cOCINumber, "hash", onum_hash, 0);
1595
+ rb_define_method_nodoc(cOCINumber, "inspect", onum_inspect, 0);
1596
+
1597
+ /* methods for marshaling */
1598
+ rb_define_method(cOCINumber, "_dump", onum__dump, -1);
1599
+ rb_define_singleton_method(cOCINumber, "_load", onum_s_load, 1);
1600
+
1601
+ oci8_define_bind_class("OraNumber", &bind_ocinumber_vtable);
1602
+ oci8_define_bind_class("Integer", &bind_integer_vtable);
1603
+ oci8_define_bind_class("Float", &bind_float_vtable);
1604
+ }
1605
+
1606
+ OCINumber *oci8_get_ocinumber(VALUE num)
1607
+ {
1608
+ if (!rb_obj_is_kind_of(num, cOCINumber)) {
1609
+ rb_raise(rb_eTypeError, "invalid argument %s (expect a subclass of %s)", rb_class2name(CLASS_OF(num)), rb_class2name(cOCINumber));
1610
+ }
1611
+ return _NUMBER(num);
1612
+ }