activerecord 4.2.11.1 → 5.2.4.5
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 +4 -4
- data/CHANGELOG.md +594 -1620
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +263 -249
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +77 -43
- data/lib/active_record/associations/association_scope.rb +106 -133
- data/lib/active_record/associations/belongs_to_association.rb +52 -41
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +9 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +139 -280
- data/lib/active_record/associations/collection_proxy.rb +231 -133
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_association.rb +34 -89
- data/lib/active_record/associations/has_many_through_association.rb +49 -76
- data/lib/active_record/associations/has_one_association.rb +38 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -87
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +133 -159
- data/lib/active_record/associations/preloader/association.rb +85 -120
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +81 -91
- data/lib/active_record/associations/singular_association.rb +27 -34
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/associations.rb +1732 -1597
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +10 -8
- data/lib/active_record/attribute_methods/dirty.rb +94 -135
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
- data/lib/active_record/attribute_methods/write.rb +30 -45
- data/lib/active_record/attribute_methods.rb +166 -109
- data/lib/active_record/attributes.rb +201 -82
- data/lib/active_record/autosave_association.rb +94 -36
- data/lib/active_record/base.rb +57 -44
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +24 -12
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
- data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +570 -228
- data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
- data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -601
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +41 -180
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- 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 +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -284
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +432 -323
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -308
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +178 -198
- data/lib/active_record/counter_cache.rb +79 -36
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +135 -88
- data/lib/active_record/errors.rb +179 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +188 -132
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +88 -96
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +581 -282
- data/lib/active_record/model_schema.rb +290 -111
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +7 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +347 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +94 -32
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +149 -156
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +414 -267
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +256 -248
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +288 -239
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +86 -86
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +116 -119
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +448 -393
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -340
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -16
- data/lib/active_record/scoping/default.rb +102 -85
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +134 -96
- data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +199 -124
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +24 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +40 -41
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +34 -22
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -3
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +72 -49
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
@@ -1,13 +1,19 @@
|
|
1
|
-
|
2
|
-
require 'active_record/connection_adapters/statement_pool'
|
3
|
-
require 'arel/visitors/bind_visitor'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
require
|
3
|
+
require "active_record/connection_adapters/abstract_adapter"
|
4
|
+
require "active_record/connection_adapters/statement_pool"
|
5
|
+
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
6
|
+
require "active_record/connection_adapters/sqlite3/quoting"
|
7
|
+
require "active_record/connection_adapters/sqlite3/schema_creation"
|
8
|
+
require "active_record/connection_adapters/sqlite3/schema_definitions"
|
9
|
+
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
10
|
+
require "active_record/connection_adapters/sqlite3/schema_statements"
|
11
|
+
|
12
|
+
gem "sqlite3", "~> 1.3", ">= 1.3.6"
|
13
|
+
require "sqlite3"
|
7
14
|
|
8
15
|
module ActiveRecord
|
9
16
|
module ConnectionHandling # :nodoc:
|
10
|
-
# sqlite3 adapter reuses sqlite_connection.
|
11
17
|
def sqlite3_connection(config)
|
12
18
|
# Require database.
|
13
19
|
unless config[:database]
|
@@ -17,7 +23,7 @@ module ActiveRecord
|
|
17
23
|
# Allow database path relative to Rails.root, but only if the database
|
18
24
|
# path is not the special path that tells sqlite to build a database only
|
19
25
|
# in memory.
|
20
|
-
if
|
26
|
+
if ":memory:" != config[:database]
|
21
27
|
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
|
22
28
|
dirname = File.dirname(config[:database])
|
23
29
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
@@ -25,7 +31,7 @@ module ActiveRecord
|
|
25
31
|
|
26
32
|
db = SQLite3::Database.new(
|
27
33
|
config[:database].to_s,
|
28
|
-
:
|
34
|
+
results_as_hash: true
|
29
35
|
)
|
30
36
|
|
31
37
|
db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
|
@@ -33,7 +39,7 @@ module ActiveRecord
|
|
33
39
|
ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
|
34
40
|
rescue Errno::ENOENT => error
|
35
41
|
if error.message.include?("No such file or directory")
|
36
|
-
raise ActiveRecord::NoDatabaseError
|
42
|
+
raise ActiveRecord::NoDatabaseError
|
37
43
|
else
|
38
44
|
raise
|
39
45
|
end
|
@@ -41,15 +47,6 @@ module ActiveRecord
|
|
41
47
|
end
|
42
48
|
|
43
49
|
module ConnectionAdapters #:nodoc:
|
44
|
-
class SQLite3Binary < Type::Binary # :nodoc:
|
45
|
-
def cast_value(value)
|
46
|
-
if value.encoding != Encoding::ASCII_8BIT
|
47
|
-
value = value.force_encoding(Encoding::ASCII_8BIT)
|
48
|
-
end
|
49
|
-
value
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
50
|
# The SQLite3 adapter works SQLite 3.6.16 or newer
|
54
51
|
# with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
|
55
52
|
#
|
@@ -57,11 +54,13 @@ module ActiveRecord
|
|
57
54
|
#
|
58
55
|
# * <tt>:database</tt> - Path to the database file.
|
59
56
|
class SQLite3Adapter < AbstractAdapter
|
60
|
-
ADAPTER_NAME =
|
61
|
-
|
57
|
+
ADAPTER_NAME = "SQLite".freeze
|
58
|
+
|
59
|
+
include SQLite3::Quoting
|
60
|
+
include SQLite3::SchemaStatements
|
62
61
|
|
63
62
|
NATIVE_DATABASE_TYPES = {
|
64
|
-
primary_key:
|
63
|
+
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
65
64
|
string: { name: "varchar" },
|
66
65
|
text: { name: "text" },
|
67
66
|
integer: { name: "integer" },
|
@@ -71,59 +70,41 @@ module ActiveRecord
|
|
71
70
|
time: { name: "time" },
|
72
71
|
date: { name: "date" },
|
73
72
|
binary: { name: "blob" },
|
74
|
-
boolean: { name: "boolean" }
|
73
|
+
boolean: { name: "boolean" },
|
74
|
+
json: { name: "json" },
|
75
75
|
}
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
def clear
|
96
|
-
cache.each_value do |hash|
|
97
|
-
dealloc hash[:stmt]
|
98
|
-
end
|
99
|
-
cache.clear
|
100
|
-
end
|
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
|
101
93
|
|
94
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
102
95
|
private
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
def dealloc(stmt)
|
108
|
-
stmt.close unless stmt.closed?
|
109
|
-
end
|
96
|
+
def dealloc(stmt)
|
97
|
+
stmt[:stmt].close unless stmt[:stmt].closed?
|
98
|
+
end
|
110
99
|
end
|
111
100
|
|
112
101
|
def initialize(connection, logger, connection_options, config)
|
113
|
-
super(connection, logger)
|
114
|
-
|
115
|
-
@active = nil
|
116
|
-
@statements = StatementPool.new(@connection,
|
117
|
-
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
118
|
-
@config = config
|
102
|
+
super(connection, logger, config)
|
119
103
|
|
120
|
-
@
|
104
|
+
@active = true
|
105
|
+
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
121
106
|
|
122
|
-
|
123
|
-
@prepared_statements = true
|
124
|
-
else
|
125
|
-
@prepared_statements = false
|
126
|
-
end
|
107
|
+
configure_connection
|
127
108
|
end
|
128
109
|
|
129
110
|
def supports_ddl_transactions?
|
@@ -135,34 +116,35 @@ module ActiveRecord
|
|
135
116
|
end
|
136
117
|
|
137
118
|
def supports_partial_index?
|
138
|
-
sqlite_version >=
|
119
|
+
sqlite_version >= "3.8.0"
|
139
120
|
end
|
140
121
|
|
141
|
-
|
142
|
-
# caching.
|
143
|
-
def supports_statement_cache?
|
122
|
+
def requires_reloading?
|
144
123
|
true
|
145
124
|
end
|
146
125
|
|
147
|
-
|
148
|
-
|
149
|
-
true
|
126
|
+
def supports_foreign_keys_in_create?
|
127
|
+
sqlite_version >= "3.6.19"
|
150
128
|
end
|
151
129
|
|
152
|
-
def
|
130
|
+
def supports_views?
|
153
131
|
true
|
154
132
|
end
|
155
133
|
|
156
|
-
def
|
134
|
+
def supports_datetime_with_precision?
|
157
135
|
true
|
158
136
|
end
|
159
137
|
|
160
|
-
def
|
138
|
+
def supports_json?
|
161
139
|
true
|
162
140
|
end
|
163
141
|
|
142
|
+
def supports_multi_insert?
|
143
|
+
sqlite_version >= "3.7.11"
|
144
|
+
end
|
145
|
+
|
164
146
|
def active?
|
165
|
-
@active
|
147
|
+
@active
|
166
148
|
end
|
167
149
|
|
168
150
|
# Disconnects from the database if already connected. Otherwise, this
|
@@ -183,7 +165,7 @@ module ActiveRecord
|
|
183
165
|
end
|
184
166
|
|
185
167
|
# Returns 62. SQLite supports index names up to 64
|
186
|
-
# characters. The rest is used by
|
168
|
+
# characters. The rest is used by Rails internally to perform
|
187
169
|
# temporary rename operations
|
188
170
|
def allowed_index_name_length
|
189
171
|
index_name_length - 2
|
@@ -202,51 +184,16 @@ module ActiveRecord
|
|
202
184
|
true
|
203
185
|
end
|
204
186
|
|
205
|
-
#
|
206
|
-
|
207
|
-
def _quote(value) # :nodoc:
|
208
|
-
case value
|
209
|
-
when Type::Binary::Data
|
210
|
-
"x'#{value.hex}'"
|
211
|
-
else
|
212
|
-
super
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def _type_cast(value) # :nodoc:
|
217
|
-
case value
|
218
|
-
when BigDecimal
|
219
|
-
value.to_f
|
220
|
-
when String
|
221
|
-
if value.encoding == Encoding::ASCII_8BIT
|
222
|
-
super(value.encode(Encoding::UTF_8))
|
223
|
-
else
|
224
|
-
super
|
225
|
-
end
|
226
|
-
else
|
227
|
-
super
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def quote_string(s) #:nodoc:
|
232
|
-
@connection.class.quote(s)
|
233
|
-
end
|
234
|
-
|
235
|
-
def quote_table_name_for_assignment(table, attr)
|
236
|
-
quote_column_name(attr)
|
237
|
-
end
|
187
|
+
# REFERENTIAL INTEGRITY ====================================
|
238
188
|
|
239
|
-
def
|
240
|
-
|
241
|
-
end
|
189
|
+
def disable_referential_integrity # :nodoc:
|
190
|
+
old = query_value("PRAGMA foreign_keys")
|
242
191
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
"#{
|
248
|
-
else
|
249
|
-
super
|
192
|
+
begin
|
193
|
+
execute("PRAGMA foreign_keys = OFF")
|
194
|
+
yield
|
195
|
+
ensure
|
196
|
+
execute("PRAGMA foreign_keys = #{old}")
|
250
197
|
end
|
251
198
|
end
|
252
199
|
|
@@ -256,54 +203,43 @@ module ActiveRecord
|
|
256
203
|
|
257
204
|
def explain(arel, binds = [])
|
258
205
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
259
|
-
ExplainPrettyPrinter.new.pp(exec_query(sql,
|
260
|
-
end
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
206
|
+
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
207
|
+
end
|
208
|
+
|
209
|
+
def exec_query(sql, name = nil, binds = [], prepare: false)
|
210
|
+
type_casted_binds = type_casted_binds(binds)
|
211
|
+
|
212
|
+
log(sql, name, binds, type_casted_binds) do
|
213
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
214
|
+
# Don't cache statements if they are not prepared
|
215
|
+
unless prepare
|
216
|
+
stmt = @connection.prepare(sql)
|
217
|
+
begin
|
218
|
+
cols = stmt.columns
|
219
|
+
unless without_prepared_statement?(binds)
|
220
|
+
stmt.bind_params(type_casted_binds)
|
221
|
+
end
|
222
|
+
records = stmt.to_a
|
223
|
+
ensure
|
224
|
+
stmt.close
|
225
|
+
end
|
226
|
+
else
|
227
|
+
cache = @statements[sql] ||= {
|
228
|
+
stmt: @connection.prepare(sql)
|
229
|
+
}
|
230
|
+
stmt = cache[:stmt]
|
231
|
+
cols = cache[:cols] ||= stmt.columns
|
232
|
+
stmt.reset!
|
233
|
+
stmt.bind_params(type_casted_binds)
|
287
234
|
records = stmt.to_a
|
288
|
-
ensure
|
289
|
-
stmt.close
|
290
235
|
end
|
291
|
-
stmt = records
|
292
|
-
else
|
293
|
-
cache = @statements[sql] ||= {
|
294
|
-
:stmt => @connection.prepare(sql)
|
295
|
-
}
|
296
|
-
stmt = cache[:stmt]
|
297
|
-
cols = cache[:cols] ||= stmt.columns
|
298
|
-
stmt.reset!
|
299
|
-
stmt.bind_params type_casted_binds.map { |_, val| val }
|
300
|
-
end
|
301
236
|
|
302
|
-
|
237
|
+
ActiveRecord::Result.new(cols, records)
|
238
|
+
end
|
303
239
|
end
|
304
240
|
end
|
305
241
|
|
306
|
-
def exec_delete(sql, name =
|
242
|
+
def exec_delete(sql, name = "SQL", binds = [])
|
307
243
|
exec_query(sql, name, binds)
|
308
244
|
@connection.changes
|
309
245
|
end
|
@@ -314,112 +250,34 @@ module ActiveRecord
|
|
314
250
|
end
|
315
251
|
|
316
252
|
def execute(sql, name = nil) #:nodoc:
|
317
|
-
log(sql, name)
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
@connection.changes
|
323
|
-
end
|
324
|
-
|
325
|
-
def delete_sql(sql, name = nil) #:nodoc:
|
326
|
-
sql += " WHERE 1=1" unless sql =~ /WHERE/i
|
327
|
-
super sql, name
|
328
|
-
end
|
329
|
-
|
330
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
331
|
-
super
|
332
|
-
id_value || @connection.last_insert_row_id
|
333
|
-
end
|
334
|
-
alias :create :insert_sql
|
335
|
-
|
336
|
-
def select_rows(sql, name = nil, binds = [])
|
337
|
-
exec_query(sql, name, binds).rows
|
253
|
+
log(sql, name) do
|
254
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
255
|
+
@connection.execute(sql)
|
256
|
+
end
|
257
|
+
end
|
338
258
|
end
|
339
259
|
|
340
260
|
def begin_db_transaction #:nodoc:
|
341
|
-
log(
|
261
|
+
log("begin transaction", nil) { @connection.transaction }
|
342
262
|
end
|
343
263
|
|
344
264
|
def commit_db_transaction #:nodoc:
|
345
|
-
log(
|
265
|
+
log("commit transaction", nil) { @connection.commit }
|
346
266
|
end
|
347
267
|
|
348
268
|
def exec_rollback_db_transaction #:nodoc:
|
349
|
-
log(
|
269
|
+
log("rollback transaction", nil) { @connection.rollback }
|
350
270
|
end
|
351
271
|
|
352
272
|
# SCHEMA STATEMENTS ========================================
|
353
273
|
|
354
|
-
def
|
355
|
-
|
356
|
-
|
357
|
-
FROM sqlite_master
|
358
|
-
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
359
|
-
SQL
|
360
|
-
sql << " AND name = #{quote_table_name(table_name)}" if table_name
|
361
|
-
|
362
|
-
exec_query(sql, 'SCHEMA').map do |row|
|
363
|
-
row['name']
|
364
|
-
end
|
365
|
-
end
|
366
|
-
alias data_sources tables
|
367
|
-
|
368
|
-
def table_exists?(table_name)
|
369
|
-
table_name && tables(nil, table_name).any?
|
370
|
-
end
|
371
|
-
alias data_source_exists? table_exists?
|
372
|
-
|
373
|
-
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
374
|
-
def columns(table_name) #:nodoc:
|
375
|
-
table_structure(table_name).map do |field|
|
376
|
-
case field["dflt_value"]
|
377
|
-
when /^null$/i
|
378
|
-
field["dflt_value"] = nil
|
379
|
-
when /^'(.*)'$/m
|
380
|
-
field["dflt_value"] = $1.gsub("''", "'")
|
381
|
-
when /^"(.*)"$/m
|
382
|
-
field["dflt_value"] = $1.gsub('""', '"')
|
383
|
-
end
|
384
|
-
|
385
|
-
sql_type = field['type']
|
386
|
-
cast_type = lookup_cast_type(sql_type)
|
387
|
-
new_column(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
# Returns an array of indexes for the given table.
|
392
|
-
def indexes(table_name, name = nil) #:nodoc:
|
393
|
-
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
|
394
|
-
sql = <<-SQL
|
395
|
-
SELECT sql
|
396
|
-
FROM sqlite_master
|
397
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
398
|
-
UNION ALL
|
399
|
-
SELECT sql
|
400
|
-
FROM sqlite_temp_master
|
401
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
402
|
-
SQL
|
403
|
-
index_sql = exec_query(sql).first['sql']
|
404
|
-
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
405
|
-
where = match[1] if match
|
406
|
-
IndexDefinition.new(
|
407
|
-
table_name,
|
408
|
-
row['name'],
|
409
|
-
row['unique'] != 0,
|
410
|
-
exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
|
411
|
-
col['name']
|
412
|
-
}, nil, nil, where)
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
def primary_key(table_name) #:nodoc:
|
417
|
-
pks = table_structure(table_name).select { |f| f['pk'] > 0 }
|
418
|
-
return nil unless pks.count == 1
|
419
|
-
pks[0]['name']
|
274
|
+
def primary_keys(table_name) # :nodoc:
|
275
|
+
pks = table_structure(table_name).select { |f| f["pk"] > 0 }
|
276
|
+
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
420
277
|
end
|
421
278
|
|
422
|
-
def remove_index
|
279
|
+
def remove_index(table_name, options = {}) #:nodoc:
|
280
|
+
index_name = index_name_for_remove(table_name, options)
|
423
281
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
424
282
|
end
|
425
283
|
|
@@ -432,19 +290,18 @@ module ActiveRecord
|
|
432
290
|
rename_table_indexes(table_name, new_name)
|
433
291
|
end
|
434
292
|
|
435
|
-
|
436
|
-
|
437
|
-
def valid_alter_table_type?(type)
|
438
|
-
type.to_sym != :primary_key
|
293
|
+
def valid_alter_table_type?(type, options = {})
|
294
|
+
!invalid_alter_table_type?(type, options)
|
439
295
|
end
|
296
|
+
deprecate :valid_alter_table_type?
|
440
297
|
|
441
298
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
442
|
-
if
|
443
|
-
super(table_name, column_name, type, options)
|
444
|
-
else
|
299
|
+
if invalid_alter_table_type?(type, options)
|
445
300
|
alter_table(table_name) do |definition|
|
446
301
|
definition.column(column_name, type, options)
|
447
302
|
end
|
303
|
+
else
|
304
|
+
super
|
448
305
|
end
|
449
306
|
end
|
450
307
|
|
@@ -454,13 +311,15 @@ module ActiveRecord
|
|
454
311
|
end
|
455
312
|
end
|
456
313
|
|
457
|
-
def change_column_default(table_name, column_name,
|
314
|
+
def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
|
315
|
+
default = extract_new_default_value(default_or_changes)
|
316
|
+
|
458
317
|
alter_table(table_name) do |definition|
|
459
318
|
definition[column_name].default = default
|
460
319
|
end
|
461
320
|
end
|
462
321
|
|
463
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
322
|
+
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
464
323
|
unless null || default.nil?
|
465
324
|
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
466
325
|
end
|
@@ -471,80 +330,127 @@ module ActiveRecord
|
|
471
330
|
|
472
331
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
473
332
|
alter_table(table_name) do |definition|
|
474
|
-
include_default = options_include_default?(options)
|
475
333
|
definition[column_name].instance_eval do
|
476
334
|
self.type = type
|
477
335
|
self.limit = options[:limit] if options.include?(:limit)
|
478
|
-
self.default = options[:default] if
|
336
|
+
self.default = options[:default] if options.include?(:default)
|
479
337
|
self.null = options[:null] if options.include?(:null)
|
480
338
|
self.precision = options[:precision] if options.include?(:precision)
|
481
|
-
self.scale
|
339
|
+
self.scale = options[:scale] if options.include?(:scale)
|
340
|
+
self.collation = options[:collation] if options.include?(:collation)
|
482
341
|
end
|
483
342
|
end
|
484
343
|
end
|
485
344
|
|
486
345
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
487
346
|
column = column_for(table_name, column_name)
|
488
|
-
alter_table(table_name, rename: {column.name => new_column_name.to_s})
|
347
|
+
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
489
348
|
rename_column_indexes(table_name, column.name, new_column_name)
|
490
349
|
end
|
491
350
|
|
492
|
-
|
351
|
+
def add_reference(table_name, ref_name, **options) # :nodoc:
|
352
|
+
super(table_name, ref_name, type: :integer, **options)
|
353
|
+
end
|
354
|
+
alias :add_belongs_to :add_reference
|
355
|
+
|
356
|
+
def foreign_keys(table_name)
|
357
|
+
fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
|
358
|
+
fk_info.map do |row|
|
359
|
+
options = {
|
360
|
+
column: row["from"],
|
361
|
+
primary_key: row["to"],
|
362
|
+
on_delete: extract_foreign_key_action(row["on_delete"]),
|
363
|
+
on_update: extract_foreign_key_action(row["on_update"])
|
364
|
+
}
|
365
|
+
ForeignKeyDefinition.new(table_name, row["table"], options)
|
366
|
+
end
|
367
|
+
end
|
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
|
493
388
|
|
494
|
-
|
389
|
+
private
|
390
|
+
def initialize_type_map(m = type_map)
|
495
391
|
super
|
496
|
-
m
|
392
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
497
393
|
end
|
498
394
|
|
499
395
|
def table_structure(table_name)
|
500
|
-
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})",
|
396
|
+
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
501
397
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
502
|
-
structure
|
398
|
+
table_structure_with_collation(table_name, structure)
|
399
|
+
end
|
400
|
+
alias column_definitions table_structure
|
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]
|
503
406
|
end
|
504
407
|
|
505
|
-
def alter_table(table_name, options = {})
|
408
|
+
def alter_table(table_name, options = {})
|
506
409
|
altered_table_name = "a#{table_name}"
|
507
|
-
caller = lambda {|definition| yield definition if block_given?}
|
410
|
+
caller = lambda { |definition| yield definition if block_given? }
|
508
411
|
|
509
412
|
transaction do
|
510
413
|
move_table(table_name, altered_table_name,
|
511
|
-
options.merge(:
|
414
|
+
options.merge(temporary: true))
|
512
415
|
move_table(altered_table_name, table_name, &caller)
|
513
416
|
end
|
514
417
|
end
|
515
418
|
|
516
|
-
def move_table(from, to, options = {}, &block)
|
419
|
+
def move_table(from, to, options = {}, &block)
|
517
420
|
copy_table(from, to, options, &block)
|
518
421
|
drop_table(from)
|
519
422
|
end
|
520
423
|
|
521
|
-
def copy_table(from, to, options = {})
|
424
|
+
def copy_table(from, to, options = {})
|
522
425
|
from_primary_key = primary_key(from)
|
523
426
|
options[:id] = false
|
524
427
|
create_table(to, options) do |definition|
|
525
428
|
@definition = definition
|
526
|
-
|
429
|
+
if from_primary_key.is_a?(Array)
|
430
|
+
@definition.primary_keys from_primary_key
|
431
|
+
end
|
527
432
|
columns(from).each do |column|
|
528
433
|
column_name = options[:rename] ?
|
529
434
|
(options[:rename][column.name] ||
|
530
435
|
options[:rename][column.name.to_sym] ||
|
531
436
|
column.name) : column.name
|
532
|
-
next if column_name == from_primary_key
|
533
437
|
|
534
438
|
@definition.column(column_name, column.type,
|
535
|
-
:
|
536
|
-
:
|
537
|
-
:null
|
439
|
+
limit: column.limit, default: column.default,
|
440
|
+
precision: column.precision, scale: column.scale,
|
441
|
+
null: column.null, collation: column.collation,
|
442
|
+
primary_key: column_name == from_primary_key
|
443
|
+
)
|
538
444
|
end
|
539
445
|
yield @definition if block_given?
|
540
446
|
end
|
541
447
|
copy_table_indexes(from, to, options[:rename] || {})
|
542
448
|
copy_table_contents(from, to,
|
543
|
-
@definition.columns.map
|
449
|
+
@definition.columns.map(&:name),
|
544
450
|
options[:rename] || {})
|
545
451
|
end
|
546
452
|
|
547
|
-
def copy_table_indexes(from, to, rename = {})
|
453
|
+
def copy_table_indexes(from, to, rename = {})
|
548
454
|
indexes(from).each do |index|
|
549
455
|
name = index.name
|
550
456
|
if to == "a#{from}"
|
@@ -553,8 +459,8 @@ module ActiveRecord
|
|
553
459
|
name = name[1..-1]
|
554
460
|
end
|
555
461
|
|
556
|
-
to_column_names = columns(to).map
|
557
|
-
columns = index.columns.map {|c| rename[c] || c }.select do |column|
|
462
|
+
to_column_names = columns(to).map(&:name)
|
463
|
+
columns = index.columns.map { |c| rename[c] || c }.select do |column|
|
558
464
|
to_column_names.include?(column)
|
559
465
|
end
|
560
466
|
|
@@ -562,37 +468,27 @@ module ActiveRecord
|
|
562
468
|
# index name can't be the same
|
563
469
|
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
564
470
|
opts[:unique] = true if index.unique
|
471
|
+
opts[:where] = index.where if index.where
|
565
472
|
add_index(to, columns, opts)
|
566
473
|
end
|
567
474
|
end
|
568
475
|
end
|
569
476
|
|
570
|
-
def copy_table_contents(from, to, columns, rename = {})
|
571
|
-
column_mappings = Hash[columns.map {|name| [name, name]}]
|
477
|
+
def copy_table_contents(from, to, columns, rename = {})
|
478
|
+
column_mappings = Hash[columns.map { |name| [name, name] }]
|
572
479
|
rename.each { |a| column_mappings[a.last] = a.first }
|
573
|
-
from_columns = columns(from).collect
|
574
|
-
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
|
582
|
-
sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
|
583
|
-
|
584
|
-
column_values = columns.map do |col|
|
585
|
-
quote(row[column_mappings[col]], raw_column_mappings[col])
|
586
|
-
end
|
587
|
-
|
588
|
-
sql << column_values * ', '
|
589
|
-
sql << ')'
|
590
|
-
exec_query sql
|
591
|
-
end
|
480
|
+
from_columns = columns(from).collect(&:name)
|
481
|
+
columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
|
482
|
+
from_columns_to_copy = columns.map { |col| column_mappings[col] }
|
483
|
+
quoted_columns = columns.map { |col| quote_column_name(col) } * ","
|
484
|
+
quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
|
485
|
+
|
486
|
+
exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
|
487
|
+
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
592
488
|
end
|
593
489
|
|
594
490
|
def sqlite_version
|
595
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(
|
491
|
+
@sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
596
492
|
end
|
597
493
|
|
598
494
|
def translate_exception(exception, message)
|
@@ -602,11 +498,76 @@ module ActiveRecord
|
|
602
498
|
# Older versions of SQLite return:
|
603
499
|
# column *column_name* is not unique
|
604
500
|
when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
|
605
|
-
RecordNotUnique.new(message
|
501
|
+
RecordNotUnique.new(message)
|
502
|
+
when /.* may not be NULL/, /NOT NULL constraint failed: .*/
|
503
|
+
NotNullViolation.new(message)
|
504
|
+
when /FOREIGN KEY constraint failed/i
|
505
|
+
InvalidForeignKey.new(message)
|
606
506
|
else
|
607
507
|
super
|
608
508
|
end
|
609
509
|
end
|
510
|
+
|
511
|
+
COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
|
512
|
+
|
513
|
+
def table_structure_with_collation(table_name, basic_structure)
|
514
|
+
collation_hash = {}
|
515
|
+
sql = <<-SQL
|
516
|
+
SELECT sql FROM
|
517
|
+
(SELECT * FROM sqlite_master UNION ALL
|
518
|
+
SELECT * FROM sqlite_temp_master)
|
519
|
+
WHERE type = 'table' AND name = #{quote(table_name)}
|
520
|
+
SQL
|
521
|
+
|
522
|
+
# Result will have following sample string
|
523
|
+
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
524
|
+
# "password_digest" varchar COLLATE "NOCASE");
|
525
|
+
result = exec_query(sql, "SCHEMA").first
|
526
|
+
|
527
|
+
if result
|
528
|
+
# Splitting with left parentheses and discarding the first part will return all
|
529
|
+
# columns separated with comma(,).
|
530
|
+
columns_string = result["sql"].split("(", 2).last
|
531
|
+
|
532
|
+
columns_string.split(",").each do |column_string|
|
533
|
+
# This regex will match the column name and collation type and will save
|
534
|
+
# the value in $1 and $2 respectively.
|
535
|
+
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
|
536
|
+
end
|
537
|
+
|
538
|
+
basic_structure.map! do |column|
|
539
|
+
column_name = column["name"]
|
540
|
+
|
541
|
+
if collation_hash.has_key? column_name
|
542
|
+
column["collation"] = collation_hash[column_name]
|
543
|
+
end
|
544
|
+
|
545
|
+
column
|
546
|
+
end
|
547
|
+
else
|
548
|
+
basic_structure.to_hash
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
def arel_visitor
|
553
|
+
Arel::Visitors::SQLite.new(self)
|
554
|
+
end
|
555
|
+
|
556
|
+
def configure_connection
|
557
|
+
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
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)
|
610
570
|
end
|
571
|
+
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
611
572
|
end
|
612
573
|
end
|