diff options
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/CHANGELOG | 2 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 3 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/quoting.rb | 10 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb | 157 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixtures.rb | 16 | ||||
-rw-r--r-- | activerecord/lib/active_record/railties/databases.rake | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/serializers/xml_serializer.rb | 11 | ||||
-rw-r--r-- | activerecord/test/cases/finder_test.rb | 4 | ||||
-rw-r--r-- | activerecord/test/cases/fixtures_test.rb | 10 | ||||
-rw-r--r-- | activerecord/test/fixtures/admin/accounts.yml | 2 | ||||
-rw-r--r-- | activerecord/test/fixtures/admin/users.yml | 7 | ||||
-rw-r--r-- | activerecord/test/models/admin.rb | 5 | ||||
-rw-r--r-- | activerecord/test/models/admin/account.rb | 3 | ||||
-rw-r--r-- | activerecord/test/models/admin/user.rb | 3 | ||||
-rw-r--r-- | activerecord/test/schema/schema.rb | 9 |
15 files changed, 80 insertions, 166 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index c0c4df5035..f7c6d1dc77 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [beta 4/release candidate] (unreleased)* +* PostgreSQL: drop support for old postgres driver. Use pg 0.9.0 or later. [Jeremy Kemper] + * Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić] diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index fd24dcddc3..2d7cfad80d 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1844,8 +1844,7 @@ module ActiveRecord #:nodoc: # user.is_admin? # => true def attributes=(new_attributes, guard_protected_attributes = true) return if new_attributes.nil? - attributes = new_attributes.dup - attributes.stringify_keys! + attributes = new_attributes.stringify_keys multi_parameter_attributes = [] attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 8649f96498..d7b5bf8e31 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -13,12 +13,12 @@ module ActiveRecord when String, ActiveSupport::Multibyte::Chars value = value.to_s if column && column.type == :binary && column.class.respond_to?(:string_to_binary) - "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode) + "'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode) elsif column && [:integer, :float].include?(column.type) value = column.type == :integer ? value.to_i : value.to_f value.to_s else - "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode) + "'#{quote_string(value)}'" # ' (for ruby-mode) end when NilClass then "NULL" when TrueClass then (column && column.type == :integer ? '1' : quoted_true) @@ -30,7 +30,7 @@ module ActiveRecord if value.acts_like?(:date) || value.acts_like?(:time) "'#{quoted_date(value)}'" else - "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'" + "'#{quote_string(value.to_yaml)}'" end end end @@ -67,10 +67,6 @@ module ActiveRecord value end.to_s(:db) end - - def quoted_string_prefix - '' - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ceb1adc9e0..74fed4ad62 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -2,26 +2,12 @@ require 'active_record/connection_adapters/abstract_adapter' require 'active_support/core_ext/kernel/requires' require 'active_support/core_ext/object/blank' -begin - require_library_or_gem 'pg' -rescue LoadError => e - begin - require_library_or_gem 'postgres' - class PGresult - alias_method :nfields, :num_fields unless self.method_defined?(:nfields) - alias_method :ntuples, :num_tuples unless self.method_defined?(:ntuples) - alias_method :ftype, :type unless self.method_defined?(:ftype) - alias_method :cmd_tuples, :cmdtuples unless self.method_defined?(:cmd_tuples) - end - rescue LoadError - raise e - end -end - module ActiveRecord class Base # Establishes a connection to the database that's used by all Active Record objects def self.postgresql_connection(config) # :nodoc: + require 'pg' + config = config.symbolize_keys host = config[:host] port = config[:port] || 5432 @@ -277,20 +263,12 @@ module ActiveRecord true end - # Does PostgreSQL support standard conforming strings? - def supports_standard_conforming_strings? - # Temporarily set the client message level above error to prevent unintentional - # error messages in the logs when working on a PostgreSQL database server that - # does not support standard conforming strings. - client_min_messages_old = client_min_messages - self.client_min_messages = 'panic' - - # postgres-pr does not raise an exception when client_min_messages is set higher - # than error and "SHOW standard_conforming_strings" fails, but returns an empty - # PGresult instead. - has_support = query('SHOW standard_conforming_strings')[0][0] rescue false - self.client_min_messages = client_min_messages_old - has_support + # Enable standard-conforming strings if available. + def set_standard_conforming_strings + old, self.client_min_messages = client_min_messages, 'panic' + execute('SET standard_conforming_strings = on') rescue nil + ensure + self.client_min_messages = old end def supports_insert_with_returning? @@ -314,85 +292,23 @@ module ActiveRecord # QUOTING ================================================== # Escapes binary strings for bytea input to the database. - def escape_bytea(original_value) - if @connection.respond_to?(:escape_bytea) - self.class.instance_eval do - define_method(:escape_bytea) do |value| - @connection.escape_bytea(value) if value - end - end - elsif PGconn.respond_to?(:escape_bytea) - self.class.instance_eval do - define_method(:escape_bytea) do |value| - PGconn.escape_bytea(value) if value - end - end - else - self.class.instance_eval do - define_method(:escape_bytea) do |value| - if value - result = '' - value.each_byte { |c| result << sprintf('\\\\%03o', c) } - result - end - end - end - end - escape_bytea(original_value) + def escape_bytea(value) + @connection.escape_bytea(value) if value end # Unescapes bytea output from a database to the binary string it represents. # NOTE: This is NOT an inverse of escape_bytea! This is only to be used # on escaped binary output from database drive. - def unescape_bytea(original_value) - # In each case, check if the value actually is escaped PostgreSQL bytea output - # or an unescaped Active Record attribute that was just written. - if PGconn.respond_to?(:unescape_bytea) - self.class.instance_eval do - define_method(:unescape_bytea) do |value| - if value =~ /\\\d{3}/ - PGconn.unescape_bytea(value) - else - value - end - end - end - else - self.class.instance_eval do - define_method(:unescape_bytea) do |value| - if value =~ /\\\d{3}/ - result = '' - i, max = 0, value.size - while i < max - char = value[i] - if char == ?\\ - if value[i+1] == ?\\ - char = ?\\ - i += 1 - else - char = value[i+1..i+3].oct - i += 3 - end - end - result << char - i += 1 - end - result - else - value - end - end - end - end - unescape_bytea(original_value) + def unescape_bytea(value) + @connection.unescape_bytea(value) if value end # Quotes PostgreSQL-specific data types for SQL input. def quote(value, column = nil) #:nodoc: if value.kind_of?(String) && column && column.type == :binary - "#{quoted_string_prefix}'#{escape_bytea(value)}'" + "'#{escape_bytea(value)}'" elsif value.kind_of?(String) && column && column.sql_type == 'xml' - "xml E'#{quote_string(value)}'" + "xml '#{quote_string(value)}'" elsif value.kind_of?(Numeric) && column && column.sql_type == 'money' # Not truly string input, so doesn't require (or allow) escape string syntax. "'#{value.to_s}'" @@ -408,28 +324,9 @@ module ActiveRecord end end - # Quotes strings for use in SQL input in the postgres driver for better performance. - def quote_string(original_value) #:nodoc: - if @connection.respond_to?(:escape) - self.class.instance_eval do - define_method(:quote_string) do |s| - @connection.escape(s) - end - end - elsif PGconn.respond_to?(:escape) - self.class.instance_eval do - define_method(:quote_string) do |s| - PGconn.escape(s) - end - end - else - # There are some incorrectly compiled postgres drivers out there - # that don't define PGconn.escape. - self.class.instance_eval do - remove_method(:quote_string) - end - end - quote_string(original_value) + # Quotes strings for use in SQL input. + def quote_string(s) #:nodoc: + @connection.escape(s) end # Checks the following cases: @@ -1005,22 +902,11 @@ module ActiveRecord # Ignore async_exec and async_query when using postgres-pr. @async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec) - # Use escape string syntax if available. We cannot do this lazily when encountering - # the first string, because that could then break any transactions in progress. - # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html - # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't - # support escape string syntax. Don't override the inherited quoted_string_prefix. - if supports_standard_conforming_strings? - self.class.instance_eval do - define_method(:quoted_string_prefix) { 'E' } - end - end - # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision # should know about this but can't detect it there, so deal with it here. - PostgreSQLColumn.money_precision = - (postgresql_version >= 80300) ? 19 : 10 + PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10 + configure_connection end @@ -1036,7 +922,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] - + + # Use standard-conforming strings if available so we don't have to do the E'...' dance. + set_standard_conforming_strings + # 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 diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 22f0e60083..0bc49c1daa 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -3,8 +3,9 @@ require 'yaml' require 'csv' require 'zlib' require 'active_support/dependencies' -require 'active_support/core_ext/logger' +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/logger' if RUBY_VERSION < '1.9' module YAML #:nodoc: @@ -492,6 +493,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) def self.create_fixtures(fixtures_directory, table_names, class_names = {}) table_names = [table_names].flatten.map { |n| n.to_s } + table_names.each { |n| class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/') } connection = block_given? ? yield : ActiveRecord::Base.connection table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) } @@ -502,7 +504,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) fixtures_map = {} fixtures = table_names_to_fetch.map do |table_name| - fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s)) + fixtures_map[table_name] = Fixtures.new(connection, table_name.tr('/', '_'), class_names[table_name.tr('/', '_').to_sym], File.join(fixtures_directory, table_name)) end all_loaded_fixtures.update(fixtures_map) @@ -836,8 +838,8 @@ module ActiveRecord def fixtures(*table_names) if table_names.first == :all - table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"] - table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') } + table_names = Dir["#{fixture_path}/**/*.{yml,csv}"] + table_names.map! { |f| f[(fixture_path.size + 1)..-5] } else table_names = table_names.flatten.map { |n| n.to_s } end @@ -868,9 +870,9 @@ module ActiveRecord end def setup_fixture_accessors(table_names = nil) - table_names = [table_names] if table_names && !table_names.respond_to?(:each) - (table_names || fixture_table_names).each do |table_name| - table_name = table_name.to_s.tr('.', '_') + table_names = Array.wrap(table_names || fixture_table_names) + table_names.each do |table_name| + table_name = table_name.to_s.tr('./', '_') define_method(table_name) do |*fixtures| force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 2b53afc68b..cb7eade0ab 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -258,8 +258,8 @@ namespace :db do base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures') fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file| - Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) + (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file| + Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5]) end end diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 2e85959b1e..255b03433d 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -182,17 +182,6 @@ module ActiveRecord #:nodoc: options[:except] |= Array.wrap(@serializable.class.inheritance_column) end - def serializable_attributes - serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) } - end - - def serializable_method_attributes - Array.wrap(options[:methods]).inject([]) do |method_attributes, name| - method_attributes << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s) - method_attributes - end - end - def add_associations(association, records, opts) if records.is_a?(Enumerable) tag = reformat_name(association.to_s) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 9e88ec8016..77b2b748b1 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -566,8 +566,8 @@ class FinderTest < ActiveRecord::TestCase end def test_string_sanitation - assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1") - assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table") + assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1") + assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table") end def test_count diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index d24283fe4e..3ce23209cc 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -16,6 +16,9 @@ require 'models/treasure' require 'models/matey' require 'models/ship' require 'models/book' +require 'models/admin' +require 'models/admin/account' +require 'models/admin/user' class FixturesTest < ActiveRecord::TestCase self.use_instantiated_fixtures = true @@ -507,7 +510,7 @@ class FasterFixturesTest < ActiveRecord::TestCase end class FoxyFixturesTest < ActiveRecord::TestCase - fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers + fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers, :"admin/accounts", :"admin/users" def test_identifies_strings assert_equal(Fixtures.identify("foo"), Fixtures.identify("foo")) @@ -629,6 +632,11 @@ class FoxyFixturesTest < ActiveRecord::TestCase assert_kind_of DeadParrot, parrots(:polly) assert_equal pirates(:blackbeard), parrots(:polly).killer end + + def test_namespaced_models + assert admin_accounts(:signals37).users.include?(admin_users(:david)) + assert_equal 2, admin_accounts(:signals37).users.size + end end class ActiveSupportSubclassWithFixturesTest < ActiveRecord::TestCase diff --git a/activerecord/test/fixtures/admin/accounts.yml b/activerecord/test/fixtures/admin/accounts.yml new file mode 100644 index 0000000000..9e341a15af --- /dev/null +++ b/activerecord/test/fixtures/admin/accounts.yml @@ -0,0 +1,2 @@ +signals37: + name: 37signals diff --git a/activerecord/test/fixtures/admin/users.yml b/activerecord/test/fixtures/admin/users.yml new file mode 100644 index 0000000000..6f11f2509e --- /dev/null +++ b/activerecord/test/fixtures/admin/users.yml @@ -0,0 +1,7 @@ +david: + name: David + account: signals37 + +jamis: + name: Jamis + account: signals37 diff --git a/activerecord/test/models/admin.rb b/activerecord/test/models/admin.rb new file mode 100644 index 0000000000..00e69fbed8 --- /dev/null +++ b/activerecord/test/models/admin.rb @@ -0,0 +1,5 @@ +module Admin + def self.table_name_prefix + 'admin_' + end +end
\ No newline at end of file diff --git a/activerecord/test/models/admin/account.rb b/activerecord/test/models/admin/account.rb new file mode 100644 index 0000000000..46de28aae1 --- /dev/null +++ b/activerecord/test/models/admin/account.rb @@ -0,0 +1,3 @@ +class Admin::Account < ActiveRecord::Base + has_many :users +end
\ No newline at end of file diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb new file mode 100644 index 0000000000..74bb21551e --- /dev/null +++ b/activerecord/test/models/admin/user.rb @@ -0,0 +1,3 @@ +class Admin::User < ActiveRecord::Base + belongs_to :account +end
\ No newline at end of file diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 7a0cf550e0..f5fba2f87d 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -26,6 +26,15 @@ ActiveRecord::Schema.define do t.integer :credit_limit end + create_table :admin_accounts, :force => true do |t| + t.string :name + end + + create_table :admin_users, :force => true do |t| + t.string :name + t.references :account + end + create_table :audit_logs, :force => true do |t| t.column :message, :string, :null=>false t.column :developer_id, :integer, :null=>false |