activerecord 5.2.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +937 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +217 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +188 -0
  8. data/lib/active_record/aggregations.rb +283 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1860 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +299 -0
  13. data/lib/active_record/associations/association_scope.rb +168 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +130 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +140 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +163 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +82 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +135 -0
  20. data/lib/active_record/associations/builder/has_many.rb +17 -0
  21. data/lib/active_record/associations/builder/has_one.rb +30 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +42 -0
  23. data/lib/active_record/associations/collection_association.rb +513 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1131 -0
  25. data/lib/active_record/associations/foreign_association.rb +13 -0
  26. data/lib/active_record/associations/has_many_association.rb +144 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +227 -0
  28. data/lib/active_record/associations/has_one_association.rb +120 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +262 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +60 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +193 -0
  35. data/lib/active_record/associations/preloader/association.rb +131 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +107 -0
  37. data/lib/active_record/associations/singular_association.rb +73 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +88 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +492 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +78 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +150 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +143 -0
  45. data/lib/active_record/attribute_methods/query.rb +42 -0
  46. data/lib/active_record/attribute_methods/read.rb +85 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +68 -0
  50. data/lib/active_record/attributes.rb +266 -0
  51. data/lib/active_record/autosave_association.rb +498 -0
  52. data/lib/active_record/base.rb +329 -0
  53. data/lib/active_record/callbacks.rb +353 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/collection_cache_key.rb +53 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1068 -0
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +72 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +540 -0
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +145 -0
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +200 -0
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +685 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1396 -0
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +628 -0
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +887 -0
  70. data/lib/active_record/connection_adapters/column.rb +91 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  73. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +863 -0
  118. data/lib/active_record/connection_adapters/schema_cache.rb +118 -0
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +573 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +145 -0
  129. data/lib/active_record/core.rb +559 -0
  130. data/lib/active_record/counter_cache.rb +218 -0
  131. data/lib/active_record/define_callbacks.rb +22 -0
  132. data/lib/active_record/dynamic_matchers.rb +122 -0
  133. data/lib/active_record/enum.rb +244 -0
  134. data/lib/active_record/errors.rb +380 -0
  135. data/lib/active_record/explain.rb +50 -0
  136. data/lib/active_record/explain_registry.rb +32 -0
  137. data/lib/active_record/explain_subscriber.rb +34 -0
  138. data/lib/active_record/fixture_set/file.rb +82 -0
  139. data/lib/active_record/fixtures.rb +1065 -0
  140. data/lib/active_record/gem_version.rb +17 -0
  141. data/lib/active_record/inheritance.rb +283 -0
  142. data/lib/active_record/integration.rb +155 -0
  143. data/lib/active_record/internal_metadata.rb +45 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  145. data/lib/active_record/locale/en.yml +48 -0
  146. data/lib/active_record/locking/optimistic.rb +198 -0
  147. data/lib/active_record/locking/pessimistic.rb +89 -0
  148. data/lib/active_record/log_subscriber.rb +137 -0
  149. data/lib/active_record/migration.rb +1378 -0
  150. data/lib/active_record/migration/command_recorder.rb +240 -0
  151. data/lib/active_record/migration/compatibility.rb +217 -0
  152. data/lib/active_record/migration/join_table.rb +17 -0
  153. data/lib/active_record/model_schema.rb +521 -0
  154. data/lib/active_record/nested_attributes.rb +600 -0
  155. data/lib/active_record/no_touching.rb +58 -0
  156. data/lib/active_record/null_relation.rb +68 -0
  157. data/lib/active_record/persistence.rb +763 -0
  158. data/lib/active_record/query_cache.rb +45 -0
  159. data/lib/active_record/querying.rb +70 -0
  160. data/lib/active_record/railtie.rb +226 -0
  161. data/lib/active_record/railties/console_sandbox.rb +7 -0
  162. data/lib/active_record/railties/controller_runtime.rb +56 -0
  163. data/lib/active_record/railties/databases.rake +377 -0
  164. data/lib/active_record/readonly_attributes.rb +24 -0
  165. data/lib/active_record/reflection.rb +1044 -0
  166. data/lib/active_record/relation.rb +629 -0
  167. data/lib/active_record/relation/batches.rb +287 -0
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  169. data/lib/active_record/relation/calculations.rb +417 -0
  170. data/lib/active_record/relation/delegation.rb +147 -0
  171. data/lib/active_record/relation/finder_methods.rb +565 -0
  172. data/lib/active_record/relation/from_clause.rb +26 -0
  173. data/lib/active_record/relation/merger.rb +193 -0
  174. data/lib/active_record/relation/predicate_builder.rb +152 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  182. data/lib/active_record/relation/query_attribute.rb +45 -0
  183. data/lib/active_record/relation/query_methods.rb +1231 -0
  184. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  185. data/lib/active_record/relation/spawn_methods.rb +77 -0
  186. data/lib/active_record/relation/where_clause.rb +186 -0
  187. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  188. data/lib/active_record/result.rb +149 -0
  189. data/lib/active_record/runtime_registry.rb +24 -0
  190. data/lib/active_record/sanitization.rb +222 -0
  191. data/lib/active_record/schema.rb +70 -0
  192. data/lib/active_record/schema_dumper.rb +255 -0
  193. data/lib/active_record/schema_migration.rb +56 -0
  194. data/lib/active_record/scoping.rb +106 -0
  195. data/lib/active_record/scoping/default.rb +152 -0
  196. data/lib/active_record/scoping/named.rb +213 -0
  197. data/lib/active_record/secure_token.rb +40 -0
  198. data/lib/active_record/serialization.rb +22 -0
  199. data/lib/active_record/statement_cache.rb +121 -0
  200. data/lib/active_record/store.rb +211 -0
  201. data/lib/active_record/suppressor.rb +61 -0
  202. data/lib/active_record/table_metadata.rb +82 -0
  203. data/lib/active_record/tasks/database_tasks.rb +337 -0
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  207. data/lib/active_record/timestamp.rb +153 -0
  208. data/lib/active_record/touch_later.rb +64 -0
  209. data/lib/active_record/transactions.rb +502 -0
  210. data/lib/active_record/translation.rb +24 -0
  211. data/lib/active_record/type.rb +79 -0
  212. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  213. data/lib/active_record/type/date.rb +9 -0
  214. data/lib/active_record/type/date_time.rb +9 -0
  215. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  217. data/lib/active_record/type/internal/timezone.rb +17 -0
  218. data/lib/active_record/type/json.rb +30 -0
  219. data/lib/active_record/type/serialized.rb +71 -0
  220. data/lib/active_record/type/text.rb +11 -0
  221. data/lib/active_record/type/time.rb +21 -0
  222. data/lib/active_record/type/type_map.rb +62 -0
  223. data/lib/active_record/type/unsigned_integer.rb +17 -0
  224. data/lib/active_record/type_caster.rb +9 -0
  225. data/lib/active_record/type_caster/connection.rb +33 -0
  226. data/lib/active_record/type_caster/map.rb +23 -0
  227. data/lib/active_record/validations.rb +93 -0
  228. data/lib/active_record/validations/absence.rb +25 -0
  229. data/lib/active_record/validations/associated.rb +60 -0
  230. data/lib/active_record/validations/length.rb +26 -0
  231. data/lib/active_record/validations/presence.rb +68 -0
  232. data/lib/active_record/validations/uniqueness.rb +238 -0
  233. data/lib/active_record/version.rb +10 -0
  234. data/lib/rails/generators/active_record.rb +19 -0
  235. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  236. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  237. data/lib/rails/generators/active_record/migration.rb +35 -0
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +78 -0
  239. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  240. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  241. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  242. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  243. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  244. metadata +333 -0
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class TransactionState
6
+ def initialize(state = nil)
7
+ @state = state
8
+ @children = []
9
+ end
10
+
11
+ def add_child(state)
12
+ @children << state
13
+ end
14
+
15
+ def finalized?
16
+ @state
17
+ end
18
+
19
+ def committed?
20
+ @state == :committed || @state == :fully_committed
21
+ end
22
+
23
+ def fully_committed?
24
+ @state == :fully_committed
25
+ end
26
+
27
+ def rolledback?
28
+ @state == :rolledback || @state == :fully_rolledback
29
+ end
30
+
31
+ def fully_rolledback?
32
+ @state == :fully_rolledback
33
+ end
34
+
35
+ def fully_completed?
36
+ completed?
37
+ end
38
+
39
+ def completed?
40
+ committed? || rolledback?
41
+ end
42
+
43
+ def set_state(state)
44
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
45
+ The set_state method is deprecated and will be removed in
46
+ Rails 6.0. Please use rollback! or commit! to set transaction
47
+ state directly.
48
+ MSG
49
+ case state
50
+ when :rolledback
51
+ rollback!
52
+ when :committed
53
+ commit!
54
+ when nil
55
+ nullify!
56
+ else
57
+ raise ArgumentError, "Invalid transaction state: #{state}"
58
+ end
59
+ end
60
+
61
+ def rollback!
62
+ @children.each { |c| c.rollback! }
63
+ @state = :rolledback
64
+ end
65
+
66
+ def full_rollback!
67
+ @children.each { |c| c.rollback! }
68
+ @state = :fully_rolledback
69
+ end
70
+
71
+ def commit!
72
+ @state = :committed
73
+ end
74
+
75
+ def full_commit!
76
+ @state = :fully_committed
77
+ end
78
+
79
+ def nullify!
80
+ @state = nil
81
+ end
82
+ end
83
+
84
+ class NullTransaction #:nodoc:
85
+ def initialize; end
86
+ def state; end
87
+ def closed?; true; end
88
+ def open?; false; end
89
+ def joinable?; false; end
90
+ def add_record(record); end
91
+ end
92
+
93
+ class Transaction #:nodoc:
94
+ attr_reader :connection, :state, :records, :savepoint_name
95
+ attr_writer :joinable
96
+
97
+ def initialize(connection, options, run_commit_callbacks: false)
98
+ @connection = connection
99
+ @state = TransactionState.new
100
+ @records = []
101
+ @joinable = options.fetch(:joinable, true)
102
+ @run_commit_callbacks = run_commit_callbacks
103
+ end
104
+
105
+ def add_record(record)
106
+ records << record
107
+ end
108
+
109
+ def rollback_records
110
+ ite = records.uniq
111
+ while record = ite.shift
112
+ record.rolledback!(force_restore_state: full_rollback?)
113
+ end
114
+ ensure
115
+ ite.each do |i|
116
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
117
+ end
118
+ end
119
+
120
+ def before_commit_records
121
+ records.uniq.each(&:before_committed!) if @run_commit_callbacks
122
+ end
123
+
124
+ def commit_records
125
+ ite = records.uniq
126
+ while record = ite.shift
127
+ if @run_commit_callbacks
128
+ record.committed!
129
+ else
130
+ # if not running callbacks, only adds the record to the parent transaction
131
+ record.add_to_transaction
132
+ end
133
+ end
134
+ ensure
135
+ ite.each { |i| i.committed!(should_run_callbacks: false) }
136
+ end
137
+
138
+ def full_rollback?; true; end
139
+ def joinable?; @joinable; end
140
+ def closed?; false; end
141
+ def open?; !closed?; end
142
+ end
143
+
144
+ class SavepointTransaction < Transaction
145
+ def initialize(connection, savepoint_name, parent_transaction, options, *args)
146
+ super(connection, options, *args)
147
+
148
+ parent_transaction.state.add_child(@state)
149
+
150
+ if options[:isolation]
151
+ raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
152
+ end
153
+ connection.create_savepoint(@savepoint_name = savepoint_name)
154
+ end
155
+
156
+ def rollback
157
+ connection.rollback_to_savepoint(savepoint_name)
158
+ @state.rollback!
159
+ end
160
+
161
+ def commit
162
+ connection.release_savepoint(savepoint_name)
163
+ @state.commit!
164
+ end
165
+
166
+ def full_rollback?; false; end
167
+ end
168
+
169
+ class RealTransaction < Transaction
170
+ def initialize(connection, options, *args)
171
+ super
172
+ if options[:isolation]
173
+ connection.begin_isolated_db_transaction(options[:isolation])
174
+ else
175
+ connection.begin_db_transaction
176
+ end
177
+ end
178
+
179
+ def rollback
180
+ connection.rollback_db_transaction
181
+ @state.full_rollback!
182
+ end
183
+
184
+ def commit
185
+ connection.commit_db_transaction
186
+ @state.full_commit!
187
+ end
188
+ end
189
+
190
+ class TransactionManager #:nodoc:
191
+ def initialize(connection)
192
+ @stack = []
193
+ @connection = connection
194
+ end
195
+
196
+ def begin_transaction(options = {})
197
+ @connection.lock.synchronize do
198
+ run_commit_callbacks = !current_transaction.joinable?
199
+ transaction =
200
+ if @stack.empty?
201
+ RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
202
+ else
203
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
204
+ run_commit_callbacks: run_commit_callbacks)
205
+ end
206
+
207
+ @stack.push(transaction)
208
+ transaction
209
+ end
210
+ end
211
+
212
+ def commit_transaction
213
+ @connection.lock.synchronize do
214
+ transaction = @stack.last
215
+
216
+ begin
217
+ transaction.before_commit_records
218
+ ensure
219
+ @stack.pop
220
+ end
221
+
222
+ transaction.commit
223
+ transaction.commit_records
224
+ end
225
+ end
226
+
227
+ def rollback_transaction(transaction = nil)
228
+ @connection.lock.synchronize do
229
+ transaction ||= @stack.pop
230
+ transaction.rollback
231
+ transaction.rollback_records
232
+ end
233
+ end
234
+
235
+ def within_new_transaction(options = {})
236
+ @connection.lock.synchronize do
237
+ begin
238
+ transaction = begin_transaction options
239
+ yield
240
+ rescue Exception => error
241
+ if transaction
242
+ rollback_transaction
243
+ after_failure_actions(transaction, error)
244
+ end
245
+ raise
246
+ ensure
247
+ unless error
248
+ if Thread.current.status == "aborting"
249
+ rollback_transaction if transaction
250
+ else
251
+ begin
252
+ commit_transaction if transaction
253
+ rescue Exception
254
+ rollback_transaction(transaction) unless transaction.state.completed?
255
+ raise
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ def open_transactions
264
+ @stack.size
265
+ end
266
+
267
+ def current_transaction
268
+ @stack.last || NULL_TRANSACTION
269
+ end
270
+
271
+ private
272
+
273
+ NULL_TRANSACTION = NullTransaction.new
274
+
275
+ # Deallocate invalidated prepared statements outside of the transaction
276
+ def after_failure_actions(transaction, error)
277
+ return unless transaction.is_a?(RealTransaction)
278
+ return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
279
+ @connection.clear_cache!
280
+ end
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,628 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/connection_adapters/determine_if_preparable_visitor"
4
+ require "active_record/connection_adapters/schema_cache"
5
+ require "active_record/connection_adapters/sql_type_metadata"
6
+ require "active_record/connection_adapters/abstract/schema_dumper"
7
+ require "active_record/connection_adapters/abstract/schema_creation"
8
+ require "active_support/concurrency/load_interlock_aware_monitor"
9
+ require "arel/collectors/bind"
10
+ require "arel/collectors/composite"
11
+ require "arel/collectors/sql_string"
12
+ require "arel/collectors/substitute_binds"
13
+
14
+ module ActiveRecord
15
+ module ConnectionAdapters # :nodoc:
16
+ extend ActiveSupport::Autoload
17
+
18
+ autoload :Column
19
+ autoload :ConnectionSpecification
20
+
21
+ autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
22
+ autoload :IndexDefinition
23
+ autoload :ColumnDefinition
24
+ autoload :ChangeColumnDefinition
25
+ autoload :ForeignKeyDefinition
26
+ autoload :TableDefinition
27
+ autoload :Table
28
+ autoload :AlterTable
29
+ autoload :ReferenceDefinition
30
+ end
31
+
32
+ autoload_at "active_record/connection_adapters/abstract/connection_pool" do
33
+ autoload :ConnectionHandler
34
+ end
35
+
36
+ autoload_under "abstract" do
37
+ autoload :SchemaStatements
38
+ autoload :DatabaseStatements
39
+ autoload :DatabaseLimits
40
+ autoload :Quoting
41
+ autoload :ConnectionPool
42
+ autoload :QueryCache
43
+ autoload :Savepoints
44
+ end
45
+
46
+ autoload_at "active_record/connection_adapters/abstract/transaction" do
47
+ autoload :TransactionManager
48
+ autoload :NullTransaction
49
+ autoload :RealTransaction
50
+ autoload :SavepointTransaction
51
+ autoload :TransactionState
52
+ end
53
+
54
+ # Active Record supports multiple database systems. AbstractAdapter and
55
+ # related classes form the abstraction layer which makes this possible.
56
+ # An AbstractAdapter represents a connection to a database, and provides an
57
+ # abstract interface for database-specific functionality such as establishing
58
+ # a connection, escaping values, building the right SQL fragments for +:offset+
59
+ # and +:limit+ options, etc.
60
+ #
61
+ # All the concrete database adapters follow the interface laid down in this class.
62
+ # {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
63
+ # you can use.
64
+ #
65
+ # Most of the methods in the adapter are useful during migrations. Most
66
+ # notably, the instance methods provided by SchemaStatements are very useful.
67
+ class AbstractAdapter
68
+ ADAPTER_NAME = "Abstract".freeze
69
+ include ActiveSupport::Callbacks
70
+ define_callbacks :checkout, :checkin
71
+
72
+ include Quoting, DatabaseStatements, SchemaStatements
73
+ include DatabaseLimits
74
+ include QueryCache
75
+ include Savepoints
76
+
77
+ SIMPLE_INT = /\A\d+\z/
78
+
79
+ attr_accessor :visitor, :pool
80
+ attr_reader :schema_cache, :owner, :logger, :prepared_statements, :lock
81
+ alias :in_use? :owner
82
+
83
+ def self.type_cast_config_to_integer(config)
84
+ if config.is_a?(Integer)
85
+ config
86
+ elsif config =~ SIMPLE_INT
87
+ config.to_i
88
+ else
89
+ config
90
+ end
91
+ end
92
+
93
+ def self.type_cast_config_to_boolean(config)
94
+ if config == "false"
95
+ false
96
+ else
97
+ config
98
+ end
99
+ end
100
+
101
+ def initialize(connection, logger = nil, config = {}) # :nodoc:
102
+ super()
103
+
104
+ @connection = connection
105
+ @owner = nil
106
+ @instrumenter = ActiveSupport::Notifications.instrumenter
107
+ @logger = logger
108
+ @config = config
109
+ @pool = nil
110
+ @idle_since = Concurrent.monotonic_time
111
+ @schema_cache = SchemaCache.new self
112
+ @quoted_column_names, @quoted_table_names = {}, {}
113
+ @visitor = arel_visitor
114
+ @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
115
+
116
+ if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
117
+ @prepared_statements = true
118
+ @visitor.extend(DetermineIfPreparableVisitor)
119
+ else
120
+ @prepared_statements = false
121
+ end
122
+ end
123
+
124
+ def migrations_paths # :nodoc:
125
+ @config[:migrations_paths] || Migrator.migrations_paths
126
+ end
127
+
128
+ def migration_context # :nodoc:
129
+ MigrationContext.new(migrations_paths)
130
+ end
131
+
132
+ class Version
133
+ include Comparable
134
+
135
+ def initialize(version_string)
136
+ @version = version_string.split(".").map(&:to_i)
137
+ end
138
+
139
+ def <=>(version_string)
140
+ @version <=> version_string.split(".").map(&:to_i)
141
+ end
142
+ end
143
+
144
+ def valid_type?(type) # :nodoc:
145
+ !native_database_types[type].nil?
146
+ end
147
+
148
+ # this method must only be called while holding connection pool's mutex
149
+ def lease
150
+ if in_use?
151
+ msg = "Cannot lease connection, ".dup
152
+ if @owner == Thread.current
153
+ msg << "it is already leased by the current thread."
154
+ else
155
+ msg << "it is already in use by a different thread: #{@owner}. " \
156
+ "Current thread: #{Thread.current}."
157
+ end
158
+ raise ActiveRecordError, msg
159
+ end
160
+
161
+ @owner = Thread.current
162
+ end
163
+
164
+ def schema_cache=(cache)
165
+ cache.connection = self
166
+ @schema_cache = cache
167
+ end
168
+
169
+ # this method must only be called while holding connection pool's mutex
170
+ def expire
171
+ if in_use?
172
+ if @owner != Thread.current
173
+ raise ActiveRecordError, "Cannot expire connection, " \
174
+ "it is owned by a different thread: #{@owner}. " \
175
+ "Current thread: #{Thread.current}."
176
+ end
177
+
178
+ @idle_since = Concurrent.monotonic_time
179
+ @owner = nil
180
+ else
181
+ raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
182
+ end
183
+ end
184
+
185
+ # this method must only be called while holding connection pool's mutex (and a desire for segfaults)
186
+ def steal! # :nodoc:
187
+ if in_use?
188
+ if @owner != Thread.current
189
+ pool.send :remove_connection_from_thread_cache, self, @owner
190
+
191
+ @owner = Thread.current
192
+ end
193
+ else
194
+ raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
195
+ end
196
+ end
197
+
198
+ # Seconds since this connection was returned to the pool
199
+ def seconds_idle # :nodoc:
200
+ return 0 if in_use?
201
+ Concurrent.monotonic_time - @idle_since
202
+ end
203
+
204
+ def unprepared_statement
205
+ old_prepared_statements, @prepared_statements = @prepared_statements, false
206
+ yield
207
+ ensure
208
+ @prepared_statements = old_prepared_statements
209
+ end
210
+
211
+ # Returns the human-readable name of the adapter. Use mixed case - one
212
+ # can always use downcase if needed.
213
+ def adapter_name
214
+ self.class::ADAPTER_NAME
215
+ end
216
+
217
+ # Does this adapter support DDL rollbacks in transactions? That is, would
218
+ # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
219
+ def supports_ddl_transactions?
220
+ false
221
+ end
222
+
223
+ def supports_bulk_alter?
224
+ false
225
+ end
226
+
227
+ # Does this adapter support savepoints?
228
+ def supports_savepoints?
229
+ false
230
+ end
231
+
232
+ # Does this adapter support application-enforced advisory locking?
233
+ def supports_advisory_locks?
234
+ false
235
+ end
236
+
237
+ # Should primary key values be selected from their corresponding
238
+ # sequence before the insert statement? If true, next_sequence_value
239
+ # is called before each insert to set the record's primary key.
240
+ def prefetch_primary_key?(table_name = nil)
241
+ false
242
+ end
243
+
244
+ # Does this adapter support index sort order?
245
+ def supports_index_sort_order?
246
+ false
247
+ end
248
+
249
+ # Does this adapter support partial indices?
250
+ def supports_partial_index?
251
+ false
252
+ end
253
+
254
+ # Does this adapter support expression indices?
255
+ def supports_expression_index?
256
+ false
257
+ end
258
+
259
+ # Does this adapter support explain?
260
+ def supports_explain?
261
+ false
262
+ end
263
+
264
+ # Does this adapter support setting the isolation level for a transaction?
265
+ def supports_transaction_isolation?
266
+ false
267
+ end
268
+
269
+ # Does this adapter support database extensions?
270
+ def supports_extensions?
271
+ false
272
+ end
273
+
274
+ # Does this adapter support creating indexes in the same statement as
275
+ # creating the table?
276
+ def supports_indexes_in_create?
277
+ false
278
+ end
279
+
280
+ # Does this adapter support creating foreign key constraints?
281
+ def supports_foreign_keys?
282
+ false
283
+ end
284
+
285
+ # Does this adapter support creating invalid constraints?
286
+ def supports_validate_constraints?
287
+ false
288
+ end
289
+
290
+ # Does this adapter support creating foreign key constraints
291
+ # in the same statement as creating the table?
292
+ def supports_foreign_keys_in_create?
293
+ supports_foreign_keys?
294
+ end
295
+
296
+ # Does this adapter support views?
297
+ def supports_views?
298
+ false
299
+ end
300
+
301
+ # Does this adapter support datetime with precision?
302
+ def supports_datetime_with_precision?
303
+ false
304
+ end
305
+
306
+ # Does this adapter support json data type?
307
+ def supports_json?
308
+ false
309
+ end
310
+
311
+ # Does this adapter support metadata comments on database objects (tables, columns, indexes)?
312
+ def supports_comments?
313
+ false
314
+ end
315
+
316
+ # Can comments for tables, columns, and indexes be specified in create/alter table statements?
317
+ def supports_comments_in_create?
318
+ false
319
+ end
320
+
321
+ # Does this adapter support multi-value insert?
322
+ def supports_multi_insert?
323
+ true
324
+ end
325
+
326
+ # Does this adapter support virtual columns?
327
+ def supports_virtual_columns?
328
+ false
329
+ end
330
+
331
+ # Does this adapter support foreign/external tables?
332
+ def supports_foreign_tables?
333
+ false
334
+ end
335
+
336
+ # This is meant to be implemented by the adapters that support extensions
337
+ def disable_extension(name)
338
+ end
339
+
340
+ # This is meant to be implemented by the adapters that support extensions
341
+ def enable_extension(name)
342
+ end
343
+
344
+ # This is meant to be implemented by the adapters that support advisory
345
+ # locks
346
+ #
347
+ # Return true if we got the lock, otherwise false
348
+ def get_advisory_lock(lock_id) # :nodoc:
349
+ end
350
+
351
+ # This is meant to be implemented by the adapters that support advisory
352
+ # locks.
353
+ #
354
+ # Return true if we released the lock, otherwise false
355
+ def release_advisory_lock(lock_id) # :nodoc:
356
+ end
357
+
358
+ # A list of extensions, to be filled in by adapters that support them.
359
+ def extensions
360
+ []
361
+ end
362
+
363
+ # A list of index algorithms, to be filled by adapters that support them.
364
+ def index_algorithms
365
+ {}
366
+ end
367
+
368
+ # REFERENTIAL INTEGRITY ====================================
369
+
370
+ # Override to turn off referential integrity while executing <tt>&block</tt>.
371
+ def disable_referential_integrity
372
+ yield
373
+ end
374
+
375
+ # CONNECTION MANAGEMENT ====================================
376
+
377
+ # Checks whether the connection to the database is still active. This includes
378
+ # checking whether the database is actually capable of responding, i.e. whether
379
+ # the connection isn't stale.
380
+ def active?
381
+ end
382
+
383
+ # Disconnects from the database if already connected, and establishes a
384
+ # new connection with the database. Implementors should call super if they
385
+ # override the default implementation.
386
+ def reconnect!
387
+ clear_cache!
388
+ reset_transaction
389
+ end
390
+
391
+ # Disconnects from the database if already connected. Otherwise, this
392
+ # method does nothing.
393
+ def disconnect!
394
+ clear_cache!
395
+ reset_transaction
396
+ end
397
+
398
+ # Immediately forget this connection ever existed. Unlike disconnect!,
399
+ # this will not communicate with the server.
400
+ #
401
+ # After calling this method, the behavior of all other methods becomes
402
+ # undefined. This is called internally just before a forked process gets
403
+ # rid of a connection that belonged to its parent.
404
+ def discard!
405
+ # This should be overridden by concrete adapters.
406
+ #
407
+ # Prevent @connection's finalizer from touching the socket, or
408
+ # otherwise communicating with its server, when it is collected.
409
+ end
410
+
411
+ # Reset the state of this connection, directing the DBMS to clear
412
+ # transactions and other connection-related server-side state. Usually a
413
+ # database-dependent operation.
414
+ #
415
+ # The default implementation does nothing; the implementation should be
416
+ # overridden by concrete adapters.
417
+ def reset!
418
+ # this should be overridden by concrete adapters
419
+ end
420
+
421
+ ###
422
+ # Clear any caching the database adapter may be doing, for example
423
+ # clearing the prepared statement cache. This is database specific.
424
+ def clear_cache!
425
+ # this should be overridden by concrete adapters
426
+ end
427
+
428
+ # Returns true if its required to reload the connection between requests for development mode.
429
+ def requires_reloading?
430
+ false
431
+ end
432
+
433
+ # Checks whether the connection to the database is still active (i.e. not stale).
434
+ # This is done under the hood by calling #active?. If the connection
435
+ # is no longer active, then this method will reconnect to the database.
436
+ def verify!
437
+ reconnect! unless active?
438
+ end
439
+
440
+ # Provides access to the underlying database driver for this adapter. For
441
+ # example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
442
+ # and a PG::Connection object in case of PostgreSQLAdapter.
443
+ #
444
+ # This is useful for when you need to call a proprietary method such as
445
+ # PostgreSQL's lo_* methods.
446
+ def raw_connection
447
+ @connection
448
+ end
449
+
450
+ def case_sensitive_comparison(table, attribute, column, value) # :nodoc:
451
+ table[attribute].eq(value)
452
+ end
453
+
454
+ def case_insensitive_comparison(table, attribute, column, value) # :nodoc:
455
+ if can_perform_case_insensitive_comparison_for?(column)
456
+ table[attribute].lower.eq(table.lower(value))
457
+ else
458
+ table[attribute].eq(value)
459
+ end
460
+ end
461
+
462
+ def can_perform_case_insensitive_comparison_for?(column)
463
+ true
464
+ end
465
+ private :can_perform_case_insensitive_comparison_for?
466
+
467
+ # Check the connection back in to the connection pool
468
+ def close
469
+ pool.checkin self
470
+ end
471
+
472
+ def column_name_for_operation(operation, node) # :nodoc:
473
+ column_name_from_arel_node(node)
474
+ end
475
+
476
+ def column_name_from_arel_node(node) # :nodoc:
477
+ visitor.accept(node, Arel::Collectors::SQLString.new).value
478
+ end
479
+
480
+ def default_index_type?(index) # :nodoc:
481
+ index.using.nil?
482
+ end
483
+
484
+ private
485
+ def type_map
486
+ @type_map ||= Type::TypeMap.new.tap do |mapping|
487
+ initialize_type_map(mapping)
488
+ end
489
+ end
490
+
491
+ def initialize_type_map(m = type_map)
492
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
493
+ register_class_with_limit m, %r(char)i, Type::String
494
+ register_class_with_limit m, %r(binary)i, Type::Binary
495
+ register_class_with_limit m, %r(text)i, Type::Text
496
+ register_class_with_precision m, %r(date)i, Type::Date
497
+ register_class_with_precision m, %r(time)i, Type::Time
498
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
499
+ register_class_with_limit m, %r(float)i, Type::Float
500
+ register_class_with_limit m, %r(int)i, Type::Integer
501
+
502
+ m.alias_type %r(blob)i, "binary"
503
+ m.alias_type %r(clob)i, "text"
504
+ m.alias_type %r(timestamp)i, "datetime"
505
+ m.alias_type %r(numeric)i, "decimal"
506
+ m.alias_type %r(number)i, "decimal"
507
+ m.alias_type %r(double)i, "float"
508
+
509
+ m.register_type %r(^json)i, Type::Json.new
510
+
511
+ m.register_type(%r(decimal)i) do |sql_type|
512
+ scale = extract_scale(sql_type)
513
+ precision = extract_precision(sql_type)
514
+
515
+ if scale == 0
516
+ # FIXME: Remove this class as well
517
+ Type::DecimalWithoutScale.new(precision: precision)
518
+ else
519
+ Type::Decimal.new(precision: precision, scale: scale)
520
+ end
521
+ end
522
+ end
523
+
524
+ def reload_type_map
525
+ type_map.clear
526
+ initialize_type_map
527
+ end
528
+
529
+ def register_class_with_limit(mapping, key, klass)
530
+ mapping.register_type(key) do |*args|
531
+ limit = extract_limit(args.last)
532
+ klass.new(limit: limit)
533
+ end
534
+ end
535
+
536
+ def register_class_with_precision(mapping, key, klass)
537
+ mapping.register_type(key) do |*args|
538
+ precision = extract_precision(args.last)
539
+ klass.new(precision: precision)
540
+ end
541
+ end
542
+
543
+ def extract_scale(sql_type)
544
+ case sql_type
545
+ when /\((\d+)\)/ then 0
546
+ when /\((\d+)(,(\d+))\)/ then $3.to_i
547
+ end
548
+ end
549
+
550
+ def extract_precision(sql_type)
551
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
552
+ end
553
+
554
+ def extract_limit(sql_type)
555
+ $1.to_i if sql_type =~ /\((.*)\)/
556
+ end
557
+
558
+ def translate_exception_class(e, sql)
559
+ begin
560
+ message = "#{e.class.name}: #{e.message}: #{sql}"
561
+ rescue Encoding::CompatibilityError
562
+ message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
563
+ end
564
+
565
+ exception = translate_exception(e, message)
566
+ exception.set_backtrace e.backtrace
567
+ exception
568
+ end
569
+
570
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
571
+ @instrumenter.instrument(
572
+ "sql.active_record",
573
+ sql: sql,
574
+ name: name,
575
+ binds: binds,
576
+ type_casted_binds: type_casted_binds,
577
+ statement_name: statement_name,
578
+ connection_id: object_id) do
579
+ begin
580
+ @lock.synchronize do
581
+ yield
582
+ end
583
+ rescue => e
584
+ raise translate_exception_class(e, sql)
585
+ end
586
+ end
587
+ end
588
+
589
+ def translate_exception(exception, message)
590
+ # override in derived class
591
+ case exception
592
+ when RuntimeError
593
+ exception
594
+ else
595
+ ActiveRecord::StatementInvalid.new(message)
596
+ end
597
+ end
598
+
599
+ def without_prepared_statement?(binds)
600
+ !prepared_statements || binds.empty?
601
+ end
602
+
603
+ def column_for(table_name, column_name)
604
+ column_name = column_name.to_s
605
+ columns(table_name).detect { |c| c.name == column_name } ||
606
+ raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
607
+ end
608
+
609
+ def collector
610
+ if prepared_statements
611
+ Arel::Collectors::Composite.new(
612
+ Arel::Collectors::SQLString.new,
613
+ Arel::Collectors::Bind.new,
614
+ )
615
+ else
616
+ Arel::Collectors::SubstituteBinds.new(
617
+ self,
618
+ Arel::Collectors::SQLString.new,
619
+ )
620
+ end
621
+ end
622
+
623
+ def arel_visitor
624
+ Arel::Visitors::ToSql.new(self)
625
+ end
626
+ end
627
+ end
628
+ end