activerecord 5.1.0 → 5.2.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +596 -450
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations.rb +77 -85
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +49 -35
- data/lib/active_record/associations/association_scope.rb +55 -55
- data/lib/active_record/associations/belongs_to_association.rb +30 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +66 -53
- data/lib/active_record/associations/collection_proxy.rb +30 -73
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +13 -2
- data/lib/active_record/associations/has_many_through_association.rb +37 -19
- data/lib/active_record/associations/has_one_association.rb +14 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency.rb +52 -96
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +27 -12
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +33 -216
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +22 -19
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +15 -13
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
- data/lib/active_record/connection_adapters/column.rb +4 -2
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +41 -61
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +60 -15
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +30 -42
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +81 -29
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +74 -58
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +199 -54
- data/lib/active_record/query_cache.rb +8 -10
- data/lib/active_record/querying.rb +5 -3
- data/lib/active_record/railtie.rb +62 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +48 -38
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +137 -207
- data/lib/active_record/relation.rb +132 -207
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +66 -25
- data/lib/active_record/relation/delegation.rb +45 -29
- data/lib/active_record/relation/finder_methods.rb +76 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +135 -103
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping.rb +12 -10
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +40 -12
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +38 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +6 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +24 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,27 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module SQLite3
|
4
|
-
module ColumnMethods
|
5
|
-
def primary_key(name, type = :primary_key, **options)
|
6
|
-
if %i(integer bigint).include?(type) && (options.delete(:auto_increment) == true || !options.key?(:default))
|
7
|
-
type = :primary_key
|
8
|
-
end
|
9
|
-
|
10
|
-
super
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
15
|
-
include ColumnMethods
|
16
|
-
|
17
7
|
def references(*args, **options)
|
18
8
|
super(*args, type: :integer, **options)
|
19
9
|
end
|
20
10
|
alias :belongs_to :references
|
21
|
-
end
|
22
11
|
|
23
|
-
|
24
|
-
|
12
|
+
private
|
13
|
+
def integer_like_primary_key_type(type, options)
|
14
|
+
:primary_key
|
15
|
+
end
|
25
16
|
end
|
26
17
|
end
|
27
18
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module SQLite3
|
4
|
-
|
6
|
+
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
5
7
|
private
|
6
|
-
|
7
8
|
def default_primary_key?(column)
|
8
9
|
schema_type(column) == :integer
|
9
10
|
end
|
@@ -1,13 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module SQLite3
|
4
6
|
module SchemaStatements # :nodoc:
|
7
|
+
# Returns an array of indexes for the given table.
|
8
|
+
def indexes(table_name)
|
9
|
+
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
|
10
|
+
# Indexes SQLite creates implicitly for internal use start with "sqlite_".
|
11
|
+
# See https://www.sqlite.org/fileformat2.html#intschema
|
12
|
+
next if row["name"].starts_with?("sqlite_")
|
13
|
+
|
14
|
+
index_sql = query_value(<<-SQL, "SCHEMA")
|
15
|
+
SELECT sql
|
16
|
+
FROM sqlite_master
|
17
|
+
WHERE name = #{quote(row['name'])} AND type = 'index'
|
18
|
+
UNION ALL
|
19
|
+
SELECT sql
|
20
|
+
FROM sqlite_temp_master
|
21
|
+
WHERE name = #{quote(row['name'])} AND type = 'index'
|
22
|
+
SQL
|
23
|
+
|
24
|
+
/\sWHERE\s+(?<where>.+)$/i =~ index_sql
|
25
|
+
|
26
|
+
columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
|
27
|
+
col["name"]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add info on sort order for columns (only desc order is explicitly specified, asc is
|
31
|
+
# the default)
|
32
|
+
orders = {}
|
33
|
+
if index_sql # index_sql can be null in case of primary key indexes
|
34
|
+
index_sql.scan(/"(\w+)" DESC/).flatten.each { |order_column|
|
35
|
+
orders[order_column] = :desc
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
IndexDefinition.new(
|
40
|
+
table_name,
|
41
|
+
row["name"],
|
42
|
+
row["unique"] != 0,
|
43
|
+
columns,
|
44
|
+
where: where,
|
45
|
+
orders: orders
|
46
|
+
)
|
47
|
+
end.compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_schema_dumper(options)
|
51
|
+
SQLite3::SchemaDumper.create(self, options)
|
52
|
+
end
|
53
|
+
|
5
54
|
private
|
55
|
+
def schema_creation
|
56
|
+
SQLite3::SchemaCreation.new(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_table_definition(*args)
|
60
|
+
SQLite3::TableDefinition.new(*args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def new_column_from_field(table_name, field)
|
64
|
+
default = \
|
65
|
+
case field["dflt_value"]
|
66
|
+
when /^null$/i
|
67
|
+
nil
|
68
|
+
when /^'(.*)'$/m
|
69
|
+
$1.gsub("''", "'")
|
70
|
+
when /^"(.*)"$/m
|
71
|
+
$1.gsub('""', '"')
|
72
|
+
else
|
73
|
+
field["dflt_value"]
|
74
|
+
end
|
75
|
+
|
76
|
+
type_metadata = fetch_type_metadata(field["type"])
|
77
|
+
Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, table_name, nil, field["collation"])
|
78
|
+
end
|
79
|
+
|
6
80
|
def data_source_sql(name = nil, type: nil)
|
7
81
|
scope = quoted_scope(name, type: type)
|
8
82
|
scope[:type] ||= "'table','view'"
|
9
83
|
|
10
|
-
sql = "SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence'"
|
84
|
+
sql = "SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence'".dup
|
11
85
|
sql << " AND name = #{scope[:name]}" if scope[:name]
|
12
86
|
sql << " AND type IN (#{scope[:type]})"
|
13
87
|
sql
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/connection_adapters/abstract_adapter"
|
2
4
|
require "active_record/connection_adapters/statement_pool"
|
3
5
|
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
@@ -7,7 +9,7 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
|
|
7
9
|
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
8
10
|
require "active_record/connection_adapters/sqlite3/schema_statements"
|
9
11
|
|
10
|
-
gem "sqlite3", "~> 1.3.6"
|
12
|
+
gem "sqlite3", "~> 1.3", ">= 1.3.6"
|
11
13
|
require "sqlite3"
|
12
14
|
|
13
15
|
module ActiveRecord
|
@@ -55,11 +57,10 @@ module ActiveRecord
|
|
55
57
|
ADAPTER_NAME = "SQLite".freeze
|
56
58
|
|
57
59
|
include SQLite3::Quoting
|
58
|
-
include SQLite3::ColumnDumper
|
59
60
|
include SQLite3::SchemaStatements
|
60
61
|
|
61
62
|
NATIVE_DATABASE_TYPES = {
|
62
|
-
primary_key: "
|
63
|
+
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
63
64
|
string: { name: "varchar" },
|
64
65
|
text: { name: "text" },
|
65
66
|
integer: { name: "integer" },
|
@@ -69,33 +70,38 @@ module ActiveRecord
|
|
69
70
|
time: { name: "time" },
|
70
71
|
date: { name: "date" },
|
71
72
|
binary: { name: "blob" },
|
72
|
-
boolean: { name: "boolean" }
|
73
|
+
boolean: { name: "boolean" },
|
74
|
+
json: { name: "json" },
|
73
75
|
}
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
+
##
|
78
|
+
# :singleton-method:
|
79
|
+
# Indicates whether boolean values are stored in sqlite3 databases as 1
|
80
|
+
# and 0 or 't' and 'f'. Leaving <tt>ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer</tt>
|
81
|
+
# set to false is deprecated. SQLite databases have used 't' and 'f' to
|
82
|
+
# serialize boolean values and must have old data converted to 1 and 0
|
83
|
+
# (its native boolean serialization) before setting this flag to true.
|
84
|
+
# Conversion can be accomplished by setting up a rake task which runs
|
85
|
+
#
|
86
|
+
# ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
87
|
+
# ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
|
88
|
+
# for all models and all boolean columns, after which the flag must be set
|
89
|
+
# to true by adding the following to your <tt>application.rb</tt> file:
|
90
|
+
#
|
91
|
+
# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
|
92
|
+
class_attribute :represent_boolean_as_integer, default: false
|
77
93
|
|
94
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
95
|
+
private
|
78
96
|
def dealloc(stmt)
|
79
97
|
stmt[:stmt].close unless stmt[:stmt].closed?
|
80
98
|
end
|
81
99
|
end
|
82
100
|
|
83
|
-
def update_table_definition(table_name, base) # :nodoc:
|
84
|
-
SQLite3::Table.new(table_name, base)
|
85
|
-
end
|
86
|
-
|
87
|
-
def schema_creation # :nodoc:
|
88
|
-
SQLite3::SchemaCreation.new self
|
89
|
-
end
|
90
|
-
|
91
|
-
def arel_visitor # :nodoc:
|
92
|
-
Arel::Visitors::SQLite.new(self)
|
93
|
-
end
|
94
|
-
|
95
101
|
def initialize(connection, logger, connection_options, config)
|
96
102
|
super(connection, logger, config)
|
97
103
|
|
98
|
-
@active =
|
104
|
+
@active = true
|
99
105
|
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
100
106
|
|
101
107
|
configure_connection
|
@@ -113,12 +119,6 @@ module ActiveRecord
|
|
113
119
|
sqlite_version >= "3.8.0"
|
114
120
|
end
|
115
121
|
|
116
|
-
# Returns true, since this connection adapter supports prepared statement
|
117
|
-
# caching.
|
118
|
-
def supports_statement_cache?
|
119
|
-
true
|
120
|
-
end
|
121
|
-
|
122
122
|
def requires_reloading?
|
123
123
|
true
|
124
124
|
end
|
@@ -135,12 +135,16 @@ module ActiveRecord
|
|
135
135
|
true
|
136
136
|
end
|
137
137
|
|
138
|
+
def supports_json?
|
139
|
+
true
|
140
|
+
end
|
141
|
+
|
138
142
|
def supports_multi_insert?
|
139
143
|
sqlite_version >= "3.7.11"
|
140
144
|
end
|
141
145
|
|
142
146
|
def active?
|
143
|
-
@active
|
147
|
+
@active
|
144
148
|
end
|
145
149
|
|
146
150
|
# Disconnects from the database if already connected. Otherwise, this
|
@@ -183,7 +187,7 @@ module ActiveRecord
|
|
183
187
|
# REFERENTIAL INTEGRITY ====================================
|
184
188
|
|
185
189
|
def disable_referential_integrity # :nodoc:
|
186
|
-
old =
|
190
|
+
old = query_value("PRAGMA foreign_keys")
|
187
191
|
|
188
192
|
begin
|
189
193
|
execute("PRAGMA foreign_keys = OFF")
|
@@ -267,53 +271,6 @@ module ActiveRecord
|
|
267
271
|
|
268
272
|
# SCHEMA STATEMENTS ========================================
|
269
273
|
|
270
|
-
def new_column_from_field(table_name, field) # :nondoc:
|
271
|
-
case field["dflt_value"]
|
272
|
-
when /^null$/i
|
273
|
-
field["dflt_value"] = nil
|
274
|
-
when /^'(.*)'$/m
|
275
|
-
field["dflt_value"] = $1.gsub("''", "'")
|
276
|
-
when /^"(.*)"$/m
|
277
|
-
field["dflt_value"] = $1.gsub('""', '"')
|
278
|
-
end
|
279
|
-
|
280
|
-
collation = field["collation"]
|
281
|
-
sql_type = field["type"]
|
282
|
-
type_metadata = fetch_type_metadata(sql_type)
|
283
|
-
new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation)
|
284
|
-
end
|
285
|
-
|
286
|
-
# Returns an array of indexes for the given table.
|
287
|
-
def indexes(table_name, name = nil) #:nodoc:
|
288
|
-
if name
|
289
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
290
|
-
Passing name to #indexes is deprecated without replacement.
|
291
|
-
MSG
|
292
|
-
end
|
293
|
-
|
294
|
-
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
|
295
|
-
sql = <<-SQL
|
296
|
-
SELECT sql
|
297
|
-
FROM sqlite_master
|
298
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
299
|
-
UNION ALL
|
300
|
-
SELECT sql
|
301
|
-
FROM sqlite_temp_master
|
302
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
303
|
-
SQL
|
304
|
-
index_sql = exec_query(sql).first["sql"]
|
305
|
-
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
306
|
-
where = match[1] if match
|
307
|
-
IndexDefinition.new(
|
308
|
-
table_name,
|
309
|
-
row["name"],
|
310
|
-
row["unique"] != 0,
|
311
|
-
exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
|
312
|
-
col["name"]
|
313
|
-
}, nil, nil, where)
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
274
|
def primary_keys(table_name) # :nodoc:
|
318
275
|
pks = table_structure(table_name).select { |f| f["pk"] > 0 }
|
319
276
|
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
@@ -333,19 +290,18 @@ module ActiveRecord
|
|
333
290
|
rename_table_indexes(table_name, new_name)
|
334
291
|
end
|
335
292
|
|
336
|
-
|
337
|
-
|
338
|
-
def valid_alter_table_type?(type)
|
339
|
-
type.to_sym != :primary_key
|
293
|
+
def valid_alter_table_type?(type, options = {})
|
294
|
+
!invalid_alter_table_type?(type, options)
|
340
295
|
end
|
296
|
+
deprecate :valid_alter_table_type?
|
341
297
|
|
342
298
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
343
|
-
if
|
344
|
-
super(table_name, column_name, type, options)
|
345
|
-
else
|
299
|
+
if invalid_alter_table_type?(type, options)
|
346
300
|
alter_table(table_name) do |definition|
|
347
301
|
definition.column(column_name, type, options)
|
348
302
|
end
|
303
|
+
else
|
304
|
+
super
|
349
305
|
end
|
350
306
|
end
|
351
307
|
|
@@ -398,7 +354,7 @@ module ActiveRecord
|
|
398
354
|
alias :add_belongs_to :add_reference
|
399
355
|
|
400
356
|
def foreign_keys(table_name)
|
401
|
-
fk_info =
|
357
|
+
fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
|
402
358
|
fk_info.map do |row|
|
403
359
|
options = {
|
404
360
|
column: row["from"],
|
@@ -410,7 +366,31 @@ module ActiveRecord
|
|
410
366
|
end
|
411
367
|
end
|
412
368
|
|
369
|
+
def insert_fixtures(rows, table_name)
|
370
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
371
|
+
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
372
|
+
Consider using `insert_fixtures_set` for performance improvement.
|
373
|
+
MSG
|
374
|
+
insert_fixtures_set(table_name => rows)
|
375
|
+
end
|
376
|
+
|
377
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
378
|
+
disable_referential_integrity do
|
379
|
+
transaction(requires_new: true) do
|
380
|
+
tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
|
381
|
+
|
382
|
+
fixture_set.each do |table_name, rows|
|
383
|
+
rows.each { |row| insert_fixture(row, table_name) }
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
413
389
|
private
|
390
|
+
def initialize_type_map(m = type_map)
|
391
|
+
super
|
392
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
393
|
+
end
|
414
394
|
|
415
395
|
def table_structure(table_name)
|
416
396
|
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
@@ -419,6 +399,12 @@ module ActiveRecord
|
|
419
399
|
end
|
420
400
|
alias column_definitions table_structure
|
421
401
|
|
402
|
+
# See: https://www.sqlite.org/lang_altertable.html
|
403
|
+
# SQLite has an additional restriction on the ALTER TABLE statement
|
404
|
+
def invalid_alter_table_type?(type, options)
|
405
|
+
type.to_sym == :primary_key || options[:primary_key]
|
406
|
+
end
|
407
|
+
|
422
408
|
def alter_table(table_name, options = {})
|
423
409
|
altered_table_name = "a#{table_name}"
|
424
410
|
caller = lambda { |definition| yield definition if block_given? }
|
@@ -440,18 +426,21 @@ module ActiveRecord
|
|
440
426
|
options[:id] = false
|
441
427
|
create_table(to, options) do |definition|
|
442
428
|
@definition = definition
|
443
|
-
|
429
|
+
if from_primary_key.is_a?(Array)
|
430
|
+
@definition.primary_keys from_primary_key
|
431
|
+
end
|
444
432
|
columns(from).each do |column|
|
445
433
|
column_name = options[:rename] ?
|
446
434
|
(options[:rename][column.name] ||
|
447
435
|
options[:rename][column.name.to_sym] ||
|
448
436
|
column.name) : column.name
|
449
|
-
next if column_name == from_primary_key
|
450
437
|
|
451
438
|
@definition.column(column_name, column.type,
|
452
439
|
limit: column.limit, default: column.default,
|
453
440
|
precision: column.precision, scale: column.scale,
|
454
|
-
null: column.null, collation: column.collation
|
441
|
+
null: column.null, collation: column.collation,
|
442
|
+
primary_key: column_name == from_primary_key
|
443
|
+
)
|
455
444
|
end
|
456
445
|
yield @definition if block_given?
|
457
446
|
end
|
@@ -479,6 +468,7 @@ module ActiveRecord
|
|
479
468
|
# index name can't be the same
|
480
469
|
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
481
470
|
opts[:unique] = true if index.unique
|
471
|
+
opts[:where] = index.where if index.where
|
482
472
|
add_index(to, columns, opts)
|
483
473
|
end
|
484
474
|
end
|
@@ -498,7 +488,7 @@ module ActiveRecord
|
|
498
488
|
end
|
499
489
|
|
500
490
|
def sqlite_version
|
501
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(
|
491
|
+
@sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
502
492
|
end
|
503
493
|
|
504
494
|
def translate_exception(exception, message)
|
@@ -559,21 +549,25 @@ module ActiveRecord
|
|
559
549
|
end
|
560
550
|
end
|
561
551
|
|
562
|
-
def
|
563
|
-
|
564
|
-
end
|
565
|
-
|
566
|
-
def extract_foreign_key_action(specifier)
|
567
|
-
case specifier
|
568
|
-
when "CASCADE"; :cascade
|
569
|
-
when "SET NULL"; :nullify
|
570
|
-
when "RESTRICT"; :restrict
|
571
|
-
end
|
552
|
+
def arel_visitor
|
553
|
+
Arel::Visitors::SQLite.new(self)
|
572
554
|
end
|
573
555
|
|
574
556
|
def configure_connection
|
575
557
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
576
558
|
end
|
559
|
+
|
560
|
+
class SQLite3Integer < Type::Integer # :nodoc:
|
561
|
+
private
|
562
|
+
def _limit
|
563
|
+
# INTEGER storage class can be stored 8 bytes value.
|
564
|
+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
565
|
+
limit || 8
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
577
570
|
end
|
571
|
+
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
578
572
|
end
|
579
573
|
end
|