activerecord 7.0.8.6 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +631 -1939
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +29 -29
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +16 -13
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +35 -12
  10. data/lib/active_record/associations/association_scope.rb +16 -9
  11. data/lib/active_record/associations/belongs_to_association.rb +23 -8
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  13. data/lib/active_record/associations/builder/association.rb +3 -3
  14. data/lib/active_record/associations/builder/belongs_to.rb +22 -8
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  16. data/lib/active_record/associations/builder/has_many.rb +3 -4
  17. data/lib/active_record/associations/builder/has_one.rb +3 -4
  18. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  19. data/lib/active_record/associations/collection_association.rb +26 -14
  20. data/lib/active_record/associations/collection_proxy.rb +29 -11
  21. data/lib/active_record/associations/errors.rb +265 -0
  22. data/lib/active_record/associations/foreign_association.rb +10 -3
  23. data/lib/active_record/associations/has_many_association.rb +21 -14
  24. data/lib/active_record/associations/has_many_through_association.rb +17 -7
  25. data/lib/active_record/associations/has_one_association.rb +10 -3
  26. data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
  27. data/lib/active_record/associations/join_dependency.rb +10 -10
  28. data/lib/active_record/associations/nested_error.rb +47 -0
  29. data/lib/active_record/associations/preloader/association.rb +33 -8
  30. data/lib/active_record/associations/preloader/branch.rb +7 -1
  31. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  32. data/lib/active_record/associations/preloader.rb +13 -10
  33. data/lib/active_record/associations/singular_association.rb +7 -1
  34. data/lib/active_record/associations/through_association.rb +22 -11
  35. data/lib/active_record/associations.rb +354 -485
  36. data/lib/active_record/attribute_assignment.rb +0 -4
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  38. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  39. data/lib/active_record/attribute_methods/dirty.rb +53 -35
  40. data/lib/active_record/attribute_methods/primary_key.rb +45 -25
  41. data/lib/active_record/attribute_methods/query.rb +28 -16
  42. data/lib/active_record/attribute_methods/read.rb +8 -7
  43. data/lib/active_record/attribute_methods/serialization.rb +131 -32
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
  45. data/lib/active_record/attribute_methods/write.rb +6 -6
  46. data/lib/active_record/attribute_methods.rb +148 -33
  47. data/lib/active_record/attributes.rb +64 -50
  48. data/lib/active_record/autosave_association.rb +69 -37
  49. data/lib/active_record/base.rb +9 -5
  50. data/lib/active_record/callbacks.rb +11 -25
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -42
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
  69. data/lib/active_record/connection_adapters/column.rb +9 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -10
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  89. data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
  90. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  91. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  92. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
  93. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
  96. data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
  97. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  101. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
  102. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  103. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
  104. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
  105. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  106. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  107. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  108. data/lib/active_record/connection_adapters.rb +124 -1
  109. data/lib/active_record/connection_handling.rb +96 -104
  110. data/lib/active_record/core.rb +251 -176
  111. data/lib/active_record/counter_cache.rb +68 -34
  112. data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
  113. data/lib/active_record/database_configurations/database_config.rb +26 -5
  114. data/lib/active_record/database_configurations/hash_config.rb +52 -34
  115. data/lib/active_record/database_configurations/url_config.rb +37 -12
  116. data/lib/active_record/database_configurations.rb +87 -34
  117. data/lib/active_record/delegated_type.rb +39 -10
  118. data/lib/active_record/deprecator.rb +7 -0
  119. data/lib/active_record/destroy_association_async_job.rb +3 -1
  120. data/lib/active_record/dynamic_matchers.rb +2 -2
  121. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  122. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  123. data/lib/active_record/encryption/config.rb +25 -1
  124. data/lib/active_record/encryption/configurable.rb +12 -19
  125. data/lib/active_record/encryption/context.rb +10 -3
  126. data/lib/active_record/encryption/contexts.rb +5 -1
  127. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  128. data/lib/active_record/encryption/encryptable_record.rb +45 -21
  129. data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
  130. data/lib/active_record/encryption/encryptor.rb +18 -3
  131. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  132. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  133. data/lib/active_record/encryption/key_generator.rb +12 -1
  134. data/lib/active_record/encryption/key_provider.rb +1 -1
  135. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  136. data/lib/active_record/encryption/message_serializer.rb +6 -0
  137. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  138. data/lib/active_record/encryption/properties.rb +3 -3
  139. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  140. data/lib/active_record/encryption/scheme.rb +22 -21
  141. data/lib/active_record/encryption.rb +3 -0
  142. data/lib/active_record/enum.rb +129 -28
  143. data/lib/active_record/errors.rb +151 -31
  144. data/lib/active_record/explain.rb +21 -12
  145. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  146. data/lib/active_record/fixture_set/render_context.rb +2 -0
  147. data/lib/active_record/fixture_set/table_row.rb +29 -8
  148. data/lib/active_record/fixtures.rb +167 -97
  149. data/lib/active_record/future_result.rb +47 -8
  150. data/lib/active_record/gem_version.rb +4 -4
  151. data/lib/active_record/inheritance.rb +34 -18
  152. data/lib/active_record/insert_all.rb +72 -22
  153. data/lib/active_record/integration.rb +11 -8
  154. data/lib/active_record/internal_metadata.rb +124 -20
  155. data/lib/active_record/locking/optimistic.rb +8 -7
  156. data/lib/active_record/locking/pessimistic.rb +5 -2
  157. data/lib/active_record/log_subscriber.rb +18 -22
  158. data/lib/active_record/marshalling.rb +59 -0
  159. data/lib/active_record/message_pack.rb +124 -0
  160. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  161. data/lib/active_record/middleware/database_selector.rb +6 -8
  162. data/lib/active_record/middleware/shard_selector.rb +3 -1
  163. data/lib/active_record/migration/command_recorder.rb +106 -8
  164. data/lib/active_record/migration/compatibility.rb +147 -5
  165. data/lib/active_record/migration/default_strategy.rb +22 -0
  166. data/lib/active_record/migration/execution_strategy.rb +19 -0
  167. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  168. data/lib/active_record/migration.rb +234 -117
  169. data/lib/active_record/model_schema.rb +90 -102
  170. data/lib/active_record/nested_attributes.rb +48 -11
  171. data/lib/active_record/normalization.rb +163 -0
  172. data/lib/active_record/persistence.rb +168 -339
  173. data/lib/active_record/promise.rb +84 -0
  174. data/lib/active_record/query_cache.rb +18 -25
  175. data/lib/active_record/query_logs.rb +92 -52
  176. data/lib/active_record/query_logs_formatter.rb +41 -0
  177. data/lib/active_record/querying.rb +33 -8
  178. data/lib/active_record/railtie.rb +129 -85
  179. data/lib/active_record/railties/controller_runtime.rb +22 -7
  180. data/lib/active_record/railties/databases.rake +145 -154
  181. data/lib/active_record/railties/job_runtime.rb +23 -0
  182. data/lib/active_record/readonly_attributes.rb +32 -5
  183. data/lib/active_record/reflection.rb +267 -69
  184. data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
  185. data/lib/active_record/relation/batches.rb +198 -63
  186. data/lib/active_record/relation/calculations.rb +250 -93
  187. data/lib/active_record/relation/delegation.rb +30 -19
  188. data/lib/active_record/relation/finder_methods.rb +93 -18
  189. data/lib/active_record/relation/merger.rb +6 -6
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  193. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  194. data/lib/active_record/relation/predicate_builder.rb +28 -16
  195. data/lib/active_record/relation/query_attribute.rb +2 -1
  196. data/lib/active_record/relation/query_methods.rb +576 -107
  197. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  198. data/lib/active_record/relation/spawn_methods.rb +5 -4
  199. data/lib/active_record/relation/where_clause.rb +7 -19
  200. data/lib/active_record/relation.rb +580 -90
  201. data/lib/active_record/result.rb +49 -48
  202. data/lib/active_record/runtime_registry.rb +63 -1
  203. data/lib/active_record/sanitization.rb +70 -25
  204. data/lib/active_record/schema.rb +8 -7
  205. data/lib/active_record/schema_dumper.rb +63 -14
  206. data/lib/active_record/schema_migration.rb +75 -24
  207. data/lib/active_record/scoping/default.rb +15 -5
  208. data/lib/active_record/scoping/named.rb +3 -2
  209. data/lib/active_record/scoping.rb +2 -1
  210. data/lib/active_record/secure_password.rb +60 -0
  211. data/lib/active_record/secure_token.rb +21 -3
  212. data/lib/active_record/signed_id.rb +27 -6
  213. data/lib/active_record/statement_cache.rb +7 -7
  214. data/lib/active_record/store.rb +8 -8
  215. data/lib/active_record/suppressor.rb +3 -1
  216. data/lib/active_record/table_metadata.rb +1 -1
  217. data/lib/active_record/tasks/database_tasks.rb +190 -118
  218. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  219. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  220. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  221. data/lib/active_record/test_fixtures.rb +170 -155
  222. data/lib/active_record/testing/query_assertions.rb +121 -0
  223. data/lib/active_record/timestamp.rb +31 -17
  224. data/lib/active_record/token_for.rb +123 -0
  225. data/lib/active_record/touch_later.rb +12 -7
  226. data/lib/active_record/transaction.rb +132 -0
  227. data/lib/active_record/transactions.rb +106 -24
  228. data/lib/active_record/translation.rb +0 -2
  229. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  230. data/lib/active_record/type/internal/timezone.rb +7 -2
  231. data/lib/active_record/type/serialized.rb +1 -3
  232. data/lib/active_record/type/time.rb +4 -0
  233. data/lib/active_record/type_caster/connection.rb +4 -4
  234. data/lib/active_record/validations/absence.rb +1 -1
  235. data/lib/active_record/validations/associated.rb +9 -3
  236. data/lib/active_record/validations/numericality.rb +5 -4
  237. data/lib/active_record/validations/presence.rb +5 -28
  238. data/lib/active_record/validations/uniqueness.rb +61 -11
  239. data/lib/active_record/validations.rb +12 -5
  240. data/lib/active_record/version.rb +1 -1
  241. data/lib/active_record.rb +247 -33
  242. data/lib/arel/alias_predication.rb +1 -1
  243. data/lib/arel/collectors/bind.rb +2 -0
  244. data/lib/arel/collectors/composite.rb +7 -0
  245. data/lib/arel/collectors/sql_string.rb +1 -1
  246. data/lib/arel/collectors/substitute_binds.rb +1 -1
  247. data/lib/arel/errors.rb +10 -0
  248. data/lib/arel/factory_methods.rb +4 -0
  249. data/lib/arel/nodes/binary.rb +6 -7
  250. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  251. data/lib/arel/nodes/cte.rb +36 -0
  252. data/lib/arel/nodes/fragments.rb +35 -0
  253. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  254. data/lib/arel/nodes/leading_join.rb +8 -0
  255. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  256. data/lib/arel/nodes/node.rb +115 -5
  257. data/lib/arel/nodes/sql_literal.rb +13 -0
  258. data/lib/arel/nodes/table_alias.rb +4 -0
  259. data/lib/arel/nodes.rb +6 -2
  260. data/lib/arel/predications.rb +3 -1
  261. data/lib/arel/select_manager.rb +1 -1
  262. data/lib/arel/table.rb +9 -5
  263. data/lib/arel/tree_manager.rb +8 -3
  264. data/lib/arel/update_manager.rb +2 -1
  265. data/lib/arel/visitors/dot.rb +1 -0
  266. data/lib/arel/visitors/mysql.rb +17 -5
  267. data/lib/arel/visitors/postgresql.rb +1 -12
  268. data/lib/arel/visitors/sqlite.rb +25 -0
  269. data/lib/arel/visitors/to_sql.rb +112 -34
  270. data/lib/arel/visitors/visitor.rb +2 -2
  271. data/lib/arel.rb +21 -3
  272. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  273. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  274. data/lib/rails/generators/active_record/migration.rb +3 -1
  275. data/lib/rails/generators/active_record/model/USAGE +113 -0
  276. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  277. metadata +56 -14
  278. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  279. data/lib/active_record/null_relation.rb +0 -63
