mysql2 0.2.24 → 0.5.4

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 (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +237 -85
  5. data/ext/mysql2/client.c +582 -249
  6. data/ext/mysql2/client.h +10 -38
  7. data/ext/mysql2/extconf.rb +217 -66
  8. data/ext/mysql2/infile.c +2 -2
  9. data/ext/mysql2/mysql2_ext.c +9 -2
  10. data/ext/mysql2/mysql2_ext.h +13 -14
  11. data/ext/mysql2/mysql_enc_name_to_ruby.h +62 -58
  12. data/ext/mysql2/mysql_enc_to_ruby.h +82 -18
  13. data/ext/mysql2/result.c +736 -200
  14. data/ext/mysql2/result.h +13 -6
  15. data/ext/mysql2/statement.c +612 -0
  16. data/ext/mysql2/statement.h +17 -0
  17. data/ext/mysql2/wait_for_single_fd.h +2 -1
  18. data/lib/mysql2/client.rb +110 -28
  19. data/lib/mysql2/console.rb +1 -1
  20. data/lib/mysql2/em.rb +15 -9
  21. data/lib/mysql2/error.rb +57 -36
  22. data/lib/mysql2/field.rb +3 -0
  23. data/lib/mysql2/result.rb +2 -0
  24. data/lib/mysql2/statement.rb +9 -0
  25. data/lib/mysql2/version.rb +1 -1
  26. data/lib/mysql2.rb +66 -15
  27. data/support/3A79BD29.asc +49 -0
  28. data/support/5072E1F5.asc +432 -0
  29. data/support/libmysql.def +219 -0
  30. data/support/mysql_enc_to_ruby.rb +15 -11
  31. data/support/ruby_enc_to_mysql.rb +8 -6
  32. metadata +30 -94
  33. data/MIT-LICENSE +0 -20
  34. data/examples/eventmachine.rb +0 -21
  35. data/examples/threaded.rb +0 -20
  36. data/lib/active_record/connection_adapters/mysql2_adapter.rb +0 -635
  37. data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +0 -11
  38. data/spec/configuration.yml.example +0 -17
  39. data/spec/em/em_spec.rb +0 -114
  40. data/spec/my.cnf.example +0 -9
  41. data/spec/mysql2/client_spec.rb +0 -897
  42. data/spec/mysql2/error_spec.rb +0 -83
  43. data/spec/mysql2/result_spec.rb +0 -505
  44. data/spec/rcov.opts +0 -3
  45. data/spec/spec_helper.rb +0 -87
  46. data/spec/test_data +0 -1
data/lib/mysql2/client.rb CHANGED
@@ -1,24 +1,28 @@
1
1
  module Mysql2
2
2
  class Client
3
3
  attr_reader :query_options, :read_timeout
4
- @@default_query_options = {
5
- :as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
6
- :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
7
- :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby
8
- :symbolize_keys => false, # return field names as symbols instead of strings
9
- :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
10
- :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
11
- :cache_rows => true, # tells Mysql2 to use it's internal row cache for results
12
- :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
13
- :cast => true,
14
- :default_file => nil,
15
- :default_group => nil
16
- }
4
+
5
+ def self.default_query_options
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 | CONNECT_ATTRS,
15
+ cast: true,
16
+ default_file: nil,
17
+ default_group: nil,
18
+ }
19
+ end
17
20
 
18
21
  def initialize(opts = {})
19
- opts = Mysql2::Util.key_hash_as_symbols( opts )
22
+ raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
23
+ opts = Mysql2::Util.key_hash_as_symbols(opts)
20
24
  @read_timeout = nil
21
- @query_options = @@default_query_options.dup
25
+ @query_options = self.class.default_query_options.dup
22
26
  @query_options.merge! opts
23
27
 
24
28
  initialize_ext
@@ -26,13 +30,14 @@ module Mysql2
26
30
  # Set default connect_timeout to avoid unlimited retries from signal interruption
27
31
  opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
28
32
 
29
- [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command].each do |key|
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 default_auth].each do |key|
30
35
  next unless opts.key?(key)
31
36
  case key
32
- when :reconnect, :local_infile, :secure_auth
33
- send(:"#{key}=", !!opts[key])
37
+ when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
38
+ send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
34
39
  when :connect_timeout, :read_timeout, :write_timeout
35
- send(:"#{key}=", opts[key].to_i)
40
+ send(:"#{key}=", Integer(opts[key])) unless opts[key].nil?
36
41
  else
37
42
  send(:"#{key}=", opts[key])
