activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  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 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_record/connection_adapters/abstract_adapter"
4
4
  require "active_record/connection_adapters/statement_pool"
5
+ require "active_record/connection_adapters/sqlite3/column"
5
6
  require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
6
7
  require "active_record/connection_adapters/sqlite3/quoting"
7
8
  require "active_record/connection_adapters/sqlite3/database_statements"
@@ -10,44 +11,23 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
10
11
  require "active_record/connection_adapters/sqlite3/schema_dumper"
11
12
  require "active_record/connection_adapters/sqlite3/schema_statements"
12
13
 
13
- gem "sqlite3", "~> 1.4"
14
+ gem "sqlite3", ">= 1.4"
14
15
  require "sqlite3"
15
16
 
16
17
  module ActiveRecord
17
18
  module ConnectionHandling # :nodoc:
18
- def sqlite3_connection(config)
19
- config = config.symbolize_keys
20
-
21
- # Require database.
22
- unless config[:database]
23
- raise ArgumentError, "No database file specified. Missing argument: database"
24
- end
25
-
26
- # Allow database path relative to Rails.root, but only if the database
27
- # path is not the special path that tells sqlite to build a database only
28
- # in memory.
29
- if ":memory:" != config[:database] && !config[:database].to_s.start_with?("file:")
30
- config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
31
- dirname = File.dirname(config[:database])
32
- Dir.mkdir(dirname) unless File.directory?(dirname)
33
- end
34
-
35
- db = SQLite3::Database.new(
36
- config[:database].to_s,
37
- config.merge(results_as_hash: true)
38
- )
19
+ def sqlite3_adapter_class
20
+ ConnectionAdapters::SQLite3Adapter
21
+ end
39
22
 
40
- ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
41
- rescue Errno::ENOENT => error
42
- if error.message.include?("No such file or directory")
43
- raise ActiveRecord::NoDatabaseError
44
- else
45
- raise
46
- end
23
+ def sqlite3_connection(config)
24
+ sqlite3_adapter_class.new(config)
47
25
  end
48
26
  end
49
27
 
50
- module ConnectionAdapters #:nodoc:
28
+ module ConnectionAdapters # :nodoc:
29
+ # = Active Record SQLite3 Adapter
30
+ #
51
31
  # The SQLite3 adapter works with the sqlite3-ruby drivers
52
32
  # (available as gem from https://rubygems.org/gems/sqlite3).
53
33
  #
@@ -57,10 +37,42 @@ module ActiveRecord
57
37
  class SQLite3Adapter < AbstractAdapter
58
38
  ADAPTER_NAME = "SQLite"
59
39
 
40
+ class << self
41
+ def new_client(config)
42
+ ::SQLite3::Database.new(config[:database].to_s, config)
43
+ rescue Errno::ENOENT => error
44
+ if error.message.include?("No such file or directory")
45
+ raise ActiveRecord::NoDatabaseError
46
+ else
47
+ raise
48
+ end
49
+ end
50
+
51
+ def dbconsole(config, options = {})
52
+ args = []
53
+
54
+ args << "-#{options[:mode]}" if options[:mode]
55
+ args << "-header" if options[:header]
56
+ args << File.expand_path(config.database, Rails.respond_to?(:root) ? Rails.root : nil)
57
+
58
+ find_cmd_and_exec("sqlite3", *args)
59
+ end
60
+ end
61
+
60
62
  include SQLite3::Quoting
61
63
  include SQLite3::SchemaStatements
62
64
  include SQLite3::DatabaseStatements
63
65
 
66
+ ##
67
+ # :singleton-method:
68
+ # Configure the SQLite3Adapter to be used in a strict strings mode.
69
+ # This will disable double-quoted string literals, because otherwise typos can silently go unnoticed.
70
+ # For example, it is possible to create an index for a non existing column.
71
+ # If you wish to enable this mode you can add the following line to your application.rb file:
72
+ #
73
+ # config.active_record.sqlite3_adapter_strict_strings_by_default = true
74
+ class_attribute :strict_strings_by_default, default: false
75
+
64
76
  NATIVE_DATABASE_TYPES = {
65
77
  primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
66
78
  string: { name: "varchar" },
@@ -77,25 +89,48 @@ module ActiveRecord
77
89
  }