@@ -4,8 +4,228 @@ require "active_support/core_ext/file/atomic"
4
4
 
5
5
  module ActiveRecord
6
6
  module ConnectionAdapters
7
+ class SchemaReflection
8
+ class << self
9
+ attr_accessor :use_schema_cache_dump
10
+ attr_accessor :check_schema_cache_dump_version
11
+ end
12
+
13
+ self.use_schema_cache_dump = true
14
+ self.check_schema_cache_dump_version = true
15
+
16
+ def initialize(cache_path, cache = nil)
17
+ @cache = cache
18
+ @cache_path = cache_path
19
+ end
20
+
21
+ def clear!
22
+ @cache = empty_cache
23
+
24
+ nil
25
+ end
26
+
27
+ def load!(pool)
28
+ cache(pool)
29
+
30
+ self
31
+ end
32
+
33
+ def primary_keys(pool, table_name)
34
+ cache(pool).primary_keys(pool, table_name)
35
+ end
36
+
37
+ def data_source_exists?(pool, name)
38
+ cache(pool).data_source_exists?(pool, name)
39
+ end
40
+
41
+ def add(pool, name)
42
+ cache(pool).add(pool, name)
43
+ end
44
+
45
+ def data_sources(pool, name)
46
+ cache(pool).data_source_exists?(pool, name)
47
+ end
48
+
49
+ def columns(pool, table_name)
50
+ cache(pool).columns(pool, table_name)
51
+ end
52
+
53
+ def columns_hash(pool, table_name)
54
+ cache(pool).columns_hash(pool, table_name)
55
+ end
56
+
57
+ def columns_hash?(pool, table_name)
58
+ cache(pool).columns_hash?(pool, table_name)
59
+ end
60
+
61
+ def indexes(pool, table_name)
62
+ cache(pool).indexes(pool, table_name)
63
+ end
64
+
65
+ def version(pool)
66
+ cache(pool).version(pool)
67
+ end
68
+
69
+ def size(pool)
70
+ cache(pool).size
71
+ end
72
+
73
+ def clear_data_source_cache!(pool, name)
74
+ return if @cache.nil? && !possible_cache_available?
75
+
76
+ cache(pool).clear_data_source_cache!(pool, name)
77
+ end
78
+
79
+ def cached?(table_name)
80
+ if @cache.nil?
81
+ # If `check_schema_cache_dump_version` is enabled we can't load
82
+ # the schema cache dump without connecting to the database.
83
+ unless self.class.check_schema_cache_dump_version
84
+ @cache = load_cache(nil)
85
+ end
86
+ end
87
+
88
+ @cache&.cached?(table_name)
89
+ end
90
+
91
+ def dump_to(pool, filename)
92
+ fresh_cache = empty_cache
93
+ fresh_cache.add_all(pool)
94
+ fresh_cache.dump_to(filename)
95
+
96
+ @cache = fresh_cache
97
+ end
98
+
99
+ private
100
+ def empty_cache
101
+ new_cache = SchemaCache.allocate
102
+ new_cache.send(:initialize)
103
+ new_cache
104
+ end
105
+
106
+ def cache(pool)
107
+ @cache ||= load_cache(pool) || empty_cache
108
+ end
109
+
110
+ def possible_cache_available?
111
+ self.class.use_schema_cache_dump &&
112
+ @cache_path &&
113
+ File.file?(@cache_path)
114
+ end
115
+
116
+ def load_cache(pool)
117
+ # Can't load if schema dumps are disabled
118
+ return unless possible_cache_available?
119
+
120
+ # Check we can find one
121
+ return unless new_cache = SchemaCache._load_from(@cache_path)
122
+
123
+ if self.class.check_schema_cache_dump_version
124
+ begin
125
+ pool.with_connection do |connection|
126
+ current_version = connection.schema_version
127
+
128
+ if new_cache.version(connection) != current_version
129
+ warn "Ignoring #{@cache_path} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{new_cache.schema_version}."
130
+ return
131
+ end
132
+ end
133
+ rescue ActiveRecordError => error
134
+ warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
135
+ return
136
+ end
137
+ end
138
+
139
+ new_cache
140
+ end
141
+ end
142
+
143
+ class BoundSchemaReflection
144
+ class FakePool # :nodoc
145
+ def initialize(connection)
146
+ @connection = connection
147
+ end
148
+
149
+ def with_connection
150
+ yield @connection
151
+ end
152
+ end
153
+
154
+ class << self
155
+ def for_lone_connection(abstract_schema_reflection, connection) # :nodoc:
156
+ new(abstract_schema_reflection, FakePool.new(connection))
157
+ end
158
+ end
159
+
160
+ def initialize(abstract_schema_reflection, pool)
161
+ @schema_reflection = abstract_schema_reflection
162
+ @pool = pool
163
+ end
164
+
165
+ def clear!
166
+ @schema_reflection.clear!
167
+ end
168
+
169
+ def load!
170
+ @schema_reflection.load!(@pool)
171
+ end
172
+
173
+ def cached?(table_name)
174
+ @schema_reflection.cached?(table_name)
175
+ end
176
+
177
+ def primary_keys(table_name)
178
+ @schema_reflection.primary_keys(@pool, table_name)
179
+ end
180
+
181
+ def data_source_exists?(name)
182
+ @schema_reflection.data_source_exists?(@pool, name)
183
+ end
184
+
185
+ def add(name)
186
+ @schema_reflection.add(@pool, name)
187
+ end
188
+
189
+ def data_sources(name)
190
+ @schema_reflection.data_sources(@pool, name)
191
+ end
192
+
193
+ def columns(table_name)
194
+ @schema_reflection.columns(@pool, table_name)
195
+ end
196
+
197
+ def columns_hash(table_name)
198
+ @schema_reflection.columns_hash(@pool, table_name)
199
+ end
200
+
201
+ def columns_hash?(table_name)
202
+ @schema_reflection.columns_hash?(@pool, table_name)
203
+ end
204
+
205
+ def indexes(table_name)
206
+ @schema_reflection.indexes(@pool, table_name)
207
+ end
208
+
209
+ def version
210
+ @schema_reflection.version(@pool)
211
+ end
212
+
213
+ def size
214
+ @schema_reflection.size(@pool)
215
+ end
216
+
217
+ def clear_data_source_cache!(name)
218
+ @schema_reflection.clear_data_source_cache!(@pool, name)
219
+ end
220
+
221
+ def dump_to(filename)
222
+ @schema_reflection.dump_to(@pool, filename)
223
+ end
224
+ end
225
+
226
+ # = Active Record Connection Adapters Schema Cache
7
227
  class SchemaCache
