mysql2 0.3.11-x86-mswin32-60 → 0.3.18-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +280 -75
  3. data/ext/mysql2/client.c +721 -206
  4. data/ext/mysql2/client.h +26 -12
  5. data/ext/mysql2/extconf.rb +120 -16
  6. data/ext/mysql2/infile.c +122 -0
  7. data/ext/mysql2/infile.h +1 -0
  8. data/ext/mysql2/mysql2_ext.h +7 -4
  9. data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
  10. data/ext/mysql2/mysql_enc_to_ruby.h +246 -0
  11. data/ext/mysql2/result.c +230 -112
  12. data/ext/mysql2/result.h +4 -1
  13. data/lib/mysql2.rb +46 -3
  14. data/lib/mysql2/1.8/mysql2.so +0 -0
  15. data/lib/mysql2/1.9/mysql2.so +0 -0
  16. data/lib/mysql2/2.0/mysql2.so +0 -0
  17. data/lib/mysql2/2.1/mysql2.so +0 -0
  18. data/lib/mysql2/client.rb +48 -200
  19. data/lib/mysql2/console.rb +5 -0
  20. data/lib/mysql2/em.rb +22 -3
  21. data/lib/mysql2/error.rb +71 -6
  22. data/lib/mysql2/mysql2.rb +2 -0
  23. data/lib/mysql2/version.rb +1 -1
  24. data/spec/configuration.yml.example +17 -0
  25. data/spec/em/em_spec.rb +90 -5
  26. data/spec/my.cnf.example +9 -0
  27. data/spec/mysql2/client_spec.rb +501 -69
  28. data/spec/mysql2/error_spec.rb +58 -44
  29. data/spec/mysql2/result_spec.rb +191 -74
  30. data/spec/spec_helper.rb +23 -3
  31. data/spec/test_data +1 -0
  32. data/support/libmysql.def +219 -0
  33. data/support/mysql_enc_to_ruby.rb +82 -0
  34. data/support/ruby_enc_to_mysql.rb +61 -0
  35. data/vendor/README +654 -0
  36. data/vendor/libmysql.dll +0 -0
  37. metadata +86 -221
  38. data/.gitignore +0 -12
  39. data/.rspec +0 -3
  40. data/.rvmrc +0 -1
  41. data/.travis.yml +0 -7
  42. data/CHANGELOG.md +0 -244
  43. data/Gemfile +0 -3
  44. data/MIT-LICENSE +0 -20
  45. data/Rakefile +0 -5
  46. data/benchmark/active_record.rb +0 -51
  47. data/benchmark/active_record_threaded.rb +0 -42
  48. data/benchmark/allocations.rb +0 -33
  49. data/benchmark/escape.rb +0 -36
  50. data/benchmark/query_with_mysql_casting.rb +0 -80
  51. data/benchmark/query_without_mysql_casting.rb +0 -56
  52. data/benchmark/sequel.rb +0 -37
  53. data/benchmark/setup_db.rb +0 -119
  54. data/benchmark/threaded.rb +0 -44
  55. data/mysql2.gemspec +0 -29
  56. data/tasks/benchmarks.rake +0 -20
  57. data/tasks/compile.rake +0 -71
  58. data/tasks/rspec.rake +0 -16
  59. data/tasks/vendor_mysql.rake +0 -40
@@ -2,17 +2,20 @@
2
2
  #define MYSQL2_RESULT_H
3
3
 
4
4
  void init_mysql2_result();
5
- VALUE rb_mysql_result_to_obj(MYSQL_RES * r);
5
+ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r);
6
6
 
7
7
  typedef struct {
8
8
  VALUE fields;
9
9
  VALUE rows;
10
+ VALUE client;
10
11
  VALUE encoding;
11
12
  unsigned int numberOfFields;
12
13
  unsigned long numberOfRows;
13
14
  unsigned long lastRowProcessed;
15
+ char streamingComplete;
14
16
  char resultFreed;
15
17
  MYSQL_RES *result;
18
+ mysql_client_wrapper *client_wrapper;
16
19
  } mysql2_result_wrapper;
