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.

Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +286 -6
  3. data/README.rdoc +3 -1
  4. data/lib/active_record.rb +0 -1
  5. data/lib/active_record/associations.rb +3 -2
  6. data/lib/active_record/associations/association.rb +1 -1
  7. data/lib/active_record/associations/builder/association.rb +14 -18
  8. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  9. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  10. data/lib/active_record/associations/builder/has_many.rb +2 -0
  11. data/lib/active_record/associations/builder/has_one.rb +35 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  13. data/lib/active_record/associations/collection_proxy.rb +1 -1
  14. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  15. data/lib/active_record/associations/preloader.rb +11 -6
  16. data/lib/active_record/associations/preloader/association.rb +32 -30
  17. data/lib/active_record/associations/preloader/through_association.rb +48 -28
  18. data/lib/active_record/attribute_methods.rb +4 -3
  19. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  20. data/lib/active_record/attribute_methods/dirty.rb +42 -14
  21. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  22. data/lib/active_record/attribute_methods/query.rb +2 -3
  23. data/lib/active_record/attribute_methods/read.rb +3 -9
  24. data/lib/active_record/attribute_methods/write.rb +6 -12
  25. data/lib/active_record/attributes.rb +13 -0
  26. data/lib/active_record/autosave_association.rb +13 -3
  27. data/lib/active_record/base.rb +0 -1
  28. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -0
  29. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  30. data/lib/active_record/connection_adapters/abstract/database_statements.rb +84 -61
  31. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
  32. data/lib/active_record/connection_adapters/abstract/quoting.rb +10 -6
  33. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
  34. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +70 -14
  35. data/lib/active_record/connection_adapters/abstract_adapter.rb +56 -11
  36. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -69
  37. data/lib/active_record/connection_adapters/column.rb +17 -13
  38. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
  39. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -4
  40. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
  41. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  42. data/lib/active_record/connection_adapters/mysql2_adapter.rb +6 -2
  43. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  44. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
  45. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
  46. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  47. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -27
  48. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  49. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  50. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  51. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  52. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +50 -112
  53. data/lib/active_record/connection_handling.rb +17 -10
  54. data/lib/active_record/core.rb +15 -20
  55. data/lib/active_record/database_configurations.rb +14 -14
  56. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  57. data/lib/active_record/database_configurations/url_config.rb +12 -12
  58. data/lib/active_record/dynamic_matchers.rb +1 -1
  59. data/lib/active_record/enum.rb +6 -0
  60. data/lib/active_record/errors.rb +1 -1
  61. data/lib/active_record/gem_version.rb +1 -1
  62. data/lib/active_record/insert_all.rb +180 -0
  63. data/lib/active_record/integration.rb +13 -1
  64. data/lib/active_record/internal_metadata.rb +5 -1
  65. data/lib/active_record/locking/optimistic.rb +3 -4
  66. data/lib/active_record/log_subscriber.rb +1 -1
  67. data/lib/active_record/migration.rb +25 -18
  68. data/lib/active_record/migration/command_recorder.rb +28 -14
  69. data/lib/active_record/migration/compatibility.rb +10 -0
  70. data/lib/active_record/persistence.rb +206 -13
  71. data/lib/active_record/querying.rb +17 -12
  72. data/lib/active_record/railties/databases.rake +68 -6
  73. data/lib/active_record/reflection.rb +2 -2
  74. data/lib/active_record/relation.rb +98 -20
  75. data/lib/active_record/relation/calculations.rb +39 -39
  76. data/lib/active_record/relation/delegation.rb +22 -30
  77. data/lib/active_record/relation/finder_methods.rb +3 -9
  78. data/lib/active_record/relation/merger.rb +7 -16
  79. data/lib/active_record/relation/query_methods.rb +153 -38
  80. data/lib/active_record/relation/where_clause.rb +9 -5
  81. data/lib/active_record/sanitization.rb +3 -2
  82. data/lib/active_record/schema_dumper.rb +5 -0
  83. data/lib/active_record/schema_migration.rb +1 -1
  84. data/lib/active_record/scoping/default.rb +6 -7
  85. data/lib/active_record/scoping/named.rb +1 -1
  86. data/lib/active_record/statement_cache.rb +2 -2
  87. data/lib/active_record/store.rb +48 -0
  88. data/lib/active_record/table_metadata.rb +3 -3
  89. data/lib/active_record/tasks/database_tasks.rb +36 -1
  90. data/lib/active_record/touch_later.rb +2 -2
  91. data/lib/active_record/transactions.rb +52 -41
  92. data/lib/active_record/validations/uniqueness.rb +3 -5
  93. data/lib/arel/insert_manager.rb +3 -3
  94. data/lib/arel/nodes.rb +2 -1
  95. data/lib/arel/nodes/comment.rb +29 -0
  96. data/lib/arel/nodes/select_core.rb +16 -12
  97. data/lib/arel/nodes/unary.rb +1 -0
  98. data/lib/arel/nodes/values_list.rb +2 -17
  99. data/lib/arel/select_manager.rb +10 -10
  100. data/lib/arel/visitors/depth_first.rb +6 -1
  101. data/lib/arel/visitors/dot.rb +7 -2
  102. data/lib/arel/visitors/ibm_db.rb +13 -0
  103. data/lib/arel/visitors/informix.rb +6 -0
  104. data/lib/arel/visitors/mssql.rb +15 -1
  105. data/lib/arel/visitors/oracle12.rb +4 -5
  106. data/lib/arel/visitors/postgresql.rb +4 -10
  107. data/lib/arel/visitors/to_sql.rb +87 -108
  108. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  109. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  110. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  111. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  112. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  113. metadata +12 -11
  114. data/lib/active_record/collection_cache_key.rb +0 -53
  115. data/lib/arel/nodes/values.rb +0 -16
@@ -3,38 +3,34 @@
3
3
  module ActiveRecord
4
4
  # :stopdoc:
5
5
  module ConnectionAdapters
6
- class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
7
- undef to_yaml if method_defined?(:to_yaml)
6
+ module PostgreSQL
7
+ class TypeMetadata < DelegateClass(SqlTypeMetadata)
8
+ undef to_yaml if method_defined?(:to_yaml)
8
9
 
9
- attr_reader :oid, :fmod, :array
10
+ attr_reader :oid, :fmod
10
11
 
11
- def initialize(type_metadata, oid: nil, fmod: nil)
12
- super(type_metadata)
13
- @type_metadata = type_metadata
14
- @oid = oid
15
- @fmod = fmod
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
- protected
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 attributes_for_hash
36
- [self.class, @type_metadata, oid, fmod]
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
- postgresql_version >= 90400
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
- res = exec_query("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", "SCHEMA")
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 postgresql_version
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
- private
429
- def check_version
430
- if postgresql_version < 90300
431
- raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.3."
432
- end
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"] = @columns
28
- coder["columns_hash"] = @columns_hash
29
- coder["primary_keys"] = @primary_keys
30
- coder["data_sources"] = @data_sources
31
- coder["version"] = connection.migration_context.current_version
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 = coder["columns"]
36
- @columns_hash = coder["columns_hash"]
37
- @primary_keys = coder["primary_keys"]
38
- @data_sources = coder["data_sources"]
39
- @version = coder["version"]
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].map(&:size).inject :+
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
- attributes_for_hash == other.attributes_for_hash
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
- attributes_for_hash.hash
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