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
@@ -16,18 +16,21 @@ module ActiveRecord
16
16
  end
17
17
 
18
18
  def setup
19
- @conn = Base.sqlite3_connection database: ":memory:",
20
- adapter: "sqlite3",
21
- timeout: 100
22
-
23
- @connection_handler = ActiveRecord::Base.connection_handler
19
+ @conn = SQLite3Adapter.new(
20
+ database: ":memory:",
21
+ adapter: "sqlite3",
22
+ timeout: 100,
23
+ )
24
24
  end
25
25
 
26
- def test_bad_connection
27
- assert_raise ActiveRecord::NoDatabaseError do
28
- connection = ActiveRecord::Base.sqlite3_connection(adapter: "sqlite3", database: "/tmp/should/_not/_exist/-cinco-dog.db")
26
+ def test_database_should_get_created_when_missing_parent_directories_for_database_path
27
+ dir = Dir.mktmpdir
28
+ db_path = File.join(dir, "_not_exist/-cinco-dog.sqlite3")
29
+ assert_nothing_raised do
30
+ connection = SQLite3Adapter.new(adapter: "sqlite3", database: db_path)
29
31
  connection.drop_table "ex", if_exists: true
30
32
  end
33
+ assert SQLite3Adapter.database_exists?(adapter: "sqlite3", database: db_path)
31
34
  end
32
35
 
33
36
  def test_database_exists_returns_false_when_the_database_does_not_exist
@@ -47,7 +50,7 @@ module ActiveRecord
47
50
  tf = Tempfile.open "whatever"
48
51
  url = "sqlite3:#{tf.path}"
49
52
  ActiveRecord::Base.establish_connection(url)
50
- assert ActiveRecord::Base.connection
53
+ assert ActiveRecord::Base.lease_connection
51
54
  ensure
52
55
  tf.close
53
56
  tf.unlink
@@ -58,7 +61,7 @@ module ActiveRecord
58
61
  original_connection = ActiveRecord::Base.remove_connection
59
62
  url = "sqlite3::memory:"
60
63
  ActiveRecord::Base.establish_connection(url)
61
- assert ActiveRecord::Base.connection
64
+ assert ActiveRecord::Base.lease_connection
62
65
  ensure
63
66
  ActiveRecord::Base.establish_connection(original_connection)
64
67
  end
@@ -73,7 +76,7 @@ module ActiveRecord
73
76
  owner = Owner.create!(name: "hello".encode("ascii-8bit"))
74
77
  owner.reload
75
78
  select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ", "
76
- result = Owner.connection.exec_query <<~SQL
79
+ result = Owner.lease_connection.exec_query <<~SQL
77
80
  SELECT #{select}
78
81
  FROM #{Owner.table_name}
79
82
  WHERE #{Owner.primary_key} = #{owner.id}
@@ -97,6 +100,19 @@ module ActiveRecord
97
100
  end
98
101
  end
99
102
 
103
+ def test_exec_insert_with_quote
104
+ with_example_table do
105
+ vals = [Relation::QueryAttribute.new("number", 10, Type::Value.new)]
106
+ @conn.exec_insert("insert into \"ex\" (number) VALUES (?)", "SQL", vals)
107
+
108
+ result = @conn.exec_query(
109
+ "select number from \"ex\" where number = ?", "SQL", vals)
110
+
111
+ assert_equal 1, result.rows.length
112
+ assert_equal 10, result.rows.first.first
113
+ end
114
+ end
115
+
100
116
  def test_primary_key_returns_nil_for_no_pk
101
117
  with_example_table "id int, data string" do
102
118
  assert_nil @conn.primary_key("ex")
@@ -105,23 +121,30 @@ module ActiveRecord
105
121
 
106
122
  def test_connection_no_db
107
123
  assert_raises(ArgumentError) do
108
- Base.sqlite3_connection { }
124
+ SQLite3Adapter.new({})
109
125
  end
110
126
  end
111
127
 
112
128
  def test_bad_timeout
113
- assert_raises(TypeError) do
114
- Base.sqlite3_connection database: ":memory:",
115
- adapter: "sqlite3",
116
- timeout: "usa"
129
+ exception = assert_raises(ActiveRecord::StatementInvalid) do
130
+ SQLite3Adapter.new(
131
+ database: ":memory:",
132
+ adapter: "sqlite3",
133
+ timeout: "usa",
134
+ ).connect!
117
135
  end
136
+ assert_match("TypeError", exception.message)
137
+ assert_kind_of ActiveRecord::ConnectionAdapters::NullPool, exception.connection_pool
118
138
  end
119
139
 
120
140
  # connection is OK with a nil timeout
121
141
  def test_nil_timeout
122
- conn = Base.sqlite3_connection database: ":memory:",
123
- adapter: "sqlite3",
124
- timeout: nil
142
+ conn = SQLite3Adapter.new(
143
+ database: ":memory:",
144
+ adapter: "sqlite3",
145
+ timeout: nil,
146
+ )
147
+ conn.connect!
125
148
  assert conn, "made a connection"
126
149
  end
127
150
 
@@ -134,6 +157,269 @@ module ActiveRecord
134
157
  assert_equal "UTF-8", @conn.encoding
135
158
  end
136
159
 
