activerecord 5.0.7 → 5.1.7
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 +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,11 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
|
7
|
-
|
8
|
-
require
|
1
|
+
require "active_record/connection_adapters/abstract_adapter"
|
2
|
+
require "active_record/connection_adapters/statement_pool"
|
3
|
+
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
4
|
+
require "active_record/connection_adapters/sqlite3/quoting"
|
5
|
+
require "active_record/connection_adapters/sqlite3/schema_creation"
|
6
|
+
require "active_record/connection_adapters/sqlite3/schema_definitions"
|
7
|
+
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
8
|
+
require "active_record/connection_adapters/sqlite3/schema_statements"
|
9
|
+
|
10
|
+
gem "sqlite3", "~> 1.3", ">= 1.3.6"
|
11
|
+
require "sqlite3"
|
9
12
|
|
10
13
|
module ActiveRecord
|
11
14
|
module ConnectionHandling # :nodoc:
|
@@ -18,7 +21,7 @@ module ActiveRecord
|
|
18
21
|
# Allow database path relative to Rails.root, but only if the database
|
19
22
|
# path is not the special path that tells sqlite to build a database only
|
20
23
|
# in memory.
|
21
|
-
if
|
24
|
+
if ":memory:" != config[:database]
|
22
25
|
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
|
23
26
|
dirname = File.dirname(config[:database])
|
24
27
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
@@ -26,7 +29,7 @@ module ActiveRecord
|
|
26
29
|
|
27
30
|
db = SQLite3::Database.new(
|
28
31
|
config[:database].to_s,
|
29
|
-
:
|
32
|
+
results_as_hash: true
|
30
33
|
)
|
31
34
|
|
32
35
|
db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
|
@@ -49,12 +52,14 @@ module ActiveRecord
|
|
49
52
|
#
|
50
53
|
# * <tt>:database</tt> - Path to the database file.
|
51
54
|
class SQLite3Adapter < AbstractAdapter
|
52
|
-
ADAPTER_NAME =
|
55
|
+
ADAPTER_NAME = "SQLite".freeze
|
53
56
|
|
54
57
|
include SQLite3::Quoting
|
58
|
+
include SQLite3::ColumnDumper
|
59
|
+
include SQLite3::SchemaStatements
|
55
60
|
|
56
61
|
NATIVE_DATABASE_TYPES = {
|
57
|
-
primary_key:
|
62
|
+
primary_key: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
|
58
63
|
string: { name: "varchar" },
|
59
64
|
text: { name: "text" },
|
60
65
|
integer: { name: "integer" },
|
@@ -70,9 +75,13 @@ module ActiveRecord
|
|
70
75
|
class StatementPool < ConnectionAdapters::StatementPool
|
71
76
|
private
|
72
77
|
|
73
|
-
|
74
|
-
|
75
|
-
|
78
|
+
def dealloc(stmt)
|
79
|
+
stmt[:stmt].close unless stmt[:stmt].closed?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def update_table_definition(table_name, base) # :nodoc:
|
84
|
+
SQLite3::Table.new(table_name, base)
|
76
85
|
end
|
77
86
|
|
78
87
|
def schema_creation # :nodoc:
|
@@ -88,6 +97,8 @@ module ActiveRecord
|
|
88
97
|
|
89
98
|
@active = nil
|
90
99
|
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
100
|
+
|
101
|
+
configure_connection
|
91
102
|
end
|
92
103
|
|
93
104
|
def supports_ddl_transactions?
|
@@ -99,7 +110,7 @@ module ActiveRecord
|
|
99
110
|
end
|
100
111
|
|
101
112
|
def supports_partial_index?
|
102
|
-
sqlite_version >=
|
113
|
+
sqlite_version >= "3.8.0"
|
103
114
|
end
|
104
115
|
|
105
116
|
# Returns true, since this connection adapter supports prepared statement
|
@@ -108,17 +119,12 @@ module ActiveRecord
|
|
108
119
|
true
|
109
120
|
end
|
110
121
|
|
111
|
-
|
112
|
-
def supports_migrations? #:nodoc:
|
113
|
-
true
|
114
|
-
end
|
115
|
-
|
116
|
-
def supports_primary_key? #:nodoc:
|
122
|
+
def requires_reloading?
|
117
123
|
true
|
118
124
|
end
|
119
125
|
|
120
|
-
def
|
121
|
-
|
126
|
+
def supports_foreign_keys_in_create?
|
127
|
+
sqlite_version >= "3.6.19"
|
122
128
|
end
|
123
129
|
|
124
130
|
def supports_views?
|
@@ -130,7 +136,7 @@ module ActiveRecord
|
|
130
136
|
end
|
131
137
|
|
132
138
|
def supports_multi_insert?
|
133
|
-
sqlite_version >=
|
139
|
+
sqlite_version >= "3.7.11"
|
134
140
|
end
|
135
141
|
|
136
142
|
def active?
|
@@ -154,12 +160,8 @@ module ActiveRecord
|
|
154
160
|
true
|
155
161
|
end
|
156
162
|
|
157
|
-
def valid_type?(type)
|
158
|
-
true
|
159
|
-
end
|
160
|
-
|
161
163
|
# Returns 62. SQLite supports index names up to 64
|
162
|
-
# characters. The rest is used by
|
164
|
+
# characters. The rest is used by Rails internally to perform
|
163
165
|
# temporary rename operations
|
164
166
|
def allowed_index_name_length
|
165
167
|
index_name_length - 2
|
@@ -178,47 +180,62 @@ module ActiveRecord
|
|
178
180
|
true
|
179
181
|
end
|
180
182
|
|
183
|
+
# REFERENTIAL INTEGRITY ====================================
|
184
|
+
|
185
|
+
def disable_referential_integrity # :nodoc:
|
186
|
+
old = query_value("PRAGMA foreign_keys")
|
187
|
+
|
188
|
+
begin
|
189
|
+
execute("PRAGMA foreign_keys = OFF")
|
190
|
+
yield
|
191
|
+
ensure
|
192
|
+
execute("PRAGMA foreign_keys = #{old}")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
181
196
|
#--
|
182
197
|
# DATABASE STATEMENTS ======================================
|
183
198
|
#++
|
184
199
|
|
185
200
|
def explain(arel, binds = [])
|
186
201
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
187
|
-
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql,
|
202
|
+
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
188
203
|
end
|
189
204
|
|
190
205
|
def exec_query(sql, name = nil, binds = [], prepare: false)
|
191
206
|
type_casted_binds = type_casted_binds(binds)
|
192
207
|
|
193
208
|
log(sql, name, binds, type_casted_binds) do
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
209
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
210
|
+
# Don't cache statements if they are not prepared
|
211
|
+
unless prepare
|
212
|
+
stmt = @connection.prepare(sql)
|
213
|
+
begin
|
214
|
+
cols = stmt.columns
|
215
|
+
unless without_prepared_statement?(binds)
|
216
|
+
stmt.bind_params(type_casted_binds)
|
217
|
+
end
|
218
|
+
records = stmt.to_a
|
219
|
+
ensure
|
220
|
+
stmt.close
|
201
221
|
end
|
222
|
+
else
|
223
|
+
cache = @statements[sql] ||= {
|
224
|
+
stmt: @connection.prepare(sql)
|
225
|
+
}
|
226
|
+
stmt = cache[:stmt]
|
227
|
+
cols = cache[:cols] ||= stmt.columns
|
228
|
+
stmt.reset!
|
229
|
+
stmt.bind_params(type_casted_binds)
|
202
230
|
records = stmt.to_a
|
203
|
-
ensure
|
204
|
-
stmt.close
|
205
231
|
end
|
206
|
-
else
|
207
|
-
cache = @statements[sql] ||= {
|
208
|
-
:stmt => @connection.prepare(sql)
|
209
|
-
}
|
210
|
-
stmt = cache[:stmt]
|
211
|
-
cols = cache[:cols] ||= stmt.columns
|
212
|
-
stmt.reset!
|
213
|
-
stmt.bind_params(type_casted_binds)
|
214
|
-
records = stmt.to_a
|
215
|
-
end
|
216
232
|
|
217
|
-
|
233
|
+
ActiveRecord::Result.new(cols, records)
|
234
|
+
end
|
218
235
|
end
|
219
236
|
end
|
220
237
|
|
221
|
-
def exec_delete(sql, name =
|
238
|
+
def exec_delete(sql, name = "SQL", binds = [])
|
222
239
|
exec_query(sql, name, binds)
|
223
240
|
@connection.changes
|
224
241
|
end
|
@@ -229,98 +246,52 @@ module ActiveRecord
|
|
229
246
|
end
|
230
247
|
|
231
248
|
def execute(sql, name = nil) #:nodoc:
|
232
|
-
log(sql, name)
|
249
|
+
log(sql, name) do
|
250
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
251
|
+
@connection.execute(sql)
|
252
|
+
end
|
253
|
+
end
|
233
254
|
end
|
234
255
|
|
235
256
|
def begin_db_transaction #:nodoc:
|
236
|
-
log(
|
257
|
+
log("begin transaction", nil) { @connection.transaction }
|
237
258
|
end
|
238
259
|
|
239
260
|
def commit_db_transaction #:nodoc:
|
240
|
-
log(
|
261
|
+
log("commit transaction", nil) { @connection.commit }
|
241
262
|
end
|
242
263
|
|
243
264
|
def exec_rollback_db_transaction #:nodoc:
|
244
|
-
log(
|
265
|
+
log("rollback transaction", nil) { @connection.rollback }
|
245
266
|
end
|
246
267
|
|
247
268
|
# SCHEMA STATEMENTS ========================================
|
248
269
|
|
249
|
-
def
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
258
|
-
Passing arguments to #tables is deprecated without replacement.
|
259
|
-
MSG
|
270
|
+
def new_column_from_field(table_name, field) # :nondoc:
|
271
|
+
case field["dflt_value"]
|
272
|
+
when /^null$/i
|
273
|
+
field["dflt_value"] = nil
|
274
|
+
when /^'(.*)'$/m
|
275
|
+
field["dflt_value"] = $1.gsub("''", "'")
|
276
|
+
when /^"(.*)"$/m
|
277
|
+
field["dflt_value"] = $1.gsub('""', '"')
|
260
278
|
end
|
261
279
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA')
|
267
|
-
end
|
268
|
-
|
269
|
-
def table_exists?(table_name)
|
270
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
271
|
-
#table_exists? currently checks both tables and views.
|
272
|
-
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
|
273
|
-
Use #data_source_exists? instead.
|
274
|
-
MSG
|
275
|
-
|
276
|
-
data_source_exists?(table_name)
|
277
|
-
end
|
278
|
-
|
279
|
-
def data_source_exists?(table_name)
|
280
|
-
return false unless table_name.present?
|
281
|
-
|
282
|
-
sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
|
283
|
-
sql << " AND name = #{quote(table_name)}"
|
284
|
-
|
285
|
-
select_values(sql, 'SCHEMA').any?
|
286
|
-
end
|
287
|
-
|
288
|
-
def views # :nodoc:
|
289
|
-
select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA')
|
290
|
-
end
|
291
|
-
|
292
|
-
def view_exists?(view_name) # :nodoc:
|
293
|
-
return false unless view_name.present?
|
294
|
-
|
295
|
-
sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'"
|
296
|
-
sql << " AND name = #{quote(view_name)}"
|
297
|
-
|
298
|
-
select_values(sql, 'SCHEMA').any?
|
299
|
-
end
|
300
|
-
|
301
|
-
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
302
|
-
def columns(table_name) # :nodoc:
|
303
|
-
table_name = table_name.to_s
|
304
|
-
table_structure(table_name).map do |field|
|
305
|
-
case field["dflt_value"]
|
306
|
-
when /^null$/i
|
307
|
-
field["dflt_value"] = nil
|
308
|
-
when /^'(.*)'$/m
|
309
|
-
field["dflt_value"] = $1.gsub("''", "'")
|
310
|
-
when /^"(.*)"$/m
|
311
|
-
field["dflt_value"] = $1.gsub('""', '"')
|
312
|
-
end
|
313
|
-
|
314
|
-
collation = field['collation']
|
315
|
-
sql_type = field['type']
|
316
|
-
type_metadata = fetch_type_metadata(sql_type)
|
317
|
-
new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, table_name, nil, collation)
|
318
|
-
end
|
280
|
+
collation = field["collation"]
|
281
|
+
sql_type = field["type"]
|
282
|
+
type_metadata = fetch_type_metadata(sql_type)
|
283
|
+
new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation)
|
319
284
|
end
|
320
285
|
|
321
286
|
# Returns an array of indexes for the given table.
|
322
287
|
def indexes(table_name, name = nil) #:nodoc:
|
323
|
-
|
288
|
+
if name
|
289
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
290
|
+
Passing name to #indexes is deprecated without replacement.
|
291
|
+
MSG
|
292
|
+
end
|
293
|
+
|
294
|
+
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
|
324
295
|
sql = <<-SQL
|
325
296
|
SELECT sql
|
326
297
|
FROM sqlite_master
|
@@ -330,22 +301,22 @@ module ActiveRecord
|
|
330
301
|
FROM sqlite_temp_master
|
331
302
|
WHERE name=#{quote(row['name'])} AND type='index'
|
332
303
|
SQL
|
333
|
-
index_sql = exec_query(sql).first[
|
304
|
+
index_sql = exec_query(sql).first["sql"]
|
334
305
|
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
335
306
|
where = match[1] if match
|
336
307
|
IndexDefinition.new(
|
337
308
|
table_name,
|
338
|
-
row[
|
339
|
-
row[
|
309
|
+
row["name"],
|
310
|
+
row["unique"] != 0,
|
340
311
|
exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
|
341
|
-
col[
|
312
|
+
col["name"]
|
342
313
|
}, nil, nil, where)
|
343
314
|
end
|
344
315
|
end
|
345
316
|
|
346
317
|
def primary_keys(table_name) # :nodoc:
|
347
|
-
pks = table_structure(table_name).select { |f| f[
|
348
|
-
pks.sort_by { |f| f[
|
318
|
+
pks = table_structure(table_name).select { |f| f["pk"] > 0 }
|
319
|
+
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
349
320
|
end
|
350
321
|
|
351
322
|
def remove_index(table_name, options = {}) #:nodoc:
|
@@ -369,7 +340,7 @@ module ActiveRecord
|
|
369
340
|
end
|
370
341
|
|
371
342
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
372
|
-
if valid_alter_table_type?(type)
|
343
|
+
if valid_alter_table_type?(type) && !options[:primary_key]
|
373
344
|
super(table_name, column_name, type, options)
|
374
345
|
else
|
375
346
|
alter_table(table_name) do |definition|
|
@@ -403,14 +374,13 @@ module ActiveRecord
|
|
403
374
|
|
404
375
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
405
376
|
alter_table(table_name) do |definition|
|
406
|
-
include_default = options_include_default?(options)
|
407
377
|
definition[column_name].instance_eval do
|
408
378
|
self.type = type
|
409
379
|
self.limit = options[:limit] if options.include?(:limit)
|
410
|
-
self.default = options[:default] if
|
380
|
+
self.default = options[:default] if options.include?(:default)
|
411
381
|
self.null = options[:null] if options.include?(:null)
|
412
382
|
self.precision = options[:precision] if options.include?(:precision)
|
413
|
-
self.scale
|
383
|
+
self.scale = options[:scale] if options.include?(:scale)
|
414
384
|
self.collation = options[:collation] if options.include?(:collation)
|
415
385
|
end
|
416
386
|
end
|
@@ -418,51 +388,73 @@ module ActiveRecord
|
|
418
388
|
|
419
389
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
420
390
|
column = column_for(table_name, column_name)
|
421
|
-
alter_table(table_name, rename: {column.name => new_column_name.to_s})
|
391
|
+
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
422
392
|
rename_column_indexes(table_name, column.name, new_column_name)
|
423
393
|
end
|
424
394
|
|
425
|
-
|
395
|
+
def add_reference(table_name, ref_name, **options) # :nodoc:
|
396
|
+
super(table_name, ref_name, type: :integer, **options)
|
397
|
+
end
|
398
|
+
alias :add_belongs_to :add_reference
|
399
|
+
|
400
|
+
def foreign_keys(table_name)
|
401
|
+
fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
|
402
|
+
fk_info.map do |row|
|
403
|
+
options = {
|
404
|
+
column: row["from"],
|
405
|
+
primary_key: row["to"],
|
406
|
+
on_delete: extract_foreign_key_action(row["on_delete"]),
|
407
|
+
on_update: extract_foreign_key_action(row["on_update"])
|
408
|
+
}
|
409
|
+
ForeignKeyDefinition.new(table_name, row["table"], options)
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
private
|
426
414
|
|
427
415
|
def table_structure(table_name)
|
428
|
-
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})",
|
416
|
+
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
429
417
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
430
418
|
table_structure_with_collation(table_name, structure)
|
431
419
|
end
|
420
|
+
alias column_definitions table_structure
|
432
421
|
|
433
|
-
def alter_table(table_name, options = {})
|
422
|
+
def alter_table(table_name, options = {})
|
434
423
|
altered_table_name = "a#{table_name}"
|
435
|
-
caller = lambda {|definition| yield definition if block_given?}
|
424
|
+
caller = lambda { |definition| yield definition if block_given? }
|
436
425
|
|
437
426
|
transaction do
|
438
427
|
move_table(table_name, altered_table_name,
|
439
|
-
options.merge(:
|
428
|
+
options.merge(temporary: true))
|
440
429
|
move_table(altered_table_name, table_name, &caller)
|
441
430
|
end
|
442
431
|
end
|
443
432
|
|
444
|
-
def move_table(from, to, options = {}, &block)
|
433
|
+
def move_table(from, to, options = {}, &block)
|
445
434
|
copy_table(from, to, options, &block)
|
446
435
|
drop_table(from)
|
447
436
|
end
|
448
437
|
|
449
|
-
def copy_table(from, to, options = {})
|
438
|
+
def copy_table(from, to, options = {})
|
450
439
|
from_primary_key = primary_key(from)
|
451
440
|
options[:id] = false
|
452
441
|
create_table(to, options) do |definition|
|
453
442
|
@definition = definition
|
454
|
-
|
443
|
+
if from_primary_key.is_a?(Array)
|
444
|
+
@definition.primary_keys from_primary_key
|
445
|
+
end
|
455
446
|
columns(from).each do |column|
|
456
447
|
column_name = options[:rename] ?
|
457
448
|
(options[:rename][column.name] ||
|
458
449
|
options[:rename][column.name.to_sym] ||
|
459
450
|
column.name) : column.name
|
460
|
-
next if column_name == from_primary_key
|
461
451
|
|
462
452
|
@definition.column(column_name, column.type,
|
463
|
-
:
|
464
|
-
:
|
465
|
-
:
|
453
|
+
limit: column.limit, default: column.default,
|
454
|
+
precision: column.precision, scale: column.scale,
|
455
|
+
null: column.null, collation: column.collation,
|
456
|
+
primary_key: column_name == from_primary_key
|
457
|
+
)
|
466
458
|
end
|
467
459
|
yield @definition if block_given?
|
468
460
|
end
|
@@ -472,9 +464,12 @@ module ActiveRecord
|
|
472
464
|
options[:rename] || {})
|
473
465
|
end
|
474
466
|
|
475
|
-
def copy_table_indexes(from, to, rename = {})
|
467
|
+
def copy_table_indexes(from, to, rename = {})
|
476
468
|
indexes(from).each do |index|
|
477
469
|
name = index.name
|
470
|
+
# indexes sqlite creates for internal use start with `sqlite_` and
|
471
|
+
# don't need to be copied
|
472
|
+
next if name.starts_with?("sqlite_")
|
478
473
|
if to == "a#{from}"
|
479
474
|
name = "t#{name}"
|
480
475
|
elsif from == "a#{to}"
|
@@ -482,7 +477,7 @@ module ActiveRecord
|
|
482
477
|
end
|
483
478
|
|
484
479
|
to_column_names = columns(to).map(&:name)
|
485
|
-
columns = index.columns.map {|c| rename[c] || c }.select do |column|
|
480
|
+
columns = index.columns.map { |c| rename[c] || c }.select do |column|
|
486
481
|
to_column_names.include?(column)
|
487
482
|
end
|
488
483
|
|
@@ -490,26 +485,27 @@ module ActiveRecord
|
|
490
485
|
# index name can't be the same
|
491
486
|
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
492
487
|
opts[:unique] = true if index.unique
|
488
|
+
opts[:where] = index.where if index.where
|
493
489
|
add_index(to, columns, opts)
|
494
490
|
end
|
495
491
|
end
|
496
492
|
end
|
497
493
|
|
498
|
-
def copy_table_contents(from, to, columns, rename = {})
|
499
|
-
column_mappings = Hash[columns.map {|name| [name, name]}]
|
494
|
+
def copy_table_contents(from, to, columns, rename = {})
|
495
|
+
column_mappings = Hash[columns.map { |name| [name, name] }]
|
500
496
|
rename.each { |a| column_mappings[a.last] = a.first }
|
501
497
|
from_columns = columns(from).collect(&:name)
|
502
|
-
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
|
498
|
+
columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
|
503
499
|
from_columns_to_copy = columns.map { |col| column_mappings[col] }
|
504
|
-
quoted_columns = columns.map { |col| quote_column_name(col) } *
|
505
|
-
quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } *
|
500
|
+
quoted_columns = columns.map { |col| quote_column_name(col) } * ","
|
501
|
+
quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
|
506
502
|
|
507
503
|
exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
|
508
504
|
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
509
505
|
end
|
510
506
|
|
511
507
|
def sqlite_version
|
512
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(
|
508
|
+
@sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
513
509
|
end
|
514
510
|
|
515
511
|
def translate_exception(exception, message)
|
@@ -520,42 +516,47 @@ module ActiveRecord
|
|
520
516
|
# column *column_name* is not unique
|
521
517
|
when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
|
522
518
|
RecordNotUnique.new(message)
|
519
|
+
when /.* may not be NULL/, /NOT NULL constraint failed: .*/
|
520
|
+
NotNullViolation.new(message)
|
521
|
+
when /FOREIGN KEY constraint failed/i
|
522
|
+
InvalidForeignKey.new(message)
|
523
523
|
else
|
524
524
|
super
|
525
525
|
end
|
526
526
|
end
|
527
527
|
|
528
|
-
private
|
529
528
|
COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
|
530
529
|
|
531
530
|
def table_structure_with_collation(table_name, basic_structure)
|
532
531
|
collation_hash = {}
|
533
|
-
sql
|
534
|
-
|
535
|
-
|
536
|
-
|
532
|
+
sql = <<-SQL
|
533
|
+
SELECT sql FROM
|
534
|
+
(SELECT * FROM sqlite_master UNION ALL
|
535
|
+
SELECT * FROM sqlite_temp_master)
|
536
|
+
WHERE type = 'table' AND name = #{quote(table_name)}
|
537
|
+
SQL
|
537
538
|
|
538
539
|
# Result will have following sample string
|
539
540
|
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
540
541
|
# "password_digest" varchar COLLATE "NOCASE");
|
541
|
-
result = exec_query(sql,
|
542
|
+
result = exec_query(sql, "SCHEMA").first
|
542
543
|
|
543
544
|
if result
|
544
545
|
# Splitting with left parentheses and picking up last will return all
|
545
546
|
# columns separated with comma(,).
|
546
|
-
columns_string = result["sql"].split(
|
547
|
+
columns_string = result["sql"].split("(").last
|
547
548
|
|
548
|
-
columns_string.split(
|
549
|
+
columns_string.split(",").each do |column_string|
|
549
550
|
# This regex will match the column name and collation type and will save
|
550
551
|
# the value in $1 and $2 respectively.
|
551
|
-
collation_hash[$1] = $2 if
|
552
|
+
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
|
552
553
|
end
|
553
554
|
|
554
555
|
basic_structure.map! do |column|
|
555
|
-
column_name = column[
|
556
|
+
column_name = column["name"]
|
556
557
|
|
557
558
|
if collation_hash.has_key? column_name
|
558
|
-
column[
|
559
|
+
column["collation"] = collation_hash[column_name]
|
559
560
|
end
|
560
561
|
|
561
562
|
column
|
@@ -564,6 +565,22 @@ module ActiveRecord
|
|
564
565
|
basic_structure.to_hash
|
565
566
|
end
|
566
567
|
end
|
568
|
+
|
569
|
+
def create_table_definition(*args)
|
570
|
+
SQLite3::TableDefinition.new(*args)
|
571
|
+
end
|
572
|
+
|
573
|
+
def extract_foreign_key_action(specifier)
|
574
|
+
case specifier
|
575
|
+
when "CASCADE"; :cascade
|
576
|
+
when "SET NULL"; :nullify
|
577
|
+
when "RESTRICT"; :restrict
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
def configure_connection
|
582
|
+
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
583
|
+
end
|
567
584
|
end
|
568
585
|
end
|
569
586
|
end
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
DEFAULT_STATEMENT_LIMIT = 1000
|
7
7
|
|
8
8
|
def initialize(statement_limit = nil)
|
9
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
9
|
+
@cache = Hash.new { |h, pid| h[pid] = {} }
|
10
10
|
@statement_limit = statement_limit || DEFAULT_STATEMENT_LIMIT
|
11
11
|
end
|
12
12
|
|
@@ -47,13 +47,13 @@ module ActiveRecord
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
def cache
|
51
|
+
@cache[Process.pid]
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
def dealloc(stmt)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|