add support for configuring which timezone Time objects should be created in
This commit is contained in:
parent
f3151db928
commit
fc6c24a20c
@ -100,6 +100,10 @@ The default result type is set to :hash, but you can override a previous setting
|
||||
I may add support for {:as => :csv} or even {:as => :json} to allow for *much* more efficient generation of those data types from result sets.
|
||||
If you'd like to see either of these (or others), open an issue and start bugging me about it ;)
|
||||
|
||||
== Timezones
|
||||
|
||||
You can set the :timezone option to :local or :utc to tell Mysql2 which timezone you'd like to have Time objects in
|
||||
|
||||
== Async
|
||||
|
||||
Mysql2::Client takes advantage of the MySQL C API's (undocumented) non-blocking function mysql_send_query for *all* queries.
|
||||
|
@ -5,7 +5,7 @@ require 'rubygems'
|
||||
require 'benchmark'
|
||||
require 'active_record'
|
||||
|
||||
ActiveRecord::Base.default_timezone = 'Pacific Time (US & Canada)'
|
||||
ActiveRecord::Base.default_timezone = :local
|
||||
ActiveRecord::Base.time_zone_aware_attributes = true
|
||||
|
||||
number_of = 10
|
||||
|
@ -1,7 +1,8 @@
|
||||
#include <mysql2_ext.h>
|
||||
|
||||
VALUE mMysql2, cMysql2Error, intern_encoding_from_charset;
|
||||
ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
|
||||
ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as,
|
||||
sym_array, sym_timezone, sym_utc, sym_local;
|
||||
ID intern_merge;
|
||||
|
||||
/* Ruby Extension initializer */
|
||||
@ -11,6 +12,9 @@ void Init_mysql2() {
|
||||
|
||||
intern_merge = rb_intern("merge");
|
||||
|
||||
sym_timezone = ID2SYM(rb_intern("timezone"));
|
||||
sym_utc = ID2SYM(rb_intern("utc"));
|
||||
sym_local = ID2SYM(rb_intern("local"));
|
||||
sym_array = ID2SYM(rb_intern("array"));
|
||||
sym_as = ID2SYM(rb_intern("as"));
|
||||
sym_id = ID2SYM(rb_intern("id"));
|
||||
|
@ -4,12 +4,12 @@
|
||||
rb_encoding *binaryEncoding;
|
||||
#endif
|
||||
|
||||
ID intern_new, intern_utc, intern_encoding_from_charset_code;
|
||||
ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code;
|
||||
|
||||
VALUE cMysql2Result;
|
||||
VALUE cBigDecimal, cDate, cDateTime;
|
||||
extern VALUE mMysql2, cMysql2Client, cMysql2Error, intern_encoding_from_charset;
|
||||
extern ID sym_symbolize_keys, sym_as, sym_array;
|
||||
extern ID sym_symbolize_keys, sym_as, sym_array, sym_timezone, sym_local, sym_utc;
|
||||
extern ID intern_merge;
|
||||
|
||||
static void rb_mysql_result_mark(void * wrapper) {
|
||||
@ -86,13 +86,12 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
||||
return rb_field;
|
||||
}
|
||||
|
||||
static VALUE rb_mysql_result_fetch_row(VALUE self, VALUE opts) {
|
||||
static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKeys, int asArray) {
|
||||
VALUE rowVal;
|
||||
mysql2_result_wrapper * wrapper;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_FIELD * fields = NULL;
|
||||
unsigned int i = 0;
|
||||
int symbolizeKeys = 0, asArray = 0;
|
||||
unsigned long * fieldLengths;
|
||||
void * ptr;
|
||||
#ifdef HAVE_RUBY_ENCODING_H
|
||||
@ -102,14 +101,6 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, VALUE opts) {
|
||||
|
||||
GetMysql2Result(self, wrapper);
|
||||
|
||||
if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
|
||||
symbolizeKeys = 1;
|
||||
}
|
||||
|
||||
if (rb_hash_aref(opts, sym_as) == sym_array) {
|
||||
asArray = 1;
|
||||
}
|
||||
|
||||
ptr = wrapper->result;
|
||||
row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
|
||||
if (row == NULL) {
|
||||
@ -158,7 +149,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, VALUE opts) {
|
||||
case MYSQL_TYPE_TIME: { // TIME field
|
||||
int hour, min, sec, tokens;
|
||||
tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
|
||||
val = rb_funcall(rb_cTime, intern_utc, 6, INT2NUM(2000), INT2NUM(1), INT2NUM(1), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
||||
val = rb_funcall(rb_cTime, timezone, 6, INT2NUM(2000), INT2NUM(1), INT2NUM(1), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP field
|
||||
@ -172,7 +163,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, VALUE opts) {
|
||||
rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
|
||||
val = Qnil;
|
||||
} else {
|
||||
val = rb_funcall(rb_cTime, intern_utc, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
||||
val = rb_funcall(rb_cTime, timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -264,9 +255,11 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
||||
}
|
||||
|
||||
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||
VALUE defaults, opts, block;
|
||||
VALUE defaults, opts, block, timezoneVal;
|
||||
ID timezone;
|
||||
mysql2_result_wrapper * wrapper;
|
||||
unsigned long i;
|
||||
int symbolizeKeys = 0, asArray = 0;
|
||||
|
||||
GetMysql2Result(self, wrapper);
|
||||
|
||||
@ -277,6 +270,24 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||
opts = defaults;
|
||||
}
|
||||
|
||||
if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
|
||||
symbolizeKeys = 1;
|
||||
}
|
||||
|
||||
if (rb_hash_aref(opts, sym_as) == sym_array) {
|
||||
asArray = 1;
|
||||
}
|
||||
|
||||
timezoneVal = rb_hash_aref(opts, sym_timezone);
|
||||
if (timezoneVal == sym_local) {
|
||||
timezone = intern_local;
|
||||
} else if (timezoneVal == sym_utc) {
|
||||
timezone = intern_utc;
|
||||
} else {
|
||||
rb_warn(":timezone config option must be :utc or :local - defaulting to :local");
|
||||
timezone = intern_local;
|
||||
}
|
||||
|
||||
if (wrapper->lastRowProcessed == 0) {
|
||||
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
|
||||
if (wrapper->numberOfRows == 0) {
|
||||
@ -300,7 +311,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||
if (i < rowsProcessed) {
|
||||
row = rb_ary_entry(wrapper->rows, i);
|
||||
} else {
|
||||
row = rb_mysql_result_fetch_row(self, opts);
|
||||
row = rb_mysql_result_fetch_row(self, timezone, symbolizeKeys, asArray);
|
||||
rb_ary_store(wrapper->rows, i, row);
|
||||
wrapper->lastRowProcessed++;
|
||||
}
|
||||
@ -349,8 +360,9 @@ void init_mysql2_result() {
|
||||
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
||||
rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
|
||||
|
||||
intern_new = rb_intern("new");
|
||||
intern_utc = rb_intern("utc");
|
||||
intern_new = rb_intern("new");
|
||||
intern_utc = rb_intern("utc");
|
||||
intern_local = rb_intern("local");
|
||||
intern_encoding_from_charset_code = rb_intern("encoding_from_charset_code");
|
||||
|
||||
#ifdef HAVE_RUBY_ENCODING_H
|
||||
|
@ -295,6 +295,9 @@ module ActiveRecord
|
||||
|
||||
# Executes the SQL statement in the context of this connection.
|
||||
def execute(sql, name = nil)
|
||||
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
||||
# made since we established the connection
|
||||
@connection.query_options[:timezone] = ActiveRecord::Base.default_timezone
|
||||
if name == :skip_logging
|
||||
@connection.query(sql)
|
||||
else
|
||||
|
@ -4,7 +4,8 @@ module Mysql2
|
||||
@@default_query_options = {
|
||||
:symbolize_keys => false,
|
||||
:async => false,
|
||||
:as => :hash
|
||||
:as => :hash,
|
||||
:timezone => :local
|
||||
}
|
||||
|
||||
def initialize(opts = {})
|
||||
|
@ -28,7 +28,7 @@ describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
||||
|
||||
context "columns" do
|
||||
before(:all) do
|
||||
ActiveRecord::Base.default_timezone = 'Pacific Time (US & Canada)'
|
||||
ActiveRecord::Base.default_timezone = :local
|
||||
ActiveRecord::Base.time_zone_aware_attributes = true
|
||||
ActiveRecord::Base.establish_connection(:adapter => 'mysql2', :database => 'test')
|
||||
Mysql2Test2.connection.execute %[
|
||||
@ -89,9 +89,9 @@ describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
||||
test.double_test.should eql('1.0000'.to_f)
|
||||
test.decimal_test.should eql(BigDecimal.new('1.0000'))
|
||||
test.date_test.should eql(Date.parse('2010-01-01'))
|
||||
test.date_time_test.should eql(DateTime.parse('2010-01-01 00:00:00'))
|
||||
test.date_time_test.should eql(Time.local(2010,1,1,0,0,0))
|
||||
test.timestamp_test.should be_nil
|
||||
test.time_test.class.should eql(DateTime)
|
||||
test.time_test.class.should eql(Time)
|
||||
test.year_test.should eql(2010)
|
||||
test.char_test.should eql('abcdefghij')
|
||||
test.varchar_test.should eql('abcdefghij')
|
||||
@ -125,8 +125,8 @@ describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
||||
test.double_test.should eql('1.0000'.to_f)
|
||||
test.decimal_test.should eql(BigDecimal.new('1.0000'))
|
||||
test.date_test.should eql(Date.parse('2010-01-01'))
|
||||
test.date_time_test.should eql(Time.utc(2010,1,1,0,0,0))
|
||||
test.timestamp_test.class.should eql(ActiveSupport::TimeWithZone)
|
||||
test.date_time_test.should eql(Time.local(2010,1,1,0,0,0))
|
||||
test.timestamp_test.class.should eql(Time)
|
||||
test.time_test.class.should eql(Time)
|
||||
test.year_test.should eql(2010)
|
||||
test.char_test.should eql('abcdefghij')
|
||||
|
Loading…
Reference in New Issue
Block a user