ibm_db 5.6.1 → 5.7.0

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 (592) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +13 -9
  3. data/ext/extconf.rb +176 -110
  4. data/ext/ibm_db.c +60 -0
  5. data/ext/ibm_db.o +0 -0
  6. data/ext/ibm_db.so +0 -0
  7. data/ext/mkmf.log +6 -6
  8. data/ext/ruby_ibm_db_cli.c +14 -10
  9. data/ext/ruby_ibm_db_cli.h +4 -0
  10. data/ext/ruby_ibm_db_cli.o +0 -0
  11. data/lib/IBM_DB.rb +2 -2
  12. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
  13. data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
  14. data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
  15. data/test/activejob/destroy_association_async_job_test.rb +62 -0
  16. data/test/activejob/destroy_association_async_test.rb +147 -11
  17. data/test/activejob/job_runtime_test.rb +41 -0
  18. data/test/activejob/unloadable_base_job.rb +3 -0
  19. data/test/cases/active_record_schema_test.rb +196 -0
  20. data/test/cases/active_record_test.rb +21 -0
  21. data/test/cases/adapter_prevent_writes_test.rb +26 -202
  22. data/test/cases/adapter_test.rb +592 -82
  23. data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
  24. data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
  25. data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
  26. data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
  27. data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
  28. data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
  29. data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
  30. data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
  31. data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
  32. data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
  33. data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
  34. data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
  35. data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
  36. data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
  37. data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
  38. data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
  39. data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
  40. data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
  41. data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
  42. data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
  43. data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
  44. data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
  45. data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
  46. data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
  47. data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
  48. data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
  49. data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
  51. data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
  52. data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
  53. data/test/cases/adapters/postgresql/array_test.rb +6 -6
  54. data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
  55. data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
  56. data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
  57. data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
  58. data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
  59. data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
  60. data/test/cases/adapters/postgresql/citext_test.rb +7 -1
  61. data/test/cases/adapters/postgresql/collation_test.rb +1 -1
  62. data/test/cases/adapters/postgresql/composite_test.rb +1 -1
  63. data/test/cases/adapters/postgresql/connection_test.rb +43 -36
  64. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
  65. data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
  66. data/test/cases/adapters/postgresql/date_test.rb +2 -2
  67. data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
  68. data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
  69. data/test/cases/adapters/postgresql/domain_test.rb +1 -1
  70. data/test/cases/adapters/postgresql/enum_test.rb +208 -8
  71. data/test/cases/adapters/postgresql/explain_test.rb +25 -6
  72. data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
  73. data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
  74. data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
  75. data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
  76. data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
  77. data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
  78. data/test/cases/adapters/postgresql/integer_test.rb +1 -1
  79. data/test/cases/adapters/postgresql/interval_test.rb +9 -17
  80. data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
  81. data/test/cases/adapters/postgresql/json_test.rb +5 -0
  82. data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
  83. data/test/cases/adapters/postgresql/money_test.rb +17 -9
  84. data/test/cases/adapters/postgresql/network_test.rb +13 -1
  85. data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
  86. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
  87. data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
  88. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
  89. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
  90. data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
  91. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
  92. data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
  93. data/test/cases/adapters/postgresql/range_test.rb +185 -21
  94. data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
  95. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
  96. data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
  97. data/test/cases/adapters/postgresql/schema_test.rb +270 -20
  98. data/test/cases/adapters/postgresql/serial_test.rb +5 -5
  99. data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
  100. data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
  101. data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
  102. data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
  103. data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
  104. data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
  105. data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
  106. data/test/cases/adapters/postgresql/xml_test.rb +1 -1
  107. data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
  108. data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
  109. data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
  110. data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
  111. data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
  112. data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
  113. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
  114. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
  115. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
  116. data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
  117. data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
  118. data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
  119. data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
  120. data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
  121. data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
  122. data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
  123. data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
  124. data/test/cases/aggregations_test.rb +16 -0
  125. data/test/cases/annotate_test.rb +14 -12
  126. data/test/cases/arel/attributes/attribute_test.rb +86 -47
  127. data/test/cases/arel/collectors/bind_test.rb +1 -1
  128. data/test/cases/arel/collectors/composite_test.rb +11 -1
  129. data/test/cases/arel/collectors/sql_string_test.rb +1 -1
  130. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
  131. data/test/cases/arel/delete_manager_test.rb +0 -6
  132. data/test/cases/arel/factory_methods_test.rb +45 -0
  133. data/test/cases/arel/insert_manager_test.rb +1 -7
  134. data/test/cases/arel/nodes/as_test.rb +12 -0
  135. data/test/cases/arel/nodes/ascending_test.rb +1 -1
  136. data/test/cases/arel/nodes/bin_test.rb +1 -1
  137. data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
  138. data/test/cases/arel/nodes/cte_test.rb +46 -0
  139. data/test/cases/arel/nodes/descending_test.rb +1 -1
  140. data/test/cases/arel/nodes/equality_test.rb +3 -3
  141. data/test/cases/arel/nodes/filter_test.rb +37 -0
  142. data/test/cases/arel/nodes/fragments_test.rb +38 -0
  143. data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
  144. data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
  145. data/test/cases/arel/nodes/node_test.rb +1 -1
  146. data/test/cases/arel/nodes/or_test.rb +2 -2
  147. data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
  148. data/test/cases/arel/nodes/table_alias_test.rb +12 -0
  149. data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
  150. data/test/cases/arel/nodes/update_statement_test.rb +4 -0
  151. data/test/cases/arel/nodes_test.rb +3 -2
  152. data/test/cases/arel/select_manager_test.rb +12 -12
  153. data/test/cases/arel/support/fake_record.rb +22 -17
  154. data/test/cases/arel/table_test.rb +15 -25
  155. data/test/cases/arel/update_manager_test.rb +51 -6
  156. data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
  157. data/test/cases/arel/visitors/dot_test.rb +177 -2
  158. data/test/cases/arel/visitors/mysql_test.rb +49 -1
  159. data/test/cases/arel/visitors/postgres_test.rb +1 -31
  160. data/test/cases/arel/visitors/sqlite_test.rb +1 -1
  161. data/test/cases/arel/visitors/to_sql_test.rb +330 -20
  162. data/test/cases/assertions/query_assertions_test.rb +136 -0
  163. data/test/cases/associations/belongs_to_associations_test.rb +502 -41
  164. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
  165. data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
  166. data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
  167. data/test/cases/associations/eager_singularization_test.rb +1 -1
  168. data/test/cases/associations/eager_test.rb +255 -93
  169. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
  170. data/test/cases/associations/has_many_associations_test.rb +282 -72
  171. data/test/cases/associations/has_many_through_associations_test.rb +172 -45
  172. data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
  173. data/test/cases/associations/has_one_associations_test.rb +160 -29
  174. data/test/cases/associations/has_one_through_associations_test.rb +64 -15
  175. data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
  176. data/test/cases/associations/inner_join_association_test.rb +36 -6
  177. data/test/cases/associations/inverse_associations_test.rb +177 -40
  178. data/test/cases/associations/join_model_test.rb +17 -12
  179. data/test/cases/associations/left_outer_join_association_test.rb +14 -3
  180. data/test/cases/associations/nested_error_test.rb +116 -0
  181. data/test/cases/associations/nested_through_associations_test.rb +54 -19
  182. data/test/cases/associations/required_test.rb +1 -1
  183. data/test/cases/associations_test.rb +1278 -21
  184. data/test/cases/asynchronous_queries_test.rb +310 -0
  185. data/test/cases/attribute_methods/read_test.rb +6 -0
  186. data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
  187. data/test/cases/attribute_methods_test.rb +565 -46
  188. data/test/cases/attributes_test.rb +42 -1
  189. data/test/cases/autosave_association_test.rb +645 -92
  190. data/test/cases/base_prevent_writes_test.rb +28 -159
  191. data/test/cases/base_test.rb +434 -209
  192. data/test/cases/batches_test.rb +441 -57
  193. data/test/cases/binary_test.rb +31 -0
  194. data/test/cases/bind_parameter_test.rb +107 -16
  195. data/test/cases/cache_key_test.rb +7 -7
  196. data/test/cases/calculations_test.rb +541 -110
  197. data/test/cases/callbacks_test.rb +0 -1
  198. data/test/cases/clone_test.rb +5 -4
  199. data/test/cases/coders/yaml_column_test.rb +97 -2
  200. data/test/cases/collection_cache_key_test.rb +24 -16
  201. data/test/cases/column_alias_test.rb +2 -8
  202. data/test/cases/column_definition_test.rb +12 -3
  203. data/test/cases/comment_test.rb +23 -26
  204. data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
  205. data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
  206. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
  207. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
  208. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
  209. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
  210. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
  211. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
  212. data/test/cases/connection_adapters/registration_test.rb +98 -0
  213. data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
  214. data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
  215. data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
  216. data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
  217. data/test/cases/connection_handling_test.rb +210 -0
  218. data/test/cases/connection_management_test.rb +44 -7
  219. data/test/cases/connection_pool_test.rb +466 -99
  220. data/test/cases/core_test.rb +167 -9
  221. data/test/cases/counter_cache_test.rb +129 -2
  222. data/test/cases/custom_locking_test.rb +3 -3
  223. data/test/cases/database_configurations/hash_config_test.rb +149 -13
  224. data/test/cases/database_configurations/resolver_test.rb +14 -10
  225. data/test/cases/database_configurations/url_config_test.rb +53 -0
  226. data/test/cases/database_configurations_test.rb +86 -43
  227. data/test/cases/database_selector_test.rb +30 -8
  228. data/test/cases/database_statements_test.rb +10 -14
  229. data/test/cases/date_time_precision_test.rb +141 -11
  230. data/test/cases/date_time_test.rb +19 -1
  231. data/test/cases/defaults_test.rb +107 -41
  232. data/test/cases/delegated_type_test.rb +69 -9
  233. data/test/cases/dirty_test.rb +82 -25
  234. data/test/cases/disconnected_test.rb +10 -9
  235. data/test/cases/dup_test.rb +26 -6
  236. data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
  237. data/test/cases/encryption/cipher_test.rb +65 -0
  238. data/test/cases/encryption/concurrency_test.rb +27 -0
  239. data/test/cases/encryption/config_test.rb +21 -0
  240. data/test/cases/encryption/configurable_test.rb +93 -0
  241. data/test/cases/encryption/contexts_test.rb +105 -0
  242. data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
  243. data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
  244. data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
  245. data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
  246. data/test/cases/encryption/encryptable_record_test.rb +470 -0
  247. data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
  248. data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
  249. data/test/cases/encryption/encryption_schemes_test.rb +240 -0
  250. data/test/cases/encryption/encryptor_test.rb +113 -0
  251. data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
  252. data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
  253. data/test/cases/encryption/helper.rb +152 -0
  254. data/test/cases/encryption/key_generator_test.rb +55 -0
  255. data/test/cases/encryption/key_provider_test.rb +57 -0
  256. data/test/cases/encryption/key_test.rb +17 -0
  257. data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
  258. data/test/cases/encryption/message_serializer_test.rb +82 -0
  259. data/test/cases/encryption/message_test.rb +43 -0
  260. data/test/cases/encryption/null_encryptor_test.rb +21 -0
  261. data/test/cases/encryption/properties_test.rb +69 -0
  262. data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
  263. data/test/cases/encryption/scheme_test.rb +58 -0
  264. data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
  265. data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
  266. data/test/cases/enum_test.rb +374 -72
  267. data/test/cases/errors_test.rb +7 -4
  268. data/test/cases/excluding_test.rb +116 -0
  269. data/test/cases/explain_subscriber_test.rb +6 -1
  270. data/test/cases/explain_test.rb +119 -10
  271. data/test/cases/filter_attributes_test.rb +7 -14
  272. data/test/cases/finder_respond_to_test.rb +3 -3
  273. data/test/cases/finder_test.rb +357 -72
  274. data/test/cases/fixture_set/file_test.rb +9 -0
  275. data/test/cases/fixtures_test.rb +426 -190
  276. data/test/cases/helper.rb +66 -192
  277. data/test/cases/hot_compatibility_test.rb +10 -10
  278. data/test/cases/inheritance_test.rb +51 -61
  279. data/test/cases/inherited_test.rb +40 -0
  280. data/test/cases/insert_all_test.rb +419 -9
  281. data/test/cases/instrumentation_test.rb +202 -30
  282. data/test/cases/integration_test.rb +25 -7
  283. data/test/cases/invalid_connection_test.rb +5 -5
  284. data/test/cases/invertible_migration_test.rb +108 -24
  285. data/test/cases/json_attribute_test.rb +1 -0
  286. data/test/cases/json_serialization_test.rb +5 -5
  287. data/test/cases/json_shared_test_cases.rb +5 -9
  288. data/test/cases/locking_test.rb +67 -31
  289. data/test/cases/log_subscriber_test.rb +17 -15
  290. data/test/cases/marshal_serialization_test.rb +78 -5
  291. data/test/cases/message_pack_test.rb +91 -0
  292. data/test/cases/migration/change_schema_test.rb +77 -46
  293. data/test/cases/migration/change_table_test.rb +129 -114
  294. data/test/cases/migration/check_constraint_test.rb +192 -10
  295. data/test/cases/migration/column_attributes_test.rb +4 -9
  296. data/test/cases/migration/column_positioning_test.rb +2 -2
  297. data/test/cases/migration/columns_test.rb +118 -4
  298. data/test/cases/migration/command_recorder_test.rb +181 -14
  299. data/test/cases/migration/compatibility_test.rb +883 -196
  300. data/test/cases/migration/create_join_table_test.rb +8 -1
  301. data/test/cases/migration/exclusion_constraint_test.rb +192 -0
  302. data/test/cases/migration/foreign_key_test.rb +356 -14
  303. data/test/cases/migration/helper.rb +4 -1
  304. data/test/cases/migration/index_test.rb +67 -2
  305. data/test/cases/migration/invalid_options_test.rb +129 -0
  306. data/test/cases/migration/logger_test.rb +7 -4
  307. data/test/cases/migration/pending_migrations_test.rb +103 -60
  308. data/test/cases/migration/references_foreign_key_test.rb +73 -4
  309. data/test/cases/migration/references_index_test.rb +25 -27
  310. data/test/cases/migration/references_statements_test.rb +27 -3
  311. data/test/cases/migration/rename_table_test.rb +39 -54
  312. data/test/cases/migration/schema_definitions_test.rb +109 -0
  313. data/test/cases/migration/unique_constraint_test.rb +248 -0
  314. data/test/cases/migration_test.rb +677 -220
  315. data/test/cases/migrator_test.rb +102 -75
  316. data/test/cases/multi_db_migrator_test.rb +55 -34
  317. data/test/cases/multiparameter_attributes_test.rb +26 -29
  318. data/test/cases/multiple_db_test.rb +42 -19
  319. data/test/cases/nested_attributes_test.rb +124 -6
  320. data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
  321. data/test/cases/normalized_attribute_test.rb +117 -0
  322. data/test/cases/null_relation_test.rb +35 -2
  323. data/test/cases/persistence/reload_association_cache_test.rb +20 -0
  324. data/test/cases/persistence_test.rb +629 -22
  325. data/test/cases/pooled_connections_test.rb +57 -56
  326. data/test/cases/prepared_statement_status_test.rb +8 -3
  327. data/test/cases/primary_class_test.rb +134 -0
  328. data/test/cases/primary_keys_test.rb +171 -55
  329. data/test/cases/query_cache_test.rb +558 -263
  330. data/test/cases/query_logs_test.rb +293 -0
  331. data/test/cases/quoting_test.rb +39 -72
  332. data/test/cases/readonly_test.rb +50 -12
  333. data/test/cases/reaper_test.rb +22 -6
  334. data/test/cases/reflection_test.rb +207 -9
  335. data/test/cases/relation/and_test.rb +43 -0
  336. data/test/cases/relation/delegation_test.rb +32 -5
  337. data/test/cases/relation/delete_all_test.rb +27 -6
  338. data/test/cases/relation/field_ordered_values_test.rb +128 -0
  339. data/test/cases/relation/load_async_test.rb +650 -0
  340. data/test/cases/relation/merging_test.rb +80 -109
  341. data/test/cases/relation/mutation_test.rb +12 -7
  342. data/test/cases/relation/or_test.rb +11 -8
  343. data/test/cases/relation/order_test.rb +90 -0
  344. data/test/cases/relation/predicate_builder_test.rb +21 -6
  345. data/test/cases/relation/select_test.rb +162 -3
  346. data/test/cases/relation/structural_compatibility_test.rb +38 -0
  347. data/test/cases/relation/update_all_test.rb +81 -27
  348. data/test/cases/relation/where_chain_test.rb +190 -3
  349. data/test/cases/relation/where_clause_test.rb +43 -1
  350. data/test/cases/relation/where_test.rb +95 -7
  351. data/test/cases/relation/with_test.rb +165 -0
  352. data/test/cases/relation_test.rb +42 -37
  353. data/test/cases/relations_test.rb +436 -138
  354. data/test/cases/reload_models_test.rb +18 -14
  355. data/test/cases/reserved_word_test.rb +2 -1
  356. data/test/cases/result_test.rb +14 -22
  357. data/test/cases/sanitize_test.rb +89 -27
  358. data/test/cases/schema_dumper_test.rb +535 -62
  359. data/test/cases/scoping/default_scoping_test.rb +219 -35
  360. data/test/cases/scoping/named_scoping_test.rb +25 -46
  361. data/test/cases/scoping/relation_scoping_test.rb +112 -4
  362. data/test/cases/secure_password_test.rb +108 -0
  363. data/test/cases/secure_token_test.rb +72 -0
  364. data/test/cases/serialization_test.rb +1 -1
  365. data/test/cases/serialized_attribute_test.rb +305 -60
  366. data/test/cases/shard_keys_test.rb +125 -0
  367. data/test/cases/shard_selector_test.rb +45 -0
  368. data/test/cases/signed_id_test.rb +57 -5
  369. data/test/cases/statement_cache_test.rb +31 -30
  370. data/test/cases/statement_invalid_test.rb +8 -4
  371. data/test/cases/store_test.rb +73 -9
  372. data/test/cases/strict_loading_test.rb +327 -13
  373. data/test/cases/table_metadata_test.rb +16 -0
  374. data/test/cases/tasks/database_tasks_test.rb +517 -244
  375. data/test/cases/test_case.rb +254 -60
  376. data/test/cases/test_case_test.rb +69 -0
  377. data/test/cases/test_databases_test.rb +7 -3
  378. data/test/cases/test_fixtures_test.rb +19 -40
  379. data/test/cases/time_precision_test.rb +17 -5
  380. data/test/cases/timestamp_test.rb +124 -16
  381. data/test/cases/token_for_test.rb +165 -0
  382. data/test/cases/touch_later_test.rb +43 -1
  383. data/test/cases/transaction_callbacks_test.rb +325 -8
  384. data/test/cases/transaction_instrumentation_test.rb +453 -0
  385. data/test/cases/transaction_isolation_test.rb +12 -8
  386. data/test/cases/transactions_test.rb +629 -112
  387. data/test/cases/type/date_time_test.rb +7 -1
  388. data/test/cases/type/time_test.rb +9 -0
  389. data/test/cases/type/type_map_test.rb +108 -73
  390. data/test/cases/type/unsigned_integer_test.rb +12 -0
  391. data/test/cases/type_caster/connection_test.rb +19 -0
  392. data/test/cases/type_test.rb +1 -1
  393. data/test/cases/unconnected_test.rb +7 -7
  394. data/test/cases/unsafe_raw_sql_test.rb +39 -8
  395. data/test/cases/validations/absence_validation_test.rb +1 -1
  396. data/test/cases/validations/association_validation_test.rb +25 -3
  397. data/test/cases/validations/numericality_validation_test.rb +3 -9
  398. data/test/cases/validations/presence_validation_test.rb +1 -1
  399. data/test/cases/validations/uniqueness_validation_test.rb +280 -40
  400. data/test/cases/validations_test.rb +2 -2
  401. data/test/cases/view_test.rb +33 -22
  402. data/test/cases/yaml_serialization_test.rb +23 -17
  403. data/test/config.example.yml +58 -56
  404. data/test/config.rb +1 -0
  405. data/test/fixtures/1_need_quoting.yml +2 -0
  406. data/test/fixtures/accounts.yml +5 -0
  407. data/test/fixtures/aircrafts.yml +7 -0
  408. data/test/fixtures/book_identifiers.yml +11 -0
  409. data/test/fixtures/books.yml +5 -4
  410. data/test/fixtures/cake_designers.yml +5 -0
  411. data/test/fixtures/cars.yml +6 -0
  412. data/test/fixtures/chefs.yml +5 -0
  413. data/test/fixtures/clothing_items.yml +23 -0
  414. data/test/fixtures/clubs.yml +1 -1
  415. data/test/fixtures/comments.yml +2 -1
  416. data/test/fixtures/cpk_authors.yml +8 -0
  417. data/test/fixtures/cpk_books.yml +21 -0
  418. data/test/fixtures/cpk_order_agreements.yml +13 -0
  419. data/test/fixtures/cpk_order_tags.yml +15 -0
  420. data/test/fixtures/cpk_orders.yml +11 -0
  421. data/test/fixtures/cpk_posts.yml +12 -0
  422. data/test/fixtures/cpk_reviews.yml +13 -0
  423. data/test/fixtures/cpk_tags.yml +11 -0
  424. data/test/fixtures/drink_designers.yml +5 -0
  425. data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
  426. data/test/fixtures/encrypted_books.yml +4 -0
  427. data/test/fixtures/fk_object_to_point_to.yml +2 -0
  428. data/test/fixtures/memberships.yml +15 -15
  429. data/test/fixtures/paragraphs.yml +5 -0
  430. data/test/fixtures/parrots.yml +4 -0
  431. data/test/fixtures/people.yml +2 -0
  432. data/test/fixtures/pirates.yml +2 -2
  433. data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
  434. data/test/fixtures/references.yml +3 -3
  435. data/test/fixtures/sharded_blog_posts.yml +14 -0
  436. data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
  437. data/test/fixtures/sharded_blogs.yml +8 -0
  438. data/test/fixtures/sharded_comments.yml +22 -0
  439. data/test/fixtures/sharded_tags.yml +34 -0
  440. data/test/fixtures/sponsors.yml +2 -2
  441. data/test/fixtures/topics.yml +1 -0
  442. data/test/fixtures/treasures.yml +4 -0
  443. data/test/fixtures/virtual_columns.yml +5 -0
  444. data/test/fixtures/warehouse_things.yml +1 -1
  445. data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
  446. data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
  447. data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
  448. data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
  449. data/test/migrations/scope/1_unscoped.rb +7 -0
  450. data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
  451. data/test/models/admin/user.rb +2 -0
  452. data/test/models/admin/user_json.rb +48 -0
  453. data/test/models/attachment.rb +7 -0
  454. data/test/models/author.rb +70 -3
  455. data/test/models/author_encrypted.rb +16 -0
  456. data/test/models/bird.rb +1 -1
  457. data/test/models/book.rb +18 -11
  458. data/test/models/book_destroy_async.rb +1 -1
  459. data/test/models/book_encrypted.rb +106 -0
  460. data/test/models/book_identifier.rb +5 -0
  461. data/test/models/branch.rb +11 -0
  462. data/test/models/bulb.rb +1 -1
  463. data/test/models/car.rb +8 -1
  464. data/test/models/cat.rb +1 -1
  465. data/test/models/category.rb +3 -1
  466. data/test/models/chat_message.rb +8 -0
  467. data/test/models/chef.rb +52 -0
  468. data/test/models/clothing_item.rb +12 -0
  469. data/test/models/club.rb +4 -1
  470. data/test/models/comment.rb +7 -4
  471. data/test/models/comment_overlapping_counter_cache.rb +15 -0
  472. data/test/models/company.rb +16 -2
  473. data/test/models/computer.rb +1 -0
  474. data/test/models/contact.rb +3 -3
  475. data/test/models/contract.rb +5 -1
  476. data/test/models/cpk/author.rb +9 -0
  477. data/test/models/cpk/book.rb +55 -0
  478. data/test/models/cpk/book_destroy_async.rb +9 -0
  479. data/test/models/cpk/car.rb +9 -0
  480. data/test/models/cpk/car_review.rb +9 -0
  481. data/test/models/cpk/chapter.rb +16 -0
  482. data/test/models/cpk/chapter_destroy_async.rb +10 -0
  483. data/test/models/cpk/comment.rb +9 -0
  484. data/test/models/cpk/order.rb +55 -0
  485. data/test/models/cpk/order_agreement.rb +10 -0
  486. data/test/models/cpk/order_tag.rb +10 -0
  487. data/test/models/cpk/post.rb +10 -0
  488. data/test/models/cpk/posts_tag.rb +10 -0
  489. data/test/models/cpk/review.rb +9 -0
  490. data/test/models/cpk/tag.rb +10 -0
  491. data/test/models/cpk.rb +15 -0
  492. data/test/models/customer.rb +3 -1
  493. data/test/models/destroy_async_parent.rb +1 -1
  494. data/test/models/developer.rb +44 -3
  495. data/test/models/discount.rb +4 -0
  496. data/test/models/drink_designer.rb +1 -0
  497. data/test/models/editor.rb +8 -0
  498. data/test/models/editorship.rb +6 -0
  499. data/test/models/entry.rb +5 -0
  500. data/test/models/essay.rb +6 -1
  501. data/test/models/essay_destroy_async.rb +1 -0
  502. data/test/models/eye.rb +87 -21
  503. data/test/models/face.rb +1 -1
  504. data/test/models/friendship.rb +3 -0
  505. data/test/models/hardback.rb +7 -0
  506. data/test/models/hotel.rb +2 -0
  507. data/test/models/human.rb +2 -2
  508. data/test/models/invoice.rb +2 -1
  509. data/test/models/invokes_an_undefined_method.rb +5 -0
  510. data/test/models/line_item.rb +6 -0
  511. data/test/models/member.rb +9 -4
  512. data/test/models/membership.rb +2 -2
  513. data/test/models/message.rb +2 -1
  514. data/test/models/need_quoting.rb +5 -0
  515. data/test/models/paragraph.rb +5 -0
  516. data/test/models/parrot.rb +6 -3
  517. data/test/models/person.rb +7 -4
  518. data/test/models/pirate.rb +4 -1
  519. data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
  520. data/test/models/post.rb +65 -2
  521. data/test/models/post_encrypted.rb +15 -0
  522. data/test/models/post_with_prefetched_pk.rb +15 -0
  523. data/test/models/project.rb +1 -0
  524. data/test/models/publication.rb +16 -0
  525. data/test/models/raises_argument_error.rb +5 -0
  526. data/test/models/raises_no_method_error.rb +5 -0
  527. data/test/models/recipient.rb +5 -0
  528. data/test/models/reference.rb +1 -1
  529. data/test/models/reply.rb +1 -1
  530. data/test/models/room.rb +3 -0
  531. data/test/models/sharded/blog.rb +12 -0
  532. data/test/models/sharded/blog_post.rb +17 -0
  533. data/test/models/sharded/blog_post_destroy_async.rb +14 -0
  534. data/test/models/sharded/blog_post_tag.rb +11 -0
  535. data/test/models/sharded/blog_post_with_revision.rb +11 -0
  536. data/test/models/sharded/comment.rb +12 -0
  537. data/test/models/sharded/comment_destroy_async.rb +12 -0
  538. data/test/models/sharded/tag.rb +11 -0
  539. data/test/models/sharded.rb +8 -0
  540. data/test/models/ship.rb +1 -1
  541. data/test/models/shipping_line.rb +11 -0
  542. data/test/models/subscriber.rb +1 -0
  543. data/test/models/subscription.rb +3 -1
  544. data/test/models/too_long_table_name.rb +5 -0
  545. data/test/models/topic.rb +3 -1
  546. data/test/models/traffic_light.rb +2 -2
  547. data/test/models/traffic_light_encrypted.rb +21 -0
  548. data/test/models/translation.rb +9 -0
  549. data/test/models/treasure.rb +1 -1
  550. data/test/models/tyre.rb +1 -1
  551. data/test/models/user.rb +16 -0
  552. data/test/models/user_with_invalid_relation.rb +28 -0
  553. data/test/models/uuid_comment.rb +5 -0
  554. data/test/models/uuid_entry.rb +5 -0
  555. data/test/models/uuid_message.rb +5 -0
  556. data/test/models/zine.rb +2 -1
  557. data/test/schema/mysql2_specific_schema.rb +26 -12
  558. data/test/schema/postgresql_specific_schema.rb +121 -13
  559. data/test/schema/schema.rb +361 -103
  560. data/test/schema/sqlite_specific_schema.rb +17 -6
  561. data/test/schema/trilogy_specific_schema.rb +96 -0
  562. data/test/support/adapter_helper.rb +104 -0
  563. data/test/support/async_helper.rb +15 -0
  564. data/test/support/config.rb +1 -1
  565. data/test/support/connection.rb +14 -2
  566. data/test/support/ddl_helper.rb +1 -1
  567. data/test/support/fake_adapter.rb +42 -0
  568. data/test/support/load_schema_helper.rb +22 -0
  569. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
  570. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
  571. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
  572. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
  573. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
  574. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
  575. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
  576. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
  577. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
  578. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
  579. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
  580. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
  581. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
  582. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
  583. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
  584. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
  585. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
  586. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
  587. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
  588. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
  589. data/test/support/schema_dumping_helper.rb +15 -9
  590. data/test/support/tools.rb +37 -0
  591. data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
  592. metadata +247 -15
