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
@@ -3,12 +3,12 @@
3
3
  require "cases/helper"
4
4
  require "support/schema_dumping_helper"
5
5
 
6
- if ActiveRecord::Base.connection.supports_foreign_keys?
6
+ if ActiveRecord::Base.lease_connection.supports_foreign_keys?
7
7
  module ActiveRecord
8
8
  class Migration
9
9
  class ForeignKeyInCreateTest < ActiveRecord::TestCase
10
10
  def test_foreign_keys
11
- foreign_keys = ActiveRecord::Base.connection.foreign_keys("fk_test_has_fk")
11
+ foreign_keys = ActiveRecord::Base.lease_connection.foreign_keys("fk_test_has_fk")
12
12
  assert_equal 1, foreign_keys.size
13
13
 
14
14
  fk = foreign_keys.first
@@ -45,7 +45,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
45
45
  end
46
46
 
47
47
  def setup
48
- @connection = ActiveRecord::Base.connection
48
+ @connection = ActiveRecord::Base.lease_connection
49
49
  @migration = CreateRocketsMigration.new
50
50
  silence_stream($stdout) { @migration.migrate(:up) }
51
51
  Rocket.reset_table_name
@@ -93,7 +93,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
93
93
  end
94
94
 
95
95
  def test_rename_reference_column_of_child_table
96
- if current_adapter?(:Mysql2Adapter) && !@connection.send(:supports_rename_index?)
96
+ if current_adapter?(:Mysql2Adapter, :TrilogyAdapter) && !@connection.send(:supports_rename_index?)
97
97
  skip "Cannot drop index, needed in a foreign key constraint"
98
98
  end
99
99
 
@@ -177,14 +177,15 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
177
177
  end
178
178
 
179
179
  setup do
180
- @connection = ActiveRecord::Base.connection
180
+ @connection = ActiveRecord::Base.lease_connection
181
181
  @connection.create_table "rockets", force: true do |t|
182
182
  t.string :name
183
183
  end
184
184
 
185
185
  @connection.create_table "astronauts", force: true do |t|
186
186
  t.string :name
187
- t.references :rocket
187
+ t.references :rocket, type: :bigint
188
+ t.references :favorite_rocket
188
189
  end
189
190
  end
190
191
 
@@ -233,6 +234,16 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
233
234
  assert_equal "fk_rails_78146ddd2e", fk.name unless current_adapter?(:SQLite3Adapter)
234
235
  end
235
236
 
237
+ def test_add_foreign_key_with_if_not_exists_to_already_referenced_table
238
+ @connection.add_foreign_key :astronauts, :rockets
239
+ @connection.add_foreign_key :astronauts, :rockets, column: "favorite_rocket_id", if_not_exists: true
240
+
241
+ foreign_keys = @connection.foreign_keys("astronauts")
242
+ assert_equal 2, foreign_keys.size
243
+ assert foreign_keys.all? { |fk| fk.to_table == "rockets" }
244
+ assert_equal ["favorite_rocket_id", "rocket_id"], foreign_keys.map(&:column).sort
245
+ end
246
+
236
247
  def test_add_foreign_key_with_non_standard_primary_key
237
248
  @connection.create_table :space_shuttles, id: false, force: true do |t|
238
249
  t.bigint :pk, primary_key: true
@@ -260,7 +271,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
260
271
  assert_equal 1, foreign_keys.size
261
272
 
262
273
  fk = foreign_keys.first
263
- if current_adapter?(:Mysql2Adapter)
274
+ if current_adapter?(:Mysql2Adapter, :TrilogyAdapter)
264
275
  # ON DELETE RESTRICT is the default on MySQL
265
276
  assert_nil fk.on_delete
266
277
  else
@@ -299,6 +310,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
299
310
  end
300
311
 
301
312
  def test_add_foreign_key_with_on_update
313
+ skip "DB2 does not support ON UPDATE SET NULL" if current_adapter?(:IBM_DBAdapter)
302
314
  @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :nullify
303
315
 
304
316
  foreign_keys = @connection.foreign_keys("astronauts")
@@ -309,17 +321,19 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
309
321
  end
