mysql2 0.2.24 → 0.3.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.
Files changed (57) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/CHANGELOG.md +148 -0
  5. data/Gemfile +3 -0
  6. data/README.rdoc +257 -0
  7. data/Rakefile +5 -0
  8. data/benchmark/active_record.rb +51 -0
  9. data/benchmark/active_record_threaded.rb +42 -0
  10. data/benchmark/allocations.rb +33 -0
  11. data/benchmark/escape.rb +36 -0
  12. data/benchmark/query_with_mysql_casting.rb +80 -0
  13. data/benchmark/query_without_mysql_casting.rb +47 -0
  14. data/benchmark/sequel.rb +37 -0
  15. data/benchmark/setup_db.rb +119 -0
  16. data/benchmark/threaded.rb +44 -0
  17. data/ext/mysql2/client.c +272 -849
  18. data/ext/mysql2/client.h +12 -27
  19. data/ext/mysql2/extconf.rb +14 -72
  20. data/ext/mysql2/mysql2_ext.h +4 -7
  21. data/ext/mysql2/result.c +123 -319
  22. data/ext/mysql2/result.h +1 -4
  23. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
  24. data/lib/active_record/fiber_patches.rb +104 -0
  25. data/lib/mysql2.rb +5 -20
  26. data/lib/mysql2/client.rb +200 -50
  27. data/lib/mysql2/em.rb +3 -13
  28. data/lib/mysql2/em_fiber.rb +31 -0
  29. data/lib/mysql2/error.rb +6 -71
  30. data/lib/mysql2/version.rb +2 -2
  31. data/mysql2.gemspec +32 -0
  32. data/spec/em/em_fiber_spec.rb +22 -0
  33. data/spec/em/em_spec.rb +9 -74
  34. data/spec/mysql2/client_spec.rb +126 -593
  35. data/spec/mysql2/error_spec.rb +44 -58
  36. data/spec/mysql2/result_spec.rb +85 -257
  37. data/spec/spec_helper.rb +3 -24
  38. data/tasks/benchmarks.rake +20 -0
  39. data/tasks/compile.rake +71 -0
  40. data/tasks/rspec.rake +16 -0
  41. data/tasks/vendor_mysql.rake +40 -0
  42. metadata +179 -92
  43. checksums.yaml +0 -7
  44. data/README.md +0 -524
  45. data/ext/mysql2/infile.c +0 -122
  46. data/ext/mysql2/infile.h +0 -1
  47. data/ext/mysql2/mysql_enc_name_to_ruby.h +0 -168
  48. data/ext/mysql2/mysql_enc_to_ruby.h +0 -246
  49. data/ext/mysql2/wait_for_single_fd.h +0 -36
  50. data/lib/active_record/connection_adapters/mysql2_adapter.rb +0 -635
  51. data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +0 -11
  52. data/lib/mysql2/console.rb +0 -5
  53. data/spec/configuration.yml.example +0 -17
  54. data/spec/my.cnf.example +0 -9
  55. data/spec/test_data +0 -1
  56. data/support/mysql_enc_to_ruby.rb +0 -82
  57. data/support/ruby_enc_to_mysql.rb +0 -61
data/ext/mysql2/client.c CHANGED
@@ -1,68 +1,28 @@
1
1
  #include <mysql2_ext.h>
2
-
3
- #include <time.h>
2
+ #include <client.h>
4
3
  #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 "wait_for_single_fd.h"
14
-
15
- #include "mysql_enc_name_to_ruby.h"
16
4
 
17
5
  VALUE cMysql2Client;
18
6
  extern VALUE mMysql2, cMysql2Error;
19
- static VALUE sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
20
- static ID intern_merge, intern_merge_bang, intern_error_number_eql, intern_sql_state_eql;
7
+ static VALUE intern_encoding_from_charset;
8
+ static VALUE sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
9
+ static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
21
10
 
