Skip to content

Commit

Permalink
Make we always type cast TimeWithZone objects before passing to mysql2
Browse files Browse the repository at this point in the history
mysql2 knows how to handle Time and Date objects but doesn't know
about TimeWithZone. This was causing failures when prepared statements
were enabled since we were passing TimeWithZone objects that mysql2 didn't
know how to deal with.

An new environment variable to enable prepared statements were added to
config.example.yml, so we can test in our CI and prevent regressions.

Fixes #41368.
  • Loading branch information
rafaelfranca committed Feb 11, 2021
1 parent 4bd8621 commit 8d825b5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "active_support/time_with_zone"

module ActiveRecord
module ConnectionAdapters
module MySQL
Expand Down Expand Up @@ -69,10 +71,23 @@ def column_name_with_order_matcher
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER

private
# Override +_type_cast+ we pass to mysql2 Date and Time objects instead
# of Strings since mysql2 is able to handle those classes more efficiently.
def _type_cast(value)
case value
when Date, Time then value
else super
when ActiveSupport::TimeWithZone
# We need to check explicitly for ActiveSupport::TimeWithZone because
# we need to transform it to Time objects but we don't want to
# transform Time objects to themselves.
if ActiveRecord::Base.default_timezone == :utc
value.getutc
else
value.getlocal
end
when Date, Time
value
else
super
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions activerecord/test/cases/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
require "models/bird"
require "models/car"
require "models/bulb"
require "models/pet"
require "concurrent/atomic/count_down_latch"
require "active_support/core_ext/enumerable"

Expand Down Expand Up @@ -312,6 +313,18 @@ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timez
end
end

def test_time_zone_aware_attribute_with_default_timezone_utc_on_utc_can_be_created
with_env_tz eastern_time_zone do
with_timezone_config aware_attributes: true, default: :utc, zone: "UTC" do
pet = Pet.create(name: 'Bidu')
assert_predicate pet, :persisted?
saved_pet = Pet.find(pet.id)
assert_not_nil saved_pet.created_at
assert_not_nil saved_pet.updated_at
end
end
end

def eastern_time_zone
if Gem.win_platform?
"EST5EDT"
Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ connections:
username: rails
encoding: utf8mb4
collation: utf8mb4_unicode_ci
<% if ENV['MYSQL_PREPARED_STATEMENTS'] %>
prepared_statements: true
<% end %>
<% if ENV['MYSQL_HOST'] %>
host: <%= ENV['MYSQL_HOST'] %>
<% end %>
arunit2:
username: rails
encoding: utf8mb4
collation: utf8mb4_general_ci
<% if ENV['MYSQL_PREPARED_STATEMENTS'] %>
prepared_statements: true
<% end %>
<% if ENV['MYSQL_HOST'] %>
host: <%= ENV['MYSQL_HOST'] %>
<% end %>
Expand Down

0 comments on commit 8d825b5

Please sign in to comment.