@@ -11,25 +11,34 @@ module ActiveRecord
11
11
  class Sample < ActiveRecord::Base
12
12
  self.table_name = "samples"
13
13
  end
14
+ class Bit < ActiveRecord::Base
15
+ self.table_name = "bits"
16
+ end
14
17
 
15
18
  setup do
16
19
  @abort, Thread.abort_on_exception = Thread.abort_on_exception, false
17
20
  Thread.report_on_exception, @original_report_on_exception = false, Thread.report_on_exception
18
21
 
19
- connection = ActiveRecord::Base.connection
22
+ connection = ActiveRecord::Base.lease_connection
20
23
 
21
24
  connection.transaction do
22
25
  connection.drop_table "samples", if_exists: true
26
+ connection.drop_table "bits", if_exists: true
23
27
  connection.create_table("samples") do |t|
24
28
  t.integer "value"
25
29
  end
30
+ connection.create_table("bits") do |t|
31
+ t.integer "value"
32
+ end
26
33
  end
27
34
 
28
35
  Sample.reset_column_information
36
+ Bit.reset_column_information
29
37
  end
30
38
 
31
39
  teardown do
32
- ActiveRecord::Base.connection.drop_table "samples", if_exists: true
40
+ ActiveRecord::Base.lease_connection.drop_table "samples", if_exists: true
41
+ ActiveRecord::Base.lease_connection.drop_table "bits", if_exists: true
33
42
 
