activerecord 3.2.22.5 → 5.2.8

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 (275) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -621
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +41 -46
  5. data/examples/performance.rb +55 -42
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +264 -236
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +127 -75
  11. data/lib/active_record/associations/association_scope.rb +126 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +78 -27
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
  14. data/lib/active_record/associations/builder/association.rb +117 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +135 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -54
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
  18. data/lib/active_record/associations/builder/has_many.rb +10 -64
  19. data/lib/active_record/associations/builder/has_one.rb +19 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +28 -18
  21. data/lib/active_record/associations/collection_association.rb +226 -293
  22. data/lib/active_record/associations/collection_proxy.rb +1067 -69
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +83 -47
  25. data/lib/active_record/associations/has_many_through_association.rb +98 -65
  26. data/lib/active_record/associations/has_one_association.rb +57 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +212 -164
  32. data/lib/active_record/associations/preloader/association.rb +95 -89
  33. data/lib/active_record/associations/preloader/through_association.rb +84 -44
  34. data/lib/active_record/associations/preloader.rb +123 -111
  35. data/lib/active_record/associations/singular_association.rb +33 -24
  36. data/lib/active_record/associations/through_association.rb +60 -26
  37. data/lib/active_record/associations.rb +1759 -1506
  38. data/lib/active_record/attribute_assignment.rb +60 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +113 -74
  42. data/lib/active_record/attribute_methods/primary_key.rb +106 -77
  43. data/lib/active_record/attribute_methods/query.rb +8 -5
  44. data/lib/active_record/attribute_methods/read.rb +63 -114
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -90
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
  47. data/lib/active_record/attribute_methods/write.rb +43 -45
  48. data/lib/active_record/attribute_methods.rb +366 -149
  49. data/lib/active_record/attributes.rb +266 -0
  50. data/lib/active_record/autosave_association.rb +312 -225
  51. data/lib/active_record/base.rb +114 -505
  52. data/lib/active_record/callbacks.rb +145 -67
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
  69. data/lib/active_record/connection_adapters/column.rb +50 -255
  70. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -210
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
  117. data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +545 -27
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +145 -0
  128. data/lib/active_record/core.rb +559 -0
  129. data/lib/active_record/counter_cache.rb +200 -105
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +107 -69
  132. data/lib/active_record/enum.rb +244 -0
  133. data/lib/active_record/errors.rb +245 -60
  134. data/lib/active_record/explain.rb +35 -71
  135. data/lib/active_record/explain_registry.rb +32 -0
  136. data/lib/active_record/explain_subscriber.rb +18 -9
  137. data/lib/active_record/fixture_set/file.rb +82 -0
  138. data/lib/active_record/fixtures.rb +418 -275
  139. data/lib/active_record/gem_version.rb +17 -0
  140. data/lib/active_record/inheritance.rb +209 -100
  141. data/lib/active_record/integration.rb +116 -21
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +9 -1
  145. data/lib/active_record/locking/optimistic.rb +107 -94
  146. data/lib/active_record/locking/pessimistic.rb +20 -8
  147. data/lib/active_record/log_subscriber.rb +99 -34
  148. data/lib/active_record/migration/command_recorder.rb +199 -64
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +17 -0
  151. data/lib/active_record/migration.rb +893 -296
  152. data/lib/active_record/model_schema.rb +328 -175
  153. data/lib/active_record/nested_attributes.rb +338 -242
  154. data/lib/active_record/no_touching.rb +58 -0
  155. data/lib/active_record/null_relation.rb +68 -0
  156. data/lib/active_record/persistence.rb +557 -170
  157. data/lib/active_record/query_cache.rb +14 -43
  158. data/lib/active_record/querying.rb +36 -24
  159. data/lib/active_record/railtie.rb +147 -52
  160. data/lib/active_record/railties/console_sandbox.rb +5 -4
  161. data/lib/active_record/railties/controller_runtime.rb +13 -6
  162. data/lib/active_record/railties/databases.rake +206 -488
  163. data/lib/active_record/readonly_attributes.rb +4 -6
  164. data/lib/active_record/reflection.rb +734 -228
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +249 -52
  167. data/lib/active_record/relation/calculations.rb +330 -284
  168. data/lib/active_record/relation/delegation.rb +135 -37
  169. data/lib/active_record/relation/finder_methods.rb +450 -287
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +193 -0
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  179. data/lib/active_record/relation/predicate_builder.rb +132 -43
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +1037 -221
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +48 -151
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +451 -359
  187. data/lib/active_record/result.rb +129 -20
  188. data/lib/active_record/runtime_registry.rb +24 -0
  189. data/lib/active_record/sanitization.rb +164 -136
  190. data/lib/active_record/schema.rb +31 -19
  191. data/lib/active_record/schema_dumper.rb +154 -107
  192. data/lib/active_record/schema_migration.rb +56 -0
  193. data/lib/active_record/scoping/default.rb +108 -98
  194. data/lib/active_record/scoping/named.rb +125 -112
  195. data/lib/active_record/scoping.rb +77 -123
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +10 -6
  198. data/lib/active_record/statement_cache.rb +121 -0
  199. data/lib/active_record/store.rb +175 -16
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +337 -0
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  206. data/lib/active_record/timestamp.rb +80 -41
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +240 -119
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +9 -0
  212. data/lib/active_record/type/date_time.rb +9 -0
  213. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  214. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +71 -0
  218. data/lib/active_record/type/text.rb +11 -0
  219. data/lib/active_record/type/time.rb +21 -0
  220. data/lib/active_record/type/type_map.rb +62 -0
  221. data/lib/active_record/type/unsigned_integer.rb +17 -0
  222. data/lib/active_record/type.rb +79 -0
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +35 -18
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +68 -0
  230. data/lib/active_record/validations/uniqueness.rb +133 -75
  231. data/lib/active_record/validations.rb +53 -43
  232. data/lib/active_record/version.rb +7 -7
  233. data/lib/active_record.rb +89 -57
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +61 -8
  237. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  238. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  239. data/lib/rails/generators/active_record/migration.rb +28 -8
  240. data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
  241. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  243. data/lib/rails/generators/active_record.rb +10 -16
  244. metadata +141 -62
  245. data/examples/associations.png +0 -0
  246. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  247. data/lib/active_record/associations/join_helper.rb +0 -55
  248. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  249. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  250. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  251. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  252. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  253. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  254. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  255. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  256. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  257. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  258. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  259. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  260. data/lib/active_record/dynamic_finder_match.rb +0 -68
  261. data/lib/active_record/dynamic_scope_match.rb +0 -23
  262. data/lib/active_record/fixtures/file.rb +0 -65
  263. data/lib/active_record/identity_map.rb +0 -162
  264. data/lib/active_record/observer.rb +0 -121
  265. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  266. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  267. data/lib/active_record/session_store.rb +0 -360
  268. data/lib/active_record/test_case.rb +0 -73
  269. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  270. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  271. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  272. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  273. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  274. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  275. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,120 +1,221 @@
