Commit Graph

18825 Commits

Author SHA1 Message Date
Ryuta Kamizono 7e08b6d2b2 Address to "DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1"
Caused by #36210.
2019-06-28 00:28:47 +09:00
Eileen M. Uchitelle 40246125b9
Merge pull request #36560 from eileencodes/warn-if-database-yml-cant-be-read
Warn if we can't read the yaml to create database tasks
2019-06-27 10:08:08 -04:00
eileencodes df6b0de7d9 Load initial database.yml once, and warn if we can't create tasks
For multiple databases we attempt to generate the tasks by reading the
database.yml before the Rails application is booted. This means that we
need to strip out ERB since it could be reading Rails configs.

In some cases like https://github.com/rails/rails/issues/36540 the ERB
is too complex and we can't overwrite with the DummyCompilier we used in
https://github.com/rails/rails/pull/35497. For the complex causes we
simply issue a warning that says we couldn't infer the database tasks
from the database.yml.

While working on this I decided to update the code to only load the
database.yml once initially so that we avoid having to issue the same
warning multiple times. Note that this had no performance impact in my
testing and is merely for not having to save the error off somewhere.
Also this feels cleaner.

Note that this will not break running tasks that exist, it will just
mean that tasks for multi-db like `db:create:other_db` will not be
generated. If the database.yml is actually unreadable it will blow up
during normal rake task calls.

Fixes #36540
2019-06-27 09:54:25 -04:00
Ryuta Kamizono f6db8b8d82 `length(title)` is a safe SQL string since #36448 2019-06-26 08:56:00 +09:00
Rafael França b65f88652f
Merge pull request #36210 from vishaltelangre/raise-record-invalid-when-associations-fail-to-save-due-to-uniqueness-failure
Fix: ActiveRecord::RecordInvalid is not raised when an associated record fails to #save! due to uniqueness validation failure
2019-06-24 13:59:15 -04:00
Kasper Timm Hansen ef1dbd8cc7
Schema Cache: extract deduplication commonality 2019-06-21 18:20:16 +02:00
Jean Boussier bba7c63a66 Also deduplicate schema cache data when using the init_with interface 2019-06-21 12:11:16 +02:00
Ryuta Kamizono 3218459c28
Merge pull request #36526 from yahonda/test_statement_cache_with_in_clause_pg
Address test_statement_cache_with_in_clause failure
2019-06-21 06:40:02 +09:00
Yasuo Honda 688da62a4c Address test_statement_cache_with_in_clause failure due to nondeterministic sort order
This failure is occasional, does not always reproduce.

```ruby
$ cd activerecord
$ bundle exec rake test_postgresql
... snip ...

....F

Failure:
ActiveRecord::BindParameterTest#test_statement_cache_with_in_clause [/home/yahonda/git/rails/activerecord/test/cases/bind_parameter_test.rb:97]:
Expected: [1, 3]
  Actual: [3, 1]

rails test home/yahonda/git/rails/activerecord/test/cases/bind_parameter_test.rb:93

```
2019-06-20 15:07:58 +00:00
eileencodes 4feeee2abe Revert schema dumper to use strings rather than integers
I think we should change this, but not in 6-0-stable since that's
already in RC and I was trying to only make changes that won't require
any app changes.

This reverts a portion of https://github.com/rails/rails/pull/36439 that
made all schema migration version numbers get dumped as an integer.
While it doesn't _really_ matter it did change behavior. We should bring
this back in 6.1 with a deprecation.
2019-06-20 14:00:42 +02:00
Ryuta Kamizono e14f3f3c11
Merge pull request #36520 from kamipo/test_case_for_deterministic_order
Add test cases to ensure deterministic order for ordinal methods
2019-06-20 18:07:40 +09:00
Kasper Timm Hansen 8a20a40fef
Merge pull request #36518 from Shopify/drop-schema-cache-column-hash
Stop serializing and parsing columns_hash in Active Record schema caches
2019-06-19 21:22:01 +02:00
Guilherme Mansur fd3532204c Better error message for calling columns_hash
When a record does not have a table name, as in the case for a record
with `self.abstract_class = true` and no `self.table_name` set the error
message raises a cryptic:
"ActiveRecord::StatementInvalid: Could not find table ''" this patch now
raises a new `TableNotSpecified Error`