8
- def self.load_from(filename)
228
+ def self._load_from(filename) # :nodoc:
9
229
  return unless File.file?(filename)
10
230
 
11
231
  read(filename) do |file|
@@ -32,20 +252,16 @@ module ActiveRecord
32
252
  end
33
253
  private_class_method :read
34
254
 
35
- attr_reader :version
36
- attr_accessor :connection
37
-
38
- def initialize(conn)
39
- @connection = conn
40
-
255
+ def initialize # :nodoc:
41
256
  @columns = {}
42
257
  @columns_hash = {}
43
258
  @primary_keys = {}
44
259
  @data_sources = {}
45
260
  @indexes = {}
261
+ @version = nil
46
262
  end
47
263
 
48
- def initialize_dup(other)
264
+ def initialize_dup(other) # :nodoc:
49
265
  super
50
266
  @columns = @columns.dup
51
267
  @columns_hash = @columns_hash.dup
@@ -54,106 +270,114 @@ module ActiveRecord
54
270
  @indexes = @indexes.dup
55
271
  end
56
272
 
57
- def encode_with(coder)
58
- reset_version!
59
-
60
- coder["columns"] = @columns
61
- coder["primary_keys"] = @primary_keys
62
- coder["data_sources"] = @data_sources
63
- coder["indexes"] = @indexes
273
+ def encode_with(coder) # :nodoc:
274
+ coder["columns"] = @columns.sort.to_h
275
+ coder["primary_keys"] = @primary_keys.sort.to_h
276
+ coder["data_sources"] = @data_sources.sort.to_h
277
+ coder["indexes"] = @indexes.sort.to_h
64
278
  coder["version"] = @version
