mysql2 0.5.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/mysql2/result.c CHANGED
@@ -1,6 +1,7 @@
1
1
  #include <mysql2_ext.h>
2
2
 
3
3
  #include "mysql_enc_to_ruby.h"
4
+ #define MYSQL2_CHARSETNR_SIZE (sizeof(mysql2_mysql_enc_to_rb)/sizeof(mysql2_mysql_enc_to_rb[0]))
4
5
 
5
6
  static rb_encoding *binaryEncoding;
6
7
 
@@ -29,14 +30,15 @@ typedef struct {
29
30
  int streaming;
30
31
  ID db_timezone;
31
32
  ID app_timezone;
32
- VALUE block_given;
33
+ int block_given; /* boolean */
33
34
  } result_each_args;
34
35
 
35
36
  extern VALUE mMysql2, cMysql2Client, cMysql2Error;
36
37
  static VALUE cMysql2Result, cDateTime, cDate;
37
38
  static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
38
39
  static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset,
39
- intern_civil, intern_new_offset, intern_merge, intern_BigDecimal;
40
+ intern_civil, intern_new_offset, intern_merge, intern_BigDecimal,
41
+ intern_query_options;
40
42
  static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
41
43
  sym_application_timezone, sym_local, sym_utc, sym_cast_booleans,
42
44
  sym_cache_rows, sym_cast, sym_stream, sym_name;
@@ -179,7 +181,8 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
179
181
  const char *enc_name;
180
182
  int enc_index;
181
183
 
182
- enc_name = mysql2_mysql_enc_to_rb[field.charsetnr-1];
184
+ enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
185
+
183
186
  if (enc_name != NULL) {
184
187
  /* use the field encoding we were able to match */
185
188
  enc_index = rb_enc_find_index(enc_name);
@@ -693,7 +696,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
693
696
 
694
697
  GET_RESULT(self);
695
698
 
696
- defaults = rb_iv_get(self, "@query_options");
699
+ defaults = rb_ivar_get(self, intern_query_options);
697
700
  Check_Type(defaults, T_HASH);
698
701
  if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
699
702
  symbolizeKeys = 1;
@@ -738,7 +741,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
738
741
  row = fetch_row_func(self, fields, args);
739
742
  if (row != Qnil) {
740
743
  wrapper->numberOfRows++;
741
- if (args->block_given != Qnil) {
744
+ if (args->block_given) {
742
745
  rb_yield(row);
743
746
  }
744
747
  }
@@ -788,7 +791,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
788
791
  return Qnil;
789
792
  }
790
793
 
791
- if (args->block_given != Qnil) {
794
+ if (args->block_given) {
792
795
  rb_yield(row);
793
796
  }
794
797
  }
@@ -806,7 +809,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
806
809
 
807
810
  static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
808
811
  result_each_args args;
809
- VALUE defaults, opts, block, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
812
+ VALUE defaults, opts, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
810
813
  ID db_timezone, app_timezone, dbTz, appTz;
811
814
  int symbolizeKeys, asArray, castBool, cacheRows, cast;
812
815
 
@@ -816,9 +819,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
816
819
  rb_raise(cMysql2Error, "Statement handle already closed");
817
820
  }
818
821
 
819
- defaults = rb_iv_get(self, "@query_options");
822
+ defaults = rb_ivar_get(self, intern_query_options);
820
823
  Check_Type(defaults, T_HASH);