34
43
  Thread.abort_on_exception = @abort
35
44
  Thread.report_on_exception = @original_report_on_exception
@@ -43,7 +52,9 @@ module ActiveRecord
43
52
  thread = Thread.new do
44
53
  with_warning_suppression do
45
54
  Sample.transaction(isolation: :serializable, requires_new: false) do
55
+ make_parent_transaction_dirty
46
56
  Sample.transaction(requires_new: true) do
57
+ assert_current_transaction_is_savepoint_transaction
47
58
  before.wait
48
59
  Sample.create value: Sample.sum(:value)
49
60
  after.wait
@@ -55,7 +66,9 @@ module ActiveRecord
55
66
  begin
56
67
  with_warning_suppression do
57
68
  Sample.transaction(isolation: :serializable, requires_new: false) do
69
+ make_parent_transaction_dirty
58
70
  Sample.transaction(requires_new: true) do
71
+ assert_current_transaction_is_savepoint_transaction
59
72
  before.wait
60
73
  Sample.create value: Sample.sum(:value)
61
74
  after.wait
@@ -68,8 +81,50 @@ module ActiveRecord
68
81
  end
69
82
  end
70
83
 
84
+ test "SerializationFailure inside nested SavepointTransaction is recoverable" do
85
+ start_right = Concurrent::Event.new
86
+ commit_left = Concurrent::Event.new
87
+ finish_right = Concurrent::Event.new
88
+ Sample.create value: 1
89
+
90
+ thread = Thread.new do
91
+ with_warning_suppression do
92
+ Sample.transaction(isolation: :serializable, requires_new: false) do
93
+ Sample.update_all value: 2
94
+ start_right.set
95
+ commit_left.wait(1)
96
+ end
97
+ finish_right.set
98
+ end
99
+ end
100
+
101
+ begin
102
+ with_warning_suppression do
103
+ start_right.wait
104
+ Sample.transaction(isolation: :serializable, requires_new: false) do
105
+ make_parent_transaction_dirty
106
+ assert_raises(ActiveRecord::SerializationFailure) do
107
+ Sample.transaction(requires_new: true) do
108
+ assert_current_transaction_is_savepoint_transaction
109
+ Sample.create value: 3
110
+ commit_left.set
111
+ finish_right.wait(2)
112
+ Sample.update_all value: 4
113
+ end
114
+ end
115
+ Bit.create value: 1
116
+ end
117
+ end
118
+ ensure
119
+ thread.join
120
+ end
121
+ assert_equal [2], Sample.pluck(:value)
122
+ assert_equal [1], Bit.pluck(:value)
123
+ end
124
+
71
125
  test "deadlock raises Deadlocked inside nested SavepointTransaction" do
