mysql2 0.3.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -151
  3. data/LICENSE +21 -0
  4. data/README.md +634 -0
  5. data/examples/eventmachine.rb +1 -3
  6. data/examples/threaded.rb +5 -9
  7. data/ext/mysql2/client.c +1154 -342
  8. data/ext/mysql2/client.h +20 -33
  9. data/ext/mysql2/extconf.rb +229 -37
  10. data/ext/mysql2/infile.c +122 -0
  11. data/ext/mysql2/infile.h +1 -0
  12. data/ext/mysql2/mysql2_ext.c +3 -1
  13. data/ext/mysql2/mysql2_ext.h +18 -16
  14. data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
  15. data/ext/mysql2/mysql_enc_to_ruby.h +259 -0
  16. data/ext/mysql2/result.c +708 -191
  17. data/ext/mysql2/result.h +15 -6
  18. data/ext/mysql2/statement.c +602 -0
  19. data/ext/mysql2/statement.h +17 -0
  20. data/ext/mysql2/wait_for_single_fd.h +37 -0
  21. data/lib/mysql2.rb +69 -7
  22. data/lib/mysql2/client.rb +126 -211
  23. data/lib/mysql2/console.rb +5 -0
  24. data/lib/mysql2/em.rb +24 -8
  25. data/lib/mysql2/error.rb +93 -8
  26. data/lib/mysql2/field.rb +3 -0
  27. data/lib/mysql2/result.rb +2 -0
  28. data/lib/mysql2/statement.rb +11 -0
  29. data/lib/mysql2/version.rb +2 -2
  30. data/spec/configuration.yml.example +11 -0
  31. data/spec/em/em_spec.rb +101 -15
  32. data/spec/my.cnf.example +9 -0
  33. data/spec/mysql2/client_spec.rb +874 -232
  34. data/spec/mysql2/error_spec.rb +55 -46
  35. data/spec/mysql2/result_spec.rb +306 -154
  36. data/spec/mysql2/statement_spec.rb +712 -0
  37. data/spec/spec_helper.rb +103 -57
  38. data/spec/ssl/ca-cert.pem +17 -0
  39. data/spec/ssl/ca-key.pem +27 -0
  40. data/spec/ssl/ca.cnf +22 -0
  41. data/spec/ssl/cert.cnf +22 -0
  42. data/spec/ssl/client-cert.pem +17 -0
  43. data/spec/ssl/client-key.pem +27 -0
  44. data/spec/ssl/client-req.pem +15 -0
  45. data/spec/ssl/gen_certs.sh +48 -0
  46. data/spec/ssl/pkcs8-client-key.pem +28 -0
  47. data/spec/ssl/pkcs8-server-key.pem +28 -0
  48. data/spec/ssl/server-cert.pem +17 -0
  49. data/spec/ssl/server-key.pem +27 -0
  50. data/spec/ssl/server-req.pem +15 -0
  51. data/spec/test_data +1 -0
  52. data/support/5072E1F5.asc +432 -0
  53. data/support/libmysql.def +219 -0
  54. data/support/mysql_enc_to_ruby.rb +81 -0
  55. data/support/ruby_enc_to_mysql.rb +61 -0
  56. metadata +82 -188
  57. data/.gitignore +0 -12
  58. data/.rspec +0 -2
  59. data/.rvmrc +0 -1
  60. data/Gemfile +0 -3
  61. data/MIT-LICENSE +0 -20
  62. data/README.rdoc +0 -257
  63. data/Rakefile +0 -5
  64. data/benchmark/active_record.rb +0 -51
  65. data/benchmark/active_record_threaded.rb +0 -42
  66. data/benchmark/allocations.rb +0 -33
  67. data/benchmark/escape.rb +0 -36
  68. data/benchmark/query_with_mysql_casting.rb +0 -80
  69. data/benchmark/query_without_mysql_casting.rb +0 -47
  70. data/benchmark/sequel.rb +0 -37
  71. data/benchmark/setup_db.rb +0 -119
  72. data/benchmark/threaded.rb +0 -44
  73. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +0 -64
  74. data/lib/active_record/fiber_patches.rb +0 -104
  75. data/lib/mysql2/em_fiber.rb +0 -31
  76. data/mysql2.gemspec +0 -32
  77. data/spec/em/em_fiber_spec.rb +0 -22
  78. data/tasks/benchmarks.rake +0 -20
  79. data/tasks/compile.rake +0 -71
  80. data/tasks/rspec.rake +0 -16
  81. data/tasks/vendor_mysql.rake +0 -40
