ruby-dm 0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/SYSDBA) +0 -0
- data/dm-0.1.0.gem +0 -0
- data/dm.gemspec +29 -0
- data/ext/client.c +520 -0
- data/ext/client.h +40 -0
- data/ext/dm_enc_name_to_ruby.h +63 -0
- data/ext/dm_ext.c +17 -0
- data/ext/dm_ext.h +43 -0
- data/ext/dm_lib_path.rb +3 -0
- data/ext/extconf.h +11 -0
- data/ext/extconf.rb +123 -0
- data/ext/result.c +1052 -0
- data/ext/result.h +39 -0
- data/ext/statement.c +666 -0
- data/ext/statement.h +36 -0
- data/lib/dm/client.rb +54 -0
- data/lib/dm/console.rb +5 -0
- data/lib/dm/error.rb +59 -0
- data/lib/dm/field.rb +3 -0
- data/lib/dm/result.rb +7 -0
- data/lib/dm/statement.rb +9 -0
- data/lib/dm/version.rb +5 -0
- data/lib/dm.rb +65 -0
- metadata +94 -0
data/ext/client.c
ADDED
@@ -0,0 +1,520 @@
|
|
1
|
+
#include <dm_ext.h>
|
2
|
+
|
3
|
+
#include <time.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#ifndef _WIN32
|
6
|
+
#include <sys/types.h>
|
7
|
+
#include <sys/socket.h>
|
8
|
+
#endif
|
9
|
+
#ifndef _MSC_VER
|
10
|
+
#include <unistd.h>
|
11
|
+
#endif
|
12
|
+
#include <fcntl.h>
|
13
|
+
#include "dm_enc_name_to_ruby.h"
|
14
|
+
|
15
|
+
VALUE cdmClient;
|
16
|
+
extern VALUE mdm, cdmError;
|
17
|
+
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
|
18
|
+
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
|
19
|
+
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args,
|
20
|
+
intern_current_query_options, intern_read_timeout;
|
21
|
+
|
22
|
+
#define REQUIRE_INITIALIZED(wrapper) \
|
23
|
+
if (!wrapper->initialized) { \
|
24
|
+
rb_raise(cdmError, "DM client is not initialized"); \
|
25
|
+
}
|
26
|
+
|
27
|
+
#define CONNECTED(wrapper) (wrapper->active == 1 && wrapper->closed != 1)
|
28
|
+
|
29
|
+
#define REQUIRE_CONNECTED(wrapper) \
|
30
|
+
REQUIRE_INITIALIZED(wrapper) \
|
31
|
+
if ((wrapper->closed) && !wrapper->reconnect_enabled) { \
|
32
|
+
rb_raise(cdmError, "DM client is not connected"); \
|
33
|
+
}
|
34
|
+
|
35
|
+
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
36
|
+
REQUIRE_INITIALIZED(wrapper) \
|
37
|
+
if ((wrapper->active)) { \
|
38
|
+
rb_raise(cdmError, "DM connection is already open"); \
|
39
|
+
}
|
40
|
+
|
41
|
+
#define DM_LINK_VERSION 8
|
42
|
+
|
43
|
+
/*
|
44
|
+
* used to pass all arguments to dm_real_connect while inside
|
45
|
+
* rb_thread_call_without_gvl
|
46
|
+
*/
|
47
|
+
struct nogvl_connect_args {
|
48
|
+
dm_client_wrapper *wrapper;
|
49
|
+
const char *server;
|
50
|
+
const char *user;
|
51
|
+
const char *passwd;
|
52
|
+
};
|
53
|
+
|
54
|
+
/*
|
55
|
+
* used to pass all arguments to dm_send_query while inside
|
56
|
+
* rb_thread_call_without_gvl
|
57
|
+
*/
|
58
|
+
struct nogvl_send_query_args {
|
59
|
+
dhcon *con;
|
60
|
+
VALUE sql;
|
61
|
+
const char *sql_ptr;
|
62
|
+
long sql_len;
|
63
|
+
dm_client_wrapper *wrapper;
|
64
|
+
};
|
65
|
+
|
66
|
+
|
67
|
+
/*
|
68
|
+
* non-blocking dm_*() functions that we won't be wrapping since
|
69
|
+
* they do not appear to hit the network nor issue any interruptible
|
70
|
+
* or blocking system calls.
|
71
|
+
*
|
72
|
+
* - dm_affected_rows()
|
73
|
+
* - dm_error()
|
74
|
+
* - dm_fetch_fields()
|
75
|
+
* - dm_fetch_lengths() - calls cli_fetch_lengths or emb_fetch_lengths
|
76
|
+
* - dm_field_count()
|
77
|
+
* - dm_get_client_info()
|
78
|
+
* - dm_get_client_version()
|
79
|
+
* - dm_get_server_info()
|
80
|
+
* - dm_get_server_version()
|
81
|
+
* - dm_insert_id()
|
82
|
+
* - dm_num_fields()
|
83
|
+
* - dm_num_rows()
|
84
|
+
* - dm_options()
|
85
|
+
* - dm_real_escape_string()
|
86
|
+
* - dm_ssl_set()
|
87
|
+
*/
|
88
|
+
|
89
|
+
static void rb_dm_client_mark(void * wrapper)
|
90
|
+
{
|
91
|
+
dm_client_wrapper * w = wrapper;
|
92
|
+
if (w) {
|
93
|
+
rb_gc_mark_movable(w->encoding);
|
94
|
+
rb_gc_mark_movable(w->active_fiber);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/* this is called during GC */
|
99
|
+
static void rb_dm_client_free(void *ptr) {
|
100
|
+
dm_client_wrapper *wrapper = ptr;
|
101
|
+
decr_dm_client(wrapper);
|
102
|
+
}
|
103
|
+
|
104
|
+
static size_t rb_dm_client_memsize(const void * wrapper) {
|
105
|
+
const dm_client_wrapper * w = wrapper;
|
106
|
+
return sizeof(*w);
|
107
|
+
}
|
108
|
+
|
109
|
+
static void rb_dm_client_compact(void * wrapper) {
|
110
|
+
dm_client_wrapper * w = wrapper;
|
111
|
+
if (w) {
|
112
|
+
rb_dm_gc_location(w->encoding);
|
113
|
+
rb_dm_gc_location(w->active_fiber);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
const rb_data_type_t rb_dm_client_type = {
|
118
|
+
"rb_dm_client",
|
119
|
+
{
|
120
|
+
rb_dm_client_mark,
|
121
|
+
rb_dm_client_free,
|
122
|
+
rb_dm_client_memsize,
|
123
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
124
|
+
rb_dm_client_compact,
|
125
|
+
#endif
|
126
|
+
},
|
127
|
+
0,
|
128
|
+
0,
|
129
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
130
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
131
|
+
#endif
|
132
|
+
};
|
133
|
+
|
134
|
+
struct nogvl_errors_args {
|
135
|
+
void* hndl;
|
136
|
+
sdbyte errormsg[4096];
|
137
|
+
sdint4 errorCode;
|
138
|
+
sdint2 hndl_type;
|
139
|
+
};
|
140
|
+
|
141
|
+
static void *nogvl_get_error(void *ptr) {
|
142
|
+
struct nogvl_errors_args *args = ptr;
|
143
|
+
sdbyte error_buf[4096];
|
144
|
+
dpi_get_diag_rec(args->hndl_type, args->hndl, 1, &args->errorCode, error_buf, sizeof(error_buf), NULL);
|
145
|
+
sprintf(args->errormsg,"[CODE:%d]%s",args->errorCode, error_buf);
|
146
|
+
return (void*)Qtrue;
|
147
|
+
}
|
148
|
+
|
149
|
+
|
150
|
+
static VALUE rb_raise_dm_error(dm_client_wrapper *wrapper, void* hndl, sdint2 hndl_type) {
|
151
|
+
VALUE rb_error_msg;
|
152
|
+
VALUE e;
|
153
|
+
struct nogvl_errors_args err;
|
154
|
+
err.hndl = hndl;
|
155
|
+
err.hndl_type = hndl_type;
|
156
|
+
|
157
|
+
rb_thread_call_without_gvl(nogvl_get_error, &err, RUBY_UBF_IO, 0);
|
158
|
+
rb_error_msg = rb_str_new2(err.errormsg);
|
159
|
+
|
160
|
+
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
161
|
+
e = rb_funcall(cdmError, intern_new_with_args, 2,
|
162
|
+
rb_error_msg,
|
163
|
+
UINT2NUM(err.errorCode));
|
164
|
+
rb_exc_raise(e);
|
165
|
+
}
|
166
|
+
|
167
|
+
static void *nogvl_connect(void *ptr) {
|
168
|
+
struct nogvl_connect_args *args = ptr;
|
169
|
+
DPIRETURN rt;
|
170
|
+
rt = dpi_alloc_env(&args->wrapper->env);
|
171
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
172
|
+
return (void*)Qfalse;
|
173
|
+
rt = dpi_alloc_con(args->wrapper->env,&args->wrapper->client);
|
174
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
175
|
+
return (void*)Qfalse;
|
176
|
+
rt = dpi_set_con_attr(args->wrapper->client,DSQL_ATTR_TCNAME_LOWER,(dpointer)1,0);
|
177
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
178
|
+
return (void*)Qfalse;
|
179
|
+
rt = dpi_set_con_attr(args->wrapper->client,DSQL_ATTR_LOCAL_CODE,(dpointer)args->wrapper->encode_code,0);
|
180
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
181
|
+
return (void*)Qfalse;
|
182
|
+
rt = dpi_login(args->wrapper->client,args->server,args->user,args->passwd);
|
183
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
184
|
+
return (void*)Qfalse;
|
185
|
+
rt = dpi_set_con_attr(args->wrapper->client,DSQL_ATTR_AUTOCOMMIT,(dpointer)1,0);
|
186
|
+
if(!(DSQL_SUCCEEDED(rt)))
|
187
|
+
return (void*)Qfalse;
|
188
|
+
|
189
|
+
return(void*)Qtrue;
|
190
|
+
}
|
191
|
+
|
192
|
+
static void *nogvl_close(void *ptr) {
|
193
|
+
dm_client_wrapper *wrapper = ptr;
|
194
|
+
|
195
|
+
if (wrapper->initialized && !wrapper->closed) {
|
196
|
+
dpi_logout(wrapper->client);
|
197
|
+
dpi_free_con(wrapper->client);
|
198
|
+
dpi_free_env(wrapper->env);
|
199
|
+
wrapper->closed = 1;
|
200
|
+
wrapper->active = 0;
|
201
|
+
wrapper->reconnect_enabled = 0;
|
202
|
+
wrapper->active_fiber = Qnil;
|
203
|
+
}
|
204
|
+
|
205
|
+
return NULL;
|
206
|
+
}
|
207
|
+
|
208
|
+
void decr_dm_client(dm_client_wrapper *wrapper)
|
209
|
+
{
|
210
|
+
wrapper->refcount--;
|
211
|
+
|
212
|
+
if (wrapper->refcount == 0) {
|
213
|
+
xfree(wrapper);
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
static VALUE allocate(VALUE klass) {
|
218
|
+
VALUE obj;
|
219
|
+
dm_client_wrapper * wrapper;
|
220
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
221
|
+
obj = TypedData_Make_Struct(klass, dm_client_wrapper, &rb_dm_client_type, wrapper);
|
222
|
+
#else
|
223
|
+
obj = Data_Make_Struct(klass, dm_client_wrapper, rb_dm_client_mark, rb_dm_client_free, wrapper);
|
224
|
+
#endif
|
225
|
+
wrapper->encoding = Qnil;
|
226
|
+
wrapper->active_fiber = Qnil;
|
227
|
+
wrapper->server_version = 0;
|
228
|
+
wrapper->reconnect_enabled = 0;
|
229
|
+
wrapper->connect_timeout = 0;
|
230
|
+
wrapper->initialized = 0; /* will be set true after calling dm_init */
|
231
|
+
wrapper->closed = 1; /* will be set false after calling dm_real_connect */
|
232
|
+
wrapper->refcount = 1;
|
233
|
+
wrapper->active = 0;
|
234
|
+
|
235
|
+
return obj;
|
236
|
+
}
|
237
|
+
|
238
|
+
static VALUE rb_dm_connect(VALUE self, VALUE user, VALUE pass, VALUE servers) {
|
239
|
+
struct nogvl_connect_args args;
|
240
|
+
time_t start_time, end_time, elapsed_time, connect_timeout;
|
241
|
+
VALUE rv;
|
242
|
+
GET_CLIENT(self);
|
243
|
+
|
244
|
+
args.server = NIL_P(servers) ? NULL : StringValueCStr(servers);
|
245
|
+
args.user = NIL_P(user) ? NULL : StringValueCStr(user);
|
246
|
+
args.passwd = NIL_P(pass) ? NULL : StringValueCStr(pass);
|
247
|
+
args.wrapper = wrapper;
|
248
|
+
|
249
|
+
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
250
|
+
|
251
|
+
if (rv == Qfalse)
|
252
|
+
rb_raise_dm_error(wrapper, wrapper->client, DSQL_HANDLE_DBC);
|
253
|
+
wrapper->closed = 0;
|
254
|
+
wrapper->server_version = 8;
|
255
|
+
wrapper->active = 1;
|
256
|
+
wrapper->initialized = 1;
|
257
|
+
return self;
|
258
|
+
}
|
259
|
+
|
260
|
+
/* call-seq:
|
261
|
+
* client.closed
|
262
|
+
*
|
263
|
+
* @return [Boolean]
|
264
|
+
*/
|
265
|
+
static VALUE rb_dm_client_close(VALUE self) {
|
266
|
+
GET_CLIENT(self);
|
267
|
+
|
268
|
+
if (wrapper->client) {
|
269
|
+
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
270
|
+
}
|
271
|
+
|
272
|
+
return Qnil;
|
273
|
+
}
|
274
|
+
|
275
|
+
/* call-seq:
|
276
|
+
* client.closed?
|
277
|
+
*
|
278
|
+
* @return [Boolean]
|
279
|
+
*/
|
280
|
+
static VALUE rb_dm_client_closed(VALUE self) {
|
281
|
+
GET_CLIENT(self);
|
282
|
+
return CONNECTED(wrapper) ? Qfalse : Qtrue;
|
283
|
+
}
|
284
|
+
|
285
|
+
|
286
|
+
static void *nogvl_send_query(void *ptr) {
|
287
|
+
struct nogvl_send_query_args *args = ptr;
|
288
|
+
DPIRETURN rt;
|
289
|
+
dhstmt hstmt;
|
290
|
+
udint2 col_num;
|
291
|
+
sdint4 nStmtType;
|
292
|
+
sdbyte lastrowid[12];
|
293
|
+
udint4 len;
|
294
|
+
|
295
|
+
args->wrapper->stmt = NULL;
|
296
|
+
rt = dpi_alloc_stmt(args->con,&hstmt);
|
297
|
+
if(!DSQL_SUCCEEDED(rt))
|
298
|
+
{
|
299
|
+
return (void*)Qfalse;
|
300
|
+
}
|
301
|
+
args->wrapper->stmt = hstmt;
|
302
|
+
|
303
|
+
rt = dpi_set_stmt_attr(hstmt,DSQL_ATTR_CURSOR_TYPE,(dpointer)DSQL_CURSOR_DYNAMIC,0);
|
304
|
+
if(!DSQL_SUCCEEDED(rt))
|
305
|
+
{
|
306
|
+
return (void*)Qfalse;
|
307
|
+
}
|
308
|
+
rt = dpi_exec_direct(hstmt,args->sql_ptr);
|
309
|
+
if(!DSQL_SUCCEEDED(rt))
|
310
|
+
{
|
311
|
+
return (void*)Qfalse;
|
312
|
+
}
|
313
|
+
rt = dpi_get_diag_field(DSQL_HANDLE_STMT, hstmt, 0,
|
314
|
+
DSQL_DIAG_DYNAMIC_FUNCTION_CODE,
|
315
|
+
(dpointer)&nStmtType, 0, NULL);
|
316
|
+
if(!DSQL_SUCCEEDED(rt))
|
317
|
+
{
|
318
|
+
return (void*)Qfalse;
|
319
|
+
}
|
320
|
+
//lastrowid
|
321
|
+
if(nStmtType == DSQL_DIAG_FUNC_CODE_INSERT ||
|
322
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_UPDATE ||
|
323
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_DELETE)
|
324
|
+
{
|
325
|
+
rt = dpi_get_diag_field(DSQL_HANDLE_STMT, hstmt, 0, DSQL_DIAG_ROWID, &lastrowid, sizeof(lastrowid), NULL);
|
326
|
+
rt = dpi_rowid_to_char(args->con,lastrowid,sizeof(lastrowid),args->wrapper->lastrowid,sizeof(args->wrapper->lastrowid),&len);
|
327
|
+
}
|
328
|
+
else
|
329
|
+
{
|
330
|
+
strncpy(args->wrapper->lastrowid, "", 20);
|
331
|
+
}
|
332
|
+
|
333
|
+
// affected_rows
|
334
|
+
if(nStmtType == DSQL_DIAG_FUNC_CODE_INSERT ||
|
335
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_UPDATE ||
|
336
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_DELETE ||
|
337
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_CALL)
|
338
|
+
{
|
339
|
+
rt = dpi_row_count(hstmt,&args->wrapper->affected_rows);
|
340
|
+
}
|
341
|
+
else{
|
342
|
+
args->wrapper->affected_rows = 0;
|
343
|
+
}
|
344
|
+
//if have a result
|
345
|
+
if(nStmtType == DSQL_DIAG_FUNC_CODE_SELECT ||
|
346
|
+
nStmtType == DSQL_DIAG_FUNC_CODE_CALL)
|
347
|
+
{
|
348
|
+
args->wrapper->is_select = 1;
|
349
|
+
}
|
350
|
+
|
351
|
+
return (void*)Qtrue;
|
352
|
+
}
|
353
|
+
|
354
|
+
static VALUE do_send_query(VALUE args) {
|
355
|
+
struct nogvl_send_query_args *query_args = (void *)args;
|
356
|
+
dm_client_wrapper *wrapper = query_args->wrapper;
|
357
|
+
wrapper->is_select = 0;
|
358
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, query_args, RUBY_UBF_IO, 0) == Qfalse) {
|
359
|
+
if(wrapper->stmt == NULL)
|
360
|
+
rb_raise(cdmError, "failed to alloc statement");
|
361
|
+
else
|
362
|
+
rb_raise_dm_error(wrapper, wrapper->stmt, DSQL_HANDLE_STMT);
|
363
|
+
}
|
364
|
+
return Qnil;
|
365
|
+
}
|
366
|
+
|
367
|
+
/* call-seq:
|
368
|
+
* client.query(sql)
|
369
|
+
*
|
370
|
+
* Query the database with +sql+, with optional +options+. For the possible
|
371
|
+
* options, see default_query_options on the dm::Client class.
|
372
|
+
*/
|
373
|
+
static VALUE rb_dm_query(VALUE self, VALUE sql, VALUE options) {
|
374
|
+
struct nogvl_send_query_args args;
|
375
|
+
VALUE resultobj;
|
376
|
+
GET_CLIENT(self);
|
377
|
+
|
378
|
+
REQUIRE_CONNECTED(wrapper);
|
379
|
+
args.con = wrapper->client;
|
380
|
+
|
381
|
+
Check_Type(sql, T_STRING);
|
382
|
+
/* ensure the string is in the encoding the connection is expecting */
|
383
|
+
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
384
|
+
args.sql_ptr = RSTRING_PTR(args.sql);
|
385
|
+
args.sql_len = RSTRING_LEN(args.sql);
|
386
|
+
args.wrapper = wrapper;
|
387
|
+
|
388
|
+
do_send_query((VALUE)&args);
|
389
|
+
(void)RB_GC_GUARD(sql);
|
390
|
+
|
391
|
+
if(wrapper->is_select == 1)
|
392
|
+
{
|
393
|
+
resultobj = rb_dm_result_to_obj(self, wrapper->encoding, wrapper->stmt, 0 , options);
|
394
|
+
wrapper->stmt = NULL;
|
395
|
+
return resultobj;
|
396
|
+
}
|
397
|
+
else
|
398
|
+
{
|
399
|
+
dpi_free_stmt(wrapper->stmt);
|
400
|
+
wrapper->stmt = NULL;
|
401
|
+
}
|
402
|
+
|
403
|
+
/* this will just block until the result is ready */
|
404
|
+
return Qnil;
|
405
|
+
}
|
406
|
+
|
407
|
+
|
408
|
+
/* call-seq:
|
409
|
+
* client.last_id
|
410
|
+
*
|
411
|
+
* Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE
|
412
|
+
* statement.
|
413
|
+
*/
|
414
|
+
static VALUE rb_dm_client_last_id(VALUE self) {
|
415
|
+
GET_CLIENT(self);
|
416
|
+
REQUIRE_CONNECTED(wrapper);
|
417
|
+
return rb_str_new2(wrapper->lastrowid);
|
418
|
+
}
|
419
|
+
|
420
|
+
|
421
|
+
/* call-seq:
|
422
|
+
* client.affected_rows
|
423
|
+
*
|
424
|
+
* returns the number of rows changed, deleted, or inserted by the last statement
|
425
|
+
* if it was an UPDATE, DELETE, or INSERT.
|
426
|
+
*/
|
427
|
+
static VALUE rb_dm_client_affected_rows(VALUE self) {
|
428
|
+
GET_CLIENT(self);
|
429
|
+
REQUIRE_CONNECTED(wrapper);
|
430
|
+
return ULL2NUM(wrapper->affected_rows);
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
/* call-seq:
|
435
|
+
* client.encoding
|
436
|
+
*
|
437
|
+
* Returns the encoding set on the client.
|
438
|
+
*/
|
439
|
+
static VALUE rb_dm_client_encoding(VALUE self) {
|
440
|
+
GET_CLIENT(self);
|
441
|
+
return wrapper->encoding;
|
442
|
+
}
|
443
|
+
|
444
|
+
static VALUE set_charset_name(VALUE self, VALUE value) {
|
445
|
+
int code;
|
446
|
+
DPIRETURN rt;
|
447
|
+
const struct dm_enc_name_to_rb_map *dmrb;
|
448
|
+
rb_encoding *enc;
|
449
|
+
VALUE rb_enc;
|
450
|
+
GET_CLIENT(self);
|
451
|
+
|
452
|
+
code = NUM2INT(value);
|
453
|
+
if(code<1 || code>11)
|
454
|
+
code = 1;
|
455
|
+
dmrb = dm_enc_name_to_rb(code);
|
456
|
+
if (dmrb == NULL || dmrb->rb_name == NULL) {
|
457
|
+
rb_raise(cdmError, "Unsupported charset");
|
458
|
+
} else {
|
459
|
+
enc = rb_enc_find(dmrb->rb_name);
|
460
|
+
rb_enc = rb_enc_from_encoding(enc);
|
461
|
+
wrapper->encoding = rb_enc;
|
462
|
+
}
|
463
|
+
|
464
|
+
wrapper->encode_code = code;
|
465
|
+
return value;
|
466
|
+
}
|
467
|
+
|
468
|
+
/* call-seq: client.prepare # => dm::Statement
|
469
|
+
*
|
470
|
+
* Create a new prepared statement.
|
471
|
+
*/
|
472
|
+
static VALUE rb_dm_client_prepare_statement(VALUE self, VALUE sql) {
|
473
|
+
GET_CLIENT(self);
|
474
|
+
REQUIRE_CONNECTED(wrapper);
|
475
|
+
VALUE obj = rb_dm_stmt_new(self,sql);
|
476
|
+
return obj;
|
477
|
+
}
|
478
|
+
|
479
|
+
void init_dm_client() {
|
480
|
+
#if 0
|
481
|
+
mdm = rb_define_module("dm"); Teach RDoc about dm constant.
|
482
|
+
#endif
|
483
|
+
cdmClient = rb_define_class_under(mdm, "Client", rb_cObject);
|
484
|
+
rb_global_variable(&cdmClient);
|
485
|
+
rb_define_alloc_func(cdmClient, allocate);
|
486
|
+
|
487
|
+
rb_define_method(cdmClient, "close", rb_dm_client_close, 0);
|
488
|
+
rb_define_method(cdmClient, "closed?", rb_dm_client_closed, 0);
|
489
|
+
rb_define_method(cdmClient, "last_id", rb_dm_client_last_id, 0);
|
490
|
+
rb_define_method(cdmClient, "affected_rows", rb_dm_client_affected_rows, 0);
|
491
|
+
rb_define_method(cdmClient, "prepare", rb_dm_client_prepare_statement, 1);
|
492
|
+
rb_define_method(cdmClient, "encoding", rb_dm_client_encoding, 0);
|
493
|
+
|
494
|
+
rb_define_private_method(cdmClient, "charset_name=", set_charset_name, 1);
|
495
|
+
rb_define_private_method(cdmClient, "connect", rb_dm_connect, 3);
|
496
|
+
rb_define_private_method(cdmClient, "_query", rb_dm_query, 2);
|
497
|
+
|
498
|
+
sym_id = ID2SYM(rb_intern("id"));
|
499
|
+
sym_version = ID2SYM(rb_intern("version"));
|
500
|
+
sym_header_version = ID2SYM(rb_intern("header_version"));
|
501
|
+
sym_async = ID2SYM(rb_intern("async"));
|
502
|
+
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
503
|
+
sym_as = ID2SYM(rb_intern("as"));
|
504
|
+
sym_array = ID2SYM(rb_intern("array"));
|
505
|
+
sym_stream = ID2SYM(rb_intern("stream"));
|
506
|
+
|
507
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
508
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
509
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
510
|
+
|
511
|
+
intern_brackets = rb_intern("[]");
|
512
|
+
intern_merge = rb_intern("merge");
|
513
|
+
intern_merge_bang = rb_intern("merge!");
|
514
|
+
intern_new_with_args = rb_intern("new_with_args");
|
515
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
516
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
517
|
+
|
518
|
+
rb_const_set(cdmClient, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
519
|
+
|
520
|
+
}
|
data/ext/client.h
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#ifndef DM_CLIENT_H
|
2
|
+
#define DM_CLIENT_H
|
3
|
+
|
4
|
+
typedef struct {
|
5
|
+
VALUE encoding;
|
6
|
+
VALUE active_fiber; /* rb_fiber_current() or Qnil */
|
7
|
+
long server_version;
|
8
|
+
int reconnect_enabled;
|
9
|
+
unsigned int connect_timeout;
|
10
|
+
int active;
|
11
|
+
int initialized;
|
12
|
+
int refcount;
|
13
|
+
int closed;
|
14
|
+
int is_select;
|
15
|
+
int encode_code;
|
16
|
+
sdbyte lastrowid[20];
|
17
|
+
sdint8 affected_rows;
|
18
|
+
dhenv env;
|
19
|
+
dhcon client;
|
20
|
+
dhstmt stmt;
|
21
|
+
} dm_client_wrapper;
|
22
|
+
|
23
|
+
void rb_dm_set_server_query_flags(dhcon client, VALUE result);
|
24
|
+
|
25
|
+
extern const rb_data_type_t rb_dm_client_type;
|
26
|
+
|
27
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
28
|
+
#define GET_CLIENT(self) \
|
29
|
+
dm_client_wrapper *wrapper; \
|
30
|
+
TypedData_Get_Struct(self, dm_client_wrapper, &rb_dm_client_type, wrapper);
|
31
|
+
#else
|
32
|
+
#define GET_CLIENT(self) \
|
33
|
+
dm_client_wrapper *wrapper; \
|
34
|
+
Data_Get_Struct(self, dm_client_wrapper, wrapper);
|
35
|
+
#endif
|
36
|
+
|
37
|
+
void init_dm_client(void);
|
38
|
+
void decr_dm_client(dm_client_wrapper *wrapper);
|
39
|
+
|
40
|
+
#endif
|
@@ -0,0 +1,63 @@
|
|
1
|
+
/* C code produced by gperf version 3.0.4 */
|
2
|
+
/* Command-line: gperf */
|
3
|
+
/* Computed positions: -k'1,3,$' */
|
4
|
+
|
5
|
+
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
6
|
+
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
7
|
+
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
8
|
+
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
9
|
+
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
10
|
+
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
11
|
+
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
12
|
+
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
13
|
+
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
14
|
+
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
15
|
+
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
16
|
+
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
17
|
+
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
18
|
+
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
19
|
+
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
20
|
+
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
21
|
+
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
22
|
+
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
23
|
+
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
24
|
+
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
25
|
+
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
26
|
+
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
27
|
+
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
28
|
+
/* The character set is not based on ISO-646. */
|
29
|
+
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
30
|
+
#endif
|
31
|
+
|
32
|
+
struct dm_enc_name_to_rb_map { int code; const char *rb_name; };
|
33
|
+
/* maximum key range = 71, duplicates = 0 */
|
34
|
+
|
35
|
+
#ifdef __GNUC__
|
36
|
+
__inline
|
37
|
+
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
38
|
+
__attribute__ ((__gnu_inline__))
|
39
|
+
#endif
|
40
|
+
#endif
|
41
|
+
const struct dm_enc_name_to_rb_map* dm_enc_name_to_rb (int code)
|
42
|
+
{
|
43
|
+
static const struct dm_enc_name_to_rb_map wordlist[] =
|
44
|
+
{
|
45
|
+
{1, "UTF-8"},
|
46
|
+
{2, "GBK"},
|
47
|
+
{3, "Big5"},
|
48
|
+
{4, "ISO-8859-9"},
|
49
|
+
{5, "ECU-JP"},
|
50
|
+
{6, "EUC-KR"},
|
51
|
+
{7, "KOI8-R"},
|
52
|
+
{8, "ISO-8859-1"},
|
53
|
+
{9, "US-ASCII"},
|
54
|
+
{10, "GB18030"},
|
55
|
+
{11, "ISO-8859-11"}
|
56
|
+
};
|
57
|
+
|
58
|
+
if (code > 0 && code < 12)
|
59
|
+
{
|
60
|
+
return &wordlist[code-1];
|
61
|
+
}
|
62
|
+
return NULL;
|
63
|
+
}
|
data/ext/dm_ext.c
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#include <dm_ext.h>
|
2
|
+
|
3
|
+
VALUE mdm, cdmError;
|
4
|
+
|
5
|
+
|
6
|
+
/* Ruby Extension initializer */
|
7
|
+
void Init_dm_ext() {
|
8
|
+
mdm = rb_define_module("Dm");
|
9
|
+
rb_global_variable(&mdm);
|
10
|
+
|
11
|
+
cdmError = rb_const_get(mdm, rb_intern("Error"));
|
12
|
+
rb_global_variable(&cdmError);
|
13
|
+
|
14
|
+
init_dm_client();
|
15
|
+
init_dm_result();
|
16
|
+
init_dm_statement();
|
17
|
+
}
|
data/ext/dm_ext.h
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#ifndef DM_EXT
|
2
|
+
#define DM_EXT
|
3
|
+
|
4
|
+
void Init_dm(void);
|
5
|
+
|
6
|
+
/* tell rbx not to use it's caching compat layer
|
7
|
+
by doing this we're making a promise to RBX that
|
8
|
+
we'll never modify the pointers we get back from RSTRING_PTR */
|
9
|
+
#define RSTRING_NOT_MODIFIED
|
10
|
+
#include <ruby.h>
|
11
|
+
|
12
|
+
#include "DPI.h"
|
13
|
+
#include "DPIext.h"
|
14
|
+
#include "DPItypes.h"
|
15
|
+
|
16
|
+
#include <ruby/encoding.h>
|
17
|
+
#include <ruby/thread.h>
|
18
|
+
|
19
|
+
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
20
|
+
#define RB_DM_NORETURN __attribute__ ((noreturn))
|
21
|
+
#define RB_DM_UNUSED __attribute__ ((unused))
|
22
|
+
#else
|
23
|
+
#define RB_DM_NORETURN
|
24
|
+
#define RB_DM_UNUSED
|
25
|
+
#endif
|
26
|
+
|
27
|
+
// ruby 2.7+
|
28
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
29
|
+
#define rb_dm_gc_location(ptr) ptr = rb_gc_location(ptr)
|
30
|
+
#else
|
31
|
+
#define rb_gc_mark_movable(ptr) rb_gc_mark(ptr)
|
32
|
+
#define rb_dm_gc_location(ptr)
|
33
|
+
#endif
|
34
|
+
|
35
|
+
// ruby 2.2+
|
36
|
+
#ifdef TypedData_Make_Struct
|
37
|
+
#define NEW_TYPEDDATA_WRAPPER 1
|
38
|
+
#endif
|
39
|
+
|
40
|
+
#include <client.h>
|
41
|
+
#include <result.h>
|
42
|
+
#include <statement.h>
|
43
|
+
#endif
|
data/ext/dm_lib_path.rb
ADDED
data/ext/extconf.h
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#ifndef EXTCONF_H
|
2
|
+
#define EXTCONF_H
|
3
|
+
#define HAVE_RB_GC_ADJUST_MEMORY_USAGE 1
|
4
|
+
#define HAVE_RB_GC_MARK_MOVABLE 1
|
5
|
+
#define HAVE_RB_IO_WAIT 1
|
6
|
+
#define HAVE_RB_IO_DESCRIPTOR 1
|
7
|
+
#define HAVE_UNISTD_H 1
|
8
|
+
#define HAVE_INTTYPES_H 1
|
9
|
+
#define HAVE_RUBY_FIBER_SCHEDULER_H 1
|
10
|
+
#define HAVE_VARIABLE_LENGTH_ARRAYS 1
|
11
|
+
#endif
|