72
126
  with_warning_suppression do
127
+ connections = Concurrent::Set.new
73
128
  assert_raises(ActiveRecord::Deadlocked) do
74
129
  barrier = Concurrent::CyclicBarrier.new(2)
75
130
 
@@ -77,8 +132,11 @@ module ActiveRecord
77
132
  s2 = Sample.create value: 2
78
133
 
79
134
  thread = Thread.new do
135
+ connections.add Sample.lease_connection
80
136
  Sample.transaction(requires_new: false) do
137
+ make_parent_transaction_dirty
81
138
  Sample.transaction(requires_new: true) do
139
+ assert_current_transaction_is_savepoint_transaction
82
140
  s1.lock!
83
141
  barrier.wait
84
142
  s2.update value: 1
@@ -87,8 +145,11 @@ module ActiveRecord
87
145
  end
88
146
 
89
147
  begin
148
+ connections.add Sample.lease_connection
90
149
  Sample.transaction(requires_new: false) do
150
+ make_parent_transaction_dirty
91
151
  Sample.transaction(requires_new: true) do
152
+ assert_current_transaction_is_savepoint_transaction
92
153
  s2.lock!
93
154
  barrier.wait
94
155
  s1.update value: 2
@@ -98,17 +159,80 @@ module ActiveRecord
98
159
  thread.join