17
20
 
18
21
  #define GetMysql2Result(obj, sval) (sval = (mysql2_result_wrapper*)DATA_PTR(obj));
@@ -3,10 +3,33 @@ require 'date'
3
3
  require 'bigdecimal'
4
4
  require 'rational' unless RUBY_VERSION >= '1.9.2'
5
5
 
6
+ # Load libmysql.dll before requiring mysql2/mysql2.so
7
+ # This gives a chance to be flexible about the load path
8
+ # Or to bomb out with a clear error message instead of a linker crash
9
+ if RUBY_PLATFORM =~ /mswin|mingw/
10
+ dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
11
+ # If this environment variable is set, it overrides any other paths
12
+ # The user is advised to use backslashes not forward slashes
13
+ ENV['RUBY_MYSQL2_LIBMYSQL_DLL'].dup
14
+ elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
15
+ # Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
16
+ File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).gsub('/', '\\')
17
+ else
18
+ # This will use default / system library paths
19
+ 'libmysql.dll'
20
+ end
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}"
26
+ end
27
+ end
28
+
6
29
  require 'mysql2/version' unless defined? Mysql2::VERSION
7
30
  require 'mysql2/error'
8
- require 'mysql2/result'
9
31
  require 'mysql2/mysql2'
32
+ require 'mysql2/result'
10
33
  require 'mysql2/client'
11
34
 
12
35
  # = Mysql2
@@ -16,6 +39,26 @@ module Mysql2
16
39
  end
17
40
 
18
41
  if defined?(ActiveRecord::VERSION::STRING) && 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"
42
+ begin
43
+ require 'active_record/connection_adapters/mysql2_adapter'
44
+ rescue LoadError
45
+ warn "============= WARNING FROM mysql2 ============="
46
+ warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter."
47
+ warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails."
48
+ 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."
49
+ warn "============= END WARNING FROM mysql2 ============="
50
+ end
51
+ end
52
+
53
+ # For holding utility methods
54
+ module Mysql2::Util
55
+
56
+ #
57
+ # Rekey a string-keyed hash with equivalent symbols.
58
+ #
59
+ def self.key_hash_as_symbols(hash)
60
+ return nil unless hash
61
+ Hash[hash.map { |k,v| [k.to_sym, v] }]
62
+ end
63
+
21
64
  end
Binary file
Binary file
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  module Mysql2
2
2
  class Client
3
- attr_reader :query_options
3
+ attr_reader :query_options, :read_timeout
4
4
  @@default_query_options = {
5
5
  :as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
6
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
@@ -10,37 +10,63 @@ module Mysql2
10
10
  :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
11
11
  :cache_rows => true, # tells Mysql2 to use it's internal row cache for results
12
12
  :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
13
- :cast => true
13
+ :cast => true,
14
+ :default_file => nil,
15
+ :default_group => nil
14
16
  }
15
17
 
16
18
  def initialize(opts = {})
19
+ opts = Mysql2::Util.key_hash_as_symbols( opts )
20
+ @read_timeout = nil
17
21
  @query_options = @@default_query_options.dup
18
22
  @query_options.merge! opts
19
23
 
20
- init_connection
24
+ initialize_ext
21
25
 
22
- [:reconnect, :connect_timeout].each do |key|
26
+ # Set default connect_timeout to avoid unlimited retries from signal interruption
27
+ opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
28
+
29
+ [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command].each do |key|
23
30
  next unless opts.key?(key)
24
- send(:"#{key}=", opts[key])
31
+ case key
32
+ when :reconnect, :local_infile, :secure_auth
33
+ send(:"#{key}=", !!opts[key])
34
+ when :connect_timeout, :read_timeout, :write_timeout
35
+ send(:"#{key}=", opts[key].to_i)
36
+ else
37
+ send(:"#{key}=", opts[key])
38
+ end
25
39
  end
