aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb15
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb40
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb43
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb21
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb25
21 files changed, 139 insertions, 151 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 6235745fb2..d99dc9a5db 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -2,7 +2,6 @@ require 'thread'
require 'thread_safe'
require 'monitor'
require 'set'
-require 'active_support/core_ext/string/filters'
module ActiveRecord
# Raised when a connection could not be obtained within the connection
@@ -454,6 +453,10 @@ module ActiveRecord
c.verify!
end
c
+ rescue
+ remove c
+ c.disconnect!
+ raise
end
end
@@ -517,15 +520,7 @@ module ActiveRecord
def connection_pool_list
owner_to_pool.values.compact
end
-
- def connection_pools
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- In the next release, this will return the same as `#connection_pool_list`.
- (An array of pools, rather than a hash mapping specs to pools.)
- MSG
-
- Hash[connection_pool_list.map { |pool| [pool.spec, pool] }]
- end
+ alias :connection_pools :connection_pool_list
def establish_connection(owner, spec)
@class_to_pool.clear
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 59cdd8e98c..c3e5e9ad61 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -285,10 +285,17 @@ module ActiveRecord
def insert_fixture(fixture, table_name)
columns = schema_cache.columns_hash(table_name)
- key_list = []
- value_list = fixture.map do |name, value|
- key_list << quote_column_name(name)
- quote(value, columns[name])
+ binds = fixture.map do |name, value|
+ type = lookup_cast_type_from_column(columns[name])
+ Relation::QueryAttribute.new(name, value, type)
+ end
+ key_list = fixture.keys.map { |name| quote_column_name(name) }
+ value_list = prepare_binds_for_database(binds).map do |value|
+ begin
+ quote(value)
+ rescue TypeError
+ quote(YAML.dump(value))
+ end
end
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
@@ -375,7 +382,7 @@ module ActiveRecord
def binds_from_relation(relation, binds)
if relation.is_a?(Relation) && binds.empty?
- relation, binds = relation.arel, relation.bind_values
+ relation, binds = relation.arel, relation.bound_attributes
end
[relation, binds]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 143d7d9574..2456376d6d 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -10,7 +10,13 @@ module ActiveRecord
return value.quoted_id if value.respond_to?(:quoted_id)
if column
- value = column.cast_type.type_cast_for_database(value)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing a column to `quote` has been deprecated. It is only used
+ for type casting, which should be handled elsewhere. See
+ https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
+ for more information.
+ MSG
+ value = type_cast_from_column(column, value)
end
_quote(value)
@@ -25,7 +31,7 @@ module ActiveRecord
end
if column
- value = column.cast_type.type_cast_for_database(value)
+ value = type_cast_from_column(column, value)
end
_type_cast(value)
@@ -34,6 +40,29 @@ module ActiveRecord
raise TypeError, "can't cast #{value.class}#{to_type}"
end
+ # If you are having to call this function, you are likely doing something
+ # wrong. The column does not have sufficient type information if the user
+ # provided a custom type on the class level either explicitly (via
+ # `attribute`) or implicitly (via `serialize`,
+ # `time_zone_aware_attributes`). In almost all cases, the sql type should
+ # only be used to change quoting behavior, when the primitive to
+ # represent the type doesn't sufficiently reflect the differences
+ # (varchar vs binary) for example. The type used to get this primitive
+ # should have been provided before reaching the connection adapter.
+ def type_cast_from_column(column, value) # :nodoc:
+ if column
+ type = lookup_cast_type_from_column(column)
+ type.type_cast_for_database(value)
+ else
+ value
+ end
+ end
+
+ # See docs for +type_cast_from_column+
+ def lookup_cast_type_from_column(column) # :nodoc:
+ lookup_cast_type(column.sql_type)
+ end
+
# Quotes a string, escaping any ' (single quote) and \ (backslash)
# characters.
def quote_string(s)
@@ -90,6 +119,10 @@ module ActiveRecord
value.to_s(:db)
end
+ def prepare_binds_for_database(binds) # :nodoc:
+ binds.map(&:value_for_database)
+ end
+
private
def types_which_need_no_typecasting
@@ -109,8 +142,7 @@ module ActiveRecord
when Date, Time then "'#{quoted_date(value)}'"
when Symbol then "'#{quote_string(value.to_s)}'"
when Class then "'#{value}'"
- else
- "'#{quote_string(YAML.dump(value))}'"
+ else raise TypeError, "can't quote #{value.class.name}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
index 18ff869ea6..db20b60d60 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
@@ -28,8 +28,8 @@ module ActiveRecord
end
def visit_ColumnDefinition(o)
- sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
- column_sql = "#{quote_column_name(o.name)} #{sql_type}"
+ o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
+ column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
column_sql
end
@@ -98,9 +98,7 @@ module ActiveRecord
end
def quote_default_expression(value, column)
- column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
value = type_for_column(column).type_cast_for_database(value)
-
@conn.quote(value)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 68d8a2cd6a..7eaa89c9a7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -56,18 +56,6 @@ module ActiveRecord
end
end
- module TimestampDefaultDeprecation # :nodoc:
- def emit_warning_if_null_unspecified(options)
- return if options.key?(:null)
-
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- `#timestamp` was called without specifying an option for `null`. In Rails 5,
- this behavior will change to `null: false`. You should manually specify
- `null: true` to prevent the behavior of your existing migrations from changing.
- MSG
- end
- end
-
class ReferenceDefinition # :nodoc:
def initialize(
name,
@@ -167,8 +155,6 @@ module ActiveRecord
# The table definitions
# The Columns are stored as a ColumnDefinition in the +columns+ attribute.
class TableDefinition
- include TimestampDefaultDeprecation
-
# An array of ColumnDefinition objects, representing the column changes
# that have been defined.
attr_accessor :indexes
@@ -375,7 +361,9 @@ module ActiveRecord
# t.timestamps null: false
def timestamps(*args)
options = args.extract_options!
- emit_warning_if_null_unspecified(options)
+
+ options[:null] = false if options[:null].nil?
+
column(:created_at, :datetime, options)
column(:updated_at, :datetime, options)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index 42ea599a74..932aaf7aa7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -46,9 +46,10 @@ module ActiveRecord
private
def schema_default(column)
- default = column.type_cast_from_database(column.default)
+ type = lookup_cast_type_from_column(column)
+ default = type.type_cast_from_database(column.default)
unless default.nil?
- column.type_cast_for_schema(default)
+ type.type_cast_for_schema(default)
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 34d60493ea..f905669a24 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -380,7 +380,7 @@ module ActiveRecord
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
# In that case, +options+ and the block will be used by create_table.
def drop_table(table_name, options = {})
- execute "DROP TABLE #{quote_table_name(table_name)}"
+ execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
end
# Adds a new column to the named table.
@@ -851,14 +851,14 @@ module ActiveRecord
columns
end
- include TimestampDefaultDeprecation
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
# Additional options (like <tt>null: false</tt>) are forwarded to #add_column.
#
# add_timestamps(:suppliers, null: false)
#
def add_timestamps(table_name, options = {})
- emit_warning_if_null_unspecified(options)
+ options[:null] = false if options[:null].nil?
+
add_column table_name, :created_at, :datetime, options
add_column table_name, :updated_at, :datetime, options
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
index fd666c8c39..7f738e89c9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -69,16 +69,11 @@ module ActiveRecord
def rollback_records
ite = records.uniq
while record = ite.shift
- begin
- record.rolledback! full_rollback?
- rescue => e
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
- end
+ record.rolledback!(force_restore_state: full_rollback?)
end
ensure
ite.each do |i|
- i.rolledback!(full_rollback?, false)
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
end
end
@@ -89,16 +84,11 @@ module ActiveRecord
def commit_records
ite = records.uniq
while record = ite.shift
- begin
- record.committed!
- rescue => e
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
- end
+ record.committed!
end
ensure
ite.each do |i|
- i.committed!(false)
+ i.committed!(should_run_callbacks: false)
end
end
@@ -121,14 +111,11 @@ module ActiveRecord
def rollback
connection.rollback_to_savepoint(savepoint_name)
super
- rollback_records
end
def commit
connection.release_savepoint(savepoint_name)
super
- parent = connection.transaction_manager.current_transaction
- records.each { |r| parent.add_record(r) }
end
def full_rollback?; false; end
@@ -148,13 +135,11 @@ module ActiveRecord
def rollback
connection.rollback_db_transaction
super
- rollback_records
end
def commit
connection.commit_db_transaction
super
- commit_records
end
end
@@ -171,16 +156,28 @@ module ActiveRecord
else
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
end
+
@stack.push(transaction)
transaction
end
def commit_transaction
- @stack.pop.commit
+ inner_transaction = @stack.pop
+ inner_transaction.commit
+
+ if current_transaction.joinable?
+ inner_transaction.records.each do |r|
+ current_transaction.add_record(r)
+ end
+ else
+ inner_transaction.commit_records
+ end
end
- def rollback_transaction
- @stack.pop.rollback
+ def rollback_transaction(transaction = nil)
+ transaction ||= @stack.pop
+ transaction.rollback
+ transaction.rollback_records
end
def within_new_transaction(options = {})
@@ -197,7 +194,7 @@ module ActiveRecord
begin
commit_transaction
rescue Exception
- transaction.rollback unless transaction.state.completed?
+ rollback_transaction(transaction) unless transaction.state.completed?
raise
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index fa24d9b43f..436552d300 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -25,7 +25,6 @@ module ActiveRecord
autoload :TableDefinition
autoload :Table
autoload :AlterTable
- autoload :TimestampDefaultDeprecation
end
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
@@ -114,7 +113,8 @@ module ActiveRecord
class BindCollector < Arel::Collectors::Bind
def compile(bvs, conn)
- super(bvs.map { |bv| conn.quote(*bv.reverse) })
+ casted_binds = conn.prepare_binds_for_database(bvs)
+ super(casted_binds.map { |value| conn.quote(value) })
end
end
@@ -393,7 +393,7 @@ module ActiveRecord
end
def column_name_for_operation(operation, node) # :nodoc:
- node.to_sql
+ visitor.accept(node, collector).value
end
protected
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index e9a3c26c32..b61b717a61 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -502,7 +502,7 @@ module ActiveRecord
end
def drop_table(table_name, options = {})
- execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
+ execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
def rename_index(table_name, old_name, new_name)
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index af307b57a4..a489141d1a 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -5,7 +5,6 @@ module ActiveRecord
module ConnectionAdapters
# An abstract definition of a column in a table.
class Column
- TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
module Format
@@ -15,11 +14,7 @@ module ActiveRecord
attr_reader :name, :cast_type, :null, :sql_type, :default, :default_function
- delegate :type, :precision, :scale, :limit, :klass, :accessor,
- :text?, :number?, :binary?, :changed?,
- :type_cast_from_user, :type_cast_from_database, :type_cast_for_database,
- :type_cast_for_schema,
- to: :cast_type
+ delegate :precision, :scale, :limit, :type, to: :cast_type
# Instantiates a new column in the table.
#
@@ -30,13 +25,13 @@ module ActiveRecord
# <tt>company_name varchar(60)</tt>.
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
# +null+ determines if this column allows +NULL+ values.
- def initialize(name, default, cast_type, sql_type = nil, null = true)
+ def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
@name = name
@cast_type = cast_type
@sql_type = sql_type
@null = null
@default = default
- @default_function = nil
+ @default_function = default_function
end
def has_default?
@@ -77,6 +72,12 @@ module ActiveRecord
[self.class, name, default, cast_type, sql_type, null, default_function]
end
end
+
+ class NullColumn < Column
+ def initialize(name)
+ super name, nil, Type::Value.new
+ end
+ end
end
# :startdoc:
end
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index e54e3199ff..08d46fca96 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -1,5 +1,4 @@
require 'uri'
-require 'active_support/core_ext/string/filters'
module ActiveRecord
module ConnectionAdapters
@@ -210,30 +209,12 @@ module ActiveRecord
when Symbol
resolve_symbol_connection spec
when String
- resolve_string_connection spec
+ resolve_url_connection spec
when Hash
resolve_hash_connection spec
end
end
- def resolve_string_connection(spec)
- # Rails has historically accepted a string to mean either
- # an environment key or a URL spec, so we have deprecated
- # this ambiguous behaviour and in the future this function
- # can be removed in favor of resolve_url_connection.
- if configurations.key?(spec) || spec !~ /:/
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing a string to ActiveRecord::Base.establish_connection for a
- configuration lookup is deprecated, please pass a symbol
- (#{spec.to_sym.inspect}) instead.
- MSG
-
- resolve_symbol_connection(spec)
- else
- resolve_url_connection(spec)
- end
- end
-
# Takes the environment such as +:production+ or +:development+.
# This requires that the @configurations was initialized with a key that
# matches.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 23d8389abb..16f50fc594 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -395,11 +395,9 @@ module ActiveRecord
def exec_stmt(sql, name, binds)
cache = {}
- type_casted_binds = binds.map { |col, val|
- [col, type_cast(val, col)]
- }
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
- log(sql, name, type_casted_binds) do
+ log(sql, name, binds) do
if binds.empty?
stmt = @connection.prepare(sql)
else
@@ -410,7 +408,7 @@ module ActiveRecord
end
begin
- stmt.execute(*type_casted_binds.map { |_, val| val })
+ stmt.execute(*type_casted_binds)
rescue Mysql::Error => e
# Older versions of MySQL leave the prepared statement in a bad
# place when an error occurs. To support older MySQL versions, we
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index 1458fbf496..8f3628ec0e 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -2,18 +2,19 @@ module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
- attr_accessor :array
+ attr_reader :array, :oid, :fmod
+ alias :array? :array
- def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
+ def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil, oid = nil, fmod = nil)
if sql_type =~ /\[\]$/
@array = true
- super(name, default, cast_type, sql_type[0..sql_type.length - 3], null)
+ sql_type = sql_type[0..sql_type.length - 3]
else
@array = false
- super(name, default, cast_type, sql_type, null)
end
-
- @default_function = default_function
+ @oid = oid
+ @fmod = fmod
+ super(name, default, cast_type, sql_type, null, default_function)
end
def serial?
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index c203e6c604..e45a2f59d9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -18,7 +18,7 @@ module ActiveRecord
end
attr_reader :subtype, :delimiter
- delegate :type, to: :subtype
+ delegate :type, :user_input_in_time_zone, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
index e12ddd9901..7dadc09a44 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
@@ -11,7 +11,7 @@ module ActiveRecord
def type_cast_from_database(value)
if value.is_a?(::String)
- ::ActiveSupport::JSON.decode(value)
+ ::ActiveSupport::JSON.decode(value) rescue nil
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index 961e6224c4..3adfb8b9d8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -25,16 +25,7 @@ module ActiveRecord
to = type_cast_single extracted[:to]
if !infinity?(from) && extracted[:exclude_start]
- if from.respond_to?(:succ)
- from = from.succ
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Excluding the beginning of a Range is only partialy supported
- through `#succ`. This is not reliable and will be removed in
- the future.
- MSG
- else
- raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
- end
+ raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
end
::Range.new(from, to, extracted[:exclude_end])
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 607848884b..464adb4e23 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -56,10 +56,15 @@ module ActiveRecord
if column.type == :uuid && value =~ /\(\)/
value
else
- quote(value, column)
+ value = type_cast_from_column(column, value)
+ quote(value)
end
end
+ def lookup_cast_type_from_column(column) # :nodoc:
+ type_map.lookup(column.oid, column.fmod, column.sql_type)
+ end
+
private
def _quote(value)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index a90adcf4aa..519a9727fb 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -112,7 +112,7 @@ module ActiveRecord
end
def drop_table(table_name, options = {})
- execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
+ execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
# Returns true if schema exists.
@@ -183,15 +183,17 @@ module ActiveRecord
def columns(table_name)
# Limit, precision, and scale are all handled by the superclass.
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
- oid = get_oid_type(oid.to_i, fmod.to_i, column_name, type)
- default_value = extract_value_from_default(oid, default)
+ oid = oid.to_i
+ fmod = fmod.to_i
+ cast_type = get_oid_type(oid, fmod, column_name, type)
+ default_value = extract_value_from_default(cast_type, default)
default_function = extract_default_function(default_value, default)
- new_column(column_name, default_value, oid, type, notnull == 'f', default_function)
+ new_column(column_name, default_value, cast_type, type, notnull == 'f', default_function, oid, fmod)
end
end
- def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil) # :nodoc:
- PostgreSQLColumn.new(name, default, cast_type, sql_type, null, default_function)
+ def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil, oid = nil, fmod = nil) # :nodoc:
+ PostgreSQLColumn.new(name, default, cast_type, sql_type, null, default_function, oid, fmod)
end
# Returns the current database name.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 13bb5c187e..d789069f0b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -64,7 +64,7 @@ module ActiveRecord
# <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:variables</tt> - An optional hash of additional parameters that
# will be used in <tt>SET SESSION key = val</tt> calls on the connection.
- # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT</tt> statements
+ # * <tt>:insert_returning</tt> - An optional boolean to control the use of <tt>RETURNING</tt> for <tt>INSERT</tt> statements
# defaults to true.
#
# Any further options are used as connection parameters to libpq. See
@@ -144,7 +144,7 @@ module ActiveRecord
# AbstractAdapter
def prepare_column_options(column) # :nodoc:
spec = super
- spec[:array] = 'true' if column.respond_to?(:array) && column.array
+ spec[:array] = 'true' if column.array?
spec[:default] = "\"#{column.default_function}\"" if column.default_function
spec
end
@@ -609,12 +609,10 @@ module ActiveRecord
def exec_cache(sql, name, binds)
stmt_key = prepare_statement(sql)
- type_casted_binds = binds.map { |col, val|
- [col, type_cast(val, col)]
- }
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
- log(sql, name, type_casted_binds, stmt_key) do
- @connection.exec_prepared(stmt_key, type_casted_binds.map { |_, val| val })
+ log(sql, name, binds, stmt_key) do
+ @connection.exec_prepared(stmt_key, type_casted_binds)
end
rescue ActiveRecord::StatementInvalid => e
pgerror = e.original_exception
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 03dfd29a0a..02a3b65934 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -50,16 +50,6 @@ module ActiveRecord
end
end
- class SQLite3String < Type::String # :nodoc:
- def type_cast_for_database(value)
- if value.is_a?(::String) && value.encoding == Encoding::ASCII_8BIT
- value.encode(Encoding::UTF_8)
- else
- super
- end
- end
- end
-
# The SQLite3 adapter works SQLite 3.6.16 or newer
# with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
#
@@ -239,6 +229,12 @@ module ActiveRecord
case value
when BigDecimal
value.to_f
+ when String
+ if value.encoding == Encoding::ASCII_8BIT
+ super(value.encode(Encoding::UTF_8))
+ else
+ super
+ end
else
super
end
@@ -280,11 +276,9 @@ module ActiveRecord
end
def exec_query(sql, name = nil, binds = [])
- type_casted_binds = binds.map { |col, val|
- [col, type_cast(val, col)]
- }
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
- log(sql, name, type_casted_binds) do
+ log(sql, name, binds) do
# Don't cache statements if they are not prepared
if without_prepared_statement?(binds)
stmt = @connection.prepare(sql)
@@ -302,7 +296,7 @@ module ActiveRecord
stmt = cache[:stmt]
cols = cache[:cols] ||= stmt.columns
stmt.reset!
- stmt.bind_params type_casted_binds.map { |_, val| val }
+ stmt.bind_params type_casted_binds
end
ActiveRecord::Result.new(cols, stmt.to_a)
@@ -498,7 +492,6 @@ module ActiveRecord
def initialize_type_map(m)
super
m.register_type(/binary/i, SQLite3Binary.new)
- register_class_with_limit m, %r(char)i, SQLite3String
end
def table_structure(table_name)