78
90
 
79
91
  class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
92
+ alias reset clear
93
+
80
94
  private
81
95
  def dealloc(stmt)
82
96
  stmt.close unless stmt.closed?
83
97
  end
84
98
  end
85
99
 
86
- def initialize(connection, logger, connection_options, config)
87
- super(connection, logger, config)
88
- configure_connection
89
- end
100
+ def initialize(...)
101
+ super
90
102
 
91
- def self.database_exists?(config)
92
- config = config.symbolize_keys
93
- if config[:database] == ":memory:"
94
- true
103
+ @memory_database = false
104
+ case @config[:database].to_s
105
+ when ""
106
+ raise ArgumentError, "No database file specified. Missing argument: database"
107
+ when ":memory:"
108
+ @memory_database = true
109
+ when /\Afile:/
95
110
  else
96
- database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
97
- File.exist?(database_file)
111
+ # Otherwise we have a path relative to Rails.root
112
+ @config[:database] = File.expand_path(@config[:database], Rails.root) if defined?(Rails.root)
113
+ dirname = File.dirname(@config[:database])
114
+ unless File.directory?(dirname)
115
+ begin
116
+ Dir.mkdir(dirname)
117
+ rescue Errno::ENOENT => error
118
+ if error.message.include?("No such file or directory")
119
+ raise ActiveRecord::NoDatabaseError.new(connection_pool: @pool)
120
+ else
121
+ raise
122
+ end
123
+ end
124
+ end
98
125
  end
126
+
127
+ @config[:strict] = ConnectionAdapters::SQLite3Adapter.strict_strings_by_default unless @config.key?(:strict)
128
+ @connection_parameters = @config.merge(database: @config[:database].to_s, results_as_hash: true)
129
+ @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
130
+ end
131
+
132
+ def database_exists?
133
+ @config[:database] == ":memory:" || File.exist?(@config[:database].to_s)
99
134
  end
100
135
 
101
136
  def supports_ddl_transactions?
@@ -146,6 +181,10 @@ module ActiveRecord
146
181
  database_version >= "3.8.3"
147
182
  end
148
183
 
184
+ def supports_insert_returning?
185
+ database_version >= "3.35.0"
186
+ end
187
+
149
188
  def supports_insert_on_conflict?
150
189
  database_version >= "3.24.0"
151
190
  end
@@ -153,33 +192,40 @@ module ActiveRecord
153
192
  alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
154
193
  alias supports_insert_conflict_target? supports_insert_on_conflict?
155
194
 
195
+ def supports_concurrent_connections?
196
+ !@memory_database
197
+ end
198
+
156
199
  def active?
157
- !@connection.closed?
200
+ @raw_connection && !@raw_connection.closed?
158
201
  end
159
202
 
160
- def reconnect!
161
- super
162
- connect if @connection.closed?
203
+ def return_value_after_insert?(column) # :nodoc:
204
+ column.auto_populated?
163
205
  end
164
206
 
207
+ alias :reset! :reconnect!
208
+
165
209
  # Disconnects from the database if already connected. Otherwise, this
166
210
  # method does nothing.
167
211
  def disconnect!
168
212
  super
169
- @connection.close rescue nil
213
+
214
+ @raw_connection&.close rescue nil
215
+ @raw_connection = nil
170
216
  end
171
217
 
172
218
  def supports_index_sort_order?
173
219
  true
174
220
  end
175
221
 
176
- def native_database_types #:nodoc:
222
+ def native_database_types # :nodoc:
177
223
  NATIVE_DATABASE_TYPES
178
224
  end
179
225
 
180
- # Returns the current database encoding format as a string, eg: 'UTF-8'
226
+ # Returns the current database encoding format as a string, e.g. 'UTF-8'
181
227
  def encoding
182
- @connection.encoding.to_s
228
+ any_raw_connection.encoding.to_s
183
229
  end