40
+
26
41
  # force the encoding to utf8
27
42
  self.charset_name = opts[:encoding] || 'utf8'
28
43
 
29
- @read_timeout = opts[:read_timeout]
30
- if @read_timeout and @read_timeout < 0
31
- raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
32
- end
44
+ ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
45
+ ssl_set(*ssl_options) if ssl_options.any?
33
46
 
34
- ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
47
+ if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) }
48
+ warn "============= WARNING FROM mysql2 ============="
49
+ warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
50
+ warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
51
+ warn "============= END WARNING FROM mysql2 ========="
52
+ end
35
53
 
36
- user = opts[:username]
37
- pass = opts[:password]
38
- host = opts[:host] || 'localhost'
39
- port = opts[:port] || 3306
40
- database = opts[:database]
41
- socket = opts[:socket]
54
+ user = opts[:username] || opts[:user]
55
+ pass = opts[:password] || opts[:pass]
56
+ host = opts[:host] || opts[:hostname]
57
+ port = opts[:port]
58
+ database = opts[:database] || opts[:dbname] || opts[:db]
59
+ socket = opts[:socket] || opts[:sock]
42
60
  flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
43
61
 
62
+ # Correct the data types before passing these values down to the C level
63
+ user = user.to_s unless user.nil?
64
+ pass = pass.to_s unless pass.nil?
65
+ host = host.to_s unless host.nil?
66
+ port = port.to_i unless port.nil?
67
+ database = database.to_s unless database.nil?
68
+ socket = socket.to_s unless socket.nil?
69
+
44
70
  connect user, pass, host, port, database, socket, flags
45
71
  end
46
72
 
@@ -48,190 +74,12 @@ module Mysql2
48
74
  @@default_query_options
49
75
  end
50
76
 