65
- coder["database_version"] = database_version
66
279
  end
67
280
 
68
- def init_with(coder)
281
+ def init_with(coder) # :nodoc:
69
282
  @columns = coder["columns"]
283
+ @columns_hash = coder["columns_hash"]
70
284
  @primary_keys = coder["primary_keys"]
71
285
  @data_sources = coder["data_sources"]
72
286
  @indexes = coder["indexes"] || {}
73
287
  @version = coder["version"]
74
- @database_version = coder["database_version"]
75
288
 
76
- derive_columns_hash_and_deduplicate_values
289
+ unless coder["deduplicated"]
290
+ derive_columns_hash_and_deduplicate_values
291
+ end
77
292
  end
78
293
 
79
- def primary_keys(table_name)
294
+ def cached?(table_name)
295
+ @columns.key?(table_name)
296
+ end
297
+
298
+ def primary_keys(pool, table_name)
80
299
  @primary_keys.fetch(table_name) do
81
- if data_source_exists?(table_name)
82
- @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
300
+ pool.with_connection do |connection|
301
+ if data_source_exists?(pool, table_name)
302
+ @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
303
+ end
83
304
  end
84
305
  end
85
306
  end
86
307
 
87
308
  # A cached lookup for table existence.
88
- def data_source_exists?(name)
309
+ def data_source_exists?(pool, name)
89
310
  return if ignored_table?(name)
