activerecord 4.2.11.1 → 6.0.3.5

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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +721 -1522
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +14 -13
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +266 -251
  9. data/lib/active_record/association_relation.rb +20 -13
  10. data/lib/active_record/associations/alias_tracker.rb +29 -36
  11. data/lib/active_record/associations/association.rb +128 -57
  12. data/lib/active_record/associations/association_scope.rb +103 -132
  13. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  15. data/lib/active_record/associations/builder/association.rb +27 -40
  16. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  17. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -66
  19. data/lib/active_record/associations/builder/has_many.rb +8 -4
  20. data/lib/active_record/associations/builder/has_one.rb +46 -5
  21. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  22. data/lib/active_record/associations/collection_association.rb +136 -288
  23. data/lib/active_record/associations/collection_proxy.rb +241 -147
  24. data/lib/active_record/associations/foreign_association.rb +10 -1
  25. data/lib/active_record/associations/has_many_association.rb +34 -98
  26. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  27. data/lib/active_record/associations/has_one_association.rb +61 -49
  28. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  29. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  30. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  31. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  32. data/lib/active_record/associations/join_dependency.rb +149 -166
  33. data/lib/active_record/associations/preloader/association.rb +90 -123
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  35. data/lib/active_record/associations/preloader.rb +90 -93
  36. data/lib/active_record/associations/singular_association.rb +18 -39
  37. data/lib/active_record/associations/through_association.rb +38 -18
  38. data/lib/active_record/associations.rb +1737 -1597
  39. data/lib/active_record/attribute_assignment.rb +57 -185
  40. data/lib/active_record/attribute_decorators.rb +39 -17
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  43. data/lib/active_record/attribute_methods/primary_key.rb +90 -84
  44. data/lib/active_record/attribute_methods/query.rb +6 -5
  45. data/lib/active_record/attribute_methods/read.rb +20 -77
  46. data/lib/active_record/attribute_methods/serialization.rb +40 -21
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +57 -37
  48. data/lib/active_record/attribute_methods/write.rb +32 -55
  49. data/lib/active_record/attribute_methods.rb +120 -135
  50. data/lib/active_record/attributes.rb +213 -82
  51. data/lib/active_record/autosave_association.rb +97 -41
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +101 -76
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +23 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +804 -297
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +240 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +371 -242
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +694 -256
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +473 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +507 -639
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -181
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -114
  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 +49 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +51 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -296
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -356
  117. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +299 -349
  127. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  128. data/lib/active_record/connection_handling.rb +167 -41
  129. data/lib/active_record/core.rb +252 -230
  130. data/lib/active_record/counter_cache.rb +70 -49
  131. data/lib/active_record/database_configurations/database_config.rb +37 -0
  132. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  133. data/lib/active_record/database_configurations/url_config.rb +78 -0
  134. data/lib/active_record/database_configurations.rb +233 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -106
  137. data/lib/active_record/enum.rb +163 -86
  138. data/lib/active_record/errors.rb +188 -53
  139. data/lib/active_record/explain.rb +22 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +10 -5
  142. data/lib/active_record/fixture_set/file.rb +35 -9
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +152 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  147. data/lib/active_record/fixtures.rb +227 -501
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -115
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +123 -29
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +86 -96
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +76 -33
  158. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector.rb +74 -0
  161. data/lib/active_record/migration/command_recorder.rb +166 -91
  162. data/lib/active_record/migration/compatibility.rb +244 -0
  163. data/lib/active_record/migration/join_table.rb +8 -7
  164. data/lib/active_record/migration.rb +623 -305
  165. data/lib/active_record/model_schema.rb +313 -112
  166. data/lib/active_record/nested_attributes.rb +263 -223
  167. data/lib/active_record/no_touching.rb +15 -2
  168. data/lib/active_record/null_relation.rb +24 -38
  169. data/lib/active_record/persistence.rb +557 -126
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +44 -30
  172. data/lib/active_record/railtie.rb +143 -44
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +331 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +430 -281
  179. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  180. data/lib/active_record/relation/batches.rb +206 -55
  181. data/lib/active_record/relation/calculations.rb +268 -254
  182. data/lib/active_record/relation/delegation.rb +75 -84
  183. data/lib/active_record/relation/finder_methods.rb +285 -241
  184. data/lib/active_record/relation/from_clause.rb +30 -0
  185. data/lib/active_record/relation/merger.rb +78 -88
  186. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  187. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  188. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  189. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  190. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  191. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  192. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  193. data/lib/active_record/relation/predicate_builder.rb +110 -119
  194. data/lib/active_record/relation/query_attribute.rb +50 -0
  195. data/lib/active_record/relation/query_methods.rb +603 -397
  196. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  197. data/lib/active_record/relation/spawn_methods.rb +11 -14
  198. data/lib/active_record/relation/where_clause.rb +189 -0
  199. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  200. data/lib/active_record/relation.rb +530 -341
  201. data/lib/active_record/result.rb +79 -43
  202. data/lib/active_record/runtime_registry.rb +6 -4
  203. data/lib/active_record/sanitization.rb +144 -121
  204. data/lib/active_record/schema.rb +21 -24
  205. data/lib/active_record/schema_dumper.rb +112 -93
  206. data/lib/active_record/schema_migration.rb +24 -17
  207. data/lib/active_record/scoping/default.rb +98 -83
  208. data/lib/active_record/scoping/named.rb +86 -33
  209. data/lib/active_record/scoping.rb +45 -27
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +5 -5
  212. data/lib/active_record/statement_cache.rb +73 -36
  213. data/lib/active_record/store.rb +127 -42
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +90 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -100
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +80 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +225 -0
  222. data/lib/active_record/timestamp.rb +86 -41
  223. data/lib/active_record/touch_later.rb +65 -0
  224. data/lib/active_record/transactions.rb +223 -157
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  227. data/lib/active_record/type/date.rb +4 -45
  228. data/lib/active_record/type/date_time.rb +4 -49
  229. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  230. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  231. data/lib/active_record/type/internal/timezone.rb +17 -0
  232. data/lib/active_record/type/json.rb +30 -0
  233. data/lib/active_record/type/serialized.rb +23 -15
  234. data/lib/active_record/type/text.rb +2 -2
  235. data/lib/active_record/type/time.rb +11 -16
  236. data/lib/active_record/type/type_map.rb +16 -19
  237. data/lib/active_record/type/unsigned_integer.rb +9 -8
  238. data/lib/active_record/type.rb +77 -23
  239. data/lib/active_record/type_caster/connection.rb +34 -0
  240. data/lib/active_record/type_caster/map.rb +20 -0
  241. data/lib/active_record/type_caster.rb +9 -0
  242. data/lib/active_record/validations/absence.rb +25 -0
  243. data/lib/active_record/validations/associated.rb +12 -4
  244. data/lib/active_record/validations/length.rb +26 -0
  245. data/lib/active_record/validations/presence.rb +14 -13
  246. data/lib/active_record/validations/uniqueness.rb +42 -55
  247. data/lib/active_record/validations.rb +38 -35
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/active_record.rb +42 -22
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes/attribute.rb +37 -0
  252. data/lib/arel/attributes.rb +22 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes/and.rb +32 -0
  266. data/lib/arel/nodes/ascending.rb +23 -0
  267. data/lib/arel/nodes/binary.rb +52 -0
  268. data/lib/arel/nodes/bind_param.rb +36 -0
  269. data/lib/arel/nodes/case.rb +55 -0
  270. data/lib/arel/nodes/casted.rb +50 -0
  271. data/lib/arel/nodes/comment.rb +29 -0
  272. data/lib/arel/nodes/count.rb +12 -0
  273. data/lib/arel/nodes/delete_statement.rb +45 -0
  274. data/lib/arel/nodes/descending.rb +23 -0
  275. data/lib/arel/nodes/equality.rb +18 -0
  276. data/lib/arel/nodes/extract.rb +24 -0
  277. data/lib/arel/nodes/false.rb +16 -0
  278. data/lib/arel/nodes/full_outer_join.rb +8 -0
  279. data/lib/arel/nodes/function.rb +44 -0
  280. data/lib/arel/nodes/grouping.rb +8 -0
  281. data/lib/arel/nodes/in.rb +8 -0
  282. data/lib/arel/nodes/infix_operation.rb +80 -0
  283. data/lib/arel/nodes/inner_join.rb +8 -0
  284. data/lib/arel/nodes/insert_statement.rb +37 -0
  285. data/lib/arel/nodes/join_source.rb +20 -0
  286. data/lib/arel/nodes/matches.rb +18 -0
  287. data/lib/arel/nodes/named_function.rb +23 -0
  288. data/lib/arel/nodes/node.rb +50 -0
  289. data/lib/arel/nodes/node_expression.rb +13 -0
  290. data/lib/arel/nodes/outer_join.rb +8 -0
  291. data/lib/arel/nodes/over.rb +15 -0
  292. data/lib/arel/nodes/regexp.rb +16 -0
  293. data/lib/arel/nodes/right_outer_join.rb +8 -0
  294. data/lib/arel/nodes/select_core.rb +67 -0
  295. data/lib/arel/nodes/select_statement.rb +41 -0
  296. data/lib/arel/nodes/sql_literal.rb +16 -0
  297. data/lib/arel/nodes/string_join.rb +11 -0
  298. data/lib/arel/nodes/table_alias.rb +27 -0
  299. data/lib/arel/nodes/terminal.rb +16 -0
  300. data/lib/arel/nodes/true.rb +16 -0
  301. data/lib/arel/nodes/unary.rb +45 -0
  302. data/lib/arel/nodes/unary_operation.rb +20 -0
  303. data/lib/arel/nodes/unqualified_column.rb +22 -0
  304. data/lib/arel/nodes/update_statement.rb +41 -0
  305. data/lib/arel/nodes/values_list.rb +9 -0
  306. data/lib/arel/nodes/window.rb +126 -0
  307. data/lib/arel/nodes/with.rb +11 -0
  308. data/lib/arel/nodes.rb +68 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +256 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors/depth_first.rb +203 -0
  316. data/lib/arel/visitors/dot.rb +296 -0
  317. data/lib/arel/visitors/ibm_db.rb +34 -0
  318. data/lib/arel/visitors/informix.rb +62 -0
  319. data/lib/arel/visitors/mssql.rb +156 -0
  320. data/lib/arel/visitors/mysql.rb +83 -0
  321. data/lib/arel/visitors/oracle.rb +158 -0
  322. data/lib/arel/visitors/oracle12.rb +65 -0
  323. data/lib/arel/visitors/postgresql.rb +109 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +888 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/visitors/where_sql.rb +22 -0
  328. data/lib/arel/visitors.rb +20 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/arel.rb +62 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
  334. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  335. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  336. data/lib/rails/generators/active_record/migration.rb +30 -1
  337. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. data/lib/rails/generators/active_record.rb +7 -5
  341. metadata +168 -59
  342. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  343. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  344. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  345. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  346. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  347. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  348. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  349. data/lib/active_record/attribute.rb +0 -163
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -31
  363. data/lib/active_record/type/decimal.rb +0 -64
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -59
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -40
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -110
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,14 +1,23 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
- require 'arel/visitors/bind_visitor'
1
+ # frozen_string_literal: true
4
2
 
