activerecord 4.2.11.3 → 5.0.7.2

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -1,13 +1,10 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  class TransactionState
4
- attr_reader :parent
5
-
6
4
  VALID_STATES = Set.new([:committed, :rolledback, nil])
7
5
 
8
6
  def initialize(state = nil)
9
7
  @state = state
10
- @parent = nil
11
8
  end
12
9
 
13
10
  def finalized?
@@ -27,7 +24,7 @@ module ActiveRecord
27
24
  end
28
25
 
29
26
  def set_state(state)
30
- if !VALID_STATES.include?(state)
27
+ unless VALID_STATES.include?(state)
31
28
  raise ArgumentError, "Invalid transaction state: #{state}"
32
29
  end
33
30
  @state = state
@@ -36,6 +33,7 @@ module ActiveRecord
36
33
 
37
34
  class NullTransaction #:nodoc:
38
35
  def initialize; end
36
+ def state; end
39
37
  def closed?; true; end
40
38
  def open?; false; end
41
39
  def joinable?; false; end
@@ -47,11 +45,12 @@ module ActiveRecord
47
45
  attr_reader :connection, :state, :records, :savepoint_name
48
46
  attr_writer :joinable
49
47
 
50
- def initialize(connection, options)
48
+ def initialize(connection, options, run_commit_callbacks: false)
51
49
  @connection = connection
52
50
  @state = TransactionState.new
53
51
  @records = []
54
52
  @joinable = options.fetch(:joinable, true)
53
+ @run_commit_callbacks = run_commit_callbacks
55
54
  end
56
55
 
57
56
  def add_record(record)
@@ -65,16 +64,11 @@ module ActiveRecord
65
64
  def rollback_records
66
65
  ite = records.uniq
67
66
  while record = ite.shift
68
- begin
69
- record.rolledback! full_rollback?
70
- rescue => e
71
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
72
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
73
- end
67
+ record.rolledback!(force_restore_state: full_rollback?)
74
68
  end
75
69
  ensure
76
70
  ite.each do |i|
77
- i.rolledback!(full_rollback?, false)
71
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
78
72
  end
79
73
  end
80
74
 
@@ -82,20 +76,22 @@ module ActiveRecord
82
76
  @state.set_state(:committed)
83
77
  end
84
78
 
79
+ def before_commit_records
80
+ records.uniq.each(&:before_committed!) if @run_commit_callbacks
81
+ end
82
+
85
83
  def commit_records
86
84
  ite = records.uniq
87
85
  while record = ite.shift
88
- begin
86
+ if @run_commit_callbacks
89
87
  record.committed!
90
- rescue => e
91
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
92
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
88
+ else
89
+ # if not running callbacks, only adds the record to the parent transaction
90
+ record.add_to_transaction
93
91
  end
94
92
  end
95
93
  ensure
96
- ite.each do |i|
97
- i.committed!(false)
98
- end
94
+ ite.each { |i| i.committed!(should_run_callbacks: false) }
99
95
  end
100
96
 
101
97
  def full_rollback?; true; end
@@ -106,8 +102,8 @@ module ActiveRecord
106
102
 
107
103
  class SavepointTransaction < Transaction
108
104
 
109
- def initialize(connection, savepoint_name, options)
110
- super(connection, options)
105
+ def initialize(connection, savepoint_name, options, *args)
106
+ super(connection, options, *args)
111
107
  if options[:isolation]
112
108
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
113
109
  end
@@ -117,14 +113,11 @@ module ActiveRecord
117
113
  def rollback
118
114
  connection.rollback_to_savepoint(savepoint_name)
119
115
  super
120
- rollback_records
121
116
  end
122
117
 
123
118
  def commit
124
119
  connection.release_savepoint(savepoint_name)
125
120
  super
126
- parent = connection.transaction_manager.current_transaction
127
- records.each { |r| parent.add_record(r) }
128
121
  end
