activerecord 4.2.0 → 5.0.0

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  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/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -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,19 +45,16 @@ 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)
58
- if record.has_transactional_callbacks?
59
- records << record
60
- else
61
- record.set_transaction_state(@state)
62
- end
57
+ records << record
63
58
  end
64
59
 
65
60
  def rollback
@@ -69,16 +64,11 @@ module ActiveRecord
69
64
  def rollback_records
70
65
  ite = records.uniq
71
66
  while record = ite.shift
72
- begin
73
- record.rolledback! full_rollback?
74
- rescue => e
75
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
76
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
77
- end
67
+ record.rolledback!(force_restore_state: full_rollback?)
78
68
  end
79
69
  ensure
80
70
  ite.each do |i|
81
- i.rolledback!(full_rollback?, false)
71
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
82
72
  end
83
73
  end
84
74
 
@@ -86,20 +76,22 @@ module ActiveRecord
86
76
  @state.set_state(:committed)
87
77
  end
88
78
 
79
+ def before_commit_records
80
+ records.uniq.each(&:before_committed!) if @run_commit_callbacks
81
+ end
82
+
89
83
  def commit_records
90
84
  ite = records.uniq
91
85
  while record = ite.shift
92
- begin
86
+ if @run_commit_callbacks
93
87
  record.committed!
94
- rescue => e
95
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
96
- 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
97
91
  end
98
92
  end
99
93
  ensure
100
- ite.each do |i|
101
- i.committed!(false)
102
- end
94
+ ite.each { |i| i.committed!(should_run_callbacks: false) }
103
95
  end
104
96
 
105
97
  def full_rollback?; true; end
@@ -110,8 +102,8 @@ module ActiveRecord
110
102
 
111
103
  class SavepointTransaction < Transaction
112
104
 
113
- def initialize(connection, savepoint_name, options)
114
- super(connection, options)
105
+ def initialize(connection, savepoint_name, options, *args)
106
+ super(connection, options, *args)
115
107
  if options[:isolation]
116
108
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
117
109
  end
@@ -121,14 +113,11 @@ module ActiveRecord
121
113
  def rollback
122
114
  connection.rollback_to_savepoint(savepoint_name)
123
115
  super
124
- rollback_records
125
116
  end
126
117
 
127
118
  def commit
128
119
  connection.release_savepoint(savepoint_name)
129
120
  super
130
- parent = connection.transaction_manager.current_transaction
131
- records.each { |r| parent.add_record(r) }
132
121
  end
133
122
 
134
123
  def full_rollback?; false; end
@@ -136,7 +125,7 @@ module ActiveRecord
136
125
 
137
126
  class RealTransaction < Transaction
138
127
 
139
- def initialize(connection, options)
128
+ def initialize(connection, options, *args)
140
129
  super
141
130
  if options[:isolation]
142
131
  connection.begin_isolated_db_transaction(options[:isolation])
@@ -148,13 +137,11 @@ module ActiveRecord
148
137
  def rollback
149
138
  connection.rollback_db_transaction
150
139
  super
151
- rollback_records
152
140
  end
153
141
 
154
142
  def commit
155
143
  connection.commit_db_transaction
156
144
  super
157
- commit_records
158
145
  end
159
146
  end
160
147
 
@@ -165,39 +152,56 @@ module ActiveRecord
165
152
  end
166
153
 
167
154
  def begin_transaction(options = {})
155
+ run_commit_callbacks = !current_transaction.joinable?
168
156
  transaction =
169
157
  if @stack.empty?
170
- RealTransaction.new(@connection, options)
158
+ RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
171
159
  else
172
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
160
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
161
+ run_commit_callbacks: run_commit_callbacks)
173
162
  end
163
+
174
164
  @stack.push(transaction)
175
165
  transaction
176
166
  end
177
167
 
178
168
  def commit_transaction
179
- @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
180
179
  end
181
180
 
182
- def rollback_transaction
183
- @stack.pop.rollback
181
+ def rollback_transaction(transaction = nil)
182
+ transaction ||= @stack.pop
183
+ transaction.rollback
184
+ transaction.rollback_records
184
185
  end
185
186
 
186
187
  def within_new_transaction(options = {})