@@ -0,0 +1,17 @@
1
+ #ifndef MYSQL2_STATEMENT_H
2
+ #define MYSQL2_STATEMENT_H
3
+
4
+ typedef struct {
5
+ VALUE client;
6
+ MYSQL_STMT *stmt;
7
+ int refcount;
8
+ int closed;
9
+ } mysql_stmt_wrapper;
10
+
11
+ void init_mysql2_statement(void);
12
+ void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper);
13
+
14
+ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql);
15
+ void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) RB_MYSQL_NORETURN;
16
+
17
+ #endif
@@ -0,0 +1,37 @@
1
+ /*
2
+ * backwards compatibility for Rubinius. See
3
+ * https://github.com/rubinius/rubinius/issues/3771.
4
+ *
5
+ * Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
6
+ * to minimize select() and malloc() overhead on high-numbered FDs.
7
+ */
8
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
9
+ # include <ruby/io.h>
10
+ #else
11
+ # define RB_WAITFD_IN 0x001
12
+ # define RB_WAITFD_PRI 0x002
13
+ # define RB_WAITFD_OUT 0x004
14
+
15
+ static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
16
+ {
17
+ fd_set fdset;
18
+ fd_set *rfds = NULL;
19
+ fd_set *wfds = NULL;
20
+ fd_set *efds = NULL;
21
+
22
+ FD_ZERO(&fdset);
23
+ FD_SET(fd, &fdset);
24
+
25
+ if (events & RB_WAITFD_IN)
26
+ rfds = &fdset;
27
+ if (events & RB_WAITFD_OUT)
28
+ wfds = &fdset;
29
+ if (events & RB_WAITFD_PRI)
30
+ efds = &fdset;
31
+
32
+ return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
33
+ }
34
+
35
+ #define rb_wait_for_single_fd(fd,events,tvp) \
36
+ my_wait_for_single_fd((fd),(events),(tvp))
37
+ #endif
data/lib/mysql2.rb CHANGED
@@ -1,13 +1,40 @@
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 '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
28
+ end
29
+ end
5
30
 
6
31
  require 'mysql2/version' unless defined? Mysql2::VERSION
7
32
  require 'mysql2/error'
8
33
  require 'mysql2/mysql2'
9
- require 'mysql2/client'
10
34
  require 'mysql2/result'
35
+ require 'mysql2/client'
36
+ require 'mysql2/field'
37
+ require 'mysql2/statement'
11
38
 
12
39
  # = Mysql2
13
40
  #
@@ -15,7 +42,42 @@ require 'mysql2/result'
15
42
  module Mysql2
16
43
  end
17
44
 