51
- # NOTE: from ruby-mysql
52
- if defined? Encoding
53
- CHARSET_MAP = {
54
- "armscii8" => nil,
55
- "ascii" => Encoding::US_ASCII,
56
- "big5" => Encoding::Big5,
57
- "binary" => Encoding::ASCII_8BIT,
58
- "cp1250" => Encoding::Windows_1250,
59
- "cp1251" => Encoding::Windows_1251,
60
- "cp1256" => Encoding::Windows_1256,
61
- "cp1257" => Encoding::Windows_1257,
62
- "cp850" => Encoding::CP850,
63
- "cp852" => Encoding::CP852,
64
- "cp866" => Encoding::IBM866,
65
- "cp932" => Encoding::Windows_31J,
66
- "dec8" => nil,
67
- "eucjpms" => Encoding::EucJP_ms,
68
- "euckr" => Encoding::EUC_KR,
69
- "gb2312" => Encoding::EUC_CN,
70
- "gbk" => Encoding::GBK,
71
- "geostd8" => nil,
72
- "greek" => Encoding::ISO_8859_7,
73
- "hebrew" => Encoding::ISO_8859_8,
74
- "hp8" => nil,
75
- "keybcs2" => nil,
76
- "koi8r" => Encoding::KOI8_R,
77
- "koi8u" => Encoding::KOI8_U,
78
- "latin1" => Encoding::ISO_8859_1,
79
- "latin2" => Encoding::ISO_8859_2,
80
- "latin5" => Encoding::ISO_8859_9,
81
- "latin7" => Encoding::ISO_8859_13,
82
- "macce" => Encoding::MacCentEuro,
83
- "macroman" => Encoding::MacRoman,
84
- "sjis" => Encoding::SHIFT_JIS,
85
- "swe7" => nil,
86
- "tis620" => Encoding::TIS_620,
87
- "ucs2" => Encoding::UTF_16BE,
88
- "ujis" => Encoding::EucJP_ms,
89
- "utf8" => Encoding::UTF_8,
90
- }
91
-
92
- MYSQL_CHARSET_MAP = {
93
- 1 => {:name => "big5", :collation => "big5_chinese_ci"},
94
- 2 => {:name => "latin2", :collation => "latin2_czech_cs"},
95
- 3 => {:name => "dec8", :collation => "dec8_swedish_ci"},
96
- 4 => {:name => "cp850", :collation => "cp850_general_ci"},
97
- 5 => {:name => "latin1", :collation => "latin1_german1_ci"},
98
- 6 => {:name => "hp8", :collation => "hp8_english_ci"},
99
- 7 => {:name => "koi8r", :collation => "koi8r_general_ci"},
100
- 8 => {:name => "latin1", :collation => "latin1_swedish_ci"},
101
- 9 => {:name => "latin2", :collation => "latin2_general_ci"},
102
- 10 => {:name => "swe7", :collation => "swe7_swedish_ci"},
103
- 11 => {:name => "ascii", :collation => "ascii_general_ci"},
104
- 12 => {:name => "ujis", :collation => "ujis_japanese_ci"},
105
- 13 => {:name => "sjis", :collation => "sjis_japanese_ci"},
106
- 14 => {:name => "cp1251", :collation => "cp1251_bulgarian_ci"},
107
- 15 => {:name => "latin1", :collation => "latin1_danish_ci"},
108
- 16 => {:name => "hebrew", :collation => "hebrew_general_ci"},
109
- 17 => {:name => "filename", :collation => "filename"},
110
- 18 => {:name => "tis620", :collation => "tis620_thai_ci"},
111
- 19 => {:name => "euckr", :collation => "euckr_korean_ci"},
112
- 20 => {:name => "latin7", :collation => "latin7_estonian_cs"},
113
- 21 => {:name => "latin2", :collation => "latin2_hungarian_ci"},
114
- 22 => {:name => "koi8u", :collation => "koi8u_general_ci"},
115
- 23 => {:name => "cp1251", :collation => "cp1251_ukrainian_ci"},
116
- 24 => {:name => "gb2312", :collation => "gb2312_chinese_ci"},
117
- 25 => {:name => "greek", :collation => "greek_general_ci"},
118
- 26 => {:name => "cp1250", :collation => "cp1250_general_ci"},
119
- 27 => {:name => "latin2", :collation => "latin2_croatian_ci"},
120
- 28 => {:name => "gbk", :collation => "gbk_chinese_ci"},
121
- 29 => {:name => "cp1257", :collation => "cp1257_lithuanian_ci"},
122
- 30 => {:name => "latin5", :collation => "latin5_turkish_ci"},
123
- 31 => {:name => "latin1", :collation => "latin1_german2_ci"},
124
- 32 => {:name => "armscii8", :collation => "armscii8_general_ci"},
125
- 33 => {:name => "utf8", :collation => "utf8_general_ci"},
126
- 34 => {:name => "cp1250", :collation => "cp1250_czech_cs"},
127
- 35 => {:name => "ucs2", :collation => "ucs2_general_ci"},
128
- 36 => {:name => "cp866", :collation => "cp866_general_ci"},
129
- 37 => {:name => "keybcs2", :collation => "keybcs2_general_ci"},
130
- 38 => {:name => "macce", :collation => "macce_general_ci"},
131
- 39 => {:name => "macroman", :collation => "macroman_general_ci"},
132
- 40 => {:name => "cp852", :collation => "cp852_general_ci"},
133
- 41 => {:name => "latin7", :collation => "latin7_general_ci"},
134
- 42 => {:name => "latin7", :collation => "latin7_general_cs"},
135
- 43 => {:name => "macce", :collation => "macce_bin"},
136
- 44 => {:name => "cp1250", :collation => "cp1250_croatian_ci"},
137
- 47 => {:name => "latin1", :collation => "latin1_bin"},
138
- 48 => {:name => "latin1", :collation => "latin1_general_ci"},
139
- 49 => {:name => "latin1", :collation => "latin1_general_cs"},
140
- 50 => {:name => "cp1251", :collation => "cp1251_bin"},
141
- 51 => {:name => "cp1251", :collation => "cp1251_general_ci"},
142
- 52 => {:name => "cp1251", :collation => "cp1251_general_cs"},
143
- 53 => {:name => "macroman", :collation => "macroman_bin"},
144
- 57 => {:name => "cp1256", :collation => "cp1256_general_ci"},
145
- 58 => {:name => "cp1257", :collation => "cp1257_bin"},
146
- 59 => {:name => "cp1257", :collation => "cp1257_general_ci"},
147
- 63 => {:name => "binary", :collation => "binary"},
148
- 64 => {:name => "armscii8", :collation => "armscii8_bin"},
149
- 65 => {:name => "ascii", :collation => "ascii_bin"},
150
- 66 => {:name => "cp1250", :collation => "cp1250_bin"},
151
- 67 => {:name => "cp1256", :collation => "cp1256_bin"},
152
- 68 => {:name => "cp866", :collation => "cp866_bin"},
153
- 69 => {:name => "dec8", :collation => "dec8_bin"},
154
- 70 => {:name => "greek", :collation => "greek_bin"},
155
- 71 => {:name => "hebrew", :collation => "hebrew_bin"},
156
- 72 => {:name => "hp8", :collation => "hp8_bin"},
157
- 73 => {:name => "keybcs2", :collation => "keybcs2_bin"},
158
- 74 => {:name => "koi8r", :collation => "koi8r_bin"},
159
- 75 => {:name => "koi8u", :collation => "koi8u_bin"},
160
- 77 => {:name => "latin2", :collation => "latin2_bin"},
161
- 78 => {:name => "latin5", :collation => "latin5_bin"},
162
- 79 => {:name => "latin7", :collation => "latin7_bin"},
163
- 80 => {:name => "cp850", :collation => "cp850_bin"},
164
- 81 => {:name => "cp852", :collation => "cp852_bin"},
165
- 82 => {:name => "swe7", :collation => "swe7_bin"},
166
- 83 => {:name => "utf8", :collation => "utf8_bin"},
167
- 84 => {:name => "big5", :collation => "big5_bin"},
168
- 85 => {:name => "euckr", :collation => "euckr_bin"},
169
- 86 => {:name => "gb2312", :collation => "gb2312_bin"},
170
- 87 => {:name => "gbk", :collation => "gbk_bin"},
171
- 88 => {:name => "sjis", :collation => "sjis_bin"},
172
- 89 => {:name => "tis620", :collation => "tis620_bin"},
173
- 90 => {:name => "ucs2", :collation => "ucs2_bin"},
174
- 91 => {:name => "ujis", :collation => "ujis_bin"},
175
- 92 => {:name => "geostd8", :collation => "geostd8_general_ci"},
176
- 93 => {:name => "geostd8", :collation => "geostd8_bin"},
177
- 94 => {:name => "latin1", :collation => "latin1_spanish_ci"},
178
- 95 => {:name => "cp932", :collation => "cp932_japanese_ci"},
179
- 96 => {:name => "cp932", :collation => "cp932_bin"},
180
- 97 => {:name => "eucjpms", :collation => "eucjpms_japanese_ci"},
181
- 98 => {:name => "eucjpms", :collation => "eucjpms_bin"},
182
- 99 => {:name => "cp1250", :collation => "cp1250_polish_ci"},
183
- 128 => {:name => "ucs2", :collation => "ucs2_unicode_ci"},
184
- 129 => {:name => "ucs2", :collation => "ucs2_icelandic_ci"},
185
- 130 => {:name => "ucs2", :collation => "ucs2_latvian_ci"},
186
- 131 => {:name => "ucs2", :collation => "ucs2_romanian_ci"},
187
- 132 => {:name => "ucs2", :collation => "ucs2_slovenian_ci"},
188
- 133 => {:name => "ucs2", :collation => "ucs2_polish_ci"},
189
- 134 => {:name => "ucs2", :collation => "ucs2_estonian_ci"},
190
- 135 => {:name => "ucs2", :collation => "ucs2_spanish_ci"},
191
- 136 => {:name => "ucs2", :collation => "ucs2_swedish_ci"},
192
- 137 => {:name => "ucs2", :collation => "ucs2_turkish_ci"},
193
- 138 => {:name => "ucs2", :collation => "ucs2_czech_ci"},
194
- 139 => {:name => "ucs2", :collation => "ucs2_danish_ci"},
195
- 140 => {:name => "ucs2", :collation => "ucs2_lithuanian_ci"},
196
- 141 => {:name => "ucs2", :collation => "ucs2_slovak_ci"},
197
- 142 => {:name => "ucs2", :collation => "ucs2_spanish2_ci"},
198
- 143 => {:name => "ucs2", :collation => "ucs2_roman_ci"},
199
- 144 => {:name => "ucs2", :collation => "ucs2_persian_ci"},
200
- 145 => {:name => "ucs2", :collation => "ucs2_esperanto_ci"},
201
- 146 => {:name => "ucs2", :collation => "ucs2_hungarian_ci"},
202
- 192 => {:name => "utf8", :collation => "utf8_unicode_ci"},
203
- 193 => {:name => "utf8", :collation => "utf8_icelandic_ci"},
204
- 194 => {:name => "utf8", :collation => "utf8_latvian_ci"},
205
- 195 => {:name => "utf8", :collation => "utf8_romanian_ci"},
206
- 196 => {:name => "utf8", :collation => "utf8_slovenian_ci"},
207
- 197 => {:name => "utf8", :collation => "utf8_polish_ci"},
208
- 198 => {:name => "utf8", :collation => "utf8_estonian_ci"},
209
- 199 => {:name => "utf8", :collation => "utf8_spanish_ci"},
210
- 200 => {:name => "utf8", :collation => "utf8_swedish_ci"},
211
- 201 => {:name => "utf8", :collation => "utf8_turkish_ci"},
212
- 202 => {:name => "utf8", :collation => "utf8_czech_ci"},
213
- 203 => {:name => "utf8", :collation => "utf8_danish_ci"},
214
- 204 => {:name => "utf8", :collation => "utf8_lithuanian_ci"},
215
- 205 => {:name => "utf8", :collation => "utf8_slovak_ci"},
216
- 206 => {:name => "utf8", :collation => "utf8_spanish2_ci"},
217
- 207 => {:name => "utf8", :collation => "utf8_roman_ci"},
218
- 208 => {:name => "utf8", :collation => "utf8_persian_ci"},
219
- 209 => {:name => "utf8", :collation => "utf8_esperanto_ci"},
220
- 210 => {:name => "utf8", :collation => "utf8_hungarian_ci"},
221
- 254 => {:name => "utf8", :collation => "utf8_general_cs"}
222
- }
223
-
224
- def self.encoding_from_charset(charset)
225
- CHARSET_MAP[charset.to_s.downcase]
226
- end
227
-
228
- def self.encoding_from_charset_code(code)
229
- if mapping = MYSQL_CHARSET_MAP[code]
230
- encoding_from_charset(mapping[:name])
231
- else
232
- nil
233
- end
234
- end
77
+ def query_info
78
+ info = query_info_string
79
+ return {} unless info
80
+ info_hash = {}
81
+ info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
82
+ info_hash
235
83
  end
