aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb6
-rw-r--r--activerecord/lib/active_record/railtie.rb30
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb16
-rw-r--r--activerecord/test/cases/calculations_test.rb3
-rw-r--r--activerecord/test/cases/datatype_test_postgresql.rb39
-rw-r--r--activerecord/test/cases/query_cache_test.rb6
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb9
10 files changed, 96 insertions, 23 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index ffff0b7e09..a4fa000964 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* PostgreSQLAdapter: set time_zone to UTC when Base.default_timezone == :utc so that Postgres doesn't incorrectly offset-adjust values inserted into TIMESTAMP WITH TIME ZONE columns. #3777 [Jack Christensen]
+
* Allow relations to be used as scope.
class Item
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 1d52c5ec14..b3ce8c79dd 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -998,7 +998,7 @@ module ActiveRecord
configure_connection
end
- # Configures the encoding, verbosity, and schema search path of the connection.
+ # Configures the encoding, verbosity, schema search path, and time zone of the connection.
# This is called by #connect and should not be called manually.
def configure_connection
if @config[:encoding]
@@ -1010,6 +1010,10 @@ module ActiveRecord
end
self.client_min_messages = @config[:min_messages] if @config[:min_messages]
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
+
+ # If using ActiveRecord's time zone support configure the connection to return
+ # TIMESTAMP WITH ZONE types in UTC.
+ execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc
end
# Returns the current ID of a table's sequence.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 0a52f3a6a2..29225b83c5 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -193,20 +193,20 @@ module ActiveRecord
SQL
execute(sql, name).map do |row|
- row[0]
+ row['name']
end
end
def columns(table_name, name = nil) #:nodoc:
table_structure(table_name).map do |field|
- SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'] == "0")
+ SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
end
end
def indexes(table_name, name = nil) #:nodoc:
execute("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
index = IndexDefinition.new(table_name, row['name'])
- index.unique = row['unique'] != '0'
+ index.unique = row['unique'].to_i != 0
index.columns = execute("PRAGMA index_info('#{index.name}')").map { |col| col['name'] }
index
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index bc06333f1c..dc80ac4b30 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -8,7 +8,10 @@ require "rails"
module ActiveRecord
class Railtie < Rails::Railtie
- plugin_name :active_record
+ railtie_name :active_record
+
+ config.generators.orm :active_record, :migration => true,
+ :timestamps => true
rake_tasks do
load "active_record/railties/databases.rake"
@@ -18,6 +21,15 @@ module ActiveRecord
require "active_record/railties/subscriber"
subscriber ActiveRecord::Railties::Subscriber.new
+ initializer "active_record.initialize_timezone" do
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+ end
+
+ initializer "active_record.logger" do
+ ActiveRecord::Base.logger ||= ::Rails.logger
+ end
+
initializer "active_record.set_configs" do |app|
app.config.active_record.each do |k,v|
ActiveRecord::Base.send "#{k}=", v
@@ -31,11 +43,6 @@ module ActiveRecord
ActiveRecord::Base.establish_connection
end
- initializer "active_record.initialize_timezone" do
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- end
-
# Expose database runtime to controller for logging.
initializer "active_record.log_runtime" do |app|
require "active_record/railties/controller_runtime"
@@ -45,9 +52,9 @@ module ActiveRecord
# Setup database middleware after initializers have run
initializer "active_record.initialize_database_middleware" do |app|
middleware = app.config.middleware
- if middleware.include?(ActiveRecord::SessionStore)
- middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::ConnectionAdapters::ConnectionManagement
- middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::QueryCache
+ if middleware.include?("ActiveRecord::SessionStore")
+ middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
+ middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::QueryCache
else
middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
middleware.use ActiveRecord::QueryCache
@@ -71,11 +78,6 @@ module ActiveRecord
end
end
- # TODO: ActiveRecord::Base.logger should delegate to its own config.logger
- initializer "active_record.logger" do
- ActiveRecord::Base.logger ||= ::Rails.logger
- end
-
initializer "active_record.i18n_deprecation" do
require 'active_support/i18n'
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 88974dd786..2ef8676f39 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -1,7 +1,7 @@
namespace :db do
task :load_config => :rails_env do
require 'active_record'
- ActiveRecord::Base.configurations = Rails::Configuration.new.database_configuration
+ ActiveRecord::Base.configurations = Rails::Application.config.database_configuration
end
namespace :create do
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 8954f2d12b..0266700f66 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -133,8 +133,13 @@ module ActiveRecord
arel = h.is_a?(String) ? arel.having(h) : arel.having(*h)
end
- arel = arel.take(@limit_value) if @limit_value.present?
- arel = arel.skip(@offset_value) if @offset_value.present?
+ if defined?(@limit_value) && @limit_value.present?
+ arel = arel.take(@limit_value)
+ end
+
+ if defined?(@offset_value) && @offset_value.present?
+ arel = arel.skip(@offset_value)
+ end
@group_values.uniq.each do |g|
arel = arel.group(g) if g.present?
@@ -157,7 +162,12 @@ module ActiveRecord
arel = arel.project(quoted_table_name + '.*')
end
- arel = @from_value.present? ? arel.from(@from_value) : arel.from(quoted_table_name)
+ arel =
+ if defined?(@from_value) && @from_value.present?
+ arel.from(@from_value)
+ else
+ arel.from(quoted_table_name)
+ end
case @lock_value
when TrueClass
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index c3b2e56387..e6d56a7193 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -288,6 +288,9 @@ class CalculationsTest < ActiveRecord::TestCase
# Oracle adapter returns floating point value 636.0 after SUM
if current_adapter?(:OracleAdapter)
assert_equal 636, Account.sum("2 * credit_limit")
+ elsif current_adapter?(:SQLite3Adapter)
+ # Future versions of the SQLite3 adapter will return a number
+ assert_equal 636, Account.sum("2 * credit_limit").to_i
else
assert_equal '636', Account.sum("2 * credit_limit")
end
diff --git a/activerecord/test/cases/datatype_test_postgresql.rb b/activerecord/test/cases/datatype_test_postgresql.rb
index 88fb6f7384..9454b6e059 100644
--- a/activerecord/test/cases/datatype_test_postgresql.rb
+++ b/activerecord/test/cases/datatype_test_postgresql.rb
@@ -21,6 +21,9 @@ end
class PostgresqlOid < ActiveRecord::Base
end
+class PostgresqlTimestampWithZone < ActiveRecord::Base
+end
+
class PostgresqlDataTypeTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
@@ -50,6 +53,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
@connection.execute("INSERT INTO postgresql_oids (obj_id) VALUES (1234)")
@first_oid = PostgresqlOid.find(1)
+
+ @connection.execute("INSERT INTO postgresql_timestamp_with_zones (time) VALUES ('2010-01-01 10:00:00-1')")
end
def test_data_type_of_array_types
@@ -201,4 +206,38 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert @first_oid.reload
assert_equal @first_oid.obj_id, new_value
end
+
+ def test_timestamp_with_zone_values_with_rails_time_zone_support
+ old_tz = ActiveRecord::Base.time_zone_aware_attributes
+ old_default_tz = ActiveRecord::Base.default_timezone
+
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+
+ @connection.reconnect!
+
+ @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
+ assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
+ ensure
+ ActiveRecord::Base.default_timezone = old_default_tz
+ ActiveRecord::Base.time_zone_aware_attributes = old_tz
+ @connection.reconnect!
+ end
+
+ def test_timestamp_with_zone_values_without_rails_time_zone_support
+ old_tz = ActiveRecord::Base.time_zone_aware_attributes
+ old_default_tz = ActiveRecord::Base.default_timezone
+
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+
+ @connection.reconnect!
+
+ @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
+ assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
+ ensure
+ ActiveRecord::Base.default_timezone = old_default_tz
+ ActiveRecord::Base.time_zone_aware_attributes = old_tz
+ @connection.reconnect!
+ end
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 2af6a56b6a..3710f8e40b 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -49,10 +49,16 @@ class QueryCacheTest < ActiveRecord::TestCase
end
def test_cache_does_not_wrap_string_results_in_arrays
+ require 'sqlite3/version' if current_adapter?(:SQLite3Adapter)
+
Task.cache do
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric)
+ elsif current_adapter?(:SQLite3Adapter) && SQLite3::Version::VERSION > '1.2.5'
+ # Future versions of the sqlite3 adapter will return numeric
+ assert_instance_of Fixnum,
+ Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
else
assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index 3d8911bfe9..065d8cfe98 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,7 +1,7 @@
ActiveRecord::Schema.define do
%w(postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings
- postgresql_oids postgresql_xml_data_type defaults geometrics).each do |table_name|
+ postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -100,6 +100,13 @@ _SQL
obj_id OID
);
_SQL
+
+ execute <<_SQL
+ CREATE TABLE postgresql_timestamp_with_zones (
+ id SERIAL PRIMARY KEY,
+ time TIMESTAMP WITH TIME ZONE
+ );
+_SQL
begin
execute <<_SQL