ruby-oci8 2.0.3 → 2.0.4

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