From a765c3be4154f0b1ee41aef46ce9247bbcb92a05 Mon Sep 17 00:00:00 2001 From: Prescott Murphy Date: Tue, 7 Mar 2017 13:37:16 -0500 Subject: [PATCH 1/4] Cast Time/Timestamp to Rails application timezone. --- .../connection_adapters/odbc_adapter.rb | 7 +++++++ lib/odbc_adapter/type_caster.rb | 16 +--------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/lib/active_record/connection_adapters/odbc_adapter.rb b/lib/active_record/connection_adapters/odbc_adapter.rb index 8e29816b..c8faefcb 100644 --- a/lib/active_record/connection_adapters/odbc_adapter.rb +++ b/lib/active_record/connection_adapters/odbc_adapter.rb @@ -79,6 +79,7 @@ class ODBCAdapter < AbstractAdapter attr_reader :database_metadata def initialize(connection, logger, config, database_metadata) + configure_time_options(connection) super(connection, logger, config) @database_metadata = database_metadata end @@ -113,6 +114,7 @@ def reconnect! else ODBC::Database.new.drvconnect(@config[:driver]) end + configure_time_options(@connection) super end alias reset! reconnect! @@ -189,6 +191,11 @@ def alias_type(map, new_type, old_type) map.lookup(old_type, *args) end end + + # Ensure ODBC is mapping time-based fields to native ruby objects in UTC + def configure_time_options(connection) + connection.use_time = true + end end end end diff --git a/lib/odbc_adapter/type_caster.rb b/lib/odbc_adapter/type_caster.rb index 4839b51a..4da3e4c2 100644 --- a/lib/odbc_adapter/type_caster.rb +++ b/lib/odbc_adapter/type_caster.rb @@ -4,7 +4,6 @@ class TypeCaster # SQL types to an equivalent Ruby type; with the exception of # SQL_DATE, SQL_TIME and SQL_TIMESTAMP. TYPES = [ - ODBC::SQL_DATE, ODBC::SQL_TIME, ODBC::SQL_TIMESTAMP ].freeze @@ -16,20 +15,7 @@ def initialize(idx) end def cast(value) - case value - when ODBC::TimeStamp - Time.gm(value.year, value.month, value.day, value.hour, value.minute, value.second) - when ODBC::Time - now = DateTime.now - Time.gm(now.year, now.month, now.day, value.hour, value.minute, value.second) - when ODBC::Date - Date.new(value.year, value.month, value.day) - else - value - end - rescue - # Handle pre-epoch dates - DateTime.new(value.year, value.month, value.day, value.hour, value.minute, value.second) + value.in_time_zone end # Build a list of casters from a list of columns From d024b760f98ea1b68143ff69b27f11da05b52f50 Mon Sep 17 00:00:00 2001 From: Prescott Murphy Date: Tue, 7 Mar 2017 14:46:55 -0500 Subject: [PATCH 2/4] Remove TypeCaster. --- .../connection_adapters/odbc_adapter.rb | 1 - lib/odbc_adapter/database_statements.rb | 7 ----- lib/odbc_adapter/type_caster.rb | 28 ------------------- 3 files changed, 36 deletions(-) delete mode 100644 lib/odbc_adapter/type_caster.rb diff --git a/lib/active_record/connection_adapters/odbc_adapter.rb b/lib/active_record/connection_adapters/odbc_adapter.rb index c8faefcb..7fefd0c0 100644 --- a/lib/active_record/connection_adapters/odbc_adapter.rb +++ b/lib/active_record/connection_adapters/odbc_adapter.rb @@ -12,7 +12,6 @@ require 'odbc_adapter/column_metadata' require 'odbc_adapter/database_metadata' require 'odbc_adapter/registry' -require 'odbc_adapter/type_caster' require 'odbc_adapter/version' module ActiveRecord diff --git a/lib/odbc_adapter/database_statements.rb b/lib/odbc_adapter/database_statements.rb index 4c314c18..cac31682 100644 --- a/lib/odbc_adapter/database_statements.rb +++ b/lib/odbc_adapter/database_statements.rb @@ -33,13 +33,6 @@ def exec_query(sql, name = 'SQL', binds = [], prepare: false) # rubocop:disable values = stmt.to_a stmt.drop - casters = TypeCaster.build_from(columns.values) - if casters.any? - values.each do |row| - casters.each { |caster| row[caster.idx] = caster.cast(row[caster.idx]) } - end - end - values = dbms_type_cast(columns.values, values) column_names = columns.keys.map { |key| format_case(key) } ActiveRecord::Result.new(column_names, values) diff --git a/lib/odbc_adapter/type_caster.rb b/lib/odbc_adapter/type_caster.rb deleted file mode 100644 index 4da3e4c2..00000000 --- a/lib/odbc_adapter/type_caster.rb +++ /dev/null @@ -1,28 +0,0 @@ -module ODBCAdapter - class TypeCaster - # When fetching a result set, the Ruby ODBC driver converts all ODBC - # SQL types to an equivalent Ruby type; with the exception of - # SQL_DATE, SQL_TIME and SQL_TIMESTAMP. - TYPES = [ - ODBC::SQL_TIME, - ODBC::SQL_TIMESTAMP - ].freeze - - attr_reader :idx - - def initialize(idx) - @idx = idx - end - - def cast(value) - value.in_time_zone - end - - # Build a list of casters from a list of columns - def self.build_from(columns) - columns.each_with_index.each_with_object([]) do |(column, idx), casters| - casters << new(idx) if TYPES.include?(column.type) - end - end - end -end From 69dd47fbdd2ba9a3b001aa5822860a0ad247a2cf Mon Sep 17 00:00:00 2001 From: Prescott Murphy Date: Tue, 7 Mar 2017 14:47:47 -0500 Subject: [PATCH 3/4] Adjust commment. --- lib/active_record/connection_adapters/odbc_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_record/connection_adapters/odbc_adapter.rb b/lib/active_record/connection_adapters/odbc_adapter.rb index 7fefd0c0..672c5db1 100644 --- a/lib/active_record/connection_adapters/odbc_adapter.rb +++ b/lib/active_record/connection_adapters/odbc_adapter.rb @@ -191,7 +191,7 @@ def alias_type(map, new_type, old_type) end end - # Ensure ODBC is mapping time-based fields to native ruby objects in UTC + # Ensure ODBC is mapping time-based fields to native ruby objects def configure_time_options(connection) connection.use_time = true end From a6aa2d38e9d69c3ed32d699ebdd7144a8037f551 Mon Sep 17 00:00:00 2001 From: Kevin Deisz Date: Tue, 7 Mar 2017 16:39:52 -0500 Subject: [PATCH 4/4] Bump version --- lib/odbc_adapter/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/odbc_adapter/version.rb b/lib/odbc_adapter/version.rb index 693cb713..fdebf9fb 100644 --- a/lib/odbc_adapter/version.rb +++ b/lib/odbc_adapter/version.rb @@ -1,3 +1,3 @@ module ODBCAdapter - VERSION = '5.0.3'.freeze + VERSION = '5.0.4'.freeze end