1
- require 'date'
2
- require 'bigdecimal'
3
- require 'bigdecimal/util'
4
- require 'active_support/core_ext/benchmark'
5
- require 'active_support/deprecation'
6
- require 'active_record/connection_adapters/schema_cache'
7
- require 'monitor'
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"
8
13
 
9
14
  module ActiveRecord
10
15
  module ConnectionAdapters # :nodoc:
11
16
  extend ActiveSupport::Autoload
12
17
 
13
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
14
31
 
15
- autoload_under 'abstract' do
16
- autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
17
- autoload :ColumnDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
18
- autoload :TableDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
19
- autoload :Table, 'active_record/connection_adapters/abstract/schema_definitions'
32
+ autoload_at "active_record/connection_adapters/abstract/connection_pool" do
33
+ autoload :ConnectionHandler
34
+ end
20
35
 
36
+ autoload_under "abstract" do
21
37
  autoload :SchemaStatements
22
38
  autoload :DatabaseStatements
23
39
  autoload :DatabaseLimits
24
40
  autoload :Quoting
25
-
26
41
  autoload :ConnectionPool
27
- autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool'
28
- autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool'
29
- autoload :ConnectionSpecification
30
-
31
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
32
52
  end
33
53
 
34
54
  # Active Record supports multiple database systems. AbstractAdapter and
35
55
  # related classes form the abstraction layer which makes this possible.
36
56
  # An AbstractAdapter represents a connection to a database, and provides an
37
57
  # abstract interface for database-specific functionality such as establishing
38
- # a connection, escaping values, building the right SQL fragments for ':offset'
39
- # and ':limit' options, etc.
58
+ # a connection, escaping values, building the right SQL fragments for +:offset+
59
+ # and +:limit+ options, etc.
40
60
  #
41
61
  # All the concrete database adapters follow the interface laid down in this class.
42
- # ActiveRecord::Base.connection returns an AbstractAdapter object, which
62
+ # {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
43
63
  # you can use.
44
64
  #
45
65
  # Most of the methods in the adapter are useful during migrations. Most
46
- # notably, the instance methods provided by SchemaStatement are very useful.
66
+ # notably, the instance methods provided by SchemaStatements are very useful.
47
67
  class AbstractAdapter
68
+ ADAPTER_NAME = "Abstract".freeze
69
+ include ActiveSupport::Callbacks
70
+ define_callbacks :checkout, :checkin
71
+
48
72
  include Quoting, DatabaseStatements, SchemaStatements
49
73
  include DatabaseLimits
50
74
  include QueryCache
