From ad34357e57e4d2752f1bca73c67b922f3a9cb744 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 5 Aug 2010 22:50:45 -0700 Subject: [PATCH] convert :timezone option into two new ones :database_timezone - the timezone (:utc or :local) Mysql2 will assume time/datetime fields are stored in the db. This modifies what initial timezone your Time objects will be in when creating them from libmysql in C and :application_timezone - the timezone (:utc or :local) you'd finally like the Time objects converted to before you get them --- ext/mysql2/result.c | 73 +++++++++++++++++++++++++++++++------------- lib/mysql2/client.rb | 9 +++--- 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index f61195f..b1850f4 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -8,9 +8,10 @@ VALUE cMysql2Result; VALUE cBigDecimal, cDate, cDateTime; extern VALUE mMysql2, cMysql2Client, cMysql2Error; static VALUE intern_encoding_from_charset; -static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code; -static ID sym_symbolize_keys, sym_as, sym_array, sym_timezone, sym_local, sym_utc, - sym_cast_booleans; +static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code, + intern_localtime; +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; static void rb_mysql_result_mark(void * wrapper) { @@ -87,7 +88,7 @@ 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, ID timezone, int symbolizeKeys, int asArray, int castBool) { +static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool) { VALUE rowVal; mysql2_result_wrapper * wrapper; MYSQL_ROW row; @@ -154,7 +155,14 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKey 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, timezone, 6, INT2NUM(2000), INT2NUM(1), INT2NUM(1), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)); + val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(2000), INT2NUM(1), INT2NUM(1), 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); + } + } break; } case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP field @@ -168,7 +176,14 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKey rb_raise(cMysql2Error, "Invalid date: %s", row[i]); val = Qnil; } else { - val = rb_funcall(rb_cTime, timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)); + 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); + } + } } } break; @@ -267,8 +282,8 @@ 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, timezoneVal; - ID timezone; + VALUE defaults, opts, block; + ID db_timezone, app_timezone, dbTz, appTz; mysql2_result_wrapper * wrapper; unsigned long i; int symbolizeKeys = 0, asArray = 0, castBool = 0; @@ -294,14 +309,28 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) { castBool = 1; } - timezoneVal = rb_hash_aref(opts, sym_timezone); - if (timezoneVal == sym_local) { - timezone = intern_local; - } else if (timezoneVal == sym_utc) { - timezone = intern_utc; + dbTz = rb_hash_aref(opts, sym_database_timezone); + if (dbTz == sym_local) { + db_timezone = intern_local; + } else if (dbTz == sym_utc) { + db_timezone = intern_utc; } else { - rb_warn(":timezone config option must be :utc or :local - defaulting to :local"); - timezone = intern_local; + if (!NIL_P(dbTz)) { + rb_warn(":database_timezone option must be :utc or :local - defaulting to :local"); + } + db_timezone = intern_local; + } + + appTz = rb_hash_aref(opts, sym_application_timezone); + if (appTz == sym_local) { + app_timezone = intern_local; + } else if (appTz == sym_utc) { + app_timezone = intern_utc; + } else { + if (!NIL_P(appTz)) { + rb_warn(":application_timezone option must be :utc or :local - defaulting to :local"); + } + app_timezone = intern_local; } if (wrapper->lastRowProcessed == 0) { @@ -327,7 +356,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, timezone, symbolizeKeys, asArray, castBool); + row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool); rb_ary_store(wrapper->rows, i, row); wrapper->lastRowProcessed++; } @@ -379,18 +408,20 @@ 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_new = rb_intern("new"); + intern_utc = rb_intern("utc"); + intern_local = rb_intern("local"); + intern_merge = rb_intern("merge"); + intern_localtime = rb_intern("localtime"); sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys")); sym_as = ID2SYM(rb_intern("as")); sym_array = ID2SYM(rb_intern("array")); - sym_timezone = ID2SYM(rb_intern("timezone")); sym_local = ID2SYM(rb_intern("local")); sym_utc = ID2SYM(rb_intern("utc")); sym_cast_booleans = ID2SYM(rb_intern("cast_booleans")); + sym_database_timezone = ID2SYM(rb_intern("database_timezone")); + sym_application_timezone = ID2SYM(rb_intern("application_timezone")); #ifdef HAVE_RUBY_ENCODING_H binaryEncoding = rb_enc_find("binary"); diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index 344313a..a830b5b 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -2,11 +2,12 @@ module Mysql2 class Client attr_reader :query_options @@default_query_options = { - :symbolize_keys => false, - :async => false, :as => :hash, - :timezone => :local, - :cast_booleans => false + :async => false, + :cast_booleans => false, + :symbolize_keys => false, + :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in + :application_timezone => :local # timezone Mysql2 will convert to before handing the object back to the caller } def initialize(opts = {})