310
322
 
311
323
  def test_add_foreign_key_with_non_existent_from_table_raises
312
- e = assert_raises ArgumentError do
324
+ skip "DB2 error messages differ from expected format" if current_adapter?(:IBM_DBAdapter)
325
+ e = assert_raises StatementInvalid do
313
326
  @connection.add_foreign_key :missions, :rockets
314
327
  end
315
- assert_match(/missions/i, e.message)
328
+ assert_match(/missions/, e.message)
316
329
  end
317
330
 
318
331
  def test_add_foreign_key_with_non_existent_to_table_raises
319
- e = assert_raises ArgumentError do
332
+ skip "DB2 error messages differ from expected format" if current_adapter?(:IBM_DBAdapter)
333
+ e = assert_raises StatementInvalid do
320
334
  @connection.add_foreign_key :missions, :rockets
321
335
  end
322
- assert_match(/missions/i, e.message)
336
+ assert_match(/missions/, e.message)
323
337
  end
324
338
 
325
339
  def test_foreign_key_exists
@@ -329,6 +343,16 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
329
343
  assert_not @connection.foreign_key_exists?(:astronauts, :stars)
330
344
  end
331
345
 
346
+ def test_foreign_key_exists_referencing_table_having_keyword_as_name
347
+ @connection.create_table :user, force: true
348
+ @connection.add_column :rockets, :user_id, :bigint
349
+ @connection.add_foreign_key :rockets, :user
350
+ assert @connection.foreign_key_exists?(:rockets, :user)
351
+ ensure
352
+ @connection.remove_foreign_key :rockets, :user
353
+ @connection.drop_table :user
354
+ end
355
+
332
356
  def test_foreign_key_exists_by_column
333
357
  @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
334
358
 
@@ -359,6 +383,17 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
359
383
  end
360
384
  end
361
385
 
386
+ if supports_sql_standard_drop_constraint?
387
+ def test_remove_constraint
388
+ skip "DB2 SQL generation issue with DROP CONSTRAINT" if current_adapter?(:IBM_DBAdapter)
389
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk"
390
+
391
+ assert_equal 1, @connection.foreign_keys("astronauts").size
392
+ @connection.remove_constraint :astronauts, "fancy_named_fk"
393
+ assert_equal [], @connection.foreign_keys("astronauts")
394
+ end
395
+ end
396
+
362
397
  def test_remove_foreign_key_inferes_column
363
398
  @connection.add_foreign_key :astronauts, :rockets
364
399
 
@@ -412,7 +447,14 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
412
447
  @connection.foreign_keys("astronauts").map { |fk| [fk.from_table, fk.to_table, fk.column] }
413
448
  end
414
449
 
415
- if ActiveRecord::Base.connection.supports_validate_constraints?
450
+ def test_remove_foreign_key_with_restrict_action
451
+ @connection.add_foreign_key :astronauts, :rockets, on_delete: :restrict
452
+ assert_equal 1, @connection.foreign_keys("astronauts").size
453
+ @connection.remove_foreign_key :astronauts, :rockets, on_delete: :restrict
454
+ assert_empty @connection.foreign_keys("astronauts")
455
+ end
456
+
457
+ if ActiveRecord::Base.lease_connection.supports_validate_constraints?
416
458
  def test_add_invalid_foreign_key
417
459
  @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", validate: false
418
460
 
@@ -467,6 +509,22 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
467
509
  @connection.validate_constraint :astronauts, "fancy_named_fk"
468
510
  assert_predicate @connection.foreign_keys("astronauts").first, :validated?
469
511
  end
512
+
513
+ def test_schema_dumping_with_validate_false
514
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", validate: false
515
+
516
+ output = dump_table_schema "astronauts"
517
+
518
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", validate: false$}, output
519
+ end
520
+
521
+ def test_schema_dumping_with_validate_true
522
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", validate: true
523
+
524
+ output = dump_table_schema "astronauts"
525
+
526
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets"$}, output
527
+ end
470
528
  else
471
529
  # Foreign key should still be created, but should not be invalid
472
530
  def test_add_invalid_foreign_key