160
+ def test_default_pragmas
161
+ if in_memory_db?
162
+ assert_equal [{ "foreign_keys" => 1 }], @conn.execute("PRAGMA foreign_keys")
163
+ assert_equal [{ "journal_mode" => "memory" }], @conn.execute("PRAGMA journal_mode")
164
+ assert_equal [{ "synchronous" => 1 }], @conn.execute("PRAGMA synchronous")
165
+ assert_equal [{ "journal_size_limit" => 67108864 }], @conn.execute("PRAGMA journal_size_limit")
166
+ assert_equal [], @conn.execute("PRAGMA mmap_size")
167
+ assert_equal [{ "cache_size" => 2000 }], @conn.execute("PRAGMA cache_size")
168
+ else
169
+ with_file_connection do |conn|
170
+ assert_equal [{ "foreign_keys" => 1 }], conn.execute("PRAGMA foreign_keys")
171
+ assert_equal [{ "journal_mode" => "wal" }], conn.execute("PRAGMA journal_mode")
172
+ assert_equal [{ "synchronous" => 1 }], conn.execute("PRAGMA synchronous")
173
+ assert_equal [{ "journal_size_limit" => 67108864 }], conn.execute("PRAGMA journal_size_limit")
174
+ assert_equal [{ "mmap_size" => 134217728 }], conn.execute("PRAGMA mmap_size")
175
+ assert_equal [{ "cache_size" => 2000 }], conn.execute("PRAGMA cache_size")
176
+ end
177
+ end
178
+ end
179
+
180
+ def test_overriding_default_foreign_keys_pragma
181
+ method_name = in_memory_db? ? :with_memory_connection : :with_file_connection
182
+
183
+ send(method_name, pragmas: { foreign_keys: false }) do |conn|
184
+ assert_equal [{ "foreign_keys" => 0 }], conn.execute("PRAGMA foreign_keys")
185
+ end
186
+
187
+ send(method_name, pragmas: { foreign_keys: 0 }) do |conn|
188
+ assert_equal [{ "foreign_keys" => 0 }], conn.execute("PRAGMA foreign_keys")
189
+ end
190
+
191
+ send(method_name, pragmas: { foreign_keys: "false" }) do |conn|
192
+ assert_equal [{ "foreign_keys" => 0 }], conn.execute("PRAGMA foreign_keys")
193
+ end
194
+
195
+ error = assert_raises(ActiveRecord::StatementInvalid) do
196
+ send(method_name, pragmas: { foreign_keys: :false }) do |conn|
197
+ conn.execute("PRAGMA foreign_keys")
198
+ end
199
+ end
200
+ assert_match(/unrecognized pragma parameter :false/, error.message)
201
+ end
202
+
203
+ def test_overriding_default_journal_mode_pragma
204
+ # in-memory databases are always only ever in `memory` journal_mode
205
+ if in_memory_db?
206
+ with_memory_connection(pragmas: { "journal_mode" => "delete" }) do |conn|
207
+ assert_equal [{ "journal_mode" => "memory" }], conn.execute("PRAGMA journal_mode")
208
+ end
209
+
210
+ with_memory_connection(pragmas: { "journal_mode" => :delete }) do |conn|
211
+ assert_equal [{ "journal_mode" => "memory" }], conn.execute("PRAGMA journal_mode")
212
+ end
213
+
214
+ error = assert_raises(ActiveRecord::StatementInvalid) do
215
+ with_memory_connection(pragmas: { "journal_mode" => 0 }) do |conn|
216
+ conn.execute("PRAGMA journal_mode")
217
+ end
218
+ end
219
+ assert_match(/nrecognized journal_mode 0/, error.message)
220
+
221
+ error = assert_raises(ActiveRecord::StatementInvalid) do
222
+ with_memory_connection(pragmas: { "journal_mode" => false }) do |conn|
223
+ conn.execute("PRAGMA journal_mode")
224
+ end
225
+ end
226
+ assert_match(/nrecognized journal_mode false/, error.message)
227
+ else
228
+ # must use a new, separate database file that hasn't been opened in WAL mode before
229
+ Dir.mktmpdir do |tmpdir|
230
+ database_file = File.join(tmpdir, "journal_mode_test.sqlite3")
231
+
232
+ with_file_connection(database: database_file, pragmas: { "journal_mode" => "delete" }) do |conn|
233
+ assert_equal [{ "journal_mode" => "delete" }], conn.execute("PRAGMA journal_mode")
234
+ end
235
+
236
+ with_file_connection(database: database_file, pragmas: { "journal_mode" => :delete }) do |conn|
237
+ assert_equal [{ "journal_mode" => "delete" }], conn.execute("PRAGMA journal_mode")
238
+ end
239
+
240
+ error = assert_raises(ActiveRecord::StatementInvalid) do
241
+ with_file_connection(database: database_file, pragmas: { "journal_mode" => 0 }) do |conn|
242
+ conn.execute("PRAGMA journal_mode")
243
+ end
244
+ end
245
+ assert_match(/unrecognized journal_mode 0/, error.message)
246
+
247
+ error = assert_raises(ActiveRecord::StatementInvalid) do
248
+ with_file_connection(database: database_file, pragmas: { "journal_mode" => false }) do |conn|
249
+ conn.execute("PRAGMA journal_mode")
250
+ end
251
+ end
252
+ assert_match(/unrecognized journal_mode false/, error.message)
253
+ end
254
+ end
255
+ end
256
+
257
+ def test_overriding_default_synchronous_pragma
258
+ method_name = in_memory_db? ? :with_memory_connection : :with_file_connection
259
+
260
+ send(method_name, pragmas: { synchronous: :full }) do |conn|
261
+ assert_equal [{ "synchronous" => 2 }], conn.execute("PRAGMA synchronous")
262
+ end
263
+
264
+ send(method_name, pragmas: { synchronous: 2 }) do |conn|
265
+ assert_equal [{ "synchronous" => 2 }], conn.execute("PRAGMA synchronous")
266
+ end
267
+
268
+ send(method_name, pragmas: { synchronous: "full" }) do |conn|
269
+ assert_equal [{ "synchronous" => 2 }], conn.execute("PRAGMA synchronous")
270
+ end
271
+
272
+ error = assert_raises(ActiveRecord::StatementInvalid) do
273
+ send(method_name, pragmas: { synchronous: false }) do |conn|
274
+ conn.execute("PRAGMA synchronous")
275
+ end
276
+ end
277
+ assert_match(/unrecognized synchronous false/, error.message)
278
+ end
279
+
280
+ def test_overriding_default_journal_size_limit_pragma
281
+ method_name = in_memory_db? ? :with_memory_connection : :with_file_connection
282
+
283
+ send(method_name, pragmas: { journal_size_limit: 100 }) do |conn|
284
+ assert_equal [{ "journal_size_limit" => 100 }], conn.execute("PRAGMA journal_size_limit")
285
+ end
286
+
287
+ send(method_name, pragmas: { journal_size_limit: "200" }) do |conn|
288
+ assert_equal [{ "journal_size_limit" => 200 }], conn.execute("PRAGMA journal_size_limit")
289
+ end
290
+
291
+ error = assert_raises(ActiveRecord::StatementInvalid) do
292
+ send(method_name, pragmas: { journal_size_limit: false }) do |conn|
293
+ conn.execute("PRAGMA journal_size_limit")
294
+ end
295
+ end
296
+ assert_match(/undefined method [`']to_i'/, error.message)
297
+
298
+ error = assert_raises(ActiveRecord::StatementInvalid) do
299
+ send(method_name, pragmas: { journal_size_limit: :false }) do |conn|
300
+ conn.execute("PRAGMA journal_size_limit")
301
+ end
302
+ end
303
+ assert_match(/undefined method [`']to_i'/, error.message)
304
+ end
305
+
306
+ def test_overriding_default_mmap_size_pragma
307
+ # in-memory databases never have an mmap_size
308
+ if in_memory_db?
309
+ with_memory_connection(pragmas: { mmap_size: 100 }) do |conn|
310
+ assert_equal [], conn.execute("PRAGMA mmap_size")
311
+ end
312
+
313
+ with_memory_connection(pragmas: { mmap_size: "200" }) do |conn|
314
+ assert_equal [], conn.execute("PRAGMA mmap_size")
315
+ end
316
+
317
+ error = assert_raises(ActiveRecord::StatementInvalid) do
318
+ with_memory_connection(pragmas: { mmap_size: false }) do |conn|
319
+ conn.execute("PRAGMA mmap_size")
320
+ end
321
+ end
322
+ assert_match(/undefined method [`']to_i'/, error.message)
323
+
324
+ error = assert_raises(ActiveRecord::StatementInvalid) do
325
+ with_memory_connection(pragmas: { mmap_size: :false }) do |conn|
326
+ conn.execute("PRAGMA mmap_size")
327
+ end
328
+ end
329
+ assert_match(/undefined method [`']to_i'/, error.message)
330
+ else
331
+ with_file_connection(pragmas: { mmap_size: 100 }) do |conn|
332
+ assert_equal [{ "mmap_size" => 100 }], conn.execute("PRAGMA mmap_size")
333
+ end
334
+
335
+ with_file_connection(pragmas: { mmap_size: "200" }) do |conn|
336
+ assert_equal [{ "mmap_size" => 200 }], conn.execute("PRAGMA mmap_size")
337
+ end
338
+
339
+ error = assert_raises(ActiveRecord::StatementInvalid) do
340
+ with_file_connection(pragmas: { mmap_size: false }) do |conn|
341
+ conn.execute("PRAGMA mmap_size")
342
+ end
343
+ end
344
+ assert_match(/undefined method [`']to_i'/, error.message)
345
+
346
+ error = assert_raises(ActiveRecord::StatementInvalid) do
347
+ with_file_connection(pragmas: { mmap_size: :false }) do |conn|
348
+ conn.execute("PRAGMA mmap_size")
349
+ end
350
+ end
351
+ assert_match(/undefined method [`']to_i'/, error.message)
352
+ end
353
+ end
354
+
355
+ def test_overriding_default_cache_size_pragma
356
+ method_name = in_memory_db? ? :with_memory_connection : :with_file_connection
357
+
358
+ send(method_name, pragmas: { cache_size: 100 }) do |conn|
359
+ assert_equal [{ "cache_size" => 100 }], conn.execute("PRAGMA cache_size")
360
+ end
361
+
362
+ send(method_name, pragmas: { cache_size: "200" }) do |conn|
363
+ assert_equal [{ "cache_size" => 200 }], conn.execute("PRAGMA cache_size")
364
+ end
365
+
366
+ error = assert_raises(ActiveRecord::StatementInvalid) do
367
+ send(method_name, pragmas: { cache_size: false }) do |conn|
368
+ conn.execute("PRAGMA cache_size")
369
+ end
370
+ end
371
+ assert_match(/undefined method [`']to_i'/, error.message)
372
+
373
+ error = assert_raises(ActiveRecord::StatementInvalid) do
374
+ send(method_name, pragmas: { cache_size: :false }) do |conn|
375
+ conn.execute("PRAGMA cache_size")
376
+ end
377
+ end
378
+ assert_match(/undefined method [`']to_i'/, error.message)
379
+ end
380
+
381
+ def test_setting_new_pragma
382
+ if in_memory_db?
383
+ with_memory_connection(pragmas: { temp_store: :memory }) do |conn|
384
+ assert_equal [{ "foreign_keys" => 1 }], conn.execute("PRAGMA foreign_keys")
385
+ assert_equal [{ "journal_mode" => "memory" }], conn.execute("PRAGMA journal_mode")
386
+ assert_equal [{ "synchronous" => 1 }], conn.execute("PRAGMA synchronous")
387
+ assert_equal [{ "journal_size_limit" => 67108864 }], conn.execute("PRAGMA journal_size_limit")
388
+ assert_equal [], conn.execute("PRAGMA mmap_size")
389
+ assert_equal [{ "cache_size" => 2000 }], conn.execute("PRAGMA cache_size")
390
+ assert_equal [{ "temp_store" => 2 }], conn.execute("PRAGMA temp_store")
391
+ end
392
+ else
393
+ with_file_connection(pragmas: { temp_store: :memory }) do |conn|
394
+ assert_equal [{ "foreign_keys" => 1 }], conn.execute("PRAGMA foreign_keys")
395
+ assert_equal [{ "journal_mode" => "wal" }], conn.execute("PRAGMA journal_mode")
396
+ assert_equal [{ "synchronous" => 1 }], conn.execute("PRAGMA synchronous")
397
+ assert_equal [{ "journal_size_limit" => 67108864 }], conn.execute("PRAGMA journal_size_limit")
398
+ assert_equal [{ "mmap_size" => 134217728 }], conn.execute("PRAGMA mmap_size")
399
+ assert_equal [{ "cache_size" => 2000 }], conn.execute("PRAGMA cache_size")
400
+ assert_equal [{ "temp_store" => 2 }], conn.execute("PRAGMA temp_store")
401
+ end
402
+ end
403
+ end
404
+
405
+ def test_setting_invalid_pragma
406
+ if in_memory_db?
407
+ warning = capture(:stderr) do
408
+ with_memory_connection(pragmas: { invalid: true }) do |conn|
409
+ conn.execute("PRAGMA foreign_keys")
410
+ end
411
+ end
412
+ assert_match(/Unknown SQLite pragma: invalid/, warning)
413
+ else
414
+ warning = capture(:stderr) do
415
+ with_file_connection(pragmas: { invalid: true }) do |conn|
416
+ conn.execute("PRAGMA foreign_keys")
417
+ end
418
+ end
419
+ assert_match(/Unknown SQLite pragma: invalid/, warning)
420
+ end
421
+ end
422
+
137
423
  def test_exec_no_binds
138
424
  with_example_table "id int, data string" do
139
425
  result = @conn.exec_query("SELECT id, data FROM ex")
@@ -141,7 +427,7 @@ module ActiveRecord
141
427
  assert_equal 2, result.columns.length
142
428
  assert_equal %w{ id data }, result.columns
143
429
 
144
- @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
430
+ @conn.exec_query("INSERT INTO ex (id, data) VALUES (1, 'foo')")
145
431
  result = @conn.exec_query("SELECT id, data FROM ex")
146
432
  assert_equal 1, result.rows.length
147
433
  assert_equal 2, result.columns.length
@@ -152,7 +438,7 @@ module ActiveRecord
152
438
 
153
439
  def test_exec_query_with_binds
154
440
  with_example_table "id int, data string" do
155
- @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
441
+ @conn.exec_query("INSERT INTO ex (id, data) VALUES (1, 'foo')")
156
442
  result = @conn.exec_query(
157
443
  "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new(nil, 1, Type::Value.new)])
158
444
 
@@ -165,7 +451,7 @@ module ActiveRecord
165
451
 
166
452
  def test_exec_query_typecasts_bind_vals
167
453
  with_example_table "id int, data string" do
168
- @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
454
+ @conn.exec_query("INSERT INTO ex (id, data) VALUES (1, 'foo')")
169
455
 
170
456
  result = @conn.exec_query(
171
457
  "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new)])
@@ -178,7 +464,7 @@ module ActiveRecord
178
464
  end
179
465
 
180
466
  def test_quote_binary_column_escapes_it
181
- DualEncoding.connection.execute(<<~SQL)
467
+ DualEncoding.lease_connection.execute(<<~SQL)
182
468
  CREATE TABLE IF NOT EXISTS dual_encodings (
183
469
  id integer PRIMARY KEY AUTOINCREMENT,
184
470
  name varchar(255),
@@ -190,7 +476,7 @@ module ActiveRecord
190
476
  binary.save!
191
477
  assert_equal str, binary.data
192
478
  ensure
193
- DualEncoding.connection.drop_table "dual_encodings", if_exists: true
479
+ DualEncoding.lease_connection.drop_table "dual_encodings", if_exists: true
194
480
  end
195
481
 
196
482
  def test_type_cast_should_not_mutate_encoding
@@ -213,15 +499,15 @@ module ActiveRecord
213
499
  end
214
500
  end
215
501
 
216
- def test_quote_string
217
- assert_equal "''", @conn.quote_string("'")
218
- end
219
-
220
502
  def test_insert_logged
221
503
  with_example_table do
222
504
  sql = "INSERT INTO ex (number) VALUES (10)"
223
505
  name = "foo"
224
- assert_logged [[sql, name, []]] do
506
+
507
+ pragma_query = ["PRAGMA table_xinfo(\"ex\")", "SCHEMA", []]
508
+ schema_query = ["SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = 'ex'", "SCHEMA", []]
509
+ modified_insert_query = [(sql + ' RETURNING "id"'), name, []]
510
+ assert_logged [pragma_query, schema_query, modified_insert_query] do
225
511
  @conn.insert(sql, name)
226
512
  end
227
513
  end
@@ -236,6 +522,36 @@ module ActiveRecord
236
522
  end
237
523
  end
238
524
 
525
+ def test_exec_insert_with_returning_disabled
526
+ original_conn = @conn
527
+ @conn = SQLite3Adapter.new(
528
+ database: ":memory:",
529
+ adapter: "sqlite3",
530
+ insert_returning: false,
531
+ )
532
+ with_example_table do
533
+ result = @conn.exec_insert("insert into ex (number) VALUES ('foo')", nil, [], "id")
534
+ expect = @conn.query("select max(id) from ex").first.first
535
+ assert_equal expect.to_i, result.rows.first.first
536
+ end
537
+ @conn = original_conn
538
+ end
539
+
540
+ def test_exec_insert_default_values_with_returning_disabled
541
+ original_conn = @conn
542
+ @conn = SQLite3Adapter.new(
543
+ database: ":memory:",
544
+ adapter: "sqlite3",
545
+ insert_returning: false,
546
+ )
547
+ with_example_table do
548
+ result = @conn.exec_insert("insert into ex DEFAULT VALUES", nil, [], "id")
549
+ expect = @conn.query("select max(id) from ex").first.first
550
+ assert_equal expect.to_i, result.rows.first.first
551
+ end
552
+ @conn = original_conn
553
+ end
554
+
239
555
  def test_select_rows
240
556
  with_example_table do
241
557
  2.times do |i|
@@ -280,8 +596,9 @@ module ActiveRecord
280
596
 
281
597
  def test_tables_logs_name
282
598
  sql = <<~SQL
283
- SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND type IN ('table')
599
+ SELECT name FROM pragma_table_list WHERE schema <> 'temp' AND name NOT IN ('sqlite_sequence', 'sqlite_schema') AND type IN ('table')
284
600
  SQL
601
+ @conn.connect!
285
602
  assert_logged [[sql.squish, "SCHEMA", []]] do
286
603
  @conn.tables
287
604
  end
@@ -290,7 +607,7 @@ module ActiveRecord
290
607
  def test_table_exists_logs_name
291
608
  with_example_table do
292
609
  sql = <<~SQL
293
- SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND name = 'ex' AND type IN ('table')
610
+ SELECT name FROM pragma_table_list WHERE schema <> 'temp' AND name NOT IN ('sqlite_sequence', 'sqlite_schema') AND name = 'ex' AND type IN ('table')
294
611
  SQL
295
612
  assert_logged [[sql.squish, "SCHEMA", []]] do
296
613
  assert @conn.table_exists?("ex")
@@ -381,7 +698,16 @@ module ActiveRecord
381
698
  end
382
699
  end
383
700
 
384
- if ActiveRecord::Base.connection.supports_expression_index?
701
+ def test_partial_index_with_comment
702
+ with_example_table do
703
+ @conn.add_index "ex", :id, name: "fun", where: "number > 0 /*tag:test*/"
704
+ index = @conn.indexes("ex").find { |idx| idx.name == "fun" }
705
+ assert_equal ["id"], index.columns
706
+ assert_equal "number > 0", index.where
707
+ end
708
+ end
709
+
710
+ if ActiveRecord::Base.lease_connection.supports_expression_index?
385
711
  def test_expression_index
386
712
  with_example_table do
387
713
  @conn.add_index "ex", "max(id, number)", name: "expression"
@@ -390,6 +716,14 @@ module ActiveRecord
390
716
  end
391
717
  end
392
718
 
719
+ def test_expression_index_with_trailing_comment
720
+ with_example_table do
721
+ @conn.execute "CREATE INDEX expression on ex (number % 10) /* comment */"
722
+ index = @conn.indexes("ex").find { |idx| idx.name == "expression" }
723
+ assert_equal "number % 10", index.columns
724
+ end
725
+ end
726
+
393
727
  def test_expression_index_with_where
394
728
  with_example_table do
395
729
  @conn.add_index "ex", "id % 10, max(id, number)", name: "expression", where: "id > 1000"
@@ -433,48 +767,55 @@ module ActiveRecord
433
767
  end
434
768
 
435
769
  class Barcode < ActiveRecord::Base
770
+ end
771
+
772
+ class BarcodeCustomPk < ActiveRecord::Base
436
773
  self.primary_key = "code"
437
774
  end
438
775
 
439
776
  def test_copy_table_with_existing_records_have_custom_primary_key
440
- connection = Barcode.connection
441
- connection.create_table(:barcodes, primary_key: "code", id: :string, limit: 42, force: true) do |t|
777
+ connection = BarcodeCustomPk.lease_connection
778
+ connection.create_table(:barcode_custom_pks, primary_key: "code", id: :string, limit: 42, force: true) do |t|
442
779
  t.text :other_attr
443
780
  end
444
781
  code = "214fe0c2-dd47-46df-b53b-66090b3c1d40"
445
- Barcode.create!(code: code, other_attr: "xxx")
782
+ BarcodeCustomPk.create!(code: code, other_attr: "xxx")
446
783
 
447
- connection.remove_column("barcodes", "other_attr")
784
+ connection.remove_column("barcode_custom_pks", "other_attr")
448
785
 
449
- assert_equal code, Barcode.first.id
786
+ assert_equal code, BarcodeCustomPk.first.id
450
787
  ensure
451
- Barcode.reset_column_information
788
+ BarcodeCustomPk.reset_column_information
789
+ end
790
+
791
+ class BarcodeCpk < ActiveRecord::Base
792
+ self.primary_key = ["region", "code"]
452
793
  end
453
794
 
454
795
  def test_copy_table_with_composite_primary_keys
455
- connection = Barcode.connection
456
- connection.create_table(:barcodes, primary_key: ["region", "code"], force: true) do |t|
796
+ connection = BarcodeCpk.lease_connection
797
+ connection.create_table(:barcode_cpks, primary_key: ["region", "code"], force: true) do |t|
457
798
  t.string :region
458
799
  t.string :code
459
800
  t.text :other_attr
460
801
  end
461
802
  region = "US"
462
803
  code = "214fe0c2-dd47-46df-b53b-66090b3c1d40"
463
- Barcode.create!(region: region, code: code, other_attr: "xxx")
804
+ BarcodeCpk.create!(region: region, code: code, other_attr: "xxx")
464
805
 
465
- connection.remove_column("barcodes", "other_attr")
806
+ connection.remove_column("barcode_cpks", "other_attr")
466
807
 
467
- assert_equal ["region", "code"], connection.primary_keys("barcodes")
808
+ assert_equal ["region", "code"], connection.primary_keys("barcode_cpks")
468
809
 
469
- barcode = Barcode.first
810
+ barcode = BarcodeCpk.first
470
811
  assert_equal region, barcode.region
471
812
  assert_equal code, barcode.code
472
813
  ensure
473
- Barcode.reset_column_information
814
+ BarcodeCpk.reset_column_information
474
815
  end
475
816
 
476
817
  def test_custom_primary_key_in_create_table
477
- connection = Barcode.connection
818
+ connection = Barcode.lease_connection
478
819
  connection.create_table :barcodes, id: false, force: true do |t|
479
820
  t.primary_key :id, :string
480
821
  end
@@ -490,7 +831,7 @@ module ActiveRecord
490
831
  end
491
832
 
492
833
  def test_custom_primary_key_in_change_table
493
- connection = Barcode.connection
834
+ connection = Barcode.lease_connection
494
835
  connection.create_table :barcodes, id: false, force: true do |t|
495
836
  t.integer :dummy
496
837
  end
@@ -509,7 +850,7 @@ module ActiveRecord
509
850
  end
510
851
 
511
852
  def test_add_column_with_custom_primary_key
512
- connection = Barcode.connection
853
+ connection = Barcode.lease_connection
513
854
  connection.create_table :barcodes, id: false, force: true do |t|
514
855
  t.integer :dummy
515
856
  end
@@ -525,23 +866,54 @@ module ActiveRecord
525
866
  Barcode.reset_column_information
526
867
  end
527
868
 
528
- def test_remove_column_preserves_partial_indexes
529
- connection = Barcode.connection
869
+ def test_remove_column_preserves_index_options
870
+ connection = Barcode.lease_connection
530
871
  connection.create_table :barcodes, force: true do |t|
531
872
  t.string :code
532
873
  t.string :region
533
874
  t.boolean :bool_attr
534
875
 
535
- t.index :code, unique: true, where: :bool_attr, name: "partial"
876
+ t.index :code, unique: true, name: "unique"
877
+ t.index :code, where: :bool_attr, name: "partial"
878
+ t.index :code, name: "ordered", order: { code: :desc }
536
879
  end
537
880
  connection.remove_column :barcodes, :region
538
881
 
539
- index = connection.indexes("barcodes").find { |idx| idx.name == "partial" }
540
- assert_equal "bool_attr", index.where
882
+ indexes = connection.indexes("barcodes")
883
+
884
+ partial_index = indexes.find { |idx| idx.name == "partial" }
885
+ assert_equal "bool_attr", partial_index.where
886
+
887
+ unique_index = indexes.find { |idx| idx.name == "unique" }
888
+ assert unique_index.unique
889
+
890
+ ordered_index = indexes.find { |idx| idx.name == "ordered" }
891
+ assert_equal :desc, ordered_index.orders
541
892
  ensure
542
893
  Barcode.reset_column_information
543
894
  end
544
895
 
896
+ def test_auto_increment_preserved_on_table_changes
897
+ connection = Barcode.lease_connection
898
+ connection.create_table :barcodes, force: true do |t|
899
+ t.string :code
900
+ end
901
+
902
+ pk_column = connection.columns("barcodes").find { |col| col.name == "id" }
903
+ sql = connection.exec_query("SELECT sql FROM sqlite_master WHERE tbl_name='barcodes'").rows.first.first
904
+
905
+ assert_predicate(pk_column, :auto_increment?)
906
+ assert(sql.match?("PRIMARY KEY AUTOINCREMENT"))
907
+
908
+ connection.change_column(:barcodes, :code, :integer)
909
+
910
+ pk_column = connection.columns("barcodes").find { |col| col.name == "id" }
911
+ sql = connection.exec_query("SELECT sql FROM sqlite_master WHERE tbl_name='barcodes'").rows.first.first
912
+
913
+ assert_predicate(pk_column, :auto_increment?)
914
+ assert(sql.match?("PRIMARY KEY AUTOINCREMENT"))
915
+ end
916
+
545
917
  def test_supports_extensions
546
918
  assert_not @conn.supports_extensions?, "does not support extensions"
547
919
  end
@@ -558,52 +930,307 @@ module ActiveRecord
558
930
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
559
931
  db = ::SQLite3::Database.new(db_config.database)
560
932
 
933
+ @conn.connect!
934
+
561
935
  statement = ::SQLite3::Statement.new(db,
562
936
  "CREATE TABLE statement_test (number integer not null)")
563
937
  statement.stub(:step, -> { raise ::SQLite3::BusyException.new("busy") }) do
564
- assert_called(statement, :columns, returns: []) do
565
- assert_called(statement, :close) do
566
- ::SQLite3::Statement.stub(:new, statement) do
567
- assert_raises ActiveRecord::StatementInvalid do
568
- @conn.exec_query "select * from statement_test"
569
- end
938
+ assert_called(statement, :close) do
939
+ ::SQLite3::Statement.stub(:new, statement) do
940
+ error = assert_raises ActiveRecord::StatementTimeout do
941
+ @conn.exec_query "select * from statement_test"
570
942
  end
943
+ assert_equal @conn.pool, error.connection_pool
571
944
  end
572
945
  end
573
946
  end
574
947
  end
575
948
 
576
949
  def test_db_is_not_readonly_when_readonly_option_is_false
577
- conn = Base.sqlite3_connection database: ":memory:",
578
- adapter: "sqlite3",
579
- readonly: false
950
+ conn = SQLite3Adapter.new(
951
+ database: ":memory:",
952
+ adapter: "sqlite3",
953
+ readonly: false,
954
+ )
955
+ conn.connect!
580
956
 
581
957
  assert_not_predicate conn.raw_connection, :readonly?
582
958
  end
583
959
 
584
960
  def test_db_is_not_readonly_when_readonly_option_is_unspecified
585
- conn = Base.sqlite3_connection database: ":memory:",
586
- adapter: "sqlite3"
961
+ conn = SQLite3Adapter.new(
962
+ database: ":memory:",
963
+ adapter: "sqlite3",
964
+ )
965
+ conn.connect!
587
966
 
588
967
  assert_not_predicate conn.raw_connection, :readonly?
589
968
  end
590
969
 
591
970
  def test_db_is_readonly_when_readonly_option_is_true
592
- conn = Base.sqlite3_connection database: ":memory:",
593
- adapter: "sqlite3",
594
- readonly: true
971
+ conn = SQLite3Adapter.new(
972
+ database: ":memory:",
973
+ adapter: "sqlite3",
974
+ readonly: true,
975
+ )
976
+ conn.connect!
595
977
 
596
978
  assert_predicate conn.raw_connection, :readonly?
597
979
  end
598
980
 
599
981
  def test_writes_are_not_permitted_to_readonly_databases
600
- conn = Base.sqlite3_connection database: ":memory:",
601
- adapter: "sqlite3",
602
- readonly: true
603
-
604
- assert_raises(ActiveRecord::StatementInvalid, /SQLite3::ReadOnlyException/) do
982
+ conn = SQLite3Adapter.new(
983
+ database: ":memory:",
984
+ adapter: "sqlite3",
985
+ readonly: true,
986
+ )
987
+ conn.connect!
988
+
989
+ exception = assert_raises(ActiveRecord::StatementInvalid) do
605
990
  conn.execute("CREATE TABLE test(id integer)")
606
991
  end
992
+ assert_match("SQLite3::ReadOnlyException", exception.message)
993
+ assert_equal conn.pool, exception.connection_pool
994
+ end
995
+
996
+ def test_strict_strings_by_default
997
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3")
998
+ conn.create_table :testings
999
+
1000
+ assert_nothing_raised do
1001
+ conn.add_index :testings, :non_existent
1002
+ end
1003
+
1004
+ with_strict_strings_by_default do
1005
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3")
1006
+ conn.create_table :testings
1007
+
1008
+ error = assert_raises(StandardError) do
1009
+ conn.add_index :testings, :non_existent2
1010
+ end
1011
+ assert_match(/no such column: "?non_existent2"?/, error.message)
1012
+ assert_equal conn.pool, error.connection_pool
1013
+ end
1014
+ end
1015
+
1016
+ def test_strict_strings_by_default_and_true_in_database_yml
1017
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: true)
1018
+ conn.create_table :testings
1019
+
1020
+ error = assert_raises(StandardError) do
1021
+ conn.add_index :testings, :non_existent
1022
+ end
1023
+ assert_match(/no such column: "?non_existent"?/, error.message)
1024
+ assert_equal conn.pool, error.connection_pool
1025
+
1026
+ with_strict_strings_by_default do
1027
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: true)
1028
+ conn.create_table :testings
1029
+
1030
+ error = assert_raises(StandardError) do
1031
+ conn.add_index :testings, :non_existent2
1032
+ end
1033
+ assert_match(/no such column: "?non_existent2"?/, error.message)
1034
+ assert_equal conn.pool, error.connection_pool
1035
+ end
1036
+ end
1037
+
1038
+ def test_strict_strings_by_default_and_false_in_database_yml
1039
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1040
+ conn.create_table :testings
1041
+
1042
+ assert_nothing_raised do
1043
+ conn.add_index :testings, :non_existent
1044
+ end
1045
+
1046
+ with_strict_strings_by_default do
1047
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1048
+ conn.create_table :testings
1049
+
1050
+ assert_nothing_raised do
1051
+ conn.add_index :testings, :non_existent
1052
+ end
1053
+ end
1054
+ end
1055
+
1056
+ def test_rowid_column
1057
+ with_example_table "id_uppercase INTEGER PRIMARY KEY" do
1058
+ assert @conn.columns("ex").index_by(&:name)["id_uppercase"].rowid
1059
+ end
1060
+ end
1061
+
1062
+ def test_lowercase_rowid_column
1063
+ with_example_table "id_lowercase integer PRIMARY KEY" do
1064
+ assert @conn.columns("ex").index_by(&:name)["id_lowercase"].rowid
1065
+ end
1066
+ end
1067
+
1068
+ def test_non_integer_column_returns_false_for_rowid
1069
+ with_example_table "id_int_short int PRIMARY KEY" do
1070
+ assert_not @conn.columns("ex").index_by(&:name)["id_int_short"].rowid
1071
+ end
1072
+ end
1073
+
1074
+ def test_mixed_case_integer_colum_returns_true_for_rowid
1075
+ with_example_table "id_mixed_case InTeGeR PRIMARY KEY" do
1076
+ assert @conn.columns("ex").index_by(&:name)["id_mixed_case"].rowid
1077
+ end
1078
+ end
1079
+
1080
+ def test_rowid_column_with_autoincrement_returns_true_for_rowid
1081
+ with_example_table "id_autoincrement integer PRIMARY KEY AUTOINCREMENT" do
1082
+ assert @conn.columns("ex").index_by(&:name)["id_autoincrement"].rowid
1083
+ end
1084
+ end
1085
+
1086
+ def test_integer_cpk_column_returns_false_for_rowid
1087
+ with_example_table("id integer, shop_id integer, PRIMARY KEY (shop_id, id)", "cpk_table") do
1088
+ assert_not @conn.columns("cpk_table").any?(&:rowid)
1089
+ end
1090
+ end
1091
+
1092
+ def test_rowid_changes_column_equality
1093
+ type_metadata = SqlTypeMetadata.new(sql_type: "integer", type: :integer)
1094
+
1095
+ rowid_column = SQLite3::Column.new("id", nil, type_metadata, true, nil, rowid: true)
1096
+ regular_column = SQLite3::Column.new("id", nil, type_metadata, true, nil, rowid: false)
1097
+
1098
+ assert_not_equal rowid_column, regular_column
1099
+ end
1100
+
1101
+ def test_generated_type_changes_column_equality
1102
+ type_metadata = SqlTypeMetadata.new(sql_type: "varchar", type: :string)
1103
+
1104
+ stored_column = SQLite3::Column.new("name", nil, type_metadata, true, nil, generated_type: :stored)
1105
+ virtual_column = SQLite3::Column.new("name", nil, type_metadata, true, nil, generated_type: :virtual)
1106
+
1107
+ assert_not_equal stored_column, virtual_column
1108
+ end
1109
+
1110
+ def test_alter_table_with_fk_preserves_rows_when_referenced_table_altered
1111
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1112
+
1113
+ conn.create_table :authors do |t|
1114
+ t.string :name, null: false
1115
+ end
1116
+
1117
+ conn.create_table :books do |t|
1118
+ t.string :title, null: false
1119
+ t.integer :author_id, null: false
1120
+ end
1121
+ conn.add_foreign_key :books, :authors, on_delete: :cascade
1122
+
1123
+ conn.execute("INSERT INTO authors (id, name) VALUES (1, 'Douglas Adams');")
1124
+ conn.execute("INSERT INTO books (id, title, author_id) VALUES (42, 'The Hitchhiker''s Guide', 1);")
1125
+ conn.execute("INSERT INTO books (id, title, author_id) VALUES (43, 'Restaurant at the End', 1);")
1126
+
1127
+ initial_book_count = conn.select_value("SELECT COUNT(*) FROM books")
1128
+ assert_equal 2, initial_book_count
1129
+
1130
+ conn.add_column :authors, :email, :string
1131
+
1132
+ book_count = conn.select_value("SELECT COUNT(*) FROM books")
1133
+ author_count = conn.select_value("SELECT COUNT(*) FROM authors")
1134
+
1135
+ assert_equal 2, book_count, "Books were CASCADE deleted when authors table was altered!"
1136
+ assert_equal 1, author_count, "Authors were lost during table alteration!"
1137
+ ensure
1138
+ conn.disconnect! if conn
1139
+ end
1140
+
1141
+ def test_alter_table_with_fk_preserves_rows_when_adding_fk_to_referenced_table
1142
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1143
+
1144
+ conn.create_table :groups do |t|
1145
+ t.string :name, null: false
1146
+ end
1147
+
1148
+ conn.create_table :users do |t|
1149
+ t.string :username, null: false
1150
+ end
1151
+
1152
+ conn.create_table :reports do |t|
1153
+ t.string :title, null: false
1154
+ t.integer :group_id, null: false
1155
+ end
1156
+ conn.add_foreign_key :reports, :groups, on_delete: :cascade
1157
+
1158
+ conn.execute("INSERT INTO groups (id, name) VALUES (1, 'Admin Group');")
1159
+ conn.execute("INSERT INTO users (id, username) VALUES (1, 'alice');")
1160
+ conn.execute("INSERT INTO reports (id, title, group_id) VALUES (1, 'Report A', 1);")
1161
+ conn.execute("INSERT INTO reports (id, title, group_id) VALUES (2, 'Report B', 1);")
1162
+
1163
+ initial_report_count = conn.select_value("SELECT COUNT(*) FROM reports")
1164
+ assert_equal 2, initial_report_count
1165
+
1166
+ conn.add_column :groups, :owner_id, :integer
1167
+ conn.add_foreign_key :groups, :users, column: :owner_id
1168
+
1169
+ report_count = conn.select_value("SELECT COUNT(*) FROM reports")
1170
+ group_count = conn.select_value("SELECT COUNT(*) FROM groups")
1171
+
1172
+ assert_equal 2, report_count, "Reports were CASCADE deleted when groups table was altered!"
1173
+ assert_equal 1, group_count, "Groups were lost during table alteration!"
1174
+ ensure
1175
+ conn.disconnect! if conn
1176
+ end
1177
+
1178
+ def test_alter_table_with_multiple_cascade_fks_preserves_all_data
1179
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1180
+
1181
+ conn.create_table :authors do |t|
1182
+ t.string :name, null: false
1183
+ end
1184
+
1185
+ conn.create_table :books do |t|
1186
+ t.string :title, null: false
1187
+ t.integer :author_id, null: false
1188
+ end
1189
+ conn.add_foreign_key :books, :authors, on_delete: :cascade
1190
+
1191
+ conn.create_table :articles do |t|
1192
+ t.string :headline, null: false
1193
+ t.integer :author_id, null: false
1194
+ end
1195
+ conn.add_foreign_key :articles, :authors, on_delete: :cascade
1196
+
1197
+ conn.execute("INSERT INTO authors (id, name) VALUES (1, 'Douglas Adams');")
1198
+ conn.execute("INSERT INTO books (id, title, author_id) VALUES (1, 'HHGTTG', 1);")
1199
+ conn.execute("INSERT INTO articles (id, headline, author_id) VALUES (1, 'Towel Day', 1);")
1200
+
1201
+ conn.add_column :authors, :bio, :text
1202
+
1203
+ book_count = conn.select_value("SELECT COUNT(*) FROM books")
1204
+ article_count = conn.select_value("SELECT COUNT(*) FROM articles")
1205
+
1206
+ assert_equal 1, book_count, "Books were CASCADE deleted when authors table was altered!"
1207
+ assert_equal 1, article_count, "Articles were CASCADE deleted when authors table was altered!"
1208
+ ensure
1209
+ conn.disconnect! if conn
1210
+ end
1211
+
1212
+ def test_rename_table_with_cascade_fk_preserves_referencing_data
1213
+ conn = SQLite3Adapter.new(database: ":memory:", adapter: "sqlite3", strict: false)
1214
+
1215
+ conn.create_table :authors do |t|
1216
+ t.string :name, null: false
1217
+ end
1218
+
1219
+ conn.create_table :books do |t|
1220
+ t.string :title, null: false
1221
+ t.integer :author_id, null: false
1222
+ end
1223
+ conn.add_foreign_key :books, :authors, on_delete: :cascade
1224
+
1225
+ conn.execute("INSERT INTO authors (id, name) VALUES (1, 'Douglas Adams');")
1226
+ conn.execute("INSERT INTO books (id, title, author_id) VALUES (1, 'HHGTTG', 1);")
1227
+
1228
+ conn.rename_table :authors, :writers
1229
+
1230
+ book_count = conn.select_value("SELECT COUNT(*) FROM books")
1231
+ assert_equal 1, book_count, "Books were CASCADE deleted when authors table was renamed!"
1232
+ ensure
1233
+ conn.disconnect! if conn
607
1234
  end
608
1235
 
609
1236
  private
@@ -623,6 +1250,34 @@ module ActiveRecord
623
1250
  SQL
624
1251
  super(@conn, table_name, definition, &block)
625
1252
  end
1253
+
1254
+ def with_strict_strings_by_default
1255
+ SQLite3Adapter.strict_strings_by_default = true
1256
+ yield
1257
+ ensure
1258
+ SQLite3Adapter.strict_strings_by_default = false
1259
+ end
1260
+
1261
+ def with_file_connection(options = {})
1262
+ options = options.dup
1263
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit2", name: "primary")
1264
+ options[:database] ||= db_config.database
1265
+ conn = SQLite3Adapter.new(options)
1266
+
1267
+ yield(conn)
1268
+ ensure
1269
+ conn.disconnect! if conn
1270
+ end
1271
+
1272
+ def with_memory_connection(options = {})
1273
+ options = options.dup
1274
+ options[:database] = ":memory:"
1275
+ conn = SQLite3Adapter.new(options)
1276
+
1277
+ yield(conn)
1278
+ ensure
1279
+ conn.disconnect! if conn
1280
+ end
626
1281
  end
627
1282
  end
628
1283
  end