90
- prepare_data_sources if @data_sources.empty?
311
+
312
+ if @data_sources.empty?
313
+ tables_to_cache(pool).each do |source|
314
+ @data_sources[source] = true
315
+ end
316
+ end
317
+
91
318
  return @data_sources[name] if @data_sources.key? name
92
319
 
93
- @data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name)
320
+ @data_sources[deep_deduplicate(name)] = pool.with_connection do |connection|
321
+ connection.data_source_exists?(name)
322
+ end
94
323
  end
95
324
 
96
325
  # Add internal cache for table with +table_name+.
97
- def add(table_name)
98
- if data_source_exists?(table_name)
99
- primary_keys(table_name)
100
- columns(table_name)
101
- columns_hash(table_name)
102
- indexes(table_name)
326
+ def add(pool, table_name)
327
+ pool.with_connection do
328
+ if data_source_exists?(pool, table_name)
329
+ primary_keys(pool, table_name)
330
+ columns(pool, table_name)
331
+ columns_hash(pool, table_name)
332
+ indexes(pool, table_name)
333
+ end
103
334
  end
104
335
  end
105
336
 
106
- def data_sources(name)
107
- @data_sources[name]
108
- end
109
-
110
337
  # Get the columns for a table
111
- def columns(table_name)
338
+ def columns(pool, table_name)
112
339
  if ignored_table?(table_name)