@@ -480,6 +538,113 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
480
538
  end
481
539
  end
482
540
 
541
+ if ActiveRecord::Base.lease_connection.supports_deferrable_constraints?
542
+ def test_deferrable_foreign_key
543
+ assert_queries_match(/\("id"\)\s+DEFERRABLE INITIALLY IMMEDIATE\W*\z/i) do
544
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :immediate
545
+ end
546
+
547
+ foreign_keys = @connection.foreign_keys("astronauts")
548
+ assert_equal 1, foreign_keys.size
549
+
550
+ fk = foreign_keys.first
551
+ assert_equal :immediate, fk.deferrable
552
+ end
553
+
554
+ def test_not_deferrable_foreign_key
555
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: false
556
+
557
+ foreign_keys = @connection.foreign_keys("astronauts")
558
+ assert_equal 1, foreign_keys.size
559
+
560
+ fk = foreign_keys.first
561
+ assert_equal false, fk.deferrable
562
+ end
563
+
564
+ def test_deferrable_initially_deferred_foreign_key
565
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :deferred
566
+
567
+ foreign_keys = @connection.foreign_keys("astronauts")
568
+ assert_equal 1, foreign_keys.size
569
+
570
+ fk = foreign_keys.first
571
+ assert_equal :deferred, fk.deferrable
572
+ end
573
+
574
+ def test_deferrable_initially_immediate_foreign_key
575
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :immediate
576
+
577
+ foreign_keys = @connection.foreign_keys("astronauts")
578
+ assert_equal 1, foreign_keys.size
579
+
580
+ fk = foreign_keys.first
581
+ assert_equal :immediate, fk.deferrable
582
+ end
583
+
584
+ def test_schema_dumping_with_defferable
585
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :immediate
586
+
587
+ output = dump_table_schema "astronauts"
588
+
589
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", deferrable: :immediate$}, output
590
+ end
591
+
592
+ def test_schema_dumping_with_disabled_defferable
593
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: false
594
+
595
+ output = dump_table_schema "astronauts"
596
+
597
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets"$}, output
598
+ end
599
+
600
+ def test_schema_dumping_with_defferable_initially_deferred
601
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :deferred
602
+
603
+ output = dump_table_schema "astronauts"
604
+
605
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", deferrable: :deferred$}, output
606
+ end
607
+
608
+ def test_schema_dumping_with_defferable_initially_immediate
609
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", deferrable: :immediate
610
+
611
+ output = dump_table_schema "astronauts"
612
+
613
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", deferrable: :immediate$}, output
614
+ end
615
+
616
+ def test_schema_dumping_with_special_chars_deferrable
617
+ @connection.add_reference :astronauts, :røcket, foreign_key: { to_table: :rockets, deferrable: :deferred }
618
+
619
+ output = dump_table_schema "astronauts"
620
+
621
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", column: "røcket_id", deferrable: :deferred$}, output
622
+ end
623
+ end
624
+
625
+ def test_does_not_create_foreign_keys_when_bypassed_by_config
626
+ skip "Test requires SQLite3Adapter" if current_adapter?(:IBM_DBAdapter)
627
+ require "active_record/connection_adapters/sqlite3_adapter"
628
+ connection = ActiveRecord::ConnectionAdapters::SQLite3Adapter.new(
629
+ adapter: "sqlite3",
630
+ database: ":memory:",
631
+ foreign_keys: false,
632
+ )
633
+
634
+ connection.create_table "rockets", force: true do |t|
635
+ t.string :name
636
+ end
637
+ connection.create_table "astronauts", force: true do |t|
638
+ t.string :name
639
+ t.references :rocket
640
+ end
641
+
642
+ connection.add_foreign_key :astronauts, :rockets
643
+
644
+ foreign_keys = connection.foreign_keys("astronauts")
645
+ assert_equal 0, foreign_keys.size
646
+ end
647
+
483
648
  def test_schema_dumping
484
649
  @connection.add_foreign_key :astronauts, :rockets
485
650
  output = dump_table_schema "astronauts"
@@ -507,6 +672,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
507
672
  end
508
673
 
509
674
  def test_schema_dumping_on_delete_and_on_update_options
