| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
| |
Sqlite3::DatabaseStatements and make those that are private in Abstract::DatabaseStatements private for sqlite3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
regression for fixture loading
d8d6bd5 makes fixture loading to bulk statements by using
`execute_batch` for sqlite3 adapter. But `execute_batch` is slower and
it caused the performance regression for fixture loading.
In sqlite3 1.4.0, it have new batch method `execute_batch2`. I've
confirmed `execute_batch2` is extremely faster than `execute_batch`.
So I think it is worth to upgrade sqlite3 to 1.4.0 to use that method.
Before:
```
% ARCONN=sqlite3 bundle exec ruby -w -Itest test/cases/associations/eager_test.rb -n test_eager_loading_too_may_ids
Using sqlite3
Run options: -n test_eager_loading_too_may_ids --seed 35790
# Running:
.
Finished in 202.437406s, 0.0049 runs/s, 0.0049 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
ARCONN=sqlite3 bundle exec ruby -w -Itest -n test_eager_loading_too_may_ids 142.57s user 60.83s system 98% cpu 3:27.08 total
```
After:
```
% ARCONN=sqlite3 bundle exec ruby -w -Itest test/cases/associations/eager_test.rb -n test_eager_loading_too_may_ids
Using sqlite3
Run options: -n test_eager_loading_too_may_ids --seed 16649
# Running:
.
Finished in 8.471032s, 0.1180 runs/s, 0.1180 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
ARCONN=sqlite3 bundle exec ruby -w -Itest -n test_eager_loading_too_may_ids 10.71s user 1.36s system 95% cpu 12.672 total
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* The database version will get cached in the schema cache file during the
schema cache dump. When the database version check happens, the version will
be pulled from the schema cache and thus avoid querying the database for
the version.
* If the schema cache file doesn't exist, we'll query the database for the
version and cache it on the schema cache object.
* To facilitate this change, all connection adapters now implement
#get_database_version and #database_version. #database_version returns the
value from the schema cache.
* To take advantage of the cached database version, the database version check
will now happen after the schema cache is set on the connection in the
connection pool.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Before:
```
(16.4ms) TRUNCATE TABLE `author_addresses`
(20.5ms) TRUNCATE TABLE `authors`
(19.4ms) TRUNCATE TABLE `posts`
```
After:
```
Truncate Tables (19.5ms) TRUNCATE TABLE `author_addresses`;
TRUNCATE TABLE `authors`;
TRUNCATE TABLE `posts`
```
|
|
|
|
| |
This is to easier make `truncate_tables` to bulk statements.
|
|
|
|
| |
It is to work that on `reconnect!` after `disconnect!`
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Since #23461, all adapters supports prepared statements, so that clears
the prepared statements cache is no longer database specific.
Actually, I struggled to identify the cause of random CI failure in
#23461, that was missing `@statements.clear` in `clear_cache!`.
This extracts `clear_cache!` to ensure the common concerns in the
abstract adapter.
|
|
|
|
|
| |
Adds a method to ActiveRecord allowing records to be inserted in bulk without instantiating ActiveRecord models. This method supports options for handling uniqueness violations by skipping duplicate records or overwriting them in an UPSERT operation.
ActiveRecord already supports bulk-update and bulk-destroy actions that execute SQL UPDATE and DELETE commands directly. It also supports bulk-read actions through `pluck`. It makes sense for it also to support bulk-creation.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Add `ActiveRecord::Base.connection.truncate` for SQLite3 adapter.
SQLite doesn't support `TRUNCATE TABLE`, but SQLite3 adapter can support
`ActiveRecord::Base.connection.truncate` by using `DELETE FROM`.
`DELETE` without `WHERE` uses "The Truncate Optimization",
see https://www.sqlite.org/lang_delete.html.
* Add `rails db:seed:replant` that truncates database tables and loads the seeds
Closes #34765
|
|
|
|
|
|
|
|
|
|
|
|
| |
I implemented Foreign key create in `create_table` for SQLite3 at
#24743. This follows #24743 to implement `add_foreign_key` and
`remove_foreign_key`.
Unfortunately SQLite3 has one limitation that
`PRAGMA foreign_key_list(table-name)` doesn't have constraint name.
So we couldn't implement find/remove foreign key by name for now.
Fixes #35207.
Closes #31343.
|
| |
|
| |
|
| |
|
|
|
|
| |
`ActiveRecord::ConnectionAdapters::SQLite3Adapter#valid_alter_table_type?`
|
| |
|
|
|
|
|
|
| |
BEGIN transaction would cause COMMIT or ROLLBACK, so unless COMMIT and
ROLLBACK aren't treated as write queries as well as BEGIN, the
`ReadOnlyError` would be raised.
|
| |
|
|
|
|
|
| |
Otherwise `save` method would raise the `ReadOnlyError` against `BEGIN`
and `ROLLBACK` queries.
|
|
|
|
| |
Follow up #34505.
|
|
|
|
|
|
|
| |
I originally named this `StatementInvalid` because that's what we do in
GitHub, but `@tenderlove` pointed out that this means apps can't test
for or explitly rescue this error. `StatementInvalid` is pretty broad so
I've renamed this to `ReadOnlyError`.
|
|
|
|
| |
And hide the `READ_QUERY` internal constant.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This PR adds the ability to prevent writes to a database even if the
database user is able to write (ie the database is a primary and not a
replica).
This is useful for a few reasons: 1) when converting your database from
a single db to a primary/replica setup - you can fix all the writes on
reads early on, 2) when we implement automatic database switching or
when an app is manually switching connections this feature can be used
to ensure reads are reading and writes are writing. We want to make sure
we raise if we ever try to write in read mode, regardless of database
type and 3) for local development if you don't want to set up multiple
databases but do want to support rw/ro queries.
This should be used in conjunction with `connected_to` in write mode.
For example:
```
ActiveRecord::Base.connected_to(role: :writing) do
Dog.connection.while_preventing_writes do
Dog.create! # will raise because we're preventing writes
end
end
ActiveRecord::Base.connected_to(role: :reading) do
Dog.connection.while_preventing_writes do
Dog.first # will not raise because we're not writing
end
end
```
|
|\
| |
| | |
Redact SQL in errors
|
| |
| |
| |
| |
| | |
Move `ActiveRecord::StatementInvalid` SQL to error property.
Also add bindings as an error property.
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Before:
```
LOG: execute <unnamed>: SELECT t.oid, t.typname
FROM pg_type as t
WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')
LOG: execute <unnamed>: SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
FROM pg_type as t
LEFT JOIN pg_range as r ON oid = rngtypid
WHERE
t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
OR t.typtype IN ('r', 'e', 'd')
OR t.typinput::varchar = 'array_in'
OR t.typelem != 0
LOG: statement: SHOW TIME ZONE
LOG: statement: SELECT 1
LOG: execute <unnamed>: SELECT COUNT(*)
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
AND c.relname = 'accounts'
AND n.nspname = ANY (current_schemas(false))
```
After:
```
LOG: execute <unnamed>: SELECT t.oid, t.typname
FROM pg_type as t
WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')
LOG: execute <unnamed>: SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
FROM pg_type as t
LEFT JOIN pg_range as r ON oid = rngtypid
WHERE
t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
OR t.typtype IN ('r', 'e', 'd')
OR t.typinput::varchar = 'array_in'
OR t.typelem != 0
LOG: statement: SHOW TIME ZONE
LOG: statement: SELECT 1
LOG: execute <unnamed>: SELECT COUNT(*)
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
AND c.relname = 'accounts'
AND n.nspname = ANY (current_schemas(false))
```
|
|
|
|
|
| |
Change `#bind_params_length` in SQLite adapter to return the default
maximum amount (999). See https://www.sqlite.org/limits.html
|
|
|
|
|
|
|
| |
I don't prefer to extract it for one adapter even though all adapters
also does.
Related to #34227.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since Rails 6.0 will support Ruby 2.4.1 or higher
`# frozen_string_literal: true` magic comment is enough to make string object frozen.
This magic comment is enabled by `Style/FrozenStringLiteralComment` cop.
* Exclude these files not to auto correct false positive `Regexp#freeze`
- 'actionpack/lib/action_dispatch/journey/router/utils.rb'
- 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb'
It has been fixed by https://github.com/rubocop-hq/rubocop/pull/6333
Once the newer version of RuboCop released and available at Code Climate these exclude entries should be removed.
* Replace `String#freeze` with `String#-@` manually if explicit frozen string objects are required
- 'actionpack/test/controller/test_case_test.rb'
- 'activemodel/test/cases/type/string_test.rb'
- 'activesupport/lib/active_support/core_ext/string/strip.rb'
- 'activesupport/test/core_ext/string_ext_test.rb'
- 'railties/test/generators/actions_test.rb'
|
|
|
|
|
|
|
| |
method returns an array of hashes, not a hash
e.g. Hash.try_convert(result) calls #to_hash and raises a TypeError
[Gannon McGibbon + Kevin Cheng]
|
|
|
|
|
| |
Follow up #33874.
Related #23393.
|
| |
|
|\
| |
| | |
Omit BEGIN/COMMIT statements for empty transactions
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
If a transaction is opened and closed without any queries being run, we
can safely omit the `BEGIN` and `COMMIT` statements, as they only exist
to modify the connection's behaviour inside the transaction. This
removes the overhead of those statements when saving a record with no
changes, which makes workarounds like `save if changed?` unnecessary.
This implementation buffers transactions inside the transaction manager
and materializes them the next time the connection is used. For this to
work, the adapter needs to guard all connection use with a call to
`materialize_transactions`. Because of this, adapters must opt in to get
this new behaviour by implementing `supports_lazy_transactions?`.
If `raw_connection` is used to get a reference to the underlying
database connection, the behaviour is disabled and transactions are
opened eagerly, as we can't know how the connection will be used.
However when the connection is checked back into the pool, we can assume
that the application won't use the reference again and reenable lazy
transactions. This prevents a single `raw_connection` call from
disabling lazy transactions for the lifetime of the connection.
|
| |
| |
| |
| | |
Fixes #33520.
|
|/
|
|
| |
Related to #33520
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Related #31201.
If creating custom primary key (like a string) in SQLite, it would also
create an internal index implicitly which named begin with "sqlite_".
It need to be hidden since the internal object names are reserved and
prohibited for public use.
See https://www.sqlite.org/fileformat2.html#intschema
Fixes #33320.
|
|\
| |
| |
| | |
Support readonly option in SQLite3Adapter
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Readonly sqlite database files are very useful as a data format for
storing configuration/lookup data that is too complicated for YAML
files. But since such files would typically be committed to a source
control repository, it's important to ensure that they are truly safe
from being inadvertently modified. Unfortunately using unix permissions
isn't enough, as sqlite will "helpfully" add the write bit to a database
file whenever it's written to.
sqlite3-ruby has supported a `:readonly` option since version 1.3.2 (see
https://github.com/sparklemotion/sqlite3-ruby/commit/c20c9f5dd2990042)
This simply passes that option through to the adapter if present in the
config hash. I think this is best considered an adapter-specific option
since no other supported database has an identical concept.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Unlike other databases, changing SQLite3 table definitions need to create a temporary table.
While changing table operations, the original table needs dropped which caused
`SQLite3::ConstraintException: FOREIGN KEY constraint failed` if the table is referenced by foreign keys.
This pull request disables foreign keys by `disable_referential_integrity`.
Also `disable_referential_integrity` method needs to execute `defer_foreign_keys = ON`
to defer re-enabling foreign keys until the transaction is committed.
https://www.sqlite.org/pragma.html#pragma_defer_foreign_keys
Fixes #31988
- This `defer_foreign_keys = ON` has been supported since SQLite 3.8.0
https://www.sqlite.org/releaselog/3_8_0.html and Rails 6 requires SQLite 3.8 #32923 now
- <Models>.reset_column_information added to address `ActiveModel::UnknownAttributeError`
```
Error:
ActiveRecord::Migration::ForeignKeyChangeColumnTest#test_change_column_of_parent_table:
ActiveModel::UnknownAttributeError: unknown attribute 'name' for ActiveRecord::Migration::ForeignKeyChangeColumnTest::Post.
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
These OS versions have SQLite 3.8 or higher by default.
- macOS 10.10 (Yosemite) or higher
- Ubuntu 14.04 LTS or higher
Raising the minimum version of SQLite 3.8 introduces these changes:
- All of bundled adapters support `supports_multi_insert?`
- SQLite 3.8 always satisifies `supports_foreign_keys_in_create?` and `supports_partial_index?`
- sqlite adapter can support `alter_table` method for foreign key referenced tables by #32865
- Deprecated `supports_multi_insert?` method
|
|
|
|
| |
https://github.com/sparklemotion/sqlite3-ruby/blob/v1.3.13/lib/sqlite3/statement.rb#L101-L104
|
|
|
|
| |
Since #31422, `insert_fixtures` is deprecated.
|
|\
| |
| | |
Build a multi-statement query when inserting fixtures
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
- The `insert_fixtures` method can be optimized by making a single multi statement query for all fixtures having the same connection instead of doing a single query per table
- The previous code was bulk inserting fixtures for a single table, making X query for X fixture files
- This patch builds a single **multi statement query** for every tables. Given a set of 3 fixtures (authors, dogs, computers):
```ruby
# before
%w(authors dogs computers).each do |table|
sql = build_sql(table)
connection.query(sql)
end
# after
sql = build_sql(authors, dogs, computers)
connection.query(sql)
```
- `insert_fixtures` is now deprecated, `insert_fixtures_set` is the new way to go with performance improvement
- My tests were done with an app having more than 700 fixtures, the time it takes to insert all of them was around 15s. Using a single multi statement query, it took on average of 8 seconds
- In order for a multi statement to be executed, mysql needs to be connected with the `MULTI_STATEMENTS` [flag](https://dev.mysql.com/doc/refman/5.7/en/c-api-multiple-queries.html), which is done before inserting the fixtures by reconnecting to da the database with the flag declared. Reconnecting to the database creates some caveats:
1. We loose all open transactions; Inside the original code, when inserting fixtures, a transaction is open. Multple delete statements are [executed](https://github.com/rails/rails/blob/a681eaf22955734c142609961a6d71746cfa0583/activerecord/lib/active_record/fixtures.rb#L566) and finally the fixtures are inserted. The problem with this patch is that we need to open the transaction only after we reconnect to the DB otherwise reconnecting drops the open transaction which doesn't commit all delete statements and inserting fixtures doesn't work since we duplicated them (Primary key duplicate exception)...
- In order to fix this problem, the transaction is now open directly inside the `insert_fixtures` method, right after we reconnect to the db
- As an effect, since the transaction is open inside the `insert_fixtures` method, the DELETE statements need to be executed here since the transaction is open later
2. The same problem happens for the `disable_referential_integrity` since we reconnect, the `FOREIGN_KEY_CHECKS` is reset to the original value
- Same solution as 1. , the disable_referential_integrity can be called after we reconnect to the transaction
3. When the multi statement query is executed, no other queries can be performed until we paginate over the set of results, otherwise mysql throws a "Commands out of sync" [Ref](https://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html)
- Iterating over the set of results until `mysql_client.next_result` is false. [Ref](https://github.com/brianmario/mysql2#multiple-result-sets)
- Removed the `active_record.sql "Fixture delete"` notification, the delete statements are now inside the INSERT's one
- On mysql the `max_allowed_packet` is looked up:
1. Before executing the multi-statements query, we check the packet length of each statements, if the packet is bigger than the max_allowed_packet config, an `ActiveRecordError` is raised
2. Otherwise we concatenate the current sql statement into the previous and so on until the packet is `< max_allowed_packet`
|
|\ \
| | |
| | | |
Don't perform unnecessary check with false, just use true/false values
|
| | |
| | |
| | |
| | | |
@active on SQLite adapter.
|
| | |
| | |
| | |
| | |
| | | |
This method which is used only in the internal was introduced in
ac384820 and was renamed in #17579. It does not need to be exposed.
|
| | | |
|