129
122
 
130
123
  def full_rollback?; false; end
@@ -132,7 +125,7 @@ module ActiveRecord
132
125
 
133
126
  class RealTransaction < Transaction
134
127
 
135
- def initialize(connection, options)
128
+ def initialize(connection, options, *args)
136
129
  super
137
130
  if options[:isolation]
138
131
  connection.begin_isolated_db_transaction(options[:isolation])
@@ -144,13 +137,11 @@ module ActiveRecord
144
137
  def rollback
145
138
  connection.rollback_db_transaction
146
139
  super
147
- rollback_records
148
140
  end
149
141
 
150
142
  def commit
151
143
  connection.commit_db_transaction
152
144
  super
153
- commit_records
154
145
  end
155
146
  end
156
147
 
@@ -161,29 +152,46 @@ module ActiveRecord
161
152
  end
162
153
 
163
154
  def begin_transaction(options = {})
155
+ run_commit_callbacks = !current_transaction.joinable?
164
156
  transaction =
165
157
  if @stack.empty?
166
- RealTransaction.new(@connection, options)
158
+ RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
167
159
  else
168
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
160
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
161
+ run_commit_callbacks: run_commit_callbacks)
169
162
  end
163
+
170
164
  @stack.push(transaction)
171
165
  transaction
172
166
  end
173
167
 
174
168
  def commit_transaction
175
- @stack.pop.commit
169
+ transaction = @stack.last
170
+
171
+ begin
172
+ transaction.before_commit_records
173
+ ensure
174
+ @stack.pop
175
+ end
176
+
177
+ transaction.commit
178
+ transaction.commit_records
176
179
  end
177
180
 
178
- def rollback_transaction
179
- @stack.pop.rollback
181
+ def rollback_transaction(transaction = nil)
182
+ transaction ||= @stack.pop
183
+ transaction.rollback
184
+ transaction.rollback_records
180
185
  end
181
186
 
182
187
  def within_new_transaction(options = {})
183
188
  transaction = begin_transaction options
184
189
  yield
185
190
  rescue Exception => error
186
- rollback_transaction if transaction
191
+ if transaction
192
+ rollback_transaction
193
+ after_failure_actions(transaction, error)
194
+ end
187
195
  raise
188
196
  ensure
189
197
  unless error
@@ -193,7 +201,7 @@ module ActiveRecord
193
201
  begin
194
202
  commit_transaction
195
203
  rescue Exception
196
- transaction.rollback unless transaction.state.completed?
204
+ rollback_transaction(transaction) unless transaction.state.completed?
197
205
  raise
198
206
  end
199
207
  end
@@ -209,7 +217,16 @@ module ActiveRecord
209
217
  end
210
218
 
211
219
  private
220
+
212
221
  NULL_TRANSACTION = NullTransaction.new
222
+
223
+ # Deallocate invalidated prepared statements outside of the transaction
224
+ def after_failure_actions(transaction, error)
225
+ return unless transaction.is_a?(RealTransaction)
226
+ return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
227
+ @connection.clear_cache!
228
+ end
229
+
213
230
  end
214
231
  end
215
232
  end
@@ -1,12 +1,9 @@
1
- require 'date'
2
- require 'bigdecimal'
3
- require 'bigdecimal/util'
4
1
  require 'active_record/type'
5
- require 'active_support/core_ext/benchmark'
2
+ require 'active_record/connection_adapters/determine_if_preparable_visitor'
6
3
  require 'active_record/connection_adapters/schema_cache'
4
+ require 'active_record/connection_adapters/sql_type_metadata'
7
5
  require 'active_record/connection_adapters/abstract/schema_dumper'
8
6
  require 'active_record/connection_adapters/abstract/schema_creation'
9
- require 'monitor'
10
7
  require 'arel/collectors/bind'
11
8
  require 'arel/collectors/sql_string'
12
9
 
