ruby-oci8 2.0.3 → 2.0.4

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.
@@ -8,6 +8,7 @@
8
8
  #include "oci8.h"
9
9
  #include <orl.h>
10
10
  #include <errno.h>
11
+ #include "oranumber_util.h"
11
12
 
12
13
  #ifndef RUBY_VM
13
14
  /* ruby 1.8 */
@@ -36,26 +37,6 @@ static OCINumber const_m1; /* -1 */
36
37
  static OCINumber const_PI2; /* +PI/2 */
37
38
  static OCINumber const_mPI2; /* -PI/2 */
38
39
 
39
- #define SHRESHOLD_FMT_STR "00000000000000000000000000"
40
- #define SHRESHOLD_FMT (OraText*)SHRESHOLD_FMT_STR
41
- #define SHRESHOLD_FMT_LEN (sizeof(SHRESHOLD_FMT_STR) - 1)
42
- #define SHRESHOLD_VAL_STR "10000000000000000000000000"
43
- #define SHRESHOLD_VAL (OraText*)SHRESHOLD_VAL_STR
44
- #define SHRESHOLD_VAL_LEN (sizeof(SHRESHOLD_VAL_STR) - 1)
45
- static OCINumber const_shreshold;
46
-
47
- /* TODO: scale: -84 - 127 */
48
- #define NUMBER_FORMAT1_STR "FM9999999999999999999999990.9999999999999999999999999999999999999"
49
- #define NUMBER_FORMAT1 (OraText*)NUMBER_FORMAT1_STR
50
- #define NUMBER_FORMAT1_LEN (sizeof(NUMBER_FORMAT1_STR) - 1)
51
- #define NUMBER_FORMAT2_STR "FM99999999999999999999999999999999999990.999999999999999999999999"
52
- #define NUMBER_FORMAT2 (OraText*)NUMBER_FORMAT2_STR
53
- #define NUMBER_FORMAT2_LEN (sizeof(NUMBER_FORMAT2_STR) - 1)
54
- #define NUMBER_FORMAT2_DECIMAL (sizeof("999999999999999999999999") - 1)
55
- #define NUMBER_FORMAT_INT_STR "FM99999999999999999999999999999999999990"
56
- #define NUMBER_FORMAT_INT (OraText*)NUMBER_FORMAT_INT_STR
57
- #define NUMBER_FORMAT_INT_LEN (sizeof(NUMBER_FORMAT_INT_STR) - 1)
58
-
59
40
  #define _NUMBER(val) ((OCINumber *)DATA_PTR(val)) /* dangerous macro */
60
41
 
61
42
  #define RBOCI8_T_ORANUMBER (T_MASK + 1)
@@ -109,6 +90,7 @@ static int rboci8_type(VALUE obj)
109
90
  static VALUE onum_to_f(VALUE self);
110
91
  static VALUE onum_to_r(VALUE self);
111
92
  static VALUE onum_to_d(VALUE self);
93
+ static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp);
112
94
 
113
95
  static VALUE onum_s_alloc(VALUE klass)