187
188
  transaction = begin_transaction options
188
189
  yield
189
190
  rescue Exception => error
190
- rollback_transaction if transaction
191
+ if transaction
192
+ rollback_transaction
193
+ after_failure_actions(transaction, error)
194
+ end
191
195
  raise
192
196
  ensure
193
197
  unless error
194
198
  if Thread.current.status == 'aborting'
195
- rollback_transaction
199
+ rollback_transaction if transaction
196
200
  else
197
201
  begin
198
202
  commit_transaction
199
203
  rescue Exception
200
- transaction.rollback unless transaction.state.completed?
204
+ rollback_transaction(transaction) unless transaction.state.completed?
201
205
  raise
202
206
  end
203
207
  end
@@ -213,7 +217,16 @@ module ActiveRecord
213
217
  end
214
218
 
215
219
  private
220
+
216
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
+
217
230
  end
218
231
  end
219
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,23 +51,23 @@ 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
64
  ADAPTER_NAME = 'Abstract'.freeze
68
65
  include Quoting, DatabaseStatements, SchemaStatements
69
66
  include DatabaseLimits
70
67
  include QueryCache
71
68
  include ActiveSupport::Callbacks
72
- include MonitorMixin
73
69
  include ColumnDumper
70
+ include Savepoints
74
71
 
75
72
  SIMPLE_INT = /\A\d+\z/
76
73
 
@@ -98,22 +95,43 @@ 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
117
+ end
118
+
119
+ class Version
120
+ include Comparable
121
+
122
+ def initialize(version_string)
123
+ @version = version_string.split('.').map(&:to_i)
124
+ end
125
+
126
+ def <=>(version_string)
127
+ @version <=> version_string.split('.').map(&:to_i)
128
+ end
112
129
  end
113
130
 
114
131
  class BindCollector < Arel::Collectors::Bind
115
132
  def compile(bvs, conn)
116
- 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) })
117
135
  end
118
136
  end
119
137
 
@@ -131,20 +149,32 @@ module ActiveRecord
131
149
  end
132
150
  end
133
151
 
152
+ def arel_visitor # :nodoc:
153
+ Arel::Visitors::ToSql.new(self)
154
+ end
155
+
134
156
  def valid_type?(type)
135
- true
157
+ false
136
158
  end
137
159
 
138
160
  def schema_creation
139
161
  SchemaCreation.new self
140
162
  end
141
163
 
164
+ # this method must only be called while holding connection pool's mutex
142
165
  def lease
143
- synchronize do
144
- unless in_use?
145
- @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}."
146
173
  end
174
+ raise ActiveRecordError, msg
147
175
  end
176
+
177
+ @owner = Thread.current
148
178
  end
149
179
 
150
180
  def schema_cache=(cache)
@@ -152,6 +182,7 @@ module ActiveRecord
152
182
  @schema_cache = cache
153
183
  end
154
184
 
185
+ # this method must only be called while holding connection pool's mutex
155
186
  def expire
156
187
  @owner = nil
157
188
  end
@@ -195,6 +226,11 @@ module ActiveRecord
195
226
  false
196
227
  end
197
228
 
229
+ # Does this adapter support application-enforced advisory locking?
230
+ def supports_advisory_locks?
231
+ false
232
+ end
233
+
198
234
  # Should primary key values be selected from their corresponding
199
235
  # sequence before the insert statement? If true, next_sequence_value
200
236
  # is called before each insert to set the record's primary key.
@@ -212,6 +248,11 @@ module ActiveRecord
212
248
  false
213
249
  end
214
250
 
251
+ # Does this adapter support expression indices?
252
+ def supports_expression_index?
253
+ false
254
+ end
255
+
215
256
  # Does this adapter support explain?
216
257
  def supports_explain?
217
258
  false
@@ -243,6 +284,31 @@ module ActiveRecord
243
284
  false
244
285
  end
245
286
 