51
- include ActiveSupport::Callbacks
52
- include MonitorMixin
75
+ include Savepoints
53
76
 
54
- define_callbacks :checkout, :checkin
77
+ SIMPLE_INT = /\A\d+\z/
55
78
 
56
79
  attr_accessor :visitor, :pool
57
- attr_reader :schema_cache, :last_use, :in_use, :logger
58
- alias :in_use? :in_use
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
59
100
 
60
- def initialize(connection, logger = nil, pool = nil) #:nodoc:
101
+ def initialize(connection, logger = nil, config = {}) # :nodoc:
61
102
  super()
62
103
 
63
- @active = nil
64
104
  @connection = connection
65
- @in_use = false
105
+ @owner = nil
66
106
  @instrumenter = ActiveSupport::Notifications.instrumenter
67
- @last_use = false
68
107
  @logger = logger
69
- @open_transactions = 0
70
- @pool = pool
71
- @query_cache = Hash.new { |h,sql| h[sql] = {} }
72
- @query_cache_enabled = false
108
+ @config = config
109
+ @pool = nil
110
+ @idle_since = Concurrent.monotonic_time
73
111
  @schema_cache = SchemaCache.new self
74
- @visitor = nil
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
75
142
  end
76
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
77
149
  def lease
78
- synchronize do
79
- unless in_use
80
- @in_use = true
81
- @last_use = Time.now
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}."
82
157
  end
158
+ raise ActiveRecordError, msg
83
159
  end
160
+
161
+ @owner = Thread.current
84
162
  end
85
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
86
170
  def expire
87
- @in_use = false
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
88
183
  end
89
184
 
90
- # Returns the human-readable name of the adapter. Use mixed case - one
91
- # can always use downcase if needed.
92
- def adapter_name
93
- 'Abstract'
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
94
196
  end
95
197
 
96
- # Does this adapter support migrations? Backend specific, as the
97
- # abstract adapter always returns +false+.
98
- def supports_migrations?
99
- false
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
100
202
  end
101
203
 
102
- # Can this adapter determine the primary key for tables not attached
103
- # to an Active Record class, such as join tables? Backend specific, as
104
- # the abstract adapter always returns +false+.
105
- def supports_primary_key?
106
- false
204
+ def unprepared_statement
205
+ old_prepared_statements, @prepared_statements = @prepared_statements, false
206
+ yield
207
+ ensure
208
+ @prepared_statements = old_prepared_statements
107
209
  end
108
210
 
109
- # Does this adapter support using DISTINCT within COUNT? This is +true+
110
- # for all adapters except sqlite.
111
- def supports_count_distinct?
112
- true
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
113
215
  end
114
216
 
115
217
  # Does this adapter support DDL rollbacks in transactions? That is, would
116
- # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
117
- # SQL Server, and others support this. MySQL and others do not.
218
+ # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
118
219
  def supports_ddl_transactions?
119
220
  false
120
221
  end
@@ -123,16 +224,19 @@ module ActiveRecord
123
224
  false
124
225
  end
125
226
 
126
- # Does this adapter support savepoints? PostgreSQL and MySQL do,
127
- # SQLite < 3.6.8 does not.
227
+ # Does this adapter support savepoints?
128
228
  def supports_savepoints?
129
229
  false
130
230
  end
131
231
 
232
+ # Does this adapter support application-enforced advisory locking?
233
+ def supports_advisory_locks?
234
+ false
235
+ end
236
+
132
237
  # Should primary key values be selected from their corresponding
133
238
  # sequence before the insert statement? If true, next_sequence_value
134
239
  # is called before each insert to set the record's primary key.
135
- # This is false for all adapters but Firebird.
136
240
  def prefetch_primary_key?(table_name = nil)
137
241
  false
138
242
  end
@@ -142,23 +246,123 @@ module ActiveRecord
142
246
  false
143
247
  end
144
248
 
145
- # Does this adapter support explain? As of this writing sqlite3,
146
- # mysql2, and postgresql are the only ones that do.
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?
147
260
  def supports_explain?
148
261
  false
149
262
  end
150
263
 
151
- # QUOTING ==================================================
264
+ # Does this adapter support setting the isolation level for a transaction?
265
+ def supports_transaction_isolation?
266
+ false
267
+ end
152
268
 
153
- # Override to return the quoted table name. Defaults to column quoting.
154
- def quote_table_name(name)
155
- quote_column_name(name)
269
+ # Does this adapter support database extensions?
270
+ def supports_extensions?
271
+ false
156
272
  end
157
273
 
158
- # Returns a bind substitution value given a +column+ and list of current
159
- # +binds+
160
- def substitute_at(column, index)
161
- Arel::Nodes::BindParam.new '?'
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
+ {}
162
366
  end
163
367
 
164
368
  # REFERENTIAL INTEGRITY ====================================