113
- raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
340
+ raise ActiveRecord::StatementInvalid.new("Table '#{table_name}' doesn't exist", connection_pool: pool)
114
341
  end
115
342
 
116
343
  @columns.fetch(table_name) do
117
- @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
344
+ pool.with_connection do |connection|
345
+ @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
346
+ end
118
347
  end
119
348
  end
120
349
 
121
350
  # Get the columns for a table as a hash, key is the column name
122
351
  # value is the column object.
123
- def columns_hash(table_name)
352
+ def columns_hash(pool, table_name)
124
353
  @columns_hash.fetch(table_name) do
125
- @columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name).freeze
354
+ @columns_hash[deep_deduplicate(table_name)] = columns(pool, table_name).index_by(&:name).freeze
126
355
  end
127
356
  end
128
357
 
129
358
  # Checks whether the columns hash is already cached for a table.
130
- def columns_hash?(table_name)
359
+ def columns_hash?(_pool, table_name)
131
360
  @columns_hash.key?(table_name)
132
361
  end
133
362
 
134
- def indexes(table_name)
363
+ def indexes(pool, table_name)
135
364
  @indexes.fetch(table_name) do
136
- if data_source_exists?(table_name)
137
- @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
138
- else
139
- []
365
+ pool.with_connection do |connection|
366
+ if data_source_exists?(pool, table_name)
367
+ @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
368
+ else
369
+ []
370
+ end
140
371
  end
141
372
  end
142
373
  end
143
374
 
144
- def database_version # :nodoc:
145
- @database_version ||= connection.get_database_version
375
+ def version(pool)
376
+ @version ||= pool.with_connection(&:schema_version)
146
377
  end
147
378
 
148
- # Clears out internal caches
149
- def clear!
150
- @columns.clear
151
- @columns_hash.clear
152
- @primary_keys.clear
153
- @data_sources.clear
154
- @indexes.clear
155
- @version = nil
156
- @database_version = nil
379
+ def schema_version
380
+ @version
157
381
  end
158
382
 
159
383
  def size
@@ -161,7 +385,7 @@ module ActiveRecord
161
385
  end
162
386
 
163
387
  # Clear out internal caches for the data source +name+.
164
- def clear_data_source_cache!(name)
388
+ def clear_data_source_cache!(_connection, name)
165
389
  @columns.delete name