114
96
  {
@@ -135,14 +117,18 @@ VALUE oci8_make_integer(OCINumber *s, OCIError *errhp)
135
117
  {
136
118
  signed long sl;
137
119
  char buf[512];
138
- ub4 buf_size = sizeof(buf);
120
+ sword rv;
139
121
 
140
122
  if (OCINumberToInt(errhp, s, sizeof(sl), OCI_NUMBER_SIGNED, &sl) == OCI_SUCCESS) {
141
123
  return LONG2NUM(sl);
142
124
  }
143
- oci_lc(OCINumberToText(errhp, s, NUMBER_FORMAT2, NUMBER_FORMAT2_LEN,
144
- NULL, 0, &buf_size, TO_ORATEXT(buf)));
145
- return rb_cstr2inum(buf, 10);
125
+ /* convert to Integer via String */
126
+ rv = oranumber_to_str(s, buf, sizeof(buf));
127
+ if (rv > 0) {
128
+ return rb_cstr2inum(buf, 10);
129
+ }
130
+ oranumber_dump(s, buf);
131
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
146
132
  }
147
133
 
148
134
  VALUE oci8_make_float(OCINumber *s, OCIError *errhp)
@@ -164,29 +150,25 @@ static void set_oci_number_from_str(OCINumber *result, VALUE str, VALUE fmt, VAL
164
150
  StringValue(str);
165
151
  /* set from string. */
166
152
  if (NIL_P(fmt)) {
167
- int i, cnt = 0;
168
- for (i = RSTRING_LEN(str) - 1; i >= 0; i--) {
169
- if (RSTRING_PTR(str)[i] != ' ')
170
- cnt++;
171
- if (RSTRING_PTR(str)[i] == '.') {
172
- i = RSTRING_LEN(str) - i;
153
+ int rv = oranumber_from_str(result, RSTRING_PTR(str), RSTRING_LEN(str));
154
+ if (rv == ORANUMBER_SUCCESS) {
155
+ return; /* success */
156
+ } else {
157
+ const char *default_msg = NULL;
158
+ switch (rv) {
159
+ case ORANUMBER_INVALID_NUMBER:
160
+ default_msg = "invalid number";
161
+ break;
162
+ case ORANUMBER_NUMERIC_OVERFLOW:
163
+ default_msg = "numeric overflow";
173
164
  break;
174
165
  }
166
+ oci8_raise_by_msgno(rv, default_msg);
175
167
  }
176
- if (i == -1)
177
- cnt = 0;
178
- if (cnt <= NUMBER_FORMAT2_DECIMAL) {
179
- fmt_ptr = NUMBER_FORMAT2;
180
- fmt_len = NUMBER_FORMAT2_LEN;
181
- } else {
182
- fmt_ptr = NUMBER_FORMAT1;
183
- fmt_len = NUMBER_FORMAT1_LEN;
184
- }
185
- } else {
186
- StringValue(fmt);
187
- fmt_ptr = RSTRING_ORATEXT(fmt);
188
- fmt_len = RSTRING_LEN(fmt);
189
168
  }
169
+ StringValue(fmt);
170
+ fmt_ptr = RSTRING_ORATEXT(fmt);
171
+ fmt_len = RSTRING_LEN(fmt);
190
172
  if (NIL_P(nls_params)) {
191
173
  nls_params_ptr = NULL;
192
174
  nls_params_len = 0;
@@ -1053,30 +1035,16 @@ static VALUE onum_to_char(int argc, VALUE *argv, VALUE self)
1053
1035
 
1054
1036
  rb_scan_args(argc, argv, "02", &fmt /* nil */, &nls_params /* nil */);
1055
1037
  if (NIL_P(fmt)) {
1056
- OCINumber absval;
1057
- sword sign;
1058
- boolean is_int;
1059
-
1060
- oci_lc(OCINumberIsInt(errhp, _NUMBER(self), &is_int));
1061
- if (is_int) {
1062
- fmt_ptr = NUMBER_FORMAT_INT;
1063
- fmt_len = NUMBER_FORMAT_INT_LEN;
1064
- } else {
1065
- oci_lc(OCINumberAbs(errhp, _NUMBER(self), &absval));
1066
- oci_lc(OCINumberCmp(errhp, &absval, &const_shreshold, &sign));
1067
- if (sign >= 0) {
1068
- fmt_ptr = NUMBER_FORMAT2;
1069
- fmt_len = NUMBER_FORMAT2_LEN;
1070
- } else {
1071
- fmt_ptr = NUMBER_FORMAT1;
1072
- fmt_len = NUMBER_FORMAT1_LEN;
1073
- }
1038
+ rv = oranumber_to_str(_NUMBER(self), buf, sizeof(buf));
1039
+ if (rv > 0) {
1040
+ return rb_usascii_str_new(buf, rv);
1074
1041
  }
1075
- } else {
1076
- StringValue(fmt);
1077
- fmt_ptr = RSTRING_ORATEXT(fmt);
1078
- fmt_len = RSTRING_LEN(fmt);
1042
+ oranumber_dump(_NUMBER(self), buf);
1043
+ rb_raise(eOCIException, "Invalid internal number format: %s", buf);
1079
1044
  }
1045
+ StringValue(fmt);
1046
+ fmt_ptr = RSTRING_ORATEXT(fmt);
1047
+ fmt_len = RSTRING_LEN(fmt);
1080
1048
  if (NIL_P(nls_params)) {
1081
1049
  nls_params_ptr = NULL;
1082
1050
  nls_params_len = 0;
@@ -1195,11 +1163,23 @@ static VALUE onum_to_r(VALUE self)
1195
1163
  */
1196
1164
  static VALUE onum_to_d(VALUE self)
1197
1165
  {
1166
+ return onum_to_d_real(_NUMBER(self), oci8_errhp);
1167
+ }
1168
+
1169
+ /* Converts to BigDecimal via number in scientific notation */
1170
+ static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp)
1171
+ {
1172
+ char buf[64];
1173
+ ub4 buf_size = sizeof(buf);
1174
+ const const char *fmt = "FM9.99999999999999999999999999999999999999EEEE";
1175
+
1198
1176
  if (!cBigDecimal) {
1199
1177
  rb_require("bigdecimal");
1200
1178
  cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
1201
1179
  }
1202
- return rb_funcall(rb_cObject, id_BigDecimal, 1, onum_to_s(self));
1180
+ oci_lc(OCINumberToText(errhp, num, (const oratext *)fmt, strlen(fmt),
1181
+ NULL, 0, &buf_size, TO_ORATEXT(buf)));
1182
+ return rb_funcall(rb_cObject, id_BigDecimal, 1, rb_usascii_str_new(buf, buf_size));
1203
1183
  }
1204
1184
 
1205
1185
  /*
@@ -1262,6 +1242,24 @@ static VALUE onum_shift(VALUE self, VALUE exp)
1262
1242
  return oci8_make_ocinumber(&result, errhp);
1263
1243
  }
1264
1244
 
1245
+ /*
1246
+ * call-seq:
1247
+ * onum.dump -> string
1248
+ *
1249
+ * Returns internal representation whose format is same with
1250
+ * the return value of Oracle SQL function DUMP().
1251
+ *
1252
+ * OraNumber.new(100).dump #=> "Typ=2 Len=2: 194,2"
1253
+ * OraNumber.new(123).dump #=> "Typ=2 Len=3: 194,2,24"
1254
+ * OraNumber.new(0.1).dump #=> "Typ=2 Len=2: 192,11"
1255
+ */
1256
+ static VALUE onum_dump(VALUE self)
1257
+ {
1258
+ char buf[ORANUMBER_DUMP_BUF_SIZ];
1259
+ int rv = oranumber_dump(_NUMBER(self), buf);
1260
+ return rb_usascii_str_new(buf, rv);
1261
+ }
1262
+
1265
1263
  static VALUE onum_hash(VALUE self)
1266
1264
  {
1267
1265
  char *c = DATA_PTR(self);
@@ -1297,7 +1295,7 @@ static VALUE onum_inspect(VALUE self)
1297
1295
  *
1298
1296
  * Dump <i>onum</i> for marshaling.
1299
1297
  */
1300
- static VALUE onum_dump(int argc, VALUE *argv, VALUE self)
1298
+ static VALUE onum__dump(int argc, VALUE *argv, VALUE self)
1301
1299
  {
1302
1300
  char *c = DATA_PTR(self);
1303
1301
  int size = c[0] + 1;
@@ -1443,9 +1441,6 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
1443
1441
  OCINumberDiv(errhp, &num1 /* PI */, &num2 /* 2 */, &const_PI2);
1444
1442
  /* set const_mPI2 */
1445
1443
  OCINumberNeg(errhp, &const_PI2 /* PI/2 */, &const_mPI2);
1446
- /* set const_shreshold */
1447
- OCINumberFromText(errhp, SHRESHOLD_VAL, SHRESHOLD_VAL_LEN, SHRESHOLD_FMT, SHRESHOLD_FMT_LEN,
1448
- NULL, 0, &const_shreshold);
1449
1444
 
1450
1445
  /* PI */
1451
1446
  OCINumberSetPi(errhp, &num1);
@@ -1516,12 +1511,13 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
1516
1511
  if (have_OCINumberShift) {
1517
1512
  rb_define_method(cOCINumber, "shift", onum_shift, 1);
1518
1513
  }
1514
+ rb_define_method(cOCINumber, "dump", onum_dump, 0);
1519
1515
 
1520
1516
  rb_define_method_nodoc(cOCINumber, "hash", onum_hash, 0);
1521
1517
  rb_define_method_nodoc(cOCINumber, "inspect", onum_inspect, 0);
1522
1518
 
1523
1519
  /* methods for marshaling */
1524
- rb_define_method(cOCINumber, "_dump", onum_dump, -1);
1520
+ rb_define_method(cOCINumber, "_dump", onum__dump, -1);
1525
1521
  rb_define_singleton_method(cOCINumber, "_load", onum_s_load, 1);
1526
1522
 
1527
1523
  oci8_define_bind_class("OraNumber", &bind_ocinumber_class);
@@ -3,7 +3,7 @@
3
3
  * oradate.c
4
4
  *
5
5
  * $Author: kubo $
6
- * $Date: 2009-10-21 22:50:01 +0900 (Wed, 21 Oct 2009) $
6
+ * $Date: 2009-01-04 01:58:01 +0900 (Sun, 04 Jan 2009) $
7
7
  *
8
8
  * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
9
9
  *
@@ -0,0 +1,315 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include "oranumber_util.h"
5
+
6
+ int oranumber_to_str(const OCINumber *on, char *buf, int buflen)
7
+ {
8
+ signed char exponent;
9
+ signed char mantissa[21]; /* terminated by a negative number */
10
+ int datalen = on->OCINumberPart[0];
11
+ int len = 0;
12
+ int idx;
13
+ int n;
14
+ #define PUTC(chr) do { \
15
+ if (len < buflen) { \
16
+ buf[len++] = (chr); \
17
+ } else { \
18
+ return ORANUMBER_TOO_SHORT_BUFFER; \
19
+ } \
20
+ } while(0)
21
+ #define PUTEND() do { \
22
+ if (len < buflen) { \
23
+ buf[len] = '\0'; \
24
+ } else { \
25
+ return ORANUMBER_TOO_SHORT_BUFFER; \
26
+ } \
27
+ } while(0)
28
+
29
+ if (datalen == 0) {
30
+ /* too short */
31
+ return -1;
32
+ }
33
+ if (datalen == 1) {
34
+ if (on->OCINumberPart[1] == 0x80) {
35
+ /* zero */
36
+ PUTC('0');
37
+ PUTEND();
38
+ return 1;
39
+ }
40
+ /* unexpected format */
41
+ return -1;
42
+ }
43
+ if (datalen > 21) {
44
+ /* too long */
45
+ return -1;
46
+ }
47
+ /* normalize exponent and mantissa */
48
+ if (on->OCINumberPart[1] >= 128) {
49
+ /* positive number */
50
+ exponent = on->OCINumberPart[1] - 193;
51
+ for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
52
+ mantissa[idx] = on->OCINumberPart[idx + 2] - 1;
53
+ }
54
+ mantissa[idx] = -1;
55
+ } else {
56
+ /* negative number */
57
+ exponent = 62 - on->OCINumberPart[1];
58
+ for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
59
+ mantissa[idx] = 101 - on->OCINumberPart[idx + 2];
60
+ }
61
+ mantissa[idx] = -1;
62
+ PUTC('-');
63
+ }
64
+ /* convert exponent and mantissa to human readable number */
65
+ idx = 0;
66
+ if (exponent-- >= 0) {
67
+ /* integer part */
68
+ n = mantissa[idx++];
69
+ if (n / 10 != 0) {
70
+ PUTC(n / 10 + '0');
71
+ }
72
+ PUTC(n % 10 + '0');
73
+ while (exponent-- >= 0) {
74
+ n = mantissa[idx++];
75
+ if (n < 0) {
76
+ do {
77
+ PUTC('0');
78
+ PUTC('0');
79
+ } while (exponent-- >= 0);
80
+ PUTEND();
81
+ return len;
82
+ }
83
+ PUTC(n / 10 + '0');
84
+ PUTC(n % 10 + '0');
85
+ }
86
+ if (mantissa[idx] < 0) {
87
+ PUTEND();
88
+ return len;
89
+ }
90
+ } else {
91
+ PUTC('0');
92
+ }
93
+ PUTC('.');
94
+ /* fractional number part */
95
+ while (++exponent < -1) {
96
+ PUTC('0');
97
+ PUTC('0');
98
+ }
99
+ while ((n = mantissa[idx++]) >= 0) {
100
+ PUTC(n / 10 + '0');
101
+ PUTC(n % 10 + '0');
102
+ }
103
+ if (buf[len - 1] == '0') {
104
+ len--;
105
+ }
106
+ PUTEND();
107
+ return len;
108
+ }
109
+
110
+ int oranumber_from_str(OCINumber *on, const char *buf, int buflen)
111
+ {
112
+ const char *end;
113
+ int is_positive = 1;
114
+ char mantissa[41];
115
+ int dec_point;
116
+ long exponent = 0;
117
+ int idx = 0;
118
+ int i;
119
+
120
+ if (buflen < 0) {
121
+ end = buf + strlen(buf);
122
+ } else {
123
+ end = buf + buflen;
124
+ }
125
+
126
+ /* skip leading spaces */
127
+ while (buf < end && *buf == ' ') {
128
+ buf++;
129
+ }
130
+ if (buf == end) {
131
+ return ORANUMBER_INVALID_NUMBER;
132
+ }
133
+ /* read a sign mark */
134
+ if (*buf == '+') {
135
+ buf++;
136
+ } else if (*buf == '-') {
137
+ buf++;
138
+ is_positive = 0;
139
+ }
140
+ /* next should be number or a dot */
141
+ if ((*buf < '0' || '9' < *buf) && *buf != '.') {
142
+ return ORANUMBER_INVALID_NUMBER;
143
+ }
144
+ /* skip leading zeros */
145
+ while (buf < end) {
146
+ if (*buf == '0') {
147
+ buf++;
148
+ } else {
149
+ break;
150
+ }
151
+ }
152
+ /* read integer part */
153
+ while (buf < end) {
154
+ if ('0' <= *buf && *buf <= '9') {
155
+ if (idx < 41) {
156
+ mantissa[idx] = *buf - '0';
157
+ }
158
+ idx++;
159
+ } else if (*buf == '.' || *buf == 'E' || *buf == 'e' || *buf == ' ') {
160
+ break;
161
+ } else {
162
+ return ORANUMBER_INVALID_NUMBER;
163
+ }
164
+ buf++;
165
+ }
166
+ dec_point = idx;
167
+ /* read fractional part */
168
+ if (buf < end && *buf == '.') {
169
+ buf++;
170
+ if (idx == 0) {
171
+ /* skip leading zeros */
172
+ while (buf < end) {
173
+ if (*buf == '0') {
174
+ dec_point--;
175
+ buf++;
176
+ } else {
177
+ break;
178
+ }
179
+ }
180
+ }
181
+ while (buf < end) {
182
+ if ('0' <= *buf && *buf <= '9') {
183
+ if (idx < 41) {
184
+ mantissa[idx++] = *buf - '0';
185
+ }
186
+ } else if (*buf == 'E' || *buf == 'e' || *buf == ' ') {
187
+ break;
188
+ } else {
189
+ return ORANUMBER_INVALID_NUMBER;
190
+ }
191
+ buf++;
192
+ }
193
+ }
194
+ /* read exponent part */
195
+ if (buf < end && (*buf == 'E' || *buf == 'e')) {
196
+ int negate = 0;
197
+ buf++;
198
+ if (buf < end) {
199
+ if (*buf == '+') {
200
+ buf++;
201
+ } else if (*buf == '-') {
202
+ buf++;
203
+ negate = 1;
204
+ }
205
+ }
206
+ while (buf < end) {
207
+ if ('0' <= *buf && *buf <= '9') {
208
+ exponent *= 10;
209
+ exponent += *buf - '0';
210
+ } else if (*buf == ' ') {
211
+ break;
212
+ } else {
213
+ return ORANUMBER_INVALID_NUMBER;
214
+ }
215
+ buf++;
216
+ }
217
+ if (negate) {
218
+ exponent = -exponent;
219
+ }
220
+ }
221
+ /* skip trailing spaces */
222
+ while (buf < end && *buf == ' ') {
223
+ buf++;
224
+ }
225
+ /* final format check */
226
+ if (buf != end) {
227
+ return ORANUMBER_INVALID_NUMBER;
228
+ }
229
+ /* determine exponent */
230
+ exponent += dec_point - 1;
231
+ if (exponent % 2 == 0) {
232
+ memmove(mantissa + 1, mantissa, 40);
233
+ mantissa[0] = 0;
234
+ idx++;
235
+ }
236
+ /* round if needed */
237
+ if (idx > 40) {
238
+ idx = 40;
239
+ if (mantissa[40] >= 5) {
240
+ /* round up */
241
+ for (i = 39; i >= 0; i--) {
242
+ mantissa[i]++;
243
+ if (mantissa[i] == 10) {
244
+ mantissa[i] = 0;
245
+ } else {
246
+ break;
247
+ }
248
+ }
249
+ if (i == -1) {
250
+ /* all figures are rounded up. */
251
+ mantissa[0] = 0;
252
+ mantissa[1] = 1;
253
+ idx = 2;
254
+ exponent++;
255
+ }
256
+ }
257
+ }
258
+ /* shrink mantissa scale */
259
+ while (idx > 0 && mantissa[idx - 1] == 0) {
260
+ idx--;
261
+ }
262
+ /* check zero or underflow */
263
+ if (idx == 0 || exponent < -130) {
264
+ on->OCINumberPart[0] = 1;
265
+ on->OCINumberPart[1] = 0x80;
266
+ return ORANUMBER_SUCCESS;
267
+ }
268
+ /* check overflow */
269
+ if (exponent > 125) {
270
+ return ORANUMBER_NUMERIC_OVERFLOW;
271
+ }
272
+ /* change the base number from 10 to 100 */
273
+ if (idx % 2 == 1) {
274
+ mantissa[idx++] = 0;
275
+ }
276
+ idx /= 2;
277
+ for (i = 0; i < idx; i++) {
278
+ mantissa[i] = mantissa[i * 2] * 10 + mantissa[i * 2 + 1];
279
+ }
280
+ /* add negative value's terminator */
281
+ if (!is_positive && idx < 20) {
282
+ mantissa[idx++] = -1;
283
+ }
284
+ /* construct OCINumber */
285
+ on->OCINumberPart[0] = 1 + idx;
286
+ if (is_positive) {
287
+ on->OCINumberPart[1] = (exponent >> 1) + 193;
288
+ for (i = 0; i < idx; i++) {
289
+ on->OCINumberPart[i + 2] = mantissa[i] + 1;
290
+ }
291
+ } else {
292
+ on->OCINumberPart[1] = 62 - (exponent >> 1);
293
+ for (i = 0; i < idx; i++) {
294
+ on->OCINumberPart[i + 2] = 101 - mantissa[i];
295
+ }
296
+ }
297
+ return ORANUMBER_SUCCESS;
298
+ }
299
+
300
+ int oranumber_dump(const OCINumber *on, char *buf)
301
+ {
302
+ int idx;
303
+ int len = on->OCINumberPart[0];
304
+ int offset;
305
+
306
+ offset = sprintf(buf, "Typ=2 Len=%u: ", len);
307
+ if (len > 21) {
308
+ len = 21;
309
+ }
310
+ for (idx = 1; idx <= len; idx++) {
311
+ offset += sprintf(buf + offset, "%hhu,", on->OCINumberPart[idx]);
312
+ }
313
+ buf[--offset] = '\0';
314
+ return offset;
315
+ }