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
This commit is contained in:
Brian Lopez 2010-08-05 22:50:45 -07:00
parent 1bdf44ce7f
commit ad34357e57
2 changed files with 57 additions and 25 deletions

View File

@ -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");

View File

@ -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 = {})