287
+ # Does this adapter support datetime with precision?
288
+ def supports_datetime_with_precision?
289
+ false
290
+ end
291
+
292
+ # Does this adapter support json data type?
293
+ def supports_json?
294
+ false
295
+ end
296
+
297
+ # Does this adapter support metadata comments on database objects (tables, columns, indexes)?
298
+ def supports_comments?
299
+ false
300
+ end
301
+
302
+ # Can comments for tables, columns, and indexes be specified in create/alter table statements?
303
+ def supports_comments_in_create?
304
+ false
305
+ end
306
+
307
+ # Does this adapter support multi-value insert?
308
+ def supports_multi_insert?
309
+ true
310
+ end
311
+
246
312
  # This is meant to be implemented by the adapters that support extensions
247
313
  def disable_extension(name)
248
314
  end
@@ -251,6 +317,20 @@ module ActiveRecord
251
317
  def enable_extension(name)
252
318
  end
253
319
 
320
+ # This is meant to be implemented by the adapters that support advisory
321
+ # locks
322
+ #
323
+ # Return true if we got the lock, otherwise false
324
+ def get_advisory_lock(lock_id) # :nodoc:
325
+ end
326
+
327
+ # This is meant to be implemented by the adapters that support advisory
328
+ # locks.
329
+ #
330
+ # Return true if we released the lock, otherwise false
331
+ def release_advisory_lock(lock_id) # :nodoc:
332
+ end
333
+
254
334
  # A list of extensions, to be filled in by adapters that support them.
255
335
  def extensions
256
336
  []
@@ -261,14 +341,6 @@ module ActiveRecord
261
341
  {}
262
342
  end
263
343
 
264
- # QUOTING ==================================================
265
-
266
- # Returns a bind substitution value given a bind +column+
267
- # NOTE: The column param is currently being used by the sqlserver-adapter
268
- def substitute_at(column, _unused = 0)
269
- Arel::Nodes::BindParam.new
270
- end
271
-
272
344
  # REFERENTIAL INTEGRITY ====================================
273
345
 
274
346
  # Override to turn off referential integrity while executing <tt>&block</tt>.
@@ -322,14 +394,14 @@ module ActiveRecord
322
394
  end
323
395
 
324
396
  # Checks whether the connection to the database is still active (i.e. not stale).
325
- # This is done under the hood by calling <tt>active?</tt>. If the connection
397
+ # This is done under the hood by calling #active?. If the connection
326
398
  # is no longer active, then this method will reconnect to the database.
327
399
  def verify!(*ignored)
328
400
  reconnect! unless active?
329
401
  end
330
402
 
331
403
  # Provides access to the underlying database driver for this adapter. For
332
- # example, this method returns a Mysql object in case of MysqlAdapter,
404
+ # example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
333
405
  # and a PGconn object in case of PostgreSQLAdapter.
334
406
  #
335
407
  # This is useful for when you need to call a proprietary method such as
@@ -338,32 +410,26 @@ module ActiveRecord
338
410
  @connection
339
411
  end
340
412
 
341
- def create_savepoint(name = nil)
342
- end
343
-
344
- def rollback_to_savepoint(name = nil)
345
- end
346
-
347
- def release_savepoint(name = nil)
348
- end
349
-
350
- def case_sensitive_modifier(node, table_attribute)
351
- node
352
- end
353
-
354
413
  def case_sensitive_comparison(table, attribute, column, value)
355
- table_attr = table[attribute]
356
- value = case_sensitive_modifier(value, table_attr) unless value.nil?
357
- table_attr.eq(value)
414
+ if value.nil?
415
+ table[attribute].eq(value)
416
+ else
417
+ table[attribute].eq(Arel::Nodes::BindParam.new)
418
+ end
358
419
  end
359
420
 
360
421
  def case_insensitive_comparison(table, attribute, column, value)
361
- table[attribute].lower.eq(table.lower(value))
422
+ if can_perform_case_insensitive_comparison_for?(column)
423
+ table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
424
+ else
425
+ table[attribute].eq(Arel::Nodes::BindParam.new)
426
+ end
362
427
  end
363
428
 
364
- def current_savepoint_name
365
- current_transaction.savepoint_name
429
+ def can_perform_case_insensitive_comparison_for?(column)
430
+ true
366
431
  end
432
+ private :can_perform_case_insensitive_comparison_for?
367
433
 
368
434
  # Check the connection back in to the connection pool
369
435
  def close
@@ -376,8 +442,8 @@ module ActiveRecord
376
442
  end