99
160
  end
100
161
  end
162
+ assert connections.all?(&:active?)
163
+ end
164
+ end
165
+
166
+ test "deadlock inside nested SavepointTransaction is recoverable" do
167
+ with_warning_suppression do
168
+ barrier = Concurrent::CyclicBarrier.new(2)
169
+ deadlocks = 0
170
+
171
+ s1 = Sample.create value: 1
172
+ s2 = Sample.create value: 2
173
+
174
+ thread = Thread.new do
175
+ Sample.transaction(requires_new: false) do
176
+ make_parent_transaction_dirty
177
+ begin
178
+ Sample.transaction(requires_new: true) do
179
+ assert_current_transaction_is_savepoint_transaction
180
+ s1.lock!
181
+ barrier.wait
182
+ s2.update value: 4
183
+ end
184
+ rescue ActiveRecord::Deadlocked
185
+ deadlocks += 1
186
+ end
187
+ s2.update value: 10
188
+ end
189
+ end
190
+
191
+ begin
192
+ Sample.transaction(requires_new: false) do
193
+ make_parent_transaction_dirty
194
+ begin
195
+ Sample.transaction(requires_new: true) do
196
+ assert_current_transaction_is_savepoint_transaction
197
+ s2.lock!
198
+ barrier.wait
199
+ s1.update value: 3
200
+ end
201
+ rescue ActiveRecord::Deadlocked
202
+ deadlocks += 1
203
+ end
204
+ s1.update value: 10
205
+ end
206
+ ensure
207
+ thread.join
208
+ end
209
+ assert_equal 1, deadlocks
210
+ assert_equal [10, 10], Sample.pluck(:value)
101
211
  end