Fixes: #36274

Co-Authored-By: Eugene Kenny <elkenny@gmail.com>
2019-06-19 14:23:03 -04:00
Jean Boussier dc99e5fe65 Stop serializing and parsing columns_hash in Active Record schema caches 2019-06-19 18:19:44 +02:00
Ryuta Kamizono 2c96b046ec Add test cases to ensure deterministic order for ordinal methods
Before 1340498d2, `order` with no-op value (e.g. `nil`, `""`) had broken
the contract of ordinal methods, which returns a result deterministic
ordered.
2019-06-19 23:18:22 +09:00
Kasper Timm Hansen aae270de9e
Merge pull request #35891 from Shopify/schema-cache-deduplication
Deduplicate various Active Record schema cache structures
2019-06-19 13:04:32 +02:00
Ryuta Kamizono d29d459897 Avoid redundant `time.getutc` call if it is already utc time object
Currently `type.serialize` and `connection.{quote|type_cast}` for a time
object always does `time.getutc` call regardless of whether it is
already utc time object or not, that duplicated proccess
(`connection.type_cast(type.serialize(time))`) allocates extra/useless
time objects for each type casting.

This avoids that redundant `time.getutc` call if it is already utc time
object. In the case of a model has timestamps (`created_at` and
`updated_at`), it avoids 6,000 time objects allocation for 1,000 times
`model.save`.

```ruby
ObjectSpace::AllocationTracer.setup(%i{path line type})

pp ObjectSpace::AllocationTracer.trace {
  1_000.times { User.create }
}.select { |k, _| k[0].end_with?("quoting.rb", "time_value.rb") }
```

Before (c104bfe424):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  203,
  :T_ARRAY]=>[1004, 0, 778, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  220,
  :T_STRING]=>[2, 0, 2, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  209,
  :T_ARRAY]=>[8, 0, 8, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  57,
  :T_ARRAY]=>[4, 0, 4, 1, 1, 0],
 ["~/rails/activemodel/lib/active_model/type/helpers/time_value.rb",
  17,
  :T_DATA]=>[4000, 0, 3096, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  120,
  :T_DATA]=>[2000, 0, 1548, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  126,
  :T_STRING]=>[4000, 0, 3096, 0, 1, 0]}
```

After (this change):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  203,
  :T_ARRAY]=>[1004, 0, 823, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  220,
  :T_STRING]=>[2, 0, 2, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  209,
  :T_ARRAY]=>[8, 0, 8, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  57,
  :T_ARRAY]=>[4, 0, 4, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  126,
  :T_STRING]=>[2000, 0, 1638, 0, 1, 0]}
```
2019-06-18 01:03:21 +09:00
Ryuta Kamizono cb0299c9eb PostgreSQL: Fix GROUP BY with ORDER BY virtual count attribute
GROUP BY with virtual count attribute is invalid for almost all
databases, but it is valid for PostgreSQL, and it had worked until Rails
5.2.2, so it is a regression for Rails 5.2.3 (caused by 311f001).

I can't find perfectly solution for fixing this for now, but I would not
like to break existing apps, so I decided to allow referencing virtual
count attribute in ORDER BY clause when GROUP BY aggrigation (it partly
revert the effect of 311f001) to fix the regression #36022.

Fixes #36022.
2019-06-17 22:14:29 +09:00
Ryuta Kamizono b57b23a37b Remove unused `Arel::Attributes.for`
`Arel::Attributes.for` is no longer used since https://github.com/rails/arel/pull/196.
2019-06-15 23:59:41 +09:00
Ryuta Kamizono 85b4ba2836 No allocation `Arel::Visitors::ToSql#visit`
Each `visit o, collector` allocates one extra array due to
receiving args by splat array.