236
84
 
237
85
  private
@@ -0,0 +1,5 @@
1
+ # Loaded by script/console. Land helpers here.
2
+
3
+ Pry.config.prompt = lambda do |context, nesting, pry|
4
+ "[mysql2] #{context}> "
5
+ end
@@ -10,23 +10,42 @@ module Mysql2
10
10
  def initialize(client, deferable)
11
11
  @client = client
12
12
  @deferable = deferable
13
+ @is_watching = true
13
14
  end
14
15
 
15
16
  def notify_readable
16
17
  detach
17
18
  begin
18
- @deferable.succeed(@client.async_result)
19
+ result = @client.async_result
19
20
  rescue Exception => e
20
21
  @deferable.fail(e)
22
+ else
23
+ @deferable.succeed(result)
21
24
  end
22
25
  end
26
+
27
+ def watching?
28
+ @is_watching
29
+ end
30
+
31
+ def unbind
32
+ @is_watching = false
33
+ end
34
+ end
35
+
36
+ def close(*args)
37
+ if @watch
38
+ @watch.detach if @watch.watching?
39
+ end
40
+ super(*args)
23
41
  end
24
42
 
25
43
  def query(sql, opts={})
26
44
  if ::EM.reactor_running?
27
45
  super(sql, opts.merge(:async => true))