22
- #ifndef HAVE_RB_HASH_DUP
23
- static VALUE rb_hash_dup(VALUE other) {
24
- return rb_funcall(rb_cHash, rb_intern("[]"), 1, other);
25
- }
26
- #endif
27
-
28
- #define REQUIRE_INITIALIZED(wrapper) \
29
- if (!wrapper->initialized) { \
30
- rb_raise(cMysql2Error, "MySQL client is not initialized"); \
31
- }
32
-
33
- #define REQUIRE_CONNECTED(wrapper) \
34
- REQUIRE_INITIALIZED(wrapper) \
35
- if (!wrapper->connected && !wrapper->reconnect_enabled) { \
11
+ #define REQUIRE_OPEN_DB(wrapper) \
12
+ if(wrapper->closed) { \
36
13
  rb_raise(cMysql2Error, "closed MySQL connection"); \
37
14
  }
38
15
 
39
- #define REQUIRE_NOT_CONNECTED(wrapper) \
40
- REQUIRE_INITIALIZED(wrapper) \
41
- if (wrapper->connected) { \
42
- rb_raise(cMysql2Error, "MySQL connection is already open"); \
43
- }
44
-
45
16
  #define MARK_CONN_INACTIVE(conn) \
46
- wrapper->active_thread = Qnil;
17
+ wrapper->active = 0
47
18
 
48
19
  #define GET_CLIENT(self) \
49
20
  mysql_client_wrapper *wrapper; \
50
21
  Data_Get_Struct(self, mysql_client_wrapper, wrapper)
51
22
 
52
- /*
53
- * compatability with mysql-connector-c, where LIBMYSQL_VERSION is the correct
54
- * variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
55
- * linking against the server itself
56
- */
57
- #ifdef LIBMYSQL_VERSION
58
- #define MYSQL_LINK_VERSION LIBMYSQL_VERSION
59
- #else
60
- #define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
61
- #endif
62
-
63
23
  /*
64
24
  * used to pass all arguments to mysql_real_connect while inside
65
- * rb_thread_call_without_gvl
25
+ * rb_thread_blocking_region
66
26
  */
67
27
  struct nogvl_connect_args {
68
28
  MYSQL *mysql;
@@ -77,23 +37,11 @@ struct nogvl_connect_args {
77
37
 
78
38
  /*
79
39
  * used to pass all arguments to mysql_send_query while inside
80
- * rb_thread_call_without_gvl
40
+ * rb_thread_blocking_region
81
41
  */
82
42
  struct nogvl_send_query_args {
83
43
  MYSQL *mysql;
84
44
  VALUE sql;
85
- const char *sql_ptr;
86
- long sql_len;
87
- mysql_client_wrapper *wrapper;
88
- };
89
-
90
- /*
91
- * used to pass all arguments to mysql_select_db while inside
92
- * rb_thread_call_without_gvl
93
- */
94
- struct nogvl_select_db_args {
95
- MYSQL *mysql;
96
- char *db;
97
45
  };
98
46
 
99
47
  /*
@@ -122,136 +70,94 @@ static void rb_mysql_client_mark(void * wrapper) {
122
70
  mysql_client_wrapper * w = wrapper;
123
71
  if (w) {
124
72
  rb_gc_mark(w->encoding);
125
- rb_gc_mark(w->active_thread);
126
73
  }
127
74
  }
128
75
 
129
76
  static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
130
77
  VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
131
78
  VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
132
- VALUE e;
133
-
134
79
  #ifdef HAVE_RUBY_ENCODING_H
135
- rb_enc_associate(rb_error_msg, rb_utf8_encoding());
136
- rb_enc_associate(rb_sql_state, rb_usascii_encoding());
80
+ rb_encoding *default_internal_enc = rb_default_internal_encoding();
81
+ rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
82
+
83
+ rb_enc_associate(rb_error_msg, conn_enc);
84
+ rb_enc_associate(rb_sql_state, conn_enc);
85
+ if (default_internal_enc) {
86
+ rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
87
+ rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
88
+ }
137
89
  #endif
138
90
 
139
- e = rb_funcall(cMysql2Error, rb_intern("new"), 2, rb_error_msg, LONG2FIX(wrapper->server_version));
91
+ VALUE e = rb_exc_new3(cMysql2Error, rb_error_msg);
140
92
  rb_funcall(e, intern_error_number_eql, 1, UINT2NUM(mysql_errno(wrapper->client)));
141
93
  rb_funcall(e, intern_sql_state_eql, 1, rb_sql_state);
142
94
  rb_exc_raise(e);
143
95
  return Qnil;
144
96
  }
145
97
 
146
- static void *nogvl_init(void *ptr) {
98
+ static VALUE nogvl_init(void *ptr) {
147
99
  MYSQL *client;
148
- mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
149
100
 
150
101
  /* may initialize embedded server and read /etc/services off disk */
151
- client = mysql_init(wrapper->client);
152
-
153
- if (client) mysql2_set_local_infile(client, wrapper);
154
-
155
- return (void*)(client ? Qtrue : Qfalse);
102
+ client = mysql_init((MYSQL *)ptr);
103
+ return client ? Qtrue : Qfalse;
156
104
  }
157
105
 
158
- static void *nogvl_connect(void *ptr) {
106
+ static VALUE nogvl_connect(void *ptr) {
159
107
  struct nogvl_connect_args *args = ptr;
160
108
  MYSQL *client;
161
109
 
162
- client = mysql_real_connect(args->mysql, args->host,
163
- args->user, args->passwd,
164
- args->db, args->port, args->unix_socket,
165
- args->client_flag);
110
+ do {
111
+ client = mysql_real_connect(args->mysql, args->host,
112
+ args->user, args->passwd,
113
+ args->db, args->port, args->unix_socket,
114
+ args->client_flag);
115
+ } while (! client && errno == EINTR && (errno = 0) == 0);
166
116
 
167
- return (void *)(client ? Qtrue : Qfalse);
117
+ return client ? Qtrue : Qfalse;
168
118
  }
169
119
 
120
+ static VALUE nogvl_close(void *ptr) {
121
+ mysql_client_wrapper *wrapper;
170
122
  #ifndef _WIN32
171
- /*
172
- * Redirect clientfd to /dev/null for mysql_close and SSL_close to write,
173
- * shutdown, and close. The hack is needed to prevent shutdown() from breaking
174
- * a socket that may be in use by the parent or other processes after fork.
175
- *
176
- * /dev/null is used to absorb writes; previously a dummy socket was used, but
177
- * it could not abosrb writes and caused openssl to go into an infinite loop.
178
- *
179
- * Returns Qtrue or Qfalse (success or failure)
180
- *
181
- * Note: if this function is needed on Windows, use "nul" instead of "/dev/null"
182
- */
183
- static VALUE invalidate_fd(int clientfd)
184
- {
185
- #ifdef SOCK_CLOEXEC
186
- /* Atomically set CLOEXEC on the new FD in case another thread forks */
187
- int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
188
- if (sockfd < 0) {
189
- /* Maybe SOCK_CLOEXEC is defined but not available on this kernel */
190
- int sockfd = open("/dev/null", O_RDWR);
191
- fcntl(sockfd, F_SETFD, FD_CLOEXEC);
192
- }
193
- #else
194
- /* Well we don't have SOCK_CLOEXEC, so just set FD_CLOEXEC quickly */
195
- int sockfd = open("/dev/null", O_RDWR);
196
- fcntl(sockfd, F_SETFD, FD_CLOEXEC);
123
+ int flags;
197
124
  #endif
125
+ wrapper = ptr;
126
+ if (!wrapper->closed) {
127
+ wrapper->closed = 1;
198
128
 
199
- if (sockfd < 0) {
200
129
  /*
201
- * Cannot raise here, because one or both of the following may be true:
202
- * a) we have no GVL (in C Ruby)
203
- * b) are running as a GC finalizer
130
+ * we'll send a QUIT message to the server, but that message is more of a
131
+ * formality than a hard requirement since the socket is getting shutdown
132
+ * anyways, so ensure the socket write does not block our interpreter
133
+ *
134
+ *
135
+ * if the socket is dead we have no chance of blocking,
136
+ * so ignore any potential fcntl errors since they don't matter
204
137
  */
205
- return Qfalse;
206
- }
207
-
208
- dup2(sockfd, clientfd);
209
- close(sockfd);
210
-
211
- return Qtrue;
212
- }
213
- #endif /* _WIN32 */
214
-
215
- static void *nogvl_close(void *ptr) {
216
- mysql_client_wrapper *wrapper;
217
- wrapper = ptr;
218
- if (wrapper->connected) {
219
- wrapper->active_thread = Qnil;
220
- wrapper->connected = 0;
221
138
  #ifndef _WIN32
222
- /* Invalidate the socket before calling mysql_close(). This prevents
223
- * mysql_close() from sending a mysql-QUIT or from calling shutdown() on
224
- * the socket. The difference is that invalidate_fd will drop this
225
- * process's reference to the socket only, while a QUIT or shutdown()
226
- * would render the underlying connection unusable, interrupting other
227
- * processes which share this object across a fork().
228
- */
229
- if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
230
- fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
231
- close(wrapper->client->net.fd);
232
- return NULL;
233
- }
139
+ flags = fcntl(wrapper->client->net.fd, F_GETFL);
140
+ if (flags > 0 && !(flags & O_NONBLOCK))
141
+ fcntl(wrapper->client->net.fd, F_SETFL, flags | O_NONBLOCK);
142
+ #else
143
+ u_long iMode;
144
+ iMode = 1;
145
+ ioctlsocket(wrapper->client->net.fd, FIONBIO, &iMode);
234
146
  #endif
235
147
 
236
- mysql_close(wrapper->client); /* only used to free memory at this point */
148
+ mysql_close(wrapper->client);
149
+ xfree(wrapper->client);
237
150
  }
238
151
 
239
- return NULL;
152
+ return Qnil;
240
153
  }
241
154
 
242
- static void rb_mysql_client_free(void *ptr) {
155
+ static void rb_mysql_client_free(void * ptr) {
243
156
  mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
244
- decr_mysql2_client(wrapper);
245
- }
246
157
 
247
- void decr_mysql2_client(mysql_client_wrapper *wrapper)
248
- {
249
- wrapper->refcount--;
250
- if (wrapper->refcount == 0) {
251
- nogvl_close(wrapper);
252
- xfree(wrapper->client);
253
- xfree(wrapper);
254
- }
158
+ nogvl_close(wrapper);
159
+
160
+ xfree(ptr);
255
161
  }
256
162
 
257
163
  static VALUE allocate(VALUE klass) {
@@ -259,25 +165,13 @@ static VALUE allocate(VALUE klass) {
259
165
  mysql_client_wrapper * wrapper;
260
166
  obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
261
167
  wrapper->encoding = Qnil;
262
- wrapper->active_thread = Qnil;
263
- wrapper->server_version = 0;
264
- wrapper->reconnect_enabled = 0;
265
- wrapper->connect_timeout = 0;
266
- wrapper->connected = 0; /* means that a database connection is open */
267
- wrapper->initialized = 0; /* means that that the wrapper is initialized */
268
- wrapper->refcount = 1;
168
+ wrapper->active = 0;
169
+ wrapper->closed = 1;
269
170
  wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
270
171
  return obj;
271
172
  }
272
173
 
273
- /* call-seq:
274
- * Mysql2::Client.escape(string)
275
- *
276
- * Escape +string+ so that it may be used in a SQL statement.
277
- * Note that this escape method is not connection encoding aware.
278
- * If you need encoding support use Mysql2::Client#escape instead.
279
- */
280
- static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
174
+ static VALUE rb_mysql_client_escape(VALUE klass, VALUE str) {
281
175
  unsigned char *newStr;
282
176
  VALUE rb_str;
283
177
  unsigned long newLen, oldLen;
@@ -289,7 +183,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
289
183
 
290
184
  newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
291
185
  if (newLen == oldLen) {
292
- /* no need to return a new ruby string if nothing changed */
186
+ // no need to return a new ruby string if nothing changed
293
187
  xfree(newStr);
294
188
  return str;
295
189
  } else {
@@ -302,81 +196,24 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
302
196
  }
303
197
  }
304
198
 
305
- static VALUE rb_mysql_client_warning_count(VALUE self) {
306
- unsigned int warning_count;
307
- GET_CLIENT(self);
308
-
309
- warning_count = mysql_warning_count(wrapper->client);
310
-
311
- return UINT2NUM(warning_count);
312
- }
313
-
314
- static VALUE rb_mysql_info(VALUE self) {
315
- const char *info;
316
- VALUE rb_str;
317
- GET_CLIENT(self);
318
-
319
- info = mysql_info(wrapper->client);
320
-
321
- if (info == NULL) {
322
- return Qnil;
323
- }
324
-
325
- rb_str = rb_str_new2(info);
326
- #ifdef HAVE_RUBY_ENCODING_H
327
- rb_enc_associate(rb_str, rb_utf8_encoding());
328
- #endif
329
-
330
- return rb_str;
331
- }
332
-
333
199
  static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
334
200
  struct nogvl_connect_args args;
335
- time_t start_time, end_time;
336
- unsigned int elapsed_time, connect_timeout;
337
- VALUE rv;
338
201
  GET_CLIENT(self);
339
202
 
340
- args.host = NIL_P(host) ? NULL : StringValuePtr(host);
203
+ args.host = NIL_P(host) ? "localhost" : StringValuePtr(host);
341
204
  args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
342
- args.port = NIL_P(port) ? 0 : NUM2INT(port);
205
+ args.port = NIL_P(port) ? 3306 : NUM2INT(port);
343
206
  args.user = NIL_P(user) ? NULL : StringValuePtr(user);
344
207
  args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
345
208
  args.db = NIL_P(database) ? NULL : StringValuePtr(database);
346
209
  args.mysql = wrapper->client;
347
210
  args.client_flag = NUM2ULONG(flags);
348
211
 
349
- if (wrapper->connect_timeout)
350
- time(&start_time);
351
- rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
352
- if (rv == Qfalse) {
353
- while (rv == Qfalse && errno == EINTR) {
354
- if (wrapper->connect_timeout) {
355
- time(&end_time);
356
- /* avoid long connect timeout from system time changes */
357
- if (end_time < start_time)
358
- start_time = end_time;
359
- elapsed_time = end_time - start_time;
360
- /* avoid an early timeout due to time truncating milliseconds off the start time */
361
- if (elapsed_time > 0)
362
- elapsed_time--;
363
- if (elapsed_time >= wrapper->connect_timeout)
364
- break;
365
- connect_timeout = wrapper->connect_timeout - elapsed_time;
366
- mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
367
- }
368
- errno = 0;
369
- rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
370
- }
371
- /* restore the connect timeout for reconnecting */
372
- if (wrapper->connect_timeout)
373
- mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout);
374
- if (rv == Qfalse)
375
- return rb_raise_mysql2_error(wrapper);
212
+ if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
213
+ // unable to connect
214
+ return rb_raise_mysql2_error(wrapper);
376
215
  }
377
216
 
378
- wrapper->server_version = mysql_get_server_version(wrapper->client);
379
- wrapper->connected = 1;
380
217
  return self;
381
218
  }
382
219
 
@@ -389,8 +226,8 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
389
226
  static VALUE rb_mysql_client_close(VALUE self) {
390
227
  GET_CLIENT(self);
391
228
 
392
- if (wrapper->connected) {
393
- rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
229
+ if (!wrapper->closed) {
230
+ rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
394
231
  }
395
232
 
396
233
  return Qnil;
@@ -401,24 +238,15 @@ static VALUE rb_mysql_client_close(VALUE self) {
401
238
  * enough to fit in a socket buffer, but sometimes large UPDATE and
402
239
  * INSERTs will cause the process to block
403
240
  */
404
- static void *nogvl_send_query(void *ptr) {
241
+ static VALUE nogvl_send_query(void *ptr) {
405
242
  struct nogvl_send_query_args *args = ptr;
406
243
  int rv;
244
+ const char *sql = StringValuePtr(args->sql);
245
+ long sql_len = RSTRING_LEN(args->sql);
407
246
 
408
- rv = mysql_send_query(args->mysql, args->sql_ptr, args->sql_len);
247
+ rv = mysql_send_query(args->mysql, sql, sql_len);
409
248
 
410
- return (void*)(rv == 0 ? Qtrue : Qfalse);
411
- }
412
-
413
- static VALUE do_send_query(void *args) {
414
- struct nogvl_send_query_args *query_args = args;
415
- mysql_client_wrapper *wrapper = query_args->wrapper;
416
- if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, args, RUBY_UBF_IO, 0) == Qfalse) {
417
- /* an error occurred, we're not active anymore */
418
- MARK_CONN_INACTIVE(self);
419
- return rb_raise_mysql2_error(wrapper);
420
- }
421
- return Qnil;
249
+ return rv == 0 ? Qtrue : Qfalse;
422
250
  }
423
251
 
424
252
  /*
@@ -426,129 +254,117 @@ static VALUE do_send_query(void *args) {
426
254
  * response can overflow the socket buffers and cause us to eventually
427
255
  * block while calling mysql_read_query_result
428
256
  */
429
- static void *nogvl_read_query_result(void *ptr) {
257
+ static VALUE nogvl_read_query_result(void *ptr) {
430
258
  MYSQL * client = ptr;
431
259
  my_bool res = mysql_read_query_result(client);
432
260
 
433
- return (void *)(res == 0 ? Qtrue : Qfalse);
434
- }
435
-
436
- static void *nogvl_do_result(void *ptr, char use_result) {
437
- mysql_client_wrapper *wrapper;
438
- MYSQL_RES *result;
439
-
440
- wrapper = (mysql_client_wrapper *)ptr;
441
- if(use_result) {
442
- result = mysql_use_result(wrapper->client);
443
- } else {
444
- result = mysql_store_result(wrapper->client);
445
- }
446
-
447
- /* once our result is stored off, this connection is
448
- ready for another command to be issued */
449
- wrapper->active_thread = Qnil;
450
-
451
- return result;
261
+ return res == 0 ? Qtrue : Qfalse;
452
262
  }
453
263
 
454
264
  /* mysql_store_result may (unlikely) read rows off the socket */
455
- static void *nogvl_store_result(void *ptr) {
456
- return nogvl_do_result(ptr, 0);
457
- }
458
-
459
- static void *nogvl_use_result(void *ptr) {
460
- return nogvl_do_result(ptr, 1);
265
+ static VALUE nogvl_store_result(void *ptr) {
266
+ MYSQL * client = ptr;
267
+ return (VALUE)mysql_store_result(client);
461
268
  }
462
269
 
463
- /* call-seq:
464
- * client.async_result
465
- *
466
- * Returns the result for the last async issued query.
467
- */
468
270
  static VALUE rb_mysql_client_async_result(VALUE self) {
469
271
  MYSQL_RES * result;
470
272
  VALUE resultObj;
471
- VALUE current, is_streaming;
273
+ #ifdef HAVE_RUBY_ENCODING_H
274
+ mysql2_result_wrapper * result_wrapper;
275
+ #endif
472
276
  GET_CLIENT(self);
473
277
 
474
- /* if we're not waiting on a result, do nothing */
475
- if (NIL_P(wrapper->active_thread))
476
- return Qnil;
477
-
478
- REQUIRE_CONNECTED(wrapper);
479
- if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
480
- /* an error occurred, mark this connection inactive */
278
+ REQUIRE_OPEN_DB(wrapper);
279
+ if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
280
+ // an error occurred, mark this connection inactive
481
281
  MARK_CONN_INACTIVE(self);
482
282
  return rb_raise_mysql2_error(wrapper);
483
283
  }
484
284
 
485
- is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream);
486
- if(is_streaming == Qtrue) {
487
- result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
488
- } else {
489
- result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
490
- }
285
+ result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper->client, RUBY_UBF_IO, 0);
286
+
287
+ // we have our result, mark this connection inactive
288
+ MARK_CONN_INACTIVE(self);
491
289
 
492
290
  if (result == NULL) {
493
- if (mysql_errno(wrapper->client) != 0) {
494
- MARK_CONN_INACTIVE(self);
291
+ if (mysql_field_count(wrapper->client) != 0) {
495
292
  rb_raise_mysql2_error(wrapper);
496
293
  }
497
- /* no data and no error, so query was not a SELECT */
498
294
  return Qnil;
499
295
  }
500
296
 
501
- current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
502
- RB_GC_GUARD(current);
503
- Check_Type(current, T_HASH);
504
- resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
297
+ resultObj = rb_mysql_result_to_obj(result);
298
+ // pass-through query options for result construction later
299
+ rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));
505
300
 
301
+ #ifdef HAVE_RUBY_ENCODING_H
302
+ GetMysql2Result(resultObj, result_wrapper);
303
+ result_wrapper->encoding = wrapper->encoding;
304
+ #endif
506
305
  return resultObj;
507
306
  }
508
307
 
509
- #ifndef _WIN32
510
- struct async_query_args {
511
- int fd;
512
- VALUE self;
513
- };
514
-
515
- static VALUE disconnect_and_raise(VALUE self, VALUE error) {
308
+ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
309
+ struct nogvl_send_query_args args;
310
+ fd_set fdset;
311
+ int fd, retval;
312
+ int async = 0;
313
+ VALUE opts, defaults, read_timeout;
314
+ #ifdef HAVE_RUBY_ENCODING_H
315
+ rb_encoding *conn_enc;
316
+ #endif
317
+ struct timeval tv;
318
+ struct timeval* tvp;
319
+ long int sec;
320
+ VALUE result;
516
321
  GET_CLIENT(self);
517
322
 
518
- wrapper->active_thread = Qnil;
519
- wrapper->connected = 0;
323
+ REQUIRE_OPEN_DB(wrapper);
324
+ args.mysql = wrapper->client;
520
325
 
521
- /* Invalidate the MySQL socket to prevent further communication.
522
- * The GC will come along later and call mysql_close to free it.
523
- */
524
- if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
525
- fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
526
- close(wrapper->client->net.fd);
326
+ // see if this connection is still waiting on a result from a previous query
327
+ if (wrapper->active == 0) {
328
+ // mark this connection active
329
+ wrapper->active = 1;
330
+ } else {
331
+ rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
527
332
  }
528
333
 
529
- rb_exc_raise(error);
334
+ defaults = rb_iv_get(self, "@query_options");
335
+ if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
336
+ opts = rb_funcall(defaults, intern_merge, 1, opts);
337
+ rb_iv_set(self, "@query_options", opts);
530
338
 
531
- return Qnil;
532
- }
339
+ if (rb_hash_aref(opts, sym_async) == Qtrue) {
340
+ async = 1;
341
+ }
342
+ } else {
343
+ opts = defaults;
344
+ }
533
345
 
534
- static VALUE do_query(void *args) {
535
- struct async_query_args *async_args;
536
- struct timeval tv;
537
- struct timeval* tvp;
538
- long int sec;
539
- int retval;
540
- VALUE read_timeout;
346
+ Check_Type(args.sql, T_STRING);
347
+ #ifdef HAVE_RUBY_ENCODING_H
348
+ conn_enc = rb_to_encoding(wrapper->encoding);
349
+ // ensure the string is in the encoding the connection is expecting
350
+ args.sql = rb_str_export_to_enc(args.sql, conn_enc);
351
+ #endif
352
+
353
+ if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
354
+ // an error occurred, we're not active anymore
355
+ MARK_CONN_INACTIVE(self);
356
+ return rb_raise_mysql2_error(wrapper);
357
+ }
541
358
 
542
- async_args = (struct async_query_args *)args;
543
- read_timeout = rb_iv_get(async_args->self, "@read_timeout");
359
+ read_timeout = rb_iv_get(self, "@read_timeout");
544
360
 
545
361
  tvp = NULL;
546
362
  if (!NIL_P(read_timeout)) {
547
363
  Check_Type(read_timeout, T_FIXNUM);
548
364
  tvp = &tv;
549
365
  sec = FIX2INT(read_timeout);
550
- /* TODO: support partial seconds?
551
- also, this check is here for sanity, we also check up in Ruby */
366
+ // TODO: support partial seconds?
367
+ // also, this check is here for sanity, we also check up in Ruby
552
368
  if (sec >= 0) {
553
369
  tvp->tv_sec = sec;
554
370
  } else {
@@ -557,163 +373,55 @@ static VALUE do_query(void *args) {
557
373
  tvp->tv_usec = 0;
558
374
  }
559
375
 
560
- for(;;) {
561
- retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
562
-
563
- if (retval == 0) {
564
- rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
565
- }
566
-
567
- if (retval < 0) {
568
- rb_sys_fail(0);
569
- }
570
-
571
- if (retval > 0) {
572
- break;
573
- }
574
- }
575
-
576
- return Qnil;
577
- }
578
- #else
579
- static VALUE finish_and_mark_inactive(void *args) {
580
- VALUE self;
581
- MYSQL_RES *result;
582
-
583
- self = (VALUE)args;
584
-
585
- GET_CLIENT(self);
586
-
587
- if (!NIL_P(wrapper->active_thread)) {
588
- /* if we got here, the result hasn't been read off the wire yet
589
- so lets do that and then throw it away because we have no way
590
- of getting it back up to the caller from here */
591
- result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
592
- mysql_free_result(result);
593
-
594
- wrapper->active_thread = Qnil;
595
- }
376
+ if (!async) {
377
+ // the below code is largely from do_mysql
378
+ // http://github.com/datamapper/do
379
+ fd = wrapper->client->net.fd;
380
+ for(;;) {
381
+ int fd_set_fd = fd;
596
382
 
597
- return Qnil;
598
- }
383
+ #ifdef _WIN32
384
+ WSAPROTOCOL_INFO wsa_pi;
385
+ // dupicate the SOCKET from libmysql
386
+ int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi);
387
+ SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
388
+ // create the CRT fd so ruby can get back to the SOCKET
389
+ fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
599
390
  #endif
600
391
 
601
- /* call-seq:
602
- * client.abandon_results!
603
- *
604
- * When using MULTI_STATEMENTS support, calling this will throw
605
- * away any unprocessed results as fast as it can in order to
606
- * put the connection back into a state where queries can be issued
607
- * again.
608
- */
609
- static VALUE rb_mysql_client_abandon_results(VALUE self) {
610
- MYSQL_RES *result;
611
- int ret;
392
+ FD_ZERO(&fdset);
393
+ FD_SET(fd_set_fd, &fdset);
612
394
 
613
- GET_CLIENT(self);
395
+ retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
614
396
 
615
- while (mysql_more_results(wrapper->client) == 1) {
616
- ret = mysql_next_result(wrapper->client);
617
- if (ret > 0) {
618
- rb_raise_mysql2_error(wrapper);
619
- }
620
-
621
- result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
622
-
623
- if (result != NULL) {
624
- mysql_free_result(result);
625
- }
626
- }
627
-
628
- return Qnil;
629
- }
630
-
631
- /* call-seq:
632
- * client.query(sql, options = {})
633
- *
634
- * Query the database with +sql+, with optional +options+. For the possible
635
- * options, see @@default_query_options on the Mysql2::Client class.
636
- */
637
- static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
638
- #ifndef _WIN32
639
- struct async_query_args async_args;
640
- #endif
641
- struct nogvl_send_query_args args;
642
- int async = 0;
643
- VALUE opts, current;
644
- VALUE thread_current = rb_thread_current();
645
- #ifdef HAVE_RUBY_ENCODING_H
646
- rb_encoding *conn_enc;
397
+ #ifdef _WIN32
398
+ // cleanup the CRT fd
399
+ _close(fd_set_fd);
400
+ // cleanup the duplicated SOCKET
401
+ closesocket(s);
647
402
  #endif
648
- GET_CLIENT(self);
649
-
650
- REQUIRE_CONNECTED(wrapper);
651
- args.mysql = wrapper->client;
652
403
 
653
- current = rb_hash_dup(rb_iv_get(self, "@query_options"));
654
- RB_GC_GUARD(current);
655
- Check_Type(current, T_HASH);
656
- rb_iv_set(self, "@current_query_options", current);
404
+ if (retval == 0) {
405
+ rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
406
+ }
657
407
 
658
- if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
659
- rb_funcall(current, intern_merge_bang, 1, opts);
408
+ if (retval < 0) {
409
+ rb_sys_fail(0);
410
+ }
660
411
 
661
- if (rb_hash_aref(current, sym_async) == Qtrue) {
662
- async = 1;
412
+ if (retval > 0) {
413
+ break;
414
+ }
663
415
  }
664
- }
665
416
 
666
- Check_Type(args.sql, T_STRING);
667
- #ifdef HAVE_RUBY_ENCODING_H
668
- conn_enc = rb_to_encoding(wrapper->encoding);
669
- /* ensure the string is in the encoding the connection is expecting */
670
- args.sql = rb_str_export_to_enc(args.sql, conn_enc);
671
- #endif
672
- args.sql_ptr = StringValuePtr(args.sql);
673
- args.sql_len = RSTRING_LEN(args.sql);
674
-
675
- /* see if this connection is still waiting on a result from a previous query */
676
- if (NIL_P(wrapper->active_thread)) {
677
- /* mark this connection active */
678
- wrapper->active_thread = thread_current;
679
- } else if (wrapper->active_thread == thread_current) {
680
- rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
681
- } else {
682
- VALUE inspect = rb_inspect(wrapper->active_thread);
683
- const char *thr = StringValueCStr(inspect);
684
-
685
- rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
686
- RB_GC_GUARD(inspect);
687
- }
688
-
689
- args.wrapper = wrapper;
690
-
691
- #ifndef _WIN32
692
- rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
693
-
694
- if (!async) {
695
- async_args.fd = wrapper->client->net.fd;
696
- async_args.self = self;
417
+ result = rb_mysql_client_async_result(self);
697
418
 
698
- rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);
699
-
700
- return rb_mysql_client_async_result(self);
419
+ return result;
701
420
  } else {
702
421
  return Qnil;
703
422
  }
704
- #else
705
- do_send_query(&args);
706
-
707
- /* this will just block until the result is ready */
708
- return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
709
- #endif
710
423
  }
711
424
 
712
- /* call-seq:
713
- * client.escape(string)
714
- *
715
- * Escape +string+ so that it may be used in a SQL statement.
716
- */
717
425
  static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
718
426
  unsigned char *newStr;
719
427
  VALUE rb_str;
@@ -724,12 +432,12 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
724
432
  #endif
725
433
  GET_CLIENT(self);
726
434
 
727
- REQUIRE_CONNECTED(wrapper);
435
+ REQUIRE_OPEN_DB(wrapper);
728
436
  Check_Type(str, T_STRING);
729
437
  #ifdef HAVE_RUBY_ENCODING_H
730
438
  default_internal_enc = rb_default_internal_encoding();
731
439
  conn_enc = rb_to_encoding(wrapper->encoding);
732
- /* ensure the string is in the encoding the connection is expecting */
440
+ // ensure the string is in the encoding the connection is expecting
733
441
  str = rb_str_export_to_enc(str, conn_enc);
734
442
  #endif
735
443
 
@@ -738,7 +446,7 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
738
446
 
739
447
  newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
740
448
  if (newLen == oldLen) {
741
- /* no need to return a new ruby string if nothing changed */
449
+ // no need to return a new ruby string if nothing changed
742
450
  xfree(newStr);
743
451
  return str;
744
452
  } else {
@@ -754,102 +462,13 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
754
462
  }
755
463
  }
756
464
 
757
- static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
758
- int result;
759
- const void *retval = NULL;
760
- unsigned int intval = 0;
761
- const char * charval = NULL;
762
- my_bool boolval;
763
-
764
- GET_CLIENT(self);
765
-
766
- REQUIRE_NOT_CONNECTED(wrapper);
767
-
768
- if (NIL_P(value))
769
- return Qfalse;
770
-
771
- switch(opt) {
772
- case MYSQL_OPT_CONNECT_TIMEOUT:
773
- intval = NUM2UINT(value);
774
- retval = &intval;
775
- break;
776
-
777
- case MYSQL_OPT_READ_TIMEOUT:
778
- intval = NUM2UINT(value);
779
- retval = &intval;
780
- break;
781
-
782
- case MYSQL_OPT_WRITE_TIMEOUT:
783
- intval = NUM2UINT(value);
784
- retval = &intval;
785
- break;
786
-
787
- case MYSQL_OPT_LOCAL_INFILE:
788
- intval = (value == Qfalse ? 0 : 1);
789
- retval = &intval;
790
- break;
791
-
792
- case MYSQL_OPT_RECONNECT:
793
- boolval = (value == Qfalse ? 0 : 1);
794
- retval = &boolval;
795
- break;
796
-
797
- case MYSQL_SECURE_AUTH:
798
- boolval = (value == Qfalse ? 0 : 1);
799
- retval = &boolval;
800
- break;
801
-
802
- case MYSQL_READ_DEFAULT_FILE:
803
- charval = (const char *)StringValuePtr(value);
804
- retval = charval;
805
- break;
806
-
807
- case MYSQL_READ_DEFAULT_GROUP:
808
- charval = (const char *)StringValuePtr(value);
809
- retval = charval;
810
- break;
811
-
812
- case MYSQL_INIT_COMMAND:
813
- charval = (const char *)StringValuePtr(value);
814
- retval = charval;
815
- break;
816
-
817
- default:
818
- return Qfalse;
819
- }
820
-
821
- result = mysql_options(wrapper->client, opt, retval);
822
-
823
- /* Zero means success */
824
- if (result != 0) {
825
- rb_warn("%s\n", mysql_error(wrapper->client));
826
- } else {
827
- /* Special case for options that are stored in the wrapper struct */
828
- switch (opt) {
829
- case MYSQL_OPT_RECONNECT:
830
- wrapper->reconnect_enabled = boolval;
831
- break;
832
- case MYSQL_OPT_CONNECT_TIMEOUT:
833
- wrapper->connect_timeout = intval;
834
- break;
835
- }
836
- }
837
-
838
- return (result == 0) ? Qtrue : Qfalse;
839
- }
840
-
841
- /* call-seq:
842
- * client.info
843
- *
844
- * Returns a string that represents the client library version.
845
- */
846
465
  static VALUE rb_mysql_client_info(VALUE self) {
847
466
  VALUE version, client_info;
848
467
  #ifdef HAVE_RUBY_ENCODING_H
849
468
  rb_encoding *default_internal_enc;
850
469
  rb_encoding *conn_enc;
851
- GET_CLIENT(self);
852
470
  #endif
471
+ GET_CLIENT(self);
853
472
  version = rb_hash_new();
854
473
 
855
474
  #ifdef HAVE_RUBY_ENCODING_H
@@ -869,11 +488,6 @@ static VALUE rb_mysql_client_info(VALUE self) {
869
488
  return version;
870
489
  }
871
490
 
872
- /* call-seq:
873
- * client.server_info
874
- *
875
- * Returns a string that represents the server version number
876
- */
877
491
  static VALUE rb_mysql_client_server_info(VALUE self) {
878
492
  VALUE version, server_info;
879
493
  #ifdef HAVE_RUBY_ENCODING_H
@@ -882,7 +496,7 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
882
496
  #endif
883
497
  GET_CLIENT(self);
884
498
 
885
- REQUIRE_CONNECTED(wrapper);
499
+ REQUIRE_OPEN_DB(wrapper);
886
500
  #ifdef HAVE_RUBY_ENCODING_H
887
501
  default_internal_enc = rb_default_internal_encoding();
888
502
  conn_enc = rb_to_encoding(wrapper->encoding);
@@ -901,48 +515,34 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
901
515
  return version;
902
516
  }
903
517
 
904
- /* call-seq:
905
- * client.socket
906
- *
907
- * Return the file descriptor number for this client.
908
- */
909
518
  static VALUE rb_mysql_client_socket(VALUE self) {
910
519
  GET_CLIENT(self);
911
- #ifndef _WIN32
912
- {
913
- int fd_set_fd;
914
- REQUIRE_CONNECTED(wrapper);
915
- fd_set_fd = wrapper->client->net.fd;
916
- return INT2NUM(fd_set_fd);
917
- }
520
+ REQUIRE_OPEN_DB(wrapper);
521
+ int fd_set_fd = wrapper->client->net.fd;
522
+ #ifdef _WIN32
523
+ WSAPROTOCOL_INFO wsa_pi;
524
+ // dupicate the SOCKET from libmysql
525
+ int r = WSADuplicateSocket(wrapper->client->net.fd, GetCurrentProcessId(), &wsa_pi);
526
+ SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
527
+ // create the CRT fd so ruby can get back to the SOCKET
528
+ fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
529
+ return INT2NUM(fd_set_fd);
918
530
  #else
919
- rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
531
+ return INT2NUM(fd_set_fd);
920
532
  #endif
921
533
  }
922
534
 
923
- /* call-seq:
924
- * client.last_id
925
- *
926
- * Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE
927
- * statement.
928
- */
929
535
  static VALUE rb_mysql_client_last_id(VALUE self) {
930
536
  GET_CLIENT(self);
931
- REQUIRE_CONNECTED(wrapper);
537
+ REQUIRE_OPEN_DB(wrapper);
932
538
  return ULL2NUM(mysql_insert_id(wrapper->client));
933
539
  }
934
540
 
935
- /* call-seq:
936
- * client.affected_rows
937
- *
938
- * returns the number of rows changed, deleted, or inserted by the last statement
939
- * if it was an UPDATE, DELETE, or INSERT.
940
- */
941
541
  static VALUE rb_mysql_client_affected_rows(VALUE self) {
942
542
  my_ulonglong retVal;
943
543
  GET_CLIENT(self);
944
544
 
945
- REQUIRE_CONNECTED(wrapper);
545
+ REQUIRE_OPEN_DB(wrapper);
946
546
  retVal = mysql_affected_rows(wrapper->client);
947
547
  if (retVal == (my_ulonglong)-1) {
948
548
  rb_raise_mysql2_error(wrapper);
@@ -950,227 +550,93 @@ static VALUE rb_mysql_client_affected_rows(VALUE self) {
950
550
  return ULL2NUM(retVal);
951
551
  }
952
552
 
953
- /* call-seq:
954
- * client.thread_id
955
- *
956
- * Returns the thread ID of the current connection.
957
- */
958
553
  static VALUE rb_mysql_client_thread_id(VALUE self) {
959
554
  unsigned long retVal;
960
555
  GET_CLIENT(self);
961
556
 
962
- REQUIRE_CONNECTED(wrapper);
557
+ REQUIRE_OPEN_DB(wrapper);
963
558
  retVal = mysql_thread_id(wrapper->client);
964
559
  return ULL2NUM(retVal);
965
560
  }
966
561
 
967
- static void *nogvl_select_db(void *ptr) {
968
- struct nogvl_select_db_args *args = ptr;
969
-
970
- if (mysql_select_db(args->mysql, args->db) == 0)
971
- return (void *)Qtrue;
972
- else
973
- return (void *)Qfalse;
974
- }
975
-
976
- /* call-seq:
977
- * client.select_db(name)
978
- *
979
- * Causes the database specified by +name+ to become the default (current)
980
- * database on the connection specified by mysql.
981
- */
982
- static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
562
+ static VALUE nogvl_ping(void *ptr)
983
563
  {
984
- struct nogvl_select_db_args args;
985
-
986
- GET_CLIENT(self);
987
- REQUIRE_CONNECTED(wrapper);
988
-
989
- args.mysql = wrapper->client;
990
- args.db = StringValuePtr(db);
991
-
992
- if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
993
- rb_raise_mysql2_error(wrapper);
994
-
995
- return db;
996
- }
997
-
998
- static void *nogvl_ping(void *ptr) {
999
564
  MYSQL *client = ptr;
1000
565
 
1001
- return (void *)(mysql_ping(client) == 0 ? Qtrue : Qfalse);
566
+ return mysql_ping(client) == 0 ? Qtrue : Qfalse;
1002
567
  }
1003
568
 
1004
- /* call-seq:
1005
- * client.ping
1006
- *
1007
- * Checks whether the connection to the server is working. If the connection
1008
- * has gone down and auto-reconnect is enabled an attempt to reconnect is made.
1009
- * If the connection is down and auto-reconnect is disabled, ping returns an
1010
- * error.
1011
- */
1012
569
  static VALUE rb_mysql_client_ping(VALUE self) {
1013
570
  GET_CLIENT(self);
1014
571
 
1015
- if (!wrapper->connected) {
572
+ if (wrapper->closed) {
1016
573
  return Qfalse;
1017
574
  } else {
1018
- return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
1019
- }
1020
- }
1021
-
1022
- /* call-seq:
1023
- * client.more_results?
1024
- *
1025
- * Returns true or false if there are more results to process.
1026
- */
1027
- static VALUE rb_mysql_client_more_results(VALUE self)
1028
- {
1029
- GET_CLIENT(self);
1030
- if (mysql_more_results(wrapper->client) == 0)
1031
- return Qfalse;
1032
- else
1033
- return Qtrue;
1034
- }
1035
-
1036
- /* call-seq:
1037
- * client.next_result
1038
- *
1039
- * Fetch the next result set from the server.
1040
- * Returns nothing.
1041
- */
1042
- static VALUE rb_mysql_client_next_result(VALUE self)
1043
- {
1044
- int ret;
1045
- GET_CLIENT(self);
1046
- ret = mysql_next_result(wrapper->client);
1047
- if (ret > 0) {
1048
- rb_raise_mysql2_error(wrapper);
1049
- return Qfalse;
1050
- } else if (ret == 0) {
1051
- return Qtrue;
1052
- } else {
1053
- return Qfalse;
1054
- }
1055
- }
1056
-
1057
- /* call-seq:
1058
- * client.store_result
1059
- *
1060
- * Return the next result object from a query which
1061
- * yielded multiple result sets.
1062
- */
1063
- static VALUE rb_mysql_client_store_result(VALUE self)
1064
- {
1065
- MYSQL_RES * result;
1066
- VALUE resultObj;
1067
- VALUE current;
1068
- GET_CLIENT(self);
1069
-
1070
- result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
1071
-
1072
- if (result == NULL) {
1073
- if (mysql_errno(wrapper->client) != 0) {
1074
- rb_raise_mysql2_error(wrapper);
1075
- }
1076
- /* no data and no error, so query was not a SELECT */
1077
- return Qnil;
575
+ return rb_thread_blocking_region(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
1078
576
  }
1079
-
1080
- current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
1081
- RB_GC_GUARD(current);
1082
- Check_Type(current, T_HASH);
1083
- resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
1084
-
1085
- return resultObj;
1086
577
  }
1087
578
 
1088
579
  #ifdef HAVE_RUBY_ENCODING_H
1089
- /* call-seq:
1090
- * client.encoding
1091
- *
1092
- * Returns the encoding set on the client.
1093
- */
1094
580
  static VALUE rb_mysql_client_encoding(VALUE self) {
1095
581
  GET_CLIENT(self);
1096
582
  return wrapper->encoding;
1097
583
  }
1098
584
  #endif
1099
585
 
1100
- /* call-seq:
1101
- * client.reconnect = true
1102
- *
1103
- * Enable or disable the automatic reconnect behavior of libmysql.
1104
- * Read http://dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html
1105
- * for more information.
1106
- */
1107
586
  static VALUE set_reconnect(VALUE self, VALUE value) {
1108
- return _mysql_client_options(self, MYSQL_OPT_RECONNECT, value);
1109
- }
587
+ my_bool reconnect;
588
+ GET_CLIENT(self);
1110
589
 
1111
- static VALUE set_local_infile(VALUE self, VALUE value) {
1112
- return _mysql_client_options(self, MYSQL_OPT_LOCAL_INFILE, value);
1113
- }
590
+ if(!NIL_P(value)) {
591
+ reconnect = value == Qfalse ? 0 : 1;
1114
592
 
1115
- static VALUE set_connect_timeout(VALUE self, VALUE value) {
1116
- long int sec;
1117
- Check_Type(value, T_FIXNUM);
1118
- sec = FIX2INT(value);
1119
- if (sec < 0) {
1120
- rb_raise(cMysql2Error, "connect_timeout must be a positive integer, you passed %ld", sec);
593
+ /* set default reconnect behavior */
594
+ if (mysql_options(wrapper->client, MYSQL_OPT_RECONNECT, &reconnect)) {
595
+ /* TODO: warning - unable to set reconnect behavior */
596
+ rb_warn("%s\n", mysql_error(wrapper->client));
597
+ }
1121
598
  }
1122
- return _mysql_client_options(self, MYSQL_OPT_CONNECT_TIMEOUT, value);
599
+ return value;
1123
600
  }
1124
601
 
1125
- static VALUE set_read_timeout(VALUE self, VALUE value) {
1126
- long int sec;
1127
- Check_Type(value, T_FIXNUM);
1128
- sec = FIX2INT(value);
1129
- if (sec < 0) {
1130
- rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
1131
- }
1132
- /* Set the instance variable here even though _mysql_client_options
1133
- might not succeed, because the timeout is used in other ways
1134
- elsewhere */
1135
- rb_iv_set(self, "@read_timeout", value);
1136
- return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
1137
- }
602
+ static VALUE set_connect_timeout(VALUE self, VALUE value) {
603
+ unsigned int connect_timeout = 0;
604
+ GET_CLIENT(self);
1138
605
 
1139
- static VALUE set_write_timeout(VALUE self, VALUE value) {
1140
- long int sec;
1141
- Check_Type(value, T_FIXNUM);
1142
- sec = FIX2INT(value);
1143
- if (sec < 0) {
1144
- rb_raise(cMysql2Error, "write_timeout must be a positive integer, you passed %ld", sec);
606
+ if(!NIL_P(value)) {
607
+ connect_timeout = NUM2INT(value);
608
+ if(0 == connect_timeout) return value;
609
+
610
+ /* set default connection timeout behavior */
611
+ if (mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout)) {
612
+ /* TODO: warning - unable to set connection timeout */
613
+ rb_warn("%s\n", mysql_error(wrapper->client));
614
+ }
1145
615
  }
1146
- return _mysql_client_options(self, MYSQL_OPT_WRITE_TIMEOUT, value);
616
+ return value;
1147
617
  }
1148
618
 
1149
619
  static VALUE set_charset_name(VALUE self, VALUE value) {
1150
- char *charset_name;
620
+ char * charset_name;
1151
621
  #ifdef HAVE_RUBY_ENCODING_H
1152
- size_t charset_name_len;
1153
- const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
1154
- rb_encoding *enc;
1155
- VALUE rb_enc;
622
+ VALUE new_encoding;
1156
623
  #endif
1157
624
  GET_CLIENT(self);
1158
625
 
1159
- charset_name = RSTRING_PTR(value);
1160
-
1161
626
  #ifdef HAVE_RUBY_ENCODING_H
1162
- charset_name_len = RSTRING_LEN(value);
1163
- mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, charset_name_len);
1164
- if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
627
+ new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
628
+ if (new_encoding == Qnil) {
1165
629
  VALUE inspect = rb_inspect(value);
1166
630
  rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
1167
631
  } else {
1168
- enc = rb_enc_find(mysql2rb->rb_name);
1169
- rb_enc = rb_enc_from_encoding(enc);
1170
- wrapper->encoding = rb_enc;
632
+ if (wrapper->encoding == Qnil) {
633
+ wrapper->encoding = new_encoding;
634
+ }
1171
635
  }
1172
636
  #endif
1173
637
 
638
+ charset_name = StringValuePtr(value);
639
+
1174
640
  if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
1175
641
  /* TODO: warning - unable to set charset */
1176
642
  rb_warn("%s\n", mysql_error(wrapper->client));
@@ -1182,73 +648,48 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
1182
648
  static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
1183
649
  GET_CLIENT(self);
1184
650
 
1185
- mysql_ssl_set(wrapper->client,
1186
- NIL_P(key) ? NULL : StringValuePtr(key),
1187
- NIL_P(cert) ? NULL : StringValuePtr(cert),
1188
- NIL_P(ca) ? NULL : StringValuePtr(ca),
1189
- NIL_P(capath) ? NULL : StringValuePtr(capath),
1190
- NIL_P(cipher) ? NULL : StringValuePtr(cipher));
651
+ if(!NIL_P(ca) || !NIL_P(key)) {
652
+ mysql_ssl_set(wrapper->client,
653
+ NIL_P(key) ? NULL : StringValuePtr(key),
654
+ NIL_P(cert) ? NULL : StringValuePtr(cert),
655
+ NIL_P(ca) ? NULL : StringValuePtr(ca),
656
+ NIL_P(capath) ? NULL : StringValuePtr(capath),
657
+ NIL_P(cipher) ? NULL : StringValuePtr(cipher));
658
+ }
1191
659
 
1192
660
  return self;
1193
661
  }
1194
662
 
1195
- static VALUE set_secure_auth(VALUE self, VALUE value) {
1196
- return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
1197
- }
1198
-
1199
- static VALUE set_read_default_file(VALUE self, VALUE value) {
1200
- return _mysql_client_options(self, MYSQL_READ_DEFAULT_FILE, value);
1201
- }
1202
-
1203
- static VALUE set_read_default_group(VALUE self, VALUE value) {
1204
- return _mysql_client_options(self, MYSQL_READ_DEFAULT_GROUP, value);
1205
- }
1206
-
1207
- static VALUE set_init_command(VALUE self, VALUE value) {
1208
- return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
1209
- }
1210
-
1211
- static VALUE initialize_ext(VALUE self) {
663
+ static VALUE init_connection(VALUE self) {
1212
664
  GET_CLIENT(self);
1213
665
 
1214
- if ((VALUE)rb_thread_call_without_gvl(nogvl_init, wrapper, RUBY_UBF_IO, 0) == Qfalse) {
666
+ if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
1215
667
  /* TODO: warning - not enough memory? */
1216
668
  return rb_raise_mysql2_error(wrapper);
1217
669
  }
1218
670
 
1219
- wrapper->initialized = 1;
671
+ wrapper->closed = 0;
1220
672
  return self;
1221
673
  }
1222
674
 
1223
675
  void init_mysql2_client() {
1224
- /* verify the libmysql we're about to use was the version we were built against
1225
- https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99 */
676
+ // verify the libmysql we're about to use was the version we were built against
677
+ // https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99
1226
678
  int i;
1227
679
  int dots = 0;
1228
680
  const char *lib = mysql_get_client_info();
1229
-
1230
- for (i = 0; lib[i] != 0 && MYSQL_LINK_VERSION[i] != 0; i++) {
681
+ for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
1231
682
  if (lib[i] == '.') {
1232
683
  dots++;
1233
- /* we only compare MAJOR and MINOR */
684
+ // we only compare MAJOR and MINOR
1234
685
  if (dots == 2) break;
1235
686
  }
1236
- if (lib[i] != MYSQL_LINK_VERSION[i]) {
1237
- rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_LINK_VERSION, lib);
687
+ if (lib[i] != MYSQL_SERVER_VERSION[i]) {
688
+ rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_SERVER_VERSION, lib);
1238
689
  return;
1239
690
  }
1240
691
  }
1241
692
 
1242
- /* Initializing mysql library, so different threads could call Client.new */
1243
- /* without race condition in the library */
1244
- if (mysql_library_init(0, NULL, NULL) != 0) {
1245
- rb_raise(rb_eRuntimeError, "Could not initialize MySQL client library");
1246
- return;
1247
- }
1248
-
1249
- #if 0
1250
- mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
1251
- #endif
1252
693
  cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
1253
694
 
1254
695
  rb_define_alloc_func(cMysql2Client, allocate);
@@ -1257,7 +698,6 @@ void init_mysql2_client() {
1257
698
 
1258
699
  rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
1259
700
  rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
1260
- rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
1261
701
  rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
1262
702
  rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1263
703
  rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
@@ -1267,150 +707,133 @@ void init_mysql2_client() {
1267
707
  rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
1268
708
  rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
1269
709
  rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
1270
- rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
1271
- rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
1272
- rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
1273
- rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
1274
- rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
1275
- rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
1276
- rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
1277
710
  #ifdef HAVE_RUBY_ENCODING_H
1278
711
  rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
1279
712
  #endif
1280
713
 
714
+ rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
1281
715
  rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
1282
- rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
1283
- rb_define_private_method(cMysql2Client, "write_timeout=", set_write_timeout, 1);
1284
- rb_define_private_method(cMysql2Client, "local_infile=", set_local_infile, 1);
1285
716
  rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1);
1286
- rb_define_private_method(cMysql2Client, "secure_auth=", set_secure_auth, 1);
1287
- rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
1288
- rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
1289
- rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
1290
717
  rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
1291
- rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
718
+ rb_define_private_method(cMysql2Client, "init_connection", init_connection, 0);
1292
719
  rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
1293
720
 
721
+ intern_encoding_from_charset = rb_intern("encoding_from_charset");
722
+
1294
723
  sym_id = ID2SYM(rb_intern("id"));
1295
724
  sym_version = ID2SYM(rb_intern("version"));
1296
725
  sym_async = ID2SYM(rb_intern("async"));
1297
726
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
1298
727
  sym_as = ID2SYM(rb_intern("as"));
1299
728
  sym_array = ID2SYM(rb_intern("array"));
1300
- sym_stream = ID2SYM(rb_intern("stream"));
1301
729
 
1302
730
  intern_merge = rb_intern("merge");
1303
- intern_merge_bang = rb_intern("merge!");
1304
731
  intern_error_number_eql = rb_intern("error_number=");
1305
732
  intern_sql_state_eql = rb_intern("sql_state=");
1306
733
 
1307
734
  #ifdef CLIENT_LONG_PASSWORD
1308
735
  rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
1309
- LONG2NUM(CLIENT_LONG_PASSWORD));
736
+ INT2NUM(CLIENT_LONG_PASSWORD));
1310
737
  #endif
1311
738
 
1312
739
  #ifdef CLIENT_FOUND_ROWS
1313
740
  rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"),
1314
- LONG2NUM(CLIENT_FOUND_ROWS));
741
+ INT2NUM(CLIENT_FOUND_ROWS));
1315
742
  #endif
1316
743
 
1317
744
  #ifdef CLIENT_LONG_FLAG
1318
745
  rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"),
1319
- LONG2NUM(CLIENT_LONG_FLAG));
746
+ INT2NUM(CLIENT_LONG_FLAG));
1320
747
  #endif
1321
748
 
1322
749
  #ifdef CLIENT_CONNECT_WITH_DB
1323
750
  rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"),
1324
- LONG2NUM(CLIENT_CONNECT_WITH_DB));
751
+ INT2NUM(CLIENT_CONNECT_WITH_DB));
1325
752
  #endif