675
+ skip "DB2 does not support ON UPDATE CASCADE" if current_adapter?(:IBM_DBAdapter)
510
676
  @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify, on_update: :cascade
511
677
 
512
678
  output = dump_table_schema "astronauts"
@@ -529,20 +695,30 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
529
695
  end
530
696
 
531
697
  def test_add_foreign_key_is_reversible
698
+ @connection.drop_table("cities", if_exists: true)
699
+ @connection.drop_table("houses", if_exists: true)
700
+
532
701
  migration = CreateCitiesAndHousesMigration.new
533
702
  silence_stream($stdout) { migration.migrate(:up) }
534
703
  assert_equal 1, @connection.foreign_keys("houses").size
535
- ensure
536
704
  silence_stream($stdout) { migration.migrate(:down) }
705
+ ensure
706
+ @connection.drop_table("cities", if_exists: true)
707
+ @connection.drop_table("houses", if_exists: true)
537
708
  end
538
709
 
539
710
  def test_foreign_key_constraint_is_not_cached_incorrectly
711
+ @connection.drop_table("cities", if_exists: true)
712
+ @connection.drop_table("houses", if_exists: true)
713
+
540
714
  migration = CreateCitiesAndHousesMigration.new
541
715
  silence_stream($stdout) { migration.migrate(:up) }
542
716
  output = dump_table_schema "houses"
543
717
  assert_match %r{\s+add_foreign_key "houses",.+on_delete: :cascade$}, output
544
- ensure
545
718
  silence_stream($stdout) { migration.migrate(:down) }
719
+ ensure
720
+ @connection.drop_table("cities", if_exists: true)
721
+ @connection.drop_table("houses", if_exists: true)
546
722
  end
547
723
 
548
724
  class CreateSchoolsAndClassesMigration < ActiveRecord::Migration::Current
@@ -575,6 +751,172 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
575
751
  silence_stream($stdout) { migration.migrate(:down) }
576
752
  ActiveRecord::Base.table_name_suffix = nil
577
753
  end