821
- if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
824
+
825
+ // A block can be passed to this method, but since we don't call the block directly from C,
826
+ // we don't need to capture it into a variable here with the "&" scan arg.
827
+ if (rb_scan_args(argc, argv, "01", &opts) == 1) {
822
828
  opts = rb_funcall(defaults, intern_merge, 1, opts);
823
829
  } else {
824
830
  opts = defaults;
@@ -884,7 +890,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
884
890
  args.cast = cast;
885
891
  args.db_timezone = db_timezone;
886
892
  args.app_timezone = app_timezone;
887
- args.block_given = block;
893
+ args.block_given = rb_block_given_p();
888
894
 
889
895
  if (wrapper->stmt_wrapper) {
890
896
  fetch_row_func = rb_mysql_result_fetch_row_stmt;
@@ -949,7 +955,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
949
955
  }
950
956
 
951
957
  rb_obj_call_init(obj, 0, NULL);
952
- rb_iv_set(obj, "@query_options", options);
958
+ rb_ivar_set(obj, intern_query_options, options);
953
959
 
954
960
  /* Options that cannot be changed in results.each(...) { |row| }
955
961
  * should be processed here. */
@@ -978,6 +984,7 @@ void init_mysql2_result() {
978
984
  intern_civil = rb_intern("civil");
979
985
  intern_new_offset = rb_intern("new_offset");
980
986
  intern_BigDecimal = rb_intern("BigDecimal");
987
+ intern_query_options = rb_intern("@query_options");
981
988
 
982
989
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
983
990
  sym_as = ID2SYM(rb_intern("as"));
@@ -3,7 +3,8 @@
3
3
  extern VALUE mMysql2, cMysql2Error;
4
4
  static VALUE cMysql2Statement, cBigDecimal, cDateTime, cDate;
5
5
  static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s, intern_merge_bang;
6
- static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year;
6
+ static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year,
7
+ intern_query_options;
7
8
 
8
9
  #define GET_STATEMENT(self) \
9
10
  mysql_stmt_wrapper *stmt_wrapper; \
@@ -403,6 +404,39 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
403
404
  }
404
405
  }
405
406
 
407
+ // Duplicate the options hash, merge! extra opts, put the copy into the Result object
408
+ current = rb_hash_dup(rb_ivar_get(stmt_wrapper->client, intern_query_options));
409
+ (void)RB_GC_GUARD(current);
410
+ Check_Type(current, T_HASH);
411
+
412
+ // Merge in hash opts/keyword arguments
413
+ if (!NIL_P(opts)) {
414
+ rb_funcall(current, intern_merge_bang, 1, opts);
415
+ }
416
+
417
+ is_streaming = (Qtrue == rb_hash_aref(current, sym_stream));
418
+
419
+ // From stmt_execute to mysql_stmt_result_metadata to stmt_store_result, no
420
+ // Ruby API calls are allowed so that GC is not invoked. If the connection is
421
+ // in results-streaming-mode for Statement A, and in the middle Statement B
422
+ // gets garbage collected, a message will be sent to the server notifying it
423
+ // to release Statement B, resulting in the following error:
424
+ // Commands out of sync; you can't run this command now
425
+ //
426
+ // In streaming mode, statement execute must return a cursor because we
427
+ // cannot prevent other Statement objects from being garbage collected
428
+ // between fetches of each row of the result set. The following error
429
+ // occurs if cursor mode is not set:
430
+ // Row retrieval was canceled by mysql_stmt_close
431
+
432
+ if (is_streaming) {
433
+ unsigned long type = CURSOR_TYPE_READ_ONLY;
434
+ if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &type)) {
435
+ FREE_BINDS;
436
+ rb_raise(cMysql2Error, "Unable to stream prepared statement, could not set CURSOR_TYPE_READ_ONLY");
437
+ }
438
+ }
439
+
406
440
  if ((VALUE)rb_thread_call_without_gvl(nogvl_stmt_execute, stmt, RUBY_UBF_IO, 0) == Qfalse) {
407
441
  FREE_BINDS;
408
442
  rb_raise_mysql2_stmt_error(stmt_wrapper);
@@ -421,17 +455,6 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
421
455
  return Qnil;
422
456
  }
423
457
 
