ruby-oci8-master 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
+ }