5
- gem 'sqlite3', '~> 1.3.6'
6
- require 'sqlite3'
3
+ require "active_record/connection_adapters/abstract_adapter"
4
+ require "active_record/connection_adapters/statement_pool"
5
+ require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
6
+ require "active_record/connection_adapters/sqlite3/quoting"
7
+ require "active_record/connection_adapters/sqlite3/database_statements"
8
+ require "active_record/connection_adapters/sqlite3/schema_creation"
9
+ require "active_record/connection_adapters/sqlite3/schema_definitions"
10
+ require "active_record/connection_adapters/sqlite3/schema_dumper"
11
+ require "active_record/connection_adapters/sqlite3/schema_statements"
12
+
13
+ gem "sqlite3", "~> 1.4"
14
+ require "sqlite3"
7
15
 
8
16
  module ActiveRecord
9
17
  module ConnectionHandling # :nodoc:
10
- # sqlite3 adapter reuses sqlite_connection.
11
18
  def sqlite3_connection(config)
19
+ config = config.symbolize_keys
20
+
12
21
  # Require database.
13
22
  unless config[:database]
14
23
  raise ArgumentError, "No database file specified. Missing argument: database"
@@ -17,7 +26,7 @@ module ActiveRecord
17
26
  # Allow database path relative to Rails.root, but only if the database