102
212
  end
103
213
 
104
214
  private
105
215
  def with_warning_suppression
106
- log_level = ActiveRecord::Base.connection.client_min_messages
107
- ActiveRecord::Base.connection.client_min_messages = "error"
216
+ log_level = ActiveRecord::Base.lease_connection.client_min_messages
217
+ ActiveRecord::Base.lease_connection.client_min_messages = "error"
108
218
  yield
109
219
  ensure
110
- ActiveRecord::Base.clear_active_connections!
111
- ActiveRecord::Base.connection.client_min_messages = log_level
220
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
221
+ ActiveRecord::Base.lease_connection.client_min_messages = log_level
222
+ end
223
+
224
+ # These tests are coordinating a controlled sequence of accesses to rows in `samples` table under serializable isolation.
225
+ # We need to run a query to dirty our transaction, but must avoid touching `samples` rows
226
+ # because otherwise our no-op query becomes an active participant of the test setup
227
+ def make_parent_transaction_dirty
228
+ Bit.take
229
+ end
230
+
231
+ def assert_current_transaction_is_savepoint_transaction
232
+ current_transaction = Sample.lease_connection.current_transaction
233
+ unless current_transaction.is_a?(ActiveRecord::ConnectionAdapters::SavepointTransaction)
234
+ flunk("current transaction is not a savepoint transaction")
235
+ end
112
236
  end
113
237
  end
114
238
  end
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  @abort, Thread.abort_on_exception = Thread.abort_on_exception, false
17
17
  Thread.report_on_exception, @original_report_on_exception = false, Thread.report_on_exception
18
18
 
19
- connection = ActiveRecord::Base.connection
19
+ connection = ActiveRecord::Base.lease_connection
20
20
 
21
21
  connection.transaction do
22
22
  connection.drop_table "samples", if_exists: true
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  end
30
30
 
31
31
  teardown do
32
- ActiveRecord::Base.connection.drop_table "samples", if_exists: true
32
+ ActiveRecord::Base.lease_connection.drop_table "samples", if_exists: true
33
33
 
34
34
  Thread.abort_on_exception = @abort
35
35
  Thread.report_on_exception = @original_report_on_exception
@@ -66,6 +66,7 @@ module ActiveRecord
66
66
 
67
67
  test "raises Deadlocked when a deadlock is encountered" do
68
68
  with_warning_suppression do
69
+ connections = Concurrent::Set.new
69
70
  assert_raises(ActiveRecord::Deadlocked) do
70
71
  barrier = Concurrent::CyclicBarrier.new(2)
71
72
 
@@ -73,6 +74,7 @@ module ActiveRecord
73
74
  s2 = Sample.create value: 2
74
75
 
75
76
  thread = Thread.new do
77
+ connections.add Sample.lease_connection
76
78
  Sample.transaction do
77
79
  s1.lock!
78
80
  barrier.wait
@@ -81,6 +83,7 @@ module ActiveRecord
81
83
  end
82
84
 
83
85
  begin
86
+ connections.add Sample.lease_connection
84
87
  Sample.transaction do
85
88
  s2.lock!
86
89
  barrier.wait
@@ -90,6 +93,7 @@ module ActiveRecord
90
93
  thread.join
91
94
  end
92
95
  end
96
+ assert connections.all?(&:active?)
93
97
  end
94
98
  end
95
99
 
@@ -110,11 +114,11 @@ module ActiveRecord
110
114
  begin
111
115
  Sample.transaction do
112
116
  latch1.wait
113
- Sample.connection.execute("SET lock_timeout = 1")
117
+ Sample.lease_connection.execute("SET lock_timeout = 1")
114
118
  Sample.lock.find(s.id)
115
119
  end
116
120
  ensure
117
- Sample.connection.execute("SET lock_timeout = DEFAULT")
121
+ Sample.lease_connection.execute("SET lock_timeout = DEFAULT")
118
122
  latch2.count_down
119
123
  thread.join
120
124
  end
@@ -138,11 +142,11 @@ module ActiveRecord
138
142
  begin
139
143
  Sample.transaction do
140
144
  latch1.wait
141
- Sample.connection.execute("SET statement_timeout = 1")
145
+ Sample.lease_connection.execute("SET statement_timeout = 1")
142
146
  Sample.lock.find(s.id)
143
147
  end
144
148
  ensure
145
- Sample.connection.execute("SET statement_timeout = DEFAULT")
149
+ Sample.lease_connection.execute("SET statement_timeout = DEFAULT")
146
150
  latch2.count_down
147
151
  thread.join
148
152
  end
@@ -159,7 +163,7 @@ module ActiveRecord
159
163
  Sample.lock.find(s.id)
160
164
  latch.count_down
161
165
  sleep(0.5)
162
- conn = Sample.connection
166
+ conn = Sample.lease_connection
163
167
  pid = conn.query_value("SELECT pid FROM pg_stat_activity WHERE query LIKE '% FOR UPDATE'")
164
168
  conn.execute("SELECT pg_cancel_backend(#{pid})")
165
169
  end
@@ -176,14 +180,36 @@ module ActiveRecord
176
180
  end
177
181
  end
178
182
 
183
+ test "raises Interrupt when canceling statement via interrupt" do
184
+ if PG.library_version >= 18_00_00 && Gem::Version.new(PG::VERSION) < Gem::Version.new("1.6.0")
185
+ skip "PG::Connection#cancel should not run when libpq of PostgreSQL #{PG.library_version / 10000} with pg gem version #{PG::VERSION}"
186
+ end
187
+ start_time = Time.now
188
+ thread = Thread.new do
189
+ Sample.transaction do
190
+ Sample.lease_connection.execute("SELECT pg_sleep(10)")
191
+ end
192
+ rescue Exception => e
193
+ e
194
+ end
195
+
196
+ sleep(0.5)
197
+ thread.raise Interrupt
198
+ thread.join
199
+ duration = Time.now - start_time
200
+
201
+ assert_instance_of Interrupt, thread.value
202
+ assert_operator duration, :<, 5
203
+ end
204
+
179
205
  private
180
206
  def with_warning_suppression
181
- log_level = ActiveRecord::Base.connection.client_min_messages
182
- ActiveRecord::Base.connection.client_min_messages = "error"
207
+ log_level = ActiveRecord::Base.lease_connection.client_min_messages
208
+ ActiveRecord::Base.lease_connection.client_min_messages = "error"
183
209
  yield
184
210
  ensure
185
- ActiveRecord::Base.clear_active_connections!
186
- ActiveRecord::Base.connection.client_min_messages = log_level
211
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
212
+ ActiveRecord::Base.lease_connection.client_min_messages = log_level
187
213
  end
188
214
  end
189
215
  end
@@ -4,7 +4,7 @@ require "cases/helper"
4
4
 
5
5
  class PostgresqlTypeLookupTest < ActiveRecord::PostgreSQLTestCase
6
6
  setup do
