cubrid 0.6-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (9) hide show
  1. data/ext/conn.c +405 -0
  2. data/ext/cubrid.c +235 -0
  3. data/ext/cubrid.h +98 -0
  4. data/ext/error.c +144 -0
  5. data/ext/extconf.rb +53 -0
  6. data/ext/oid.c +727 -0
  7. data/ext/stmt.c +1074 -0
  8. data/lib/cubrid.so +0 -0
  9. metadata +62 -0
data/ext/cubrid.h ADDED
@@ -0,0 +1,98 @@
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
+ #ifdef _WINDOWS
32
+ #pragma warning(disable:4312) /* type corecing */
33
+ #endif
34
+
35
+ #include "ruby.h"
36
+ #include "cas_cci.h"
37
+
38
+ #define MAX_STR_LEN 255
39
+
40
+ #define CUBRID_ER_INVALID_SQL_TYPE -2002
41
+ #define CUBRID_ER_CANNOT_GET_COLUMN_INFO -2003
42
+ #define CUBRID_ER_INIT_ARRAY_FAIL -2004
43
+ #define CUBRID_ER_UNKNOWN_TYPE -2005
44
+ #define CUBRID_ER_INVALID_PARAM -2006
45
+ #define CUBRID_ER_INVALID_ARRAY_TYPE -2007
46
+ #define CUBRID_ER_NOT_SUPPORTED_TYPE -2008
47
+ #define CUBRID_ER_OPEN_FILE -2009
48
+ #define CUBRID_ER_CREATE_TEMP_FILE -2010
49
+ #define CUBRID_ER_TRANSFER_FAIL -2011
50
+
51
+ typedef struct {
52
+ int handle;
53
+ char host[MAX_STR_LEN];
54
+ int port;
55
+ char db[MAX_STR_LEN];
56
+ char user[MAX_STR_LEN];
57
+ VALUE auto_commit;
58
+ } Connection;
59
+
60
+ typedef struct {
61
+ Connection *con;
62
+ int handle;
63
+ int affected_rows;
64
+ int col_count;
65
+ int param_cnt;
66
+ T_CCI_SQLX_CMD sql_type;
67
+ T_CCI_COL_INFO *col_info;
68
+ int bound;
69
+ } Statement;
70
+
71
+ typedef struct {
72
+ Connection *con;
73
+ char oid_str[MAX_STR_LEN];
74
+ int col_count;
75
+ VALUE col_type;
76
+ VALUE hash;
77
+ } Oid;
78
+
79
+ extern void cubrid_handle_error(int e, T_CCI_ERROR *error);
80
+
81
+ #define GET_CONN_STRUCT(self, con) Data_Get_Struct((self), Connection, (con))
82
+ #define CHECK_CONNECTION(con, rtn) \
83
+ do { \
84
+ if (!((con)->handle)) { \
85
+ cubrid_handle_error(CCI_ER_CON_HANDLE, NULL); \
86
+ return (rtn); \
87
+ } \
88
+ } while(0)
89
+
90
+ #define GET_STMT_STRUCT(self, stmt) Data_Get_Struct((self), Statement, (stmt))
91
+ #define CHECK_HANDLE(stmt, rtn) \
92
+ do { \
93
+ if (!((stmt)->handle)) { \
94
+ cubrid_handle_error(CCI_ER_REQ_HANDLE, NULL); \
95
+ return (rtn); \
96
+ } \
97
+ } while(0)
98
+
data/ext/error.c ADDED
@@ -0,0 +1,144 @@
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
+ static struct _error_message {
34
+ int err;
35
+ char* msg;
36
+ } cubrid_err_msgs[] = {
37
+ {-1, "CUBRID database error"},
38
+ {-2, "Invalid connection handle"},
39
+ {-3, "Memory allocation error"},
40
+ {-4, "Communication error"},
41
+ {-5, "No more data"},
42
+ {-6, "Unknown transaction type"},
43
+ {-7, "Invalid string parameter"},
44
+ {-8, "Type conversion error"},
45
+ {-9, "Parameter binding error"},
46
+ {-10, "Invalid type"},
47
+ {-11, "Parameter binding error"},
48
+ {-12, "Invalid database parameter name"},
49
+ {-13, "Invalid column index"},
50
+ {-14, "Invalid schema type"},
51
+ {-15, "File open error"},
52
+ {-16, "Connection error"},
53
+ {-17, "Connection handle creation error"},
54
+ {-18, "Invalid request handle"},
55
+ {-19, "Invalid cursor position"},
56
+ {-20, "Object is not valid"},
57
+ {-21, "CAS error"},
58
+ {-22, "Unknown host name"},
59
+ {-99, "Not implemented"},
60
+ {-1000, "Database connection error"},
61
+ {-1002, "Memory allocation error"},
62
+ {-1003, "Communication error"},
63
+ {-1004, "Invalid argument"},
64
+ {-1005, "Unknown transaction type"},
65
+ {-1007, "Parameter binding error"},
66
+ {-1008, "Parameter binding error"},
67
+ {-1009, "Cannot make DB_VALUE"},
68
+ {-1010, "Type conversion error"},
69
+ {-1011, "Invalid database parameter name"},
70
+ {-1012, "No more data"},
71
+ {-1013, "Object is not valid"},
72
+ {-1014, "File open error"},
73
+ {-1015, "Invalid schema type"},
74
+ {-1016, "Version mismatch"},
75
+ {-1017, "Cannot process the request. Try again later."},
76
+ {-1018, "Authorization error"},
77
+ {-1020, "The attribute domain must be the set type."},
78
+ {-1021, "The domain of a set must be the same data type."},
79
+ {-2001, "Memory allocation error"},
80
+ {-2002, "Invalid API call"},
81
+ {-2003, "Cannot get column info"},
82
+ {-2004, "Array initializing error"},
83
+ {-2005, "Unknown column type"},
84
+ {-2006, "Invalid parameter"},
85
+ {-2007, "Invalid array type"},
86
+ {-2008, "Invalid type"},
87
+ {-2009, "File open error"},
88
+ {-2010, "Temporary file open error"},
89
+ {-2011, "Glo transfering error"},
90
+ {0, "Unknown Error"}
91
+ };
92
+
93
+ static char *
94
+ get_error_msg(int err_code)
95
+ {
96
+ int i;
97
+
98
+ for(i = 0; ; i++) {
99
+ if (!cubrid_err_msgs[i].err || cubrid_err_msgs[i].err == err_code) {
100
+ return cubrid_err_msgs[i].msg;
101
+ }
102
+ }
103
+ return NULL;
104
+ }
105
+
106
+ void
107
+ cubrid_handle_error(int e, T_CCI_ERROR *error)
108
+ {
109
+ int err_code;
110
+ char msg[1024];
111
+ char *err_msg = NULL, *facility_msg;
112
+
113
+ if (e == CCI_ER_DBMS) {
114
+ facility_msg = "DBMS";
115
+ if (error) {
116
+ err_code = error->err_code;
117
+ err_msg = error->err_msg;
118
+ } else {
119
+ err_code = 0;
120
+ err_msg = "Unknown DBMS Error";
121
+ }
122
+ } else {
123
+ err_msg = get_error_msg(e);
124
+ err_code = e;
125
+
126
+ if (e > -1000) {
127
+ facility_msg = "CCI";
128
+ } else if (e > -2000) {
129
+ facility_msg = "CAS";
130
+ } else if (e > -3000) {
131
+ facility_msg = "CLIENT";
132
+ } else {
133
+ facility_msg = "UNKNOWN";
134
+ }
135
+ }
136
+
137
+ if (!err_msg) {
138
+ err_msg = "Unknown Error";
139
+ }
140
+
141
+ sprintf(msg, "ERROR: %s, %d, %s", facility_msg, err_code, err_msg);
142
+ rb_raise(rb_eStandardError, msg);
143
+ }
144
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,53 @@
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
+ require 'mkmf'
32
+ require 'rbconfig'
33
+
34
+ is_machine_64_bit = (Config::CONFIG["arch"] =~ /64/)
35
+
36
+ if ENV["CUBRID"] then
37
+ if is_machine_64_bit then
38
+ cci_lib_path = ENV["CUBRID"] + "/lib64"
39
+ else
40
+ cci_lib_path = ENV["CUBRID"] + "/lib"
41
+ end
42
+
43
+ cci_inc_path = ENV["CUBRID"] + "/include"
44
+ else
45
+ puts "$CUBRID_BROKER is not defined."
46
+ exit
47
+ end
48
+
49
+ $INCFLAGS = $INCFLAGS + " -I" + cci_inc_path
50
+ $LIBPATH.push(cci_lib_path)
51
+
52
+ have_library("cascci", "cci_init")
53
+ create_makefile("cubrid")
data/ext/oid.c ADDED
@@ -0,0 +1,727 @@
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 cOid;
34
+ extern VALUE cubrid_stmt_fetch_one_row(int req_handle, int col_count, T_CCI_COL_INFO *col_info, Connection *con);
35
+ extern T_CCI_SET cubrid_stmt_make_set(VALUE data, int u_type);
36
+
37
+ void
38
+ cubrid_oid_free(void *p)
39
+ {
40
+ free(p);
41
+ }
42
+
43
+ VALUE
44
+ cubrid_oid_new(Connection *con, char *oid_str)
45
+ {
46
+ VALUE oid;
47
+ Oid *o;
48
+
49
+ oid = Data_Make_Struct(cOid, Oid, 0, cubrid_oid_free, o);
50
+
51
+ o->con = con;
52
+ strcpy(o->oid_str, oid_str);
53
+
54
+ return oid;
55
+ }
56
+
57
+ /* call-seq:
58
+ * to_s() -> string
59
+ *
60
+ * OID string을 반환합니다.
61
+ */
62
+ VALUE
63
+ cubrid_oid_to_s(VALUE self)
64
+ {
65
+ Oid *oid;
66
+
67
+ Data_Get_Struct(self, Oid, oid);
68
+ return rb_str_new2(oid->oid_str);
69
+ }
70
+
71
+ /* call-seq:
72
+ * table() -> string
73
+ *
74
+ * OID의 table 이름을 반환합니다.
75
+ */
76
+ VALUE
77
+ cubrid_oid_table(VALUE self)
78
+ {
79
+ Oid *oid;
80
+ char table_name[MAX_STR_LEN];
81
+ T_CCI_ERROR error;
82
+
83
+ Data_Get_Struct(self, Oid, oid);
84
+ CHECK_CONNECTION(oid->con, Qnil);
85
+
86
+ cci_oid_get_class_name(oid->con->handle, oid->oid_str, table_name, MAX_STR_LEN, &error);
87
+
88
+ return rb_str_new2(table_name);
89
+ }
90
+
91
+ /* call-seq:
92
+ * refresh() -> self
93
+ *
94
+ * 데이터베이스 서버로 부터 OID의 데이터를 읽어옵니다.
95
+ * OID의 컬럼 데이터는 데이터베이스 서버와 자동으로 동기화되지 않습니다.
96
+ * Oid 객체가 생성된 후에 시간이 많이 경과하여 데이터베이스가 갱신되었을 가능성이 있다면
97
+ * 이 메쏘드를 호출하여 데이터베이스 서버로 부터 최신의 데이터를 읽어올 수 있습니다.
98
+ *
99
+ * con = Cubrid.connect('demodb')
100
+ * stmt = con.prepare('SELECT * FROM db_user', CUBRID::INCLUDE_OID)
101
+ * stmt.execute
102
+ * stmt.fetch
103
+ * oid = stmt.get_oid
104
+ * print oid['name']
105
+ * #after some time
106
+ * oid.refresh
107
+ * print oid['name']
108
+ * stmt.close
109
+ * con.close
110
+ *
111
+ */
112
+ VALUE
113
+ cubrid_oid_refresh(VALUE self)
114
+ {
115
+ Oid *oid;
116
+ int req_handle;
117
+ T_CCI_ERROR error;
118
+ T_CCI_COL_INFO *col_info;
119
+ T_CCI_SQLX_CMD sql_type;
120
+ int col_count, i, res;
121
+ VALUE row, col;
122
+ char *attr_name;
123
+
124
+ Data_Get_Struct(self, Oid, oid);
125
+ CHECK_CONNECTION(oid->con, self);
126
+
127
+ req_handle = cci_oid_get(oid->con->handle, oid->oid_str, NULL, &error);
128
+ if (req_handle < 0) {
129
+ cubrid_handle_error(req_handle, &error);
130
+ return self;
131
+ }
132
+
133
+ col_info = cci_get_result_info(req_handle, &sql_type, &col_count);
134
+ if (!col_info) {
135
+ cubrid_handle_error(CUBRID_ER_CANNOT_GET_COLUMN_INFO, &error);
136
+ return self;
137
+ }
138
+
139
+ res = cci_cursor(req_handle, 1, CCI_CURSOR_CURRENT, &error);
140
+ if (res < 0) {
141
+ cubrid_handle_error(res, &error);
142
+ return self;
143
+ }
144
+
145
+ res = cci_fetch(req_handle, &error);
146
+ if (res < 0) {
147
+ cubrid_handle_error(res, &error);
148
+ return self;
149
+ }
150
+
151
+ row = cubrid_stmt_fetch_one_row(req_handle, col_count, col_info, oid->con);
152
+
153
+ if (NIL_P(row)) { /* TODO */
154
+ return self;
155
+ }
156
+
157
+ oid->hash = rb_hash_new();
158
+ oid->col_type = rb_hash_new();
159
+ oid->col_count = col_count;
160
+
161
+ for(i = 0; i < col_count; i++) {
162
+ col = RARRAY(row)->ptr[i];
163
+ attr_name = CCI_GET_RESULT_INFO_NAME(col_info, i+1);
164
+ rb_hash_aset(oid->hash, rb_str_new2(attr_name), col);
165
+ rb_hash_aset(oid->col_type, rb_str_new2(attr_name), INT2NUM(CCI_GET_RESULT_INFO_TYPE(col_info, i+1)));
166
+ }
167
+
168
+ cci_close_req_handle(req_handle);
169
+
170
+ return self;
171
+ }
172
+
173
+ /* call-seq:
174
+ * [](col_name) -> obj
175
+ *
176
+ * OID의 컬럼 데이터를 반환합니다.
177
+ *
178
+ * con = Cubrid.connect('demodb')
179
+ * stmt = con.prepare('SELECT * FROM db_user', CUBRID::INCLUDE_OID)
180
+ * stmt.execute
181
+ * stmt.fetch
182
+ * oid = stmt.get_oid
183
+ * print oid['name']
184
+ * print oid.name
185
+ * stmt.close
186
+ * con.close
187
+ *
188
+ * 컬럼의 데이터에 접근하는 또다른 방법으로 컬럼의 이름을 메쏘드처럼 사용할 수 있습니다.
189
+ *
190
+ * oid = stmt.get_oid
191
+ * print oid.name
192
+ */
193
+ VALUE
194
+ cubrid_oid_get_value(VALUE self, VALUE attr_name)
195
+ {
196
+ Oid *oid;
197
+ VALUE has_key;
198
+
199
+ Data_Get_Struct(self, Oid, oid);
200
+
201
+ if (oid->hash == Qfalse) {
202
+ cubrid_oid_refresh(self);
203
+ }
204
+
205
+ has_key = rb_funcall(oid->hash, rb_intern("has_key?"), 1, attr_name);
206
+ if (has_key == Qfalse) {
207
+ rb_raise(rb_eArgError, "Invalid column name");
208
+ return Qnil;
209
+ }
210
+
211
+ return rb_hash_aref(oid->hash, attr_name);
212
+ }
213
+
214
+ /* call-seq:
215
+ * []=(col_name, obj) -> nil
216
+ *
217
+ * OID의 컬럼에 데이터를 저장합니다.
218
+ * 저장된 데이터를 데이터베이스 서버에 반영하기 위해서는 save 메쏘드를 호출하여야 합니다.
219
+ *
220
+ * con = Cubrid.connect('demodb')
221
+ * stmt = con.prepare('SELECT * FROM db_user', CUBRID::INCLUDE_OID)
222
+ * stmt.execute
223
+ * stmt.fetch
224
+ * oid = stmt.get_oid
225
+ * oid['name'] = 'foo'
226
+ * oid.save
227
+ * stmt.close
228
+ * con.close
229
+ *
230
+ * 컬럼의 이름을 메쏘드처럼 사용하여 데이터를 저장할 수 도 있습니다.
231
+ *
232
+ * oid = stmt.get_oid
233
+ * oid.name = 'foo'
234
+ * oid.save
235
+ */
236
+ VALUE
237
+ cubrid_oid_set_value(VALUE self, VALUE attr_name, VALUE val)
238
+ {
239
+ Oid *oid;
240
+ VALUE has_key;
241
+
242
+ Data_Get_Struct(self, Oid, oid);
243
+
244
+ if (oid->hash == Qfalse) {
245
+ cubrid_oid_refresh(self);
246
+ }
247
+
248
+ has_key = rb_funcall(oid->hash, rb_intern("has_key?"), 1, attr_name);
249
+ if (has_key == Qfalse) {
250
+ rb_raise(rb_eArgError, "Invalid column name");
251
+ return Qnil;
252
+ }
253
+
254
+ return rb_hash_aset(oid->hash, attr_name, val);
255
+ }
256
+
257
+ /* call-seq:
258
+ * save() -> self
259
+ *
260
+ * OID의 데이터를 데이터베이스 서버에 반영합니다.
261
+ */
262
+ VALUE
263
+ cubrid_oid_save(VALUE self)
264
+ {
265
+ Oid *oid;
266
+ int res, i, u_type;
267
+ T_CCI_ERROR error;
268
+ char **attr_names;
269
+ void **vals;
270
+ int *types;
271
+ VALUE val, keys, key, col_type;
272
+ int *int_val;
273
+ double *dbl_val;
274
+ T_CCI_SET set = NULL;
275
+ T_CCI_DATE *date;
276
+ T_CCI_BIT *bit;
277
+
278
+ Data_Get_Struct(self, Oid, oid);
279
+ CHECK_CONNECTION(oid->con, Qnil);
280
+
281
+ if (oid->hash == Qfalse) {
282
+ return self;
283
+ }
284
+
285
+ attr_names = (char **) ALLOCA_N(char *, oid->col_count + 1);
286
+ if (attr_names == NULL) {
287
+ rb_raise(rb_eNoMemError, "Not enough memory");
288
+ return self;
289
+ }
290
+
291
+ attr_names[oid->col_count] = NULL;
292
+
293
+ vals = (void **) ALLOCA_N(void *, oid->col_count);
294
+ if (vals == NULL) {
295
+ rb_raise(rb_eNoMemError, "Not enough memory");
296
+ return self;
297
+ }
298
+
299
+ types = (int *) ALLOCA_N(int, oid->col_count);
300
+ if (types == NULL) {
301
+ rb_raise(rb_eNoMemError, "Not enough memory");
302
+ return self;
303
+ }
304
+
305
+ keys = rb_funcall(oid->hash, rb_intern("keys"), 0);
306
+
307
+ for(i = 0; i < oid->col_count; i++) {
308
+ key = rb_ary_entry(keys, i);
309
+ attr_names[i] = StringValueCStr(key);
310
+ val = rb_hash_aref(oid->hash, key);
311
+
312
+ switch (TYPE(val)) {
313
+ case T_NIL:
314
+ vals[i] = NULL;
315
+ types[i] = CCI_A_TYPE_STR;
316
+ break;
317
+
318
+ case T_FIXNUM:
319
+ case T_BIGNUM:
320
+ int_val = (int *) ALLOCA_N(int, 1);
321
+ if (int_val == NULL) {
322
+ rb_raise(rb_eNoMemError, "Not enough memory");
323
+ return self;
324
+ }
325
+
326
+ *int_val = NUM2INT(val);
327
+ vals[i] = int_val;
328
+ types[i] = CCI_A_TYPE_INT;
329
+ break;
330
+
331
+ case T_FLOAT:
332
+ dbl_val = (double *) ALLOCA_N(double, 1);
333
+ if (dbl_val == NULL) {
334
+ rb_raise(rb_eNoMemError, "Not enough memory");
335
+ return self;
336
+ }
337
+
338
+ *dbl_val = NUM2DBL(val);
339
+ vals[i] = dbl_val;
340
+ types[i] = CCI_A_TYPE_DOUBLE;
341
+ break;
342
+
343
+ case T_STRING:
344
+ col_type = rb_hash_aref(oid->col_type, key);
345
+ u_type = FIX2INT(col_type);
346
+
347
+ if (u_type == CCI_U_TYPE_BIT || u_type == CCI_U_TYPE_VARBIT) {
348
+ bit = (T_CCI_BIT *) ALLOCA_N(T_CCI_BIT, 1);
349
+ if (bit == NULL) {
350
+ rb_raise(rb_eNoMemError, "Not enough memory");
351
+ return self;
352
+ }
353
+
354
+ bit->size = RSTRING(val)->len;
355
+ bit->buf = RSTRING(val)->ptr;
356
+ vals[i] = bit;
357
+ types[i] = CCI_A_TYPE_BIT;
358
+ } else {
359
+ vals[i] = RSTRING(val)->ptr;
360
+ types[i] = CCI_A_TYPE_STR;
361
+ }
362
+ break;
363
+
364
+ case T_DATA:
365
+ if (CLASS_OF(val) == rb_cTime) {
366
+ VALUE a;
367
+
368
+ a = rb_funcall(val, rb_intern("to_a"), 0);
369
+
370
+ date = (T_CCI_DATE *) ALLOCA_N(T_CCI_DATE, 1);
371
+ if (date == NULL) {
372
+ rb_raise(rb_eNoMemError, "Not enough memory");
373
+ return self;
374
+ }
375
+
376
+ date->ss = FIX2INT(RARRAY(a)->ptr[0]);
377
+ date->mm = FIX2INT(RARRAY(a)->ptr[1]);
378
+ date->hh = FIX2INT(RARRAY(a)->ptr[2]);
379
+ date->day = FIX2INT(RARRAY(a)->ptr[3]);
380
+ date->mon = FIX2INT(RARRAY(a)->ptr[4]);
381
+ date->yr = FIX2INT(RARRAY(a)->ptr[5]);
382
+
383
+ vals[i] = date;
384
+ types[i] = CCI_A_TYPE_DATE;
385
+ } else if (CLASS_OF(val) == cOid) {
386
+ Oid *oid;
387
+
388
+ Data_Get_Struct(val, Oid, oid);
389
+ vals[i] = oid->oid_str;
390
+ types[i] = CCI_A_TYPE_STR;
391
+ }
392
+ break;
393
+
394
+ case T_ARRAY:
395
+ set = cubrid_stmt_make_set(val, CCI_U_TYPE_UNKNOWN);
396
+ vals[i] = set;
397
+ types[i] = CCI_A_TYPE_SET;
398
+ break;
399
+
400
+ default:
401
+ rb_raise(rb_eArgError, "Wrong data type");
402
+ return self; /* TODO: avoid leak */
403
+ }
404
+ }
405
+
406
+ res = cci_oid_put2(oid->con->handle, oid->oid_str, attr_names, vals, types, &error);
407
+
408
+ for(i = 0; i < oid->col_count; i++) {
409
+ if (types[i] == CCI_A_TYPE_SET) {
410
+ cci_set_free(vals[i]);
411
+ }
412
+ }
413
+
414
+ if (res < 0) {
415
+ cubrid_handle_error(res, &error);
416
+ return INT2NUM(0);
417
+ }
418
+
419
+ return self;
420
+ }
421
+
422
+ static VALUE
423
+ cubrid_oid_cmd(VALUE self, T_CCI_OID_CMD cmd)
424
+ {
425
+ Oid *oid;
426
+ int res;
427
+ T_CCI_ERROR error;
428
+
429
+ Data_Get_Struct(self, Oid, oid);
430
+ CHECK_CONNECTION(oid->con, Qnil);
431
+
432
+ res = cci_oid(oid->con->handle, cmd, oid->oid_str, &error);
433
+
434
+ if (res < 0) {
435
+ cubrid_handle_error(res, &error);
436
+ return INT2NUM(0);
437
+ }
438
+
439
+ return Qnil;
440
+ }
441
+
442
+ /* call-seq:
443
+ * drop() -> self
444
+ *
445
+ * OID를 데이터베이스 서버에서 삭제합니다.
446
+ */
447
+ VALUE
448
+ cubrid_oid_drop(VALUE self)
449
+ {
450
+ return cubrid_oid_cmd(self, CCI_OID_DROP);
451
+ }
452
+
453
+ /* call-seq:
454
+ * lock(lockmode) -> self
455
+ *
456
+ * OID에 Cubrid::READ_LOCK 또는 Cubrid::WRITE_LOCK 잠금을 설정합니다.
457
+ * 설정된 잠금은 트랜잭션이 종료될 때 헤제됩니다.
458
+ *
459
+ */
460
+ VALUE
461
+ cubrid_oid_lock(VALUE self, VALUE lock)
462
+ {
463
+ return cubrid_oid_cmd(self, NUM2INT(lock));
464
+ }
465
+
466
+ /*
467
+ stopdoc:
468
+ static VALUE
469
+ cubrid_oid_column_info(VALUE self)
470
+ {
471
+ VALUE desc;
472
+ int req_handle;
473
+ T_CCI_ERROR error;
474
+ T_CCI_COL_INFO *col_info;
475
+ T_CCI_SQLX_CMD sql_type;
476
+ int col_count, i;
477
+ char *col_name;
478
+ int datatype, precision, scale, nullable;
479
+ Oid *oid;
480
+
481
+ Data_Get_Struct(self, Oid, oid);
482
+ CHECK_CONNECTION(oid->con, self);
483
+
484
+ req_handle = cci_oid_get(oid->con->handle, oid->oid_str, NULL, &error);
485
+ if (req_handle < 0) {
486
+ cubrid_handle_error(req_handle, &error);
487
+ return Qnil;
488
+ }
489
+
490
+ col_info = cci_get_result_info(req_handle, &sql_type, &col_count);
491
+ if (!col_info) {
492
+ cubrid_handle_error(CUBRID_ER_CANNOT_GET_COLUMN_INFO, &error);
493
+ return Qnil;
494
+ }
495
+
496
+ desc = rb_ary_new2(col_count);
497
+
498
+ for (i = 0; i < col_count; i++) {
499
+ VALUE item;
500
+
501
+ item = rb_hash_new();
502
+
503
+ col_name = CCI_GET_RESULT_INFO_NAME(col_info, i+1);
504
+ precision = CCI_GET_RESULT_INFO_PRECISION(col_info, i+1);
505
+ scale = CCI_GET_RESULT_INFO_SCALE(col_info, i+1);
506
+ nullable = CCI_GET_RESULT_INFO_IS_NON_NULL(col_info, i+1);
507
+ datatype = CCI_GET_RESULT_INFO_TYPE(col_info, i+1);
508
+
509
+ rb_hash_aset(item, rb_str_new2("name"), rb_str_new2(col_name));
510
+ rb_hash_aset(item, rb_str_new2("type_name"), INT2NUM(datatype));
511
+ rb_hash_aset(item, rb_str_new2("precision"), INT2NUM(precision));
512
+ rb_hash_aset(item, rb_str_new2("scale"), INT2NUM(scale));
513
+ rb_hash_aset(item, rb_str_new2("nullable"), INT2NUM(nullable));
514
+
515
+ rb_ary_push(desc, item);
516
+ }
517
+
518
+ cci_close_req_handle(req_handle);
519
+
520
+ return desc;
521
+ }
522
+ startdoc:
523
+ */
524
+
525
+ /* call-seq:
526
+ * glo_load(filename) -> File
527
+ *
528
+ * 데이터베이스에 저장되어 있는 GLO 데이터를 File로 저장합니다.
529
+ *
530
+ * con = Cubrid.connect('subway')
531
+ * con.query('create table attachfile under glo (name string)')
532
+ * con.commit
533
+ *
534
+ * glo = con.glo_new('attachfile', 'pic.jpg')
535
+ * newfile = glo.glo_load('pic_copy.jpg')
536
+ */
537
+ VALUE
538
+ cubrid_oid_glo_load(VALUE self, VALUE file_name)
539
+ {
540
+ Oid *oid;
541
+ int res;
542
+ T_CCI_ERROR error;
543
+ VALUE file, fd;
544
+
545
+ Data_Get_Struct(self, Oid, oid);
546
+ CHECK_CONNECTION(oid->con, Qnil);
547
+
548
+ file = rb_file_open(StringValueCStr(file_name), "w");
549
+ fd = rb_funcall(file, rb_intern("fileno"), 0);
550
+
551
+ res = cci_glo_load(oid->con->handle, oid->oid_str, FIX2INT(fd), &error);
552
+ if (res < 0) {
553
+ cubrid_handle_error(res, &error);
554
+ return Qnil;
555
+ }
556
+
557
+ return file;
558
+ }
559
+
560
+ /* call-seq:
561
+ * glo_save(filename) -> self
562
+ *
563
+ * 주어진 파일의 데이터를 데이터베이스 서버의 GLO로 저장합니다.
564
+ *
565
+ * con = Cubrid.connect('subway')
566
+ * con.query('create table attachfile under glo (name string)')
567
+ * con.commit
568
+ *
569
+ * glo = con.glo_new('attachfile')
570
+ * glo.glo_save('pic.jpg')
571
+ */
572
+ VALUE
573
+ cubrid_oid_glo_save(VALUE self, VALUE file_name)
574
+ {
575
+ Oid *oid;
576
+ int res;
577
+ T_CCI_ERROR error;
578
+
579
+ Data_Get_Struct(self, Oid, oid);
580
+ CHECK_CONNECTION(oid->con, self);
581
+
582
+ if (NIL_P(file_name)) {
583
+ rb_raise(rb_eArgError, "file name is required.");
584
+ return self;
585
+ }
586
+
587
+ res = cci_glo_save(oid->con->handle, oid->oid_str, StringValueCStr(file_name), &error);
588
+ if (res < 0) {
589
+ cubrid_handle_error(res, &error);
590
+ return self;
591
+ }
592
+
593
+ return self;
594
+ }
595
+
596
+ /* call-seq:
597
+ * glo_size() -> int
598
+ *
599
+ * GLO에 저장된 데이터의 크기를 반환합니다.
600
+ */
601
+ VALUE
602
+ cubrid_oid_glo_size(VALUE self)
603
+ {
604
+ Oid *oid;
605
+ int size;
606
+ T_CCI_ERROR error;
607
+
608
+ Data_Get_Struct(self, Oid, oid);
609
+ CHECK_CONNECTION(oid->con, INT2NUM(0));
610
+
611
+ size = cci_glo_data_size(oid->con->handle, oid->oid_str, &error);
612
+ if (size < 0) {
613
+ cubrid_handle_error(size, &error);
614
+ return INT2NUM(0);
615
+ }
616
+
617
+ return INT2NUM(size);
618
+ }
619
+
620
+ /* call-seq:
621
+ * glo_drop() -> self
622
+ *
623
+ * 데이터베이스 서버에서 GLO를 삭제합니다.
624
+ *
625
+ * con = Cubrid.connect('demodb')
626
+ * stmt = con.prepare("SELECT * FROM attachfile WHERE name = 'pig.jpg'", CUBRID::INCLUDE_OID)
627
+ * stmt.execute
628
+ * stmt.fetch
629
+ * oid = stmt.get_oid
630
+ * oid.drop
631
+ */
632
+ VALUE
633
+ cubrid_oid_glo_drop(VALUE self)
634
+ {
635
+ Oid *oid;
636
+ int res;
637
+ T_CCI_ERROR error;
638
+
639
+ Data_Get_Struct(self, Oid, oid);
640
+ CHECK_CONNECTION(oid->con, self);
641
+
642
+ res = cci_glo_destroy_data(oid->con->handle, oid->oid_str, &error);
643
+ if (res < 0) {
644
+ cubrid_handle_error(res, &error);
645
+ return self;
646
+ }
647
+
648
+ return self;
649
+ }
650
+
651
+ /* call-seq:
652
+ * each() { |name, val| block } -> nil
653
+ *
654
+ * OID의 컬럼 이름과 데이터를 넘겨 주어진 block을 실행합니다.
655
+ *
656
+ * con = Cubrid.connect('demodb')
657
+ * stmt = con.prepare('SELECT * FROM db_user', CUBRID::INCLUDE_OID)
658
+ * stmt.execute
659
+ * stmt.fetch
660
+ * oid = stmt.get_oid
661
+ * oid.each { |name, val|
662
+ * print name
663
+ * print val
664
+ * }
665
+ */
666
+ VALUE
667
+ cubrid_oid_each(VALUE self)
668
+ {
669
+ Oid *oid;
670
+
671
+ Data_Get_Struct(self, Oid, oid);
672
+
673
+ if (oid->hash == Qfalse) {
674
+ cubrid_oid_refresh(self);
675
+ }
676
+
677
+ rb_iterate(rb_each, oid->hash, rb_yield, Qnil);
678
+
679
+ return Qnil;
680
+ }
681
+
682
+ /* call-seq:
683
+ * to_hash() -> Hash
684
+ *
685
+ * OID의 데이터를 hash로 반환합니다. key는 컬럼의 이름이며, value는 컬럼의 데이터입니다.
686
+ */
687
+ VALUE
688
+ cubrid_oid_to_hash(VALUE self)
689
+ {
690
+ Oid *oid;
691
+
692
+ Data_Get_Struct(self, Oid, oid);
693
+
694
+ if (oid->hash == Qfalse) {
695
+ cubrid_oid_refresh(self);
696
+ }
697
+
698
+ return oid->hash;
699
+ }
700
+
701
+ VALUE
702
+ cubrid_oid_method_missing(int argc, VALUE* argv, VALUE self)
703
+ {
704
+ Oid *oid;
705
+ VALUE method, attr_name;
706
+ char *attr_name_str;
707
+ int size, is_set_method = 0;
708
+
709
+ Data_Get_Struct(self, Oid, oid);
710
+
711
+ method = rb_funcall(argv[0], rb_intern("id2name"), 0);
712
+ attr_name_str = StringValueCStr(method);
713
+ size = strlen(attr_name_str);
714
+
715
+ if (attr_name_str[size - 1] == '=') {
716
+ is_set_method = 1;
717
+ attr_name_str[size - 1] = '\0';
718
+ }
719
+
720
+ attr_name = rb_str_new2(attr_name_str);
721
+
722
+ if (is_set_method) {
723
+ return cubrid_oid_set_value(self, attr_name, argv[1]);
724
+ }
725
+ return cubrid_oid_get_value(self, attr_name);
726
+ }
727
+