38
43
  end
@@ -41,12 +46,32 @@ module Mysql2
41
46
  # force the encoding to utf8
42
47
  self.charset_name = opts[:encoding] || 'utf8'
43
48
 
49
+ mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
50
+ if (mode == SSL_MODE_VERIFY_CA || mode == SSL_MODE_VERIFY_IDENTITY) && !opts[:sslca]
51
+ opts[:sslca] = find_default_ca_path
52
+ end
53
+
44
54
  ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
45
- ssl_set(*ssl_options) if ssl_options.any?
55
+ ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
56
+ self.ssl_mode = mode if mode
57
+
58
+ flags = case opts[:flags]
59
+ when Array
60
+ parse_flags_array(opts[:flags], @query_options[:connect_flags])
61
+ when String
62
+ parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
63
+ when Integer
64
+ @query_options[:connect_flags] | opts[:flags]
65
+ else
66
+ @query_options[:connect_flags]
67
+ end
46
68
 
47
- if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) }
69
+ # SSL verify is a connection flag rather than a mysql_ssl_set option
70
+ flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
71
+
72
+ if %i[user pass hostname dbname db sock].any? { |k| @query_options.key?(k) }
48
73
  warn "============= WARNING FROM mysql2 ============="
49
- warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
74
+ warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed at some point in the future."
50
75
  warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
51
76
  warn "============= END WARNING FROM mysql2 ========="
52
77
  end
@@ -57,7 +82,6 @@ module Mysql2
57
82
  port = opts[:port]
58
83
  database = opts[:database] || opts[:dbname] || opts[:db]
59
84
  socket = opts[:socket] || opts[:sock]
60
- flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
61
85
 
62
86
  # Correct the data types before passing these values down to the C level
63
87
  user = user.to_s unless user.nil?
@@ -66,12 +90,63 @@ module Mysql2
66
90
  port = port.to_i unless port.nil?
67
91
  database = database.to_s unless database.nil?
68
92
  socket = socket.to_s unless socket.nil?
93
+ conn_attrs = parse_connect_attrs(opts[:connect_attrs])
69
94
 
70
- connect user, pass, host, port, database, socket, flags
95
+ connect user, pass, host, port, database, socket, flags, conn_attrs
71
96
  end
72
97
 
73
- def self.default_query_options
74
- @@default_query_options
98
+ def parse_ssl_mode(mode)
99
+ m = mode.to_s.upcase
100
+ if m.start_with?('SSL_MODE_')
101
+ return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m)
102
+ else
103
+ x = 'SSL_MODE_' + m
104
+ return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x)
105
+ end
106
+ warn "Unknown MySQL ssl_mode flag: #{mode}"
107
+ end
108
+
109
+ def parse_flags_array(flags, initial = 0)
110
+ flags.reduce(initial) do |memo, f|
111
+ fneg = f.start_with?('-') ? f[1..-1] : nil
112
+ if fneg && fneg =~ /^\w+$/ && Mysql2::Client.const_defined?(fneg)
113
+ memo & ~ Mysql2::Client.const_get(fneg)
114
+ elsif f && f =~ /^\w+$/ && Mysql2::Client.const_defined?(f)
115
+ memo | Mysql2::Client.const_get(f)
116
+ else
117
+ warn "Unknown MySQL connection flag: '#{f}'"
118
+ memo
119
+ end
120
+ end
121
+ end
122
+
123
+ # Find any default system CA paths to handle system roots
124
+ # by default if stricter validation is requested and no
125
+ # path is provide.
126
+ def find_default_ca_path
127
+ [
128
+ "/etc/ssl/certs/ca-certificates.crt",
129
+ "/etc/pki/tls/certs/ca-bundle.crt",
130
+ "/etc/ssl/ca-bundle.pem",
131
+ "/etc/ssl/cert.pem",
132
+ ].find { |f| File.exist?(f) }
133
+ end
134
+
135
+ # Set default program_name in performance_schema.session_connect_attrs
136
+ # and performance_schema.session_account_connect_attrs
137
+ def parse_connect_attrs(conn_attrs)
138
+ return {} if Mysql2::Client::CONNECT_ATTRS.zero?
139
+ conn_attrs ||= {}
140
+ conn_attrs[:program_name] ||= $PROGRAM_NAME
141
+ conn_attrs.each_with_object({}) do |(key, value), hash|
142
+ hash[key.to_s] = value.to_s
143
+ end
144
+ end
145
+
146
+ def query(sql, options = {})
147
+ Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do
148
+ _query(sql, @query_options.merge(options))
149
+ end
75
150
  end