1326
753
 
1327
754
  #ifdef CLIENT_NO_SCHEMA
1328
755
  rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"),
1329
- LONG2NUM(CLIENT_NO_SCHEMA));
756
+ INT2NUM(CLIENT_NO_SCHEMA));
1330
757
  #endif
1331
758
 
1332
759
  #ifdef CLIENT_COMPRESS
1333
- rb_const_set(cMysql2Client, rb_intern("COMPRESS"), LONG2NUM(CLIENT_COMPRESS));
760
+ rb_const_set(cMysql2Client, rb_intern("COMPRESS"), INT2NUM(CLIENT_COMPRESS));
1334
761
  #endif
1335
762
 
1336
763
  #ifdef CLIENT_ODBC
1337
- rb_const_set(cMysql2Client, rb_intern("ODBC"), LONG2NUM(CLIENT_ODBC));
764
+ rb_const_set(cMysql2Client, rb_intern("ODBC"), INT2NUM(CLIENT_ODBC));
1338
765
  #endif
1339
766
 
1340
767
  #ifdef CLIENT_LOCAL_FILES
1341
768
  rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"),
1342
- LONG2NUM(CLIENT_LOCAL_FILES));
769
+ INT2NUM(CLIENT_LOCAL_FILES));
1343
770
  #endif