377
443
  end
378
444
 
379
- def new_column(name, default, cast_type, sql_type = nil, null = true)
380
- Column.new(name, default, cast_type, sql_type, null)
445
+ def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
446
+ Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
381
447
  end
382
448
 
383
449
  def lookup_cast_type(sql_type) # :nodoc:
@@ -385,21 +451,39 @@ module ActiveRecord
385
451
  end
386
452
 
387
453
  def column_name_for_operation(operation, node) # :nodoc:
388
- node.to_sql
454
+ visitor.accept(node, collector).value
455
+ end
456
+
457
+ def combine_bind_parameters(
458
+ from_clause: [],
459
+ join_clause: [],
460
+ where_clause: [],
461
+ having_clause: [],
462
+ limit: nil,
463
+ offset: nil
464
+ ) # :nodoc:
465
+ result = from_clause + join_clause + where_clause + having_clause
466
+ if limit
467
+ result << limit
468
+ end
469
+ if offset
470
+ result << offset
471
+ end
472
+ result
389
473
  end
390
474
 
391
475
  protected
392
476
 
393
477
  def initialize_type_map(m) # :nodoc:
394
- register_class_with_limit m, %r(boolean)i, Type::Boolean
395
- register_class_with_limit m, %r(char)i, Type::String
396
- register_class_with_limit m, %r(binary)i, Type::Binary
397
- register_class_with_limit m, %r(text)i, Type::Text
398
- register_class_with_limit m, %r(date)i, Type::Date
399
- register_class_with_limit m, %r(time)i, Type::Time
400
- register_class_with_limit m, %r(datetime)i, Type::DateTime
401
- register_class_with_limit m, %r(float)i, Type::Float
402
- register_class_with_limit m, %r(int)i, Type::Integer
478
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
479
+ register_class_with_limit m, %r(char)i, Type::String
480
+ register_class_with_limit m, %r(binary)i, Type::Binary
481
+ register_class_with_limit m, %r(text)i, Type::Text
482
+ register_class_with_precision m, %r(date)i, Type::Date
483
+ register_class_with_precision m, %r(time)i, Type::Time
484
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
485
+ register_class_with_limit m, %r(float)i, Type::Float
486
+ register_class_with_limit m, %r(int)i, Type::Integer
403
487
 
404
488
  m.alias_type %r(blob)i, 'binary'
405
489
  m.alias_type %r(clob)i, 'text'
@@ -433,6 +517,13 @@ module ActiveRecord
433
517
  end
434
518
  end
435
519
 
520
+ def register_class_with_precision(mapping, key, klass) # :nodoc:
521
+ mapping.register_type(key) do |*args|
522
+ precision = extract_precision(args.last)
523
+ klass.new(precision: precision)
524
+ end
525
+ end
526
+
436
527
  def extract_scale(sql_type) # :nodoc:
437
528
  case sql_type
438
529
  when /\((\d+)\)/ then 0
@@ -445,12 +536,21 @@ module ActiveRecord
445
536
  end
446
537
 
447
538
  def extract_limit(sql_type) # :nodoc:
448
- $1.to_i if sql_type =~ /\((.*)\)/
539
+ case sql_type
540
+ when /^bigint/i
541
+ 8
542
+ when /\((.*)\)/
543
+ $1.to_i
544
+ end
449
545
  end
450
546
 
451
547
  def translate_exception_class(e, sql)
452
- message = "#{e.class.name}: #{e.message}: #{sql}"
453
- @logger.error message if @logger
548
+ begin
549
+ message = "#{e.class.name}: #{e.message}: #{sql}"
550
+ rescue Encoding::CompatibilityError
551
+ message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
552
+ end
553
+
454
554
  exception = translate_exception(e, message)
455
555
  exception.set_backtrace e.backtrace
456
556
  exception
@@ -470,7 +570,7 @@ module ActiveRecord
470
570
 
471
571
  def translate_exception(exception, message)
472
572
  # override in derived class
473
- ActiveRecord::StatementInvalid.new(message, exception)
573
+ ActiveRecord::StatementInvalid.new(message)
474
574
  end
475
575
 
476
576
  def without_prepared_statement?(binds)