424
- // Duplicate the options hash, merge! extra opts, put the copy into the Result object
425
- current = rb_hash_dup(rb_iv_get(stmt_wrapper->client, "@query_options"));
426
- (void)RB_GC_GUARD(current);
427
- Check_Type(current, T_HASH);
428
-
429
- // Merge in hash opts/keyword arguments
430
- if (!NIL_P(opts)) {
431
- rb_funcall(current, intern_merge_bang, 1, opts);
432
- }
433
-
434
- is_streaming = (Qtrue == rb_hash_aref(current, sym_stream));
435
458
  if (!is_streaming) {
436
459
  // recieve the whole result set from the server
437
460
  if (mysql_stmt_store_result(stmt)) {
@@ -577,4 +600,5 @@ void init_mysql2_statement() {
577
600
 
578
601
  intern_to_s = rb_intern("to_s");
579
602
  intern_merge_bang = rb_intern("merge!");
603
+ intern_query_options = rb_intern("@query_options");
580
604
  }
data/lib/mysql2/client.rb CHANGED
@@ -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
- %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|
34
+ %i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin default_auth].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
data/lib/mysql2/error.rb CHANGED
@@ -52,7 +52,7 @@ module Mysql2
52
52
  def initialize(msg, server_version = nil, error_number = nil, sql_state = nil)
53
53
  @server_version = server_version
54
54
  @error_number = error_number
55
- @sql_state = sql_state ? sql_state.encode(ENCODE_OPTS) : nil
55
+ @sql_state = sql_state ? sql_state.encode(**ENCODE_OPTS) : nil
56
56
 
57
57
  super(clean_message(msg))
58
58
  end
@@ -91,9 +91,9 @@ module Mysql2
91
91
  # Returns a valid UTF-8 string.
92
92
  def clean_message(message)
93
93
  if @server_version && @server_version > 50500
94
- message.encode(ENCODE_OPTS)
94
+ message.encode(**ENCODE_OPTS)
95
95
  else
96
- message.encode(Encoding::UTF_8, ENCODE_OPTS)
96
+ message.encode(Encoding::UTF_8, **ENCODE_OPTS)
97
97
  end
98
98
  end
99
99
  end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.5.0".freeze
2
+ VERSION = "0.5.3".freeze
3
3
  end
data/lib/mysql2.rb CHANGED
@@ -20,9 +20,12 @@ if RUBY_PLATFORM =~ /mswin|mingw/
20
20
  end
21
21
 
22
22
  if dll_path
23
- require 'Win32API'
24
- LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
25
- if LoadLibrary.call(dll_path).zero?
23
+ require 'fiddle'
24
+ kernel32 = Fiddle.dlopen 'kernel32'
25
+ load_library = Fiddle::Function.new(
26
+ kernel32['LoadLibraryW'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT,
27
+ )
28
+ if load_library.call(dll_path.encode('utf-16le')).zero?
26
29
  abort "Failed to load libmysql.dll from #{dll_path}"
27
30
  end
28
31
  end
data/support/5072E1F5.asc CHANGED
@@ -1,5 +1,5 @@
1
1
  -----BEGIN PGP PUBLIC KEY BLOCK-----
2
- Version: GnuPG v1.4.5 (GNU/Linux)
2
+ Version: GnuPG v1
3
3
 
4
4
  mQGiBD4+owwRBAC14GIfUfCyEDSIePvEW3SAFUdJBtoQHH/nJKZyQT7h9bPlUWC3
5
5
  RODjQReyCITRrdwyrKUGku2FmeVGwn2u2WmDMNABLnpprWPkBdCk96+OmSLN9brZ
@@ -11,9 +11,9 @@ kYpXBACmWpP8NJTkamEnPCia2ZoOHODANwpUkP43I7jsDmgtobZX9qnrAXw+uNDI
11
11
  QJEXM6FSbi0LLtZciNlYsafwAPEOMDKpMqAK6IyisNtPvaLd8lH0bPAnWqcyefep
12
12
  rv0sxxqUEMcM3o7wwgfN83POkDasDbs3pjwPhxvhz6//62zQJ7Q2TXlTUUwgUmVs
13
13
  ZWFzZSBFbmdpbmVlcmluZyA8bXlzcWwtYnVpbGRAb3NzLm9yYWNsZS5jb20+iGwE
14
- ExECACwCGyMCHgECF4ACGQEGCwkIBwMCBhUKCQgCAwUWAgMBAAUCWKcFIAUJHirJ
15
- FAAKCRCMcY07UHLh9VcFAJ46pUyVd8BZ2r5CppMC1tmyQ3ceRgCfVPwuVsiS0VER
16
- 5WUqtAQDt+DoetCIaQQTEQIAKQIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkB
14
+ ExECACwCGyMCHgECF4ACGQEGCwkIBwMCBhUKCQgCAwUWAgMBAAUCXEBY+wUJI87e
15
+ 5AAKCRCMcY07UHLh9RZPAJ9uvm0zlzfCN+DHxHVaoFLFjdVYTQCfborsC9tmEZYa
16
+ whhogjeBkZkorbyIaQQTEQIAKQIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkB
17
17
  BQJTAdRmBQkaZsvLAAoJEIxxjTtQcuH1X4MAoKNLWAbCBUj96637kv6Xa/fJuX5m
18
18
  AJwPtmgDfjUe2iuhXdTrFEPT19SB6ohmBBMRAgAmAhsjBgsJCAcDAgQVAggDBBYC
19
19
  AwECHgECF4AFAk53PioFCRP7AhUACgkQjHGNO1By4fUmzACeJdfqgc9gWTUhgmcM
@@ -428,5 +428,5 @@ GoaU9u41oyZTIiXPiFidJoIZCh7fdurP8pn3X+R5HUNXMr7M+ba8lSNxce/F3kmH
428
428
  0L7rsKqdh9d/aVxhJINJ+inVDnrXWVoXu9GBjT8Nco1iU9SIVAQYEQIADAUCTnc9
429
429
  7QUJE/sBuAASB2VHUEcAAQEJEIxxjTtQcuH1FJsAmwWK9vmwRJ/y9gTnJ8PWf0BV
430
430
  roUTAKClYAhZuX2nUNwH4vlEJQHDqYa5yQ==
431
- =HfUN
431
+ =ghXk
432
432
  -----END PGP PUBLIC KEY BLOCK-----
@@ -43,6 +43,8 @@ mysql_to_rb = {
43
43
  "geostd8" => "NULL",
44
44
  "cp932" => "Windows-31J",
45
45
  "eucjpms" => "eucJP-ms",
46
+ "utf16le" => "UTF-16LE",
47
+ "gb18030" => "GB18030",
46
48
  }
47
49
 
48
50
  client = Mysql2::Client.new(username: user, password: pass, host: host, port: port.to_i)
@@ -52,7 +54,10 @@ encodings_with_nil = Array.new(encodings.size)
52
54
 
53
55
  collations.each do |collation|
54
56
  mysql_col_idx = collation[2].to_i
55
- rb_enc = mysql_to_rb[collation[1]]
57
+ rb_enc = mysql_to_rb.fetch(collation[1]) do |mysql_enc|
58
+ $stderr.puts "WARNING: Missing mapping for collation \"#{collation[0]}\" with encoding \"#{mysql_enc}\" and id #{mysql_col_idx}, assuming NULL"
59
+ "NULL"
60
+ end
56
61
  encodings[mysql_col_idx - 1] = [mysql_col_idx, rb_enc]
57
62
  end
58
63
 
@@ -38,6 +38,8 @@ mysql_to_rb = {
38
38
  "geostd8" => nil,
39
39
  "cp932" => "Windows-31J",
40
40
  "eucjpms" => "eucJP-ms",
41
+ "utf16le" => "UTF-16LE",
42
+ "gb18030" => "GB18030",
41
43
  }
42
44
 
43
45
  puts <<-HEADER
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Lopez
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-03-20 00:00:00.000000000 Z
12
+ date: 2019-11-27 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email:
@@ -23,8 +23,6 @@ files:
23
23
  - CHANGELOG.md
24
24
  - LICENSE
25
25
  - README.md
26
- - examples/eventmachine.rb
27
- - examples/threaded.rb
28
26
  - ext/mysql2/client.c
29
27
  - ext/mysql2/client.h
30
28
  - ext/mysql2/extconf.rb
@@ -48,29 +46,6 @@ files:
48
46
  - lib/mysql2/result.rb
49
47
  - lib/mysql2/statement.rb
50
48
  - lib/mysql2/version.rb
51
- - spec/configuration.yml.example
52
- - spec/em/em_spec.rb
53
- - spec/my.cnf.example
54
- - spec/mysql2/client_spec.rb
55
- - spec/mysql2/error_spec.rb
56
- - spec/mysql2/result_spec.rb
57
- - spec/mysql2/statement_spec.rb
58
- - spec/rcov.opts
59
- - spec/spec_helper.rb
60
- - spec/ssl/ca-cert.pem
61
- - spec/ssl/ca-key.pem
62
- - spec/ssl/ca.cnf
63
- - spec/ssl/cert.cnf
64
- - spec/ssl/client-cert.pem
65
- - spec/ssl/client-key.pem
66
- - spec/ssl/client-req.pem
67
- - spec/ssl/gen_certs.sh
68
- - spec/ssl/pkcs8-client-key.pem
69
- - spec/ssl/pkcs8-server-key.pem
70
- - spec/ssl/server-cert.pem
71
- - spec/ssl/server-key.pem
72
- - spec/ssl/server-req.pem
73
- - spec/test_data
74
49
  - support/5072E1F5.asc
75
50
  - support/libmysql.def
76
51
  - support/mysql_enc_to_ruby.rb
@@ -96,34 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
71
  - !ruby/object:Gem::Version
97
72
  version: '0'
98
73
  requirements: []
99
- rubyforge_project:
100
- rubygems_version: 2.5.2
74
+ rubygems_version: 3.0.3
101
75
  signing_key:
102
76
  specification_version: 4
103
77
  summary: A simple, fast Mysql library for Ruby, binding to libmysql
104
- test_files:
105
- - examples/eventmachine.rb
106
- - examples/threaded.rb
107
- - spec/configuration.yml.example
108
- - spec/em/em_spec.rb
109
- - spec/my.cnf.example
110
- - spec/mysql2/client_spec.rb
111
- - spec/mysql2/error_spec.rb
112
- - spec/mysql2/result_spec.rb
113
- - spec/mysql2/statement_spec.rb
114
- - spec/rcov.opts
115
- - spec/spec_helper.rb
116
- - spec/ssl/ca-cert.pem
117
- - spec/ssl/ca-key.pem
118
- - spec/ssl/ca.cnf
119
- - spec/ssl/cert.cnf
120
- - spec/ssl/client-cert.pem
121
- - spec/ssl/client-key.pem
122
- - spec/ssl/client-req.pem
123
- - spec/ssl/gen_certs.sh
124
- - spec/ssl/pkcs8-client-key.pem
125
- - spec/ssl/pkcs8-server-key.pem
126
- - spec/ssl/server-cert.pem
127
- - spec/ssl/server-key.pem
128
- - spec/ssl/server-req.pem
129
- - spec/test_data
78
+ test_files: []
@@ -1,19 +0,0 @@
1
- $LOAD_PATH.unshift 'lib'
2
-
3
- require 'rubygems'
4
- require 'eventmachine'
5
- require 'mysql2/em'
6
-
7
- EM.run do
8
- client1 = Mysql2::EM::Client.new
9
- defer1 = client1.query "SELECT sleep(3) as first_query"
10
- defer1.callback do |result|
11
- puts "Result: #{result.to_a.inspect}"
12
- end
13
-
14
- client2 = Mysql2::EM::Client.new
15
- defer2 = client2.query "SELECT sleep(1) second_query"
16
- defer2.callback do |result|
17
- puts "Result: #{result.to_a.inspect}"
18
- end
19
- end
data/examples/threaded.rb DELETED
@@ -1,16 +0,0 @@
1
- $LOAD_PATH.unshift 'lib'
2
- require 'mysql2'
3
- require 'timeout'
4
-
5
- # Should never exceed worst case 3.5 secs across all 20 threads
6
- Timeout.timeout(3.5) do
7
- Array.new(20) do
8
- Thread.new do
9
- overhead = rand(3)
10
- puts ">> thread #{Thread.current.object_id} query, #{overhead} sec overhead"
11
- # 3 second overhead per query
12
- Mysql2::Client.new(host: "localhost", username: "root").query("SELECT sleep(#{overhead}) as result")
13
- puts "<< thread #{Thread.current.object_id} result, #{overhead} sec overhead"
14
- end
15
- end.each(&:join)
16
- end
@@ -1,11 +0,0 @@
1
- root:
2
- host: localhost
3
- username: root
4
- password:
5
- database: test
6
-
7
- user:
8
- host: localhost
9
- username: LOCALUSERNAME
10
- password:
11
- database: mysql2_test
data/spec/em/em_spec.rb DELETED
@@ -1,135 +0,0 @@
1
- require 'spec_helper'
2
- begin
3
- require 'eventmachine'
4
- require 'mysql2/em'
5
-
6
- RSpec.describe Mysql2::EM::Client do
7
- it "should support async queries" do
8
- results = []
9
- EM.run do
10
- client1 = Mysql2::EM::Client.new DatabaseCredentials['root']
11
- defer1 = client1.query "SELECT sleep(0.1) as first_query"
12
- defer1.callback do |result|
13
- results << result.first
14
- client1.close
15
- EM.stop_event_loop
16
- end
17
-
18
- client2 = Mysql2::EM::Client.new DatabaseCredentials['root']
19
- defer2 = client2.query "SELECT sleep(0.025) second_query"
20
- defer2.callback do |result|
21
- results << result.first
22
- client2.close
23
- end
24
- end
25
-
26
- expect(results[0].keys).to include("second_query")
27
- expect(results[1].keys).to include("first_query")
28
- end
29
-
30
- it "should support queries in callbacks" do
31
- results = []
32
- EM.run do
33
- client = Mysql2::EM::Client.new DatabaseCredentials['root']
34
- defer1 = client.query "SELECT sleep(0.025) as first_query"
35
- defer1.callback do |result|
36
- results << result.first
37
- defer2 = client.query "SELECT sleep(0.025) as second_query"
38
- defer2.callback do |r|
39
- results << r.first
40
- client.close
41
- EM.stop_event_loop
42
- end
43
- end
44
- end
45
-
46
- expect(results[0].keys).to include("first_query")
47
- expect(results[1].keys).to include("second_query")
48
- end
49
-
50
- it "should not swallow exceptions raised in callbacks" do
51
- expect do
52
- EM.run do
53
- client = Mysql2::EM::Client.new DatabaseCredentials['root']
54
- defer = client.query "SELECT sleep(0.1) as first_query"
55
- defer.callback do
56
- client.close
57
- raise 'some error'
58
- end
59
- defer.errback do
60
- # This _shouldn't_ be run, but it needed to prevent the specs from
61
- # freezing if this test fails.
62
- EM.stop_event_loop
63
- end
64
- end
65
- end.to raise_error('some error')
66
- end
67
-
68
- context 'when an exception is raised by the client' do
69
- let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
70
- let(:error) { StandardError.new('some error') }
71
- before { allow(client).to receive(:async_result).and_raise(error) }
72
- after { client.close }
73
-
74
- it "should swallow exceptions raised in by the client" do
75
- errors = []
76
- EM.run do
77
- defer = client.query "SELECT sleep(0.1) as first_query"
78
- defer.callback do
79
- # This _shouldn't_ be run, but it is needed to prevent the specs from
80
- # freezing if this test fails.
81
- EM.stop_event_loop
82
- end
83
- defer.errback do |err|
84
- errors << err
85
- EM.stop_event_loop
86
- end
87
- end
88
- expect(errors).to eq([error])
89
- end
90
-
91
- it "should fail the deferrable" do
92
- callbacks_run = []
93
- EM.run do
94
- defer = client.query "SELECT sleep(0.025) as first_query"
95
- EM.add_timer(0.1) do
96
- defer.callback do
97
- callbacks_run << :callback
98
- # This _shouldn't_ be run, but it is needed to prevent the specs from
99
- # freezing if this test fails.
100
- EM.stop_event_loop
101
- end
102
- defer.errback do
103
- callbacks_run << :errback
104
- EM.stop_event_loop
105
- end
106
- end
107
- end
108
- expect(callbacks_run).to eq([:errback])
109
- end
110
- end
111
-
112
- it "should not raise error when closing client with no query running" do
113
- callbacks_run = []
114
- EM.run do
115
- client = Mysql2::EM::Client.new DatabaseCredentials['root']
116
- defer = client.query("select sleep(0.025)")
117
- defer.callback do
118
- callbacks_run << :callback
119
- end
120
- defer.errback do
121
- callbacks_run << :errback
122
- end
123
- EM.add_timer(0.1) do
124
- expect(callbacks_run).to eq([:callback])
125
- expect do
126
- client.close
127
- end.not_to raise_error
128
- EM.stop_event_loop
129
- end
130
- end
131
- end
132
- end
133
- rescue LoadError
134
- puts "EventMachine not installed, skipping the specs that use it"
135
- end
data/spec/my.cnf.example DELETED
@@ -1,9 +0,0 @@
1
- [root]
2
- host=localhost
3
- user=LOCALUSERNAME
4
- password=
5
-
6
- [client]
7
- host=localhost
8
- user=LOCALUSERNAME
9
- password=