18
- if defined?(ActiveRecord::VERSION::STRING) < "3.1"
19
- puts "WARNING: This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter bundled anymore as it's now part of Rails 3.1"
20
- puts "WARNING: Please use the 0.2.x releases if you plan on using it in Rails <= 3.0.x"
21
- end
45
+ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3.1"
46
+ begin
47
+ require 'active_record/connection_adapters/mysql2_adapter'
48
+ rescue LoadError
49
+ warn "============= WARNING FROM mysql2 ============="
50
+ warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter."
51
+ warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails."
52
+ 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."
53
+ warn "============= END WARNING FROM mysql2 ============="
54
+ end
55
+ end
56
+
57
+ # For holding utility methods
58
+ module Mysql2
59
+ module Util
60
+ #
61
+ # Rekey a string-keyed hash with equivalent symbols.
62
+ #
63
+ def self.key_hash_as_symbols(hash)
64
+ return nil unless hash
65
+ Hash[hash.map { |k, v| [k.to_sym, v] }]
66
+ end
67
+
68
+ #
69
+ # In Mysql2::Client#query and Mysql2::Statement#execute,
70
+ # Thread#handle_interrupt is used to prevent Timeout#timeout
71
+ # from interrupting query execution.
72
+ #
73
+ # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
74
+ # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
75
+ #
76
+ require 'timeout'
77
+ TIMEOUT_ERROR_CLASS = if defined?(::Timeout::ExitException)
78
+ ::Timeout::ExitException
79
+ else
80
+ ::Timeout::Error
81
+ end
82
+ end
83
+ end
data/lib/mysql2/client.rb CHANGED
@@ -1,240 +1,155 @@
1
1
  module Mysql2
2
2
  class Client
3
- attr_reader :query_options
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
- }
3
+ attr_reader :query_options, :read_timeout
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
14
20
 
15
21
  def initialize(opts = {})
16
- @query_options = @@default_query_options.dup
22
+ raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
23
+ opts = Mysql2::Util.key_hash_as_symbols(opts)
24
+ @read_timeout = nil
25
+ @query_options = self.class.default_query_options.dup
26
+ @query_options.merge! opts
17
27
 
18
- init_connection
28
+ initialize_ext
19
29
 
20
- [:reconnect, :connect_timeout].each do |key|
30
+ # Set default connect_timeout to avoid unlimited retries from signal interruption
31
+ opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
32
+
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|
21
35
  next unless opts.key?(key)
22
- send(:"#{key}=", opts[key])
36
+ case key
37
+ when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
38
+ send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
39
+ when :connect_timeout, :read_timeout, :write_timeout
40
+ send(:"#{key}=", Integer(opts[key])) unless opts[key].nil?
41
+ else
42
+ send(:"#{key}=", opts[key])
43
+ end
23
44
  end
45
+
24
46
  # force the encoding to utf8
25
47
  self.charset_name = opts[:encoding] || 'utf8'
26
48
 
27
- @read_timeout = opts[:read_timeout]
28
- if @read_timeout and @read_timeout < 0
29
- raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
49
+ ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
50
+ ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
51
+ self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
52
+
53
+ flags = case opts[:flags]
54
+ when Array
55
+ parse_flags_array(opts[:flags], @query_options[:connect_flags])
56
+ when String
57
+ parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
58
+ when Integer
59
+ @query_options[:connect_flags] | opts[:flags]
60
+ else
61
+ @query_options[:connect_flags]
30
62
  end
31
63
 
32
- ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
64
+ # SSL verify is a connection flag rather than a mysql_ssl_set option
65
+ flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
33
66
 
34
- user = opts[:username]
35
- pass = opts[:password]
36
- host = opts[:host] || 'localhost'
37
- port = opts[:port] || 3306
38
- database = opts[:database]
39
- socket = opts[:socket]
40
- flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
67
+ if %i[user pass hostname dbname db sock].any? { |k| @query_options.key?(k) }
68
+ warn "============= WARNING FROM mysql2 ============="
69
+ warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed at some point in the future."
70
+ warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
71
+ warn "============= END WARNING FROM mysql2 ========="
72
+ end
41
73
 
42
- connect user, pass, host, port, database, socket, flags
43
- end
74
+ user = opts[:username] || opts[:user]
75
+ pass = opts[:password] || opts[:pass]
76
+ host = opts[:host] || opts[:hostname]
77
+ port = opts[:port]
78
+ database = opts[:database] || opts[:dbname] || opts[:db]
79
+ socket = opts[:socket] || opts[:sock]
44
80
 