2c3332cc4c/activerecord/lib/arel/visitors/visitor.rb (L27-L29)

Currently 1,000 times `User.where(id: 1).to_sql` allocates 13,000
arrays in `visitor.accept`. This avoids receiving args by splat array,
it makes `visitor.accept` no array allocation.

```ruby
ObjectSpace::AllocationTracer.setup(%i{path line type})

pp ObjectSpace::AllocationTracer.trace {
  1_000.times { User.where(id: 1).to_sql }
}.select { |k, _| k[2] == :T_ARRAY && k[0].end_with?("visitor.rb", "to_sql.rb") }
```

Before (2c3332cc4c):

```
{["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  18,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb",
  11,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/visitor.rb",
  12,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  788,
  :T_ARRAY]=>[3000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  794,
  :T_ARRAY]=>[3000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  156,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  443,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  603,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0],
 ["~/rails/activerecord/lib/arel/visitors/to_sql.rb",
  611,
  :T_ARRAY]=>[1000, 0, 0, 0, 0, 0]}
```

After (this change):

```
{}
```
2019-06-15 21:48:12 +09:00
Ryuta Kamizono e919a00848 Should find last created record
Tables in tests are not always empty so `klass.first` does not always
find last created record.

Fixes #36479.
2019-06-15 08:19:31 +09:00
Ryuta Kamizono 74174d786b Ensure to reset actually used `@connection.schema_migration`'s table name
https://buildkite.com/rails/rails/builds/61744#f12cc6cf-7458-4131-917a-9735615f6259/999-1010
2019-06-15 08:04:18 +09:00
Ryuta Kamizono ce7ccd8168 Fix `test_schema_names` to include "hint_plan" schema 2019-06-15 07:29:33 +09:00
eileencodes cd881ab169 Move while_preventing_writes from conn to handler
If we put the `while_preventing_writes` on the connection then the
middleware that sends reads to the primary and ensures they can't write
will not work. The `while_preventing_writes` will only be applied to the
connection which it's called on - which in the case of the middleware is
Ar::Base.

This worked fine if you called it directly like
`OtherDbConn.connection.while_preventing_writes` but Rails didn't have a
way of knowing you wanted to call it on all the connections.

The change here moves the `while_preventing_writes` method from the
connection to the handler so that it can block writes to all queries for
that handler. This will apply to all the connections associated with
that handler.
2019-06-14 16:11:36 -04:00
Eileen M. Uchitelle f813119aec
Merge pull request #36439 from eileencodes/move-schema-migration-to-migration-context
Move SchemaMigration to migration_context
2019-06-14 14:17:49 -04:00
eileencodes 7cc27d749c Move SchemaMigration to migration_context
This PR moves the `schema_migration` to `migration_context` so that we
can access the `schema_migration` per connection.

This does not change behavior of the SchemaMigration if you are using
one database. This also does not change behavior of any public APIs.
`Migrator` is private as is `MigrationContext` so we can change these as
needed.

We now need to pass a `schema_migration` to `Migrator` so that we can
run migrations on the right connection outside the context of a rake
task.