@@ -174,19 +378,34 @@ module ActiveRecord
174
378
  # checking whether the database is actually capable of responding, i.e. whether
175
379
  # the connection isn't stale.
176
380
  def active?
177
- @active != false
178
381
  end
179
382
 
180
383
  # Disconnects from the database if already connected, and establishes a
181
- # new connection with the database.
384
+ # new connection with the database. Implementors should call super if they
385
+ # override the default implementation.
182
386
  def reconnect!
183
- @active = true
387
+ clear_cache!
388
+ reset_transaction
184
389
  end
185
390
 
186
391
  # Disconnects from the database if already connected. Otherwise, this
187
392
  # method does nothing.
188
393
  def disconnect!
189
- @active = false
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.
190
409
  end
191
410
 
192
411
  # Reset the state of this connection, directing the DBMS to clear
@@ -207,21 +426,20 @@ module ActiveRecord
207
426
  end
208
427
 
209
428
  # Returns true if its required to reload the connection between requests for development mode.
210
- # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
211
429
  def requires_reloading?
212
430
  false
213
431
  end
214
432
 
215
433
  # Checks whether the connection to the database is still active (i.e. not stale).
216
- # This is done under the hood by calling <tt>active?</tt>. If the connection
434
+ # This is done under the hood by calling #active?. If the connection
217
435
  # is no longer active, then this method will reconnect to the database.
218
- def verify!(*ignored)
436
+ def verify!
219
437
  reconnect! unless active?
220
438
  end
221
439
 
222
440
  # Provides access to the underlying database driver for this adapter. For
223
- # example, this method returns a Mysql object in case of MysqlAdapter,
224
- # and a PGconn object in case of PostgreSQLAdapter.
441
+ # example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
442
+ # and a PG::Connection object in case of PostgreSQLAdapter.
225
443
  #
226
444
  # This is useful for when you need to call a proprietary method such as
227
445
  # PostgreSQL's lo_* methods.
@@ -229,68 +447,182 @@ module ActiveRecord
229
447
  @connection
230
448
  end
231
449
 
232
- attr_reader :open_transactions
233
-
234
- def increment_open_transactions
235
- @open_transactions += 1
450
+ def case_sensitive_comparison(table, attribute, column, value) # :nodoc:
451
+ table[attribute].eq(value)
236
452
  end
237
453
 
238
- def decrement_open_transactions
239
- @open_transactions -= 1
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
240
460
  end
241
461
 
242
- def transaction_joinable=(joinable)
243
- @transaction_joinable = joinable
462
+ def can_perform_case_insensitive_comparison_for?(column)
463
+ true
244
464
  end
465
+ private :can_perform_case_insensitive_comparison_for?
245
466
 
246
- def create_savepoint
467
+ # Check the connection back in to the connection pool
468
+ def close
469
+ pool.checkin self
247
470
  end
248
471
 
249
- def rollback_to_savepoint
472
+ def column_name_for_operation(operation, node) # :nodoc:
473
+ column_name_from_arel_node(node)
250
474
  end
251
475
 
252
- def release_savepoint
476
+ def column_name_from_arel_node(node) # :nodoc:
477
+ visitor.accept(node, Arel::Collectors::SQLString.new).value
253
478
  end
254
479
 
255
- def case_sensitive_modifier(node)
256
- node
480
+ def default_index_type?(index) # :nodoc:
481
+ index.using.nil?
257
482
  end
258
483
 
259
- def case_insensitive_comparison(table, attribute, column, value)
260
- table[attribute].lower.eq(table.lower(value))
261
- end
484
+ private
485
+ def type_map
486
+ @type_map ||= Type::TypeMap.new.tap do |mapping|
487
+ initialize_type_map(mapping)
488
+ end
489
+ end
262
490
 
263
- def current_savepoint_name
264
- "active_record_#{open_transactions}"
265
- end
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
266
523
 
267
- # Check the connection back in to the connection pool
268
- def close
269
- pool.checkin self
270
- end
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
271
535
 
272
- protected
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
273
564
 
274
- def log(sql, name = "SQL", binds = [])
275
- @instrumenter.instrument(
276
- "sql.active_record",
277
- :sql => sql,
278
- :name => name,
279
- :connection_id => object_id,
280
- :binds => binds) { yield }
281
- rescue Exception => e
282
- message = "#{e.class.name}: #{e.message}: #{sql}"
283
- @logger.debug message if @logger
284
565
  exception = translate_exception(e, message)
285
566
  exception.set_backtrace e.backtrace
286
- raise exception
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
287
587
  end
288
588
 
289
- def translate_exception(e, message)
589
+ def translate_exception(exception, message)
290
590
  # override in derived class
291
- ActiveRecord::StatementInvalid.new(message)
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}")
292
607
  end
293
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
294
626
  end
295
627
  end
296
628
  end