45
- def self.default_query_options
46
- @@default_query_options
47
- end
48
-
49
- # NOTE: from ruby-mysql
50
- if defined? Encoding
51
- CHARSET_MAP = {
52
- "armscii8" => nil,
53
- "ascii" => Encoding::US_ASCII,
54
- "big5" => Encoding::Big5,
55
- "binary" => Encoding::ASCII_8BIT,
56
- "cp1250" => Encoding::Windows_1250,
57
- "cp1251" => Encoding::Windows_1251,
58
- "cp1256" => Encoding::Windows_1256,
59
- "cp1257" => Encoding::Windows_1257,
60
- "cp850" => Encoding::CP850,
61
- "cp852" => Encoding::CP852,
62
- "cp866" => Encoding::IBM866,
63
- "cp932" => Encoding::Windows_31J,
64
- "dec8" => nil,
65
- "eucjpms" => Encoding::EucJP_ms,
66
- "euckr" => Encoding::EUC_KR,
67
- "gb2312" => Encoding::EUC_CN,
68
- "gbk" => Encoding::GBK,
69
- "geostd8" => nil,
70
- "greek" => Encoding::ISO_8859_7,
71
- "hebrew" => Encoding::ISO_8859_8,
72
- "hp8" => nil,
73
- "keybcs2" => nil,
74
- "koi8r" => Encoding::KOI8_R,
75
- "koi8u" => Encoding::KOI8_U,
76
- "latin1" => Encoding::ISO_8859_1,
77
- "latin2" => Encoding::ISO_8859_2,
78
- "latin5" => Encoding::ISO_8859_9,
79
- "latin7" => Encoding::ISO_8859_13,
80
- "macce" => Encoding::MacCentEuro,
81
- "macroman" => Encoding::MacRoman,
82
- "sjis" => Encoding::SHIFT_JIS,
83
- "swe7" => nil,
84
- "tis620" => Encoding::TIS_620,
85
- "ucs2" => Encoding::UTF_16BE,
86
- "ujis" => Encoding::EucJP_ms,
87
- "utf8" => Encoding::UTF_8,
88
- }
81
+ # Correct the data types before passing these values down to the C level
82
+ user = user.to_s unless user.nil?
83
+ pass = pass.to_s unless pass.nil?
84
+ host = host.to_s unless host.nil?
85
+ port = port.to_i unless port.nil?
86
+ database = database.to_s unless database.nil?
87
+ socket = socket.to_s unless socket.nil?
88
+ conn_attrs = parse_connect_attrs(opts[:connect_attrs])
89
89
 