76
151
 
77
152
  def query_info
@@ -82,9 +157,16 @@ module Mysql2
82
157
  info_hash
83
158
  end
84
159
 
85
- private
86
- def self.local_offset
160
+ def info
161
+ self.class.info
162
+ end
163
+
164
+ class << self
165
+ private
166
+
167
+ def local_offset
87
168
  ::Time.local(2010).utc_offset.to_r / 86400
88
169
  end
170
+ end
89
171
  end
90
172
  end
@@ -1,5 +1,5 @@
1
1
  # Loaded by script/console. Land helpers here.
2
2
 
3
- Pry.config.prompt = lambda do |context, nesting, pry|
3
+ Pry.config.prompt = lambda do |context, *|
4
4
  "[mysql2] #{context}> "
5
5
  end
data/lib/mysql2/em.rb CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'eventmachine'
4
2
  require 'mysql2'
5
3
 
@@ -10,32 +8,40 @@ module Mysql2
10
8
  def initialize(client, deferable)
11
9
  @client = client
12
10
  @deferable = deferable
11
+ @is_watching = true
13
12
  end
14
13
 
15
14
  def notify_readable
16
15
  detach
17
16
  begin
18
17
  result = @client.async_result
19
- rescue Exception => e
18
+ rescue StandardError => e
20
19
  @deferable.fail(e)
21
20
  else
22
21
  @deferable.succeed(result)
23
22
  end
24
23
  end
24
+
25
+ def watching?
26
+ @is_watching
27
+ end
28
+
29
+ def unbind
30
+ @is_watching = false
31
+ end
25
32
  end
26
33
 
27
34
  def close(*args)
28
- if @watch
29
- @watch.detach
30
- end
35
+ @watch.detach if @watch && @watch.watching?
36
+
31
37
  super(*args)
32
38
  end
33
39
 
34
- def query(sql, opts={})
40
+ def query(sql, opts = {})
35
41
  if ::EM.reactor_running?
36
- super(sql, opts.merge(:async => true))
42
+ super(sql, opts.merge(async: true))
37
43
  deferable = ::EM::DefaultDeferrable.new
38
- @watch = ::EM.watch(self.socket, Watcher, self, deferable)
44
+ @watch = ::EM.watch(socket, Watcher, self, deferable)
39
45
  @watch.notify_readable = true
40
46
  deferable
41
47
  else
data/lib/mysql2/error.rb CHANGED
@@ -1,26 +1,66 @@
1
- # encoding: UTF-8
2
-
3
1
  module Mysql2
4
2
  class Error < StandardError
5
- REPLACEMENT_CHAR = '?'
6
- ENCODE_OPTS = {:undef => :replace, :invalid => :replace, :replace => REPLACEMENT_CHAR}
3
+ ENCODE_OPTS = {
4
+ undef: :replace,
5
+ invalid: :replace,
6
+ replace: '?'.freeze,
7
+ }.freeze
8
+
9
+ ConnectionError = Class.new(Error)
10
+ TimeoutError = Class.new(Error)
11
+
12
+ CODES = {
13
+ 1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
14
+
15
+ 1044 => ConnectionError, # ER_DBACCESS_DENIED_ERROR
16
+ 1045 => ConnectionError, # ER_ACCESS_DENIED_ERROR
17
+ 1152 => ConnectionError, # ER_ABORTING_CONNECTION
18
+ 1153 => ConnectionError, # ER_NET_PACKET_TOO_LARGE
19
+ 1154 => ConnectionError, # ER_NET_READ_ERROR_FROM_PIPE
20
+ 1155 => ConnectionError, # ER_NET_FCNTL_ERROR
21
+ 1156 => ConnectionError, # ER_NET_PACKETS_OUT_OF_ORDER
22
+ 1157 => ConnectionError, # ER_NET_UNCOMPRESS_ERROR
23
+ 1158 => ConnectionError, # ER_NET_READ_ERROR
24
+ 1159 => ConnectionError, # ER_NET_READ_INTERRUPTED
25
+ 1160 => ConnectionError, # ER_NET_ERROR_ON_WRITE
26
+ 1161 => ConnectionError, # ER_NET_WRITE_INTERRUPTED
27
+ 1927 => ConnectionError, # ER_CONNECTION_KILLED
7
28
 
8
- attr_accessor :error_number
9
- attr_reader :sql_state
10
- attr_writer :server_version
29
+ 2001 => ConnectionError, # CR_SOCKET_CREATE_ERROR
30
+ 2002 => ConnectionError, # CR_CONNECTION_ERROR
31
+ 2003 => ConnectionError, # CR_CONN_HOST_ERROR
32
+ 2004 => ConnectionError, # CR_IPSOCK_ERROR
33
+ 2005 => ConnectionError, # CR_UNKNOWN_HOST
34
+ 2006 => ConnectionError, # CR_SERVER_GONE_ERROR
35
+ 2007 => ConnectionError, # CR_VERSION_ERROR
36
+ 2009 => ConnectionError, # CR_WRONG_HOST_INFO
37
+ 2012 => ConnectionError, # CR_SERVER_HANDSHAKE_ERR
38
+ 2013 => ConnectionError, # CR_SERVER_LOST
39
+ 2020 => ConnectionError, # CR_NET_PACKET_TOO_LARGE
40
+ 2026 => ConnectionError, # CR_SSL_CONNECTION_ERROR
41
+ 2027 => ConnectionError, # CR_MALFORMED_PACKET
42
+ 2047 => ConnectionError, # CR_CONN_UNKNOW_PROTOCOL
43
+ 2048 => ConnectionError, # CR_INVALID_CONN_HANDLE
44
+ 2049 => ConnectionError, # CR_UNUSED_1
45
+ }.freeze
46
+
47
+ attr_reader :error_number, :sql_state
11
48
 