18
27
  # path is not the special path that tells sqlite to build a database only
19
28
  # in memory.
20
- if ':memory:' != config[:database]
29
+ if ":memory:" != config[:database]
21
30
  config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
22
31
  dirname = File.dirname(config[:database])
23
32
  Dir.mkdir(dirname) unless File.directory?(dirname)
@@ -25,15 +34,13 @@ module ActiveRecord
25
34
 
26
35
  db = SQLite3::Database.new(
27
36
  config[:database].to_s,
28
- :results_as_hash => true
37
+ config.merge(results_as_hash: true)
29
38
  )
30
39
 
31
- db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
32
-
33
40
  ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
34
41
  rescue Errno::ENOENT => error
35
42
  if error.message.include?("No such file or directory")
36
- raise ActiveRecord::NoDatabaseError.new(error.message, error)
43
+ raise ActiveRecord::NoDatabaseError
37
44
  else
38
45
  raise
39
46
  end
@@ -41,15 +48,6 @@ module ActiveRecord
41
48
  end
42
49
 
43
50
  module ConnectionAdapters #:nodoc:
44
- class SQLite3Binary < Type::Binary # :nodoc:
45
- def cast_value(value)
46
- if value.encoding != Encoding::ASCII_8BIT
47
- value = value.force_encoding(Encoding::ASCII_8BIT)
48
- end
49
- value
50
- end
51
- end
52
-
53
51
  # The SQLite3 adapter works SQLite 3.6.16 or newer
54
52
  # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
55
53
  #
@@ -57,11 +55,14 @@ module ActiveRecord
57
55
  #
58
56
  # * <tt>:database</tt> - Path to the database file.
59
57
  class SQLite3Adapter < AbstractAdapter
60
- ADAPTER_NAME = 'SQLite'.freeze
61
- include Savepoints
58
+ ADAPTER_NAME = "SQLite"
59
+
60
+ include SQLite3::Quoting
61
+ include SQLite3::SchemaStatements
62
+ include SQLite3::DatabaseStatements
62
63
 
63
64
  NATIVE_DATABASE_TYPES = {
64
- primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
65
+ primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
65
66
  string: { name: "varchar" },
66
67
  text: { name: "text" },
67
68
  integer: { name: "integer" },
@@ -71,58 +72,39 @@ module ActiveRecord
71
72
  time: { name: "time" },
72
73
  date: { name: "date" },
73
74
  binary: { name: "blob" },
74
- boolean: { name: "boolean" }
75
+ boolean: { name: "boolean" },
76
+ json: { name: "json" },
75
77
  }
