diff options
Diffstat (limited to 'activerecord')
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 |