ruby-oci8 1.0.2
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.
- data/ChangeLog +569 -0
- data/Makefile +51 -0
- data/NEWS +322 -0
- data/README +415 -0
- data/VERSION +1 -0
- data/dist-files +70 -0
- data/doc/api.en.html +527 -0
- data/doc/api.en.rd +554 -0
- data/doc/api.ja.html +525 -0
- data/doc/api.ja.rd +557 -0
- data/doc/manual.css +35 -0
- data/ext/oci8/MANIFEST +22 -0
- data/ext/oci8/attr.c +415 -0
- data/ext/oci8/bind.c +194 -0
- data/ext/oci8/const.c +165 -0
- data/ext/oci8/define.c +53 -0
- data/ext/oci8/describe.c +81 -0
- data/ext/oci8/descriptor.c +39 -0
- data/ext/oci8/env.c +276 -0
- data/ext/oci8/error.c +234 -0
- data/ext/oci8/extconf.rb +118 -0
- data/ext/oci8/handle.c +262 -0
- data/ext/oci8/lob.c +386 -0
- data/ext/oci8/oci8.c +137 -0
- data/ext/oci8/oci8.h +345 -0
- data/ext/oci8/ocinumber.c +117 -0
- data/ext/oci8/oraconf.rb +1026 -0
- data/ext/oci8/oradate.c +426 -0
- data/ext/oci8/oranumber.c +445 -0
- data/ext/oci8/param.c +37 -0
- data/ext/oci8/post-config.rb +5 -0
- data/ext/oci8/server.c +182 -0
- data/ext/oci8/session.c +99 -0
- data/ext/oci8/stmt.c +624 -0
- data/ext/oci8/svcctx.c +229 -0
- data/lib/DBD/OCI8/OCI8.rb +549 -0
- data/lib/oci8.rb.in +1605 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +54 -0
- data/ruby-oci8.spec +62 -0
- data/setup.rb +1331 -0
- data/support/README +4 -0
- data/support/runit/assert.rb +281 -0
- data/support/runit/cui/testrunner.rb +101 -0
- data/support/runit/error.rb +4 -0
- data/support/runit/method_mappable.rb +20 -0
- data/support/runit/robserver.rb +25 -0
- data/support/runit/setuppable.rb +15 -0
- data/support/runit/teardownable.rb +16 -0
- data/support/runit/testcase.rb +113 -0
- data/support/runit/testfailure.rb +25 -0
- data/support/runit/testresult.rb +121 -0
- data/support/runit/testsuite.rb +43 -0
- data/support/runit/version.rb +3 -0
- data/test/README +4 -0
- data/test/config.rb +129 -0
- data/test/test_all.rb +43 -0
- data/test/test_bind_raw.rb +53 -0
- data/test/test_bind_time.rb +191 -0
- data/test/test_break.rb +81 -0
- data/test/test_clob.rb +101 -0
- data/test/test_connstr.rb +80 -0
- data/test/test_dbi.rb +317 -0
- data/test/test_dbi_clob.rb +56 -0
- data/test/test_describe.rb +137 -0
- data/test/test_metadata.rb +243 -0
- data/test/test_oci8.rb +273 -0
- data/test/test_oradate.rb +263 -0
- data/test/test_oranumber.rb +149 -0
- metadata +118 -0
data/ext/oci8/oradate.c
ADDED
@@ -0,0 +1,426 @@
|
|
1
|
+
/*
|
2
|
+
oradate.c - part of ruby-oci8
|
3
|
+
|
4
|
+
Copyright (C) 2002 KUBO Takehiro <kubo@jiubao.org>
|
5
|
+
|
6
|
+
=begin
|
7
|
+
== OraDate
|
8
|
+
date and time between 4712 B.C. and 9999 A.D.
|
9
|
+
=end
|
10
|
+
*/
|
11
|
+
#include "oci8.h"
|
12
|
+
#include <time.h>
|
13
|
+
|
14
|
+
#define Set_year(od, y) (od)->century = y / 100 + 100, (od)->year = y % 100 + 100
|
15
|
+
#define Set_month(od, m) (od)->month = m
|
16
|
+
#define Set_day(od, d) (od)->day = d
|
17
|
+
#define Set_hour(od, h) (od)->hour = h + 1
|
18
|
+
#define Set_minute(od, m) (od)->minute = m + 1
|
19
|
+
#define Set_second(od, s) (od)->second = s + 1
|
20
|
+
|
21
|
+
#define Get_year(od) (((od)->century - 100) * 100 + ((od)->year - 100))
|
22
|
+
#define Get_month(od) ((od)->month)
|
23
|
+
#define Get_day(od) ((od)->day)
|
24
|
+
#define Get_hour(od) ((od)->hour - 1)
|
25
|
+
#define Get_minute(od) ((od)->minute - 1)
|
26
|
+
#define Get_second(od) ((od)->second - 1)
|
27
|
+
|
28
|
+
#define Check_year(year) \
|
29
|
+
if (year < -4712 || 9999 < year) \
|
30
|
+
rb_raise(rb_eRangeError, "Out of range for year %d (expect -4712 .. 9999)", year)
|
31
|
+
#define Check_month(month) \
|
32
|
+
if (month < 1 || 12 < month) \
|
33
|
+
rb_raise(rb_eRangeError, "Out of range for month %d (expect 1 .. 12)", month)
|
34
|
+
#define Check_day(day) \
|
35
|
+
if (day < 1 || 31 < day) \
|
36
|
+
rb_raise(rb_eRangeError, "Out of range for day %d (expect 1 .. 31)", day)
|
37
|
+
#define Check_hour(hour) \
|
38
|
+
if (hour < 0 || 23 < hour) \
|
39
|
+
rb_raise(rb_eRangeError, "Out of range for hour %d (expect 0 .. 24)", hour)
|
40
|
+
#define Check_minute(min) \
|
41
|
+
if (min < 0 || 59 < min) \
|
42
|
+
rb_raise(rb_eRangeError, "Out of range for minute %d (expect 0 .. 59)", min)
|
43
|
+
#define Check_second(sec) \
|
44
|
+
if (sec < 0 || 59 < sec) \
|
45
|
+
rb_raise(rb_eRangeError, "Out of range for second %d (expect 0 .. 59)", sec)
|
46
|
+
|
47
|
+
|
48
|
+
static VALUE ora_date_s_allocate(VALUE klass)
|
49
|
+
{
|
50
|
+
ora_date_t *od;
|
51
|
+
return Data_Make_Struct(klass, ora_date_t, NULL, xfree, od);
|
52
|
+
}
|
53
|
+
|
54
|
+
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
|
55
|
+
/* ruby 1.6 */
|
56
|
+
static VALUE ora_date_s_new(int argc, VALUE *argv, VALUE klass)
|
57
|
+
{
|
58
|
+
VALUE obj = ora_date_s_allocate(klass);
|
59
|
+
rb_obj_call_init(obj, argc, argv);
|
60
|
+
return obj;
|
61
|
+
}
|
62
|
+
#endif
|
63
|
+
|
64
|
+
/*
|
65
|
+
=begin
|
66
|
+
--- OraDate.new([year [, month [, day [, hour [, min [,sec]]]]]])
|
67
|
+
=end
|
68
|
+
*/
|
69
|
+
static VALUE ora_date_initialize(int argc, VALUE *argv, VALUE self)
|
70
|
+
{
|
71
|
+
VALUE vyear, vmonth, vday, vhour, vmin, vsec;
|
72
|
+
ora_date_t *od;
|
73
|
+
int year, month, day, hour, min, sec;
|
74
|
+
|
75
|
+
rb_scan_args(argc, argv, "06", &vyear, &vmonth, &vday, &vhour, &vmin, &vsec);
|
76
|
+
/* set year */
|
77
|
+
if (argc > 0) {
|
78
|
+
year = NUM2INT(vyear);
|
79
|
+
Check_year(year);
|
80
|
+
} else {
|
81
|
+
year = 1;
|
82
|
+
}
|
83
|
+
/* set month */
|
84
|
+
if (argc > 1) {
|
85
|
+
month = NUM2INT(vmonth);
|
86
|
+
Check_month(month);
|
87
|
+
} else {
|
88
|
+
month = 1;
|
89
|
+
}
|
90
|
+
/* set day */
|
91
|
+
if (argc > 2) {
|
92
|
+
day = NUM2INT(vday);
|
93
|
+
Check_day(day);
|
94
|
+
} else {
|
95
|
+
day = 1;
|
96
|
+
}
|
97
|
+
/* set hour */
|
98
|
+
if (argc > 3) {
|
99
|
+
hour = NUM2INT(vhour);
|
100
|
+
Check_hour(hour);
|
101
|
+
} else {
|
102
|
+
hour = 0;
|
103
|
+
}
|
104
|
+
/* set minute */
|
105
|
+
if (argc > 4) {
|
106
|
+
min = NUM2INT(vmin);
|
107
|
+
Check_minute(min);
|
108
|
+
} else {
|
109
|
+
min = 0;
|
110
|
+
}
|
111
|
+
/* set second */
|
112
|
+
if (argc > 5) {
|
113
|
+
sec = NUM2INT(vsec);
|
114
|
+
Check_second(sec);
|
115
|
+
} else {
|
116
|
+
sec = 0;
|
117
|
+
}
|
118
|
+
|
119
|
+
Data_Get_Struct(self, ora_date_t, od);
|
120
|
+
oci8_set_ora_date(od, year, month, day, hour, min, sec);
|
121
|
+
return Qnil;
|
122
|
+
}
|
123
|
+
|
124
|
+
static VALUE ora_date_initialize_copy(VALUE lhs, VALUE rhs)
|
125
|
+
{
|
126
|
+
ora_date_t *l, *r;
|
127
|
+
|
128
|
+
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
|
129
|
+
/* ruby 1.8 */
|
130
|
+
rb_obj_init_copy(lhs, rhs);
|
131
|
+
#endif
|
132
|
+
Data_Get_Struct(lhs, ora_date_t, l);
|
133
|
+
Data_Get_Struct(rhs, ora_date_t, r);
|
134
|
+
memcpy(l, r, sizeof(ora_date_t));
|
135
|
+
return lhs;
|
136
|
+
}
|
137
|
+
|
138
|
+
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
|
139
|
+
/* ruby 1.6 */
|
140
|
+
static VALUE ora_date_clone(VALUE self)
|
141
|
+
{
|
142
|
+
VALUE obj = ora_date_s_allocate(CLASS_OF(self));
|
143
|
+
return ora_date_initialize_copy(obj, self);
|
144
|
+
}
|
145
|
+
#endif
|
146
|
+
|
147
|
+
/*
|
148
|
+
=begin
|
149
|
+
--- OraDate.now()
|
150
|
+
=end
|
151
|
+
*/
|
152
|
+
static VALUE ora_date_s_now(int argc, VALUE *argv)
|
153
|
+
{
|
154
|
+
ora_date_t *od;
|
155
|
+
VALUE obj;
|
156
|
+
int year, month, day, hour, min, sec;
|
157
|
+
time_t tm;
|
158
|
+
struct tm *tp;
|
159
|
+
|
160
|
+
tm = time(0);
|
161
|
+
tp = localtime(&tm);
|
162
|
+
year = tp->tm_year + 1900;
|
163
|
+
month = tp->tm_mon + 1;
|
164
|
+
day = tp->tm_mday;
|
165
|
+
hour = tp->tm_hour;
|
166
|
+
min = tp->tm_min;
|
167
|
+
sec = tp->tm_sec;
|
168
|
+
|
169
|
+
obj = Data_Make_Struct(cOraDate, ora_date_t, NULL, xfree, od);
|
170
|
+
oci8_set_ora_date(od, year, month, day, hour, min, sec);
|
171
|
+
return obj;
|
172
|
+
}
|
173
|
+
|
174
|
+
/*
|
175
|
+
=begin
|
176
|
+
--- OraDate#to_s()
|
177
|
+
=end
|
178
|
+
*/
|
179
|
+
static VALUE ora_date_to_s(VALUE self)
|
180
|
+
{
|
181
|
+
ora_date_t *od;
|
182
|
+
char buf[30];
|
183
|
+
|
184
|
+
Data_Get_Struct(self, ora_date_t, od);
|
185
|
+
sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d", Get_year(od), Get_month(od),
|
186
|
+
Get_day(od), Get_hour(od), Get_minute(od), Get_second(od));
|
187
|
+
return rb_str_new2(buf);
|
188
|
+
}
|
189
|
+
|
190
|
+
/*
|
191
|
+
=begin
|
192
|
+
--- OraDate#to_a()
|
193
|
+
=end
|
194
|
+
*/
|
195
|
+
static VALUE ora_date_to_a(VALUE self)
|
196
|
+
{
|
197
|
+
ora_date_t *od;
|
198
|
+
VALUE ary[6];
|
199
|
+
|
200
|
+
Data_Get_Struct(self, ora_date_t, od);
|
201
|
+
ary[0] = INT2FIX(Get_year(od));
|
202
|
+
ary[1] = INT2FIX(Get_month(od));
|
203
|
+
ary[2] = INT2FIX(Get_day(od));
|
204
|
+
ary[3] = INT2FIX(Get_hour(od));
|
205
|
+
ary[4] = INT2FIX(Get_minute(od));
|
206
|
+
ary[5] = INT2FIX(Get_second(od));
|
207
|
+
return rb_ary_new4(6, ary);
|
208
|
+
}
|
209
|
+
|
210
|
+
#define DEFINE_GETTER_FUNC(where) \
|
211
|
+
static VALUE ora_date_##where(VALUE self) \
|
212
|
+
{ \
|
213
|
+
ora_date_t *od; \
|
214
|
+
\
|
215
|
+
Data_Get_Struct(self, ora_date_t, od); \
|
216
|
+
return INT2FIX(Get_##where(od)); \
|
217
|
+
}
|
218
|
+
|
219
|
+
#define DEFINE_SETTER_FUNC(where) \
|
220
|
+
static VALUE ora_date_set_##where(VALUE self, VALUE val) \
|
221
|
+
{ \
|
222
|
+
ora_date_t *od; \
|
223
|
+
int v; \
|
224
|
+
\
|
225
|
+
v = NUM2INT(val); \
|
226
|
+
Check_##where(v); \
|
227
|
+
Data_Get_Struct(self, ora_date_t, od); \
|
228
|
+
Set_##where(od, v); \
|
229
|
+
return self; \
|
230
|
+
}
|
231
|
+
|
232
|
+
/*
|
233
|
+
=begin
|
234
|
+
--- OraDate#year
|
235
|
+
=end
|
236
|
+
*/
|
237
|
+
DEFINE_GETTER_FUNC(year)
|
238
|
+
DEFINE_SETTER_FUNC(year)
|
239
|
+
|
240
|
+
/*
|
241
|
+
=begin
|
242
|
+
--- OraDate#month
|
243
|
+
=end
|
244
|
+
*/
|
245
|
+
DEFINE_GETTER_FUNC(month)
|
246
|
+
DEFINE_SETTER_FUNC(month)
|
247
|
+
|
248
|
+
/*
|
249
|
+
=begin
|
250
|
+
--- OraDate#day
|
251
|
+
=end
|
252
|
+
*/
|
253
|
+
DEFINE_GETTER_FUNC(day)
|
254
|
+
DEFINE_SETTER_FUNC(day)
|
255
|
+
|
256
|
+
/*
|
257
|
+
=begin
|
258
|
+
--- OraDate#hour
|
259
|
+
=end
|
260
|
+
*/
|
261
|
+
DEFINE_GETTER_FUNC(hour)
|
262
|
+
DEFINE_SETTER_FUNC(hour)
|
263
|
+
|
264
|
+
/*
|
265
|
+
=begin
|
266
|
+
--- OraDate#minute
|
267
|
+
=end
|
268
|
+
*/
|
269
|
+
DEFINE_GETTER_FUNC(minute)
|
270
|
+
DEFINE_SETTER_FUNC(minute)
|
271
|
+
|
272
|
+
/*
|
273
|
+
=begin
|
274
|
+
--- OraDate#second
|
275
|
+
=end
|
276
|
+
*/
|
277
|
+
DEFINE_GETTER_FUNC(second)
|
278
|
+
DEFINE_SETTER_FUNC(second)
|
279
|
+
|
280
|
+
/*
|
281
|
+
=begin
|
282
|
+
--- OraDate#trunc()
|
283
|
+
=end
|
284
|
+
*/
|
285
|
+
static VALUE ora_date_trunc(VALUE self)
|
286
|
+
{
|
287
|
+
ora_date_t *od;
|
288
|
+
|
289
|
+
Data_Get_Struct(self, ora_date_t, od);
|
290
|
+
od->hour = 1;
|
291
|
+
od->minute = 1;
|
292
|
+
od->second = 1;
|
293
|
+
return self;
|
294
|
+
}
|
295
|
+
|
296
|
+
static VALUE ora_date_hash(VALUE self)
|
297
|
+
{
|
298
|
+
ora_date_t *od;
|
299
|
+
unsigned int v;
|
300
|
+
|
301
|
+
Data_Get_Struct(self, ora_date_t, od);
|
302
|
+
v = (od->century << 8)
|
303
|
+
+ (od->year << 15)
|
304
|
+
+ (od->month << 22)
|
305
|
+
+ (od->day << 26)
|
306
|
+
+ (od->hour << 12)
|
307
|
+
+ (od->minute << 6)
|
308
|
+
+ (od->second << 0);
|
309
|
+
return INT2FIX(v);
|
310
|
+
}
|
311
|
+
|
312
|
+
/*
|
313
|
+
=begin
|
314
|
+
--- OraDate#<=>(other)
|
315
|
+
=end
|
316
|
+
*/
|
317
|
+
static VALUE ora_date_cmp(VALUE self, VALUE val)
|
318
|
+
{
|
319
|
+
ora_date_t *od1, *od2;
|
320
|
+
Data_Get_Struct(self, ora_date_t, od1);
|
321
|
+
Data_Get_Struct(val, ora_date_t, od2);
|
322
|
+
if (od1->century < od2->century) return INT2FIX(-1);
|
323
|
+
if (od1->century > od2->century) return INT2FIX(1);
|
324
|
+
if (od1->year < od2->year) return INT2FIX(-1);
|
325
|
+
if (od1->year > od2->year) return INT2FIX(1);
|
326
|
+
if (od1->month < od2->month) return INT2FIX(-1);
|
327
|
+
if (od1->month > od2->month) return INT2FIX(1);
|
328
|
+
if (od1->day < od2->day) return INT2FIX(-1);
|
329
|
+
if (od1->day > od2->day) return INT2FIX(1);
|
330
|
+
if (od1->hour < od2->hour) return INT2FIX(-1);
|
331
|
+
if (od1->hour > od2->hour) return INT2FIX(1);
|
332
|
+
if (od1->minute < od2->minute) return INT2FIX(-1);
|
333
|
+
if (od1->minute > od2->minute) return INT2FIX(1);
|
334
|
+
if (od1->second < od2->second) return INT2FIX(-1);
|
335
|
+
if (od1->second > od2->second) return INT2FIX(1);
|
336
|
+
return INT2FIX(0);
|
337
|
+
}
|
338
|
+
|
339
|
+
static VALUE ora_date_dump(int argc, VALUE *argv, VALUE self)
|
340
|
+
{
|
341
|
+
ora_date_t *od;
|
342
|
+
Data_Get_Struct(self, ora_date_t, od);
|
343
|
+
return rb_str_new((const char*)od, sizeof(ora_date_t));
|
344
|
+
}
|
345
|
+
|
346
|
+
static VALUE ora_date_s_load(VALUE klass, VALUE str)
|
347
|
+
{
|
348
|
+
ora_date_t *od;
|
349
|
+
VALUE obj;
|
350
|
+
|
351
|
+
Check_Type(str, T_STRING);
|
352
|
+
if (RSTRING_LEN(str) != sizeof(ora_date_t)) {
|
353
|
+
rb_raise(rb_eTypeError, "marshaled OraDate format differ");
|
354
|
+
}
|
355
|
+
obj = Data_Make_Struct(cOraDate, ora_date_t, NULL, xfree, od);
|
356
|
+
memcpy(od, RSTRING_PTR(str), sizeof(ora_date_t));
|
357
|
+
return obj;
|
358
|
+
}
|
359
|
+
|
360
|
+
void Init_ora_date(void)
|
361
|
+
{
|
362
|
+
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
|
363
|
+
/* ruby 1.8 */
|
364
|
+
rb_define_alloc_func(cOraDate, RUBY_METHOD_FUNC(ora_date_s_allocate));
|
365
|
+
rb_define_method(cOraDate, "initialize", ora_date_initialize, -1);
|
366
|
+
rb_define_method(cOraDate, "initialize_copy", ora_date_initialize_copy, 1);
|
367
|
+
#else
|
368
|
+
/* ruby 1.6 */
|
369
|
+
rb_define_singleton_method(cOraDate, "new", ora_date_s_new, -1);
|
370
|
+
rb_define_method(cOraDate, "initialize", ora_date_initialize, -1);
|
371
|
+
rb_define_method(cOraDate, "clone", ora_date_clone, 0);
|
372
|
+
rb_define_method(cOraDate, "dup", ora_date_clone, 0);
|
373
|
+
#endif
|
374
|
+
|
375
|
+
rb_define_singleton_method(cOraDate, "now", ora_date_s_now, 0);
|
376
|
+
rb_define_method(cOraDate, "to_s", ora_date_to_s, 0);
|
377
|
+
rb_define_method(cOraDate, "to_a", ora_date_to_a, 0);
|
378
|
+
|
379
|
+
rb_define_method(cOraDate, "year", ora_date_year, 0);
|
380
|
+
rb_define_method(cOraDate, "year=", ora_date_set_year, 1);
|
381
|
+
|
382
|
+
rb_define_method(cOraDate, "month", ora_date_month, 0);
|
383
|
+
rb_define_method(cOraDate, "month=", ora_date_set_month, 1);
|
384
|
+
|
385
|
+
rb_define_method(cOraDate, "day", ora_date_day, 0);
|
386
|
+
rb_define_method(cOraDate, "day=", ora_date_set_day, 1);
|
387
|
+
|
388
|
+
rb_define_method(cOraDate, "hour", ora_date_hour, 0);
|
389
|
+
rb_define_method(cOraDate, "hour=", ora_date_set_hour, 1);
|
390
|
+
|
391
|
+
rb_define_method(cOraDate, "minute", ora_date_minute, 0);
|
392
|
+
rb_define_method(cOraDate, "minute=", ora_date_set_minute, 1);
|
393
|
+
|
394
|
+
rb_define_method(cOraDate, "second", ora_date_second, 0);
|
395
|
+
rb_define_method(cOraDate, "second=", ora_date_set_second, 1);
|
396
|
+
|
397
|
+
rb_define_method(cOraDate, "trunc", ora_date_trunc, 0);
|
398
|
+
|
399
|
+
rb_define_method(cOraDate, "<=>", ora_date_cmp, 1);
|
400
|
+
rb_include_module(cOraDate, rb_mComparable);
|
401
|
+
|
402
|
+
rb_define_method(cOraDate, "hash", ora_date_hash, 0);
|
403
|
+
|
404
|
+
rb_define_method(cOraDate, "_dump", ora_date_dump, -1);
|
405
|
+
rb_define_singleton_method(cOraDate, "_load", ora_date_s_load, 1);
|
406
|
+
}
|
407
|
+
|
408
|
+
void oci8_set_ora_date(ora_date_t *od, int year, int month, int day, int hour, int minute, int second)
|
409
|
+
{
|
410
|
+
Set_year(od, year);
|
411
|
+
Set_month(od, month);
|
412
|
+
Set_day(od, day);
|
413
|
+
Set_hour(od, hour);
|
414
|
+
Set_minute(od, minute);
|
415
|
+
Set_second(od, second);
|
416
|
+
}
|
417
|
+
|
418
|
+
void oci8_get_ora_date(ora_date_t *od, int *year, int *month, int *day, int *hour, int *minute, int *second)
|
419
|
+
{
|
420
|
+
*year = Get_year(od);
|
421
|
+
*month = Get_month(od);
|
422
|
+
*day = Get_day(od);
|
423
|
+
*hour = Get_hour(od);
|
424
|
+
*minute = Get_minute(od);
|
425
|
+
*second = Get_second(od);
|
426
|
+
}
|
@@ -0,0 +1,445 @@
|
|
1
|
+
/*
|
2
|
+
oranumber.c - part of ruby-oci8
|
3
|
+
|
4
|
+
Copyright (C) 2002 KUBO Takehiro <kubo@jiubao.org>
|
5
|
+
|
6
|
+
=begin
|
7
|
+
== OraNumber
|
8
|
+
This is not a numeric class, so algebra operations and setter methods
|
9
|
+
are not permitted, but a place to hold fetched date from Oracle server.
|
10
|
+
|
11
|
+
In fact as matter, this is a test class to check the algorithm to
|
12
|
+
convert Oracle internal number format to Ruby's number, which is internally used by,
|
13
|
+
for example, ((<OCIStmt#attrGet|OCIHandle#attrGet>))(((<OCI_ATTR_MIN>))).
|
14
|
+
=end
|
15
|
+
*/
|
16
|
+
#include "oci8.h"
|
17
|
+
#include "math.h"
|
18
|
+
|
19
|
+
#define Get_Sign(on) ((on)->exponent & 0x80)
|
20
|
+
#define Get_Exp_Part(on) ((on)->exponent & 0x7F)
|
21
|
+
#define Get_Exponent(on) (Get_Sign(on) ? (Get_Exp_Part(on) - 65) : (~(Get_Exp_Part(on)) + 63))
|
22
|
+
#define Get_Mantissa_At(on, i) (Get_Sign(on) ? (on)->mantissa[i] - 1 : 101 - (on)->mantissa[i])
|
23
|
+
|
24
|
+
static int ora_number_from_str(ora_vnumber_t *ovn, unsigned char *buf, size_t len);
|
25
|
+
|
26
|
+
static ora_vnumber_t *get_ora_number(VALUE self)
|
27
|
+
{
|
28
|
+
ora_vnumber_t *ovn;
|
29
|
+
Data_Get_Struct(self, ora_vnumber_t, ovn);
|
30
|
+
return ovn;
|
31
|
+
}
|
32
|
+
|
33
|
+
static VALUE ora_number_s_allocate(VALUE klass)
|
34
|
+
{
|
35
|
+
ora_vnumber_t *ovn;
|
36
|
+
return Data_Make_Struct(klass, ora_vnumber_t, NULL, xfree, ovn);
|
37
|
+
}
|
38
|
+
|
39
|
+
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
|
40
|
+
/* ruby 1.6 */
|
41
|
+
static VALUE ora_number_s_new(int argc, VALUE *argv, VALUE klass)
|
42
|
+
{
|
43
|
+
VALUE obj = ora_number_s_allocate(klass);
|
44
|
+
rb_obj_call_init(obj, argc, argv);
|
45
|
+
return obj;
|
46
|
+
}
|
47
|
+
#endif
|
48
|
+
|
49
|
+
/*
|
50
|
+
=begin
|
51
|
+
--- OraNumber.new()
|
52
|
+
=end
|
53
|
+
*/
|
54
|
+
static VALUE ora_number_initialize(int argc, VALUE *argv, VALUE self)
|
55
|
+
{
|
56
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
57
|
+
volatile VALUE arg;
|
58
|
+
|
59
|
+
rb_scan_args(argc, argv, "01", &arg);
|
60
|
+
ovn->size = 1;
|
61
|
+
ovn->num.exponent = 0x80;
|
62
|
+
memset(ovn->num.mantissa, 0, sizeof(ovn->num.mantissa));
|
63
|
+
if (argc == 1) {
|
64
|
+
if (TYPE(arg) != T_STRING) {
|
65
|
+
arg = rb_obj_as_string(arg);
|
66
|
+
}
|
67
|
+
if (ora_number_from_str(ovn, RSTRING_ORATEXT(arg), RSTRING_LEN(arg)) != 0) {
|
68
|
+
rb_raise(rb_eArgError, "could not convert '%s' to OraNumber", RSTRING_PTR(arg));
|
69
|
+
}
|
70
|
+
}
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE ora_number_initialize_copy(VALUE lhs, VALUE rhs)
|
75
|
+
{
|
76
|
+
ora_vnumber_t *l, *r;
|
77
|
+
|
78
|
+
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
|
79
|
+
/* ruby 1.8 */
|
80
|
+
rb_obj_init_copy(lhs, rhs);
|
81
|
+
#endif
|
82
|
+
Data_Get_Struct(lhs, ora_vnumber_t, l);
|
83
|
+
Data_Get_Struct(rhs, ora_vnumber_t, r);
|
84
|
+
memcpy(l, r, sizeof(ora_vnumber_t));
|
85
|
+
return lhs;
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE ora_number_clone(VALUE self)
|
89
|
+
{
|
90
|
+
VALUE obj = ora_number_s_allocate(CLASS_OF(self));
|
91
|
+
return ora_number_initialize_copy(obj, self);
|
92
|
+
}
|
93
|
+
|
94
|
+
/*
|
95
|
+
=begin
|
96
|
+
--- OraNumber#to_i()
|
97
|
+
=end
|
98
|
+
*/
|
99
|
+
static VALUE ora_number_to_i(VALUE self)
|
100
|
+
{
|
101
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
102
|
+
unsigned char buf[ORA_NUMBER_BUF_SIZE];
|
103
|
+
|
104
|
+
ora_number_to_str(buf, NULL, &(ovn->num), ovn->size);
|
105
|
+
return rb_cstr2inum(TO_CHARPTR(buf), 10);
|
106
|
+
}
|
107
|
+
|
108
|
+
/*
|
109
|
+
=begin
|
110
|
+
--- OraNumber#to_f()
|
111
|
+
=end
|
112
|
+
*/
|
113
|
+
static VALUE ora_number_to_f(VALUE self)
|
114
|
+
{
|
115
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
116
|
+
unsigned char buf[ORA_NUMBER_BUF_SIZE];
|
117
|
+
|
118
|
+
ora_number_to_str(buf, NULL, &(ovn->num), ovn->size);
|
119
|
+
return rb_float_new(rb_cstr_to_dbl(TO_CHARPTR(buf), Qfalse));
|
120
|
+
}
|
121
|
+
|
122
|
+
/*
|
123
|
+
=begin
|
124
|
+
--- OraNumber#to_s()
|
125
|
+
=end
|
126
|
+
*/
|
127
|
+
static VALUE ora_number_to_s(VALUE self)
|
128
|
+
{
|
129
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
130
|
+
unsigned char buf[ORA_NUMBER_BUF_SIZE];
|
131
|
+
size_t len;
|
132
|
+
|
133
|
+
ora_number_to_str(buf, &len, &(ovn->num), ovn->size);
|
134
|
+
return rb_str_new(TO_CHARPTR(buf), len);
|
135
|
+
}
|
136
|
+
|
137
|
+
static VALUE ora_number_uminus(VALUE self)
|
138
|
+
{
|
139
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
140
|
+
VALUE obj;
|
141
|
+
int i;
|
142
|
+
|
143
|
+
if (ovn->num.exponent == 0x80)
|
144
|
+
return self;
|
145
|
+
obj = ora_number_clone(self);
|
146
|
+
ovn = get_ora_number(obj);
|
147
|
+
ovn->num.exponent = ~(ovn->num.exponent);
|
148
|
+
for (i = 0;i < ovn->size - 1;i++)
|
149
|
+
ovn->num.mantissa[i] = 102 - ovn->num.mantissa[i];
|
150
|
+
if (Get_Sign(&(ovn->num))) {
|
151
|
+
if (ovn->size != 21 || ovn->num.mantissa[19] == 0x00) {
|
152
|
+
ovn->size--;
|
153
|
+
}
|
154
|
+
} else {
|
155
|
+
if (ovn->size != 21) {
|
156
|
+
ovn->num.mantissa[ovn->size - 1] = 102;
|
157
|
+
ovn->size++;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
return obj;
|
161
|
+
}
|
162
|
+
|
163
|
+
static VALUE ora_number_dump(int argc, VALUE *argv, VALUE self)
|
164
|
+
{
|
165
|
+
ora_vnumber_t *ovn = get_ora_number(self);
|
166
|
+
unsigned char i;
|
167
|
+
for (i = ovn->size - 1; i < 20; i++) {
|
168
|
+
ovn->num.mantissa[i] = 0;
|
169
|
+
}
|
170
|
+
return rb_str_new((const char*)ovn, sizeof(ora_vnumber_t));
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE ora_number_s_load(VALUE klass, VALUE str)
|
174
|
+
{
|
175
|
+
ora_vnumber_t *ovn;
|
176
|
+
VALUE obj;
|
177
|
+
|
178
|
+
Check_Type(str, T_STRING);
|
179
|
+
if (RSTRING_LEN(str) != sizeof(ora_vnumber_t)) {
|
180
|
+
rb_raise(rb_eTypeError, "marshaled OraNumber format differ");
|
181
|
+
}
|
182
|
+
obj = ora_number_s_allocate(klass);
|
183
|
+
ovn = get_ora_number(obj);
|
184
|
+
memcpy(ovn, RSTRING_PTR(str), sizeof(ora_vnumber_t));
|
185
|
+
return obj;
|
186
|
+
}
|
187
|
+
|
188
|
+
void Init_ora_number(void)
|
189
|
+
{
|
190
|
+
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
|
191
|
+
/* ruby 1.8 */
|
192
|
+
rb_define_alloc_func(cOraNumber, RUBY_METHOD_FUNC(ora_number_s_allocate));
|
193
|
+
rb_define_method(cOraNumber, "initialize", ora_number_initialize, -1);
|
194
|
+
rb_define_method(cOraNumber, "initialize_copy", ora_number_initialize_copy, 1);
|
195
|
+
#else
|
196
|
+
/* ruby 1.6 */
|
197
|
+
rb_define_singleton_method(cOraNumber, "new", ora_number_s_new, -1);
|
198
|
+
rb_define_method(cOraNumber, "initialize", ora_number_initialize, -1);
|
199
|
+
rb_define_method(cOraNumber, "clone", ora_number_clone, 0);
|
200
|
+
rb_define_method(cOraNumber, "dup", ora_number_clone, 0);
|
201
|
+
#endif
|
202
|
+
|
203
|
+
rb_define_method(cOraNumber, "to_i", ora_number_to_i, 0);
|
204
|
+
rb_define_method(cOraNumber, "to_f", ora_number_to_f, 0);
|
205
|
+
rb_define_method(cOraNumber, "to_s", ora_number_to_s, 0);
|
206
|
+
rb_define_method(cOraNumber, "-@", ora_number_uminus, 0);
|
207
|
+
|
208
|
+
rb_define_method(cOraNumber, "_dump", ora_number_dump, -1);
|
209
|
+
rb_define_singleton_method(cOraNumber, "_load", ora_number_s_load, 1);
|
210
|
+
}
|
211
|
+
|
212
|
+
void ora_number_to_str(unsigned char *buf, size_t *lenp, ora_number_t *on, unsigned char size)
|
213
|
+
{
|
214
|
+
int exponent;
|
215
|
+
int len = 0;
|
216
|
+
int mentissa_size;
|
217
|
+
int i, j;
|
218
|
+
|
219
|
+
if (on->exponent == 0x80) {
|
220
|
+
buf[0] = '0';
|
221
|
+
buf[1] = '\0';
|
222
|
+
if (lenp != NULL)
|
223
|
+
*lenp = 1;
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
|
227
|
+
if (Get_Sign(on)) {
|
228
|
+
mentissa_size = size - 1;
|
229
|
+
} else {
|
230
|
+
if (size == 21 && on->mantissa[19] != 102)
|
231
|
+
mentissa_size = 20;
|
232
|
+
else
|
233
|
+
mentissa_size = size - 2;
|
234
|
+
buf[len++] = '-';
|
235
|
+
}
|
236
|
+
exponent = Get_Exponent(on);
|
237
|
+
if (exponent < 0) {
|
238
|
+
buf[len++] = '0';
|
239
|
+
buf[len++] = '.';
|
240
|
+
for (i = exponent * 2;i < -2;i++)
|
241
|
+
buf[len++] = '0';
|
242
|
+
for (i = 0;i < mentissa_size;i++) {
|
243
|
+
j = Get_Mantissa_At(on, i);
|
244
|
+
buf[len++] = j / 10 + '0';
|
245
|
+
if (i != mentissa_size - 1 || j % 10 != 0)
|
246
|
+
buf[len++] = j % 10 + '0';
|
247
|
+
}
|
248
|
+
} else {
|
249
|
+
for (i = 0;i < mentissa_size;i++) {
|
250
|
+
j = Get_Mantissa_At(on, i);
|
251
|
+
if (i == exponent + 1) {
|
252
|
+
buf[len++] = '.';
|
253
|
+
}
|
254
|
+
if (i != 0 || j / 10 != 0)
|
255
|
+
buf[len++] = j / 10 + '0';
|
256
|
+
if ((i < exponent + 1) /* integer part */
|
257
|
+
|| (i != mentissa_size - 1 || j % 10 != 0) /* decimal fraction */)
|
258
|
+
buf[len++] = j % 10 + '0';
|
259
|
+
}
|
260
|
+
for (;i <= exponent;i++) {
|
261
|
+
buf[len++] = '0';
|
262
|
+
buf[len++] = '0';
|
263
|
+
}
|
264
|
+
}
|
265
|
+
buf[len] = '\0';
|
266
|
+
if (lenp != NULL)
|
267
|
+
*lenp = len;
|
268
|
+
}
|
269
|
+
|
270
|
+
static int ora_number_from_str(ora_vnumber_t *ovn, unsigned char *buf, size_t len)
|
271
|
+
{
|
272
|
+
unsigned char work[80];
|
273
|
+
int sign = 1;
|
274
|
+
int state = 0;
|
275
|
+
int i, j;
|
276
|
+
int iidx; /* index of integer part */
|
277
|
+
int fidx; /* index of fraction part */
|
278
|
+
unsigned char *p;
|
279
|
+
int mantissa_size;
|
280
|
+
int exponent;
|
281
|
+
|
282
|
+
if (len > ORA_NUMBER_BUF_SIZE) {
|
283
|
+
return 1;
|
284
|
+
}
|
285
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
286
|
+
for (i = iidx = fidx = 0; i < len; i++) {
|
287
|
+
unsigned char uc = buf[i];
|
288
|
+
switch (state) {
|
289
|
+
case 0:
|
290
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
291
|
+
/* ^ */
|
292
|
+
switch (uc) {
|
293
|
+
case ' ':
|
294
|
+
case '\t':
|
295
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
296
|
+
/* ^ */
|
297
|
+
break;
|
298
|
+
case '-':
|
299
|
+
sign = -1;
|
300
|
+
state = 1;
|
301
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
302
|
+
/* ^ */
|
303
|
+
break;
|
304
|
+
case '+':
|
305
|
+
case '0':
|
306
|
+
state = 1;
|
307
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
308
|
+
/* ^ */
|
309
|
+
break;
|
310
|
+
case '1':
|
311
|
+
case '2':
|
312
|
+
case '3':
|
313
|
+
case '4':
|
314
|
+
case '5':
|
315
|
+
case '6':
|
316
|
+
case '7':
|
317
|
+
case '8':
|
318
|
+
case '9':
|
319
|
+
work[iidx++] = uc - '0';
|
320
|
+
state = 1;
|
321
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
322
|
+
/* ^ */
|
323
|
+
break;
|
324
|
+
case '.':
|
325
|
+
state = 2;
|
326
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
327
|
+
/* ^ */
|
328
|
+
break;
|
329
|
+
default:
|
330
|
+
return 1;
|
331
|
+
}
|
332
|
+
break;
|
333
|
+
case 1:
|
334
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
335
|
+
/* ^ */
|
336
|
+
switch (uc) {
|
337
|
+
case '0':
|
338
|
+
case '1':
|
339
|
+
case '2':
|
340
|
+
case '3':
|
341
|
+
case '4':
|
342
|
+
case '5':
|
343
|
+
case '6':
|
344
|
+
case '7':
|
345
|
+
case '8':
|
346
|
+
case '9':
|
347
|
+
if (iidx > sizeof(work))
|
348
|
+
return 1;
|
349
|
+
work[iidx++] = uc - '0';
|
350
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
351
|
+
/* ^ */
|
352
|
+
break;
|
353
|
+
case '.':
|
354
|
+
state = 2;
|
355
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
356
|
+
/* ^ */
|
357
|
+
break;
|
358
|
+
default:
|
359
|
+
return 1;
|
360
|
+
}
|
361
|
+
break;
|
362
|
+
case 2:
|
363
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
364
|
+
/* ^ */
|
365
|
+
switch (uc) {
|
366
|
+
case '0':
|
367
|
+
case '1':
|
368
|
+
case '2':
|
369
|
+
case '3':
|
370
|
+
case '4':
|
371
|
+
case '5':
|
372
|
+
case '6':
|
373
|
+
case '7':
|
374
|
+
case '8':
|
375
|
+
case '9':
|
376
|
+
if (iidx + fidx > sizeof(work))
|
377
|
+
return 1;
|
378
|
+
work[iidx + fidx++] = uc - '0';
|
379
|
+
/* [ \t]*(+|-)[0-9]*(.[0-9]*) */
|
380
|
+
/* ^ */
|
381
|
+
break;
|
382
|
+
default:
|
383
|
+
return 1;
|
384
|
+
}
|
385
|
+
break;
|
386
|
+
}
|
387
|
+
}
|
388
|
+
/* convert to 100-base number */
|
389
|
+
if (iidx & 1) {
|
390
|
+
i = j = 1;
|
391
|
+
} else {
|
392
|
+
i = j = 0;
|
393
|
+
}
|
394
|
+
if (fidx & 1) {
|
395
|
+
if (iidx + fidx > sizeof(work))
|
396
|
+
return 1;
|
397
|
+
work[iidx + fidx++] = 0;
|
398
|
+
}
|
399
|
+
while (i < iidx + fidx) {
|
400
|
+
work[j++] = work[i] * 10 + work[i + 1];
|
401
|
+
i += 2;
|
402
|
+
}
|
403
|
+
iidx = (iidx + 1) >> 1;
|
404
|
+
fidx >>= 1;
|
405
|
+
/* ... */
|
406
|
+
p = work;
|
407
|
+
mantissa_size = iidx + fidx;
|
408
|
+
exponent = (int)iidx - 1;
|
409
|
+
/* delete leading zeros */
|
410
|
+
while (mantissa_size > 0 && p[0] == 0) {
|
411
|
+
mantissa_size--;
|
412
|
+
exponent--;
|
413
|
+
p++;
|
414
|
+
}
|
415
|
+
/* delete trailing zeros */
|
416
|
+
while (mantissa_size > 0 && p[mantissa_size - 1] == 0) {
|
417
|
+
mantissa_size--;
|
418
|
+
}
|
419
|
+
/* check size */
|
420
|
+
if (mantissa_size > sizeof(ovn->num.mantissa))
|
421
|
+
return 1;
|
422
|
+
if (mantissa_size == 0) {
|
423
|
+
ovn->size = 1;
|
424
|
+
ovn->num.exponent = 0x80;
|
425
|
+
return 0;
|
426
|
+
}
|
427
|
+
if (sign > 0) {
|
428
|
+
ovn->size = mantissa_size + 1;
|
429
|
+
ovn->num.exponent = 0x80 + exponent + 65;
|
430
|
+
for (i = 0; i < mantissa_size; i++) {
|
431
|
+
ovn->num.mantissa[i] = p[i] + 1;
|
432
|
+
}
|
433
|
+
} else {
|
434
|
+
ovn->size = mantissa_size + 1;
|
435
|
+
ovn->num.exponent = 62 - exponent;
|
436
|
+
for (i = 0; i < mantissa_size; i++) {
|
437
|
+
ovn->num.mantissa[i] = 101 - p[i];
|
438
|
+
}
|
439
|
+
if (mantissa_size < 20) {
|
440
|
+
ovn->size++;
|
441
|
+
ovn->num.mantissa[i] = 102;
|
442
|
+
}
|
443
|
+
}
|
444
|
+
return 0;
|
445
|
+
}
|