754
+
755
+ def test_remove_foreign_key_with_if_exists_not_set
756
+ @connection.add_foreign_key :astronauts, :rockets
757
+ assert_equal 1, @connection.foreign_keys("astronauts").size
758
+
759
+ @connection.remove_foreign_key :astronauts, :rockets
760
+ assert_equal [], @connection.foreign_keys("astronauts")
761
+
762
+ error = assert_raises do
763
+ @connection.remove_foreign_key :astronauts, :rockets
764
+ end
765
+
766
+ assert_equal("Table 'astronauts' has no foreign key for rockets", error.message)
767
+ end
768
+
769
+ def test_remove_foreign_key_with_if_exists_set
770
+ @connection.add_foreign_key :astronauts, :rockets
771
+ assert_equal 1, @connection.foreign_keys("astronauts").size
772
+
773
+ @connection.remove_foreign_key :astronauts, :rockets, if_exists: true
774
+ assert_equal [], @connection.foreign_keys("astronauts")
775
+
776
+ assert_nothing_raised do
777
+ @connection.remove_foreign_key :astronauts, :rockets, if_exists: true
778
+ end
779
+ end
780
+
781
+ def test_add_foreign_key_with_if_not_exists_not_set
782
+ @connection.add_foreign_key :astronauts, :rockets
783
+ assert_equal 1, @connection.foreign_keys("astronauts").size
784
+
785
+ if current_adapter?(:SQLite3Adapter)
786
+ assert_nothing_raised do
787
+ @connection.add_foreign_key :astronauts, :rockets
788
+ end
789
+ elsif current_adapter?(:IBM_DBAdapter)
790
+ skip "DB2 error message format differs from PostgreSQL"
791
+ else
792
+ error = assert_raises do
793
+ @connection.add_foreign_key :astronauts, :rockets
794
+ end
795
+
796
+ if current_adapter?(:Mysql2Adapter, :TrilogyAdapter)
797
+ if ActiveRecord::Base.lease_connection.mariadb?
798
+ assert_match(/Duplicate key on write or update/, error.message)
799
+ elsif ActiveRecord::Base.lease_connection.database_version < "8.0"
800
+ assert_match(/Can't write; duplicate key in table/, error.message)
801
+ else
802
+ assert_match(/Duplicate foreign key constraint name/, error.message)
803
+ end
804
+ else
805
+ assert_match(/PG::DuplicateObject: ERROR:.*for relation "astronauts" already exists/, error.message)
806
+ end
807
+
808
+ end
809
+ end
810
+
811
+ def test_add_foreign_key_with_if_not_exists_set
812
+ @connection.add_foreign_key :astronauts, :rockets
813
+ assert_equal 1, @connection.foreign_keys("astronauts").size
814
+
815
+ assert_nothing_raised do
816
+ @connection.add_foreign_key :astronauts, :rockets, if_not_exists: true
817
+ end
818
+ end
819
+
820
+ def test_add_foreign_key_preserves_existing_column_types
821
+ assert_no_changes -> { column_for(:astronauts, :rocket_id).bigint? }, from: true do
822
+ @connection.add_foreign_key :astronauts, :rockets
823
+ end
824
+ end
825
+
826
+ private
827
+ def column_for(table_name, column_name)
828
+ @connection.columns(table_name).find { |column| column.name == column_name.to_s }
829
+ end
830
+ end
831
+
832
+ class CompositeForeignKeyTest < ActiveRecord::TestCase
833
+ include SchemaDumpingHelper
834
+
835
+ setup do
836
+ @connection = ActiveRecord::Base.lease_connection
837
+ @connection.create_table :rockets, primary_key: [:tenant_id, :id], force: true do |t|
838
+ t.integer :tenant_id
839
+ t.integer :id
840
+ end
841
+ @connection.create_table :astronauts, force: true do |t|
842
+ t.integer :rocket_id
843
+ t.integer :rocket_tenant_id
844
+ end
845
+ end
846
+
847
+ teardown do
848
+ @connection.drop_table :astronauts, if_exists: true rescue nil
849
+ @connection.drop_table :rockets, if_exists: true rescue nil
850
+ end
851
+
852
+ def test_add_composite_foreign_key_raises_without_options
853
+ error = assert_raises(ActiveRecord::StatementInvalid) do
854
+ @connection.add_foreign_key :astronauts, :rockets
855
+ end
856
+
857
+ if current_adapter?(:PostgreSQLAdapter)
858
+ assert_match(/there is no unique constraint matching given keys for referenced table "rockets"/, error.message)
859
+ elsif current_adapter?(:SQLite3Adapter)
860
+ assert_match(/foreign key mismatch - "astronauts" referencing "rockets"/, error.message)
861
+ else
862
+ # MariaDB and different versions of MySQL generate different error messages.
863
+ [
864
+ /Foreign key constraint is incorrectly formed/i,
865
+ /Failed to add the foreign key constraint/i,
866
+ /Cannot add foreign key constraint/i
867
+ ].any? { |message| error.message.match?(message) }
868
+ end
869
+ end
870
+
871
+ def test_add_composite_foreign_key_infers_column
872
+ @connection.add_foreign_key :astronauts, :rockets, primary_key: [:tenant_id, :id]
873
+
874
+ foreign_keys = @connection.foreign_keys(:astronauts)
875
+ assert_equal 1, foreign_keys.size
876
+
877
+ fk = foreign_keys.first
878
+ assert_equal ["rocket_tenant_id", "rocket_id"], fk.column
879
+ end
880
+
881
+ def test_add_composite_foreign_key_raises_if_column_and_primary_key_sizes_mismatch
882
+ assert_raises(ArgumentError, match: ":column must reference all the :primary_key columns") do
883
+ @connection.add_foreign_key :astronauts, :rockets, column: :rocket_id, primary_key: [:tenant_id, :id]
884
+ end
885
+ end
886
+
887
+ def test_foreign_key_exists
888
+ @connection.add_foreign_key :astronauts, :rockets, primary_key: [:tenant_id, :id]
889
+
890
+ assert @connection.foreign_key_exists?(:astronauts, :rockets)
891
+ assert_not @connection.foreign_key_exists?(:astronauts, :stars)
892
+ end
893
+
894
+ def test_foreign_key_exists_by_options
895
+ @connection.add_foreign_key :astronauts, :rockets, primary_key: [:tenant_id, :id]
896
+
897
+ assert @connection.foreign_key_exists?(:astronauts, :rockets, primary_key: [:tenant_id, :id])
898
+ assert @connection.foreign_key_exists?(:astronauts, :rockets, column: [:rocket_tenant_id, :rocket_id], primary_key: [:tenant_id, :id])
899
+
900
+ assert_not @connection.foreign_key_exists?(:astronauts, :rockets, primary_key: [:id, :tenant_id])
901
+ assert_not @connection.foreign_key_exists?(:astronauts, :rockets, primary_key: :id)
902
+ assert_not @connection.foreign_key_exists?(:astronauts, :rockets, column: :rocket_id)
903
+ end
904
+
905
+ def test_remove_foreign_key
906
+ @connection.add_foreign_key :astronauts, :rockets, primary_key: [:tenant_id, :id]
907
+ assert_equal 1, @connection.foreign_keys(:astronauts).size
908
+
909
+ @connection.remove_foreign_key :astronauts, :rockets
910
+ assert_empty @connection.foreign_keys(:astronauts)
911
+ end
912
+
913
+ def test_schema_dumping
914
+ @connection.add_foreign_key :astronauts, :rockets, primary_key: [:tenant_id, :id]
915
+
916
+ output = dump_table_schema "astronauts"
917
+
918
+ assert_match %r{\s+add_foreign_key "astronauts", "rockets", column: \["rocket_tenant_id", "rocket_id"\], primary_key: \["tenant_id", "id"\]$}, output
919
+ end
578
920
  end
579
921
  end
580
922
  end
@@ -18,7 +18,10 @@ module ActiveRecord
18
18
 
19
19
  def setup
20
20
  super
21
- @connection = ActiveRecord::Base.connection
21
+ @connection = ActiveRecord::Base.lease_connection
22
+ connection.drop_table :testings, if_exists: true rescue nil
23
+ connection.drop_table :testing, if_exists: true rescue nil
24
+ connection.drop_table :test_models, if_exists: true rescue nil
22
25
  connection.create_table :test_models do |t|
23
26
  t.timestamps null: true
24
27
  end
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
 
10
10
  def setup
11
11
  super
12
- @connection = ActiveRecord::Base.connection
12
+ @connection = ActiveRecord::Base.lease_connection
13
13
  @table_name = :testings
14
14
 
15
15
  connection.create_table table_name do |t|
@@ -103,6 +103,11 @@ module ActiveRecord
103
103
  assert connection.index_name_exists?(table_name, "index_testings_on_foo_and_bar")
104
104
  end
105
105
 
106
+ def test_add_index_fallback_to_short_name
107
+ connection.add_index(table_name, [:foo, :bar, :first_name, :last_name, :administrator])
108
+ assert connection.index_name_exists?(table_name, "idx_on_foo_bar_first_name_last_name_administrator_5939248142")
109
+ end
110
+
106
111
  def test_remove_index_which_does_not_exist_doesnt_raise_with_option
107
112
  connection.add_index(table_name, "foo")
108
113
 
@@ -127,6 +132,19 @@ module ActiveRecord
127
132
  assert_not connection.index_exists?(table_name, :foo, name: "foo")
128
133
  end
129
134
 
135
+ def test_remove_index_with_column_array_which_does_not_exist_doesnt_raise_with_option
136
+ connection.add_index(table_name, [:foo], name: "foo")
137
+
138
+ assert connection.index_exists?(table_name, :foo, name: "foo")
139
+
140
+ assert_nothing_raised do
141
+ connection.remove_index(table_name, column: [:foo, :bar], if_exists: true)
142
+ end
143
+
144
+ assert connection.index_exists?(table_name, :foo, name: "foo")
145
+ assert_not connection.index_exists?(table_name, nil, column: [:foo, :bar], name: "foo")
146
+ end
147
+
130
148
  def test_internal_index_with_name_matching_database_limit
131
149
  good_index_name = "x" * connection.index_name_length
132
150
  connection.add_index(table_name, "foo", name: good_index_name, internal: true)
@@ -159,6 +177,7 @@ module ActiveRecord
159
177
  def test_index_exists_with_custom_name_checks_columns
160
178
  connection.add_index :testings, [:foo, :bar], name: "my_index"
161
179
  assert connection.index_exists?(:testings, [:foo, :bar], name: "my_index")
180
+ assert connection.index_exists?(:testings, [], name: "my_index")
162
181
  assert_not connection.index_exists?(:testings, [:foo], name: "my_index")
163
182
  end
164
183
 
@@ -201,7 +220,9 @@ module ActiveRecord
201
220
 
202
221
  def test_add_index
203
222
  connection.add_index("testings", "last_name")
223
+ assert connection.index_exists?("testings", "last_name")
204
224
  connection.remove_index("testings", "last_name")
225
+ assert_not connection.index_exists?("testings", "last_name")
205
226
 
206
227
  connection.add_index("testings", ["last_name", "first_name"])
207
228
  connection.remove_index("testings", column: ["last_name", "first_name"])
@@ -236,7 +257,7 @@ module ActiveRecord
236
257
  connection.remove_index("testings", name: "named_admin")
237
258
 
238
259
  # Selected adapters support index sort order
239
- if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter)
260
+ if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :TrilogyAdapter, :PostgreSQLAdapter)
240
261
  connection.add_index("testings", ["last_name"], order: { last_name: :desc })
