From c5f2eb7f3fcd6ff704aa041b8eb69700ab7cdb9f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 20 Aug 2010 10:14:49 -0700 Subject: [PATCH 1/6] adding FOUND_ROWS to the client flags --- lib/active_record/connection_adapters/mysql2_adapter.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index b5ee9cd..e4ab71d 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -6,6 +6,11 @@ module ActiveRecord class Base def self.mysql2_connection(config) config[:username] = 'root' if config[:username].nil? + + if Mysql2::Client.const_defined? :FOUND_ROWS + config[:flags] = Mysql2::Client::FOUND_ROWS + end + client = Mysql2::Client.new(config.symbolize_keys) options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0] ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) From a19888e939b2cccf6c433103533b4f8942706357 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 20 Aug 2010 12:07:27 -0700 Subject: [PATCH 2/6] Make sure we switch over to the DateTime class for DATETIME/TIMESTAMP columns that are out of the supported range for 32bit platforms --- ext/mysql2/result.c | 34 ++++++++++++++++++++++------------ lib/mysql2.rb | 1 + lib/mysql2/client.rb | 5 +++++ spec/mysql2/result_spec.rb | 9 +++++++-- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index 9df4131..e237b1b 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -10,7 +10,7 @@ VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month; extern VALUE mMysql2, cMysql2Client, cMysql2Error; static VALUE intern_encoding_from_charset; static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code, - intern_localtime; + intern_localtime, intern_local_offset, intern_civil; static ID sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone, sym_local, sym_utc, sym_cast_booleans; static ID intern_merge; @@ -190,12 +190,20 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo rb_raise(cMysql2Error, "Invalid date: %s", row[i]); val = Qnil; } else { - val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)); - if (!NIL_P(app_timezone)) { - if (app_timezone == intern_local) { - val = rb_funcall(val, intern_localtime, 0); - } else { // utc - val = rb_funcall(val, intern_utc, 0); + if (year < 1902 || year+month+day > 2058) { // use DateTime instead + VALUE offset = INT2NUM(0); + if (db_timezone == intern_local) { + offset = rb_funcall(cMysql2Client, rb_intern("local_offset"), 0); + } + val = rb_funcall(cDateTime, intern_civil, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset); + } else { + val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)); + if (!NIL_P(app_timezone)) { + if (app_timezone == intern_local) { + val = rb_funcall(val, intern_localtime, 0); + } else { // utc + val = rb_funcall(val, intern_utc, 0); + } } } } @@ -420,11 +428,13 @@ void init_mysql2_result() { intern_encoding_from_charset = rb_intern("encoding_from_charset"); intern_encoding_from_charset_code = rb_intern("encoding_from_charset_code"); - intern_new = rb_intern("new"); - intern_utc = rb_intern("utc"); - intern_local = rb_intern("local"); - intern_merge = rb_intern("merge"); - intern_localtime = rb_intern("localtime"); + intern_new = rb_intern("new"); + intern_utc = rb_intern("utc"); + intern_local = rb_intern("local"); + intern_merge = rb_intern("merge"); + intern_localtime = rb_intern("localtime"); + intern_local_offset = rb_intern("local_offset"); + intern_civil = rb_intern("civil"); sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys")); sym_as = ID2SYM(rb_intern("as")); diff --git a/lib/mysql2.rb b/lib/mysql2.rb index 5446d2f..12bc28f 100644 --- a/lib/mysql2.rb +++ b/lib/mysql2.rb @@ -1,6 +1,7 @@ # encoding: UTF-8 require 'date' require 'bigdecimal' +require 'rational' unless RUBY_VERSION >= '1.9.2' require 'mysql2/error' require 'mysql2/mysql2' diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index cbb6a60..732508d 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -224,5 +224,10 @@ module Mysql2 end end end + + private + def self.local_offset + ::Time.local(2010).utc_offset.to_r / 86400 + end end end diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index fd230cb..ee3820d 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -143,12 +143,17 @@ describe Mysql2::Result do @test_result['double_test'].should eql(10.3) end - it "should return Time for a DATETIME value" do + it "should return Time for a DATETIME value when within the supported range" do @test_result['date_time_test'].class.should eql(Time) @test_result['date_time_test'].strftime("%F %T").should eql('2010-04-04 11:44:00') end - it "should return Time for a TIMESTAMP value" do + it "should return DateTime for a DATETIME value when outside the supported range" do + r = @client.query("SELECT CAST('1901-1-1 01:01:01' AS DATETIME) as test") + r.first['test'].class.should eql(DateTime) + end + + it "should return Time for a TIMESTAMP value when within the supported range" do @test_result['timestamp_test'].class.should eql(Time) @test_result['timestamp_test'].strftime("%F %T").should eql('2010-04-04 11:44:00') end From e56c79894c5e2d009466b96fa6b60bcc61ea2188 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 20 Aug 2010 12:08:29 -0700 Subject: [PATCH 3/6] fix compiler warning --- ext/mysql2/result.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index e237b1b..f788f1c 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -127,7 +127,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo for (i = 0; i < wrapper->numberOfFields; i++) { VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys); if (row[i]) { - VALUE val; + VALUE val = Qnil; switch(fields[i].type) { case MYSQL_TYPE_NULL: // NULL-type field val = Qnil; From dd5f5635545f12abf7be654be47a2033079ffec6 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 20 Aug 2010 15:13:08 -0700 Subject: [PATCH 4/6] make sure we respect application_timezone for DateTime values as well --- ext/mysql2/result.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index f788f1c..5c7302e 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -6,11 +6,11 @@ rb_encoding *binaryEncoding; VALUE cMysql2Result; VALUE cBigDecimal, cDate, cDateTime; -VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month; +VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset; extern VALUE mMysql2, cMysql2Client, cMysql2Error; static VALUE intern_encoding_from_charset; static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code, - intern_localtime, intern_local_offset, intern_civil; + intern_localtime, intern_local_offset, intern_civil, intern_new_offset; static ID sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone, sym_local, sym_utc, sym_cast_booleans; static ID intern_merge; @@ -193,9 +193,17 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo if (year < 1902 || year+month+day > 2058) { // use DateTime instead VALUE offset = INT2NUM(0); if (db_timezone == intern_local) { - offset = rb_funcall(cMysql2Client, rb_intern("local_offset"), 0); + offset = rb_funcall(cMysql2Client, intern_local_offset, 0); } val = rb_funcall(cDateTime, intern_civil, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset); + if (!NIL_P(app_timezone)) { + if (app_timezone == intern_local) { + offset = rb_funcall(cMysql2Client, intern_local_offset, 0); + val = rb_funcall(val, intern_new_offset, 1, offset); + } else { // utc + val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset); + } + } } else { val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)); if (!NIL_P(app_timezone)) { @@ -435,6 +443,7 @@ void init_mysql2_result() { intern_localtime = rb_intern("localtime"); intern_local_offset = rb_intern("local_offset"); intern_civil = rb_intern("civil"); + intern_new_offset = rb_intern("new_offset"); sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys")); sym_as = ID2SYM(rb_intern("as")); @@ -451,6 +460,7 @@ void init_mysql2_result() { opt_float_zero = rb_float_new((double)0); opt_time_year = INT2NUM(2000); opt_time_month = INT2NUM(1); + opt_utc_offset = INT2NUM(0); #ifdef HAVE_RUBY_ENCODING_H binaryEncoding = rb_enc_find("binary"); From 15da806495607a9e5e3180f7cc8308b27806227d Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 20 Aug 2010 20:23:38 -0700 Subject: [PATCH 5/6] Version bump to 0.2.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ee1372d..7179039 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.2 +0.2.3 From 17cabf55594cb4fa85b2286efd2103e368ce74bd Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 20 Aug 2010 20:24:00 -0700 Subject: [PATCH 6/6] update files for 0.2.3 release --- CHANGELOG.md | 7 ++++++- lib/mysql2.rb | 2 +- mysql2.gemspec | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42d5ee7..2f413d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -# 0.2.2 (August 19th, 2010) +## 0.2.3 (August 20th, 2010) +* connection flags can now be passed to the constructor via the :flags key +* switch AR adapter connection over to use FOUND_ROWS option +* patch to ensure we use DateTime objects in place of Time for timestamps that are out of the supported range on 32bit platforms < 1.9.2 + +## 0.2.2 (August 19th, 2010) * Change how AR adapter would send initial commands upon connecting ** we can make multiple session variable assignments in a single query * fix signal handling when waiting on queries diff --git a/lib/mysql2.rb b/lib/mysql2.rb index 12bc28f..52ae5a5 100644 --- a/lib/mysql2.rb +++ b/lib/mysql2.rb @@ -12,5 +12,5 @@ require 'mysql2/result' # # A modern, simple and very fast Mysql library for Ruby - binding to libmysql module Mysql2 - VERSION = "0.2.2" + VERSION = "0.2.3" end diff --git a/mysql2.gemspec b/mysql2.gemspec index f84097f..e49757f 100644 --- a/mysql2.gemspec +++ b/mysql2.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = %q{mysql2} - s.version = "0.2.2" + s.version = "0.2.3" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Brian Lopez"] - s.date = %q{2010-08-19} + s.date = %q{2010-08-20} s.email = %q{seniorlopez@gmail.com} s.extensions = ["ext/mysql2/extconf.rb"] s.extra_rdoc_files = [