The bugs this fixes were discovered while debugging the issues around
the SchemaCache on initialization with multiple database. It was clear
that `get_all_versions` wouldn't work without these changes outside the
context of a rake task (because in the rake task we establish a
connection and change AR::Base.connection to the db we're running on).

Because the `SchemaCache` relies on the `SchemaMigration` information we
need to make sure we store it per-connection rather than on
ActiveRecord::Base.

[Eileen M. Uchitelle & Aaron Patterson]
2019-06-14 11:15:08 -04:00
Ryuta Kamizono c284771691
Merge pull request #36484 from albertoalmagro/alberto/reverse-column-is-reversible
[ci skip] Update docs as `remove_column` can be reversed
2019-06-14 23:47:07 +09:00
Ryuta Kamizono c0af72bf86 Fix rubocop violations 2019-06-14 23:32:15 +09:00
Alberto Almagro 88de317992 [ci skip] Update docs as `remove_column` can be reversed
As `remove_column` can be reversed when a type is provided this example
was not accurate anymore.
2019-06-14 16:00:10 +02:00
Ryuta Kamizono 05c718a109 Allocation on demand in transactions
Currently 1,000 transactions creates 10,000 objects regardless whether
it is necessary or not.

This makes allocation on demand in transactions, now 1,000 transactions
creates required 5,000 objects only by default.

```ruby
ObjectSpace::AllocationTracer.setup(%i{path line type})

pp ObjectSpace::AllocationTracer.trace {
  1_000.times { User.create }
}.select { |k, _| k[0].end_with?("transaction.rb") }
```

Before (95d038f):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  209,
  :T_HASH]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  210,
  :T_OBJECT]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  210,
  :T_HASH]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  80,
  :T_OBJECT]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  8,
  :T_ARRAY]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  81,
  :T_ARRAY]=>[1000, 0, 715, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  289,
  :T_STRING]=>[1000, 0, 714, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  116,
  :T_ARRAY]=>[1000, 0, 714, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  120,
  :T_ARRAY]=>[1000, 0, 714, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  121,
  :T_HASH]=>[1000, 0, 714, 0, 1, 0]}