241
262
  connection.remove_index("testings", ["last_name"])
242
263
  connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc })
@@ -256,6 +277,50 @@ module ActiveRecord
256
277
  connection.remove_index("testings", "last_name")
257
278
  assert_not connection.index_exists?("testings", "last_name")
258
279
  end
280
+
281
+ def test_add_index_with_included_column
282
+ skip("current adapter doesn't support include indexes") unless supports_index_include?
283
+
284
+ connection.add_index("testings", "last_name", include: :foo)
285
+ assert connection.index_exists?("testings", "last_name", include: :foo)
286
+
287
+ connection.remove_index("testings", "last_name")
288
+ assert_not connection.index_exists?("testings", "last_name")
289
+ end
290
+
291
+ def test_add_index_with_multiple_included_columns
292
+ skip("current adapter doesn't support include indexes") unless supports_index_include?
293
+
294
+ connection.add_index("testings", "last_name", include: [:foo, :bar])
295
+ assert connection.index_exists?("testings", "last_name", include: [:foo, :bar])
296
+
297
+ connection.remove_index("testings", "last_name")
298
+ assert_not connection.index_exists?("testings", "last_name")
299
+ end
300
+
301
+ def test_add_index_with_included_column_and_where_clause
302
+ skip("current adapter doesn't support include indexes") unless supports_index_include?
303
+
304
+ connection.add_index("testings", "last_name", include: :foo, where: "first_name = 'john doe'")
305
+ assert connection.index_exists?("testings", "last_name", include: :foo, where: "first_name = 'john doe'")
306
+
307
+ connection.remove_index("testings", "last_name")
308
+ assert_not connection.index_exists?("testings", "last_name", include: :foo, where: "first_name = 'john doe'")
309
+ end
310
+
311
+ def test_add_index_with_nulls_not_distinct_assert_exists_with_same_values
312
+ skip("current adapter doesn't support nulls not distinct") unless supports_nulls_not_distinct?
313
+
314
+ connection.add_index("testings", "last_name", nulls_not_distinct: true)
315
+ assert connection.index_exists?("testings", "last_name", nulls_not_distinct: true)
316
+ end
317
+
318
+ def test_add_index_with_nulls_not_distinct_assert_exists_with_different_values
319
+ skip("current adapter doesn't support nulls not distinct") unless supports_nulls_not_distinct?
320
+
321
+ connection.add_index("testings", "last_name", nulls_not_distinct: false)
322
+ assert_not connection.index_exists?("testings", "last_name", nulls_not_distinct: true)
323
+ end
259
324
  end
260
325
 
261
326
  private