12
49
  # Mysql gem compatibility
13
- alias_method :errno, :error_number
14
- alias_method :error, :message
50
+ alias errno error_number
51
+ alias error message
15
52
 
16
- def initialize(msg, server_version=nil)
17
- self.server_version = server_version
53
+ def initialize(msg, server_version = nil, error_number = nil, sql_state = nil)
54
+ @server_version = server_version
55
+ @error_number = error_number
56
+ @sql_state = sql_state ? sql_state.encode(**ENCODE_OPTS) : nil
18
57
 
19
58
  super(clean_message(msg))
20
59
  end
21
60
 
22
- def sql_state=(state)
23
- @sql_state = ''.respond_to?(:encode) ? state.encode(ENCODE_OPTS) : state
61
+ def self.new_with_args(msg, server_version, error_number, sql_state)
62
+ error_class = CODES.fetch(error_number, self)
63
+ error_class.new(msg, server_version, error_number, sql_state)
24
64
  end
25
65
 
26
66
  private
@@ -30,7 +70,7 @@ module Mysql2
30
70
  # variable.
31
71
  #
32
72
  # See http://dev.mysql.com/doc/refman/5.5/en/charset-errors.html for
33
- # more contetx.
73
+ # more context.
34
74
  #
35
75
  # Before MySQL 5.5 error message template strings are in whatever encoding
36
76
  # is associated with the error message language.
@@ -49,31 +89,12 @@ module Mysql2
49
89
  # encoding, we'll assume UTF-8 and clean the string of anything that's not a
50
90
  # valid UTF-8 character.
51
91
  #
52
- # Except for if we're on 1.8, where we'll do nothing ;)
53
- #
54
- # Returns a valid UTF-8 string in Ruby 1.9+, the original string on Ruby 1.8
92
+ # Returns a valid UTF-8 string.
55
93
  def clean_message(message)
56
- return message if !message.respond_to?(:encoding)
57
-
58
94
  if @server_version && @server_version > 50500
59
- message.encode(ENCODE_OPTS)
95
+ message.encode(**ENCODE_OPTS)
60
96
  else
61
- if message.respond_to? :scrub
62
- message.scrub(REPLACEMENT_CHAR).encode(ENCODE_OPTS)
63
- else
64
- # This is ugly as hell but Ruby 1.9 doesn't provide a way to clean a string
65
- # and retain it's valid UTF-8 characters, that I know of.
66
-
67
- new_message = "".force_encoding(Encoding::UTF_8)
68
- message.chars.each do |char|
69
- if char.valid_encoding?
70
- new_message << char
71
- else
72
- new_message << REPLACEMENT_CHAR
73
- end
74
- end
75
- new_message.encode(ENCODE_OPTS)
76
- end
97
+ message.encode(Encoding::UTF_8, **ENCODE_OPTS)
77
98
  end
78
99
  end
79
100
  end
@@ -0,0 +1,3 @@
1
+ module Mysql2
2
+ Field = Struct.new(:name, :type)
3
+ end
data/lib/mysql2/result.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Mysql2
2
2
  class Result