@@ -21,15 +18,15 @@ module ActiveRecord
21
18
  autoload :IndexDefinition
22
19
  autoload :ColumnDefinition
23
20
  autoload :ChangeColumnDefinition
21
+ autoload :ForeignKeyDefinition
24
22
  autoload :TableDefinition
25
23
  autoload :Table
26
24
  autoload :AlterTable
27
- autoload :TimestampDefaultDeprecation
25
+ autoload :ReferenceDefinition
28
26
  end
29
27
 
30
28
  autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
31
29
  autoload :ConnectionHandler
32
- autoload :ConnectionManagement
33
30
  end
34
31
 
35
32
  autoload_under 'abstract' do
@@ -54,28 +51,28 @@ module ActiveRecord
54
51
  # related classes form the abstraction layer which makes this possible.
55
52
  # An AbstractAdapter represents a connection to a database, and provides an
56
53
  # abstract interface for database-specific functionality such as establishing
57
- # a connection, escaping values, building the right SQL fragments for ':offset'
58
- # and ':limit' options, etc.
54
+ # a connection, escaping values, building the right SQL fragments for +:offset+
55
+ # and +:limit+ options, etc.
59
56
  #
60
57
  # All the concrete database adapters follow the interface laid down in this class.
61
- # ActiveRecord::Base.connection returns an AbstractAdapter object, which
58
+ # {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
62
59
  # you can use.
63
60
  #
64
61
  # Most of the methods in the adapter are useful during migrations. Most
65
- # notably, the instance methods provided by SchemaStatement are very useful.
62
+ # notably, the instance methods provided by SchemaStatements are very useful.
66
63
  class AbstractAdapter
67
- ADAPTER_NAME = 'Abstract'.freeze
64
+ ADAPTER_NAME = "Abstract".freeze
65
+ include ActiveSupport::Callbacks
66
+ define_callbacks :checkout, :checkin
67
+
68
68
  include Quoting, DatabaseStatements, SchemaStatements
69
69
  include DatabaseLimits
70
70
  include QueryCache
71
- include ActiveSupport::Callbacks
72
- include MonitorMixin
73
71
  include ColumnDumper
72
+ include Savepoints
74
73
 
75
74
  SIMPLE_INT = /\A\d+\z/
76
75
 
77
- define_callbacks :checkout, :checkin
78
-
79
76
  attr_accessor :visitor, :pool
80
77
  attr_reader :schema_cache, :owner, :logger
81
78
  alias :in_use? :owner
@@ -98,17 +95,25 @@ module ActiveRecord
98
95
 
99
96
  attr_reader :prepared_statements
100
97
 
101
- def initialize(connection, logger = nil, pool = nil) #:nodoc:
98
+ def initialize(connection, logger = nil, config = {}) # :nodoc:
102
99
  super()
103
100
 
104
101
  @connection = connection
105
102
  @owner = nil
106
103
  @instrumenter = ActiveSupport::Notifications.instrumenter
107
104
  @logger = logger
108
- @pool = pool
105
+ @config = config
106
+ @pool = nil
109
107
  @schema_cache = SchemaCache.new self
110
- @visitor = nil
111
- @prepared_statements = false
108
+ @quoted_column_names, @quoted_table_names = {}, {}
109
+ @visitor = arel_visitor
110
+
111
+ if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
112
+ @prepared_statements = true
113
+ @visitor.extend(DetermineIfPreparableVisitor)
114
+ else
115
+ @prepared_statements = false
116
+ end
112
117
  end
113
118
 
114
119
  class Version
@@ -125,7 +130,8 @@ module ActiveRecord
125
130
 
126
131
  class BindCollector < Arel::Collectors::Bind
127
132
  def compile(bvs, conn)
128
- super(bvs.map { |bv| conn.quote(*bv.reverse) })
133
+ casted_binds = conn.prepare_binds_for_database(bvs)
134
+ super(casted_binds.map { |value| conn.quote(value) })
129
135
  end