7
- @connection = ActiveRecord::Base.connection
7
+ @connection = ActiveRecord::Base.lease_connection
8
8
  end
9
9
 
10
10
  test "array delimiters are looked up correctly" do
@@ -5,7 +5,7 @@ require "support/schema_dumping_helper"
5
5
 
6
6
  module PostgresqlUUIDHelper
7
7
  def connection
8
- @connection ||= ActiveRecord::Base.connection
8
+ @connection ||= ActiveRecord::Base.lease_connection
9
9
  end
10
10
 
11
11
  def drop_table(name)
@@ -39,11 +39,12 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase
39
39
  end
40
40
 
41
41
  teardown do
42
+ UUIDType.reset_column_information
42
43
  drop_table "uuid_data_type"
43
44
  end
44
45
 
45
- if ActiveRecord::Base.connection.respond_to?(:supports_pgcrypto_uuid?) &&
46
- ActiveRecord::Base.connection.supports_pgcrypto_uuid?
46
+ if ActiveRecord::Base.lease_connection.respond_to?(:supports_pgcrypto_uuid?) &&
47
+ ActiveRecord::Base.lease_connection.supports_pgcrypto_uuid?
47
48
  def test_uuid_column_default
48
49
  connection.add_column :uuid_data_type, :thingy, :uuid, null: false, default: "gen_random_uuid()"
49
50
  UUIDType.reset_column_information
@@ -120,10 +121,13 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase
120
121
  assert_empty UUIDType.where(guid: "foobar")
121
122
  end
122
123
 
123
- def test_uuid_change_case_does_not_mark_dirty
124
+ def test_uuid_change_format_does_not_mark_dirty
124
125
  model = UUIDType.create!(guid: "abcd-0123-4567-89ef-dead-beef-0101-1010")
125
126
  model.guid = model.guid.swapcase
126
127
  assert_not_predicate model, :changed?
128
+
129
+ model.guid = "{#{model.guid}}"
130
+ assert_not_predicate model, :changed?
127
131
  end
128
132
 
129
133
  class DuckUUID
@@ -201,7 +205,7 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase
201
205
  record = klass.create!(guid: "a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11")
202
206
  duplicate = klass.new(guid: record.guid)
203
207
 
204
- assert record.guid.present? # Ensure we actually are testing a UUID
208
+ assert_predicate record.guid, :present? # Ensure we actually are testing a UUID
205
209
  assert_not_predicate duplicate, :valid?
206
210
  end
207
211
  end
@@ -299,14 +303,16 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase
299
303
  create_table("pg_uuids_4", id: :uuid)
300
304
  end
301
305
  end.new
302
- ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
306
+
307
+ pool = ActiveRecord::Base.connection_pool
308
+ ActiveRecord::Migrator.new(:up, [migration], pool.schema_migration, pool.internal_metadata).migrate
303
309
 
304
310
  schema = dump_table_schema "pg_uuids_4"
305
311
  assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema)
306
312
  ensure
307
313
  drop_table "pg_uuids_4"
308
314
  ActiveRecord::Migration.verbose = @verbose_was
309
- ActiveRecord::Base.connection.schema_migration.delete_all
315
+ ActiveRecord::Base.connection_pool.schema_migration.delete_all_versions
310
316
  end
311
317
  uses_transaction :test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration
312
318
  end
@@ -349,14 +355,16 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase
349
355
  create_table("pg_uuids_4", id: :uuid, default: nil)
350
356
  end
351
357
  end.new
352
- ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
358
+
359
+ pool = ActiveRecord::Base.connection_pool
360
+ ActiveRecord::Migrator.new(:up, [migration], pool.schema_migration, pool.internal_metadata).migrate
353
361
 
354
362
  schema = dump_table_schema "pg_uuids_4"
355
363
  assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: nil/, schema)
356
364
  ensure
357
365
  drop_table "pg_uuids_4"
358
366
  ActiveRecord::Migration.verbose = @verbose_was
359
- ActiveRecord::Base.connection.schema_migration.delete_all
367
+ ActiveRecord::Base.connection_pool.schema_migration.delete_all_versions
360
368
  end
361
369
  uses_transaction :test_schema_dumper_for_uuid_primary_key_with_default_nil_in_legacy_migration
362
370
  end
@@ -409,3 +417,63 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::PostgreSQLTestCase
409
417
  assert_nil UuidPost.find_by(id: 789)
410
418
  end
411
419
  end