76
78
 
77
- class StatementPool < ConnectionAdapters::StatementPool
78
- def initialize(connection, max)
79
- super
80
- @cache = Hash.new { |h,pid| h[pid] = {} }
81
- end
82
-
83
- def each(&block); cache.each(&block); end
84
- def key?(key); cache.key?(key); end
85
- def [](key); cache[key]; end
86
- def length; cache.length; end
87
-
88
- def []=(sql, key)
89
- while @max <= cache.size
90
- dealloc(cache.shift.last[:stmt])
91
- end
92
- cache[sql] = key
79
+ def self.represent_boolean_as_integer=(value) # :nodoc:
80
+ if value == false
81
+ raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
93
82
  end
94
83
 
95
- def clear
96
- cache.each_value do |hash|
97
- dealloc hash[:stmt]
98
- end
99
- cache.clear
100
- end
84
+ ActiveSupport::Deprecation.warn(
85
+ "`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
86
+ )
87
+ end
101
88
 
89
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
102
90
  private
103
- def cache
104
- @cache[$$]
105
- end
106
-
107
- def dealloc(stmt)
108
- stmt.close unless stmt.closed?
109
- end
91
+ def dealloc(stmt)
92
+ stmt.close unless stmt.closed?
93
+ end
110
94
  end
111
95
 
112
96
  def initialize(connection, logger, connection_options, config)