1344
771
 
1345
772
  #ifdef CLIENT_IGNORE_SPACE
1346
773
  rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"),
1347
- LONG2NUM(CLIENT_IGNORE_SPACE));
774
+ INT2NUM(CLIENT_IGNORE_SPACE));
1348
775
  #endif
1349
776
 
1350
777
  #ifdef CLIENT_PROTOCOL_41
1351
778
  rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"),
1352
- LONG2NUM(CLIENT_PROTOCOL_41));
779
+ INT2NUM(CLIENT_PROTOCOL_41));
1353
780
  #endif
1354
781
 
1355
782
  #ifdef CLIENT_INTERACTIVE
1356
783
  rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"),
1357
- LONG2NUM(CLIENT_INTERACTIVE));
784
+ INT2NUM(CLIENT_INTERACTIVE));
1358
785
  #endif
1359
786
 
1360
787
  #ifdef CLIENT_SSL
1361
- rb_const_set(cMysql2Client, rb_intern("SSL"), LONG2NUM(CLIENT_SSL));
788
+ rb_const_set(cMysql2Client, rb_intern("SSL"), INT2NUM(CLIENT_SSL));
1362
789
  #endif
1363
790
 
1364
791
  #ifdef CLIENT_IGNORE_SIGPIPE
1365
792
  rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"),