420
+
421
+ class PostgresqlUUIDHasManyThroughDisableJoinsTest < ActiveRecord::PostgreSQLTestCase
422
+ include PostgresqlUUIDHelper
423
+
424
+ class UuidForum < ActiveRecord::Base
425
+ self.table_name = "pg_uuid_forums"
426
+ has_many :uuid_posts, -> { order("title DESC") }
427
+ has_many :uuid_comments, through: :uuid_posts
428
+ has_many :uuid_comments_without_joins, through: :uuid_posts, source: :uuid_comments, disable_joins: true
429
+ end
430
+
431
+ class UuidPost < ActiveRecord::Base
432
+ self.table_name = "pg_uuid_posts"
433
+ belongs_to :uuid_forum
434
+ has_many :uuid_comments
435
+ end
436
+
437
+ class UuidComment < ActiveRecord::Base
438
+ self.table_name = "pg_uuid_comments"
439
+ belongs_to :uuid_post
440
+ has_one :uuid_forum, through: :uuid_post
441
+ has_one :uuid_forum_without_joins, through: :uuid_post, source: :uuid_forum, disable_joins: true
442
+ end
443
+
444
+ setup do
445
+ connection.transaction do
446
+ connection.create_table("pg_uuid_forums", id: :uuid, **uuid_default) do |t|
447
+ t.string "name"
448
+ end
449
+ connection.create_table("pg_uuid_posts", id: :uuid, **uuid_default) do |t|
450
+ t.references :uuid_forum, type: :uuid
451
+ t.string "title"
452
+ end
453
+ connection.create_table("pg_uuid_comments", id: :uuid, **uuid_default) do |t|
454
+ t.references :uuid_post, type: :uuid
455
+ t.string "content"
456
+ end
457
+ end
458
+ end
459
+
460
+ teardown do
461
+ drop_table "pg_uuid_comments"
462
+ drop_table "pg_uuid_posts"
463
+ drop_table "pg_uuid_forums"
464
+ end
465
+
466
+ def test_uuid_primary_key_and_disable_joins_with_delegate_cache
467
+ uuid_forum = UuidForum.create!
468
+ uuid_post_1 = uuid_forum.uuid_posts.create!
469
+ uuid_comment_1_1 = uuid_post_1.uuid_comments.create!
470
+ uuid_comment_1_2 = uuid_post_1.uuid_comments.create!
471
+ uuid_post_2 = uuid_forum.uuid_posts.create!
472
+ uuid_comment_2_1 = uuid_post_2.uuid_comments.create!
473
+ uuid_comment_2_2 = uuid_post_2.uuid_comments.create!
474
+ uuid_comment_2_3 = uuid_post_2.uuid_comments.create!
475
+
476
+ assert_equal uuid_forum.uuid_comments_without_joins.order(:id).to_a.map(&:id).sort,
477
+ [uuid_comment_1_1.id, uuid_comment_1_2.id, uuid_comment_2_1.id, uuid_comment_2_2.id, uuid_comment_2_3.id].sort
478
+ end
479
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "support/schema_dumping_helper"
5
+
6
+ if ActiveRecord::Base.lease_connection.supports_virtual_columns?
7
+ class PostgresqlVirtualColumnTest < ActiveRecord::PostgreSQLTestCase
8
+ include SchemaDumpingHelper
9
+
10
+ class VirtualColumn < ActiveRecord::Base
11
+ end
12
+
13
+ def setup
14
+ @connection = ActiveRecord::Base.lease_connection
15
+ @connection.create_table :virtual_columns, force: true do |t|
16
+ t.string :name
17
+ t.virtual :upper_name, type: :string, as: "UPPER(name)", stored: true
18
+ t.virtual :name_length, type: :integer, as: "LENGTH(name)", stored: true
19
+ t.virtual :name_octet_length, type: :integer, as: "OCTET_LENGTH(name)", stored: true
20
+ t.integer :column1
21
+ t.virtual :column2, type: :integer, as: "column1 + 1", stored: true
22
+ end
23
+ VirtualColumn.create(name: "Rails")
24
+ end
25
+
26
+ def test_virtual_column_with_full_inserts
27
+ partial_inserts_was = VirtualColumn.partial_inserts
28
+ VirtualColumn.partial_inserts = false
29
+ assert_nothing_raised do
30
+ VirtualColumn.create!(name: "Rails")
31
+ end
32
+ ensure
33
+ VirtualColumn.partial_inserts = partial_inserts_was
34
+ end
35
+
36
+ def teardown
37
+ @connection.drop_table :virtual_columns, if_exists: true
38
+ VirtualColumn.reset_column_information
39
+ end
40
+
41
+ def test_virtual_column
42
+ column = VirtualColumn.columns_hash["upper_name"]
43
+ assert_predicate column, :virtual?
44
+ assert_equal "RAILS", VirtualColumn.take.upper_name
45
+ end
46
+
47
+ def test_stored_column
48
+ column = VirtualColumn.columns_hash["name_length"]
49
+ assert_predicate column, :virtual?
50
+ assert_equal 5, VirtualColumn.take.name_length
51
+ end
52
+
53
+ def test_change_table
54
+ @connection.change_table :virtual_columns do |t|
55
+ t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: true
56
+ end
57
+ VirtualColumn.reset_column_information
58
+ column = VirtualColumn.columns_hash["lower_name"]
59
+ assert_predicate column, :virtual?
60
+ assert_equal "rails", VirtualColumn.take.lower_name
61
+ end
62
+
63
+ def test_non_persisted_column
64
+ message = <<~MSG
65
+ PostgreSQL currently does not support VIRTUAL (not persisted) generated columns.
66
+ Specify 'stored: true' option for 'invalid_definition'
67
+ MSG
68
+
69
+ assert_raise ArgumentError, message do
70
+ @connection.change_table :virtual_columns do |t|
71
+ t.virtual :invalid_definition, type: :string, as: "LOWER(name)"
72
+ end
73
+ end
74
+ end
75
+
76
+ def test_schema_dumping
77
+ output = dump_table_schema("virtual_columns")
78
+ assert_match(/t\.virtual\s+"upper_name",\s+type: :string,\s+as: "upper\(\(name\)::text\)", stored: true$/i, output)
79
+ assert_match(/t\.virtual\s+"name_length",\s+type: :integer,\s+as: "length\(\(name\)::text\)", stored: true$/i, output)
80
+ assert_match(/t\.virtual\s+"name_octet_length",\s+type: :integer,\s+as: "octet_length\(\(name\)::text\)", stored: true$/i, output)
81
+ assert_match(/t\.virtual\s+"column2",\s+type: :integer,\s+as: "\(column1 \+ 1\)", stored: true$/i, output)
82
+ end
83
+
84
+ def test_build_fixture_sql
85
+ fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :virtual_columns).first
86
+ assert_equal 2, fixtures.size
87
+ end
88
+
89
+ def test_virtual_column_does_not_deduplicate_with_regular_column
90
+ @connection.create_table :regular_columns, force: true do |t|
91
+ t.string :name
92
+ end
93
+
94
+ regular_model = Class.new(ActiveRecord::Base) { self.table_name = "regular_columns" }
95
+
96
+ # Ensure deduplication has seen the virtual column first
97
+ VirtualColumn.columns_hash
98
+
99
+ regular_col = regular_model.columns_hash["name"]
100
+ virtual_col = VirtualColumn.columns_hash["upper_name"]
101
+
102
+ assert_predicate virtual_col, :virtual?
103
+ assert_not_predicate regular_col, :virtual?
104
+ assert_not_equal regular_col, virtual_col
105
+
106
+ # The regular column must not be excluded from inserts
107
+ record = regular_model.create!(name: "hello")
108
+ record.reload
109
+ assert_equal "hello", record.name
110
+ ensure
111
+ @connection.drop_table :regular_columns, if_exists: true
112
+ end
113
+ end
114
+ end
@@ -10,7 +10,7 @@ class PostgresqlXMLTest < ActiveRecord::PostgreSQLTestCase
10
10
  end
11
11
 
12
12
  def setup
13
- @connection = ActiveRecord::Base.connection
13
+ @connection = ActiveRecord::Base.lease_connection
14
14
  @connection.create_table("xml_data_type") do |t|
15
15
  t.xml "payload"
16
16
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "models/post"
5
+
6
+ module ActiveRecord
7
+ module ConnectionAdapters
8
+ class SQLite3Adapter
9
+ class BindParameterTest < ActiveRecord::SQLite3TestCase
10
+ fixtures :posts
11
+
12
+ def test_where_with_string_for_string_column_using_bind_parameters
13
+ assert_quoted_as "'Welcome to the weblog'", "Welcome to the weblog", match: 1
14
+ end
15
+
16
+ def test_where_with_integer_for_string_column_using_bind_parameters
17
+ assert_quoted_as "0", 0
18
+ end
19
+
20
+ def test_where_with_float_for_string_column_using_bind_parameters
21
+ assert_quoted_as "0.0", 0.0
22
+ end
23
+
24
+ def test_where_with_boolean_for_string_column_using_bind_parameters
25
+ assert_quoted_as "0", false
26
+ end
27
+
28
+ def test_where_with_decimal_for_string_column_using_bind_parameters
29
+ assert_quoted_as "0.0", BigDecimal(0)
30
+ end
31
+
32
+ def test_where_with_rational_for_string_column_using_bind_parameters
33
+ assert_quoted_as "0/1", Rational(0)
34
+ end
35
+
36
+ private
37
+ def assert_quoted_as(expected, value, match: 0)
38
+ relation = Post.where("title = ?", value)
39
+ assert_equal(
40
+ %{SELECT "posts".* FROM "posts" WHERE (title = #{expected})},
41
+ relation.to_sql,
42
+ )
43
+ if match == 0
44
+ assert_empty relation.to_a
45
+ else
46
+ assert_equal match, relation.count
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -7,7 +7,7 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase
7
7
  include SchemaDumpingHelper
8
8
 
9
9
  def setup
10
- @connection = ActiveRecord::Base.connection
10
+ @connection = ActiveRecord::Base.lease_connection
11
11
  @connection.create_table :collation_table_sqlite3, force: true do |t|
12
12
  t.string :string_nocase, collation: "NOCASE"
13
13
  t.text :text_rtrim, collation: "RTRIM"