184
230
 
185
231
  def supports_explain?
@@ -206,6 +252,16 @@ module ActiveRecord
206
252
  end
207
253
  end
208
254
 
255
+ def check_all_foreign_keys_valid! # :nodoc:
256
+ sql = "PRAGMA foreign_key_check"
257
+ result = execute(sql)
258
+
259
+ unless result.blank?
260
+ tables = result.map { |row| row["table"] }
261
+ raise ActiveRecord::StatementInvalid.new("Foreign key violations found: #{tables.join(", ")}", sql: sql)
262
+ end
263
+ end
264
+
209
265
  # SCHEMA STATEMENTS ========================================
210
266
 
211
267
  def primary_keys(table_name) # :nodoc:
@@ -225,14 +281,15 @@ module ActiveRecord
225
281
  #
226
282
  # Example:
227
283
  # rename_table('octopuses', 'octopi')
228
- def rename_table(table_name, new_name)
284
+ def rename_table(table_name, new_name, **options)
285
+ validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
229
286
  schema_cache.clear_data_source_cache!(table_name.to_s)
230
287
  schema_cache.clear_data_source_cache!(new_name.to_s)
231
288
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
232
- rename_table_indexes(table_name, new_name)
289
+ rename_table_indexes(table_name, new_name, **options)
233
290
  end
234
291
 
235
- def add_column(table_name, column_name, type, **options) #:nodoc:
292
+ def add_column(table_name, column_name, type, **options) # :nodoc:
236
293
  if invalid_alter_table_type?(type, options)
237
294
  alter_table(table_name) do |definition|
238
295
  definition.column(column_name, type, **options)
@@ -242,16 +299,24 @@ module ActiveRecord
242
299
  end
243
300
  end
244
301
 
245
- def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
302
+ def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
246
303
  alter_table(table_name) do |definition|
247
304
  definition.remove_column column_name
248
- definition.foreign_keys.delete_if do |_, fk_options|
249
- fk_options[:column] == column_name.to_s
305
+ definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
306
+ end
307
+ end
308
+
309
+ def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
310
+ alter_table(table_name) do |definition|
311
+ column_names.each do |column_name|
312
+ definition.remove_column column_name
250
313
  end
314
+ column_names = column_names.map(&:to_s)
315
+ definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
251
316
  end
252
317
  end
253
318
 
254
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
319
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
255
320
  default = extract_new_default_value(default_or_changes)
256
321
 
257
322
  alter_table(table_name) do |definition|
@@ -259,44 +324,65 @@ module ActiveRecord
259
324
  end
260
325
  end
261
326
 
262
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
327
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
328
+ validate_change_column_null_argument!(null)
329
+
263
330
  unless null || default.nil?
264
- exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
331
+ internal_exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
265
332
  end
266
333
  alter_table(table_name) do |definition|
267
334
  definition[column_name].null = null
268
335
  end
269
336
  end
270
337
 
271
- def change_column(table_name, column_name, type, **options) #:nodoc:
338
+ def change_column(table_name, column_name, type, **options) # :nodoc:
272
339
  alter_table(table_name) do |definition|
273
- definition[column_name].instance_eval do
274
- self.type = aliased_types(type.to_s, type)
275
- self.options.merge!(options)
276
- end
340
+ definition.change_column(column_name, type, **options)
277
341
  end
278
342
  end
279
343
 
280
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
344
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
281
345
  column = column_for(table_name, column_name)
282
346
  alter_table(table_name, rename: { column.name => new_column_name.to_s })
283
347
  rename_column_indexes(table_name, column.name, new_column_name)
284
348
  end
285
349
 
350
+ def add_timestamps(table_name, **options)
351
+ options[:null] = false if options[:null].nil?
352
+
353
+ if !options.key?(:precision)
354
+ options[:precision] = 6
355
+ end
356
+
357
+ alter_table(table_name) do |definition|
358
+ definition.column :created_at, :datetime, **options
359
+ definition.column :updated_at, :datetime, **options
360
+ end
361
+ end
362
+
286
363
  def add_reference(table_name, ref_name, **options) # :nodoc:
