cubrid 9.3.0 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,62 +31,23 @@
31
31
  require 'mkmf'
32
32
  require 'rbconfig'
33
33
 
34
-
35
- if RUBY_PLATFORM.include?"linux"
36
-
37
- if RUBY_PLATFORM.include?"64"
38
- $os_type="x64"
39
- else
40
- $os_type="x86"
41
- end
42
-
43
- system("chmod +x build_cci.sh")
44
- system("./build_cci.sh",$os_type)
45
-
46
- cci_lib_path = "cci-src/cci/.libs/libcascci.a"
47
- cci_base_inc_path = "./cci-src/src/base"
48
- cci_cci_inc_path = "./cci-src/src/cci"
49
- cci_broker_inc_path = "./cci-src/src/broker"
50
-
51
- $INCFLAGS = ($INCFLAGS ? $INCFLAGS : "") + " -I" + cci_base_inc_path \
52
- +" -I" + cci_cci_inc_path +" -I" + cci_broker_inc_path
53
-
54
- if(ARGV[0] == "daily")
55
- print "daily test"
56
- $CPPFLAGS =($CPPFLAGS ? $CPPFLAGS : "") + " -fprofile-arcs -ftest-coverage"
57
- $LDFLAGS =($LDFLAGS ? $LDFLAGS : "") + " -lgcov"
58
- end
59
-
60
- if !$LIBPATH
61
- $LIBPATH = []
62
- end
63
-
64
- $LIBPATH.push(cci_lib_path)
65
-
66
- if have_library("supc++") and have_library("stdc++")
67
- create_makefile("cubrid")
68
- else
69
- puts "your system can not support supc++ or stdc++,install failed."
70
- end
71
-
72
- else
73
- if ENV["CUBRID"]
74
- cci_lib_path = ENV["CUBRID"] + "\\lib"
75
- cci_inc_path = ENV["CUBRID"] + "\\include"
76
-
77
- $INCFLAGS = ($INCFLAGS ? $INCFLAGS : "") + " -I" + cci_inc_path
78
-
79
- if !$LIBPATH
80
- $LIBPATH = []
81
- end
82
-
83
- $LIBPATH.push(cci_lib_path)
84
- if have_library("cascci", "cci_init")
85
- create_makefile("cubrid")
86
- else
87
- puts "cascci could not be found.\nPlease check if CUBRID database is installed and if the $CUBRID environment variable is correctly set to the location where cubrid is installed."
88
- end
89
- else
90
- puts "$CUBRID environment variable is not defined.\nPlease check that you have installed CUBRID database and if the $CUBRID environment variable is correctly set to the location where cubrid is installed."
91
- end
34
+ if ENV["CUBRID"]
35
+ cci_lib_path = ENV["CUBRID"] + "/lib"
36
+ cci_inc_path = ENV["CUBRID"] + "/include"
37
+
38
+ $INCFLAGS = ($INCFLAGS ? $INCFLAGS : "") + " -I" + cci_inc_path
39
+
40
+ if !$LIBPATH
41
+ $LIBPATH = []
42
+ end
43
+
44
+ $LIBPATH.push(cci_lib_path)
45
+
46
+ if have_library("cascci", "cci_init")
47
+ create_makefile("cubrid")
48
+ else
49
+ puts "cascci could not be found. Possibly you have not installed CUBRID Database yet."
50
+ end
51
+ else
52
+ puts "$CUBRID_BROKER is not defined. Possibly you have not installed CUBRID Database yet."
92
53
  end
