diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
-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 |
2 files changed, 26 insertions, 141 deletions
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 |