287
364
  super(table_name, ref_name, type: :integer, **options)
288
365
  end
289
366
  alias :add_belongs_to :add_reference
290
367
 
291
368
  def foreign_keys(table_name)
292
- fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
293
- fk_info.map do |row|
369
+ # SQLite returns 1 row for each column of composite foreign keys.
370
+ fk_info = internal_exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
371
+ grouped_fk = fk_info.group_by { |row| row["id"] }.values.each { |group| group.sort_by! { |row| row["seq"] } }
372
+ grouped_fk.map do |group|
373
+ row = group.first
294
374
  options = {
295
- column: row["from"],
296
- primary_key: row["to"],
297
375
  on_delete: extract_foreign_key_action(row["on_delete"]),
298
376
  on_update: extract_foreign_key_action(row["on_update"])
299
377
  }
378
+
379
+ if group.one?
380
+ options[:column] = row["from"]
381
+ options[:primary_key] = row["to"]
382
+ else
383
+ options[:column] = group.map { |row| row["from"] }
384
+ options[:primary_key] = group.map { |row| row["to"] }
385
+ end
300
386
  ForeignKeyDefinition.new(table_name, row["table"], options)
301
387
  end
302
388
  end
@@ -308,10 +394,15 @@ module ActiveRecord
308
394
  sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
309
395
  elsif insert.update_duplicates?
310
396
  sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
311
- sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
312
- sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
397
+ if insert.raw_update_sql?
398
+ sql << insert.raw_update_sql
399
+ else
400
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
401
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
402
+ end
313
403
  end
314
404
 
405
+ sql << " RETURNING #{insert.returning}" if insert.returning
315
406
  sql
316
407
  end
317
408
 
@@ -319,8 +410,12 @@ module ActiveRecord
319
410
  @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
320
411
  end
321
412
 
413
+ def use_insert_returning?
414
+ @use_insert_returning
415
+ end
416
+
322
417
  def get_database_version # :nodoc:
323
- SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
418
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
324
419
  end
325
420
 
326
421
  def check_version # :nodoc:
@@ -329,6 +424,28 @@ module ActiveRecord
329
424
  end
330
425
  end
331
426
 
427
+ class SQLite3Integer < Type::Integer # :nodoc:
428
+ private
429
+ def _limit
430
+ # INTEGER storage class can be stored 8 bytes value.
431
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
432
+ limit || 8
433
+ end
434
+ end
435
+
436
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
437
+
438
+ class << self
439
+ private
440
+ def initialize_type_map(m)
441
+ super
442
+ register_class_with_limit m, %r(int)i, SQLite3Integer
443
+ end
444
+ end
445
+
446
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
447
+ EXTENDED_TYPE_MAPS = Concurrent::Map.new
448
+
332
449
  private
333
450
  # See https://www.sqlite.org/limits.html,
334
451
  # the default value is 999 when not configured.
@@ -336,18 +453,44 @@ module ActiveRecord
336
453
  999
337
454
  end
338
455
 
339
- def initialize_type_map(m = type_map)
340
- super
341
- register_class_with_limit m, %r(int)i, SQLite3Integer
342
- end
343
-
344
456
  def table_structure(table_name)
345
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
457
+ structure = internal_exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
346
458
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
347
459
  table_structure_with_collation(table_name, structure)
348
460
  end
349
461
  alias column_definitions table_structure
350
462
 
463
+ def extract_value_from_default(default)
464
+ case default
465
+ when /^null$/i
466
+ nil
467
+ # Quoted types
468
+ when /^'([^|]*)'$/m
469
+ $1.gsub("''", "'")
470
+ # Quoted types
471
+ when /^"([^|]*)"$/m
472
+ $1.gsub('""', '"')
473
+ # Numeric types
474
+ when /\A-?\d+(\.\d*)?\z/
475
+ $&
476
+ # Binary columns
477
+ when /x'(.*)'/
478
+ [ $1 ].pack("H*")
479
+ else
480
+ # Anything else is blank or some function
481
+ # and we can't know the value of that, so return nil.
482
+ nil
483
+ end
484
+ end
485
+
486
+ def extract_default_function(default_value, default)
487
+ default if has_default_function?(default_value, default)
488
+ end
489
+
490
+ def has_default_function?(default_value, default)
491
+ !default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP|\|\|}.match?(default)
492
+ end
493
+
351
494
  # See: https://www.sqlite.org/lang_altertable.html