90
- MYSQL_CHARSET_MAP = {
91
- 1 => {:name => "big5", :collation => "big5_chinese_ci"},
92
- 2 => {:name => "latin2", :collation => "latin2_czech_cs"},
93
- 3 => {:name => "dec8", :collation => "dec8_swedish_ci"},
94
- 4 => {:name => "cp850", :collation => "cp850_general_ci"},
95
- 5 => {:name => "latin1", :collation => "latin1_german1_ci"},
96
- 6 => {:name => "hp8", :collation => "hp8_english_ci"},
97
- 7 => {:name => "koi8r", :collation => "koi8r_general_ci"},
98
- 8 => {:name => "latin1", :collation => "latin1_swedish_ci"},
99
- 9 => {:name => "latin2", :collation => "latin2_general_ci"},
100
- 10 => {:name => "swe7", :collation => "swe7_swedish_ci"},
101
- 11 => {:name => "ascii", :collation => "ascii_general_ci"},
102
- 12 => {:name => "ujis", :collation => "ujis_japanese_ci"},
103
- 13 => {:name => "sjis", :collation => "sjis_japanese_ci"},
104
- 14 => {:name => "cp1251", :collation => "cp1251_bulgarian_ci"},
105
- 15 => {:name => "latin1", :collation => "latin1_danish_ci"},
106
- 16 => {:name => "hebrew", :collation => "hebrew_general_ci"},
107
- 17 => {:name => "filename", :collation => "filename"},
108
- 18 => {:name => "tis620", :collation => "tis620_thai_ci"},
109
- 19 => {:name => "euckr", :collation => "euckr_korean_ci"},
110
- 20 => {:name => "latin7", :collation => "latin7_estonian_cs"},
111
- 21 => {:name => "latin2", :collation => "latin2_hungarian_ci"},
112
- 22 => {:name => "koi8u", :collation => "koi8u_general_ci"},
113
- 23 => {:name => "cp1251", :collation => "cp1251_ukrainian_ci"},
114
- 24 => {:name => "gb2312", :collation => "gb2312_chinese_ci"},
115
- 25 => {:name => "greek", :collation => "greek_general_ci"},
116
- 26 => {:name => "cp1250", :collation => "cp1250_general_ci"},
117
- 27 => {:name => "latin2", :collation => "latin2_croatian_ci"},
118
- 28 => {:name => "gbk", :collation => "gbk_chinese_ci"},
119
- 29 => {:name => "cp1257", :collation => "cp1257_lithuanian_ci"},
120
- 30 => {:name => "latin5", :collation => "latin5_turkish_ci"},
121
- 31 => {:name => "latin1", :collation => "latin1_german2_ci"},
122
- 32 => {:name => "armscii8", :collation => "armscii8_general_ci"},
123
- 33 => {:name => "utf8", :collation => "utf8_general_ci"},
124
- 34 => {:name => "cp1250", :collation => "cp1250_czech_cs"},
125
- 35 => {:name => "ucs2", :collation => "ucs2_general_ci"},
126
- 36 => {:name => "cp866", :collation => "cp866_general_ci"},
127
- 37 => {:name => "keybcs2", :collation => "keybcs2_general_ci"},
128
- 38 => {:name => "macce", :collation => "macce_general_ci"},
129
- 39 => {:name => "macroman", :collation => "macroman_general_ci"},
130
- 40 => {:name => "cp852", :collation => "cp852_general_ci"},
131
- 41 => {:name => "latin7", :collation => "latin7_general_ci"},
132
- 42 => {:name => "latin7", :collation => "latin7_general_cs"},
133
- 43 => {:name => "macce", :collation => "macce_bin"},
134
- 44 => {:name => "cp1250", :collation => "cp1250_croatian_ci"},
135
- 47 => {:name => "latin1", :collation => "latin1_bin"},
136
- 48 => {:name => "latin1", :collation => "latin1_general_ci"},
137
- 49 => {:name => "latin1", :collation => "latin1_general_cs"},
138
- 50 => {:name => "cp1251", :collation => "cp1251_bin"},
139
- 51 => {:name => "cp1251", :collation => "cp1251_general_ci"},
140
- 52 => {:name => "cp1251", :collation => "cp1251_general_cs"},
141
- 53 => {:name => "macroman", :collation => "macroman_bin"},
142
- 57 => {:name => "cp1256", :collation => "cp1256_general_ci"},
143
- 58 => {:name => "cp1257", :collation => "cp1257_bin"},
144
- 59 => {:name => "cp1257", :collation => "cp1257_general_ci"},
145
- 63 => {:name => "binary", :collation => "binary"},
146
- 64 => {:name => "armscii8", :collation => "armscii8_bin"},
147
- 65 => {:name => "ascii", :collation => "ascii_bin"},
148
- 66 => {:name => "cp1250", :collation => "cp1250_bin"},
149
- 67 => {:name => "cp1256", :collation => "cp1256_bin"},
150
- 68 => {:name => "cp866", :collation => "cp866_bin"},
151
- 69 => {:name => "dec8", :collation => "dec8_bin"},
152
- 70 => {:name => "greek", :collation => "greek_bin"},
153
- 71 => {:name => "hebrew", :collation => "hebrew_bin"},
154
- 72 => {:name => "hp8", :collation => "hp8_bin"},
155
- 73 => {:name => "keybcs2", :collation => "keybcs2_bin"},
156
- 74 => {:name => "koi8r", :collation => "koi8r_bin"},
157
- 75 => {:name => "koi8u", :collation => "koi8u_bin"},
158
- 77 => {:name => "latin2", :collation => "latin2_bin"},
159
- 78 => {:name => "latin5", :collation => "latin5_bin"},
160
- 79 => {:name => "latin7", :collation => "latin7_bin"},
161
- 80 => {:name => "cp850", :collation => "cp850_bin"},
162
- 81 => {:name => "cp852", :collation => "cp852_bin"},
163
- 82 => {:name => "swe7", :collation => "swe7_bin"},
164
- 83 => {:name => "utf8", :collation => "utf8_bin"},
165
- 84 => {:name => "big5", :collation => "big5_bin"},
166
- 85 => {:name => "euckr", :collation => "euckr_bin"},
167
- 86 => {:name => "gb2312", :collation => "gb2312_bin"},
168
- 87 => {:name => "gbk", :collation => "gbk_bin"},
169
- 88 => {:name => "sjis", :collation => "sjis_bin"},
170
- 89 => {:name => "tis620", :collation => "tis620_bin"},
171
- 90 => {:name => "ucs2", :collation => "ucs2_bin"},
172
- 91 => {:name => "ujis", :collation => "ujis_bin"},
173
- 92 => {:name => "geostd8", :collation => "geostd8_general_ci"},
174
- 93 => {:name => "geostd8", :collation => "geostd8_bin"},
175
- 94 => {:name => "latin1", :collation => "latin1_spanish_ci"},
176
- 95 => {:name => "cp932", :collation => "cp932_japanese_ci"},
177
- 96 => {:name => "cp932", :collation => "cp932_bin"},
178
- 97 => {:name => "eucjpms", :collation => "eucjpms_japanese_ci"},
179
- 98 => {:name => "eucjpms", :collation => "eucjpms_bin"},
180
- 99 => {:name => "cp1250", :collation => "cp1250_polish_ci"},
181
- 128 => {:name => "ucs2", :collation => "ucs2_unicode_ci"},
182
- 129 => {:name => "ucs2", :collation => "ucs2_icelandic_ci"},
183
- 130 => {:name => "ucs2", :collation => "ucs2_latvian_ci"},
184
- 131 => {:name => "ucs2", :collation => "ucs2_romanian_ci"},
185
- 132 => {:name => "ucs2", :collation => "ucs2_slovenian_ci"},
186
- 133 => {:name => "ucs2", :collation => "ucs2_polish_ci"},
187
- 134 => {:name => "ucs2", :collation => "ucs2_estonian_ci"},
188
- 135 => {:name => "ucs2", :collation => "ucs2_spanish_ci"},
189
- 136 => {:name => "ucs2", :collation => "ucs2_swedish_ci"},
190
- 137 => {:name => "ucs2", :collation => "ucs2_turkish_ci"},
191
- 138 => {:name => "ucs2", :collation => "ucs2_czech_ci"},
192
- 139 => {:name => "ucs2", :collation => "ucs2_danish_ci"},
193
- 140 => {:name => "ucs2", :collation => "ucs2_lithuanian_ci"},
194
- 141 => {:name => "ucs2", :collation => "ucs2_slovak_ci"},
195
- 142 => {:name => "ucs2", :collation => "ucs2_spanish2_ci"},
196
- 143 => {:name => "ucs2", :collation => "ucs2_roman_ci"},
197
- 144 => {:name => "ucs2", :collation => "ucs2_persian_ci"},
198
- 145 => {:name => "ucs2", :collation => "ucs2_esperanto_ci"},
199
- 146 => {:name => "ucs2", :collation => "ucs2_hungarian_ci"},
200
- 192 => {:name => "utf8", :collation => "utf8_unicode_ci"},
201
- 193 => {:name => "utf8", :collation => "utf8_icelandic_ci"},
202
- 194 => {:name => "utf8", :collation => "utf8_latvian_ci"},
203
- 195 => {:name => "utf8", :collation => "utf8_romanian_ci"},
204
- 196 => {:name => "utf8", :collation => "utf8_slovenian_ci"},
205
- 197 => {:name => "utf8", :collation => "utf8_polish_ci"},
206
- 198 => {:name => "utf8", :collation => "utf8_estonian_ci"},
207
- 199 => {:name => "utf8", :collation => "utf8_spanish_ci"},
208
- 200 => {:name => "utf8", :collation => "utf8_swedish_ci"},
209
- 201 => {:name => "utf8", :collation => "utf8_turkish_ci"},
210
- 202 => {:name => "utf8", :collation => "utf8_czech_ci"},
211
- 203 => {:name => "utf8", :collation => "utf8_danish_ci"},
212
- 204 => {:name => "utf8", :collation => "utf8_lithuanian_ci"},
213
- 205 => {:name => "utf8", :collation => "utf8_slovak_ci"},
214
- 206 => {:name => "utf8", :collation => "utf8_spanish2_ci"},
215
- 207 => {:name => "utf8", :collation => "utf8_roman_ci"},
216
- 208 => {:name => "utf8", :collation => "utf8_persian_ci"},
217
- 209 => {:name => "utf8", :collation => "utf8_esperanto_ci"},
218
- 210 => {:name => "utf8", :collation => "utf8_hungarian_ci"},
219
- 254 => {:name => "utf8", :collation => "utf8_general_cs"}
220
- }
90
+ connect user, pass, host, port, database, socket, flags, conn_attrs
91
+ end
221
92
 
