Skip to content

Commit 3ca5204

Browse files
committed
Merge pull request #459 from sodabrew/binary_error_strings
If the server version is less than 5.5, set the error text to binary
2 parents a9787cb + 3f3c7be commit 3ca5204

File tree

3 files changed

+79
-56
lines changed

3 files changed

+79
-56
lines changed

ext/mysql2/client.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,21 @@ static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
126126
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
127127
VALUE e;
128128
#ifdef HAVE_RUBY_ENCODING_H
129-
rb_encoding *default_internal_enc = rb_default_internal_encoding();
130-
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
131-
132-
rb_enc_associate(rb_error_msg, conn_enc);
133-
rb_enc_associate(rb_sql_state, conn_enc);
134-
if (default_internal_enc) {
135-
rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
136-
rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
129+
if (wrapper->server_version < 50500) {
130+
/* MySQL < 5.5 uses mixed encoding, just call it binary. */
131+
int err_enc = rb_ascii8bit_encindex();
132+
rb_enc_associate_index(rb_error_msg, err_enc);
133+
rb_enc_associate_index(rb_sql_state, err_enc);
134+
} else {
135+
/* MySQL >= 5.5 uses UTF-8 errors internally and converts them to the connection encoding. */
136+
rb_encoding *default_internal_enc = rb_default_internal_encoding();
137+
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
138+
rb_enc_associate(rb_error_msg, conn_enc);
139+
rb_enc_associate(rb_sql_state, conn_enc);
140+
if (default_internal_enc) {
141+
rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
142+
rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
143+
}
137144
}
138145
#endif
139146

@@ -219,6 +226,7 @@ static VALUE allocate(VALUE klass) {
219226
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
220227
wrapper->encoding = Qnil;
221228
wrapper->active_thread = Qnil;
229+
wrapper->server_version = 0;
222230
wrapper->reconnect_enabled = 0;
223231
wrapper->connected = 0; /* means that a database connection is open */
224232
wrapper->initialized = 0; /* means that that the wrapper is initialized */
@@ -311,6 +319,7 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
311319
return rb_raise_mysql2_error(wrapper);
312320
}
313321

322+
wrapper->server_version = mysql_get_server_version(wrapper->client);
314323
wrapper->connected = 1;
315324
return self;
316325
}

ext/mysql2/client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ rb_thread_call_without_gvl(
3939
typedef struct {
4040
VALUE encoding;
4141
VALUE active_thread; /* rb_thread_current() or Qnil */
42+
long server_version;
4243
int reconnect_enabled;
4344
int active;
4445
int connected;

spec/mysql2/error_spec.rb

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,86 @@
11
# encoding: UTF-8
22
require 'spec_helper'
33

4+
# The matrix of error encoding tests:
5+
# ('Enc = X' means 'Encoding.default_internal = X')
6+
# MySQL < 5.5 MySQL >= 5.5
7+
# Ruby 1.8 N/A N/A
8+
# Ruby 1.9+
9+
# Enc = nil
10+
# :enc = nil BINARY UTF-8
11+
#
12+
# Enc = XYZ
13+
# :enc = XYZ BINARY XYZ
14+
#
15+
# Enc = FOO
16+
# :enc = BAR BINARY FOO
17+
#
18+
19+
420
describe Mysql2::Error do
5-
before(:each) do
21+
shared_examples "mysql2 error" do
622
begin
7-
@err_client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8"))
8-
@err_client.query("HAHAHA")
23+
err_client = Mysql2::Client.new(DatabaseCredentials['root'])
24+
err_client.query("HAHAHA")
925
rescue Mysql2::Error => e
10-
@error = e
26+
error = e
1127
ensure
12-
@err_client.close
28+
err_client.close
1329
end
1430

31+
subject { error }
32+
it { should respond_to(:error_number) }
33+
it { should respond_to(:sql_state) }
34+
35+
# Mysql gem compatibility
36+
it { should respond_to(:errno) }
37+
it { should respond_to(:error) }
38+
end
39+
40+
shared_examples "mysql2 error encoding" do |db_enc, def_enc, err_enc|
41+
Encoding.default_internal = def_enc
42+
1543
begin
16-
@err_client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5"))
17-
@err_client2.query("HAHAHA")
44+
err_client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => db_enc))
45+
err_client.query("造字")
1846
rescue Mysql2::Error => e
19-
@error2 = e
47+
error = e
2048
ensure
21-
@err_client2.close
49+
err_client.close
2250
end
23-
end
2451