data/ext/stmt.c CHANGED
@@ -1,1044 +1,1019 @@
1
- /*
2
- * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution.
3
- *
4
- * Redistribution and use in source and binary forms, with or without modification,
5
- * are permitted provided that the following conditions are met:
6
- *
7
- * - Redistributions of source code must retain the above copyright notice,
8
- * this list of conditions and the following disclaimer.
9
- *
10
- * - Redistributions in binary form must reproduce the above copyright notice,
11
- * this list of conditions and the following disclaimer in the documentation
12
- * and/or other materials provided with the distribution.
13
- *
14
- * - Neither the name of the <ORGANIZATION> nor the names of its contributors
15
- * may be used to endorse or promote products derived from this software without
16
- * specific prior written permission.
17
- *
18
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27
- * OF SUCH DAMAGE.
28
- *
29
- */
30
-
31
- #include "cubrid.h"
32
-
33
- extern VALUE cubrid_conn_end_tran(Connection *con, int type);
34
-
35
- extern VALUE cStatement, cOid;
36
-
37
- char*
38
- get_type_name_by_u_type(T_CCI_COL_INFO * column_info)
39
- {
40
- int i,u_type;
41
- int size = sizeof(db_type_info) / sizeof(db_type_info[0]);
42
- char buf[64] = {'\0'};
43
- int type_buf_len=63;
44
-
45
- u_type = CCI_GET_COLLECTION_DOMAIN(column_info->type);
46
- for (i = 0; i < size; i++) {
47
- if (db_type_info[i].cubrid_u_type== u_type) {
48
- break;
49
- }
50
- }
51
-
52
- if (CCI_IS_SET_TYPE(column_info->type)) {
53
- snprintf(buf, type_buf_len, "set(%s)", db_type_info[i].type_name);
54
- } else if (CCI_IS_MULTISET_TYPE(column_info->type)) {
55
- snprintf(buf, type_buf_len, "multiset(%s)", db_type_info[i].type_name);
56
- } else if (CCI_IS_SEQUENCE_TYPE(column_info->type)) {
57
- snprintf(buf, type_buf_len, "sequence(%s)", db_type_info[i].type_name);
58
- } else {
59
- return db_type_info[i].type_name;
60
- }
61
- return buf;
62
- }
63
-
64
- void
65
- cubrid_stmt_free(void *p)
66
- {
67
- free(p);
68
- }
69
-
70
- VALUE
71
- cubrid_stmt_new(Connection *con, char *sql, int option)
72
- {
73
- VALUE cursor;
74
- Statement *stmt;
75
- int handle, param_cnt;
76
- T_CCI_ERROR error;
77
-
78
- /* printf("%s\n", sql); */
79
-
80
- handle = cci_prepare(con->handle, sql, option, &error);
81
- if (handle < 0) {
82
- cubrid_handle_error(handle, &error);
83
- return Qnil;
84
- }
85
-
86
- param_cnt = cci_get_bind_num(handle);
87
- if (param_cnt < 0) {
88
- cubrid_handle_error(param_cnt, NULL);
89
- return Qnil;
90
- }
91
-
92
- cursor = Data_Make_Struct(cStatement, Statement, 0, cubrid_stmt_free, stmt);
93
- stmt->con = con;
94
- stmt->handle = handle;
95
- stmt->param_cnt = param_cnt;
96
- stmt->bound = 0;
97
-
98
- return cursor;
99
- }
100
-
101
- /* call-seq:
102
- * close() -> nil
103
- */
104
- VALUE
105
- cubrid_stmt_close(VALUE self)
106
- {
107
- Statement *stmt;
108
-
109
- GET_STMT_STRUCT(self, stmt);
110
-
111
- if (stmt->handle) {
112
- cci_close_req_handle(stmt->handle);
113
- stmt->handle = 0;
114
- }
115
-
116
- return Qnil;
117
- }
118
-
119
- T_CCI_SET
120
- cubrid_stmt_make_set(VALUE data, int u_type) /* TODO: check if all item has same type */
121
- {
122
- int i, arr_size, res;
123
- T_CCI_SET set = NULL;
124
- void *val = NULL;
125
- int *ind;
126
-
127
- arr_size = RARRAY_LEN(data);//RARRAY(data)->len;
128
- ind = ALLOCA_N(int, arr_size);
129
- if (ind == NULL) {
130
- rb_raise(rb_eNoMemError, "Not enough memory");
131
- return NULL;
132
- }
133
-
134
- switch (TYPE(rb_ary_entry(data, 0))) {
135
- case T_FIXNUM:
136
- case T_BIGNUM:
137
- {
138
- int *int_ary = ALLOCA_N(int, arr_size);
139
- if (int_ary == NULL) {
140
- rb_raise(rb_eNoMemError, "Not enough memory");
141
- return NULL;
142
- }
143
-
144
- for(i = 0; i < arr_size; i++) {
145
- if (NIL_P(rb_ary_entry(data, i))) {
146
- ind[i] = 1;
147
- }
148
- else {
149
- int_ary[i] = NUM2INT(rb_ary_entry(data, i));
150
- ind[i] = 0;
151
- }
152
- }
153
-
154
- if (u_type == CCI_U_TYPE_UNKNOWN) {
155
- u_type = CCI_U_TYPE_INT;
156
- }
157
- val = int_ary;
158
- }
159
- break;
160
- case T_FLOAT:
161
- {
162
- double *dbl_ary;
163
-
164
- dbl_ary = ALLOCA_N(double, arr_size);
165
- if (dbl_ary == NULL) {
166
- rb_raise(rb_eNoMemError, "Not enough memory");
167
- return NULL;
168
- }
169
-
170
- for(i = 0; i < arr_size; i++) {
171
- if (NIL_P(rb_ary_entry(data, i))) {
172
- ind[i] = 1;
173
- }
174
- else {
175
- dbl_ary[i] = NUM2DBL(rb_ary_entry(data, i));
176
- ind[i] = 0;
177
- }
178
- }
179
-
180
- if (u_type == CCI_U_TYPE_UNKNOWN) {
181
- u_type = CCI_U_TYPE_DOUBLE;
182
- }
183
- val = dbl_ary;
184
- }
185
- break;
186
- case T_STRING:
187
- {
188
- if (u_type == CCI_U_TYPE_BIT || u_type == CCI_U_TYPE_VARBIT) {
189
- T_CCI_BIT *bit_ary;
190
-
191
- bit_ary = ALLOCA_N(T_CCI_BIT, arr_size);
192
- if (bit_ary == NULL) {
193
- rb_raise(rb_eNoMemError, "Not enough memory");
194
- return NULL;
195
- }
196
-
197
- for(i = 0; i < arr_size; i++) {
198
- if (NIL_P(rb_ary_entry(data, i))) {
199
- ind[i] = 1;
200
- }
201
- else {
202
- bit_ary[i].size =RSTRING_LEN(rb_ary_entry(data, i));//RSTRING(rb_ary_entry(data, i))->len;
203
- bit_ary[i].buf =RSTRING_PTR(rb_ary_entry(data, i)); //RSTRING(rb_ary_entry(data, i))->ptr;
204
- ind[i] = 0;
205
- }
206
- }
207
-
208
- val = bit_ary;
209
- } else {
210
- char **str_ary;
211
-
212
- str_ary = ALLOCA_N(char*, arr_size);
213
- if (str_ary == NULL) {
214
- rb_raise(rb_eNoMemError, "Not enough memory");
215
- return NULL;
216
- }
217
-
218
- for(i = 0; i < arr_size; i++) {
219
- if (NIL_P(rb_ary_entry(data, i))) {
220
- ind[i] = 1;
221
- }
222
- else {
223
- str_ary[i] =RSTRING_PTR(rb_ary_entry(data, i));// RSTRING(rb_ary_entry(data, i))->ptr;
224
- ind[i] = 0;
225
- }
226
- }
227
-
228
- if (u_type == CCI_U_TYPE_UNKNOWN) {
229
- u_type = CCI_U_TYPE_STRING;
230
- }
231
- val = str_ary;
232
- }
233
- }
234
- break;
235
- case T_DATA:
236
- if (CLASS_OF(rb_ary_entry(data, 0)) == rb_cTime) {
237
- VALUE a;
238
- T_CCI_DATE *date_ary;
239
-
240
- date_ary = ALLOCA_N(T_CCI_DATE, arr_size);
241
- if (date_ary == NULL) {
242
- rb_raise(rb_eNoMemError, "Not enough memory");
243
- return NULL;
244
- }
245
-
246
- for(i = 0; i < arr_size; i++) {
247
- if (NIL_P(rb_ary_entry(data, i))) {
248
- ind[i] = 1;
249
- }
250
- else {
251
- a = rb_funcall(rb_ary_entry(data, i), rb_intern("to_a"), 0);
252
- date_ary[i].ss = FIX2INT(RARRAY_PTR(a)[0]);
253
- date_ary[i].mm = FIX2INT(RARRAY_PTR(a)[1]);
254
- date_ary[i].hh = FIX2INT(RARRAY_PTR(a)[2]);
255
- date_ary[i].day = FIX2INT(RARRAY_PTR(a)[3]);
256
- date_ary[i].mon = FIX2INT(RARRAY_PTR(a)[4]);
257
- date_ary[i].yr = FIX2INT(RARRAY_PTR(a)[5]);
258
-
259
- ind[i] = 0;
260
- }
261
- }
262
-
263
- if (u_type == CCI_U_TYPE_UNKNOWN) {
264
- u_type = CCI_U_TYPE_TIMESTAMP;
265
- }
266
- val = date_ary;
267
- } else if (CLASS_OF(rb_ary_entry(data, 0)) == cOid) {
268
- char **str_ary;
269
- Oid *oid;
270
-
271
- str_ary = ALLOCA_N(char*, arr_size);
272
- if (str_ary == NULL) {
273
- rb_raise(rb_eNoMemError, "Not enough memory");
274
- return NULL;
275
- }
276
-
277
- for(i = 0; i < arr_size; i++) {
278
- if (NIL_P(rb_ary_entry(data, i))) {
279
- ind[i] = 1;
280
- }
281
- else {
282
- Data_Get_Struct(rb_ary_entry(data, i), Oid, oid);
283
- str_ary[i] = oid->oid_str;
284
- ind[i] = 0;
285
- }
286
- }
287
-
288
- if (u_type == CCI_U_TYPE_UNKNOWN) {
289
- u_type = CCI_U_TYPE_OBJECT;
290
- }
291
- val = str_ary;
292
- }
293
- break;
294
- default:
295
- rb_raise(rb_eArgError, "Wrong data type");
296
- break;
297
- }
298
-
299
- res = cci_set_make(&set, u_type, arr_size, val, ind);
300
- if (res < 0) {
301
- cubrid_handle_error(res, NULL);
302
- return NULL;
303
- }
304
-
305
- return set;
306
- }
307
-
308
- static void
309
- cubrid_stmt_bind_internal(Statement *stmt, int index, VALUE data, int u_type, int set_type)
310
- {
311
- int res, int_val, a_type = CCI_A_TYPE_STR;
312
- char *str_val;
313
- double dbl_val;
314
- void *val = NULL;
315
- T_CCI_SET set = NULL;
316
- T_CCI_DATE date;
317
- T_CCI_BIT bit;
318
-
319
- switch (TYPE(data)) {
320
- case T_NIL:
321
- a_type = CCI_A_TYPE_STR;
322
- val = NULL;
323
- u_type = CCI_U_TYPE_NULL;
324
- break;
325
-
326
- case T_FIXNUM:
327
- case T_BIGNUM:
328
- int_val = NUM2INT(data);
329
- a_type = CCI_A_TYPE_INT;
330
- val = &int_val;
331
- if (u_type == CCI_U_TYPE_UNKNOWN) {
332
- u_type = CCI_U_TYPE_INT;
333
- }
334
- break;
335
-
336
- case T_FLOAT:
337
- dbl_val = NUM2DBL(data);
338
- a_type = CCI_A_TYPE_DOUBLE;
339
- val = &dbl_val;
340
- if (u_type == CCI_U_TYPE_UNKNOWN) {
341
- u_type = CCI_U_TYPE_DOUBLE;
342
- }
343
- break;
344
-
345
- case T_STRING:
346
- str_val = StringValueCStr(data);
347
- a_type = CCI_A_TYPE_STR;
348
- val = str_val;
349
- if (u_type == CCI_U_TYPE_UNKNOWN) {
350
- u_type = CCI_U_TYPE_STRING;
351
- } else if (u_type == CCI_U_TYPE_BIT || u_type == CCI_U_TYPE_VARBIT) {
352
- bit.size = RARRAY_LEN(data);
353
- bit.buf = str_val;
354
- a_type = CCI_A_TYPE_BIT;
355
- val = &bit;
356
- }
357
- break;
358
-
359
- case T_DATA:
360
- if (CLASS_OF(data) == rb_cTime) {
361
- VALUE a;
362
-
363
- a = rb_funcall(data, rb_intern("to_a"), 0);
364
- date.ss = FIX2INT(RARRAY_PTR(a)[0]);
365
- date.mm = FIX2INT(RARRAY_PTR(a)[1]);
366
- date.hh = FIX2INT(RARRAY_PTR(a)[2]);
367
- date.day = FIX2INT(RARRAY_PTR(a)[3]);
368
- date.mon = FIX2INT(RARRAY_PTR(a)[4]);
369
- date.yr = FIX2INT(RARRAY_PTR(a)[5]);
370
-
371
- a_type = CCI_A_TYPE_DATE;
372
- val = &date;
373
- if (u_type == CCI_U_TYPE_UNKNOWN) {
374
- u_type = CCI_U_TYPE_TIMESTAMP;
375
- }
376
- } else if (CLASS_OF(data) == cOid) {
377
- Oid *oid;
378
-
379
- Data_Get_Struct(data, Oid, oid);
380
- a_type = CCI_A_TYPE_STR;
381
- val = oid->oid_str;
382
- if (u_type == CCI_U_TYPE_UNKNOWN) {
383
- u_type = CCI_U_TYPE_OBJECT;
384
- }
385
- }
386
- break;
387
-
388
- case T_ARRAY:
389
- set = cubrid_stmt_make_set(data, set_type);
390
- a_type = CCI_A_TYPE_SET;
391
- val = set;
392
- if (u_type == CCI_U_TYPE_UNKNOWN) {
393
- u_type = CCI_U_TYPE_SET;
394
- }
395
- break;
396
-
397
- default:
398
- rb_raise(rb_eArgError, "Wrong data type");
399
- return;
400
- }
401
-
402
- res = cci_bind_param(stmt->handle, index, a_type, val, u_type, 0);
403
-
404
- if (TYPE(data) == T_ARRAY && set) {
405
- cci_set_free(set);
406
- }
407
-
408
- if (res < 0) {
409
- cubrid_handle_error(res, NULL);
410
- return;
411
- }
412
-
413
- return;
414
- }
415
-
416
- /* call-seq:
417
- * bind(index, data <, db_type, set_type>) -> nil
418
- *
419
- * *fixnum, bignum -> integer
420
- * *float -> double
421
- * *string -> string(varchar)
422
- * *Time -> timestamp
423
- * *Oid -> object
424
- * *array -> collection
425
- *
426
- *
427
- * con = Cubrid.connect('demodb')
428
- * con.auto_commit = true
429
- * con.query('create table a (a int, b double, c string, d date)')
430
- * con.prepare('insert into a values (?, ?, ?, ?)') { |stmt|
431
- * stmt.bind(1, 10)
432
- * stmt.bind(2, 3.141592)
433
- * stmt.bind(3, 'hello')
434
- * stmt.bind(4, Time.local(2007, 12, 25, 10, 10, 10), CUBRID::DATE)
435
- * stmt.execute
436
- * }
437
- * con.close
438
- */
439
- VALUE
440
- cubrid_stmt_bind(int argc, VALUE* argv, VALUE self)
441
- {
442
- Statement *stmt;
443
- VALUE index, u_type, data, set_type;
444
-
445
- GET_STMT_STRUCT(self, stmt);
446
- CHECK_HANDLE(stmt, self);
447
-
448
- rb_scan_args(argc, argv, "22", &index, &data, &u_type, &set_type);
449
-
450
- if (NIL_P(u_type)) {
451
- u_type = INT2NUM(CCI_U_TYPE_UNKNOWN);
452
- }
453
-
454
- if (NIL_P(set_type)) {
455
- set_type = INT2NUM(CCI_U_TYPE_UNKNOWN);
456
- }
457
-
458
- cubrid_stmt_bind_internal(stmt, NUM2INT(index), data, NUM2INT(u_type), NUM2INT(set_type));
459
- stmt->bound = 1;
460
-
461
- return Qnil;
462
- }
463
-
464
- static int
465
- cubrid_stmt_is_auto_commitable(T_CCI_SQLX_CMD cmd)
466
- {
467
- switch(cmd) {
468
- case SQLX_CMD_SELECT:
469
- case SQLX_CMD_CALL:
470
- case SQLX_CMD_CALL_SP:
471
- case SQLX_CMD_COMMIT_WORK:
472
- case SQLX_CMD_ROLLBACK_WORK:
473
- case SQLX_CMD_GET_ISO_LVL:
474
- case SQLX_CMD_GET_TIMEOUT:
475
- case SQLX_CMD_GET_OPT_LVL:
476
- case SQLX_CMD_GET_TRIGGER:
477
- case SQLX_CMD_SAVEPOINT:
478
- case SQLX_CMD_GET_LDB:
479
- case SQLX_CMD_GET_STATS:
480
- return 0;
481
- }
482
-
483
- return 1;
484
- }
485
-
486
- /* call-seq:
487
- * execute() -> int
488
- * execute(...) -> int
489
- *
490
- * con = Cubrid.connect('demodb')
491
- * con.prepare('insert into a values (?, ?, ?, ?)') { |stmt|
492
- * stmt.execute (10, 3.141592, 'hello', Time.local(2007, 12, 25))
493
- * }
494
- * con.close
495
- */
496
- VALUE
497
- cubrid_stmt_execute(int argc, VALUE* argv, VALUE self)
498
- {
499
- T_CCI_ERROR error;
500
- T_CCI_COL_INFO *res_col_info;
501
- T_CCI_SQLX_CMD res_sql_type;
502
- int res_col_count, row_count;
503
- Statement *stmt;
504
-
505
- GET_STMT_STRUCT(self, stmt);
506
- CHECK_HANDLE(stmt, self);
507
-
508
- if (!stmt->bound && stmt->param_cnt != argc) {
509
- rb_raise(rb_eStandardError, "execute: param_count(%d) != number of argument(%d)",
510
- stmt->param_cnt, argc);
511
- return INT2NUM(0);
512
- }
513
-
514
- if (argc > 0) {
515
- int i;
516
- for (i = 0; i < argc; i++) {
517
- cubrid_stmt_bind_internal(stmt, i + 1, argv[i], CCI_U_TYPE_UNKNOWN, CCI_U_TYPE_UNKNOWN);
518
- }
519
- }
520
-
521
- row_count = cci_execute(stmt->handle, 0, 0, &error);
522
- if (row_count < 0) {
523
- cubrid_handle_error(row_count, &error);
524
- return INT2NUM(0);
525
- }
526
-
527
- res_col_info = cci_get_result_info(stmt->handle, &res_sql_type, &res_col_count);
528
- if (res_sql_type == SQLX_CMD_SELECT && !res_col_info) {
529
- cubrid_handle_error(CUBRID_ER_CANNOT_GET_COLUMN_INFO, &error);
530
- return INT2NUM(0);
531
- }
532
-
533
- stmt->col_info = res_col_info;
534
- stmt->sql_type = res_sql_type;
535
- stmt->col_count = res_col_count;
536
- stmt->affected_rows = row_count;
537
-
538
- if(stmt->con->auto_commit == Qtrue && cubrid_stmt_is_auto_commitable(stmt->sql_type)) {
539
- cubrid_conn_end_tran(stmt->con, CCI_TRAN_COMMIT);
540
- }
541
-
542
- stmt->bound = 0;
543
- return INT2NUM(row_count);
544
- }
545
-
546
- /* call-seq:
547
- * affected_rows() -> int
548
- */
549
- VALUE
550
- cubrid_stmt_affected_rows(VALUE self)
551
- {
552
- Statement *stmt;
553
-
554
- GET_STMT_STRUCT(self, stmt);
555
- CHECK_HANDLE(stmt, self);
556
-
557
- return INT2NUM(stmt->affected_rows);
558
- }
559
-
560
- static int ut_str_to_bigint (char *str, CUBRID_LONG_LONG * value)
561
- { char *end_p;
562
- CUBRID_LONG_LONG bi_val;
563
- bi_val = strtoll (str, &end_p, 10);
564
- if (*end_p == 0 || *end_p == '.' || isspace ((int) *end_p))
565
- {
566
- *value = bi_val;
567
- return 0;
568
- }
569
-
570
- return (-1);
571
-
572
- }
573
-
574
-
575
- static VALUE
576
- cubrid_stmt_dbval_to_ruby_value(int req_handle, int type, int index, Connection *con)
577
- {
578
- int res, ind;
579
- VALUE val;
580
- char *res_buf;
581
- int int_val;
582
- double double_val;
583
- T_CCI_DATE date;
584
- T_CCI_BIT bit;
585
- CUBRID_LONG_LONG l_val;
586
-
587
- switch (type) {
588
- case CCI_U_TYPE_INT:
589
- case CCI_U_TYPE_SHORT:
590
- res = cci_get_data(req_handle, index, CCI_A_TYPE_INT, &int_val, &ind);
591
- if (res < 0) {
592
- cubrid_handle_error(res, NULL);
593
- return Qnil;
594
- }
595
-
596
- if (ind < 0) {
597
- val = Qnil;
598
- } else {
599
- val = INT2NUM(int_val);
600
- }
601
- break;
602
- case CCI_U_TYPE_BIGINT:
603
- res = cci_get_data(req_handle, index, CCI_A_TYPE_STR, &res_buf, &ind);
604
- if (res < 0) {
605
- cubrid_handle_error(res, NULL);
606
- return Qnil;
607
- }
608
-
609
- res = ut_str_to_bigint(res_buf,&l_val);
610
- if(res < 0){
611
- cubrid_handle_error(res, NULL);
612
- return Qnil;
613
- }
614
- if (ind < 0) {
615
- val = Qnil;
616
- } else {
617
- val = LL2NUM(l_val);
618
- }
619
- break;
620
- case CCI_U_TYPE_FLOAT:
621
- case CCI_U_TYPE_DOUBLE:
622
- //case CCI_U_TYPE_NUMERIC:
623
- case CCI_U_TYPE_MONETARY:
624
- res = cci_get_data(req_handle, index, CCI_A_TYPE_STR, &res_buf, &ind);
625
- if (res < 0) {
626
- cubrid_handle_error(res, NULL);
627
- return Qnil;
628
- }
629
- if (ind < 0) {
630
- val = Qnil;
631
- } else {
632
- double_val = atof(res_buf);
633
- val = rb_float_new(double_val);
634
- }
635
- break;
636
- case CCI_U_TYPE_DATE:
637
- case CCI_U_TYPE_TIME:
638
- case CCI_U_TYPE_TIMESTAMP:
639
- res = cci_get_data(req_handle, index, CCI_A_TYPE_DATE, &date, &ind);
640
- if (res < 0) {
641
- cubrid_handle_error(res, NULL);
642
- return Qnil;
643
- }
644
- if (ind < 0) {
645
- val = Qnil;
646
- } else {
647
- if (type == CCI_U_TYPE_DATE) {
648
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 3,
649
- INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day));
650
- } else if (type == CCI_U_TYPE_TIME) {
651
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
652
- INT2NUM(1970), INT2NUM(1), INT2NUM(1),
653
- INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
654
- } else {
655
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
656
- INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day),
657
- INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
658
- }
659
- }
660
- break;
661
-
662
- case CCI_U_TYPE_BIT:
663
- case CCI_U_TYPE_VARBIT:
664
- res = cci_get_data(req_handle, index, CCI_A_TYPE_BIT, &bit, &ind);
665
- if (res < 0) {
666
- cubrid_handle_error(res, NULL);
667
- return Qnil;
668
- }
669
- if (ind < 0) {
670
- val = Qnil;
671
- } else {
672
- val = rb_tainted_str_new(bit.buf, bit.size);
673
- }
674
- break;
675
-
676
- default:
677
- res = cci_get_data(req_handle, index, CCI_A_TYPE_STR, &res_buf, &ind);
678
- if (res < 0) {
679
- cubrid_handle_error(res, NULL);
680
- return Qnil;
681
- }
682
- if (ind < 0) {
683
- val = Qnil;
684
- } else {
685
- val = rb_str_new2(res_buf);
686
- }
687
- break;
688
- }
689
-
690
- return val;
691
- }
692
-
693
- static VALUE
694
- cubrid_stmt_dbval_to_ruby_value_from_set(T_CCI_SET set, int type, int index, Connection *con)
695
- {
696
- int res, ind;
697
- VALUE val;
698
- char *res_buf;
699
- int int_val;
700
- double double_val;
701
- T_CCI_DATE date;
702
- T_CCI_BIT bit;
703
-
704
- switch (type) {
705
- case CCI_U_TYPE_INT:
706
- case CCI_U_TYPE_SHORT:
707
- res = cci_set_get(set, index, CCI_A_TYPE_INT, &int_val, &ind);
708
- if (res < 0) {
709
- cubrid_handle_error(res, NULL);
710
- return Qnil;
711
- }
712
- if (ind < 0) {
713
- val = Qnil;
714
- } else {
715
- val = INT2NUM(int_val);
716
- }
717
- break;
718
-
719
- case CCI_U_TYPE_FLOAT:
720
- case CCI_U_TYPE_DOUBLE:
721
- case CCI_U_TYPE_NUMERIC:
722
- case CCI_U_TYPE_MONETARY:
723
- res = cci_set_get(set, index, CCI_A_TYPE_STR, &res_buf, &ind);
724
- if (res < 0) {
725
- cubrid_handle_error(res, NULL);
726
- return Qnil;
727
- }
728
- if (ind < 0) {
729
- val = Qnil;
730
- } else {
731
- double_val = atof(res_buf);
732
- val = rb_float_new(double_val);
733
- }
734
- break;
735
-
736
- case CCI_U_TYPE_DATE:
737
- case CCI_U_TYPE_TIME:
738
- case CCI_U_TYPE_TIMESTAMP:
739
- res = cci_set_get(set, index, CCI_A_TYPE_DATE, &date, &ind);
740
- if (res < 0) {
741
- cubrid_handle_error(res, NULL);
742
- return Qnil;
743
- }
744
- if (ind < 0) {
745
- val = Qnil;
746
- } else {
747
- if (type == CCI_U_TYPE_DATE) {
748
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 3,
749
- INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day));
750
- } else if (type == CCI_U_TYPE_TIME) {
751
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
752
- INT2NUM(1970), INT2NUM(1), INT2NUM(1),
753
- INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
754
- } else {
755
- val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
756
- INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day),
757
- INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
758
- }
759
- }
760
- break;
761
-
762
- case CCI_U_TYPE_BIT:
763
- case CCI_U_TYPE_VARBIT:
764
- res = cci_set_get(set, index, CCI_A_TYPE_BIT, &bit, &ind);
765
- if (res < 0) {
766
- cubrid_handle_error(res, NULL);
767
- return Qnil;
768
- }
769
- if (ind < 0) {
770
- val = Qnil;
771
- } else {
772
- val = rb_tainted_str_new(bit.buf, bit.size);
773
- }
774
- break;
775
-
776
- default:
777
- res = cci_set_get(set, index, CCI_A_TYPE_STR, &res_buf, &ind);
778
- if (res < 0) {
779
- cubrid_handle_error(res, NULL);
780
- return Qnil;
781
- }
782
- if (ind < 0) {
783
- val = Qnil;
784
- } else {
785
- val = rb_str_new2(res_buf);
786
- }
787
- break;
788
- }
789
-
790
- return val;
791
- }
792
-
793
- static VALUE
794
- cubrid_stmt_dbset_to_ruby_value(int req_handle, int index, Connection *con)
795
- {
796
- int i, res, ind, e_type;
797
- VALUE val, e;
798
- T_CCI_SET set = NULL;
799
- int set_size;
800
-
801
- res = cci_get_data(req_handle, index, CCI_A_TYPE_SET, &set, &ind);
802
- if (res < 0) {
803
- cubrid_handle_error(res, NULL);
804
- return Qnil;
805
- }
806
-
807
- if (set == NULL)
808
- return Qnil;
809
-
810
- set_size = cci_set_size(set);
811
- val = rb_ary_new2(set_size);
812
-
813
- e_type = cci_set_element_type(set);
814
-
815
- for (i = 0; i < set_size; i++) {
816
- e = cubrid_stmt_dbval_to_ruby_value_from_set(set, e_type, i + 1, con);
817
- rb_ary_push(val, e);
818
- }
819
- cci_set_free(set);
820
-
821
- return val;
822
- }
823
-
824
- VALUE
825
- cubrid_stmt_fetch_one_row(int req_handle, int col_count, T_CCI_COL_INFO *col_info, Connection *con)
826
- {
827
- int i, type;
828
- VALUE row, val;
829
-
830
- row = rb_ary_new();
831
-
832
- for (i = 0; i < col_count; i++) {
833
- type = CCI_GET_RESULT_INFO_TYPE(col_info, i + 1);
834
-
835
- if (CCI_IS_COLLECTION_TYPE(type)) {
836
- val = cubrid_stmt_dbset_to_ruby_value(req_handle, i + 1, con);
837
- } else {
838
- val = cubrid_stmt_dbval_to_ruby_value(req_handle, type, i + 1, con);
839
- }
840
-
841
- rb_ary_push(row, val);
842
- }
843
-
844
- return row;
845
- }
846
-
847
- /* call-seq:
848
- * fetch() -> array or nil
849
- *
850
- * con = Cubrid.connect('demodb')
851
- * con.prepare('SELECT * FROM db_user') { |stmt|
852
- * stmt.execute
853
- * r = stmt.fetch
854
- * print r[0]
855
- * }
856
- * con.close
857
- *
858
- * *int, short -> fixnum, bignum
859
- * *float, double, numeric, monetary -> float
860
- * *char, varchar, ncahr, varnchar -> string
861
- * *bit, varbit -> string
862
- * *date, time, timestamp -> Time
863
- * *object -> Oid
864
- * *collection -> array
865
- *
866
- */
867
- VALUE
868
- cubrid_stmt_fetch(VALUE self)
869
- {
870
- int res;
871
- T_CCI_ERROR error;
872
- Statement *stmt;
873
-
874
- GET_STMT_STRUCT(self, stmt);
875
- CHECK_HANDLE(stmt, self);
876
-
877
- res = cci_cursor(stmt->handle, 1, CCI_CURSOR_CURRENT, &error);
878
- if (res == CCI_ER_NO_MORE_DATA) {
879
- return Qnil;
880
- } else if (res < 0) {
881
- cubrid_handle_error(res, &error);
882
- return Qnil;
883
- }
884
-
885
- res = cci_fetch(stmt->handle, &error);
886
- if (res < 0) {
887
- cubrid_handle_error(res, &error);
888
- return Qnil;
889
- }
890
-
891
- return cubrid_stmt_fetch_one_row(stmt->handle, stmt->col_count, stmt->col_info, stmt->con);
892
- }
893
-
894
- /* call-seq:
895
- * fetch_hash() -> hash or nil
896
-
897
- * con = Cubrid.connect('demodb')
898
- * con.prepare('SELECT * FROM db_user') { |stmt|
899
- * stmt.execute
900
- * r = stmt.fetch_hash
901
- * print r['name']
902
- * }
903
- * con.close
904
- */
905
- VALUE
906
- cubrid_stmt_fetch_hash(VALUE self)
907
- {
908
- VALUE row, col, hash;
909
- int i;
910
- char colName[128];
911
- Statement *stmt;
912
-
913
- GET_STMT_STRUCT(self, stmt);
914
- CHECK_HANDLE(stmt, self);
915
-
916
- row = cubrid_stmt_fetch(self);
917
- if (NIL_P(row))
918
- return Qnil;
919
-
920
- hash = rb_hash_new();
921
- for(i = 0; i < stmt->col_count; i++) {
922
- col = RARRAY_PTR(row)[i];
923
- strcpy(colName, CCI_GET_RESULT_INFO_NAME(stmt->col_info, i+1));
924
- rb_hash_aset(hash, rb_str_new2(colName), col);
925
- }
926
-
927
- return hash;
928
- }
929
-
930
- /* call-seq:
931
- * each() { |row| block } -> nil
932
- *
933
- *
934
- * con = Cubrid.connect('demodb')
935
- * con.prepare('SELECT * FROM db_user') { |stmt|
936
- * stmt.execute
937
- * stmt.each { |r|
938
- * print r[0]
939
- * }
940
- * }
941
- * con.close
942
- */
943
- VALUE
944
- cubrid_stmt_each(VALUE self)
945
- {
946
- VALUE row;
947
-
948
- while(1) {
949
- row = cubrid_stmt_fetch(self);
950
- if (NIL_P(row)) {
951
- break;
952
- }
953
- rb_yield(row);
954
- }
955
-
956
- return Qnil;
957
- }
958
-
959
- /* call-seq:
960
- * each_hash() { |hash| block } -> nil
961
- *
962
- * con = Cubrid.connect('demodb')
963
- * con.prepare('SELECT * FROM db_user') { |stmt|
964
- * stmt.execute
965
- * stmt.each_hash { |r|
966
- * print r['name']
967
- * }
968
- * }
969
- * con.close
970
- */
971
- VALUE
972
- cubrid_stmt_each_hash(VALUE self)
973
- {
974
- VALUE row;
975
-
976
- while(1) {
977
- row = cubrid_stmt_fetch_hash(self);
978
- if (NIL_P(row)) {
979
- break;
980
- }
981
- rb_yield(row);
982
- }
983
-
984
- return Qnil;
985
- }
986
-
987
- /* call-seq:
988
- * column_info() -> array
989
- *
990
- * con = Cubrid.connect('demodb')
991
- * con.prepare('SELECT * FROM db_user') { |stmt|
992
- * stmt.column_info.each { |col|
993
- * print col['name']
994
- * print col['type_name']
995
- * print col['precision']
996
- * print col['scale']
997
- * print col['nullable']
998
- * }
999
- * }
1000
- * con.close
1001
- */
1002
- VALUE
1003
- cubrid_stmt_column_info(VALUE self)
1004
- {
1005
- VALUE desc;
1006
- int i;
1007
- char col_name[MAX_STR_LEN];
1008
- int datatype, precision, scale, nullable;
1009
- Statement *stmt;
1010
- char type_name[MAX_STR_LEN]={0};
1011
- GET_STMT_STRUCT(self, stmt);
1012
- CHECK_HANDLE(stmt, self);
1013
-
1014
- desc = rb_ary_new2(stmt->col_count);
1015
-
1016
- for (i = 0; i < stmt->col_count; i++) {
1017
- VALUE item;
1018
- char* temp;
1019
-
1020
- item = rb_hash_new();
1021
-
1022
- strcpy(col_name, CCI_GET_RESULT_INFO_NAME(stmt->col_info, i+1));
1023
- precision = CCI_GET_RESULT_INFO_PRECISION(stmt->col_info, i+1);
1024
- scale = CCI_GET_RESULT_INFO_SCALE(stmt->col_info, i+1);
1025
- nullable = CCI_GET_RESULT_INFO_IS_NON_NULL(stmt->col_info, i+1);
1026
- datatype = CCI_GET_RESULT_INFO_TYPE(stmt->col_info, i+1);
1027
-
1028
- rb_hash_aset(item, rb_str_new2("name"), rb_str_new2(col_name));
1029
-
1030
- temp = get_type_name_by_u_type(&stmt->col_info[i]);
1031
- memcpy(type_name,temp,strlen(temp));
1032
- rb_hash_aset(item, rb_str_new2("type_name"), rb_str_new2(type_name));
1033
- memset(type_name,0,strlen(temp));
1034
-
1035
- rb_hash_aset(item, rb_str_new2("precision"), INT2NUM(precision));
1036
- rb_hash_aset(item, rb_str_new2("scale"), INT2NUM(scale));
1037
- rb_hash_aset(item, rb_str_new2("nullable"), INT2NUM(nullable));
1038
-
1039
- rb_ary_push(desc, item);
1040
- }
1041
-
1042
- return desc;
1043
- }
1044
-
1
+ /*
2
+ * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without modification,
5
+ * are permitted provided that the following conditions are met:
6
+ *
7
+ * - Redistributions of source code must retain the above copyright notice,
8
+ * this list of conditions and the following disclaimer.
9
+ *
10
+ * - Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ *
14
+ * - Neither the name of the <ORGANIZATION> nor the names of its contributors
15
+ * may be used to endorse or promote products derived from this software without
16
+ * specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27
+ * OF SUCH DAMAGE.
28
+ *
29
+ */
30
+
31
+ #include "cubrid.h"
32
+
33
+ extern VALUE cubrid_conn_end_tran(Connection *con, int type);
34
+
35
+ extern VALUE cStatement, cOid;
36
+
37
+ void
38
+ cubrid_stmt_free(void *p)
39
+ {
40
+ free(p);
41
+ }
42
+
43
+ VALUE
44
+ cubrid_stmt_new(Connection *con, char *sql, int option)
45
+ {
46
+ VALUE cursor;
47
+ Statement *stmt;
48
+ int handle, param_cnt;
49
+ T_CCI_ERROR error;
50
+
51
+ /* printf("%s\n", sql); */
52
+
53
+ handle = cci_prepare(con->handle, sql, option, &error);
54
+ if (handle < 0) {
55
+ cubrid_handle_error(handle, &error);
56
+ return Qnil;
57
+ }
58
+
59
+ param_cnt = cci_get_bind_num(handle);
60
+ if (param_cnt < 0) {
61
+ cubrid_handle_error(param_cnt, NULL);
62
+ return Qnil;
63
+ }
64
+
65
+ cursor = Data_Make_Struct(cStatement, Statement, 0, cubrid_stmt_free, stmt);
66
+ stmt->con = con;
67
+ stmt->handle = handle;
68
+ stmt->param_cnt = param_cnt;
69
+ stmt->bound = 0;
70
+
71
+ return cursor;
72
+ }
73
+
74
+ /* call-seq:
75
+ * close() -> nil
76
+ *
77
+ * Statement를 종료합니다.
78
+ */
79
+ VALUE
80
+ cubrid_stmt_close(VALUE self)
81
+ {
82
+ Statement *stmt;
83
+
84
+ GET_STMT_STRUCT(self, stmt);
85
+
86
+ if (stmt->handle) {
87
+ cci_close_req_handle(stmt->handle);
88
+ stmt->handle = 0;
89
+ }
90
+
91
+ return Qnil;
92
+ }
93
+
94
+ T_CCI_SET
95
+ cubrid_stmt_make_set(VALUE data, int u_type) /* TODO: check if all item has same type */
96
+ {
97
+ int i, arr_size, res;
98
+ T_CCI_SET set = NULL;
99
+ void *val = NULL;
100
+ int *ind;
101
+
102
+ arr_size = RARRAY(data)->len;
103
+ ind = ALLOCA_N(int, arr_size);
104
+ if (ind == NULL) {
105
+ rb_raise(rb_eNoMemError, "Not enough memory");
106
+ return NULL;
107
+ }
108
+
109
+ switch (TYPE(rb_ary_entry(data, 0))) {
110
+ case T_FIXNUM:
111
+ case T_BIGNUM:
112
+ {
113
+ int *int_ary = ALLOCA_N(int, arr_size);
114
+ if (int_ary == NULL) {
115
+ rb_raise(rb_eNoMemError, "Not enough memory");
116
+ return NULL;
117
+ }
118
+
119
+ for(i = 0; i < arr_size; i++) {
120
+ if (NIL_P(rb_ary_entry(data, i))) {
121
+ ind[i] = 1;
122
+ }
123
+ else {
124
+ int_ary[i] = NUM2INT(rb_ary_entry(data, i));
125
+ ind[i] = 0;
126
+ }
127
+ }
128
+
129
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
130
+ u_type = CCI_U_TYPE_INT;
131
+ }
132
+ val = int_ary;
133
+ }
134
+ break;
135
+ case T_FLOAT:
136
+ {
137
+ double *dbl_ary;
138
+
139
+ dbl_ary = ALLOCA_N(double, arr_size);
140
+ if (dbl_ary == NULL) {
141
+ rb_raise(rb_eNoMemError, "Not enough memory");
142
+ return NULL;
143
+ }
144
+
145
+ for(i = 0; i < arr_size; i++) {
146
+ if (NIL_P(rb_ary_entry(data, i))) {
147
+ ind[i] = 1;
148
+ }
149
+ else {
150
+ dbl_ary[i] = NUM2DBL(rb_ary_entry(data, i));
151
+ ind[i] = 0;
152
+ }
153
+ }
154
+
155
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
156
+ u_type = CCI_U_TYPE_DOUBLE;
157
+ }
158
+ val = dbl_ary;
159
+ }
160
+ break;
161
+ case T_STRING:
162
+ {
163
+ if (u_type == CCI_U_TYPE_BIT || u_type == CCI_U_TYPE_VARBIT) {
164
+ T_CCI_BIT *bit_ary;
165
+
166
+ bit_ary = ALLOCA_N(T_CCI_BIT, arr_size);
167
+ if (bit_ary == NULL) {
168
+ rb_raise(rb_eNoMemError, "Not enough memory");
169
+ return NULL;
170
+ }
171
+
172
+ for(i = 0; i < arr_size; i++) {
173
+ if (NIL_P(rb_ary_entry(data, i))) {
174
+ ind[i] = 1;
175
+ }
176
+ else {
177
+ bit_ary[i].size = RSTRING(rb_ary_entry(data, i))->len;
178
+ bit_ary[i].buf = RSTRING(rb_ary_entry(data, i))->ptr;
179
+ ind[i] = 0;
180
+ }
181
+ }
182
+
183
+ val = bit_ary;
184
+ } else {
185
+ char **str_ary;
186
+
187
+ str_ary = ALLOCA_N(char*, arr_size);
188
+ if (str_ary == NULL) {
189
+ rb_raise(rb_eNoMemError, "Not enough memory");
190
+ return NULL;
191
+ }
192
+
193
+ for(i = 0; i < arr_size; i++) {
194
+ if (NIL_P(rb_ary_entry(data, i))) {
195
+ ind[i] = 1;
196
+ }
197
+ else {
198
+ str_ary[i] = RSTRING(rb_ary_entry(data, i))->ptr;
199
+ ind[i] = 0;
200
+ }
201
+ }
202
+
203
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
204
+ u_type = CCI_U_TYPE_STRING;
205
+ }
206
+ val = str_ary;
207
+ }
208
+ }
209
+ break;
210
+ case T_DATA:
211
+ if (CLASS_OF(rb_ary_entry(data, 0)) == rb_cTime) {
212
+ VALUE a;
213
+ T_CCI_DATE *date_ary;
214
+
215
+ date_ary = ALLOCA_N(T_CCI_DATE, arr_size);
216
+ if (date_ary == NULL) {
217
+ rb_raise(rb_eNoMemError, "Not enough memory");
218
+ return NULL;
219
+ }
220
+
221
+ for(i = 0; i < arr_size; i++) {
222
+ if (NIL_P(rb_ary_entry(data, i))) {
223
+ ind[i] = 1;
224
+ }
225
+ else {
226
+ a = rb_funcall(rb_ary_entry(data, i), rb_intern("to_a"), 0);
227
+ date_ary[i].ss = FIX2INT(RARRAY(a)->ptr[0]);
228
+ date_ary[i].mm = FIX2INT(RARRAY(a)->ptr[1]);
229
+ date_ary[i].hh = FIX2INT(RARRAY(a)->ptr[2]);
230
+ date_ary[i].day = FIX2INT(RARRAY(a)->ptr[3]);
231
+ date_ary[i].mon = FIX2INT(RARRAY(a)->ptr[4]);
232
+ date_ary[i].yr = FIX2INT(RARRAY(a)->ptr[5]);
233
+
234
+ ind[i] = 0;
235
+ }
236
+ }
237
+
238
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
239
+ u_type = CCI_U_TYPE_TIMESTAMP;
240
+ }
241
+ val = date_ary;
242
+ } else if (CLASS_OF(rb_ary_entry(data, 0)) == cOid) {
243
+ char **str_ary;
244
+ Oid *oid;
245
+
246
+ str_ary = ALLOCA_N(char*, arr_size);
247
+ if (str_ary == NULL) {
248
+ rb_raise(rb_eNoMemError, "Not enough memory");
249
+ return NULL;
250
+ }
251
+
252
+ for(i = 0; i < arr_size; i++) {
253
+ if (NIL_P(rb_ary_entry(data, i))) {
254
+ ind[i] = 1;
255
+ }
256
+ else {
257
+ Data_Get_Struct(rb_ary_entry(data, i), Oid, oid);
258
+ str_ary[i] = oid->oid_str;
259
+ ind[i] = 0;
260
+ }
261
+ }
262
+
263
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
264
+ u_type = CCI_U_TYPE_OBJECT;
265
+ }
266
+ val = str_ary;
267
+ }
268
+ break;
269
+ default:
270
+ rb_raise(rb_eArgError, "Wrong data type");
271
+ break;
272
+ }
273
+
274
+ res = cci_set_make(&set, u_type, arr_size, val, ind);
275
+ if (res < 0) {
276
+ cubrid_handle_error(res, NULL);
277
+ return NULL;
278
+ }
279
+
280
+ return set;
281
+ }
282
+
283
+ static void
284
+ cubrid_stmt_bind_internal(Statement *stmt, int index, VALUE data, int u_type, int set_type)
285
+ {
286
+ int res, int_val, a_type = CCI_A_TYPE_STR;
287
+ char *str_val;
288
+ double dbl_val;
289
+ void *val = NULL;
290
+ T_CCI_SET set = NULL;
291
+ T_CCI_DATE date;
292
+ T_CCI_BIT bit;
293
+
294
+ switch (TYPE(data)) {
295
+ case T_NIL:
296
+ a_type = CCI_A_TYPE_STR;
297
+ val = NULL;
298
+ u_type = CCI_U_TYPE_NULL;
299
+ break;
300
+
301
+ case T_FIXNUM:
302
+ case T_BIGNUM:
303
+ int_val = NUM2INT(data);
304
+ a_type = CCI_A_TYPE_INT;
305
+ val = &int_val;
306
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
307
+ u_type = CCI_U_TYPE_INT;
308
+ }
309
+ break;
310
+
311
+ case T_FLOAT:
312
+ dbl_val = NUM2DBL(data);
313
+ a_type = CCI_A_TYPE_DOUBLE;
314
+ val = &dbl_val;
315
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
316
+ u_type = CCI_U_TYPE_DOUBLE;
317
+ }
318
+ break;
319
+
320
+ case T_STRING:
321
+ str_val = RSTRING(data)->ptr;
322
+ a_type = CCI_A_TYPE_STR;
323
+ val = str_val;
324
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
325
+ u_type = CCI_U_TYPE_STRING;
326
+ } else if (u_type == CCI_U_TYPE_BIT || u_type == CCI_U_TYPE_VARBIT) {
327
+ bit.size = RSTRING(data)->len;
328
+ bit.buf = str_val;
329
+ a_type = CCI_A_TYPE_BIT;
330
+ val = &bit;
331
+ }
332
+ break;
333
+
334
+ case T_DATA:
335
+ if (CLASS_OF(data) == rb_cTime) {
336
+ VALUE a;
337
+
338
+ a = rb_funcall(data, rb_intern("to_a"), 0);
339
+ date.ss = FIX2INT(RARRAY(a)->ptr[0]);
340
+ date.mm = FIX2INT(RARRAY(a)->ptr[1]);
341
+ date.hh = FIX2INT(RARRAY(a)->ptr[2]);
342
+ date.day = FIX2INT(RARRAY(a)->ptr[3]);
343
+ date.mon = FIX2INT(RARRAY(a)->ptr[4]);
344
+ date.yr = FIX2INT(RARRAY(a)->ptr[5]);
345
+
346
+ a_type = CCI_A_TYPE_DATE;
347
+ val = &date;
348
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
349
+ u_type = CCI_U_TYPE_TIMESTAMP;
350
+ }
351
+ } else if (CLASS_OF(data) == cOid) {
352
+ Oid *oid;
353
+
354
+ Data_Get_Struct(data, Oid, oid);
355
+ a_type = CCI_A_TYPE_STR;
356
+ val = oid->oid_str;
357
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
358
+ u_type = CCI_U_TYPE_OBJECT;
359
+ }
360
+ }
361
+ break;
362
+
363
+ case T_ARRAY:
364
+ set = cubrid_stmt_make_set(data, set_type);
365
+ a_type = CCI_A_TYPE_SET;
366
+ val = set;
367
+ if (u_type == CCI_U_TYPE_UNKNOWN) {
368
+ u_type = CCI_U_TYPE_SET;
369
+ }
370
+ break;
371
+
372
+ default:
373
+ rb_raise(rb_eArgError, "Wrong data type");
374
+ return;
375
+ }
376
+
377
+ res = cci_bind_param(stmt->handle, index, a_type, val, u_type, 0);
378
+
379
+ if (TYPE(data) == T_ARRAY && set) {
380
+ cci_set_free(set);
381
+ }
382
+
383
+ if (res < 0) {
384
+ cubrid_handle_error(res, NULL);
385
+ return;
386
+ }
387
+
388
+ return;
389
+ }
390
+
391
+ /* call-seq:
392
+ * bind(index, data <, db_type, set_type>) -> nil
393
+ *
394
+ * prepare된 Statement의 호스트변수에 데이터를 바인딩합니다.
395
+ * db_type은 ruby의 데이터가 바인딩될 때 적용될 데이터베이스의 타입을 지정합니다.
396
+ * db_type이 주어지지 않으면 아래와 같이 기본 타입으로 적용됩니다.
397
+ *
398
+ * *fixnum, bignum -> integer
399
+ * *float -> double
400
+ * *string -> string(varchar)
401
+ * *Time -> timestamp
402
+ * *Oid -> object
403
+ * *array -> collection
404
+ *
405
+ * set_type은 data가 배열인 경우 배열의 원소에 적용될 데이터베이스 타입을 지정합니다.
406
+ * 배열의 모든 원소들은 동일한 타입이어야 합니다.
407
+ * set_type이 주어지지 않으면 배열의 원소들은 기본 타입으로 바인딩됩니다.
408
+ *
409
+ * con = Cubrid.connect('demodb')
410
+ * con.auto_commit = true
411
+ * con.query('create table a (a int, b double, c string, d date)')
412
+ * con.prepare('insert into a values (?, ?, ?, ?)') { |stmt|
413
+ * stmt.bind(1, 10)
414
+ * stmt.bind(2, 3.141592)
415
+ * stmt.bind(3, 'hello')
416
+ * stmt.bind(4, Time.local(2007, 12, 25, 10, 10, 10), CUBRID::DATE)
417
+ * stmt.execute
418
+ * }
419
+ * con.close
420
+ */
421
+ VALUE
422
+ cubrid_stmt_bind(int argc, VALUE* argv, VALUE self)
423
+ {
424
+ Statement *stmt;
425
+ VALUE index, u_type, data, set_type;
426
+
427
+ GET_STMT_STRUCT(self, stmt);
428
+ CHECK_HANDLE(stmt, self);
429
+
430
+ rb_scan_args(argc, argv, "22", &index, &data, &u_type, &set_type);
431
+
432
+ if (NIL_P(u_type)) {
433
+ u_type = INT2NUM(CCI_U_TYPE_UNKNOWN);
434
+ }
435
+
436
+ if (NIL_P(set_type)) {
437
+ set_type = INT2NUM(CCI_U_TYPE_UNKNOWN);
438
+ }
439
+
440
+ cubrid_stmt_bind_internal(stmt, NUM2INT(index), data, NUM2INT(u_type), NUM2INT(set_type));
441
+ stmt->bound = 1;
442
+
443
+ return Qnil;
444
+ }
445
+
446
+ static int
447
+ cubrid_stmt_is_auto_commitable(T_CCI_SQLX_CMD cmd)
448
+ {
449
+ switch(cmd) {
450
+ case SQLX_CMD_SELECT:
451
+ case SQLX_CMD_CALL:
452
+ case SQLX_CMD_CALL_SP:
453
+ case SQLX_CMD_COMMIT_WORK:
454
+ case SQLX_CMD_ROLLBACK_WORK:
455
+ case SQLX_CMD_GET_ISO_LVL:
456
+ case SQLX_CMD_GET_TIMEOUT:
457
+ case SQLX_CMD_GET_OPT_LVL:
458
+ case SQLX_CMD_GET_TRIGGER:
459
+ case SQLX_CMD_SAVEPOINT:
460
+ case SQLX_CMD_GET_LDB:
461
+ case SQLX_CMD_GET_STATS:
462
+ return 0;
463
+ }
464
+
465
+ return 1;
466
+ }
467
+
468
+ /* call-seq:
469
+ * execute() -> int
470
+ * execute(...) -> int
471
+ *
472
+ * prepare된 Statement를 실행하고 검색되거나 영향을 받은 row의 개수를 반환합니다.
473
+ *
474
+ * 인수가 주어지면 prepare된 Statement의 호스트 변수에 데이터를 바인딩합니다.
475
+ * 인수는 순서대로 호스트 변수에 바인딩 되기 때문에 인수의 개수와 호스트 변수의 개수가 일치해야 합니다.
476
+ * 인수는 묵시적으로 기본 타입으로 바인딩 됩니다.
477
+ *
478
+ * connection의 auto commit 모드가 true이면 commit이 곧바로 수행됩니다.
479
+ *
480
+ * con = Cubrid.connect('demodb')
481
+ * con.prepare('insert into a values (?, ?, ?, ?)') { |stmt|
482
+ * stmt.execute (10, 3.141592, 'hello', Time.local(2007, 12, 25))
483
+ * }
484
+ * con.close
485
+ */
486
+ VALUE
487
+ cubrid_stmt_execute(int argc, VALUE* argv, VALUE self)
488
+ {
489
+ T_CCI_ERROR error;
490
+ T_CCI_COL_INFO *res_col_info;
491
+ T_CCI_SQLX_CMD res_sql_type;
492
+ int res_col_count, row_count;
493
+ Statement *stmt;
494
+
495
+ GET_STMT_STRUCT(self, stmt);
496
+ CHECK_HANDLE(stmt, self);
497
+
498
+ if (!stmt->bound && stmt->param_cnt != argc) {
499
+ rb_raise(rb_eStandardError, "execute: param_count(%d) != number of argument(%d)",
500
+ stmt->param_cnt, argc);
501
+ return INT2NUM(0);
502
+ }
503
+
504
+ if (argc > 0) {
505
+ int i;
506
+ for (i = 0; i < argc; i++) {
507
+ cubrid_stmt_bind_internal(stmt, i + 1, argv[i], CCI_U_TYPE_UNKNOWN, CCI_U_TYPE_UNKNOWN);
508
+ }
509
+ }
510
+
511
+ row_count = cci_execute(stmt->handle, 0, 0, &error);
512
+ if (row_count < 0) {
513
+ cubrid_handle_error(row_count, &error);
514
+ return INT2NUM(0);
515
+ }
516
+
517
+ res_col_info = cci_get_result_info(stmt->handle, &res_sql_type, &res_col_count);
518
+ if (res_sql_type == SQLX_CMD_SELECT && !res_col_info) {
519
+ cubrid_handle_error(CUBRID_ER_CANNOT_GET_COLUMN_INFO, &error);
520
+ return INT2NUM(0);
521
+ }
522
+
523
+ stmt->col_info = res_col_info;
524
+ stmt->sql_type = res_sql_type;
525
+ stmt->col_count = res_col_count;
526
+ stmt->affected_rows = row_count;
527
+
528
+ if(stmt->con->auto_commit == Qtrue && cubrid_stmt_is_auto_commitable(stmt->sql_type)) {
529
+ cubrid_stmt_close(self);
530
+ cubrid_conn_end_tran(stmt->con, CCI_TRAN_COMMIT);
531
+ }
532
+
533
+ stmt->bound = 0;
534
+ return INT2NUM(row_count);
535
+ }
536
+
537
+ /* call-seq:
538
+ * affected_rows() -> int
539
+ *
540
+ * 수행된 SQL로 영향을 받았거나 검색된 row의 개수를 반환합니다.
541
+ */
542
+ VALUE
543
+ cubrid_stmt_affected_rows(VALUE self)
544
+ {
545
+ Statement *stmt;
546
+
547
+ GET_STMT_STRUCT(self, stmt);
548
+ CHECK_HANDLE(stmt, self);
549
+
550
+ return INT2NUM(stmt->affected_rows);
551
+ }
552
+
553
+ static VALUE
554
+ cubrid_stmt_dbval_to_ruby_value(int req_handle, int type, int index, Connection *con)
555
+ {
556
+ int res, ind;
557
+ VALUE val;
558
+ char *res_buf;
559
+ int int_val;
560
+ double double_val;
561
+ T_CCI_DATE date;
562
+ T_CCI_BIT bit;
563
+
564
+ switch (type) {
565
+ case CCI_U_TYPE_INT:
566
+ case CCI_U_TYPE_SHORT:
567
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_INT, &int_val, &ind);
568
+ if (res < 0) {
569
+ cubrid_handle_error(res, NULL);
570
+ return Qnil;
571
+ }
572
+ if (ind < 0) {
573
+ val = Qnil;
574
+ } else {
575
+ val = INT2NUM(int_val);
576
+ }
577
+ break;
578
+
579
+ case CCI_U_TYPE_FLOAT:
580
+ case CCI_U_TYPE_DOUBLE:
581
+ case CCI_U_TYPE_NUMERIC:
582
+ case CCI_U_TYPE_MONETARY:
583
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_STR, &res_buf, &ind);
584
+ if (res < 0) {
585
+ cubrid_handle_error(res, NULL);
586
+ return Qnil;
587
+ }
588
+ if (ind < 0) {
589
+ val = Qnil;
590
+ } else {
591
+ double_val = atof(res_buf);
592
+ val = rb_float_new(double_val);
593
+ }
594
+ break;
595
+
596
+ case CCI_U_TYPE_DATE:
597
+ case CCI_U_TYPE_TIME:
598
+ case CCI_U_TYPE_TIMESTAMP:
599
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_DATE, &date, &ind);
600
+ if (res < 0) {
601
+ cubrid_handle_error(res, NULL);
602
+ return Qnil;
603
+ }
604
+ if (ind < 0) {
605
+ val = Qnil;
606
+ } else {
607
+ if (type == CCI_U_TYPE_DATE) {
608
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 3,
609
+ INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day));
610
+ } else if (type == CCI_U_TYPE_TIME) {
611
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
612
+ INT2NUM(1970), INT2NUM(1), INT2NUM(1),
613
+ INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
614
+ } else {
615
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
616
+ INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day),
617
+ INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
618
+ }
619
+ }
620
+ break;
621
+
622
+ case CCI_U_TYPE_BIT:
623
+ case CCI_U_TYPE_VARBIT:
624
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_BIT, &bit, &ind);
625
+ if (res < 0) {
626
+ cubrid_handle_error(res, NULL);
627
+ return Qnil;
628
+ }
629
+ if (ind < 0) {
630
+ val = Qnil;
631
+ } else {
632
+ val = rb_tainted_str_new(bit.buf, bit.size);
633
+ }
634
+ break;
635
+
636
+ default:
637
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_STR, &res_buf, &ind);
638
+ if (res < 0) {
639
+ cubrid_handle_error(res, NULL);
640
+ return Qnil;
641
+ }
642
+ if (ind < 0) {
643
+ val = Qnil;
644
+ } else {
645
+ val = rb_str_new2(res_buf);
646
+ }
647
+ break;
648
+ }
649
+
650
+ return val;
651
+ }
652
+
653
+ static VALUE
654
+ cubrid_stmt_dbval_to_ruby_value_from_set(T_CCI_SET set, int type, int index, Connection *con)
655
+ {
656
+ int res, ind;
657
+ VALUE val;
658
+ char *res_buf;
659
+ int int_val;
660
+ double double_val;
661
+ T_CCI_DATE date;
662
+ T_CCI_BIT bit;
663
+
664
+ switch (type) {
665
+ case CCI_U_TYPE_INT:
666
+ case CCI_U_TYPE_SHORT:
667
+ res = cci_set_get(set, index, CCI_A_TYPE_INT, &int_val, &ind);
668
+ if (res < 0) {
669
+ cubrid_handle_error(res, NULL);
670
+ return Qnil;
671
+ }
672
+ if (ind < 0) {
673
+ val = Qnil;
674
+ } else {
675
+ val = INT2NUM(int_val);
676
+ }
677
+ break;
678
+
679
+ case CCI_U_TYPE_FLOAT:
680
+ case CCI_U_TYPE_DOUBLE:
681
+ case CCI_U_TYPE_NUMERIC:
682
+ case CCI_U_TYPE_MONETARY:
683
+ res = cci_set_get(set, index, CCI_A_TYPE_STR, &res_buf, &ind);
684
+ if (res < 0) {
685
+ cubrid_handle_error(res, NULL);
686
+ return Qnil;
687
+ }
688
+ if (ind < 0) {
689
+ val = Qnil;
690
+ } else {
691
+ double_val = atof(res_buf);
692
+ val = rb_float_new(double_val);
693
+ }
694
+ break;
695
+
696
+ case CCI_U_TYPE_DATE:
697
+ case CCI_U_TYPE_TIME:
698
+ case CCI_U_TYPE_TIMESTAMP:
699
+ res = cci_set_get(set, index, CCI_A_TYPE_DATE, &date, &ind);
700
+ if (res < 0) {
701
+ cubrid_handle_error(res, NULL);
702
+ return Qnil;
703
+ }
704
+ if (ind < 0) {
705
+ val = Qnil;
706
+ } else {
707
+ if (type == CCI_U_TYPE_DATE) {
708
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 3,
709
+ INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day));
710
+ } else if (type == CCI_U_TYPE_TIME) {
711
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
712
+ INT2NUM(1970), INT2NUM(1), INT2NUM(1),
713
+ INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
714
+ } else {
715
+ val = rb_funcall(rb_cTime, rb_intern("mktime"), 7,
716
+ INT2NUM(date.yr), INT2NUM(date.mon), INT2NUM(date.day),
717
+ INT2NUM(date.hh), INT2NUM(date.mm), INT2NUM(date.ss), INT2NUM(0));
718
+ }
719
+ }
720
+ break;
721
+
722
+ case CCI_U_TYPE_BIT:
723
+ case CCI_U_TYPE_VARBIT:
724
+ res = cci_set_get(set, index, CCI_A_TYPE_BIT, &bit, &ind);
725
+ if (res < 0) {
726
+ cubrid_handle_error(res, NULL);
727
+ return Qnil;
728
+ }
729
+ if (ind < 0) {
730
+ val = Qnil;
731
+ } else {
732
+ val = rb_tainted_str_new(bit.buf, bit.size);
733
+ }
734
+ break;
735
+
736
+ default:
737
+ res = cci_set_get(set, index, CCI_A_TYPE_STR, &res_buf, &ind);
738
+ if (res < 0) {
739
+ cubrid_handle_error(res, NULL);
740
+ return Qnil;
741
+ }
742
+ if (ind < 0) {
743
+ val = Qnil;
744
+ } else {
745
+ val = rb_str_new2(res_buf);
746
+ }
747
+ break;
748
+ }
749
+
750
+ return val;
751
+ }
752
+
753
+ static VALUE
754
+ cubrid_stmt_dbset_to_ruby_value(int req_handle, int index, Connection *con)
755
+ {
756
+ int i, res, ind, e_type;
757
+ VALUE val, e;
758
+ T_CCI_SET set = NULL;
759
+ int set_size;
760
+
761
+ res = cci_get_data(req_handle, index, CCI_A_TYPE_SET, &set, &ind);
762
+ if (res < 0) {
763
+ cubrid_handle_error(res, NULL);
764
+ return Qnil;
765
+ }
766
+
767
+ if (set == NULL)
768
+ return Qnil;
769
+
770
+ set_size = cci_set_size(set);
771
+ val = rb_ary_new2(set_size);
772
+
773
+ e_type = cci_set_element_type(set);
774
+
775
+ for (i = 0; i < set_size; i++) {
776
+ e = cubrid_stmt_dbval_to_ruby_value_from_set(set, e_type, i + 1, con);
777
+ rb_ary_push(val, e);
778
+ }
779
+ cci_set_free(set);
780
+
781
+ return val;
782
+ }
783
+
784
+ VALUE
785
+ cubrid_stmt_fetch_one_row(int req_handle, int col_count, T_CCI_COL_INFO *col_info, Connection *con)
786
+ {
787
+ int i, type;
788
+ VALUE row, val;
789
+
790
+ row = rb_ary_new();
791
+
792
+ for (i = 0; i < col_count; i++) {
793
+ type = CCI_GET_RESULT_INFO_TYPE(col_info, i + 1);
794
+
795
+ if (CCI_IS_COLLECTION_TYPE(type)) {
796
+ val = cubrid_stmt_dbset_to_ruby_value(req_handle, i + 1, con);
797
+ } else {
798
+ val = cubrid_stmt_dbval_to_ruby_value(req_handle, type, i + 1, con);
799
+ }
800
+
801
+ rb_ary_push(row, val);
802
+ }
803
+
804
+ return row;
805
+ }
806
+
807
+ /* call-seq:
808
+ * fetch() -> array or nil
809
+ *
810
+ * 검색된 결과에서 현재 커서가 위치한 row를 반환하고 커서의 위치를 다음으로 옮깁니다.
811
+ * row의 column들은 배열에 저장되어 반환됩니다.
812
+ * 더 이상 fetch할 row가 없으면 nil을 반환합니다.
813
+ *
814
+ * con = Cubrid.connect('demodb')
815
+ * con.prepare('SELECT * FROM db_user') { |stmt|
816
+ * stmt.execute
817
+ * r = stmt.fetch
818
+ * print r[0]
819
+ * }
820
+ * con.close
821
+ *
822
+ * 데이터베이스의 타입은 아래와 같이 루비의 타입으로 대응됩니다.
823
+ *
824
+ * *int, short -> fixnum, bignum
825
+ * *float, double, numeric, monetary -> float
826
+ * *char, varchar, ncahr, varnchar -> string
827
+ * *bit, varbit -> string
828
+ * *date, time, timestamp -> Time
829
+ * *object -> Oid
830
+ * *collection -> array
831
+ *
832
+ */
833
+ VALUE
834
+ cubrid_stmt_fetch(VALUE self)
835
+ {
836
+ int res;
837
+ T_CCI_ERROR error;
838
+ Statement *stmt;
839
+
840
+ GET_STMT_STRUCT(self, stmt);
841
+ CHECK_HANDLE(stmt, self);
842
+
843
+ res = cci_cursor(stmt->handle, 1, CCI_CURSOR_CURRENT, &error);
844
+ if (res == CCI_ER_NO_MORE_DATA) {
845
+ return Qnil;
846
+ } else if (res < 0) {
847
+ cubrid_handle_error(res, &error);
848
+ return Qnil;
849
+ }
850
+
851
+ res = cci_fetch(stmt->handle, &error);
852
+ if (res < 0) {
853
+ cubrid_handle_error(res, &error);
854
+ return Qnil;
855
+ }
856
+
857
+ return cubrid_stmt_fetch_one_row(stmt->handle, stmt->col_count, stmt->col_info, stmt->con);
858
+ }
859
+
860
+ /* call-seq:
861
+ * fetch_hash() -> hash or nil
862
+ *
863
+ * 검색된 결과에서 현재 커서가 위치한 row를 반환하고 커서의 위치를 다음으로 옮깁니다.
864
+ * row의 column들은 hash에 저장되어 반환됩니다.
865
+ * hash의 key는 column 이름이거나 SELECT 문에 주어진 alias 입니다.
866
+ * 더 이상 fetch할 row가 없으면 nil을 반환합니다.
867
+ *
868
+ * con = Cubrid.connect('demodb')
869
+ * con.prepare('SELECT * FROM db_user') { |stmt|
870
+ * stmt.execute
871
+ * r = stmt.fetch_hash
872
+ * print r['name']
873
+ * }
874
+ * con.close
875
+ */
876
+ VALUE
877
+ cubrid_stmt_fetch_hash(VALUE self)
878
+ {
879
+ VALUE row, col, hash;
880
+ int i;
881
+ char colName[128];
882
+ Statement *stmt;
883
+
884
+ GET_STMT_STRUCT(self, stmt);
885
+ CHECK_HANDLE(stmt, self);
886
+
887
+ row = cubrid_stmt_fetch(self);
888
+ if (NIL_P(row))
889
+ return Qnil;
890
+
891
+ hash = rb_hash_new();
892
+ for(i = 0; i < stmt->col_count; i++) {
893
+ col = RARRAY(row)->ptr[i];
894
+ strcpy(colName, CCI_GET_RESULT_INFO_NAME(stmt->col_info, i+1));
895
+ rb_hash_aset(hash, rb_str_new2(colName), col);
896
+ }
897
+
898
+ return hash;
899
+ }
900
+
901
+ /* call-seq:
902
+ * each() { |row| block } -> nil
903
+ *
904
+ * row를 fetch하여 주어진 block에 전달하여 수행시킵니다. 전달되는 row는 array입니다.
905
+ * block은 row가 fetch될 때마다 수행됩니다.
906
+ *
907
+ * con = Cubrid.connect('demodb')
908
+ * con.prepare('SELECT * FROM db_user') { |stmt|
909
+ * stmt.execute
910
+ * stmt.each { |r|
911
+ * print r[0]
912
+ * }
913
+ * }
914
+ * con.close
915
+ */
916
+ VALUE
917
+ cubrid_stmt_each(VALUE self)
918
+ {
919
+ VALUE row;
920
+
921
+ while(1) {
922
+ row = cubrid_stmt_fetch(self);
923
+ if (NIL_P(row)) {
924
+ break;
925
+ }
926
+ rb_yield(row);
927
+ }
928
+
929
+ return Qnil;
930
+ }
931
+
932
+ /* call-seq:
933
+ * each_hash() { |hash| block } -> nil
934
+ *
935
+ * row를 fetch하여 주어진 block에 전달하여 수행시킵니다. 전달되는 row는 hash입니다.
936
+ * block은 row가 fetch될 때마다 수행됩니다.
937
+ *
938
+ * con = Cubrid.connect('demodb')
939
+ * con.prepare('SELECT * FROM db_user') { |stmt|
940
+ * stmt.execute
941
+ * stmt.each_hash { |r|
942
+ * print r['name']
943
+ * }
944
+ * }
945
+ * con.close
946
+ */
947
+ VALUE
948
+ cubrid_stmt_each_hash(VALUE self)
949
+ {
950
+ VALUE row;
951
+
952
+ while(1) {
953
+ row = cubrid_stmt_fetch_hash(self);
954
+ if (NIL_P(row)) {
955
+ break;
956
+ }
957
+ rb_yield(row);
958
+ }
959
+
960
+ return Qnil;
961
+ }
962
+
963
+ /* call-seq:
964
+ * column_info() -> array
965
+ *
966
+ * fetch 될 row의 column 정보를 반환합니다.
967
+ * 한 컬럼의 정보가 hash로 구성되기 때문에, 결국 전체 컬럼 정보는 hash를 저장하고 있는 array로 반환됩니다.
968
+ * hash의 key는 name, type_name, precision, scale, nullable 이며,
969
+ * 각각 컬럼 이름, 컬럼의 데이터 타입, 정밀도, 스케일, 널가능 여부를 의미합니다.
970
+ *
971
+ * con = Cubrid.connect('demodb')
972
+ * con.prepare('SELECT * FROM db_user') { |stmt|
973
+ * stmt.column_info.each { |col|
974
+ * print col['name']
975
+ * print col['type_name']
976
+ * print col['precision']
977
+ * print col['scale']
978
+ * print col['nullable']
979
+ * }
980
+ * }
981
+ * con.close
982
+ */
983
+ VALUE
984
+ cubrid_stmt_column_info(VALUE self)
985
+ {
986
+ VALUE desc;
987
+ int i;
988
+ char col_name[MAX_STR_LEN];
989
+ int datatype, precision, scale, nullable;
990
+ Statement *stmt;
991
+
992
+ GET_STMT_STRUCT(self, stmt);
993
+ CHECK_HANDLE(stmt, self);
994
+
995
+ desc = rb_ary_new2(stmt->col_count);
996
+
997
+ for (i = 0; i < stmt->col_count; i++) {
998
+ VALUE item;
999
+
1000
+ item = rb_hash_new();
1001
+
1002
+ strcpy(col_name, CCI_GET_RESULT_INFO_NAME(stmt->col_info, i+1));
1003
+ precision = CCI_GET_RESULT_INFO_PRECISION(stmt->col_info, i+1);
1004
+ scale = CCI_GET_RESULT_INFO_SCALE(stmt->col_info, i+1);
1005
+ nullable = CCI_GET_RESULT_INFO_IS_NON_NULL(stmt->col_info, i+1);
1006
+ datatype = CCI_GET_RESULT_INFO_TYPE(stmt->col_info, i+1);
1007
+
1008
+ rb_hash_aset(item, rb_str_new2("name"), rb_str_new2(col_name));
1009
+ rb_hash_aset(item, rb_str_new2("type_name"), INT2NUM(datatype));
1010
+ rb_hash_aset(item, rb_str_new2("precision"), INT2NUM(precision));
1011
+ rb_hash_aset(item, rb_str_new2("scale"), INT2NUM(scale));
1012
+ rb_hash_aset(item, rb_str_new2("nullable"), INT2NUM(nullable));
1013
+
1014
+ rb_ary_push(desc, item);
1015
+ }
1016
+
1017
+ return desc;
1018
+ }
1019
+