222
- def self.encoding_from_charset(charset)
223
- CHARSET_MAP[charset.to_s.downcase]
93
+ def parse_ssl_mode(mode)
94
+ m = mode.to_s.upcase
95
+ if m.start_with?('SSL_MODE_')
96
+ return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m)
97
+ else
98
+ x = 'SSL_MODE_' + m
99
+ return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x)
224
100
  end
101
+ warn "Unknown MySQL ssl_mode flag: #{mode}"
102
+ end
225
103
 
226
- def self.encoding_from_charset_code(code)
227
- if mapping = MYSQL_CHARSET_MAP[code]
228
- encoding_from_charset(mapping[:name])
104
+ def parse_flags_array(flags, initial = 0)
105
+ flags.reduce(initial) do |memo, f|
106
+ fneg = f.start_with?('-') ? f[1..-1] : nil
107
+ if fneg && fneg =~ /^\w+$/ && Mysql2::Client.const_defined?(fneg)
108
+ memo & ~ Mysql2::Client.const_get(fneg)
109
+ elsif f && f =~ /^\w+$/ && Mysql2::Client.const_defined?(f)
110
+ memo | Mysql2::Client.const_get(f)
229
111
  else
230
- nil
112
+ warn "Unknown MySQL connection flag: '#{f}'"
113
+ memo
231
114
  end
232
115
  end
233
116
  end
234
117
 
235
- private
236
- def self.local_offset
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
126
+ end
127
+ end
128
+
129
+ def query(sql, options = {})
130
+ Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_CLASS => :never) do
131
+ _query(sql, @query_options.merge(options))
132
+ end
133
+ end
134
+
135
+ def query_info
136
+ info = query_info_string
137
+ return {} unless info
138
+ info_hash = {}
139
+ info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
140
+ info_hash
141
+ end
142
+
143
+ def info
144
+ self.class.info
145
+ end
146
+
147
+ class << self
148
+ private
149
+
150
+ def local_offset
237
151
  ::Time.local(2010).utc_offset.to_r / 86400
238
152
  end
153
+ end
239
154
  end
240
155
  end