1366
- LONG2NUM(CLIENT_IGNORE_SIGPIPE));
793
+ INT2NUM(CLIENT_IGNORE_SIGPIPE));
1367
794
  #endif
1368
795
 
1369
796
  #ifdef CLIENT_TRANSACTIONS
1370
797
  rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"),
1371
- LONG2NUM(CLIENT_TRANSACTIONS));
798
+ INT2NUM(CLIENT_TRANSACTIONS));
1372
799
  #endif
1373
800
 
1374
801
  #ifdef CLIENT_RESERVED
1375
- rb_const_set(cMysql2Client, rb_intern("RESERVED"), LONG2NUM(CLIENT_RESERVED));
802
+ rb_const_set(cMysql2Client, rb_intern("RESERVED"), INT2NUM(CLIENT_RESERVED));
1376
803
  #endif
1377
804
 
1378
805
  #ifdef CLIENT_SECURE_CONNECTION
1379
806
  rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
1380
- LONG2NUM(CLIENT_SECURE_CONNECTION));
1381
- #else
1382
- /* HACK because MySQL5.7 no longer defines this constant,
1383
- * but we're using it in our default connection flags. */
1384
- rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
807
+ INT2NUM(CLIENT_SECURE_CONNECTION));
1385
808
  #endif
1386
809
 
