cubrid 9.3.0 → 10.1.0

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.
@@ -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
+