352
495
  # SQLite has an additional restriction on the ALTER TABLE statement
353
496
  def invalid_alter_table_type?(type, options)
@@ -408,12 +551,27 @@ module ActiveRecord
408
551
  options[:rename][column.name.to_sym] ||
409
552
  column.name) : column.name
410
553
 
411
- @definition.column(column_name, column.type,
412
- limit: column.limit, default: column.default,
413
- precision: column.precision, scale: column.scale,
414
- null: column.null, collation: column.collation,
554
+ if column.has_default?
555
+ type = lookup_cast_type_from_column(column)
556
+ default = type.deserialize(column.default)
557
+ default = -> { column.default_function } if default.nil?
558
+ end
559
+
560
+ column_options = {
561
+ limit: column.limit,
562
+ precision: column.precision,
563
+ scale: column.scale,
564
+ null: column.null,
565
+ collation: column.collation,
415
566
  primary_key: column_name == from_primary_key
416
- )
567
+ }
568
+
569
+ unless column.auto_increment?
570
+ column_options[:default] = default
571
+ end
572
+
573
+ column_type = column.bigint? ? :bigint : column.type
574
+ @definition.column(column_name, column_type, **column_options)
417
575
  end
418
576
 
419
577
  yield @definition if block_given?
@@ -446,6 +604,7 @@ module ActiveRecord
446
604
  options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
447
605
  options[:unique] = true if index.unique
448
606
  options[:where] = index.where if index.where
607
+ options[:order] = index.orders if index.orders
449
608
  add_index(to, columns, **options)
450
609
  end
451
610
  end
@@ -460,7 +619,7 @@ module ActiveRecord
460
619
  quoted_columns = columns.map { |col| quote_column_name(col) } * ","
461
620
  quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
462
621
 
463
- exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
622
+ internal_exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
464
623
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
465
624
  end
466
625
 
@@ -470,22 +629,24 @@ module ActiveRecord
470
629
  # Older versions of SQLite return:
471
630
  # column *column_name* is not unique
472
631
  if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
473
- RecordNotUnique.new(message, sql: sql, binds: binds)
632
+ RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
474
633
  elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
475
- NotNullViolation.new(message, sql: sql, binds: binds)
634
+ NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
476
635
  elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
477
- InvalidForeignKey.new(message, sql: sql, binds: binds)
636
+ InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
478
637
  elsif exception.message.match?(/called on a closed database/i)
479
- ConnectionNotEstablished.new(exception)
638
+ ConnectionNotEstablished.new(exception, connection_pool: @pool)
480
639
  else
481
640
  super
482
641
  end
483
642
  end
484
643
 
485
- COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
644
+ COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i
645
+ PRIMARY_KEY_AUTOINCREMENT_REGEX = /.*"(\w+)".+PRIMARY KEY AUTOINCREMENT/i
486
646
 
487
647
  def table_structure_with_collation(table_name, basic_structure)
488
648
  collation_hash = {}
649
+ auto_increments = {}
489
650
  sql = <<~SQL
490
651
  SELECT sql FROM
