mysql2 0.4.10 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,5 @@
1
1
  #ifndef MYSQL2_RESULT_H
2
2
  #define MYSQL2_RESULT_H
3
- #include <stdbool.h>
4
3
 
5
4
  void init_mysql2_result(void);
6
5
  VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r, VALUE statement);
@@ -22,8 +21,8 @@ typedef struct {
22
21
  mysql_client_wrapper *client_wrapper;
23
22
  /* statement result bind buffers */
24
23
  MYSQL_BIND *result_buffers;
25
- bool *is_null;
26
- bool *error;
24
+ my_bool *is_null;
25
+ my_bool *error;
27
26
  unsigned long *length;
28
27
  } mysql2_result_wrapper;
29
28
 
@@ -1,12 +1,9 @@
1
1
  #include <mysql2_ext.h>
2
2
 
3
- VALUE cMysql2Statement;
4
- extern VALUE mMysql2, cMysql2Error, cBigDecimal, cDateTime, cDate;
5
- static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s;
3
+ extern VALUE mMysql2, cMysql2Error;
4
+ static VALUE cMysql2Statement, cBigDecimal, cDateTime, cDate;
5
+ static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s, intern_merge_bang;
6
6
  static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year;
7
- #ifndef HAVE_RB_BIG_CMP
8
- static ID id_cmp;
9
- #endif
10
7
 
11
8
  #define GET_STATEMENT(self) \
12
9
  mysql_stmt_wrapper *stmt_wrapper; \
@@ -21,7 +18,7 @@ static void rb_mysql_stmt_mark(void * ptr) {
21
18
  rb_gc_mark(stmt_wrapper->client);
22
19
  }
23
20
 