130
136
  end
131
137
 
@@ -143,20 +149,32 @@ module ActiveRecord
143
149
  end
144
150
  end
145
151
 
152
+ def arel_visitor # :nodoc:
153
+ Arel::Visitors::ToSql.new(self)
154
+ end
155
+
146
156
  def valid_type?(type)
147
- true
157
+ false
148
158
  end
149
159
 
150
160
  def schema_creation
151
161
  SchemaCreation.new self
152
162
  end
153
163
 
164
+ # this method must only be called while holding connection pool's mutex
154
165
  def lease
155
- synchronize do
156
- unless in_use?
157
- @owner = Thread.current
166
+ if in_use?
167
+ msg = 'Cannot lease connection, '
168
+ if @owner == Thread.current
169
+ msg << 'it is already leased by the current thread.'
170
+ else
171
+ msg << "it is already in use by a different thread: #{@owner}. " <<
172
+ "Current thread: #{Thread.current}."
158
173
  end
174
+ raise ActiveRecordError, msg
159
175
  end
176
+
177
+ @owner = Thread.current
160
178
  end
161
179
 
162
180
  def schema_cache=(cache)
@@ -164,8 +182,32 @@ module ActiveRecord
164
182
  @schema_cache = cache
165
183
  end
166
184
 
185
+ # this method must only be called while holding connection pool's mutex
167
186
  def expire
168
- @owner = nil
187
+ if in_use?
188
+ if @owner != Thread.current
189
+ raise ActiveRecordError, "Cannot expire connection, " <<
190
+ "it is owned by a different thread: #{@owner}. " <<
191
+ "Current thread: #{Thread.current}."
192
+ end
193
+
194
+ @owner = nil
195
+ else
196
+ raise ActiveRecordError, 'Cannot expire connection, it is not currently leased.'
197
+ end
198
+ end
199
+
200
+ # this method must only be called while holding connection pool's mutex (and a desire for segfaults)
201
+ def steal! # :nodoc:
202
+ if in_use?
203
+ if @owner != Thread.current
204
+ pool.send :remove_connection_from_thread_cache, self, @owner
205
+
206
+ @owner = Thread.current
207
+ end
208
+ else
209
+ raise ActiveRecordError, 'Cannot steal connection, it is not currently leased.'
210
+ end
169
211
  end
170
212
 
171
213
  def unprepared_statement
@@ -207,6 +249,11 @@ module ActiveRecord
207
249
  false
208
250
  end
209
251
 
252
+ # Does this adapter support application-enforced advisory locking?
253
+ def supports_advisory_locks?
254
+ false
255
+ end
256
+
210
257
  # Should primary key values be selected from their corresponding
211
258
  # sequence before the insert statement? If true, next_sequence_value
212
259
  # is called before each insert to set the record's primary key.
@@ -224,6 +271,11 @@ module ActiveRecord
224
271
  false
225
272
  end
226
273
 
274
+ # Does this adapter support expression indices?
275
+ def supports_expression_index?
276
+ false
277
+ end
278
+
227
279
  # Does this adapter support explain?
228
280
  def supports_explain?
229
281
  false
@@ -255,6 +307,31 @@ module ActiveRecord
255
307
  false
256
308
  end
257
309
 
310
+ # Does this adapter support datetime with precision?
311
+ def supports_datetime_with_precision?
312
+ false
313
+ end
314
+
315
+ # Does this adapter support json data type?
316
+ def supports_json?
317
+ false
318
+ end
319
+
320
+ # Does this adapter support metadata comments on database objects (tables, columns, indexes)?
321
+ def supports_comments?
322
+ false
323
+ end
324
+
325
+ # Can comments for tables, columns, and indexes be specified in create/alter table statements?
326
+ def supports_comments_in_create?
327
+ false
328
+ end
329
+
330
+ # Does this adapter support multi-value insert?
331
+ def supports_multi_insert?
332
+ true
333
+ end
334
+
258
335
  # This is meant to be implemented by the adapters that support extensions