3
+ attr_reader :server_flags
4
+
3
5
  include Enumerable
4
6
  end
5
7
  end
@@ -0,0 +1,9 @@
1
+ module Mysql2
2
+ class Statement
3
+ def execute(*args, **kwargs)
4
+ Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do
5
+ _execute(*args, **kwargs)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.2.24"
2
+ VERSION = "0.5.4".freeze
3
3
  end
data/lib/mysql2.rb CHANGED
@@ -1,13 +1,43 @@
1
- # encoding: UTF-8
2
1
  require 'date'
3
2
  require 'bigdecimal'
4
- require 'rational' unless RUBY_VERSION >= '1.9.2'
3
+
4
+ # Load libmysql.dll before requiring mysql2/mysql2.so
5
+ # This gives a chance to be flexible about the load path
6
+ # Or to bomb out with a clear error message instead of a linker crash
7
+ if RUBY_PLATFORM =~ /mswin|mingw/
8
+ dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
9
+ # If this environment variable is set, it overrides any other paths
10
+ # The user is advised to use backslashes not forward slashes
11
+ ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
12
+ elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
13
+ # Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
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
+ else
18
+ # This will use default / system library paths
19
+ 'libmysql.dll'
20
+ end
21
+
22
+ if dll_path
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?
29
+ abort "Failed to load libmysql.dll from #{dll_path}"
30
+ end
31
+ end
32
+ end
5
33
 
6
34
  require 'mysql2/version' unless defined? Mysql2::VERSION
7
35
  require 'mysql2/error'
8
36
  require 'mysql2/mysql2'
9
37
  require 'mysql2/result'
10
38
  require 'mysql2/client'
39
+ require 'mysql2/field'
40
+ require 'mysql2/statement'
11
41
 
12
42
  # = Mysql2
13
43
  #
@@ -15,22 +45,43 @@ require 'mysql2/client'
15
45
  module Mysql2
16
46
  end
17
47
 
18
- if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING >= "3.1"
19
- warn "============= WARNING FROM mysql2 ============="
20
- warn "This version of mysql2 (#{Mysql2::VERSION}) isn't compatible with Rails 3.1 as the ActiveRecord adapter was pulled into Rails itself."
21
- warn "Please use the 0.3.x (or greater) releases if you plan on using it in Rails >= 3.1.x"
22
- warn "============= END WARNING FROM mysql2 ============="
48
+ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3.1"
49
+ begin
50
+ require 'active_record/connection_adapters/mysql2_adapter'
51
+ rescue LoadError
52
+ warn "============= WARNING FROM mysql2 ============="
53
+ warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter."
54
+ warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails."
55
+ warn "If you want to use the mysql2 gem with Rails <= 3.0.x, please use the latest mysql2 in the 0.2.x series."
56
+ warn "============= END WARNING FROM mysql2 ============="
57
+ end
23
58
  end
24
59
 
25
60
  # For holding utility methods
26
- module Mysql2::Util
61
+ module Mysql2
62
+ module Util
63
+ #
64
+ # Rekey a string-keyed hash with equivalent symbols.
65
+ #
66
+ def self.key_hash_as_symbols(hash)
67
+ return nil unless hash
68
+ Hash[hash.map { |k, v| [k.to_sym, v] }]
69
+ end
27
70
 
28
- #
29
- # Rekey a string-keyed hash with equivalent symbols.
30
- #
31
- def self.key_hash_as_symbols(hash)
32
- return nil unless hash
33
- Hash[hash.map { |k,v| [k.to_sym, v] }]
71
+ #
72
+ # In Mysql2::Client#query and Mysql2::Statement#execute,
73
+ # Thread#handle_interrupt is used to prevent Timeout#timeout
74
+ # from interrupting query execution.
75
+ #
76
+ # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
77
+ # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
78
+ #
79
+ require 'timeout'
80
+ TIMEOUT_ERROR_CLASS = if defined?(::Timeout::ExitException)
81
+ ::Timeout::ExitException
82
+ else
83
+ ::Timeout::Error
84
+ end
85
+ TIMEOUT_ERROR_NEVER = { TIMEOUT_ERROR_CLASS => :never }.freeze
34
86
  end
35
-
36
87
  end
@@ -0,0 +1,49 @@
1
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
2
+ Version: SKS 1.1.6
3
+ Comment: Hostname: pgp.mit.edu
4
+
5
+ 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
47
+ sTSKHe+QnnnoFmu4gnmDU31i
48
+ =Xqbo
49
+ -----END PGP PUBLIC KEY BLOCK-----