113
- super(connection, logger)
114
-
115
- @active = nil
116
- @statements = StatementPool.new(@connection,
117
- self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
118
- @config = config
119
-
120
- @visitor = Arel::Visitors::SQLite.new self
97
+ super(connection, logger, config)
98
+ configure_connection
99
+ end
121
100
 
122
- if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
123
- @prepared_statements = true
101
+ def self.database_exists?(config)
102
+ config = config.symbolize_keys
103
+ if config[:database] == ":memory:"
104
+ true
124
105
  else
125
- @prepared_statements = false
106
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
107
+ File.exist?(database_file)
126
108
  end
127
109
  end
128
110
 
@@ -135,55 +117,66 @@ module ActiveRecord
135
117
  end
136
118
 
137
119
  def supports_partial_index?
138
- sqlite_version >= '3.8.0'
120
+ true
121
+ end
122
+
123
+ def supports_expression_index?
124
+ database_version >= "3.9.0"
139
125
  end
140
126
 
141
- # Returns true, since this connection adapter supports prepared statement
142
- # caching.
143
- def supports_statement_cache?
127
+ def requires_reloading?
144
128
  true
145
129
  end
146
130
 
147
- # Returns true, since this connection adapter supports migrations.
148
- def supports_migrations? #:nodoc:
131
+ def supports_foreign_keys?
149
132
  true
150
133
  end
151
134
 
152
- def supports_primary_key? #:nodoc:
135
+ def supports_views?
153
136
  true
154
137
  end
155
138
 
156
- def requires_reloading?
139
+ def supports_datetime_with_precision?
157
140
  true
158
141
  end
159
142
 
160
- def supports_views?
143
+ def supports_json?
161
144
  true
162
145
  end
163
146
 
147
+ def supports_common_table_expressions?
148
+ database_version >= "3.8.3"
149
+ end
150
+
151
+ def supports_insert_on_conflict?
152
+ database_version >= "3.24.0"
153
+ end
154
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
155
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
156
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
157
+
164
158
  def active?
165
- @active != false
159
+ !@connection.closed?
160
+ end
161
+
162
+ def reconnect!
163
+ super
164
+ connect if @connection.closed?
166
165
  end
167
166
 
168
167
  # Disconnects from the database if already connected. Otherwise, this
169
168
  # method does nothing.
170
169
  def disconnect!
171
170
  super
172
- @active = false
173
171
  @connection.close rescue nil
174
172
  end
175
173
 
176
- # Clears the prepared statements cache.
177
- def clear_cache!
178
- @statements.clear
179
- end
180
-
181
174
  def supports_index_sort_order?
182
175
  true
183
176
  end
184
177
 
185
178
  # Returns 62. SQLite supports index names up to 64
186
- # characters. The rest is used by rails internally to perform
179
+ # characters. The rest is used by Rails internally to perform
187
180
  # temporary rename operations
188
181
  def allowed_index_name_length
189
182
  index_name_length - 2
@@ -202,224 +195,43 @@ module ActiveRecord
202
195
  true
203
196
  end
204
197
 
205
- # QUOTING ==================================================
206
-
207
- def _quote(value) # :nodoc:
208
- case value
209
- when Type::Binary::Data
210
- "x'#{value.hex}'"
211
- else
212
- super
213
- end
214
- end
215
-
216
- def _type_cast(value) # :nodoc:
217
- case value
218
- when BigDecimal
219
- value.to_f
220
- when String
221
- if value.encoding == Encoding::ASCII_8BIT
222
- super(value.encode(Encoding::UTF_8))
223
- else
224
- super
225
- end
226
- else
227
- super
228
- end
229
- end
230
-
231
- def quote_string(s) #:nodoc:
232
- @connection.class.quote(s)
198
+ def supports_lazy_transactions?
199
+ true
233
200
  end
234
201
 
235
- def quote_table_name_for_assignment(table, attr)
236
- quote_column_name(attr)
237
- end
202
+ # REFERENTIAL INTEGRITY ====================================
238
203
 
239
- def quote_column_name(name) #:nodoc:
240
- %Q("#{name.to_s.gsub('"', '""')}")
241
- end
204
+ def disable_referential_integrity # :nodoc:
205
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
206
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
242
207
 
243
- # Quote date/time values for use in SQL input. Includes microseconds
244
- # if the value is a Time responding to usec.
245
- def quoted_date(value) #:nodoc:
246
- if value.respond_to?(:usec)
247
- "#{super}.#{sprintf("%06d", value.usec)}"
248
- else
249
- super
208
+ begin
209
+ execute("PRAGMA defer_foreign_keys = ON")
210
+ execute("PRAGMA foreign_keys = OFF")
211
+ yield
212
+ ensure
213
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
214
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
250
215
  end
251
216
  end
252
217
 
253
218
  #--
254
219
  # DATABASE STATEMENTS ======================================
255
220
  #++
256
-
257
221
  def explain(arel, binds = [])
258
222
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
259
- ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
260
- end
261
-
262
- class ExplainPrettyPrinter
263
- # Pretty prints the result of a EXPLAIN QUERY PLAN in a way that resembles
264
- # the output of the SQLite shell:
265
- #
266
- # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
267
- # 0|1|1|SCAN TABLE posts (~100000 rows)
268
- #
269
- def pp(result) # :nodoc:
270
- result.rows.map do |row|
271
- row.join('|')
272
- end.join("\n") + "\n"
273
- end
274
- end
275
-
276
- def exec_query(sql, name = nil, binds = [])
277
- type_casted_binds = binds.map { |col, val|
278
- [col, type_cast(val, col)]
279
- }
280
-
281
- log(sql, name, type_casted_binds) do
282
- # Don't cache statements if they are not prepared
283
- if without_prepared_statement?(binds)
284
- stmt = @connection.prepare(sql)
285
- begin
286
- cols = stmt.columns
287
- records = stmt.to_a
288
- ensure
289
- stmt.close
290
- end
291
- stmt = records
292
- else
293
- cache = @statements[sql] ||= {
294
- :stmt => @connection.prepare(sql)
295
- }
296
- stmt = cache[:stmt]
297
- cols = cache[:cols] ||= stmt.columns
298
- stmt.reset!
299
- stmt.bind_params type_casted_binds.map { |_, val| val }
300
- end
301
-
302
- ActiveRecord::Result.new(cols, stmt.to_a)
303
- end
304
- end
305
-
306
- def exec_delete(sql, name = 'SQL', binds = [])
307
- exec_query(sql, name, binds)
308
- @connection.changes
309
- end
310
- alias :exec_update :exec_delete
311
-
312
- def last_inserted_id(result)
313
- @connection.last_insert_row_id
314
- end
315
-
316
- def execute(sql, name = nil) #:nodoc:
317
- log(sql, name) { @connection.execute(sql) }
318
- end
319
-
320
- def update_sql(sql, name = nil) #:nodoc:
321
- super
322
- @connection.changes
323
- end
324
-
325
- def delete_sql(sql, name = nil) #:nodoc:
326
- sql += " WHERE 1=1" unless sql =~ /WHERE/i
327
- super sql, name
328
- end
329
-
330
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
331
- super
332
- id_value || @connection.last_insert_row_id
333
- end
334
- alias :create :insert_sql
335
-
336
- def select_rows(sql, name = nil, binds = [])
337
- exec_query(sql, name, binds).rows
338
- end
339
-
340
- def begin_db_transaction #:nodoc:
341
- log('begin transaction',nil) { @connection.transaction }
342
- end
343
-
344
- def commit_db_transaction #:nodoc:
345
- log('commit transaction',nil) { @connection.commit }
346
- end
347
-
348
- def exec_rollback_db_transaction #:nodoc:
349
- log('rollback transaction',nil) { @connection.rollback }
223
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
350
224
  end
351
225
 
352
226
  # SCHEMA STATEMENTS ========================================
353
227
 
354
- def tables(name = nil, table_name = nil) #:nodoc:
355
- sql = <<-SQL
356
- SELECT name
357
- FROM sqlite_master
358
- WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
359
- SQL
360
- sql << " AND name = #{quote_table_name(table_name)}" if table_name
361
-
362
- exec_query(sql, 'SCHEMA').map do |row|
363
- row['name']
364
- end
365
- end
366
- alias data_sources tables
367
-
368
- def table_exists?(table_name)
369
- table_name && tables(nil, table_name).any?
370
- end
371
- alias data_source_exists? table_exists?
372
-
373
- # Returns an array of +Column+ objects for the table specified by +table_name+.
374
- def columns(table_name) #:nodoc:
375
- table_structure(table_name).map do |field|
376
- case field["dflt_value"]
377
- when /^null$/i
378
- field["dflt_value"] = nil
379
- when /^'(.*)'$/m
380
- field["dflt_value"] = $1.gsub("''", "'")
381
- when /^"(.*)"$/m
382
- field["dflt_value"] = $1.gsub('""', '"')
383
- end
384
-
385
- sql_type = field['type']
386
- cast_type = lookup_cast_type(sql_type)
387
- new_column(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
388
- end
389
- end
390
-
391
- # Returns an array of indexes for the given table.
392
- def indexes(table_name, name = nil) #:nodoc:
393
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
394
- sql = <<-SQL
395
- SELECT sql
396
- FROM sqlite_master
397
- WHERE name=#{quote(row['name'])} AND type='index'
398
- UNION ALL
399
- SELECT sql
400
- FROM sqlite_temp_master
401
- WHERE name=#{quote(row['name'])} AND type='index'
402
- SQL
403
- index_sql = exec_query(sql).first['sql']
404
- match = /\sWHERE\s+(.+)$/i.match(index_sql)
405
- where = match[1] if match
406
- IndexDefinition.new(
407
- table_name,
408
- row['name'],
409
- row['unique'] != 0,
410
- exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
411
- col['name']
412
- }, nil, nil, where)
413
- end
228
+ def primary_keys(table_name) # :nodoc:
229
+ pks = table_structure(table_name).select { |f| f["pk"] > 0 }
230
+ pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
414
231
  end
415
232
 
416
- def primary_key(table_name) #:nodoc:
417
- pks = table_structure(table_name).select { |f| f['pk'] > 0 }
418
- return nil unless pks.count == 1
419
- pks[0]['name']
420
- end
421
-
422
- def remove_index!(table_name, index_name) #:nodoc:
233
+ def remove_index(table_name, options = {}) #:nodoc:
234
+ index_name = index_name_for_remove(table_name, options)
423
235
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
424
236
  end
425
237
 
@@ -432,35 +244,34 @@ module ActiveRecord
432
244
  rename_table_indexes(table_name, new_name)
433
245
  end
434
246
 
435
- # See: http://www.sqlite.org/lang_altertable.html
436
- # SQLite has an additional restriction on the ALTER TABLE statement
437
- def valid_alter_table_type?(type)
438
- type.to_sym != :primary_key
439
- end
440
-
441
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
442
- if valid_alter_table_type?(type)
443
- super(table_name, column_name, type, options)
444
- else
247
+ def add_column(table_name, column_name, type, **options) #:nodoc:
248
+ if invalid_alter_table_type?(type, options)
445
249
  alter_table(table_name) do |definition|
446
- definition.column(column_name, type, options)
250
+ definition.column(column_name, type, **options)
447
251
  end
252
+ else
253
+ super
448
254
  end
449
255
  end
450
256
 
451
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
257
+ def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
452
258
  alter_table(table_name) do |definition|
453
259
  definition.remove_column column_name
260
+ definition.foreign_keys.delete_if do |_, fk_options|
261
+ fk_options[:column] == column_name.to_s
262
+ end
454
263
  end
455
264
  end
456
265
 
457
- def change_column_default(table_name, column_name, default) #:nodoc:
266
+ def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
267
+ default = extract_new_default_value(default_or_changes)
268
+
458
269
  alter_table(table_name) do |definition|
459
270
  definition[column_name].default = default
460
271
  end
461
272
  end
462
273
 
463
- def change_column_null(table_name, column_name, null, default = nil)
274
+ def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
464
275
  unless null || default.nil?
465
276
  exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
466
277
  end
@@ -471,80 +282,151 @@ module ActiveRecord
471
282
 
472
283
  def change_column(table_name, column_name, type, options = {}) #:nodoc:
473
284
  alter_table(table_name) do |definition|
474
- include_default = options_include_default?(options)
475
285
  definition[column_name].instance_eval do
476
286
  self.type = type
477
287
  self.limit = options[:limit] if options.include?(:limit)
478
- self.default = options[:default] if include_default
288
+ self.default = options[:default] if options.include?(:default)
479
289
  self.null = options[:null] if options.include?(:null)
480
290
  self.precision = options[:precision] if options.include?(:precision)
481
- self.scale = options[:scale] if options.include?(:scale)
291
+ self.scale = options[:scale] if options.include?(:scale)
292
+ self.collation = options[:collation] if options.include?(:collation)
482
293
  end
483
294
  end
484
295
  end
485
296
 
486
297
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
487
298
  column = column_for(table_name, column_name)
488
- alter_table(table_name, rename: {column.name => new_column_name.to_s})
299
+ alter_table(table_name, rename: { column.name => new_column_name.to_s })
489
300
  rename_column_indexes(table_name, column.name, new_column_name)
490
301
  end
491
302
 
492
- protected
303
+ def add_reference(table_name, ref_name, **options) # :nodoc:
304
+ super(table_name, ref_name, type: :integer, **options)
305
+ end
306
+ alias :add_belongs_to :add_reference
493
307
 
494
- def initialize_type_map(m)
308
+ def foreign_keys(table_name)
309
+ fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
310
+ fk_info.map do |row|
311
+ options = {
312
+ column: row["from"],
313
+ primary_key: row["to"],
314
+ on_delete: extract_foreign_key_action(row["on_delete"]),
315
+ on_update: extract_foreign_key_action(row["on_update"])
316
+ }
317
+ ForeignKeyDefinition.new(table_name, row["table"], options)
318
+ end
319
+ end
320
+
321
+ def build_insert_sql(insert) # :nodoc:
322
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
323
+
324
+ if insert.skip_duplicates?
325
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
326
+ elsif insert.update_duplicates?
327
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
328
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
329
+ end
330
+
331
+ sql
332
+ end
333
+
334
+ def get_database_version # :nodoc:
335
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
336
+ end
337
+
338
+ def check_version # :nodoc:
339
+ if database_version < "3.8.0"
340
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
341
+ end
342
+ end
343
+
344
+ private
345
+ # See https://www.sqlite.org/limits.html,
346
+ # the default value is 999 when not configured.
347
+ def bind_params_length
348
+ 999
349
+ end
350
+
351
+ def initialize_type_map(m = type_map)
495
352
  super
496
- m.register_type(/binary/i, SQLite3Binary.new)
353
+ register_class_with_limit m, %r(int)i, SQLite3Integer
497
354
  end
498
355
 
499
356
  def table_structure(table_name)
500
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
357
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
501
358
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
502
- structure
359
+ table_structure_with_collation(table_name, structure)
360
+ end
361
+ alias column_definitions table_structure
362
+
363
+ # See: https://www.sqlite.org/lang_altertable.html
364
+ # SQLite has an additional restriction on the ALTER TABLE statement
365
+ def invalid_alter_table_type?(type, options)
366
+ type.to_sym == :primary_key || options[:primary_key] ||
367
+ options[:null] == false && options[:default].nil?
503
368
  end
504
369
 
505
- def alter_table(table_name, options = {}) #:nodoc:
370
+ def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
506
371
  altered_table_name = "a#{table_name}"
507
- caller = lambda {|definition| yield definition if block_given?}
372
+
373
+ caller = lambda do |definition|
374
+ rename = options[:rename] || {}
375
+ foreign_keys.each do |fk|
376
+ if column = rename[fk.options[:column]]
377
+ fk.options[:column] = column
378
+ end
379
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
380
+ definition.foreign_key(to_table, **fk.options)
381
+ end
382
+
383
+ yield definition if block_given?
384
+ end
508
385
 
509
386
  transaction do
510
- move_table(table_name, altered_table_name,
511
- options.merge(:temporary => true))
512
- move_table(altered_table_name, table_name, &caller)
387
+ disable_referential_integrity do
388
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
389
+ move_table(altered_table_name, table_name, &caller)
390
+ end
513
391
  end
514
392
  end
515
393
 
516
- def move_table(from, to, options = {}, &block) #:nodoc:
394
+ def move_table(from, to, options = {}, &block)
517
395
  copy_table(from, to, options, &block)
518
396
  drop_table(from)
519
397
  end
520
398
 
521
- def copy_table(from, to, options = {}) #:nodoc:
399
+ def copy_table(from, to, options = {})
522
400
  from_primary_key = primary_key(from)
523
401
  options[:id] = false
524
- create_table(to, options) do |definition|
402
+ create_table(to, **options) do |definition|
525
403
  @definition = definition
526
- @definition.primary_key(from_primary_key) if from_primary_key.present?
404
+ if from_primary_key.is_a?(Array)
405
+ @definition.primary_keys from_primary_key
406
+ end
527
407
  columns(from).each do |column|
528
408
  column_name = options[:rename] ?
529
409
  (options[:rename][column.name] ||
530
410
  options[:rename][column.name.to_sym] ||
531
411
  column.name) : column.name
532
- next if column_name == from_primary_key
533
412
 
534
413
  @definition.column(column_name, column.type,
535
- :limit => column.limit, :default => column.default,
536
- :precision => column.precision, :scale => column.scale,
537
- :null => column.null)
414
+ limit: column.limit, default: column.default,
415
+ precision: column.precision, scale: column.scale,
416
+ null: column.null, collation: column.collation,
417
+ primary_key: column_name == from_primary_key
418
+ )
538
419
  end
420
+
539
421
  yield @definition if block_given?
540
422
  end
541
423
  copy_table_indexes(from, to, options[:rename] || {})
542
424
  copy_table_contents(from, to,
543
- @definition.columns.map {|column| column.name},
425
+ @definition.columns.map(&:name),
544
426
  options[:rename] || {})
545
427
  end
546
428
 
547
- def copy_table_indexes(from, to, rename = {}) #:nodoc:
429
+ def copy_table_indexes(from, to, rename = {})
548
430
  indexes(from).each do |index|
549
431
  name = index.name
550
432
  if to == "a#{from}"
@@ -553,60 +435,128 @@ module ActiveRecord
553
435
  name = name[1..-1]
554
436
  end
555
437
 
556
- to_column_names = columns(to).map { |c| c.name }
557
- columns = index.columns.map {|c| rename[c] || c }.select do |column|
558
- to_column_names.include?(column)
438
+ columns = index.columns
439
+ if columns.is_a?(Array)
440
+ to_column_names = columns(to).map(&:name)
441
+ columns = columns.map { |c| rename[c] || c }.select do |column|
442
+ to_column_names.include?(column)
443
+ end
559
444
  end
560
445
 
561
446
  unless columns.empty?
562
447
  # index name can't be the same
563
448
  opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
564
449
  opts[:unique] = true if index.unique
450
+ opts[:where] = index.where if index.where
565
451
  add_index(to, columns, opts)
566
452
  end
567
453
  end
568
454
  end
569
455
 
570
- def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
571
- column_mappings = Hash[columns.map {|name| [name, name]}]
456
+ def copy_table_contents(from, to, columns, rename = {})
457
+ column_mappings = Hash[columns.map { |name| [name, name] }]
572
458
  rename.each { |a| column_mappings[a.last] = a.first }
573
- from_columns = columns(from).collect {|col| col.name}
574
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
575
- quoted_columns = columns.map { |col| quote_column_name(col) } * ','
576
-
577
- quoted_to = quote_table_name(to)
578
-
579
- raw_column_mappings = Hash[columns(from).map { |c| [c.name, c] }]
580
-
581
- exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
582
- sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
583
-
584
- column_values = columns.map do |col|
585
- quote(row[column_mappings[col]], raw_column_mappings[col])
586
- end
587
-
588
- sql << column_values * ', '
589
- sql << ')'
590
- exec_query sql
591
- end
459
+ from_columns = columns(from).collect(&:name)
460
+ columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
461
+ from_columns_to_copy = columns.map { |col| column_mappings[col] }
462
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ","
463
+ quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
464
+
465
+ exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
466
+ SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
592
467
  end
593
468
 
594
- def sqlite_version
595
- @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
596
- end
597
-
598
- def translate_exception(exception, message)
469
+ def translate_exception(exception, message:, sql:, binds:)
599
470
  case exception.message
600
471
  # SQLite 3.8.2 returns a newly formatted error message:
601
472
  # UNIQUE constraint failed: *table_name*.*column_name*
602
473
  # Older versions of SQLite return:
603
474
  # column *column_name* is not unique
604
475
  when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
605
- RecordNotUnique.new(message, exception)
476
+ RecordNotUnique.new(message, sql: sql, binds: binds)
477
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
478
+ NotNullViolation.new(message, sql: sql, binds: binds)
479
+ when /FOREIGN KEY constraint failed/i
480
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
606
481
  else
607
482
  super
608
483
  end
609
484
  end
485
+
486
+ COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
487
+
488
+ def table_structure_with_collation(table_name, basic_structure)
489
+ collation_hash = {}
490
+ sql = <<~SQL
491
+ SELECT sql FROM
492
+ (SELECT * FROM sqlite_master UNION ALL
493
+ SELECT * FROM sqlite_temp_master)
494
+ WHERE type = 'table' AND name = #{quote(table_name)}
495
+ SQL
496
+
497
+ # Result will have following sample string
498
+ # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
499
+ # "password_digest" varchar COLLATE "NOCASE");
500
+ result = exec_query(sql, "SCHEMA").first
501
+
502
+ if result
503
+ # Splitting with left parentheses and discarding the first part will return all
504
+ # columns separated with comma(,).
505
+ columns_string = result["sql"].split("(", 2).last
506
+
507
+ columns_string.split(",").each do |column_string|
508
+ # This regex will match the column name and collation type and will save
509
+ # the value in $1 and $2 respectively.
510
+ collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
511
+ end
512
+
513
+ basic_structure.map! do |column|
514
+ column_name = column["name"]
515
+
516
+ if collation_hash.has_key? column_name
517
+ column["collation"] = collation_hash[column_name]
518
+ end
519
+
520
+ column
521
+ end
522
+ else
523
+ basic_structure.to_a
524
+ end
525
+ end
526
+
527
+ def arel_visitor
528
+ Arel::Visitors::SQLite.new(self)
529
+ end
530
+
531
+ def build_statement_pool
532
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
533
+ end
534
+
535
+ def connect
536
+ @connection = ::SQLite3::Database.new(
537
+ @config[:database].to_s,
538
+ @config.merge(results_as_hash: true)
539
+ )
540
+ configure_connection
541
+ end
542
+
543
+ def configure_connection
544
+ @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
545
+
546
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
547
+ end
548
+
549
+ class SQLite3Integer < Type::Integer # :nodoc:
550
+ private
551
+ def _limit
552
+ # INTEGER storage class can be stored 8 bytes value.
553
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
554
+ limit || 8
555
+ end
556
+ end
557
+
558
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
610
559
  end
560
+ ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
611
561
  end
612
562
  end