259
336
  def disable_extension(name)
260
337
  end
@@ -263,6 +340,20 @@ module ActiveRecord
263
340
  def enable_extension(name)
264
341
  end
265
342
 
343
+ # This is meant to be implemented by the adapters that support advisory
344
+ # locks
345
+ #
346
+ # Return true if we got the lock, otherwise false
347
+ def get_advisory_lock(lock_id) # :nodoc:
348
+ end
349
+
350
+ # This is meant to be implemented by the adapters that support advisory
351
+ # locks.
352
+ #
353
+ # Return true if we released the lock, otherwise false
354
+ def release_advisory_lock(lock_id) # :nodoc:
355
+ end
356
+
266
357
  # A list of extensions, to be filled in by adapters that support them.
267
358
  def extensions
268
359
  []
@@ -273,14 +364,6 @@ module ActiveRecord
273
364
  {}
274
365
  end
275
366
 
276
- # QUOTING ==================================================
277
-
278
- # Returns a bind substitution value given a bind +column+
279
- # NOTE: The column param is currently being used by the sqlserver-adapter
280
- def substitute_at(column, _unused = 0)
281
- Arel::Nodes::BindParam.new
282
- end
283
-
284
367
  # REFERENTIAL INTEGRITY ====================================
285
368
 
286
369
  # Override to turn off referential integrity while executing <tt>&block</tt>.
@@ -334,15 +417,15 @@ module ActiveRecord
334
417
  end
335
418
 
336
419
  # Checks whether the connection to the database is still active (i.e. not stale).
337
- # This is done under the hood by calling <tt>active?</tt>. If the connection
420
+ # This is done under the hood by calling #active?. If the connection
338
421
  # is no longer active, then this method will reconnect to the database.
339
422
  def verify!(*ignored)
340
423
  reconnect! unless active?
341
424
  end
342
425
 
343
426
  # Provides access to the underlying database driver for this adapter. For
344
- # example, this method returns a Mysql object in case of MysqlAdapter,
345
- # and a PGconn object in case of PostgreSQLAdapter.
427
+ # example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
428
+ # and a PG::Connection object in case of PostgreSQLAdapter.
346
429
  #
347
430
  # This is useful for when you need to call a proprietary method such as
348
431
  # PostgreSQL's lo_* methods.
@@ -350,29 +433,26 @@ module ActiveRecord
350
433
  @connection
351
434
  end
352
435
 
353
- def create_savepoint(name = nil)
354
- end
355
-
356
- def release_savepoint(name = nil)
357
- end
358
-
359
- def case_sensitive_modifier(node, table_attribute)
360
- node
361
- end
362
-
363
436
  def case_sensitive_comparison(table, attribute, column, value)
364
- table_attr = table[attribute]
365
- value = case_sensitive_modifier(value, table_attr) unless value.nil?
366
- table_attr.eq(value)
437
+ if value.nil?
438
+ table[attribute].eq(value)
439
+ else
440
+ table[attribute].eq(Arel::Nodes::BindParam.new)
441
+ end
367
442
  end
368
443
 
369
444
  def case_insensitive_comparison(table, attribute, column, value)
370
- table[attribute].lower.eq(table.lower(value))
445
+ if can_perform_case_insensitive_comparison_for?(column)
446
+ table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
447
+ else
448
+ table[attribute].eq(Arel::Nodes::BindParam.new)
449
+ end
371
450
  end
372
451
 
373
- def current_savepoint_name
374
- current_transaction.savepoint_name
452
+ def can_perform_case_insensitive_comparison_for?(column)
453
+ true
375
454
  end
455
+ private :can_perform_case_insensitive_comparison_for?
376
456
 
377
457
  # Check the connection back in to the connection pool
378
458
  def close
