Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cast the BIT(1) type when :cast_booleans is true for prepared statements #903

Merged
merged 5 commits into from
Nov 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ext/mysql2/result.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,13 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
val = INT2NUM(*((signed char*)result_buffer->buffer));
}
break;
case MYSQL_TYPE_BIT: /* BIT field (MySQL 5.0.3 and up) */
if (args->castBool && fields[i].length == 1) {
val = (*((unsigned char*)result_buffer->buffer) != 0) ? Qtrue : Qfalse;
}else{
val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
}
break;
case MYSQL_TYPE_SHORT: // short int
if (result_buffer->is_unsigned) {
val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
Expand Down Expand Up @@ -494,7 +501,6 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
case MYSQL_TYPE_BLOB: // char[]
case MYSQL_TYPE_MEDIUM_BLOB: // char[]
case MYSQL_TYPE_LONG_BLOB: // char[]
case MYSQL_TYPE_BIT: // char[]
case MYSQL_TYPE_SET: // char[]
case MYSQL_TYPE_ENUM: // char[]
case MYSQL_TYPE_GEOMETRY: // char[]
Expand Down
4 changes: 2 additions & 2 deletions spec/mysql2/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ def run_gc
end

it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.server_info.fetch(:version).start_with?('5.5')
if RUBY_PLATFORM.include?('darwin') && @client.server_info.fetch(:version).start_with?('5.5')
pending('MySQL 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
end

Expand All @@ -615,7 +615,7 @@ def run_gc
end

it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction" do
if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.server_info.fetch(:version).start_with?('5.5')
if RUBY_PLATFORM.include?('darwin') && @client.server_info.fetch(:version).start_with?('5.5')
pending('MySQL 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
end

Expand Down
75 changes: 43 additions & 32 deletions spec/mysql2/statement_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -374,36 +374,47 @@ def stmt_count
expect(@test_result['tiny_int_test']).to eql(1)
end

it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
@client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (1)'
id1 = @client.last_id
@client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
id2 = @client.last_id
@client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (-1)'
id3 = @client.last_id

result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
result3 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = -1 LIMIT 1', :cast_booleans => true
expect(result1.first['bool_cast_test']).to be true
expect(result2.first['bool_cast_test']).to be false
expect(result3.first['bool_cast_test']).to be true
context "cast booleans for TINYINY if :cast_booleans is enabled" do
# rubocop:disable Style/Semicolon
let(:client) { new_client(:cast_booleans => true) }
let(:id1) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 1)'; client.last_id }
let(:id2) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 0)'; client.last_id }
let(:id3) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (-1)'; client.last_id }
# rubocop:enable Style/Semicolon

after do
client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
end

@client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
query = client.prepare 'SELECT bool_cast_test FROM mysql2_test WHERE id = ?'
result1 = query.execute id1
result2 = query.execute id2
result3 = query.execute id3
expect(result1.first['bool_cast_test']).to be true
expect(result2.first['bool_cast_test']).to be false
expect(result3.first['bool_cast_test']).to be true
end
end

it "should return TrueClass or FalseClass for a BIT(1) value if :cast_booleans is enabled" do
@client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (1)'
id1 = @client.last_id
@client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (0)'
id2 = @client.last_id
context "cast booleans for BIT(1) if :cast_booleans is enabled" do
# rubocop:disable Style/Semicolon
let(:client) { new_client(:cast_booleans => true) }
let(:id1) { client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (1)'; client.last_id }
let(:id2) { client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (0)'; client.last_id }
# rubocop:enable Style/Semicolon

result1 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id1}", :cast_booleans => true
result2 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id2}", :cast_booleans => true
expect(result1.first['single_bit_test']).to be true
expect(result2.first['single_bit_test']).to be false
after do
client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
end

@client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
it "should return TrueClass or FalseClass for a BIT(1) value if :cast_booleans is enabled" do
query = client.prepare 'SELECT single_bit_test FROM mysql2_test WHERE id = ?'
result1 = query.execute id1
result2 = query.execute id2
expect(result1.first['single_bit_test']).to be true
expect(result2.first['single_bit_test']).to be false
end
end

it "should return Fixnum for a SMALLINT value" do
Expand Down Expand Up @@ -460,39 +471,39 @@ def stmt_count

it "should return DateTime when timestamp is < 1901-12-13 20:45:52" do
# 1901-12-13T20:45:52 is the min for 32bit Ruby 1.8
r = @client.query("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(klass)
end

it "should return DateTime when timestamp is > 2038-01-19T03:14:07" do
# 2038-01-19T03:14:07 is the max for 32bit Ruby 1.8
r = @client.query("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(klass)
end
elsif 1.size == 8 # 64bit
if RUBY_VERSION =~ /1.8/
it "should return Time when timestamp is > 0138-12-31 11:59:59" do
r = @client.query("SELECT CAST('0139-1-1 00:00:00' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('0139-1-1 00:00:00' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(Time)
end

it "should return DateTime when timestamp is < 0139-1-1T00:00:00" do
r = @client.query("SELECT CAST('0138-12-31 11:59:59' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('0138-12-31 11:59:59' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(DateTime)
end

it "should return Time when timestamp is > 2038-01-19T03:14:07" do
r = @client.query("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(Time)
end
else
it "should return Time when timestamp is < 1901-12-13 20:45:52" do
r = @client.query("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(Time)
end

it "should return Time when timestamp is > 2038-01-19T03:14:07" do
r = @client.query("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test")
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
expect(r.first['test']).to be_an_instance_of(Time)
end
end
Expand Down