25-
it "should respond to #error_number" do
26-
@error.should respond_to(:error_number)
27-
end
52+
subject { error.message.encoding }
53+
it "#message should transcode from #{db_enc.inspect} to #{err_enc}" do should eql(err_enc) end
2854

29-
it "should respond to #sql_state" do
30-
@error.should respond_to(:sql_state)
31-
end
55+
subject { error.error.encoding }
56+
it "#error should transcode from #{db_enc.inspect} to #{err_enc}" do should eql(err_enc) end
3257

33-
# Mysql gem compatibility
34-
it "should alias #error_number to #errno" do
35-
@error.should respond_to(:errno)
58+
subject { error.sql_state.encoding }
59+
it "#sql_state should transcode from #{db_enc.inspect} to #{err_enc}" do should eql(err_enc) end
3660
end
3761

38-
it "should alias #message to #error" do
39-
@error.should respond_to(:error)
62+
shared_examples "mysql2 error encoding (MySQL < 5.5)" do |db_enc, def_enc, err_enc|
63+
include_examples "mysql2 error encoding", db_enc, def_enc, err_enc
4064
end
4165

42-
unless RUBY_VERSION =~ /1.8/
43-
it "#message encoding should match the connection's encoding, or Encoding.default_internal if set" do
44-
if Encoding.default_internal.nil?
45-
@error.message.encoding.should eql(@err_client.encoding)
46-
@error2.message.encoding.should eql(@err_client2.encoding)
47-
else
48-
@error.message.encoding.should eql(Encoding.default_internal)
49-
@error2.message.encoding.should eql(Encoding.default_internal)
50-
end
51-
end
66+
shared_examples "mysql2 error encoding (MySQL >= 5.5)" do |db_enc, def_enc, err_enc|
67+
include_examples "mysql2 error encoding", db_enc, def_enc, err_enc
68+
end
5269

53-
it "#error encoding should match the connection's encoding, or Encoding.default_internal if set" do
54-
if Encoding.default_internal.nil?
55-
@error.error.encoding.should eql(@err_client.encoding)
56-
@error2.error.encoding.should eql(@err_client2.encoding)
57-
else
58-
@error.error.encoding.should eql(Encoding.default_internal)
59-
@error2.error.encoding.should eql(Encoding.default_internal)
60-
end
61-
end
70+
it_behaves_like "mysql2 error"
6271

63-
it "#sql_state encoding should match the connection's encoding, or Encoding.default_internal if set" do
64-
if Encoding.default_internal.nil?
65-
@error.sql_state.encoding.should eql(@err_client.encoding)
66-
@error2.sql_state.encoding.should eql(@err_client2.encoding)
67-
else
68-
@error.sql_state.encoding.should eql(Encoding.default_internal)
69-
@error2.sql_state.encoding.should eql(Encoding.default_internal)
70-
end
72+
unless RUBY_VERSION =~ /1.8/
73+
mysql_ver = Mysql2::Client.new(DatabaseCredentials['root']).server_info[:id]
74+
if mysql_ver < 50505
75+
it_behaves_like "mysql2 error encoding (MySQL < 5.5)", nil, nil, Encoding::ASCII_8BIT
76+
it_behaves_like "mysql2 error encoding (MySQL < 5.5)", 'utf8', Encoding::UTF_8, Encoding::ASCII_8BIT
77+
it_behaves_like "mysql2 error encoding (MySQL < 5.5)", 'big5', Encoding::Big5, Encoding::ASCII_8BIT
78+
it_behaves_like "mysql2 error encoding (MySQL < 5.5)", 'big5', Encoding::US_ASCII, Encoding::ASCII_8BIT
79+
else
80+
it_behaves_like "mysql2 error encoding (MySQL >= 5.5)", nil, nil, Encoding::UTF_8
81+
it_behaves_like "mysql2 error encoding (MySQL >= 5.5)", 'utf8', Encoding::UTF_8, Encoding::UTF_8
82+
it_behaves_like "mysql2 error encoding (MySQL >= 5.5)", 'big5', Encoding::Big5, Encoding::Big5
83+
it_behaves_like "mysql2 error encoding (MySQL >= 5.5)", 'big5', Encoding::US_ASCII, Encoding::US_ASCII
7184
end
7285
end
7386
end

0 commit comments

Comments
 (0)