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.
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
@@ -0,0 +1,3 @@
1
+ module Dm
2
+ DM_LIB_PATH = "E:\\dmdbms\\bin"
3
+ end
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