1387
810
  #ifdef CLIENT_MULTI_STATEMENTS
1388
811
  rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
1389
- LONG2NUM(CLIENT_MULTI_STATEMENTS));
812
+ INT2NUM(CLIENT_MULTI_STATEMENTS));
1390
813
  #endif
1391
814
 
1392
815
  #ifdef CLIENT_PS_MULTI_RESULTS
1393
816
  rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"),
1394
- LONG2NUM(CLIENT_PS_MULTI_RESULTS));
817
+ INT2NUM(CLIENT_PS_MULTI_RESULTS));
1395
818
  #endif
1396
819
 
1397
820
  #ifdef CLIENT_SSL_VERIFY_SERVER_CERT
1398
821
  rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"),
1399
- LONG2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
822
+ INT2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
1400
823
  #endif
1401
824
 
1402
825
  #ifdef CLIENT_REMEMBER_OPTIONS
1403
826
  rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"),
1404
- LONG2NUM(CLIENT_REMEMBER_OPTIONS));
827
+ INT2NUM(CLIENT_REMEMBER_OPTIONS));
1405
828
  #endif
1406
829
 
1407
830
  #ifdef CLIENT_ALL_FLAGS
1408
831
  rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"),
1409
- LONG2NUM(CLIENT_ALL_FLAGS));
832
+ INT2NUM(CLIENT_ALL_FLAGS));
1410
833
  #endif
1411
834
 
1412
835
  #ifdef CLIENT_BASIC_FLAGS
1413
836
  rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
1414
- LONG2NUM(CLIENT_BASIC_FLAGS));
837
+ INT2NUM(CLIENT_BASIC_FLAGS));
1415
838
  #endif
1416
839
  }