28
46
  deferable = ::EM::DefaultDeferrable.new
29
- ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
47
+ @watch = ::EM.watch(self.socket, Watcher, self, deferable)
48
+ @watch.notify_readable = true
30
49
  deferable
31
50
  else
32
51
  super(sql, opts)
@@ -34,4 +53,4 @@ module Mysql2
34
53
  end
35
54
  end
36
55
  end
37
- end
56
+ end
@@ -1,15 +1,80 @@
1
+ # encoding: UTF-8
2
+
1
3
  module Mysql2
2
4
  class Error < StandardError
3
- attr_accessor :error_number, :sql_state
5
+ REPLACEMENT_CHAR = '?'
6
+ ENCODE_OPTS = {:undef => :replace, :invalid => :replace, :replace => REPLACEMENT_CHAR}
4
7
 
5
- def initialize msg
6
- super
7
- @error_number = nil
8
- @sql_state = nil
9
- end
8
+ attr_accessor :error_number
9
+ attr_reader :sql_state
10
+ attr_writer :server_version
10
11
 
11
12
  # Mysql gem compatibility
12
13
  alias_method :errno, :error_number
13
14
  alias_method :error, :message
15
+
16
+ def initialize(msg, server_version=nil)
17
+ self.server_version = server_version
18
+
19
+ super(clean_message(msg))
20
+ end
21
+
22
+ def sql_state=(state)
23
+ @sql_state = ''.respond_to?(:encode) ? state.encode(ENCODE_OPTS) : state
24
+ end
25
+
26
+ private
27
+
28
+ # In MySQL 5.5+ error messages are always constructed server-side as UTF-8
29
+ # then returned in the encoding set by the `character_set_results` system
30
+ # variable.
31
+ #
32
+ # See http://dev.mysql.com/doc/refman/5.5/en/charset-errors.html for
33
+ # more contetx.
34
+ #
35
+ # Before MySQL 5.5 error message template strings are in whatever encoding
36
+ # is associated with the error message language.
37
+ # See http://dev.mysql.com/doc/refman/5.1/en/error-message-language.html
38
+ # for more information.
39
+ #
40
+ # The issue is that the user-data inserted in the message could potentially
41
+ # be in any encoding MySQL supports and is insert into the latin1, euckr or
42
+ # koi8r string raw. Meaning there's a high probability the string will be
43
+ # corrupt encoding-wise.
44
+ #
45
+ # See http://dev.mysql.com/doc/refman/5.1/en/charset-errors.html for
46
+ # more information.
47
+ #
48
+ # So in an attempt to make sure the error message string is always in a valid
49
+ # encoding, we'll assume UTF-8 and clean the string of anything that's not a
50
+ # valid UTF-8 character.
51
+ #
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
55
+ def clean_message(message)
56
+ return message if !message.respond_to?(:encoding)
57
+
58
+ if @server_version && @server_version > 50500
59
+ message.encode(ENCODE_OPTS)
60
+ 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
77
+ end
78
+ end
14
79
  end
15
80
  end