491
652
  (SELECT * FROM sqlite_master UNION ALL
@@ -507,6 +668,7 @@ module ActiveRecord
507
668
  # This regex will match the column name and collation type and will save
508
669
  # the value in $1 and $2 respectively.
509
670
  collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
671
+ auto_increments[$1] = true if PRIMARY_KEY_AUTOINCREMENT_REGEX =~ column_string
510
672
  end
511
673
 
512
674
  basic_structure.map do |column|
@@ -516,6 +678,10 @@ module ActiveRecord
516
678
  column["collation"] = collation_hash[column_name]
517
679
  end
518
680
 
681
+ if auto_increments.has_key?(column_name)
682
+ column["auto_increment"] = true
683
+ end
684
+
519
685
  column
520
686
  end
521
687
  else
@@ -532,29 +698,55 @@ module ActiveRecord
532
698
  end
533
699
 
534
700
  def connect
535
- @connection = ::SQLite3::Database.new(
536
- @config[:database].to_s,
537
- @config.merge(results_as_hash: true)
538
- )
539
- configure_connection
701
+ @raw_connection = self.class.new_client(@connection_parameters)
702
+ rescue ConnectionNotEstablished => ex
703
+ raise ex.set_pool(@pool)
540
704
  end
541
705
 
542
- def configure_connection
543
- @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
544
-
545
- execute("PRAGMA foreign_keys = ON", "SCHEMA")
706
+ def reconnect
707
+ if active?
708
+ @raw_connection.rollback rescue nil
709
+ else
710
+ connect
711
+ end
546
712
  end
547
713
 
548
- class SQLite3Integer < Type::Integer # :nodoc:
549
- private
550
- def _limit
551
- # INTEGER storage class can be stored 8 bytes value.
552
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
553
- limit || 8
714
+ def configure_connection
715
+ if @config[:timeout] && @config[:retries]
716
+ raise ArgumentError, "Cannot specify both timeout and retries arguments"
717
+ elsif @config[:timeout]
718
+ @raw_connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout]))
719
+ elsif @config[:retries]
720
+ retries = self.class.type_cast_config_to_integer(@config[:retries])
721
+ raw_connection.busy_handler do |count|
722
+ count <= retries
554
723
  end
555
- end
724
+ end
556
725
 
557
- ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
726
+ # Enforce foreign key constraints
727
+ # https://www.sqlite.org/pragma.html#pragma_foreign_keys
728
+ # https://www.sqlite.org/foreignkeys.html
729
+ raw_execute("PRAGMA foreign_keys = ON", "SCHEMA")
730
+ unless @memory_database
731
+ # Journal mode WAL allows for greater concurrency (many readers + one writer)
732
+ # https://www.sqlite.org/pragma.html#pragma_journal_mode
733
+ raw_execute("PRAGMA journal_mode = WAL", "SCHEMA")
734
+ # Set more relaxed level of database durability
735
+ # 2 = "FULL" (sync on every write), 1 = "NORMAL" (sync every 1000 written pages) and 0 = "NONE"
736
+ # https://www.sqlite.org/pragma.html#pragma_synchronous
737
+ raw_execute("PRAGMA synchronous = NORMAL", "SCHEMA")
738
+ # Set the global memory map so all processes can share some data
739
+ # https://www.sqlite.org/pragma.html#pragma_mmap_size
740
+ # https://www.sqlite.org/mmap.html
741
+ raw_execute("PRAGMA mmap_size = #{128.megabytes}", "SCHEMA")
742
+ end
743
+ # Impose a limit on the WAL file to prevent unlimited growth
744
+ # https://www.sqlite.org/pragma.html#pragma_journal_size_limit
745
+ raw_execute("PRAGMA journal_size_limit = #{64.megabytes}", "SCHEMA")
746
+ # Set the local connection cache to 2000 pages
747
+ # https://www.sqlite.org/pragma.html#pragma_cache_size
748
+ raw_execute("PRAGMA cache_size = 2000", "SCHEMA")
749
+ end
558
750
  end
559
751
  ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
560
752
  end
@@ -42,6 +42,13 @@ module ActiveRecord
42
42
  cache.clear
43
43
  end
44
44
 
45
+ # Clear the pool without deallocating; this is only safe when we
46
+ # know the server has independently deallocated all statements
47
+ # (e.g. due to a reconnect, or a DISCARD ALL)
48
+ def reset
49
+ cache.clear
50
+ end
51
+
45
52
  def delete(key)
46
53
  dealloc cache[key]
47
54
  cache.delete(key)