@@ -385,8 +465,8 @@ module ActiveRecord
385
465
  end
386
466
  end
387
467
 
388
- def new_column(name, default, cast_type, sql_type = nil, null = true)
389
- Column.new(name, default, cast_type, sql_type, null)
468
+ def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
469
+ Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
390
470
  end
391
471
 
392
472
  def lookup_cast_type(sql_type) # :nodoc:
@@ -397,18 +477,36 @@ module ActiveRecord
397
477
  visitor.accept(node, collector).value
398
478
  end
399
479
 
480
+ def combine_bind_parameters(
481
+ from_clause: [],
482
+ join_clause: [],
483
+ where_clause: [],
484
+ having_clause: [],
485
+ limit: nil,
486
+ offset: nil
487
+ ) # :nodoc:
488
+ result = from_clause + join_clause + where_clause + having_clause
489
+ if limit
490
+ result << limit
491
+ end
492
+ if offset
493
+ result << offset
494
+ end
495
+ result
496
+ end
497
+
400
498
  protected
401
499
 
402
500
  def initialize_type_map(m) # :nodoc:
403
- register_class_with_limit m, %r(boolean)i, Type::Boolean
404
- register_class_with_limit m, %r(char)i, Type::String
405
- register_class_with_limit m, %r(binary)i, Type::Binary
406
- register_class_with_limit m, %r(text)i, Type::Text
407
- register_class_with_limit m, %r(date)i, Type::Date
408
- register_class_with_limit m, %r(time)i, Type::Time
409
- register_class_with_limit m, %r(datetime)i, Type::DateTime
410
- register_class_with_limit m, %r(float)i, Type::Float
411
- register_class_with_limit m, %r(int)i, Type::Integer
501
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
502
+ register_class_with_limit m, %r(char)i, Type::String
503
+ register_class_with_limit m, %r(binary)i, Type::Binary
504
+ register_class_with_limit m, %r(text)i, Type::Text
505
+ register_class_with_precision m, %r(date)i, Type::Date
506
+ register_class_with_precision m, %r(time)i, Type::Time
507
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
508
+ register_class_with_limit m, %r(float)i, Type::Float
509
+ register_class_with_limit m, %r(int)i, Type::Integer
412
510
 
413
511
  m.alias_type %r(blob)i, 'binary'
414
512
  m.alias_type %r(clob)i, 'text'
@@ -442,6 +540,13 @@ module ActiveRecord
442
540
  end
443
541
  end
444
542
 
543
+ def register_class_with_precision(mapping, key, klass) # :nodoc:
544
+ mapping.register_type(key) do |*args|
545
+ precision = extract_precision(args.last)
546
+ klass.new(precision: precision)
547
+ end
548
+ end
549
+
445
550
  def extract_scale(sql_type) # :nodoc:
446
551
  case sql_type
447
552
  when /\((\d+)\)/ then 0
@@ -474,21 +579,22 @@ module ActiveRecord
474
579
  exception
475
580
  end
476
581
 
477
- def log(sql, name = "SQL", binds = [], statement_name = nil)
582
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
478
583
  @instrumenter.instrument(
479
584
  "sql.active_record",
480
- :sql => sql,
481
- :name => name,
482
- :connection_id => object_id,
483
- :statement_name => statement_name,
484
- :binds => binds) { yield }
585
+ sql: sql,
586
+ name: name,
587
+ binds: binds,
588
+ type_casted_binds: type_casted_binds,
589
+ statement_name: statement_name,
590
+ connection_id: object_id) { yield }
485
591
  rescue => e
486
592
  raise translate_exception_class(e, sql)
487
593
  end
488
594
 
489
595
  def translate_exception(exception, message)
490
596
  # override in derived class
491
- ActiveRecord::StatementInvalid.new(message, exception)
597
+ ActiveRecord::StatementInvalid.new(message)
492
598
  end
493
599
 
494
600
  def without_prepared_statement?(binds)