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/VERSION b/VERSION index ee1372d..7179039 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.2 +0.2.3 diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index 9df4131..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_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; @@ -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; @@ -190,12 +190,28 @@ 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, 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)) { + if (app_timezone == intern_local) { + val = rb_funcall(val, intern_localtime, 0); + } else { // utc + val = rb_funcall(val, intern_utc, 0); + } } } } @@ -420,11 +436,14 @@ 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"); + intern_new_offset = rb_intern("new_offset"); sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys")); sym_as = ID2SYM(rb_intern("as")); @@ -441,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"); 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) diff --git a/lib/mysql2.rb b/lib/mysql2.rb index 6bdadb6..934b92e 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' @@ -12,5 +13,5 @@ require 'mysql2/field' # # 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/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/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 = [ 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