166
390
  @columns_hash.delete name
167
391
  @primary_keys.delete name
@@ -169,9 +393,17 @@ module ActiveRecord
169
393
  @indexes.delete name
170
394
  end
171
395
 
396
+ def add_all(pool) # :nodoc:
397
+ pool.with_connection do
398
+ tables_to_cache(pool).each do |table|
399
+ add(pool, table)
400
+ end
401
+
402
+ version(pool)
403
+ end
404
+ end
405
+
172
406
  def dump_to(filename)
173
- clear!
174
- tables_to_cache.each { |table| add(table) }
175
407
  open(filename) { |f|
176
408
  if filename.include?(".dump")
177
409
  f.write(Marshal.dump(self))
@@ -181,23 +413,23 @@ module ActiveRecord
181
413
  }
182
414
  end
183
415
 
184
- def marshal_dump
185
- reset_version!
186
-
187
- [@version, @columns, {}, @primary_keys, @data_sources, @indexes, database_version]
416
+ def marshal_dump # :nodoc:
417
+ [@version, @columns, {}, @primary_keys, @data_sources, @indexes]
188
418
  end
189
419
 
190
- def marshal_load(array)
191
- @version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
420
+ def marshal_load(array) # :nodoc:
421
+ @version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, _database_version = array
192
422
  @indexes ||= {}
193
423
 
194
424
  derive_columns_hash_and_deduplicate_values
195
425
  end
196
426
 
197
427
  private
198
- def tables_to_cache
199
- connection.data_sources.reject do |table|
200
- ignored_table?(table)
428
+ def tables_to_cache(pool)
429
+ pool.with_connection do |connection|
430
+ connection.data_sources.reject do |table|
431
+ ignored_table?(table)
432
+ end
201
433
  end
202
434
  end
203
435
 
@@ -207,10 +439,6 @@ module ActiveRecord
207
439
  end
208
440
  end
209
441
 
210
- def reset_version!
211
- @version = connection.schema_version
212
- end
213
-
214
442
  def derive_columns_hash_and_deduplicate_values
215
443
  @columns = deep_deduplicate(@columns)
216
444
  @columns_hash = @columns.transform_values { |columns| columns.index_by(&:name) }
@@ -232,18 +460,13 @@ module ActiveRecord
232
460
  end
233
461
  end
234
462
 
235
- def prepare_data_sources
236
- tables_to_cache.each do |source|
237
- @data_sources[source] = true
238
- end
239
- end
240
-
241
463
  def open(filename)
242
464
  FileUtils.mkdir_p(File.dirname(filename))
243
465
 
244
466
  File.atomic_write(filename) do |file|
245
467
  if File.extname(filename) == ".gz"
246
468
  zipper = Zlib::GzipWriter.new file
469
+ zipper.mtime = 0
247
470
  yield zipper
248
471
  zipper.flush
249
472
  zipper.close
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module SQLite3
6
+ class Column < ConnectionAdapters::Column # :nodoc:
7
+ attr_reader :rowid
8
+
9
+ def initialize(*, auto_increment: nil, rowid: false, generated_type: nil, **)
10
+ super
11
+ @auto_increment = auto_increment
12
+ @rowid = rowid
13
+ @generated_type = generated_type
14
+ end
15
+
16
+ def auto_increment?
17
+ @auto_increment
18
+ end
19
+
20
+ def auto_incremented_by_db?
21
+ auto_increment? || rowid
22
+ end
23
+
24
+ def virtual?
25
+ !@generated_type.nil?
26
+ end
27
+
28
+ def virtual_stored?
29
+ virtual? && @generated_type == :stored
30
+ end
31
+
32
+ def has_default?
33
+ super && !virtual?
34
+ end
35
+
36
+ def init_with(coder)
37
+ @auto_increment = coder["auto_increment"]
38
+ super
39
+ end
40
+
41
+ def encode_with(coder)
42
+ coder["auto_increment"] = @auto_increment
43
+ super
44
+ end
45
+
46
+ def ==(other)
47
+ other.is_a?(Column) &&
48
+ super &&
49
+ auto_increment? == other.auto_increment?
50
+ end
51
+ alias :eql? :==
52
+
53
+ def hash
54
+ Column.hash ^
55
+ super.hash ^
56
+ auto_increment?.hash ^
57
+ rowid.hash
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end