24
- static void *nogvl_stmt_close(void * ptr) {
21
+ static void *nogvl_stmt_close(void *ptr) {
25
22
  mysql_stmt_wrapper *stmt_wrapper = ptr;
26
23
  if (stmt_wrapper->stmt) {
27
24
  mysql_stmt_close(stmt_wrapper->stmt);
@@ -30,7 +27,7 @@ static void *nogvl_stmt_close(void * ptr) {
30
27
  return NULL;
31
28
  }
32
29
 
33
- static void rb_mysql_stmt_free(void * ptr) {
30
+ static void rb_mysql_stmt_free(void *ptr) {
34
31
  mysql_stmt_wrapper *stmt_wrapper = ptr;
35
32
  decr_mysql2_stmt(stmt_wrapper);
36
33
  }
@@ -50,7 +47,6 @@ void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) {
50
47
  VALUE rb_error_msg = rb_str_new2(mysql_stmt_error(stmt_wrapper->stmt));
51
48
  VALUE rb_sql_state = rb_tainted_str_new2(mysql_stmt_sqlstate(stmt_wrapper->stmt));
52
49
 
53
- #ifdef HAVE_RUBY_ENCODING_H
54
50
  rb_encoding *conn_enc;
55
51
  conn_enc = rb_to_encoding(wrapper->encoding);
56
52
 
@@ -62,7 +58,6 @@ void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) {
62
58
  rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
63
59
  rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
64
60
  }
65
- #endif
66
61
 
67
62
  e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
68
63
  rb_error_msg,
@@ -96,9 +91,7 @@ static void *nogvl_prepare_statement(void *ptr) {
96
91
  VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
97
92
  mysql_stmt_wrapper *stmt_wrapper;
98
93
  VALUE rb_stmt;
99
- #ifdef HAVE_RUBY_ENCODING_H
100
94
  rb_encoding *conn_enc;
101
- #endif
102
95
 
103
96
  Check_Type(sql, T_STRING);
104
97
 
@@ -114,9 +107,7 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
114
107
  {
115
108
  GET_CLIENT(rb_client);
116
109
  stmt_wrapper->stmt = mysql_stmt_init(wrapper->client);
117
- #ifdef HAVE_RUBY_ENCODING_H
118
110
  conn_enc = rb_to_encoding(wrapper->encoding);
119
- #endif
120
111
  }
121
112
  if (stmt_wrapper->stmt == NULL) {
122
113
  rb_raise(cMysql2Error, "Unable to initialize prepared statement: out of memory");
@@ -124,7 +115,7 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
124
115
 
125
116
  // set STMT_ATTR_UPDATE_MAX_LENGTH attr
126
117
  {
127
- bool truth = 1;
118
+ my_bool truth = 1;
128
119
  if (mysql_stmt_attr_set(stmt_wrapper->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &truth)) {
129
120
  rb_raise(cMysql2Error, "Unable to initialize prepared statement: set STMT_ATTR_UPDATE_MAX_LENGTH");
130
121
  }
@@ -134,11 +125,8 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
134
125
  {
135
126
  struct nogvl_prepare_statement_args args;
136
127
  args.stmt = stmt_wrapper->stmt;
137
- args.sql = sql;
138
- #ifdef HAVE_RUBY_ENCODING_H
139
128
  // ensure the string is in the encoding the connection is expecting
140
- args.sql = rb_str_export_to_enc(args.sql, conn_enc);
141
- #endif
129
+ args.sql = rb_str_export_to_enc(sql, conn_enc);
142
130
  args.sql_ptr = RSTRING_PTR(sql);
143
131
  args.sql_len = RSTRING_LEN(sql);
144
132
 
@@ -154,7 +142,7 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
154
142
  *
155
143
  * Returns the number of parameters the prepared statement expects.
156
144
  */
157
- static VALUE param_count(VALUE self) {
145
+ static VALUE rb_mysql_stmt_param_count(VALUE self) {
158
146
  GET_STATEMENT(self);
159
147
 
160
148
  return ULL2NUM(mysql_stmt_param_count(stmt_wrapper->stmt));
@@ -164,13 +152,13 @@ static VALUE param_count(VALUE self) {
164
152
  *
165
153
  * Returns the number of fields the prepared statement returns.
166
154
  */
167
- static VALUE field_count(VALUE self) {
155
+ static VALUE rb_mysql_stmt_field_count(VALUE self) {
168
156
  GET_STATEMENT(self);
169
157
 
170
158
  return UINT2NUM(mysql_stmt_field_count(stmt_wrapper->stmt));
171
159
  }
172
160
 
173
- static void *nogvl_execute(void *ptr) {
161
+ static void *nogvl_stmt_execute(void *ptr) {
174
162
  MYSQL_STMT *stmt = ptr;
175
163
 
176
164
  if (mysql_stmt_execute(stmt)) {
@@ -196,7 +184,7 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
196
184
  * the buffer is a Ruby string pointer and not our memory to manage.
197
185
  */
198
186
  #define FREE_BINDS \
199
- for (i = 0; i < argc; i++) { \
187
+ for (i = 0; i < bind_count; i++) { \
200
188
  if (bind_buffers[i].buffer && NIL_P(params_enc[i])) { \
201
189
  xfree(bind_buffers[i].buffer); \
202
190
  } \
@@ -211,6 +199,8 @@ static int my_big2ll(VALUE bignum, LONG_LONG *ptr)
211
199
  {
212
200
  unsigned LONG_LONG num;
213
201
  size_t len;
202
+ // rb_absint_size was added in 2.1.0. See:
203
+ // https://github.com/ruby/ruby/commit/9fea875
214
204
  #ifdef HAVE_RB_ABSINT_SIZE
215
205
  int nlz_bits = 0;
216
206
  len = rb_absint_size(bignum, &nlz_bits);
@@ -229,16 +219,15 @@ static int my_big2ll(VALUE bignum, LONG_LONG *ptr)
229
219
  #ifdef HAVE_RB_ABSINT_SIZE
230
220
  nlz_bits == 0 &&
231
221
  #endif
222
+ // rb_absint_singlebit_p was added in 2.1.0. See:
223
+ // https://github.com/ruby/ruby/commit/e5ff9d5
232
224
  #if defined(HAVE_RB_ABSINT_SIZE) && defined(HAVE_RB_ABSINT_SINGLEBIT_P)
233
225
  /* Optimized to avoid object allocation for Ruby 2.1+
234
226
  * only -0x8000000000000000 is safe if `len == 8 && nlz_bits == 0`
235
227
  */
236
228
  !rb_absint_singlebit_p(bignum)
237
- #elif defined(HAVE_RB_BIG_CMP)
238
- rb_big_cmp(bignum, LL2NUM(LLONG_MIN)) == INT2FIX(-1)
239
229
  #else
240
- /* Ruby 1.8.7 and REE doesn't have rb_big_cmp */
241
- rb_funcall(bignum, id_cmp, 1, LL2NUM(LLONG_MIN)) == INT2FIX(-1)
230
+ rb_big_cmp(bignum, LL2NUM(LLONG_MIN)) == INT2FIX(-1)
242
231
  #endif
243
232
  ) {
244
233
  goto overflow;
@@ -254,44 +243,45 @@ overflow:
254
243
  *
255
244
  * Executes the current prepared statement, returns +result+.
256
245
  */
257
- static VALUE execute(int argc, VALUE *argv, VALUE self) {
246
+ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
258
247
  MYSQL_BIND *bind_buffers = NULL;
259
248
  unsigned long *length_buffers = NULL;
260
249
  unsigned long bind_count;
261
- long i;
250
+ unsigned long i;
262
251
  MYSQL_STMT *stmt;
263
252
  MYSQL_RES *metadata;
253
+ VALUE opts;
264
254
  VALUE current;
265
255
  VALUE resultObj;
266
- VALUE *params_enc;
256
+ VALUE *params_enc = NULL;
267
257
  int is_streaming;
268
- #ifdef HAVE_RUBY_ENCODING_H
269
258
  rb_encoding *conn_enc;
270
- #endif
271
259
 
272
260
  GET_STATEMENT(self);
273
261
  GET_CLIENT(stmt_wrapper->client);
274
262
 
275
- #ifdef HAVE_RUBY_ENCODING_H
276
263
  conn_enc = rb_to_encoding(wrapper->encoding);
277
- #endif
278
-
279
- /* Scratch space for string encoding exports, allocate on the stack. */
280
- params_enc = alloca(sizeof(VALUE) * argc);
281
264
 
282
265
  stmt = stmt_wrapper->stmt;
283
-
284
266
  bind_count = mysql_stmt_param_count(stmt);
285
- if (argc != (long)bind_count) {
286
- rb_raise(cMysql2Error, "Bind parameter count (%ld) doesn't match number of arguments (%d)", bind_count, argc);
267
+
268
+ // Get count of ordinary arguments, and extract hash opts/keyword arguments
269
+ // Use a local scope to avoid leaking the temporary count variable
270
+ {
271
+ int c = rb_scan_args(argc, argv, "*:", NULL, &opts);
272
+ if (c != (long)bind_count) {
273
+ rb_raise(cMysql2Error, "Bind parameter count (%ld) doesn't match number of arguments (%d)", bind_count, c);
274
+ }
287
275
  }
288
276
 
289
277
  // setup any bind variables in the query
290
278
  if (bind_count > 0) {
279
+ // Scratch space for string encoding exports, allocate on the stack
280
+ params_enc = alloca(sizeof(VALUE) * bind_count);
291
281
  bind_buffers = xcalloc(bind_count, sizeof(MYSQL_BIND));
292
282
  length_buffers = xcalloc(bind_count, sizeof(unsigned long));
293
283
 
294
- for (i = 0; i < argc; i++) {
284
+ for (i = 0; i < bind_count; i++) {
295
285
  bind_buffers[i].buffer = NULL;
296
286
  params_enc[i] = Qnil;
297
287
 
@@ -319,12 +309,8 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
319
309
  *(LONG_LONG*)(bind_buffers[i].buffer) = num;
320
310
  } else {
321
311
  /* The bignum was larger than we can fit in LONG_LONG, send it as a string */
322
- VALUE rb_val_as_string = rb_big2str(argv[i], 10);
323
312
  bind_buffers[i].buffer_type = MYSQL_TYPE_NEWDECIMAL;
324
- params_enc[i] = rb_val_as_string;
325
- #ifdef HAVE_RUBY_ENCODING_H
326
- params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
327
- #endif
313
+ params_enc[i] = rb_str_export_to_enc(rb_big2str(argv[i], 10), conn_enc);
328
314
  set_buffer_for_string(&bind_buffers[i], &length_buffers[i], params_enc[i]);
329
315
  }
330
316
  }
@@ -338,9 +324,7 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
338
324
  bind_buffers[i].buffer_type = MYSQL_TYPE_STRING;
339
325
 
340
326
  params_enc[i] = argv[i];
341
- #ifdef HAVE_RUBY_ENCODING_H
342
327
  params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
343
- #endif
344
328
  set_buffer_for_string(&bind_buffers[i], &length_buffers[i], params_enc[i]);
345
329
  break;
346
330
  case T_TRUE:
@@ -405,9 +389,7 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
405
389
  VALUE rb_val_as_string = rb_funcall(argv[i], intern_to_s, 0);
406
390
 
407
391
  params_enc[i] = rb_val_as_string;
408
- #ifdef HAVE_RUBY_ENCODING_H
409
392
  params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
410
- #endif
411
393
  set_buffer_for_string(&bind_buffers[i], &length_buffers[i], params_enc[i]);
412
394
  }
413
395
  break;
@@ -421,7 +403,7 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
421
403
  }
422
404
  }
423
405
 
424
- if ((VALUE)rb_thread_call_without_gvl(nogvl_execute, stmt, RUBY_UBF_IO, 0) == Qfalse) {
406
+ if ((VALUE)rb_thread_call_without_gvl(nogvl_stmt_execute, stmt, RUBY_UBF_IO, 0) == Qfalse) {
425
407
  FREE_BINDS;
426
408
  rb_raise_mysql2_stmt_error(stmt_wrapper);
427
409
  }
@@ -439,10 +421,16 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
439
421
  return Qnil;
440
422
  }
441
423
 
424
+ // Duplicate the options hash, merge! extra opts, put the copy into the Result object
442
425
  current = rb_hash_dup(rb_iv_get(stmt_wrapper->client, "@query_options"));
443
426
  (void)RB_GC_GUARD(current);
444
427
  Check_Type(current, T_HASH);
445
428
 
429
+ // Merge in hash opts/keyword arguments
430
+ if (!NIL_P(opts)) {
431
+ rb_funcall(current, intern_merge_bang, 1, opts);
432
+ }
433
+
446
434
  is_streaming = (Qtrue == rb_hash_aref(current, sym_stream));
447
435
  if (!is_streaming) {
448
436
  // recieve the whole result set from the server
@@ -455,6 +443,8 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
455
443
 
456
444
  resultObj = rb_mysql_result_to_obj(stmt_wrapper->client, wrapper->encoding, current, metadata, self);
457
445
 
446
+ rb_mysql_set_server_query_flags(wrapper->client, resultObj);
447
+
458
448
  if (!is_streaming) {
459
449
  // cache all result
460
450
  rb_funcall(resultObj, intern_each, 0);
@@ -467,27 +457,23 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
467
457
  *
468
458
  * Returns a list of fields that will be returned by this statement.
469
459
  */
470
- static VALUE fields(VALUE self) {
460
+ static VALUE rb_mysql_stmt_fields(VALUE self) {
471
461
  MYSQL_FIELD *fields;
472
462
  MYSQL_RES *metadata;
473
463
  unsigned int field_count;
474
464
  unsigned int i;
475
465
  VALUE field_list;
476
466
  MYSQL_STMT* stmt;
477
- #ifdef HAVE_RUBY_ENCODING_H
478
467
  rb_encoding *default_internal_enc, *conn_enc;
479
- #endif
480
468
  GET_STATEMENT(self);
481
469
  GET_CLIENT(stmt_wrapper->client);
482
470
  stmt = stmt_wrapper->stmt;
483
471
 
484
- #ifdef HAVE_RUBY_ENCODING_H
485
472
  default_internal_enc = rb_default_internal_encoding();
486
473
  {
487
474
  GET_CLIENT(stmt_wrapper->client);
488
475
  conn_enc = rb_to_encoding(wrapper->encoding);
489
476
  }
490
- #endif
491
477
 
492
478
  metadata = mysql_stmt_result_metadata(stmt);
493
479
  if (metadata == NULL) {
@@ -508,12 +494,10 @@ static VALUE fields(VALUE self) {
508
494
  VALUE rb_field;
509
495
 
510
496
  rb_field = rb_str_new(fields[i].name, fields[i].name_length);
511
- #ifdef HAVE_RUBY_ENCODING_H
512
497
  rb_enc_associate(rb_field, conn_enc);
513
498
  if (default_internal_enc) {
514
499
  rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
515
500
  }
516
- #endif
517
501
 
518
502
  rb_ary_store(field_list, (long)i, rb_field);
519
503
  }
@@ -564,12 +548,15 @@ static VALUE rb_mysql_stmt_close(VALUE self) {
564
548
  }
565
549
 
566
550
  void init_mysql2_statement() {
567
- cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
551
+ cDate = rb_const_get(rb_cObject, rb_intern("Date"));
552
+ cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
553
+ cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
568
554
 
569
- rb_define_method(cMysql2Statement, "param_count", param_count, 0);
570
- rb_define_method(cMysql2Statement, "field_count", field_count, 0);
571
- rb_define_method(cMysql2Statement, "_execute", execute, -1);
572
- rb_define_method(cMysql2Statement, "fields", fields, 0);
555
+ cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
556
+ rb_define_method(cMysql2Statement, "param_count", rb_mysql_stmt_param_count, 0);
557
+ rb_define_method(cMysql2Statement, "field_count", rb_mysql_stmt_field_count, 0);
558
+ rb_define_method(cMysql2Statement, "_execute", rb_mysql_stmt_execute, -1);
559
+ rb_define_method(cMysql2Statement, "fields", rb_mysql_stmt_fields, 0);
573
560
  rb_define_method(cMysql2Statement, "last_id", rb_mysql_stmt_last_id, 0);
574
561
  rb_define_method(cMysql2Statement, "affected_rows", rb_mysql_stmt_affected_rows, 0);
575
562
  rb_define_method(cMysql2Statement, "close", rb_mysql_stmt_close, 0);
@@ -589,7 +576,5 @@ void init_mysql2_statement() {
589
576
  intern_year = rb_intern("year");
590
577
 
591
578
  intern_to_s = rb_intern("to_s");
592
- #ifndef HAVE_RB_BIG_CMP
593
- id_cmp = rb_intern("<=>");
594
- #endif
579
+ intern_merge_bang = rb_intern("merge!");
595
580
  }
@@ -1,8 +1,6 @@
1
1
  #ifndef MYSQL2_STATEMENT_H
2
2
  #define MYSQL2_STATEMENT_H
3
3
 
4
- extern VALUE cMysql2Statement;
5
-
6
4
  typedef struct {
7
5
  VALUE client;
8
6
  MYSQL_STMT *stmt;
@@ -1,5 +1,6 @@
1
1
  /*
2
- * backwards compatibility for pre-1.9.3 C API
2
+ * backwards compatibility for Rubinius. See
3
+ * https://github.com/rubinius/rubinius/issues/3771.
3
4
  *
4
5
  * Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
5
6
  * to minimize select() and malloc() overhead on high-numbered FDs.
@@ -1,7 +1,5 @@
1
- # encoding: UTF-8
2
1
  require 'date'
3
2
  require 'bigdecimal'
4
- require 'rational' unless RUBY_VERSION >= '1.9.2'
5
3
 
6
4
  # Load libmysql.dll before requiring mysql2/mysql2.so
7
5
  # This gives a chance to be flexible about the load path
@@ -13,16 +11,20 @@ if RUBY_PLATFORM =~ /mswin|mingw/
13
11
  ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
14
12
  elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
15
13
  # Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
16
- File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).tr('/', '\\')
14
+ File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__))
15
+ elsif defined?(RubyInstaller)
16
+ # RubyInstaller-2.4+ native build doesn't need DLL preloading
17
17
  else
18
18
  # This will use default / system library paths
19
19
  'libmysql.dll'
20
20
  end
21
21
 
22
- require 'Win32API'
23
- LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
24
- if 0 == LoadLibrary.call(dll_path)
25
- abort "Failed to load libmysql.dll from #{dll_path}"
22
+ if dll_path
23
+ require 'Win32API'
24
+ LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
25
+ if LoadLibrary.call(dll_path).zero?
26
+ abort "Failed to load libmysql.dll from #{dll_path}"
27
+ end
26
28
  end
27
29
  end
28
30
 
@@ -71,14 +73,11 @@ module Mysql2
71
73
  # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
72
74
  # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
73
75
  #
74
- if Thread.respond_to?(:handle_interrupt)
75
- require 'timeout'
76
- # rubocop:disable Style/ConstantName
77
- TimeoutError = if defined?(::Timeout::ExitException)
78
- ::Timeout::ExitException
79
- else
80
- ::Timeout::Error
81
- end
76
+ require 'timeout'
77
+ TIMEOUT_ERROR_CLASS = if defined?(::Timeout::ExitException)
78
+ ::Timeout::ExitException
79
+ else
80
+ ::Timeout::Error
82
81
  end
83
82
  end
84
83
  end
@@ -4,22 +4,22 @@ module Mysql2
4
4
 
5
5
  def self.default_query_options
6
6
  @default_query_options ||= {
7
- :as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
8
- :async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
9
- :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby
10
- :symbolize_keys => false, # return field names as symbols instead of strings
11
- :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
12
- :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
13
- :cache_rows => true, # tells Mysql2 to use its internal row cache for results
14
- :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
15
- :cast => true,
16
- :default_file => nil,
17
- :default_group => nil,
7
+ as: :hash, # the type of object you want each row back as; also supports :array (an array of values)
8
+ async: false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
9
+ cast_booleans: false, # cast tinyint(1) fields as true/false in ruby
10
+ symbolize_keys: false, # return field names as symbols instead of strings
11
+ database_timezone: :local, # timezone Mysql2 will assume datetime objects are stored in
12
+ application_timezone: nil, # timezone Mysql2 will convert to before handing the object back to the caller
13
+ cache_rows: true, # tells Mysql2 to use its internal row cache for results
14
+ connect_flags: REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | CONNECT_ATTRS,
15
+ cast: true,
16
+ default_file: nil,
17
+ default_group: nil,
18
18
  }
19
19
  end
20
20
 
21
21
  def initialize(opts = {})
22
- fail Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
22
+ raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
23
23
  opts = Mysql2::Util.key_hash_as_symbols(opts)
24
24
  @read_timeout = nil
25
25
  @query_options = self.class.default_query_options.dup
@@ -31,7 +31,7 @@ module Mysql2
31
31
  opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
32
32
 
33
33
  # TODO: stricter validation rather than silent massaging
34
- [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command, :automatic_close, :enable_cleartext_plugin].each do |key|
34
+ %i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin].each do |key|
35
35
  next unless opts.key?(key)
36
36
  case key
37
37
  when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
@@ -50,21 +50,21 @@ module Mysql2
50
50
  ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
51
51
  self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
52
52
 
53
- case opts[:flags]
53
+ flags = case opts[:flags]
54
54
  when Array
55
- flags = parse_flags_array(opts[:flags], @query_options[:connect_flags])
55
+ parse_flags_array(opts[:flags], @query_options[:connect_flags])
56
56
  when String
57
- flags = parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
57
+ parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
58
58
  when Integer
59
- flags = @query_options[:connect_flags] | opts[:flags]
59
+ @query_options[:connect_flags] | opts[:flags]
60
60
  else
61
- flags = @query_options[:connect_flags]
61
+ @query_options[:connect_flags]
62
62
  end
63
63
 
64
64
  # SSL verify is a connection flag rather than a mysql_ssl_set option
65
65
  flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
66
66
 
67
- if [:user, :pass, :hostname, :dbname, :db, :sock].any? { |k| @query_options.key?(k) }
67
+ if %i[user pass hostname dbname db sock].any? { |k| @query_options.key?(k) }
68
68
  warn "============= WARNING FROM mysql2 ============="
69
69
  warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed at some point in the future."
70
70
  warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
@@ -85,8 +85,9 @@ module Mysql2
85
85
  port = port.to_i unless port.nil?
86
86
  database = database.to_s unless database.nil?
87
87
  socket = socket.to_s unless socket.nil?
88
+ conn_attrs = parse_connect_attrs(opts[:connect_attrs])
88
89
 
89
- connect user, pass, host, port, database, socket, flags
90
+ connect user, pass, host, port, database, socket, flags, conn_attrs
90
91
  end
91
92
 
92
93
  def parse_ssl_mode(mode)
@@ -114,14 +115,19 @@ module Mysql2
114
115
  end
115
116
  end
116
117
 
117
- if Thread.respond_to?(:handle_interrupt)
118
- def query(sql, options = {})
119
- Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
120
- _query(sql, @query_options.merge(options))
121
- end
118
+ # Set default program_name in performance_schema.session_connect_attrs
119
+ # and performance_schema.session_account_connect_attrs
120
+ def parse_connect_attrs(conn_attrs)
121
+ return {} if Mysql2::Client::CONNECT_ATTRS.zero?
122
+ conn_attrs ||= {}
123
+ conn_attrs[:program_name] ||= $PROGRAM_NAME
124
+ conn_attrs.each_with_object({}) do |(key, value), hash|
125
+ hash[key.to_s] = value.to_s
122
126
  end
123
- else
124
- def query(sql, options = {})
127
+ end
128
+
129
+ def query(sql, options = {})
130
+ Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_CLASS => :never) do
125
131
  _query(sql, @query_options.merge(options))
126
132
  end
127
133
  end