From 52e050ed00b023968fecda82f19a858876a7c435 Mon Sep 17 00:00:00 2001 From: Lisa Ugray Date: Thu, 6 Jul 2017 12:59:33 -0400 Subject: Change sqlite3 boolean serialization to use 1 and 0 Abstract boolean serialization has been using 't' and 'f', with MySQL overriding that to use 1 and 0. This has the advantage that SQLite natively recognizes 1 and 0 as true and false, but does not natively recognize 't' and 'f'. This change in serialization requires a migration of stored boolean data for SQLite databases, so it's implemented behind a configuration flag whose default false value is deprecated. The flag itself can be deprecated in a future version of Rails. While loaded models will give the correct result for boolean columns without migrating old data, where() clauses will interact incorrectly with old data. While working in this area, also change the abstract adapter to use `"TRUE"` and `"FALSE"` as quoted values and `true` and `false` for unquoted. These are supported by PostreSQL, and MySQL remains overriden. --- .../lib/active_record/connection_adapters/abstract/quoting.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 61233dcc51..de78c6db44 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -106,19 +106,19 @@ module ActiveRecord end def quoted_true - "'t'".freeze + "TRUE".freeze end def unquoted_true - "t".freeze + true end def quoted_false - "'f'".freeze + "FALSE".freeze end def unquoted_false - "f".freeze + false end # Quote date/time values for use in SQL input. Includes microseconds -- cgit v1.2.3 From 831be98f9a6685da3410b0c9bf4143bd8dd647af Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Sun, 9 Jul 2017 20:41:28 +0300 Subject: Use frozen-string-literal in ActiveRecord --- .../lib/active_record/connection_adapters/abstract/connection_pool.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/database_limits.rb | 2 ++ .../active_record/connection_adapters/abstract/database_statements.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/query_cache.rb | 2 ++ activerecord/lib/active_record/connection_adapters/abstract/quoting.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/savepoints.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/schema_creation.rb | 2 ++ .../active_record/connection_adapters/abstract/schema_definitions.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/schema_dumper.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/schema_statements.rb | 2 ++ .../lib/active_record/connection_adapters/abstract/transaction.rb | 2 ++ 11 files changed, 22 insertions(+) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 627b753f01..c11b7b012f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "thread" require "concurrent/map" require "monitor" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb index 407e019326..7a9e7add24 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters # :nodoc: module DatabaseLimits 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 879626b72a..f2715cdab0 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters # :nodoc: module DatabaseStatements diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index c352ddfc11..077e8beba9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters # :nodoc: module QueryCache diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index de78c6db44..b637518fc8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/big_decimal/conversions" require "active_support/multibyte/chars" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb index 3a06f75292..52a796b926 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters module Savepoints 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 8865e7c703..8bf3879a4c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/string/strip" module ActiveRecord 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 a30fbe0e05..3b2c51ef94 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters #:nodoc: # Abstract representation of an index definition on a table. Instances of 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 34036d8a1d..9be26254b2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters # :nodoc: # The goal of this module is to move Adapter specific column 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 475463c4fd..989ebc81a9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "../../migration/join_table" require "active_support/core_ext/string/access" require "digest" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index f63d09039f..147e16e9fa 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord module ConnectionAdapters class TransactionState -- cgit v1.2.3 From 213796fb4936dce1da2f0c097a054e1af5c25c2c Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 24 Jul 2017 08:19:35 -0400 Subject: Refactor Active Record to let Arel manage bind params A common source of bugs and code bloat within Active Record has been the need for us to maintain the list of bind values separately from the AST they're associated with. This makes any sort of AST manipulation incredibly difficult, as any time we want to potentially insert or remove an AST node, we need to traverse the entire tree to find where the associated bind parameters are. With this change, the bind parameters now live on the AST directly. Active Record does not need to know or care about them until the final AST traversal for SQL construction. Rather than returning just the SQL, the Arel collector will now return both the SQL and the bind parameters. At this point the connection adapter will have all the values that it had before. A bit of this code is janky and something I'd like to refactor later. In particular, I don't like how we're handling associations in the predicate builder, the special casing of `StatementCache::Substitute` in `QueryAttribute`, or generally how we're handling bind value replacement in the statement cache when prepared statements are disabled. This also mostly reverts #26378, as it moved all the code into a location that I wanted to delete. /cc @metaskills @yahonda, this change will affect the adapters Fixes #29766. Fixes #29804. Fixes #26541. Close #28539. Close #24769. Close #26468. Close #26202. There are probably other issues/PRs that can be closed because of this commit, but that's all I could find on the first few pages. --- .../abstract/database_statements.rb | 50 +++++++++++++--------- .../connection_adapters/abstract/query_cache.rb | 4 +- .../connection_adapters/abstract/quoting.rb | 4 ++ 3 files changed, 36 insertions(+), 22 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 f2715cdab0..f687d3a7e8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -9,30 +9,36 @@ module ActiveRecord end # Converts an arel AST to SQL - def to_sql(arel, binds = []) - if arel.respond_to?(:ast) - collected = visitor.accept(arel.ast, collector) - collected.compile(binds, self).freeze + def to_sql(arel_or_sql_string, binds = []) + if arel_or_sql_string.respond_to?(:ast) + unless binds.empty? + raise "Passing bind parameters with an arel AST is forbidden. " \ + "The values must be stored on the AST directly" + end + sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value + [sql.freeze, binds || []] else - arel.dup.freeze + [arel_or_sql_string.dup.freeze, binds] end end # This is used in the StatementCache object. It returns an object that # can be used to query the database repeatedly. def cacheable_query(klass, arel) # :nodoc: - collected = visitor.accept(arel.ast, collector) if prepared_statements - klass.query(collected.value) + sql, binds = visitor.accept(arel.ast, collector).value + query = klass.query(sql) else - klass.partial_query(collected.value) + query = klass.partial_query(arel.ast) + binds = [] end + [query, binds] end # Returns an ActiveRecord::Result instance. def select_all(arel, name = nil, binds = [], preparable: nil) - arel, binds = binds_from_relation arel, binds - sql = to_sql(arel, binds) + arel = arel_from_relation(arel) + sql, binds = to_sql(arel, binds) if !prepared_statements || (arel.is_a?(String) && preparable.nil?) preparable = false else @@ -131,20 +137,23 @@ module ActiveRecord # # If the next id was calculated in advance (as in Oracle), it should be # passed in as +id_value+. - def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) - value = exec_insert(to_sql(arel, binds), name, binds, pk, sequence_name) + def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil) + sql, binds = to_sql(arel) + value = exec_insert(sql, name, binds, pk, sequence_name) id_value || last_inserted_id(value) end alias create insert # Executes the update statement and returns the number of rows affected. - def update(arel, name = nil, binds = []) - exec_update(to_sql(arel, binds), name, binds) + def update(arel, name = nil) + sql, binds = to_sql(arel) + exec_update(sql, name, binds) end # Executes the delete statement and returns the number of rows affected. - def delete(arel, name = nil, binds = []) - exec_delete(to_sql(arel, binds), name, binds) + def delete(arel, name = nil) + sql, binds = to_sql(arel) + exec_delete(sql, name, binds) end # Returns +true+ when the connection adapter supports prepared statement @@ -430,11 +439,12 @@ module ActiveRecord row && row.first end - def binds_from_relation(relation, binds) - if relation.is_a?(Relation) && binds.empty? - relation, binds = relation.arel, relation.bound_attributes + def arel_from_relation(relation) + if relation.is_a?(Relation) + relation.arel + else + relation end - [relation, binds] end # Fixture value is quoted by Arel, however scalar values diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 077e8beba9..ecf5201d12 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -92,8 +92,8 @@ module ActiveRecord def select_all(arel, name = nil, binds = [], preparable: nil) if @query_cache_enabled && !locked?(arel) - arel, binds = binds_from_relation arel, binds - sql = to_sql(arel, binds) + arel = arel_from_relation(arel) + sql, binds = to_sql(arel, binds) cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) } else super diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index b637518fc8..7b83bc319c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -24,6 +24,10 @@ module ActiveRecord return value.quoted_id end + if value.respond_to?(:value_for_database) + value = value.value_for_database + end + _quote(value) end -- cgit v1.2.3 From 846832ae54f93a480f37a14a10874767a6330086 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 24 Jul 2017 12:28:26 -0400 Subject: Fix test failures when prepared statements are disabled This also reverts the change to enable prepared statements by default on MySQL (though I suspect we could enable them and it'd be great). This change brings back a collector closer to the old `Bind` collector in Arel. However, this one lives in AR, since this is an AR specific need. Additionally, we only use it for statement caching, since the new substitute collector in Arel is higher performance for most cases. --- .../abstract/database_statements.rb | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 f687d3a7e8..00e54edac0 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -29,8 +29,9 @@ module ActiveRecord sql, binds = visitor.accept(arel.ast, collector).value query = klass.query(sql) else - query = klass.partial_query(arel.ast) - binds = [] + collector = PartialQueryCollector.new + parts, binds = visitor.accept(arel.ast, collector).value + query = klass.partial_query(parts) end [query, binds] end @@ -457,6 +458,28 @@ module ActiveRecord value end end + + class PartialQueryCollector + def initialize + @parts = [] + @binds = [] + end + + def << str + @parts << str + self + end + + def add_bind obj + @binds << obj + @parts << Arel::Nodes::BindParam.new(1) + self + end + + def value + [@parts, @binds] + end + end end end end -- cgit v1.2.3 From 7f58ef656b6bfa4e72a59dead9b9fa5346e531a1 Mon Sep 17 00:00:00 2001 From: Lisa Ugray Date: Tue, 25 Jul 2017 14:51:19 -0400 Subject: Clarify add_column limit documentation The limit option is ignored by PostgreSQL and may be ignored by 3rd party backends. Make this clear in the docs. Fixes #29922. --- .../lib/active_record/connection_adapters/abstract/schema_statements.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 989ebc81a9..e21f93856e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -511,6 +511,7 @@ module ActiveRecord # * :limit - # Requests a maximum column length. This is the number of characters for a :string column # and number of bytes for :text, :binary and :integer columns. + # This option is ignored by some backends. # * :default - # The column's default value. Use +nil+ for +NULL+. # * :null - -- cgit v1.2.3 From b52849d42137b1b2c0b09a67babcbf858f501926 Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Sun, 30 Jul 2017 21:52:31 +0900 Subject: Change http postgresql.org links to https [ci skip] It seems that it accepts only HTTPS connections. Ref: https://github.com/postgres/postgres/commit/7f77cbd996855a06fb742ea11adbe55c42b48fe2 --- .../active_record/connection_adapters/abstract/database_statements.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 00e54edac0..314a35207b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -227,7 +227,7 @@ module ActiveRecord # You should consult the documentation for your database to understand the # semantics of these different levels: # - # * http://www.postgresql.org/docs/current/static/transaction-iso.html + # * https://www.postgresql.org/docs/current/static/transaction-iso.html # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html # # An ActiveRecord::TransactionIsolationError will be raised if: -- cgit v1.2.3