activerecord 4.2.0 → 5.2.8.1
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 +640 -928
- 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 +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- 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 +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- 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 +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- 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 +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- 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 +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- 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 +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- 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 +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- 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 +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- 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 +5 -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 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -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 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- 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 +466 -280
- 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 +439 -330
- 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 -324
- 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 +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -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 +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- 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 +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- 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 +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- 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 +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- 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 +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- 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 +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- 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 -339
- 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 -19
- data/lib/active_record/scoping/default.rb +102 -84
- 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 +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- 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 +208 -123
- 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 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- 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 +30 -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 +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- 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 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- 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.rb +7 -5
- metadata +77 -53
- 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 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -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,25 +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
|
-
class SQLite3String < Type::String # :nodoc:
|
54
|
-
def type_cast_for_database(value)
|
55
|
-
if value.is_a?(::String) && value.encoding == Encoding::ASCII_8BIT
|
56
|
-
value.encode(Encoding::UTF_8)
|
57
|
-
else
|
58
|
-
super
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
50
|
# The SQLite3 adapter works SQLite 3.6.16 or newer
|
64
51
|
# with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
|
65
52
|
#
|
@@ -67,11 +54,13 @@ module ActiveRecord
|
|
67
54
|
#
|
68
55
|
# * <tt>:database</tt> - Path to the database file.
|
69
56
|
class SQLite3Adapter < AbstractAdapter
|
70
|
-
ADAPTER_NAME =
|
71
|
-
|
57
|
+
ADAPTER_NAME = "SQLite".freeze
|
58
|
+
|
59
|
+
include SQLite3::Quoting
|
60
|
+
include SQLite3::SchemaStatements
|
72
61
|
|
73
62
|
NATIVE_DATABASE_TYPES = {
|
74
|
-
primary_key:
|
63
|
+
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
75
64
|
string: { name: "varchar" },
|
76
65
|
text: { name: "text" },
|
77
66
|
integer: { name: "integer" },
|
@@ -81,71 +70,41 @@ module ActiveRecord
|
|
81
70
|
time: { name: "time" },
|
82
71
|
date: { name: "date" },
|
83
72
|
binary: { name: "blob" },
|
84
|
-
boolean: { name: "boolean" }
|
73
|
+
boolean: { name: "boolean" },
|
74
|
+
json: { name: "json" },
|
85
75
|
}
|
86
76
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
def each(&block); cache.each(&block); end
|
106
|
-
def key?(key); cache.key?(key); end
|
107
|
-
def [](key); cache[key]; end
|
108
|
-
def length; cache.length; end
|
109
|
-
|
110
|
-
def []=(sql, key)
|
111
|
-
while @max <= cache.size
|
112
|
-
dealloc(cache.shift.last[:stmt])
|
113
|
-
end
|
114
|
-
cache[sql] = key
|
115
|
-
end
|
116
|
-
|
117
|
-
def clear
|
118
|
-
cache.each_value do |hash|
|
119
|
-
dealloc hash[:stmt]
|
120
|
-
end
|
121
|
-
cache.clear
|
122
|
-
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
|
123
93
|
|
94
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
124
95
|
private
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
def dealloc(stmt)
|
130
|
-
stmt.close unless stmt.closed?
|
131
|
-
end
|
96
|
+
def dealloc(stmt)
|
97
|
+
stmt[:stmt].close unless stmt[:stmt].closed?
|
98
|
+
end
|
132
99
|
end
|
133
100
|
|
134
101
|
def initialize(connection, logger, connection_options, config)
|
135
|
-
super(connection, logger)
|
136
|
-
|
137
|
-
@active = nil
|
138
|
-
@statements = StatementPool.new(@connection,
|
139
|
-
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
140
|
-
@config = config
|
102
|
+
super(connection, logger, config)
|
141
103
|
|
142
|
-
@
|
104
|
+
@active = true
|
105
|
+
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
143
106
|
|
144
|
-
|
145
|
-
@prepared_statements = true
|
146
|
-
else
|
147
|
-
@prepared_statements = false
|
148
|
-
end
|
107
|
+
configure_connection
|
149
108
|
end
|
150
109
|
|
151
110
|
def supports_ddl_transactions?
|
@@ -157,34 +116,35 @@ module ActiveRecord
|
|
157
116
|
end
|
158
117
|
|
159
118
|
def supports_partial_index?
|
160
|
-
sqlite_version >=
|
119
|
+
sqlite_version >= "3.8.0"
|
161
120
|
end
|
162
121
|
|
163
|
-
|
164
|
-
# caching.
|
165
|
-
def supports_statement_cache?
|
122
|
+
def requires_reloading?
|
166
123
|
true
|
167
124
|
end
|
168
125
|
|
169
|
-
|
170
|
-
|
171
|
-
true
|
126
|
+
def supports_foreign_keys_in_create?
|
127
|
+
sqlite_version >= "3.6.19"
|
172
128
|
end
|
173
129
|
|
174
|
-
def
|
130
|
+
def supports_views?
|
175
131
|
true
|
176
132
|
end
|
177
133
|
|
178
|
-
def
|
134
|
+
def supports_datetime_with_precision?
|
179
135
|
true
|
180
136
|
end
|
181
137
|
|
182
|
-
def
|
138
|
+
def supports_json?
|
183
139
|
true
|
184
140
|
end
|
185
141
|
|
142
|
+
def supports_multi_insert?
|
143
|
+
sqlite_version >= "3.7.11"
|
144
|
+
end
|
145
|
+
|
186
146
|
def active?
|
187
|
-
@active
|
147
|
+
@active
|
188
148
|
end
|
189
149
|
|
190
150
|
# Disconnects from the database if already connected. Otherwise, this
|
@@ -205,7 +165,7 @@ module ActiveRecord
|
|
205
165
|
end
|
206
166
|
|
207
167
|
# Returns 62. SQLite supports index names up to 64
|
208
|
-
# characters. The rest is used by
|
168
|
+
# characters. The rest is used by Rails internally to perform
|
209
169
|
# temporary rename operations
|
210
170
|
def allowed_index_name_length
|
211
171
|
index_name_length - 2
|
@@ -224,45 +184,16 @@ module ActiveRecord
|
|
224
184
|
true
|
225
185
|
end
|
226
186
|
|
227
|
-
#
|
228
|
-
|
229
|
-
def _quote(value) # :nodoc:
|
230
|
-
case value
|
231
|
-
when Type::Binary::Data
|
232
|
-
"x'#{value.hex}'"
|
233
|
-
else
|
234
|
-
super
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
def _type_cast(value) # :nodoc:
|
239
|
-
case value
|
240
|
-
when BigDecimal
|
241
|
-
value.to_f
|
242
|
-
else
|
243
|
-
super
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def quote_string(s) #:nodoc:
|
248
|
-
@connection.class.quote(s)
|
249
|
-
end
|
187
|
+
# REFERENTIAL INTEGRITY ====================================
|
250
188
|
|
251
|
-
def
|
252
|
-
|
253
|
-
end
|
189
|
+
def disable_referential_integrity # :nodoc:
|
190
|
+
old = query_value("PRAGMA foreign_keys")
|
254
191
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
# if the value is a Time responding to usec.
|
261
|
-
def quoted_date(value) #:nodoc:
|
262
|
-
if value.respond_to?(:usec)
|
263
|
-
"#{super}.#{sprintf("%06d", value.usec)}"
|
264
|
-
else
|
265
|
-
super
|
192
|
+
begin
|
193
|
+
execute("PRAGMA foreign_keys = OFF")
|
194
|
+
yield
|
195
|
+
ensure
|
196
|
+
execute("PRAGMA foreign_keys = #{old}")
|
266
197
|
end
|
267
198
|
end
|
268
199
|
|
@@ -272,54 +203,43 @@ module ActiveRecord
|
|
272
203
|
|
273
204
|
def explain(arel, binds = [])
|
274
205
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
275
|
-
ExplainPrettyPrinter.new.pp(exec_query(sql,
|
276
|
-
end
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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)
|
303
234
|
records = stmt.to_a
|
304
|
-
ensure
|
305
|
-
stmt.close
|
306
235
|
end
|
307
|
-
stmt = records
|
308
|
-
else
|
309
|
-
cache = @statements[sql] ||= {
|
310
|
-
:stmt => @connection.prepare(sql)
|
311
|
-
}
|
312
|
-
stmt = cache[:stmt]
|
313
|
-
cols = cache[:cols] ||= stmt.columns
|
314
|
-
stmt.reset!
|
315
|
-
stmt.bind_params type_casted_binds.map { |_, val| val }
|
316
|
-
end
|
317
236
|
|
318
|
-
|
237
|
+
ActiveRecord::Result.new(cols, records)
|
238
|
+
end
|
319
239
|
end
|
320
240
|
end
|
321
241
|
|
322
|
-
def exec_delete(sql, name =
|
242
|
+
def exec_delete(sql, name = "SQL", binds = [])
|
323
243
|
exec_query(sql, name, binds)
|
324
244
|
@connection.changes
|
325
245
|
end
|
@@ -330,111 +250,34 @@ module ActiveRecord
|
|
330
250
|
end
|
331
251
|
|
332
252
|
def execute(sql, name = nil) #:nodoc:
|
333
|
-
log(sql, name)
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
@connection.changes
|
339
|
-
end
|
340
|
-
|
341
|
-
def delete_sql(sql, name = nil) #:nodoc:
|
342
|
-
sql += " WHERE 1=1" unless sql =~ /WHERE/i
|
343
|
-
super sql, name
|
344
|
-
end
|
345
|
-
|
346
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
347
|
-
super
|
348
|
-
id_value || @connection.last_insert_row_id
|
349
|
-
end
|
350
|
-
alias :create :insert_sql
|
351
|
-
|
352
|
-
def select_rows(sql, name = nil, binds = [])
|
353
|
-
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
|
354
258
|
end
|
355
259
|
|
356
260
|
def begin_db_transaction #:nodoc:
|
357
|
-
log(
|
261
|
+
log("begin transaction", nil) { @connection.transaction }
|
358
262
|
end
|
359
263
|
|
360
264
|
def commit_db_transaction #:nodoc:
|
361
|
-
log(
|
265
|
+
log("commit transaction", nil) { @connection.commit }
|
362
266
|
end
|
363
267
|
|
364
|
-
def
|
365
|
-
log(
|
268
|
+
def exec_rollback_db_transaction #:nodoc:
|
269
|
+
log("rollback transaction", nil) { @connection.rollback }
|
366
270
|
end
|
367
271
|
|
368
272
|
# SCHEMA STATEMENTS ========================================
|
369
273
|
|
370
|
-
def
|
371
|
-
|
372
|
-
|
373
|
-
FROM sqlite_master
|
374
|
-
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
375
|
-
SQL
|
376
|
-
sql << " AND name = #{quote_table_name(table_name)}" if table_name
|
377
|
-
|
378
|
-
exec_query(sql, 'SCHEMA').map do |row|
|
379
|
-
row['name']
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
def table_exists?(table_name)
|
384
|
-
table_name && tables(nil, table_name).any?
|
385
|
-
end
|
386
|
-
|
387
|
-
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
388
|
-
def columns(table_name) #:nodoc:
|
389
|
-
table_structure(table_name).map do |field|
|
390
|
-
case field["dflt_value"]
|
391
|
-
when /^null$/i
|
392
|
-
field["dflt_value"] = nil
|
393
|
-
when /^'(.*)'$/m
|
394
|
-
field["dflt_value"] = $1.gsub("''", "'")
|
395
|
-
when /^"(.*)"$/m
|
396
|
-
field["dflt_value"] = $1.gsub('""', '"')
|
397
|
-
end
|
398
|
-
|
399
|
-
sql_type = field['type']
|
400
|
-
cast_type = lookup_cast_type(sql_type)
|
401
|
-
new_column(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
# Returns an array of indexes for the given table.
|
406
|
-
def indexes(table_name, name = nil) #:nodoc:
|
407
|
-
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
|
408
|
-
sql = <<-SQL
|
409
|
-
SELECT sql
|
410
|
-
FROM sqlite_master
|
411
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
412
|
-
UNION ALL
|
413
|
-
SELECT sql
|
414
|
-
FROM sqlite_temp_master
|
415
|
-
WHERE name=#{quote(row['name'])} AND type='index'
|
416
|
-
SQL
|
417
|
-
index_sql = exec_query(sql).first['sql']
|
418
|
-
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
419
|
-
where = match[1] if match
|
420
|
-
IndexDefinition.new(
|
421
|
-
table_name,
|
422
|
-
row['name'],
|
423
|
-
row['unique'] != 0,
|
424
|
-
exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
|
425
|
-
col['name']
|
426
|
-
}, nil, nil, where)
|
427
|
-
end
|
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"] }
|
428
277
|
end
|
429
278
|
|
430
|
-
def
|
431
|
-
|
432
|
-
field['pk'] == 1
|
433
|
-
}
|
434
|
-
column && column['name']
|
435
|
-
end
|
436
|
-
|
437
|
-
def remove_index!(table_name, index_name) #:nodoc:
|
279
|
+
def remove_index(table_name, options = {}) #:nodoc:
|
280
|
+
index_name = index_name_for_remove(table_name, options)
|
438
281
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
439
282
|
end
|
440
283
|
|
@@ -447,19 +290,18 @@ module ActiveRecord
|
|
447
290
|
rename_table_indexes(table_name, new_name)
|
448
291
|
end
|
449
292
|
|
450
|
-
|
451
|
-
|
452
|
-
def valid_alter_table_type?(type)
|
453
|
-
type.to_sym != :primary_key
|
293
|
+
def valid_alter_table_type?(type, options = {})
|
294
|
+
!invalid_alter_table_type?(type, options)
|
454
295
|
end
|
296
|
+
deprecate :valid_alter_table_type?
|
455
297
|
|
456
298
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
457
|
-
if
|
458
|
-
super(table_name, column_name, type, options)
|
459
|
-
else
|
299
|
+
if invalid_alter_table_type?(type, options)
|
460
300
|
alter_table(table_name) do |definition|
|
461
301
|
definition.column(column_name, type, options)
|
462
302
|
end
|
303
|
+
else
|
304
|
+
super
|
463
305
|
end
|
464
306
|
end
|
465
307
|
|
@@ -469,13 +311,15 @@ module ActiveRecord
|
|
469
311
|
end
|
470
312
|
end
|
471
313
|
|
472
|
-
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
|
+
|
473
317
|
alter_table(table_name) do |definition|
|
474
318
|
definition[column_name].default = default
|
475
319
|
end
|
476
320
|
end
|
477
321
|
|
478
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
322
|
+
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
479
323
|
unless null || default.nil?
|
480
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")
|
481
325
|
end
|
@@ -486,81 +330,127 @@ module ActiveRecord
|
|
486
330
|
|
487
331
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
488
332
|
alter_table(table_name) do |definition|
|
489
|
-
include_default = options_include_default?(options)
|
490
333
|
definition[column_name].instance_eval do
|
491
334
|
self.type = type
|
492
335
|
self.limit = options[:limit] if options.include?(:limit)
|
493
|
-
self.default = options[:default] if
|
336
|
+
self.default = options[:default] if options.include?(:default)
|
494
337
|
self.null = options[:null] if options.include?(:null)
|
495
338
|
self.precision = options[:precision] if options.include?(:precision)
|
496
|
-
self.scale
|
339
|
+
self.scale = options[:scale] if options.include?(:scale)
|
340
|
+
self.collation = options[:collation] if options.include?(:collation)
|
497
341
|
end
|
498
342
|
end
|
499
343
|
end
|
500
344
|
|
501
345
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
502
346
|
column = column_for(table_name, column_name)
|
503
|
-
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 })
|
504
348
|
rename_column_indexes(table_name, column.name, new_column_name)
|
505
349
|
end
|
506
350
|
|
507
|
-
|
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
|
508
388
|
|
509
|
-
|
389
|
+
private
|
390
|
+
def initialize_type_map(m = type_map)
|
510
391
|
super
|
511
|
-
m
|
512
|
-
register_class_with_limit m, %r(char)i, SQLite3String
|
392
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
513
393
|
end
|
514
394
|
|
515
395
|
def table_structure(table_name)
|
516
|
-
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})",
|
396
|
+
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
517
397
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
518
|
-
structure
|
398
|
+
table_structure_with_collation(table_name, structure)
|
519
399
|
end
|
400
|
+
alias column_definitions table_structure
|
520
401
|
|
521
|
-
|
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
|
+
|
408
|
+
def alter_table(table_name, options = {})
|
522
409
|
altered_table_name = "a#{table_name}"
|
523
|
-
caller = lambda {|definition| yield definition if block_given?}
|
410
|
+
caller = lambda { |definition| yield definition if block_given? }
|
524
411
|
|
525
412
|
transaction do
|
526
413
|
move_table(table_name, altered_table_name,
|
527
|
-
options.merge(:
|
414
|
+
options.merge(temporary: true))
|
528
415
|
move_table(altered_table_name, table_name, &caller)
|
529
416
|
end
|
530
417
|
end
|
531
418
|
|
532
|
-
def move_table(from, to, options = {}, &block)
|
419
|
+
def move_table(from, to, options = {}, &block)
|
533
420
|
copy_table(from, to, options, &block)
|
534
421
|
drop_table(from)
|
535
422
|
end
|
536
423
|
|
537
|
-
def copy_table(from, to, options = {})
|
424
|
+
def copy_table(from, to, options = {})
|
538
425
|
from_primary_key = primary_key(from)
|
539
426
|
options[:id] = false
|
540
427
|
create_table(to, options) do |definition|
|
541
428
|
@definition = definition
|
542
|
-
|
429
|
+
if from_primary_key.is_a?(Array)
|
430
|
+
@definition.primary_keys from_primary_key
|
431
|
+
end
|
543
432
|
columns(from).each do |column|
|
544
433
|
column_name = options[:rename] ?
|
545
434
|
(options[:rename][column.name] ||
|
546
435
|
options[:rename][column.name.to_sym] ||
|
547
436
|
column.name) : column.name
|
548
|
-
next if column_name == from_primary_key
|
549
437
|
|
550
438
|
@definition.column(column_name, column.type,
|
551
|
-
:
|
552
|
-
:
|
553
|
-
: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
|
+
)
|
554
444
|
end
|
555
445
|
yield @definition if block_given?
|
556
446
|
end
|
557
447
|
copy_table_indexes(from, to, options[:rename] || {})
|
558
448
|
copy_table_contents(from, to,
|
559
|
-
@definition.columns.map
|
449
|
+
@definition.columns.map(&:name),
|
560
450
|
options[:rename] || {})
|
561
451
|
end
|
562
452
|
|
563
|
-
def copy_table_indexes(from, to, rename = {})
|
453
|
+
def copy_table_indexes(from, to, rename = {})
|
564
454
|
indexes(from).each do |index|
|
565
455
|
name = index.name
|
566
456
|
if to == "a#{from}"
|
@@ -569,8 +459,8 @@ module ActiveRecord
|
|
569
459
|
name = name[1..-1]
|
570
460
|
end
|
571
461
|
|
572
|
-
to_column_names = columns(to).map
|
573
|
-
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|
|
574
464
|
to_column_names.include?(column)
|
575
465
|
end
|
576
466
|
|
@@ -578,37 +468,27 @@ module ActiveRecord
|
|
578
468
|
# index name can't be the same
|
579
469
|
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
580
470
|
opts[:unique] = true if index.unique
|
471
|
+
opts[:where] = index.where if index.where
|
581
472
|
add_index(to, columns, opts)
|
582
473
|
end
|
583
474
|
end
|
584
475
|
end
|
585
476
|
|
586
|
-
def copy_table_contents(from, to, columns, rename = {})
|
587
|
-
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] }]
|
588
479
|
rename.each { |a| column_mappings[a.last] = a.first }
|
589
|
-
from_columns = columns(from).collect
|
590
|
-
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
raw_column_mappings = Hash[columns(from).map { |c| [c.name, c] }]
|
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) } * ","
|
596
485
|
|
597
|
-
exec_query("
|
598
|
-
|
599
|
-
|
600
|
-
column_values = columns.map do |col|
|
601
|
-
quote(row[column_mappings[col]], raw_column_mappings[col])
|
602
|
-
end
|
603
|
-
|
604
|
-
sql << column_values * ', '
|
605
|
-
sql << ')'
|
606
|
-
exec_query sql
|
607
|
-
end
|
486
|
+
exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
|
487
|
+
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
608
488
|
end
|
609
489
|
|
610
490
|
def sqlite_version
|
611
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(
|
491
|
+
@sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
612
492
|
end
|
613
493
|
|
614
494
|
def translate_exception(exception, message)
|
@@ -618,11 +498,76 @@ module ActiveRecord
|
|
618
498
|
# Older versions of SQLite return:
|
619
499
|
# column *column_name* is not unique
|
620
500
|
when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
|
621
|
-
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)
|
622
506
|
else
|
623
507
|
super
|
624
508
|
end
|
625
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)
|
626
570
|
end
|
571
|
+
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
627
572
|
end
|
628
573
|
end
|