activerecord 6.0.0.beta3 → 6.0.0.rc1
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 +286 -6
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations/preloader/association.rb +32 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +4 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +42 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +13 -3
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +84 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +10 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +70 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +56 -11
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -69
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +6 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -27
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +50 -112
- data/lib/active_record/connection_handling.rb +17 -10
- data/lib/active_record/core.rb +15 -20
- data/lib/active_record/database_configurations.rb +14 -14
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +6 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +180 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration.rb +25 -18
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railties/databases.rake +68 -6
- data/lib/active_record/reflection.rb +2 -2
- data/lib/active_record/relation.rb +98 -20
- data/lib/active_record/relation/calculations.rb +39 -39
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +3 -9
- data/lib/active_record/relation/merger.rb +7 -16
- data/lib/active_record/relation/query_methods.rb +153 -38
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +3 -2
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +3 -3
- data/lib/active_record/tasks/database_tasks.rb +36 -1
- data/lib/active_record/touch_later.rb +2 -2
- data/lib/active_record/transactions.rb +52 -41
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +6 -1
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +87 -108
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +12 -11
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -3,38 +3,34 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
# :stopdoc:
|
5
5
|
module ConnectionAdapters
|
6
|
-
|
7
|
-
|
6
|
+
module PostgreSQL
|
7
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
8
|
+
undef to_yaml if method_defined?(:to_yaml)
|
8
9
|
|
9
|
-
|
10
|
+
attr_reader :oid, :fmod
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@array = /\[\]$/.match?(type_metadata.sql_type)
|
17
|
-
end
|
18
|
-
|
19
|
-
def sql_type
|
20
|
-
super.gsub(/\[\]$/, "")
|
21
|
-
end
|
22
|
-
|
23
|
-
def ==(other)
|
24
|
-
other.is_a?(PostgreSQLTypeMetadata) &&
|
25
|
-
attributes_for_hash == other.attributes_for_hash
|
26
|
-
end
|
27
|
-
alias eql? ==
|
28
|
-
|
29
|
-
def hash
|
30
|
-
attributes_for_hash.hash
|
31
|
-
end
|
12
|
+
def initialize(type_metadata, oid: nil, fmod: nil)
|
13
|
+
super(type_metadata)
|
14
|
+
@oid = oid
|
15
|
+
@fmod = fmod
|
16
|
+
end
|
32
17
|
|
33
|
-
|
18
|
+
def ==(other)
|
19
|
+
other.is_a?(TypeMetadata) &&
|
20
|
+
__getobj__ == other.__getobj__ &&
|
21
|
+
oid == other.oid &&
|
22
|
+
fmod == other.fmod
|
23
|
+
end
|
24
|
+
alias eql? ==
|
34
25
|
|
35
|
-
def
|
36
|
-
|
26
|
+
def hash
|
27
|
+
TypeMetadata.hash ^
|
28
|
+
__getobj__.hash ^
|
29
|
+
oid.hash ^
|
30
|
+
fmod.hash
|
37
31
|
end
|
32
|
+
end
|
38
33
|
end
|
34
|
+
PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
|
39
35
|
end
|
40
36
|
end
|
@@ -196,6 +196,17 @@ module ActiveRecord
|
|
196
196
|
true
|
197
197
|
end
|
198
198
|
|
199
|
+
def supports_insert_returning?
|
200
|
+
true
|
201
|
+
end
|
202
|
+
|
203
|
+
def supports_insert_on_conflict?
|
204
|
+
database_version >= 90500
|
205
|
+
end
|
206
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
207
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
208
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
209
|
+
|
199
210
|
def index_algorithms
|
200
211
|
{ concurrently: "CONCURRENTLY" }
|
201
212
|
end
|
@@ -236,15 +247,10 @@ module ActiveRecord
|
|
236
247
|
|
237
248
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
238
249
|
@local_tz = nil
|
239
|
-
@default_timezone = nil
|
240
|
-
@timestamp_decoder = nil
|
241
250
|
@max_identifier_length = nil
|
242
251
|
|
243
252
|
configure_connection
|
244
253
|
add_pg_encoders
|
245
|
-
@statements = StatementPool.new @connection,
|
246
|
-
self.class.type_cast_config_to_integer(config[:statement_limit])
|
247
|
-
|
248
254
|
add_pg_decoders
|
249
255
|
|
250
256
|
@type_map = Type::HashLookupTypeMap.new
|
@@ -253,17 +259,6 @@ module ActiveRecord
|
|
253
259
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
254
260
|
end
|
255
261
|
|
256
|
-
# Clears the prepared statements cache.
|
257
|
-
def clear_cache!
|
258
|
-
@lock.synchronize do
|
259
|
-
@statements.clear
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
def truncate(table_name, name = nil)
|
264
|
-
exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
|
265
|
-
end
|
266
|
-
|
267
262
|
# Is this connection alive and ready for queries?
|
268
263
|
def active?
|
269
264
|
@lock.synchronize do
|
@@ -280,6 +275,8 @@ module ActiveRecord
|
|
280
275
|
super
|
281
276
|
@connection.reset
|
282
277
|
configure_connection
|
278
|
+
rescue PG::ConnectionBad
|
279
|
+
connect
|
283
280
|
end
|
284
281
|
end
|
285
282
|
|
@@ -347,7 +344,14 @@ module ActiveRecord
|
|
347
344
|
end
|
348
345
|
|
349
346
|
def supports_pgcrypto_uuid?
|
350
|
-
|
347
|
+
database_version >= 90400
|
348
|
+
end
|
349
|
+
|
350
|
+
def supports_optimizer_hints?
|
351
|
+
unless defined?(@has_pg_hint_plan)
|
352
|
+
@has_pg_hint_plan = extension_available?("pg_hint_plan")
|
353
|
+
end
|
354
|
+
@has_pg_hint_plan
|
351
355
|
end
|
352
356
|
|
353
357
|
def supports_lazy_transactions?
|
@@ -380,9 +384,12 @@ module ActiveRecord
|
|
380
384
|
}
|
381
385
|
end
|
382
386
|
|
387
|
+
def extension_available?(name)
|
388
|
+
query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
389
|
+
end
|
390
|
+
|
383
391
|
def extension_enabled?(name)
|
384
|
-
|
385
|
-
res.cast_values.first
|
392
|
+
query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
386
393
|
end
|
387
394
|
|
388
395
|
def extensions
|
@@ -393,8 +400,6 @@ module ActiveRecord
|
|
393
400
|
def max_identifier_length
|
394
401
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
395
402
|
end
|
396
|
-
alias table_alias_length max_identifier_length
|
397
|
-
alias index_name_length max_identifier_length
|
398
403
|
|
399
404
|
# Set the authorized user for this session
|
400
405
|
def session_auth=(user)
|
@@ -417,21 +422,37 @@ module ActiveRecord
|
|
417
422
|
}
|
418
423
|
|
419
424
|
# Returns the version of the connected PostgreSQL server.
|
420
|
-
def
|
425
|
+
def get_database_version # :nodoc:
|
421
426
|
@connection.server_version
|
422
427
|
end
|
428
|
+
alias :postgresql_version :database_version
|
423
429
|
|
424
430
|
def default_index_type?(index) # :nodoc:
|
425
431
|
index.using == :btree || super
|
426
432
|
end
|
427
433
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
434
|
+
def build_insert_sql(insert) # :nodoc:
|
435
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
436
|
+
|
437
|
+
if insert.skip_duplicates?
|
438
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
439
|
+
elsif insert.update_duplicates?
|
440
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
441
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
433
442
|
end
|
434
443
|
|
444
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
445
|
+
sql
|
446
|
+
end
|
447
|
+
|
448
|
+
def check_version # :nodoc:
|
449
|
+
if database_version < 90300
|
450
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
private
|
455
|
+
|
435
456
|
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
436
457
|
VALUE_LIMIT_VIOLATION = "22001"
|
437
458
|
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
@@ -723,6 +744,8 @@ module ActiveRecord
|
|
723
744
|
def connect
|
724
745
|
@connection = PG.connect(@connection_parameters)
|
725
746
|
configure_connection
|
747
|
+
add_pg_encoders
|
748
|
+
add_pg_decoders
|
726
749
|
end
|
727
750
|
|
728
751
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -803,6 +826,10 @@ module ActiveRecord
|
|
803
826
|
Arel::Visitors::PostgreSQL.new(self)
|
804
827
|
end
|
805
828
|
|
829
|
+
def build_statement_pool
|
830
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
831
|
+
end
|
832
|
+
|
806
833
|
def can_perform_case_insensitive_comparison_for?(column)
|
807
834
|
@case_insensitive_cache ||= {}
|
808
835
|
@case_insensitive_cache[column.sql_type] ||= begin
|
@@ -846,6 +873,9 @@ module ActiveRecord
|
|
846
873
|
end
|
847
874
|
|
848
875
|
def add_pg_decoders
|
876
|
+
@default_timezone = nil
|
877
|
+
@timestamp_decoder = nil
|
878
|
+
|
849
879
|
coders_by_name = {
|
850
880
|
"int2" => PG::TextDecoder::Integer,
|
851
881
|
"int4" => PG::TextDecoder::Integer,
|
@@ -13,6 +13,7 @@ module ActiveRecord
|
|
13
13
|
@columns_hash = {}
|
14
14
|
@primary_keys = {}
|
15
15
|
@data_sources = {}
|
16
|
+
@indexes = {}
|
16
17
|
end
|
17
18
|
|
18
19
|
def initialize_dup(other)
|
@@ -21,22 +22,27 @@ module ActiveRecord
|
|
21
22
|
@columns_hash = @columns_hash.dup
|
22
23
|
@primary_keys = @primary_keys.dup
|
23
24
|
@data_sources = @data_sources.dup
|
25
|
+
@indexes = @indexes.dup
|
24
26
|
end
|
25
27
|
|
26
28
|
def encode_with(coder)
|
27
|
-
coder["columns"]
|
28
|
-
coder["columns_hash"]
|
29
|
-
coder["primary_keys"]
|
30
|
-
coder["data_sources"]
|
31
|
-
coder["
|
29
|
+
coder["columns"] = @columns
|
30
|
+
coder["columns_hash"] = @columns_hash
|
31
|
+
coder["primary_keys"] = @primary_keys
|
32
|
+
coder["data_sources"] = @data_sources
|
33
|
+
coder["indexes"] = @indexes
|
34
|
+
coder["version"] = connection.migration_context.current_version
|
35
|
+
coder["database_version"] = database_version
|
32
36
|
end
|
33
37
|
|
34
38
|
def init_with(coder)
|
35
|
-
@columns
|
36
|
-
@columns_hash
|
37
|
-
@primary_keys
|
38
|
-
@data_sources
|
39
|
-
@
|
39
|
+
@columns = coder["columns"]
|
40
|
+
@columns_hash = coder["columns_hash"]
|
41
|
+
@primary_keys = coder["primary_keys"]
|
42
|
+
@data_sources = coder["data_sources"]
|
43
|
+
@indexes = coder["indexes"] || {}
|
44
|
+
@version = coder["version"]
|
45
|
+
@database_version = coder["database_version"]
|
40
46
|
end
|
41
47
|
|
42
48
|
def primary_keys(table_name)
|
@@ -57,6 +63,7 @@ module ActiveRecord
|
|
57
63
|
primary_keys(table_name)
|
58
64
|
columns(table_name)
|
59
65
|
columns_hash(table_name)
|
66
|
+
indexes(table_name)
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
@@ -82,17 +89,27 @@ module ActiveRecord
|
|
82
89
|
@columns_hash.key?(table_name)
|
83
90
|
end
|
84
91
|
|
92
|
+
def indexes(table_name)
|
93
|
+
@indexes[table_name] ||= connection.indexes(table_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def database_version # :nodoc:
|
97
|
+
@database_version ||= connection.get_database_version
|
98
|
+
end
|
99
|
+
|
85
100
|
# Clears out internal caches
|
86
101
|
def clear!
|
87
102
|
@columns.clear
|
88
103
|
@columns_hash.clear
|
89
104
|
@primary_keys.clear
|
90
105
|
@data_sources.clear
|
106
|
+
@indexes.clear
|
91
107
|
@version = nil
|
108
|
+
@database_version = nil
|
92
109
|
end
|
93
110
|
|
94
111
|
def size
|
95
|
-
[@columns, @columns_hash, @primary_keys, @data_sources].
|
112
|
+
[@columns, @columns_hash, @primary_keys, @data_sources].sum(&:size)
|
96
113
|
end
|
97
114
|
|
98
115
|
# Clear out internal caches for the data source +name+.
|
@@ -101,20 +118,21 @@ module ActiveRecord
|
|
101
118
|
@columns_hash.delete name
|
102
119
|
@primary_keys.delete name
|
103
120
|
@data_sources.delete name
|
121
|
+
@indexes.delete name
|
104
122
|
end
|
105
123
|
|
106
124
|
def marshal_dump
|
107
125
|
# if we get current version during initialization, it happens stack over flow.
|
108
126
|
@version = connection.migration_context.current_version
|
109
|
-
[@version, @columns, @columns_hash, @primary_keys, @data_sources]
|
127
|
+
[@version, @columns, @columns_hash, @primary_keys, @data_sources, @indexes, database_version]
|
110
128
|
end
|
111
129
|
|
112
130
|
def marshal_load(array)
|
113
|
-
@version, @columns, @columns_hash, @primary_keys, @data_sources = array
|
131
|
+
@version, @columns, @columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
|
132
|
+
@indexes = @indexes || {}
|
114
133
|
end
|
115
134
|
|
116
135
|
private
|
117
|
-
|
118
136
|
def prepare_data_sources
|
119
137
|
connection.data_sources.each { |source| @data_sources[source] = true }
|
120
138
|
end
|
@@ -16,19 +16,22 @@ module ActiveRecord
|
|
16
16
|
|
17
17
|
def ==(other)
|
18
18
|
other.is_a?(SqlTypeMetadata) &&
|
19
|
-
|
19
|
+
sql_type == other.sql_type &&
|
20
|
+
type == other.type &&
|
21
|
+
limit == other.limit &&
|
22
|
+
precision == other.precision &&
|
23
|
+
scale == other.scale
|
20
24
|
end
|
21
25
|
alias eql? ==
|
22
26
|
|
23
27
|
def hash
|
24
|
-
|
28
|
+
SqlTypeMetadata.hash ^
|
29
|
+
sql_type.hash ^
|
30
|
+
type.hash ^
|
31
|
+
limit.hash ^
|
32
|
+
precision.hash >> 1 ^
|
33
|
+
scale.hash >> 2
|
25
34
|
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
def attributes_for_hash
|
30
|
-
[self.class, sql_type, type, limit, precision, scale]
|
31
|
-
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module SQLite3
|
6
|
+
module DatabaseStatements
|
7
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc:
|
8
|
+
private_constant :READ_QUERY
|
9
|
+
|
10
|
+
def write_query?(sql) # :nodoc:
|
11
|
+
!READ_QUERY.match?(sql)
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(sql, name = nil) #:nodoc:
|
15
|
+
if preventing_writes? && write_query?(sql)
|
16
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
17
|
+
end
|
18
|
+
|
19
|
+
materialize_transactions
|
20
|
+
|
21
|
+
log(sql, name) do
|
22
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
23
|
+
@connection.execute(sql)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def exec_query(sql, name = nil, binds = [], prepare: false)
|
29
|
+
if preventing_writes? && write_query?(sql)
|
30
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
31
|
+
end
|
32
|
+
|
33
|
+
materialize_transactions
|
34
|
+
|
35
|
+
type_casted_binds = type_casted_binds(binds)
|
36
|
+
|
37
|
+
log(sql, name, binds, type_casted_binds) do
|
38
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
39
|
+
# Don't cache statements if they are not prepared
|
40
|
+
unless prepare
|
41
|
+
stmt = @connection.prepare(sql)
|
42
|
+
begin
|
43
|
+
cols = stmt.columns
|
44
|
+
unless without_prepared_statement?(binds)
|
45
|
+
stmt.bind_params(type_casted_binds)
|
46
|
+
end
|
47
|
+
records = stmt.to_a
|
48
|
+
ensure
|
49
|
+
stmt.close
|
50
|
+
end
|
51
|
+
else
|
52
|
+
stmt = @statements[sql] ||= @connection.prepare(sql)
|
53
|
+
cols = stmt.columns
|
54
|
+
stmt.reset!
|
55
|
+
stmt.bind_params(type_casted_binds)
|
56
|
+
records = stmt.to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
ActiveRecord::Result.new(cols, records)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def exec_delete(sql, name = "SQL", binds = [])
|
65
|
+
exec_query(sql, name, binds)
|
66
|
+
@connection.changes
|
67
|
+
end
|
68
|
+
alias :exec_update :exec_delete
|
69
|
+
|
70
|
+
def begin_db_transaction #:nodoc:
|
71
|
+
log("begin transaction", nil) { @connection.transaction }
|
72
|
+
end
|
73
|
+
|
74
|
+
def commit_db_transaction #:nodoc:
|
75
|
+
log("commit transaction", nil) { @connection.commit }
|
76
|
+
end
|
77
|
+
|
78
|
+
def exec_rollback_db_transaction #:nodoc:
|
79
|
+
log("rollback transaction", nil) { @connection.rollback }
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
def execute_batch(sql, name = nil)
|
85
|
+
if preventing_writes? && write_query?(sql)
|
86
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
87
|
+
end
|
88
|
+
|
89
|
+
materialize_transactions
|
90
|
+
|
91
|
+
log(sql, name) do
|
92
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
93
|
+
@connection.execute_batch2(sql)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def last_inserted_id(result)
|
99
|
+
@connection.last_insert_row_id
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_fixture_statements(fixture_set)
|
103
|
+
fixture_set.flat_map do |table_name, fixtures|
|
104
|
+
next if fixtures.empty?
|
105
|
+
fixtures.map { |fixture| build_fixture_sql([fixture], table_name) }
|
106
|
+
end.compact
|
107
|
+
end
|
108
|
+
|
109
|
+
def build_truncate_statements(*table_names)
|
110
|
+
truncate_tables = table_names.map do |table_name|
|
111
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
112
|
+
end
|
113
|
+
combine_multi_statements(truncate_tables)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|