```

After (this change):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  213,
  :T_HASH]=>[1000, 0, 739, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  214,
  :T_OBJECT]=>[1000, 0, 739, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  214,
  :T_HASH]=>[1000, 0, 739, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  81,
  :T_OBJECT]=>[1000, 0, 739, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb",
  304,
  :T_STRING]=>[1000, 0, 738, 0, 1, 0]}
```
2019-06-14 07:16:53 +09:00
jeffdoering e2d11970f2 Make ActiveRecord `ConnectionPool.connections` thread-safe. (#36473)
* Make ActiveRecord `ConnectionPool.connections` thread-safe.

ConnectionPool documentation is clear on the need to synchronize
access to @connections but also states that public methods do not
require synchronization. Existing code exposed @connections
directly via attr_reader. The fix uses synchronize() to lock
@connections then returns a copy to the caller using Array.dup().

Includes comments on the connections method that thread-safe access
to the connections array does not imply thread-safety of accessing
methods on the actual connections.

Adds a test-case that modifies the pool using a supported method
in one thread  while a second thread accesses pool.connections.
The test fails without this patch.

Fixes #36465.

* Update activerecord/test/cases/connection_pool_test.rb

[jeffdoering + Rafael Mendonça França]
2019-06-13 14:23:13 -04:00
Ryuta Kamizono 5a8714e559 Ensure to reset migration version after testing migration
"schema_migrations" table may be hard dropped before, so the reset
migration version should be done in ensure block.

https://buildkite.com/rails/rails/builds/61697#18d6f3ac-2257-4f4b-8efc-4010464c4d9a/999-1011
2019-06-13 23:51:11 +09:00
Ryuta Kamizono e9e7e7d3fd Reset migration version before testing migration
https://buildkite.com/rails/rails/builds/61695#373bb1a7-677f-49ec-95e7-a92467fefd60/1076-1084
2019-06-13 23:37:38 +09:00
Ryuta Kamizono 4f7d32311e Avoid implicit rollback when testing migration
"schema_migrations" is hard dropped by some existing tests, so testing
migration in using transactional tests may cause implicit creation and
rollback "schema_migrations" table, it makes migration tests flaky.

https://buildkite.com/rails/rails/builds/61692#42383249-30be-4508-b1fb-a7bb27600c8e/999-1010
https://buildkite.com/rails/rails/builds/61694#6e462ad3-41d8-4e26-95ce-728495b0ac64/999-1010
2019-06-13 22:10:46 +09:00
Ryuta Kamizono 98a57aa5f6
Merge pull request #36472 from kamipo/empty_line_only_before_access_modifier
Enable `Layout/EmptyLinesAroundAccessModifier` cop
2019-06-13 18:36:23 +09:00
Ryuta Kamizono c5ecc338e8 Remove duplicated `table_exists?`
`table_exists?` is already exist in `ModelSchema`.

5cab344494/activerecord/lib/active_record/model_schema.rb (L339-L341)
2019-06-13 13:52:07 +09:00
Ryuta Kamizono 5cab344494 Clear schema cache when a table is created/dropped/renamed
Otherwise `Model.table_exists?` returns the staled cache result.
2019-06-13 13:15:50 +09:00
Ryuta Kamizono c81af6ae72 Enable `Layout/EmptyLinesAroundAccessModifier` cop
We sometimes say "✂️ newline after `private`" in a code review (e.g.
https://github.com/rails/rails/pull/18546#discussion_r23188776,
https://github.com/rails/rails/pull/34832#discussion_r244847195).

Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style
`EnforcedStyle: only_before` (https://github.com/rubocop-hq/rubocop/pull/7059).

That cop and enforced style will reduce the our code review cost.
2019-06-13 12:00:45 +09:00
Eileen M. Uchitelle 96f142ae76
Merge pull request #36440 from malept/multi-db-abort_if_pending_migrations-task
Add support for multiple databases to `rails db:abort_if_pending_migrations`
2019-06-11 08:17:50 -04:00
Ryuta Kamizono 4dcb46182a
Merge pull request #36448 from kamipo/allow_column_name_with_simple_function_call
Allow column name with function (e.g. `length(title)`) as safe SQL string
2019-06-11 14:25:46 +09:00
Mark Lee cb8b57d07e Convert the db:abort_if_pending_migrations task to be multi-DB aware 2019-06-10 18:01:32 -07:00
Ryuta Kamizono 0542e0608f All modern adapters returns a numeric value as the result of numeric calculation 2019-06-11 01:49:48 +09:00
Ryuta Kamizono 64d8c54e16 Allow column name with function (e.g. `length(title)`) as safe SQL string
Currently, almost all "Dangerous query method" warnings are false alarm.
As long as almost all the warnings are false alarm, developers think
"Let's ignore the warnings by using `Arel.sql()`, it actually is false
alarm in practice.", so I think we should effort to reduce false alarm
in order to make the warnings valuable.

This allows column name with function (e.g. `length(title)`) as safe SQL
string, which is very common false alarm pattern, even in the our
codebase.

Related 6c82b6c99, 6607ecb2a, #36420.

Fixes #32995.
2019-06-10 07:36:58 +09:00
Ryuta Kamizono 6607ecb2a1 Allow `column_name AS alias` as safe SQL string 2019-06-10 06:21:23 +09:00
Ryuta Kamizono 1340498d21 Refactor `disallow_raw_sql!` to avoid `split(/\s*,\s*/)` to order args
`split(/\s*,\s*/)` to order args and then `permit.match?` one by one is
much slower than `permit.match?` once.
2019-06-09 14:14:10 +09:00
Wojciech Wnętrzak 3e9fbfc182
Add forgotten nodoc to dump_schema method.
Method added in https://github.com/rails/rails/pull/36416
2019-06-07 17:24:14 +02:00
Ryuta Kamizono 7cc67a368c NULLS { FIRST | LAST } is safe SQL string since 6c82b6c99d
There is no need to be wrapped by `Arel.sql()`.
2019-06-07 17:17:51 +09:00
Ryuta Kamizono e3c1f42b31
Merge pull request #36429 from bogdan/fix-preloading-duplicate-records
Fix preloading on AR::Relation where records are duplicated by a join
2019-06-07 07:38:27 +09:00
Bogdan Gusiev 30c1999df1 Fix preloading on AR::Relation where records are duplicated by a join 2019-06-06 15:14:40 +03:00
Ryuta Kamizono 648144649a
Merge pull request #36426 from abhaynikam/bump-codeclimate-rubocop-version
Bump rubocop to 0.71
2019-06-06 20:40:20 +09:00