ibm_db 4.0.0-x86-mingw32 → 5.1.0-x86-mingw32

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 (576) hide show
  1. checksums.yaml +5 -5
  2. data/MANIFEST +14 -14
  3. data/README +208 -208
  4. data/ext/Makefile +269 -0
  5. data/ext/Makefile.nt32 +181 -181
  6. data/ext/Makefile.nt32.191 +212 -212
  7. data/ext/extconf.rb +322 -291
  8. data/ext/gil_release_version.h +3 -0
  9. data/ext/ibm_db-i386-mingw32.def +2 -0
  10. data/ext/ibm_db.c +11879 -11887
  11. data/ext/ibm_db.o +0 -0
  12. data/ext/ibm_db.so +0 -0
  13. data/ext/mkmf.log +110 -0
  14. data/ext/ruby_ibm_db.h +241 -241
  15. data/ext/ruby_ibm_db_cli.c +866 -866
  16. data/ext/ruby_ibm_db_cli.h +500 -500
  17. data/ext/ruby_ibm_db_cli.o +0 -0
  18. data/ext/unicode_support_version.h +3 -0
  19. data/init.rb +41 -41
  20. data/lib/IBM_DB.rb +27 -27
  21. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3593 -3452
  22. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -5
  23. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  24. data/lib/mswin32/ibm_db.rb +94 -90
  25. data/lib/mswin32/rb2x/i386/ruby26/ibm_db.so +0 -0
  26. data/lib/mswin32/rb2x/i386/ruby27/ibm_db.so +0 -0
  27. data/test/active_record/connection_adapters/fake_adapter.rb +49 -49
  28. data/test/assets/example.log +1 -1
  29. data/test/assets/test.txt +1 -1
  30. data/test/cases/adapter_test.rb +351 -351
  31. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -193
  32. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -50
  33. data/test/cases/adapters/mysql2/boolean_test.rb +100 -100
  34. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -63
  35. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -54
  36. data/test/cases/adapters/mysql2/connection_test.rb +210 -210
  37. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -45
  38. data/test/cases/adapters/mysql2/enum_test.rb +26 -26
  39. data/test/cases/adapters/mysql2/explain_test.rb +21 -21
  40. data/test/cases/adapters/mysql2/json_test.rb +195 -195
  41. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -83
  42. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -152
  43. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -59
  44. data/test/cases/adapters/mysql2/schema_test.rb +126 -126
  45. data/test/cases/adapters/mysql2/sp_test.rb +36 -36
  46. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -14
  47. data/test/cases/adapters/mysql2/table_options_test.rb +42 -42
  48. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -66
  49. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -98
  50. data/test/cases/adapters/postgresql/array_test.rb +339 -339
  51. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -82
  52. data/test/cases/adapters/postgresql/bytea_test.rb +134 -134
  53. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -26
  54. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -38
  55. data/test/cases/adapters/postgresql/cidr_test.rb +25 -25
  56. data/test/cases/adapters/postgresql/citext_test.rb +78 -78
  57. data/test/cases/adapters/postgresql/collation_test.rb +53 -53
  58. data/test/cases/adapters/postgresql/composite_test.rb +132 -132
  59. data/test/cases/adapters/postgresql/connection_test.rb +257 -257
  60. data/test/cases/adapters/postgresql/datatype_test.rb +92 -92
  61. data/test/cases/adapters/postgresql/domain_test.rb +47 -47
  62. data/test/cases/adapters/postgresql/enum_test.rb +91 -91
  63. data/test/cases/adapters/postgresql/explain_test.rb +20 -20
  64. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -63
  65. data/test/cases/adapters/postgresql/full_text_test.rb +44 -44
  66. data/test/cases/adapters/postgresql/geometric_test.rb +378 -378
  67. data/test/cases/adapters/postgresql/hstore_test.rb +382 -382
  68. data/test/cases/adapters/postgresql/infinity_test.rb +69 -69
  69. data/test/cases/adapters/postgresql/integer_test.rb +25 -25
  70. data/test/cases/adapters/postgresql/json_test.rb +237 -237
  71. data/test/cases/adapters/postgresql/ltree_test.rb +53 -53
  72. data/test/cases/adapters/postgresql/money_test.rb +96 -96
  73. data/test/cases/adapters/postgresql/network_test.rb +94 -94
  74. data/test/cases/adapters/postgresql/numbers_test.rb +49 -49
  75. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -405
  76. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -22
  77. data/test/cases/adapters/postgresql/quoting_test.rb +44 -44
  78. data/test/cases/adapters/postgresql/range_test.rb +343 -343
  79. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -111
  80. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -34
  81. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -119
  82. data/test/cases/adapters/postgresql/schema_test.rb +597 -597
  83. data/test/cases/adapters/postgresql/serial_test.rb +154 -154
  84. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -41
  85. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -90
  86. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -33
  87. data/test/cases/adapters/postgresql/utils_test.rb +62 -62
  88. data/test/cases/adapters/postgresql/uuid_test.rb +294 -294
  89. data/test/cases/adapters/postgresql/xml_test.rb +54 -54
  90. data/test/cases/adapters/sqlite3/collation_test.rb +53 -53
  91. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -98
  92. data/test/cases/adapters/sqlite3/explain_test.rb +21 -21
  93. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -101
  94. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -441
  95. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -24
  96. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -20
  97. data/test/cases/aggregations_test.rb +168 -168
  98. data/test/cases/ar_schema_test.rb +146 -146
  99. data/test/cases/associations/association_scope_test.rb +16 -16
  100. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1141
  101. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -41
  102. data/test/cases/associations/callbacks_test.rb +190 -190
  103. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  104. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  105. data/test/cases/associations/eager_load_nested_include_test.rb +126 -126
  106. data/test/cases/associations/eager_singularization_test.rb +148 -148
  107. data/test/cases/associations/eager_test.rb +1514 -1514
  108. data/test/cases/associations/extension_test.rb +87 -87
  109. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -1004
  110. data/test/cases/associations/has_many_associations_test.rb +2501 -2501
  111. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1271
  112. data/test/cases/associations/has_one_associations_test.rb +707 -707
  113. data/test/cases/associations/has_one_through_associations_test.rb +383 -383
  114. data/test/cases/associations/inner_join_association_test.rb +139 -139
  115. data/test/cases/associations/inverse_associations_test.rb +733 -733
  116. data/test/cases/associations/join_model_test.rb +777 -777
  117. data/test/cases/associations/left_outer_join_association_test.rb +88 -88
  118. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  119. data/test/cases/associations/required_test.rb +102 -102
  120. data/test/cases/associations_test.rb +385 -385
  121. data/test/cases/attribute_decorators_test.rb +126 -125
  122. data/test/cases/attribute_methods/read_test.rb +60 -60
  123. data/test/cases/attribute_methods_test.rb +1009 -1009
  124. data/test/cases/attribute_set_test.rb +270 -270
  125. data/test/cases/attribute_test.rb +246 -246
  126. data/test/cases/attributes_test.rb +253 -253
  127. data/test/cases/autosave_association_test.rb +1708 -1708
  128. data/test/cases/base_test.rb +1713 -1713
  129. data/test/cases/batches_test.rb +489 -489
  130. data/test/cases/binary_test.rb +44 -44
  131. data/test/cases/bind_parameter_test.rb +110 -110
  132. data/test/cases/cache_key_test.rb +26 -25
  133. data/test/cases/calculations_test.rb +798 -798
  134. data/test/cases/callbacks_test.rb +636 -636
  135. data/test/cases/clone_test.rb +40 -40
  136. data/test/cases/coders/json_test.rb +15 -15
  137. data/test/cases/coders/yaml_column_test.rb +63 -63
  138. data/test/cases/collection_cache_key_test.rb +115 -115
  139. data/test/cases/column_alias_test.rb +17 -17
  140. data/test/cases/column_definition_test.rb +92 -92
  141. data/test/cases/comment_test.rb +145 -143
  142. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -56
  143. data/test/cases/connection_adapters/connection_handler_test.rb +160 -160
  144. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  145. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -255
  146. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -69
  147. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  148. data/test/cases/connection_adapters/schema_cache_test.rb +61 -61
  149. data/test/cases/connection_adapters/type_lookup_test.rb +118 -118
  150. data/test/cases/connection_management_test.rb +112 -112
  151. data/test/cases/connection_pool_test.rb +521 -521
  152. data/test/cases/connection_specification/resolver_test.rb +131 -131
  153. data/test/cases/core_test.rb +112 -112
  154. data/test/cases/counter_cache_test.rb +214 -214
  155. data/test/cases/custom_locking_test.rb +17 -17
  156. data/test/cases/database_statements_test.rb +34 -34
  157. data/test/cases/date_test.rb +44 -44
  158. data/test/cases/date_time_precision_test.rb +107 -106
  159. data/test/cases/date_time_test.rb +61 -61
  160. data/test/cases/defaults_test.rb +219 -218
  161. data/test/cases/dirty_test.rb +763 -763
  162. data/test/cases/disconnected_test.rb +30 -30
  163. data/test/cases/dup_test.rb +157 -157
  164. data/test/cases/enum_test.rb +444 -444
  165. data/test/cases/errors_test.rb +16 -16
  166. data/test/cases/explain_subscriber_test.rb +64 -64
  167. data/test/cases/explain_test.rb +87 -87
  168. data/test/cases/finder_respond_to_test.rb +60 -60
  169. data/test/cases/finder_test.rb +1294 -1294
  170. data/test/cases/fixture_set/file_test.rb +156 -156
  171. data/test/cases/fixtures_test.rb +988 -988
  172. data/test/cases/forbidden_attributes_protection_test.rb +165 -165
  173. data/test/cases/habtm_destroy_order_test.rb +61 -61
  174. data/test/cases/helper.rb +204 -204
  175. data/test/cases/hot_compatibility_test.rb +142 -142
  176. data/test/cases/i18n_test.rb +45 -45
  177. data/test/cases/inheritance_test.rb +606 -606
  178. data/test/cases/integration_test.rb +155 -155
  179. data/test/cases/invalid_connection_test.rb +24 -24
  180. data/test/cases/invertible_migration_test.rb +387 -387
  181. data/test/cases/json_serialization_test.rb +311 -311
  182. data/test/cases/locking_test.rb +493 -493
  183. data/test/cases/log_subscriber_test.rb +225 -225
  184. data/test/cases/migration/change_schema_test.rb +458 -458
  185. data/test/cases/migration/change_table_test.rb +256 -256
  186. data/test/cases/migration/column_attributes_test.rb +176 -176
  187. data/test/cases/migration/column_positioning_test.rb +56 -56
  188. data/test/cases/migration/columns_test.rb +310 -310
  189. data/test/cases/migration/command_recorder_test.rb +350 -350
  190. data/test/cases/migration/compatibility_test.rb +118 -118
  191. data/test/cases/migration/create_join_table_test.rb +157 -157
  192. data/test/cases/migration/foreign_key_test.rb +362 -360
  193. data/test/cases/migration/helper.rb +39 -39
  194. data/test/cases/migration/index_test.rb +218 -218
  195. data/test/cases/migration/logger_test.rb +36 -36
  196. data/test/cases/migration/pending_migrations_test.rb +52 -52
  197. data/test/cases/migration/references_foreign_key_test.rb +221 -216
  198. data/test/cases/migration/references_index_test.rb +101 -101
  199. data/test/cases/migration/references_statements_test.rb +136 -136
  200. data/test/cases/migration/rename_table_test.rb +93 -93
  201. data/test/cases/migration_test.rb +1157 -1157
  202. data/test/cases/migrator_test.rb +471 -470
  203. data/test/cases/mixin_test.rb +68 -68
  204. data/test/cases/modules_test.rb +172 -172
  205. data/test/cases/multiparameter_attributes_test.rb +372 -372
  206. data/test/cases/multiple_db_test.rb +122 -122
  207. data/test/cases/nested_attributes_test.rb +1098 -1098
  208. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  209. data/test/cases/persistence_test.rb +1001 -1001
  210. data/test/cases/pooled_connections_test.rb +81 -81
  211. data/test/cases/primary_keys_test.rb +376 -376
  212. data/test/cases/query_cache_test.rb +446 -446
  213. data/test/cases/quoting_test.rb +202 -202
  214. data/test/cases/readonly_test.rb +119 -119
  215. data/test/cases/reaper_test.rb +85 -85
  216. data/test/cases/reflection_test.rb +509 -509
  217. data/test/cases/relation/delegation_test.rb +63 -63
  218. data/test/cases/relation/merging_test.rb +157 -157
  219. data/test/cases/relation/mutation_test.rb +183 -183
  220. data/test/cases/relation/or_test.rb +92 -92
  221. data/test/cases/relation/predicate_builder_test.rb +16 -16
  222. data/test/cases/relation/record_fetch_warning_test.rb +40 -40
  223. data/test/cases/relation/where_chain_test.rb +105 -105
  224. data/test/cases/relation/where_clause_test.rb +182 -182
  225. data/test/cases/relation/where_test.rb +322 -322
  226. data/test/cases/relation_test.rb +328 -328
  227. data/test/cases/relations_test.rb +2026 -2026
  228. data/test/cases/reload_models_test.rb +22 -22
  229. data/test/cases/result_test.rb +90 -90
  230. data/test/cases/sanitize_test.rb +176 -176
  231. data/test/cases/schema_dumper_test.rb +457 -457
  232. data/test/cases/schema_loading_test.rb +52 -52
  233. data/test/cases/scoping/default_scoping_test.rb +528 -528
  234. data/test/cases/scoping/named_scoping_test.rb +561 -561
  235. data/test/cases/scoping/relation_scoping_test.rb +400 -400
  236. data/test/cases/secure_token_test.rb +32 -32
  237. data/test/cases/serialization_test.rb +104 -104
  238. data/test/cases/serialized_attribute_test.rb +364 -364
  239. data/test/cases/statement_cache_test.rb +136 -136
  240. data/test/cases/store_test.rb +195 -195
  241. data/test/cases/suppressor_test.rb +63 -63
  242. data/test/cases/tasks/database_tasks_test.rb +462 -462
  243. data/test/cases/tasks/mysql_rake_test.rb +345 -345
  244. data/test/cases/tasks/postgresql_rake_test.rb +304 -304
  245. data/test/cases/tasks/sqlite_rake_test.rb +220 -220
  246. data/test/cases/test_case.rb +131 -131
  247. data/test/cases/test_fixtures_test.rb +36 -36
  248. data/test/cases/time_precision_test.rb +103 -102
  249. data/test/cases/timestamp_test.rb +501 -501
  250. data/test/cases/touch_later_test.rb +121 -121
  251. data/test/cases/transaction_callbacks_test.rb +518 -518
  252. data/test/cases/transaction_isolation_test.rb +106 -106
  253. data/test/cases/transactions_test.rb +835 -834
  254. data/test/cases/type/adapter_specific_registry_test.rb +133 -133
  255. data/test/cases/type/date_time_test.rb +14 -14
  256. data/test/cases/type/integer_test.rb +27 -27
  257. data/test/cases/type/string_test.rb +22 -22
  258. data/test/cases/type/type_map_test.rb +177 -177
  259. data/test/cases/type_test.rb +39 -39
  260. data/test/cases/types_test.rb +24 -24
  261. data/test/cases/unconnected_test.rb +33 -33
  262. data/test/cases/validations/absence_validation_test.rb +73 -73
  263. data/test/cases/validations/association_validation_test.rb +97 -97
  264. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  265. data/test/cases/validations/i18n_validation_test.rb +86 -86
  266. data/test/cases/validations/length_validation_test.rb +79 -79
  267. data/test/cases/validations/presence_validation_test.rb +103 -103
  268. data/test/cases/validations/uniqueness_validation_test.rb +548 -548
  269. data/test/cases/validations_repair_helper.rb +19 -19
  270. data/test/cases/validations_test.rb +194 -194
  271. data/test/cases/view_test.rb +216 -216
  272. data/test/cases/yaml_serialization_test.rb +121 -121
  273. data/test/config.example.yml +97 -97
  274. data/test/config.rb +5 -5
  275. data/test/connections/native_ibm_db/connection.rb +44 -0
  276. data/test/fixtures/accounts.yml +29 -29
  277. data/test/fixtures/admin/accounts.yml +2 -2
  278. data/test/fixtures/admin/users.yml +10 -10
  279. data/test/fixtures/author_addresses.yml +17 -17
  280. data/test/fixtures/author_favorites.yml +3 -3
  281. data/test/fixtures/authors.yml +23 -23
  282. data/test/fixtures/bad_posts.yml +9 -9
  283. data/test/fixtures/binaries.yml +133 -133
  284. data/test/fixtures/books.yml +31 -31
  285. data/test/fixtures/bulbs.yml +5 -5
  286. data/test/fixtures/cars.yml +9 -9
  287. data/test/fixtures/categories.yml +19 -19
  288. data/test/fixtures/categories/special_categories.yml +9 -9
  289. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  290. data/test/fixtures/categories_ordered.yml +7 -7
  291. data/test/fixtures/categories_posts.yml +31 -31
  292. data/test/fixtures/categorizations.yml +23 -23
  293. data/test/fixtures/clubs.yml +8 -8
  294. data/test/fixtures/collections.yml +3 -3
  295. data/test/fixtures/colleges.yml +3 -3
  296. data/test/fixtures/comments.yml +65 -65
  297. data/test/fixtures/companies.yml +67 -67
  298. data/test/fixtures/computers.yml +10 -10
  299. data/test/fixtures/content.yml +3 -3
  300. data/test/fixtures/content_positions.yml +3 -3
  301. data/test/fixtures/courses.yml +8 -8
  302. data/test/fixtures/customers.yml +25 -25
  303. data/test/fixtures/dashboards.yml +6 -6
  304. data/test/fixtures/dead_parrots.yml +5 -5
  305. data/test/fixtures/developers.yml +22 -22
  306. data/test/fixtures/developers_projects.yml +16 -16
  307. data/test/fixtures/dog_lovers.yml +7 -7
  308. data/test/fixtures/dogs.yml +4 -4
  309. data/test/fixtures/doubloons.yml +3 -3
  310. data/test/fixtures/edges.yml +5 -5
  311. data/test/fixtures/entrants.yml +14 -14
  312. data/test/fixtures/essays.yml +6 -6
  313. data/test/fixtures/faces.yml +11 -11
  314. data/test/fixtures/fk_test_has_fk.yml +3 -3
  315. data/test/fixtures/fk_test_has_pk.yml +1 -1
  316. data/test/fixtures/friendships.yml +4 -4
  317. data/test/fixtures/funny_jokes.yml +10 -10
  318. data/test/fixtures/interests.yml +33 -33
  319. data/test/fixtures/items.yml +3 -3
  320. data/test/fixtures/jobs.yml +7 -7
  321. data/test/fixtures/legacy_things.yml +3 -3
  322. data/test/fixtures/live_parrots.yml +4 -4
  323. data/test/fixtures/mateys.yml +4 -4
  324. data/test/fixtures/member_details.yml +8 -8
  325. data/test/fixtures/member_types.yml +6 -6
  326. data/test/fixtures/members.yml +11 -11
  327. data/test/fixtures/memberships.yml +34 -34
  328. data/test/fixtures/men.yml +5 -5
  329. data/test/fixtures/minimalistics.yml +2 -2
  330. data/test/fixtures/minivans.yml +5 -5
  331. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  332. data/test/fixtures/mixins.yml +29 -29
  333. data/test/fixtures/movies.yml +7 -7
  334. data/test/fixtures/naked/yml/accounts.yml +1 -1
  335. data/test/fixtures/naked/yml/companies.yml +1 -1
  336. data/test/fixtures/naked/yml/courses.yml +1 -1
  337. data/test/fixtures/naked/yml/parrots.yml +2 -2
  338. data/test/fixtures/naked/yml/trees.yml +3 -3
  339. data/test/fixtures/nodes.yml +29 -29
  340. data/test/fixtures/organizations.yml +5 -5
  341. data/test/fixtures/other_comments.yml +6 -6
  342. data/test/fixtures/other_dogs.yml +2 -2
  343. data/test/fixtures/other_posts.yml +7 -7
  344. data/test/fixtures/other_topics.yml +42 -42
  345. data/test/fixtures/owners.yml +9 -9
  346. data/test/fixtures/parrots.yml +27 -27
  347. data/test/fixtures/parrots_pirates.yml +7 -7
  348. data/test/fixtures/people.yml +24 -24
  349. data/test/fixtures/peoples_treasures.yml +3 -3
  350. data/test/fixtures/pets.yml +19 -19
  351. data/test/fixtures/pirates.yml +12 -15
  352. data/test/fixtures/posts.yml +80 -80
  353. data/test/fixtures/price_estimates.yml +16 -16
  354. data/test/fixtures/products.yml +4 -4
  355. data/test/fixtures/projects.yml +7 -7
  356. data/test/fixtures/ratings.yml +14 -14
  357. data/test/fixtures/readers.yml +11 -11
  358. data/test/fixtures/references.yml +17 -17
  359. data/test/fixtures/reserved_words/distinct.yml +5 -5
  360. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  361. data/test/fixtures/reserved_words/group.yml +14 -14
  362. data/test/fixtures/reserved_words/select.yml +8 -8
  363. data/test/fixtures/reserved_words/values.yml +7 -7
  364. data/test/fixtures/ships.yml +6 -6
  365. data/test/fixtures/speedometers.yml +8 -8
  366. data/test/fixtures/sponsors.yml +12 -12
  367. data/test/fixtures/string_key_objects.yml +7 -7
  368. data/test/fixtures/subscribers.yml +10 -10
  369. data/test/fixtures/subscriptions.yml +12 -12
  370. data/test/fixtures/taggings.yml +78 -78
  371. data/test/fixtures/tags.yml +11 -11
  372. data/test/fixtures/tasks.yml +7 -7
  373. data/test/fixtures/teapots.yml +3 -3
  374. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  375. data/test/fixtures/to_be_linked/users.yml +10 -10
  376. data/test/fixtures/topics.yml +49 -49
  377. data/test/fixtures/toys.yml +14 -14
  378. data/test/fixtures/traffic_lights.yml +9 -9
  379. data/test/fixtures/treasures.yml +10 -10
  380. data/test/fixtures/trees.yml +3 -3
  381. data/test/fixtures/uuid_children.yml +3 -3
  382. data/test/fixtures/uuid_parents.yml +2 -2
  383. data/test/fixtures/variants.yml +4 -4
  384. data/test/fixtures/vegetables.yml +19 -19
  385. data/test/fixtures/vertices.yml +3 -3
  386. data/test/fixtures/warehouse_things.yml +2 -2
  387. data/test/fixtures/zines.yml +5 -5
  388. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  389. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  390. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  391. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  392. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  393. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  394. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  395. data/test/migrations/rename/1_we_need_things.rb +11 -11
  396. data/test/migrations/rename/2_rename_things.rb +9 -9
  397. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  398. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  399. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  400. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  401. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  402. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  403. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  404. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  405. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  406. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  407. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  408. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  409. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  410. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  411. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  412. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  413. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  414. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  415. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  416. data/test/models/admin.rb +5 -5
  417. data/test/models/admin/account.rb +3 -3
  418. data/test/models/admin/user.rb +40 -40
  419. data/test/models/aircraft.rb +5 -5
  420. data/test/models/arunit2_model.rb +3 -3
  421. data/test/models/author.rb +209 -209
  422. data/test/models/auto_id.rb +4 -4
  423. data/test/models/autoloadable/extra_firm.rb +2 -2
  424. data/test/models/binary.rb +2 -2
  425. data/test/models/bird.rb +12 -12
  426. data/test/models/book.rb +23 -23
  427. data/test/models/boolean.rb +2 -2
  428. data/test/models/bulb.rb +52 -52
  429. data/test/models/cake_designer.rb +3 -3
  430. data/test/models/car.rb +29 -29
  431. data/test/models/carrier.rb +2 -2
  432. data/test/models/cat.rb +10 -10
  433. data/test/models/categorization.rb +19 -19
  434. data/test/models/category.rb +35 -35
  435. data/test/models/chef.rb +8 -8
  436. data/test/models/citation.rb +3 -3
  437. data/test/models/club.rb +25 -25
  438. data/test/models/college.rb +10 -10
  439. data/test/models/column.rb +3 -3
  440. data/test/models/column_name.rb +3 -3
  441. data/test/models/comment.rb +76 -76
  442. data/test/models/company.rb +230 -230
  443. data/test/models/company_in_module.rb +98 -98
  444. data/test/models/computer.rb +3 -3
  445. data/test/models/contact.rb +41 -41
  446. data/test/models/content.rb +40 -40
  447. data/test/models/contract.rb +20 -20
  448. data/test/models/country.rb +7 -7
  449. data/test/models/course.rb +6 -6
  450. data/test/models/customer.rb +83 -83
  451. data/test/models/customer_carrier.rb +14 -14
  452. data/test/models/dashboard.rb +3 -3
  453. data/test/models/default.rb +2 -2
  454. data/test/models/department.rb +4 -4
  455. data/test/models/developer.rb +274 -274
  456. data/test/models/dog.rb +5 -5
  457. data/test/models/dog_lover.rb +5 -5
  458. data/test/models/doubloon.rb +12 -12
  459. data/test/models/drink_designer.rb +3 -3
  460. data/test/models/edge.rb +5 -5
  461. data/test/models/electron.rb +5 -5
  462. data/test/models/engine.rb +4 -4
  463. data/test/models/entrant.rb +3 -3
  464. data/test/models/essay.rb +5 -5
  465. data/test/models/event.rb +3 -3
  466. data/test/models/eye.rb +37 -37
  467. data/test/models/face.rb +9 -9
  468. data/test/models/friendship.rb +6 -6
  469. data/test/models/guid.rb +2 -2
  470. data/test/models/guitar.rb +4 -4
  471. data/test/models/hotel.rb +11 -11
  472. data/test/models/image.rb +3 -3
  473. data/test/models/interest.rb +5 -5
  474. data/test/models/invoice.rb +4 -4
  475. data/test/models/item.rb +7 -7
  476. data/test/models/job.rb +7 -7
  477. data/test/models/joke.rb +7 -7
  478. data/test/models/keyboard.rb +3 -3
  479. data/test/models/legacy_thing.rb +3 -3
  480. data/test/models/lesson.rb +11 -11
  481. data/test/models/line_item.rb +3 -3
  482. data/test/models/liquid.rb +4 -4
  483. data/test/models/man.rb +11 -11
  484. data/test/models/matey.rb +4 -4
  485. data/test/models/member.rb +42 -42
  486. data/test/models/member_detail.rb +8 -8
  487. data/test/models/member_type.rb +3 -3
  488. data/test/models/membership.rb +35 -35
  489. data/test/models/mentor.rb +2 -2
  490. data/test/models/minimalistic.rb +2 -2
  491. data/test/models/minivan.rb +9 -9
  492. data/test/models/mixed_case_monkey.rb +3 -3
  493. data/test/models/mocktail_designer.rb +2 -2
  494. data/test/models/molecule.rb +6 -6
  495. data/test/models/movie.rb +5 -5
  496. data/test/models/node.rb +5 -5
  497. data/test/models/non_primary_key.rb +2 -2
  498. data/test/models/notification.rb +3 -3
  499. data/test/models/order.rb +4 -4
  500. data/test/models/organization.rb +14 -14
  501. data/test/models/other_dog.rb +5 -5
  502. data/test/models/owner.rb +37 -37
  503. data/test/models/parrot.rb +28 -28
  504. data/test/models/person.rb +142 -142
  505. data/test/models/personal_legacy_thing.rb +4 -4
  506. data/test/models/pet.rb +18 -18
  507. data/test/models/pet_treasure.rb +6 -6
  508. data/test/models/pirate.rb +92 -92
  509. data/test/models/possession.rb +3 -3
  510. data/test/models/post.rb +273 -273
  511. data/test/models/price_estimate.rb +4 -4
  512. data/test/models/professor.rb +5 -5
  513. data/test/models/project.rb +40 -40
  514. data/test/models/publisher.rb +2 -2
  515. data/test/models/publisher/article.rb +4 -4
  516. data/test/models/publisher/magazine.rb +3 -3
  517. data/test/models/rating.rb +4 -4
  518. data/test/models/reader.rb +23 -23
  519. data/test/models/recipe.rb +3 -3
  520. data/test/models/record.rb +2 -2
  521. data/test/models/reference.rb +22 -22
  522. data/test/models/reply.rb +61 -61
  523. data/test/models/ship.rb +39 -39
  524. data/test/models/ship_part.rb +8 -8
  525. data/test/models/shop.rb +17 -17
  526. data/test/models/shop_account.rb +6 -6
  527. data/test/models/speedometer.rb +6 -6
  528. data/test/models/sponsor.rb +7 -7
  529. data/test/models/string_key_object.rb +3 -3
  530. data/test/models/student.rb +4 -4
  531. data/test/models/subject.rb +16 -16
  532. data/test/models/subscriber.rb +8 -8
  533. data/test/models/subscription.rb +4 -4
  534. data/test/models/tag.rb +13 -13
  535. data/test/models/tagging.rb +13 -13
  536. data/test/models/task.rb +5 -5
  537. data/test/models/topic.rb +118 -118
  538. data/test/models/toy.rb +6 -6
  539. data/test/models/traffic_light.rb +4 -4
  540. data/test/models/treasure.rb +14 -14
  541. data/test/models/treaty.rb +7 -7
  542. data/test/models/tree.rb +3 -3
  543. data/test/models/tuning_peg.rb +4 -4
  544. data/test/models/tyre.rb +11 -11
  545. data/test/models/user.rb +14 -14
  546. data/test/models/uuid_child.rb +3 -3
  547. data/test/models/uuid_item.rb +6 -6
  548. data/test/models/uuid_parent.rb +3 -3
  549. data/test/models/vegetables.rb +24 -24
  550. data/test/models/vehicle.rb +6 -6
  551. data/test/models/vertex.rb +9 -9
  552. data/test/models/warehouse_thing.rb +5 -5
  553. data/test/models/wheel.rb +3 -3
  554. data/test/models/without_table.rb +3 -3
  555. data/test/models/zine.rb +3 -3
  556. data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
  557. data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
  558. data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
  559. data/test/schema/mysql2_specific_schema.rb +68 -68
  560. data/test/schema/oracle_specific_schema.rb +40 -40
  561. data/test/schema/postgresql_specific_schema.rb +114 -114
  562. data/test/schema/schema.rb +1057 -1057
  563. data/test/schema/schema.rb.original +1057 -1057
  564. data/test/schema/sqlite_specific_schema.rb +18 -18
  565. data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
  566. data/test/support/config.rb +43 -43
  567. data/test/support/connection.rb +23 -23
  568. data/test/support/connection_helper.rb +14 -14
  569. data/test/support/ddl_helper.rb +8 -8
  570. data/test/support/schema_dumping_helper.rb +20 -20
  571. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -22
  572. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -182
  573. metadata +30 -14
  574. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  575. data/test/fixtures/author_addresses.original +0 -11
  576. data/test/fixtures/authors.original +0 -17
@@ -1,106 +1,106 @@
1
- require 'cases/helper'
2
-
3
- unless ActiveRecord::Base.connection.supports_transaction_isolation?
4
- class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase
5
- self.use_transactional_tests = false
6
-
7
- class Tag < ActiveRecord::Base
8
- end
9
-
10
- test "setting the isolation level raises an error" do
11
- assert_raises(ActiveRecord::TransactionIsolationError) do
12
- Tag.transaction(isolation: :serializable) { }
13
- end
14
- end
15
- end
16
- end
17
-
18
- if ActiveRecord::Base.connection.supports_transaction_isolation?
19
- class TransactionIsolationTest < ActiveRecord::TestCase
20
- self.use_transactional_tests = false
21
-
22
- class Tag < ActiveRecord::Base
23
- self.table_name = 'tags'
24
- end
25
-
26
- class Tag2 < ActiveRecord::Base
27
- self.table_name = 'tags'
28
- end
29
-
30
- setup do
31
- Tag.establish_connection :arunit
32
- Tag2.establish_connection :arunit
33
- Tag.destroy_all
34
- end
35
-
36
- # It is impossible to properly test read uncommitted. The SQL standard only
37
- # specifies what must not happen at a certain level, not what must happen. At
38
- # the read uncommitted level, there is nothing that must not happen.
39
- if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted)
40
- test "read uncommitted" do
41
- Tag.transaction(isolation: :read_uncommitted) do
42
- assert_equal 0, Tag.count
43
- Tag2.create
44
- assert_equal 1, Tag.count
45
- end
46
- end
47
- end
48
-
49
- # We are testing that a dirty read does not happen
50
- test "read committed" do
51
- Tag.transaction(isolation: :read_committed) do
52
- assert_equal 0, Tag.count
53
-
54
- Tag2.transaction do
55
- Tag2.create
56
- assert_equal 0, Tag.count
57
- end
58
- end
59
-
60
- assert_equal 1, Tag.count
61
- end
62
-
63
- # We are testing that a nonrepeatable read does not happen
64
- if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read)
65
- test "repeatable read" do
66
- tag = Tag.create(name: 'jon')
67
-
68
- Tag.transaction(isolation: :repeatable_read) do
69
- tag.reload
70
- Tag2.find(tag.id).update(name: 'emily')
71
-
72
- tag.reload
73
- assert_equal 'jon', tag.name
74
- end
75
-
76
- tag.reload
77
- assert_equal 'emily', tag.name
78
- end
79
- end
80
-
81
- # We are only testing that there are no errors because it's too hard to
82
- # test serializable. Databases behave differently to enforce the serializability
83
- # constraint.
84
- test "serializable" do
85
- Tag.transaction(isolation: :serializable) do
86
- Tag.create
87
- end
88
- end
89
-
90
- test "setting isolation when joining a transaction raises an error" do
91
- Tag.transaction do
92
- assert_raises(ActiveRecord::TransactionIsolationError) do
93
- Tag.transaction(isolation: :serializable) { }
94
- end
95
- end
96
- end
97
-
98
- test "setting isolation when starting a nested transaction raises error" do
99
- Tag.transaction do
100
- assert_raises(ActiveRecord::TransactionIsolationError) do
101
- Tag.transaction(requires_new: true, isolation: :serializable) { }
102
- end
103
- end
104
- end
105
- end
106
- end
1
+ require 'cases/helper'
2
+
3
+ unless ActiveRecord::Base.connection.supports_transaction_isolation?
4
+ class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase
5
+ self.use_transactional_tests = false
6
+
7
+ class Tag < ActiveRecord::Base
8
+ end
9
+
10
+ test "setting the isolation level raises an error" do
11
+ assert_raises(ActiveRecord::TransactionIsolationError) do
12
+ Tag.transaction(isolation: :serializable) { }
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ if ActiveRecord::Base.connection.supports_transaction_isolation?
19
+ class TransactionIsolationTest < ActiveRecord::TestCase
20
+ self.use_transactional_tests = false
21
+
22
+ class Tag < ActiveRecord::Base
23
+ self.table_name = 'tags'
24
+ end
25
+
26
+ class Tag2 < ActiveRecord::Base
27
+ self.table_name = 'tags'
28
+ end
29
+
30
+ setup do
31
+ Tag.establish_connection :arunit
32
+ Tag2.establish_connection :arunit
33
+ Tag.destroy_all
34
+ end
35
+
36
+ # It is impossible to properly test read uncommitted. The SQL standard only
37
+ # specifies what must not happen at a certain level, not what must happen. At
38
+ # the read uncommitted level, there is nothing that must not happen.
39
+ if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted)
40
+ test "read uncommitted" do
41
+ Tag.transaction(isolation: :read_uncommitted) do
42
+ assert_equal 0, Tag.count
43
+ Tag2.create
44
+ assert_equal 1, Tag.count
45
+ end
46
+ end
47
+ end
48
+
49
+ # We are testing that a dirty read does not happen
50
+ test "read committed" do
51
+ Tag.transaction(isolation: :read_committed) do
52
+ assert_equal 0, Tag.count
53
+
54
+ Tag2.transaction do
55
+ Tag2.create
56
+ assert_equal 0, Tag.count
57
+ end
58
+ end
59
+
60
+ assert_equal 1, Tag.count
61
+ end
62
+
63
+ # We are testing that a nonrepeatable read does not happen
64
+ if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read)
65
+ test "repeatable read" do
66
+ tag = Tag.create(name: 'jon')
67
+
68
+ Tag.transaction(isolation: :repeatable_read) do
69
+ tag.reload
70
+ Tag2.find(tag.id).update(name: 'emily')
71
+
72
+ tag.reload
73
+ assert_equal 'jon', tag.name
74
+ end
75
+
76
+ tag.reload
77
+ assert_equal 'emily', tag.name
78
+ end
79
+ end
80
+
81
+ # We are only testing that there are no errors because it's too hard to
82
+ # test serializable. Databases behave differently to enforce the serializability
83
+ # constraint.
84
+ test "serializable" do
85
+ Tag.transaction(isolation: :serializable) do
86
+ Tag.create
87
+ end
88
+ end
89
+
90
+ test "setting isolation when joining a transaction raises an error" do
91
+ Tag.transaction do
92
+ assert_raises(ActiveRecord::TransactionIsolationError) do
93
+ Tag.transaction(isolation: :serializable) { }
94
+ end
95
+ end
96
+ end
97
+
98
+ test "setting isolation when starting a nested transaction raises error" do
99
+ Tag.transaction do
100
+ assert_raises(ActiveRecord::TransactionIsolationError) do
101
+ Tag.transaction(requires_new: true, isolation: :serializable) { }
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,834 +1,835 @@
1
- require "cases/helper"
2
- require 'models/topic'
3
- require 'models/reply'
4
- require 'models/developer'
5
- require 'models/computer'
6
- require 'models/book'
7
- require 'models/author'
8
- require 'models/post'
9
- require 'models/movie'
10
-
11
- class TransactionTest < ActiveRecord::TestCase
12
- self.use_transactional_tests = false
13
- fixtures :topics, :developers, :authors, :posts
14
-
15
- def setup
16
- @first, @second = Topic.find(1, 2).sort_by(&:id)
17
- end
18
-
19
- def test_persisted_in_a_model_with_custom_primary_key_after_failed_save
20
- movie = Movie.create
21
- assert !movie.persisted?
22
- end
23
-
24
- def test_raise_after_destroy
25
- assert_not @first.frozen?
26
-
27
- assert_raises(RuntimeError) {
28
- Topic.transaction do
29
- @first.destroy
30
- assert @first.frozen?
31
- raise
32
- end
33
- }
34
-
35
- assert @first.reload
36
- assert_not @first.frozen?
37
- end
38
-
39
- def test_successful
40
- Topic.transaction do
41
- @first.approved = true
42
- @second.approved = false
43
- @first.save
44
- @second.save
45
- end
46
-
47
- assert Topic.find(1).approved?, "First should have been approved"
48
- assert !Topic.find(2).approved?, "Second should have been unapproved"
49
- end
50
-
51
- def transaction_with_return
52
- Topic.transaction do
53
- @first.approved = true
54
- @second.approved = false
55
- @first.save
56
- @second.save
57
- return
58
- end
59
- end
60
-
61
- def test_add_to_null_transaction
62
- topic = Topic.new
63
- topic.add_to_transaction
64
- end
65
-
66
- def test_successful_with_return
67
- committed = false
68
-
69
- Topic.connection.class_eval do
70
- alias :real_commit_db_transaction :commit_db_transaction
71
- define_method(:commit_db_transaction) do
72
- committed = true
73
- real_commit_db_transaction
74
- end
75
- end
76
-
77
- transaction_with_return
78
- assert committed
79
-
80
- assert Topic.find(1).approved?, "First should have been approved"
81
- assert !Topic.find(2).approved?, "Second should have been unapproved"
82
- ensure
83
- Topic.connection.class_eval do
84
- remove_method :commit_db_transaction
85
- alias :commit_db_transaction :real_commit_db_transaction rescue nil
86
- end
87
- end
88
-
89
- def test_number_of_transactions_in_commit
90
- num = nil
91
-
92
- Topic.connection.class_eval do
93
- alias :real_commit_db_transaction :commit_db_transaction
94
- define_method(:commit_db_transaction) do
95
- num = transaction_manager.open_transactions
96
- real_commit_db_transaction
97
- end
98
- end
99
-
100
- Topic.transaction do
101
- @first.approved = true
102
- @first.save!
103
- end
104
-
105
- assert_equal 0, num
106
- ensure
107
- Topic.connection.class_eval do
108
- remove_method :commit_db_transaction
109
- alias :commit_db_transaction :real_commit_db_transaction rescue nil
110
- end
111
- end
112
-
113
- def test_successful_with_instance_method
114
- @first.transaction do
115
- @first.approved = true
116
- @second.approved = false
117
- @first.save
118
- @second.save
119
- end
120
-
121
- assert Topic.find(1).approved?, "First should have been approved"
122
- assert !Topic.find(2).approved?, "Second should have been unapproved"
123
- end
124
-
125
- def test_failing_on_exception
126
- begin
127
- Topic.transaction do
128
- @first.approved = true
129
- @second.approved = false
130
- @first.save
131
- @second.save
132
- raise "Bad things!"
133
- end
134
- rescue
135
- # caught it
136
- end
137
-
138
- assert @first.approved?, "First should still be changed in the objects"
139
- assert !@second.approved?, "Second should still be changed in the objects"
140
-
141
- assert !Topic.find(1).approved?, "First shouldn't have been approved"
142
- assert Topic.find(2).approved?, "Second should still be approved"
143
- end
144
-
145
- def test_raising_exception_in_callback_rollbacks_in_save
146
- def @first.after_save_for_transaction
147
- raise 'Make the transaction rollback'
148
- end
149
-
150
- @first.approved = true
151
- e = assert_raises(RuntimeError) { @first.save }
152
- assert_equal "Make the transaction rollback", e.message
153
- assert !Topic.find(1).approved?
154
- end
155
-
156
- def test_rolling_back_in_a_callback_rollbacks_before_save
157
- def @first.before_save_for_transaction
158
- raise ActiveRecord::Rollback
159
- end
160
- assert !@first.approved
161
-
162
- Topic.transaction do
163
- @first.approved = true
164
- @first.save!
165
- end
166
- assert !Topic.find(@first.id).approved?, "Should not commit the approved flag"
167
- end
168
-
169
- def test_raising_exception_in_nested_transaction_restore_state_in_save
170
- topic = Topic.new
171
-
172
- def topic.after_save_for_transaction
173
- raise 'Make the transaction rollback'
174
- end
175
-
176
- assert_raises(RuntimeError) do
177
- Topic.transaction { topic.save }
178
- end
179
-
180
- assert topic.new_record?, "#{topic.inspect} should be new record"
181
- end
182
-
183
- def test_transaction_state_is_cleared_when_record_is_persisted
184
- author = Author.create! name: 'foo'
185
- author.name = nil
186
- assert_not author.save
187
- assert_not author.new_record?
188
- end
189
-
190
- def test_update_should_rollback_on_failure
191
- author = Author.find(1)
192
- posts_count = author.posts.size
193
- assert posts_count > 0
194
- status = author.update(name: nil, post_ids: [])
195
- assert !status
196
- assert_equal posts_count, author.posts.reload.size
197
- end
198
-
199
- def test_update_should_rollback_on_failure!
200
- author = Author.find(1)
201
- posts_count = author.posts.size
202
- assert posts_count > 0
203
- assert_raise(ActiveRecord::RecordInvalid) do
204
- author.update!(name: nil, post_ids: [])
205
- end
206
- assert_equal posts_count, author.posts.reload.size
207
- end
208
-
209
- def test_cancellation_from_returning_false_in_before_filter
210
- def @first.before_save_for_transaction
211
- false
212
- end
213
-
214
- assert_deprecated do
215
- @first.save
216
- end
217
- end
218
-
219
- def test_cancellation_from_before_destroy_rollbacks_in_destroy
220
- add_cancelling_before_destroy_with_db_side_effect_to_topic @first
221
- nbooks_before_destroy = Book.count
222
- status = @first.destroy
223
- assert !status
224
- @first.reload
225
- assert_equal nbooks_before_destroy, Book.count
226
- end
227
-
228
- %w(validation save).each do |filter|
229
- define_method("test_cancellation_from_before_filters_rollbacks_in_#{filter}") do
230
- send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first)
231
- nbooks_before_save = Book.count
232
- original_author_name = @first.author_name
233
- @first.author_name += '_this_should_not_end_up_in_the_db'
234
- status = @first.save
235
- assert !status
236
- assert_equal original_author_name, @first.reload.author_name
237
- assert_equal nbooks_before_save, Book.count
238
- end
239
-
240
- define_method("test_cancellation_from_before_filters_rollbacks_in_#{filter}!") do
241
- send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first)
242
- nbooks_before_save = Book.count
243
- original_author_name = @first.author_name
244
- @first.author_name += '_this_should_not_end_up_in_the_db'
245
-
246
- begin
247
- @first.save!
248
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved
249
- end
250
-
251
- assert_equal original_author_name, @first.reload.author_name
252
- assert_equal nbooks_before_save, Book.count
253
- end
254
- end
255
-
256
- def test_callback_rollback_in_create
257
- topic = Class.new(Topic) {
258
- def after_create_for_transaction
259
- raise 'Make the transaction rollback'
260
- end
261
- }
262
-
263
- new_topic = topic.new(:title => "A new topic",
264
- :author_name => "Ben",
265
- :author_email_address => "ben@example.com",
266
- :written_on => "2003-07-16t15:28:11.2233+01:00",
267
- :last_read => "2004-04-15",
268
- :bonus_time => "2005-01-30t15:28:00.00+01:00",
269
- :content => "Have a nice day",
270
- :approved => false)
271
-
272
- new_record_snapshot = !new_topic.persisted?
273
- id_present = new_topic.has_attribute?(Topic.primary_key)
274
- id_snapshot = new_topic.id
275
-
276
- # Make sure the second save gets the after_create callback called.
277
- 2.times do
278
- new_topic.approved = true
279
- e = assert_raises(RuntimeError) { new_topic.save }
280
- assert_equal "Make the transaction rollback", e.message
281
- assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value"
282
- assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
283
- assert_equal id_present, new_topic.has_attribute?(Topic.primary_key)
284
- end
285
- end
286
-
287
- def test_callback_rollback_in_create_with_record_invalid_exception
288
- topic = Class.new(Topic) {
289
- def after_create_for_transaction
290
- raise ActiveRecord::RecordInvalid.new(Author.new)
291
- end
292
- }
293
-
294
- new_topic = topic.create(:title => "A new topic")
295
- assert !new_topic.persisted?, "The topic should not be persisted"
296
- assert_nil new_topic.id, "The topic should not have an ID"
297
- end
298
-
299
- def test_nested_explicit_transactions
300
- Topic.transaction do
301
- Topic.transaction do
302
- @first.approved = true
303
- @second.approved = false
304
- @first.save
305
- @second.save
306
- end
307
- end
308
-
309
- assert Topic.find(1).approved?, "First should have been approved"
310
- assert !Topic.find(2).approved?, "Second should have been unapproved"
311
- end
312
-
313
- def test_manually_rolling_back_a_transaction
314
- Topic.transaction do
315
- @first.approved = true
316
- @second.approved = false
317
- @first.save
318
- @second.save
319
-
320
- raise ActiveRecord::Rollback
321
- end
322
-
323
- assert @first.approved?, "First should still be changed in the objects"
324
- assert !@second.approved?, "Second should still be changed in the objects"
325
-
326
- assert !Topic.find(1).approved?, "First shouldn't have been approved"
327
- assert Topic.find(2).approved?, "Second should still be approved"
328
- end
329
-
330
- def test_invalid_keys_for_transaction
331
- assert_raise ArgumentError do
332
- Topic.transaction :nested => true do
333
- end
334
- end
335
- end
336
-
337
- def test_force_savepoint_in_nested_transaction
338
- Topic.transaction do
339
- @first.approved = true
340
- @second.approved = false
341
- @first.save!
342
- @second.save!
343
-
344
- begin
345
- Topic.transaction :requires_new => true do
346
- @first.happy = false
347
- @first.save!
348
- raise
349
- end
350
- rescue
351
- end
352
- end
353
-
354
- assert @first.reload.approved?
355
- assert !@second.reload.approved?
356
- end if Topic.connection.supports_savepoints?
357
-
358
- def test_force_savepoint_on_instance
359
- @first.transaction do
360
- @first.approved = true
361
- @second.approved = false
362
- @first.save!
363
- @second.save!
364
-
365
- begin
366
- @second.transaction :requires_new => true do
367
- @first.happy = false
368
- @first.save!
369
- raise
370
- end
371
- rescue
372
- end
373
- end
374
-
375
- assert @first.reload.approved?
376
- assert !@second.reload.approved?
377
- end if Topic.connection.supports_savepoints?
378
-
379
- def test_no_savepoint_in_nested_transaction_without_force
380
- Topic.transaction do
381
- @first.approved = true
382
- @second.approved = false
383
- @first.save!
384
- @second.save!
385
-
386
- begin
387
- Topic.transaction do
388
- @first.approved = false
389
- @first.save!
390
- raise
391
- end
392
- rescue
393
- end
394
- end
395
-
396
- assert !@first.reload.approved?
397
- assert !@second.reload.approved?
398
- end if Topic.connection.supports_savepoints?
399
-
400
- def test_many_savepoints
401
- Topic.transaction do
402
- @first.content = "One"
403
- @first.save!
404
-
405
- begin
406
- Topic.transaction :requires_new => true do
407
- @first.content = "Two"
408
- @first.save!
409
-
410
- begin
411
- Topic.transaction :requires_new => true do
412
- @first.content = "Three"
413
- @first.save!
414
-
415
- begin
416
- Topic.transaction :requires_new => true do
417
- @first.content = "Four"
418
- @first.save!
419
- raise
420
- end
421
- rescue
422
- end
423
-
424
- @three = @first.reload.content
425
- raise
426
- end
427
- rescue
428
- end
429
-
430
- @two = @first.reload.content
431
- raise
432
- end
433
- rescue
434
- end
435
-
436
- @one = @first.reload.content
437
- end
438
-
439
- assert_equal "One", @one
440
- assert_equal "Two", @two
441
- assert_equal "Three", @three
442
- end if Topic.connection.supports_savepoints?
443
-
444
- def test_using_named_savepoints
445
- Topic.transaction do
446
- @first.approved = true
447
- @first.save!
448
- Topic.connection.create_savepoint("first")
449
-
450
- @first.approved = false
451
- @first.save!
452
- Topic.connection.rollback_to_savepoint("first")
453
- assert @first.reload.approved?
454
-
455
- @first.approved = false
456
- @first.save!
457
- Topic.connection.release_savepoint("first")
458
- assert_not @first.reload.approved?
459
- end
460
- end if Topic.connection.supports_savepoints?
461
-
462
- def test_releasing_named_savepoints
463
- Topic.transaction do
464
- Topic.connection.create_savepoint("another")
465
- Topic.connection.release_savepoint("another")
466
-
467
- # The savepoint is now gone and we can't remove it again.
468
- assert_raises(ActiveRecord::StatementInvalid) do
469
- Topic.connection.release_savepoint("another")
470
- end
471
- end
472
- end
473
-
474
- def test_savepoints_name
475
- Topic.transaction do
476
- assert_nil Topic.connection.current_savepoint_name
477
- assert_nil Topic.connection.current_transaction.savepoint_name
478
-
479
- Topic.transaction(requires_new: true) do
480
- assert_equal "active_record_1", Topic.connection.current_savepoint_name
481
- assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
482
-
483
- Topic.transaction(requires_new: true) do
484
- assert_equal "active_record_2", Topic.connection.current_savepoint_name
485
- assert_equal "active_record_2", Topic.connection.current_transaction.savepoint_name
486
- end
487
-
488
- assert_equal "active_record_1", Topic.connection.current_savepoint_name
489
- assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
490
- end
491
- end
492
- end
493
-
494
- def test_rollback_when_commit_raises
495
- assert_called(Topic.connection, :begin_db_transaction) do
496
- Topic.connection.stub(:commit_db_transaction, ->{ raise('OH NOES') }) do
497
- assert_called(Topic.connection, :rollback_db_transaction) do
498
-
499
- e = assert_raise RuntimeError do
500
- Topic.transaction do
501
- # do nothing
502
- end
503
- end
504
- assert_equal 'OH NOES', e.message
505
- end
506
- end
507
- end
508
- end
509
-
510
- def test_rollback_when_saving_a_frozen_record
511
- topic = Topic.new(:title => 'test')
512
- topic.freeze
513
- e = assert_raise(frozen_error_class) { topic.save }
514
- # Not good enough, but we can't do much
515
- # about it since there is no specific error
516
- # for frozen objects.
517
- assert_match(/frozen/i, e.message)
518
- assert !topic.persisted?, "not persisted"
519
- assert_nil topic.id
520
- assert topic.frozen?, 'not frozen'
521
- end
522
-
523
- def test_rollback_when_thread_killed
524
- return if in_memory_db?
525
-
526
- queue = Queue.new
527
- thread = Thread.new do
528
- Topic.transaction do
529
- @first.approved = true
530
- @second.approved = false
531
- @first.save
532
-
533
- queue.push nil
534
- sleep
535
-
536
- @second.save
537
- end
538
- end
539
-
540
- queue.pop
541
- thread.kill
542
- thread.join
543
-
544
- assert @first.approved?, "First should still be changed in the objects"
545
- assert !@second.approved?, "Second should still be changed in the objects"
546
-
547
- assert !Topic.find(1).approved?, "First shouldn't have been approved"
548
- assert Topic.find(2).approved?, "Second should still be approved"
549
- end
550
-
551
- def test_restore_active_record_state_for_all_records_in_a_transaction
552
- topic_without_callbacks = Class.new(ActiveRecord::Base) do
553
- self.table_name = 'topics'
554
- end
555
-
556
- topic_1 = Topic.new(:title => 'test_1')
557
- topic_2 = Topic.new(:title => 'test_2')
558
- topic_3 = topic_without_callbacks.new(:title => 'test_3')
559
-
560
- Topic.transaction do
561
- assert topic_1.save
562
- assert topic_2.save
563
- assert topic_3.save
564
- @first.save
565
- @second.destroy
566
- assert topic_1.persisted?, 'persisted'
567
- assert_not_nil topic_1.id
568
- assert topic_2.persisted?, 'persisted'
569
- assert_not_nil topic_2.id
570
- assert topic_3.persisted?, 'persisted'
571
- assert_not_nil topic_3.id
572
- assert @first.persisted?, 'persisted'
573
- assert_not_nil @first.id
574
- assert @second.destroyed?, 'destroyed'
575
- raise ActiveRecord::Rollback
576
- end
577
-
578
- assert !topic_1.persisted?, 'not persisted'
579
- assert_nil topic_1.id
580
- assert !topic_2.persisted?, 'not persisted'
581
- assert_nil topic_2.id
582
- assert !topic_3.persisted?, 'not persisted'
583
- assert_nil topic_3.id
584
- assert @first.persisted?, 'persisted'
585
- assert_not_nil @first.id
586
- assert !@second.destroyed?, 'not destroyed'
587
- end
588
-
589
- def test_restore_frozen_state_after_double_destroy
590
- topic = Topic.create
591
- reply = topic.replies.create
592
-
593
- Topic.transaction do
594
- topic.destroy # calls #destroy on reply (since dependent: destroy)
595
- reply.destroy
596
-
597
- raise ActiveRecord::Rollback
598
- end
599
-
600
- assert_not reply.frozen?
601
- assert_not topic.frozen?
602
- end
603
-
604
- def test_rollback_of_frozen_records
605
- topic = Topic.create.freeze
606
- Topic.transaction do
607
- topic.destroy
608
- raise ActiveRecord::Rollback
609
- end
610
- assert topic.frozen?, 'frozen'
611
- end
612
-
613
- def test_rollback_for_freshly_persisted_records
614
- topic = Topic.create
615
- Topic.transaction do
616
- topic.destroy
617
- raise ActiveRecord::Rollback
618
- end
619
- assert topic.persisted?, 'persisted'
620
- end
621
-
622
- def test_sqlite_add_column_in_transaction
623
- return true unless current_adapter?(:SQLite3Adapter)
624
-
625
- # Test first if column creation/deletion works correctly when no
626
- # transaction is in place.
627
- #
628
- # We go back to the connection for the column queries because
629
- # Topic.columns is cached and won't report changes to the DB
630
-
631
- assert_nothing_raised do
632
- Topic.reset_column_information
633
- Topic.connection.add_column('topics', 'stuff', :string)
634
- assert Topic.column_names.include?('stuff')
635
-
636
- Topic.reset_column_information
637
- Topic.connection.remove_column('topics', 'stuff')
638
- assert !Topic.column_names.include?('stuff')
639
- end
640
-
641
- if Topic.connection.supports_ddl_transactions?
642
- assert_nothing_raised do
643
- Topic.transaction { Topic.connection.add_column('topics', 'stuff', :string) }
644
- end
645
- else
646
- Topic.transaction do
647
- assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) }
648
- raise ActiveRecord::Rollback
649
- end
650
- end
651
- ensure
652
- begin
653
- Topic.connection.remove_column('topics', 'stuff')
654
- rescue
655
- ensure
656
- Topic.reset_column_information
657
- end
658
- end
659
-
660
- def test_transactions_state_from_rollback
661
- connection = Topic.connection
662
- transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
663
-
664
- assert transaction.open?
665
- assert !transaction.state.rolledback?
666
- assert !transaction.state.committed?
667
-
668
- transaction.rollback
669
-
670
- assert transaction.state.rolledback?
671
- assert !transaction.state.committed?
672
- end
673
-
674
- def test_transactions_state_from_commit
675
- connection = Topic.connection
676
- transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
677
-
678
- assert transaction.open?
679
- assert !transaction.state.rolledback?
680
- assert !transaction.state.committed?
681
-
682
- transaction.commit
683
-
684
- assert !transaction.state.rolledback?
685
- assert transaction.state.committed?
686
- end
687
-
688
- def test_transaction_rollback_with_primarykeyless_tables
689
- connection = ActiveRecord::Base.connection
690
- connection.create_table(:transaction_without_primary_keys, force: true, id: false) do |t|
691
- t.integer :thing_id
692
- end
693
-
694
- klass = Class.new(ActiveRecord::Base) do
695
- self.table_name = 'transaction_without_primary_keys'
696
- after_commit { } # necessary to trigger the has_transactional_callbacks branch
697
- end
698
-
699
- assert_no_difference(-> { klass.count }) do
700
- ActiveRecord::Base.transaction do
701
- klass.create!
702
- raise ActiveRecord::Rollback
703
- end
704
- end
705
- ensure
706
- connection.drop_table 'transaction_without_primary_keys', if_exists: true
707
- end
708
-
709
- private
710
-
711
- %w(validation save destroy).each do |filter|
712
- define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic|
713
- meta = class << topic; self; end
714
- meta.send("define_method", "before_#{filter}_for_transaction") do
715
- Book.create
716
- throw(:abort)
717
- end
718
- end
719
- end
720
- end
721
-
722
- class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
723
- self.use_transactional_tests = true
724
- fixtures :topics
725
-
726
- def test_automatic_savepoint_in_outer_transaction
727
- @first = Topic.find(1)
728
-
729
- begin
730
- Topic.transaction do
731
- @first.approved = true
732
- @first.save!
733
- raise
734
- end
735
- rescue
736
- assert !@first.reload.approved?
737
- end
738
- end
739
-
740
- def test_no_automatic_savepoint_for_inner_transaction
741
- @first = Topic.find(1)
742
-
743
- Topic.transaction do
744
- @first.approved = true
745
- @first.save!
746
-
747
- begin
748
- Topic.transaction do
749
- @first.approved = false
750
- @first.save!
751
- raise
752
- end
753
- rescue
754
- end
755
- end
756
-
757
- assert !@first.reload.approved?
758
- end
759
- end if Topic.connection.supports_savepoints?
760
-
761
- if current_adapter?(:PostgreSQLAdapter)
762
- class ConcurrentTransactionTest < TransactionTest
763
- # This will cause transactions to overlap and fail unless they are performed on
764
- # separate database connections.
765
- unless in_memory_db?
766
- def test_transaction_per_thread
767
- threads = 3.times.map do
768
- Thread.new do
769
- Topic.transaction do
770
- topic = Topic.find(1)
771
- topic.approved = !topic.approved?
772
- assert topic.save!
773
- topic.approved = !topic.approved?
774
- assert topic.save!
775
- end
776
- Topic.connection.close
777
- end
778
- end
779
-
780
- threads.each(&:join)
781
- end
782
- end
783
-
784
- # Test for dirty reads among simultaneous transactions.
785
- def test_transaction_isolation__read_committed
786
- # Should be invariant.
787
- original_salary = Developer.find(1).salary
788
- temporary_salary = 200000
789
-
790
- assert_nothing_raised do
791
- threads = (1..3).map do
792
- Thread.new do
793
- Developer.transaction do
794
- # Expect original salary.
795
- dev = Developer.find(1)
796
- assert_equal original_salary, dev.salary
797
-
798
- dev.salary = temporary_salary
799
- dev.save!
800
-
801
- # Expect temporary salary.
802
- dev = Developer.find(1)
803
- assert_equal temporary_salary, dev.salary
804
-
805
- dev.salary = original_salary
806
- dev.save!
807
-
808
- # Expect original salary.
809
- dev = Developer.find(1)
810
- assert_equal original_salary, dev.salary
811
- end
812
- Developer.connection.close
813
- end
814
- end
815
-
816
- # Keep our eyes peeled.
817
- threads << Thread.new do
818
- 10.times do
819
- sleep 0.05
820
- Developer.transaction do
821
- # Always expect original salary.
822
- assert_equal original_salary, Developer.find(1).salary
823
- end
824
- end
825
- Developer.connection.close
826
- end
827
-
828
- threads.each(&:join)
829
- end
830
-
831
- assert_equal original_salary, Developer.find(1).salary
832
- end
833
- end
834
- end
1
+ require "cases/helper"
2
+ require 'models/topic'
3
+ require 'models/reply'
4
+ require 'models/developer'
5
+ require 'models/computer'
6
+ require 'models/book'
7
+ require 'models/author'
8
+ require 'models/post'
9
+ require 'models/movie'
10
+
11
+ class TransactionTest < ActiveRecord::TestCase
12
+ self.use_transactional_tests = false
13
+ fixtures :topics, :developers, :authors, :posts, :author_addresses
14
+
15
+ def setup
16
+ @first, @second = Topic.find(1, 2).sort_by(&:id)
17
+ end
18
+
19
+ def test_persisted_in_a_model_with_custom_primary_key_after_failed_save
20
+ movie = Movie.create
21
+ assert !movie.persisted?
22
+ end
23
+
24
+ def test_raise_after_destroy
25
+ assert_not @first.frozen?
26
+
27
+ assert_raises(RuntimeError) {
28
+ Topic.transaction do
29
+ @first.destroy
30
+ assert @first.frozen?
31
+ raise
32
+ end
33
+ }
34
+
35
+ assert @first.reload
36
+ assert_not @first.frozen?
37
+ end
38
+
39
+ def test_successful
40
+ Topic.transaction do
41
+ @first.approved = true
42
+ @second.approved = false
43
+ @first.save
44
+ @second.save
45
+ end
46
+
47
+ assert Topic.find(1).approved?, "First should have been approved"
48
+ assert !Topic.find(2).approved?, "Second should have been unapproved"
49
+ end
50
+
51
+ def transaction_with_return
52
+ Topic.transaction do
53
+ @first.approved = true
54
+ @second.approved = false
55
+ @first.save
56
+ @second.save
57
+ return
58
+ end
59
+ end
60
+
61
+ def test_add_to_null_transaction
62
+ topic = Topic.new
63
+ topic.add_to_transaction
64
+ end
65
+
66
+ def test_successful_with_return
67
+ committed = false
68
+
69
+ Topic.connection.class_eval do
70
+ alias :real_commit_db_transaction :commit_db_transaction
71
+ define_method(:commit_db_transaction) do
72
+ committed = true
73
+ real_commit_db_transaction
74
+ end
75
+ end
76
+
77
+ transaction_with_return
78
+ assert committed
79
+
80
+ assert Topic.find(1).approved?, "First should have been approved"
81
+ assert !Topic.find(2).approved?, "Second should have been unapproved"
82
+ ensure
83
+ Topic.connection.class_eval do
84
+ remove_method :commit_db_transaction
85
+ alias :commit_db_transaction :real_commit_db_transaction rescue nil
86
+ end
87
+ end
88
+
89
+ def test_number_of_transactions_in_commit
90
+ num = nil
91
+
92
+ Topic.connection.class_eval do
93
+ alias :real_commit_db_transaction :commit_db_transaction
94
+ define_method(:commit_db_transaction) do
95
+ num = transaction_manager.open_transactions
96
+ real_commit_db_transaction
97
+ end
98
+ end
99
+
100
+ Topic.transaction do
101
+ @first.approved = true
102
+ @first.save!
103
+ end
104
+
105
+ assert_equal 0, num
106
+ ensure
107
+ Topic.connection.class_eval do
108
+ remove_method :commit_db_transaction
109
+ alias :commit_db_transaction :real_commit_db_transaction rescue nil
110
+ end
111
+ end
112
+
113
+ def test_successful_with_instance_method
114
+ @first.transaction do
115
+ @first.approved = true
116
+ @second.approved = false
117
+ @first.save
118
+ @second.save
119
+ end
120
+
121
+ assert Topic.find(1).approved?, "First should have been approved"
122
+ assert !Topic.find(2).approved?, "Second should have been unapproved"
123
+ end
124
+
125
+ def test_failing_on_exception
126
+ begin
127
+ Topic.transaction do
128
+ @first.approved = true
129
+ @second.approved = false
130
+ @first.save
131
+ @second.save
132
+ raise "Bad things!"
133
+ end
134
+ rescue
135
+ # caught it
136
+ end
137
+
138
+ assert @first.approved?, "First should still be changed in the objects"
139
+ assert !@second.approved?, "Second should still be changed in the objects"
140
+
141
+ assert !Topic.find(1).approved?, "First shouldn't have been approved"
142
+ assert Topic.find(2).approved?, "Second should still be approved"
143
+ end
144
+
145
+ def test_raising_exception_in_callback_rollbacks_in_save
146
+ def @first.after_save_for_transaction
147
+ raise 'Make the transaction rollback'
148
+ end
149
+
150
+ @first.approved = true
151
+ e = assert_raises(RuntimeError) { @first.save }
152
+ assert_equal "Make the transaction rollback", e.message
153
+ assert !Topic.find(1).approved?
154
+ end
155
+
156
+ def test_rolling_back_in_a_callback_rollbacks_before_save
157
+ def @first.before_save_for_transaction
158
+ raise ActiveRecord::Rollback
159
+ end
160
+ assert !@first.approved
161
+
162
+ Topic.transaction do
163
+ @first.approved = true
164
+ @first.save!
165
+ end
166
+ assert !Topic.find(@first.id).approved?, "Should not commit the approved flag"
167
+ end
168
+
169
+ def test_raising_exception_in_nested_transaction_restore_state_in_save
170
+ topic = Topic.new
171
+
172
+ def topic.after_save_for_transaction
173
+ raise 'Make the transaction rollback'
174
+ end
175
+
176
+ assert_raises(RuntimeError) do
177
+ Topic.transaction { topic.save }
178
+ end
179
+
180
+ assert topic.new_record?, "#{topic.inspect} should be new record"
181
+ end
182
+
183
+ def test_transaction_state_is_cleared_when_record_is_persisted
184
+ author = Author.create! name: 'foo'
185
+ author.name = nil
186
+ assert_not author.save
187
+ assert_not author.new_record?
188
+ end
189
+
190
+ def test_update_should_rollback_on_failure
191
+ author = Author.find(1)
192
+ posts_count = author.posts.size
193
+ assert posts_count > 0
194
+ status = author.update(name: nil, post_ids: [])
195
+ assert !status
196
+ assert_equal posts_count, author.posts.reload.size
197
+ end
198
+
199
+ def test_update_should_rollback_on_failure!
200
+ author = Author.find(1)
201
+ posts_count = author.posts.size
202
+ assert posts_count > 0
203
+ assert_raise(ActiveRecord::RecordInvalid) do
204
+ author.update!(name: nil, post_ids: [])
205
+ end
206
+ assert_equal posts_count, author.posts.reload.size
207
+ end
208
+
209
+ def test_cancellation_from_returning_false_in_before_filter
210
+ def @first.before_save_for_transaction
211
+ false
212
+ end
213
+
214
+ assert_deprecated do
215
+ @first.save
216
+ end
217
+ end
218
+
219
+ def test_cancellation_from_before_destroy_rollbacks_in_destroy
220
+ add_cancelling_before_destroy_with_db_side_effect_to_topic @first
221
+ nbooks_before_destroy = Book.count
222
+ status = @first.destroy
223
+ assert !status
224
+ @first.reload
225
+ assert_equal nbooks_before_destroy, Book.count
226
+ end
227
+
228
+ %w(validation save).each do |filter|
229
+ define_method("test_cancellation_from_before_filters_rollbacks_in_#{filter}") do
230
+ send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first)
231
+ nbooks_before_save = Book.count
232
+ original_author_name = @first.author_name
233
+ @first.author_name += '_this_should_not_end_up_in_the_db'
234
+ status = @first.save
235
+ assert !status
236
+ assert_equal original_author_name, @first.reload.author_name
237
+ assert_equal nbooks_before_save, Book.count
238
+ end
239
+
240
+ define_method("test_cancellation_from_before_filters_rollbacks_in_#{filter}!") do
241
+ send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first)
242
+ nbooks_before_save = Book.count
243
+ original_author_name = @first.author_name
244
+ @first.author_name += '_this_should_not_end_up_in_the_db'
245
+
246
+ begin
247
+ @first.save!
248
+ rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved
249
+ end
250
+
251
+ assert_equal original_author_name, @first.reload.author_name
252
+ assert_equal nbooks_before_save, Book.count
253
+ end
254
+ end
255
+
256
+ def test_callback_rollback_in_create
257
+ topic = Class.new(Topic) {
258
+ def after_create_for_transaction
259
+ raise 'Make the transaction rollback'
260
+ end
261
+ }
262
+
263
+ new_topic = topic.new(:title => "A new topic",
264
+ :author_name => "Ben",
265
+ :author_email_address => "ben@example.com",
266
+ :written_on => "2003-07-16t15:28:11.2233+01:00",
267
+ :last_read => "2004-04-15",
268
+ :bonus_time => "2005-01-30t15:28:00.00+01:00",
269
+ :content => "Have a nice day",
270
+ :approved => false)
271
+
272
+ new_record_snapshot = !new_topic.persisted?
273
+ id_present = new_topic.has_attribute?(Topic.primary_key)
274
+ id_snapshot = new_topic.id
275
+
276
+ # Make sure the second save gets the after_create callback called.
277
+ 2.times do
278
+ new_topic.approved = true
279
+ e = assert_raises(RuntimeError) { new_topic.save }
280
+ assert_equal "Make the transaction rollback", e.message
281
+ assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value"
282
+ assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
283
+ assert_equal id_present, new_topic.has_attribute?(Topic.primary_key)
284
+ end
285
+ end
286
+
287
+ def test_callback_rollback_in_create_with_record_invalid_exception
288
+ topic = Class.new(Topic) {
289
+ def after_create_for_transaction
290
+ raise ActiveRecord::RecordInvalid.new(Author.new)
291
+ end
292
+ }
293
+
294
+ new_topic = topic.create(:title => "A new topic")
295
+ assert !new_topic.persisted?, "The topic should not be persisted"
296
+ assert_nil new_topic.id, "The topic should not have an ID"
297
+ end
298
+
299
+ def test_nested_explicit_transactions
300
+ Topic.transaction do
301
+ Topic.transaction do
302
+ @first.approved = true
303
+ @second.approved = false
304
+ @first.save
305
+ @second.save
306
+ end
307
+ end
308
+
309
+ assert Topic.find(1).approved?, "First should have been approved"
310
+ assert !Topic.find(2).approved?, "Second should have been unapproved"
311
+ end
312
+
313
+ def test_manually_rolling_back_a_transaction
314
+ Topic.transaction do
315
+ @first.approved = true
316
+ @second.approved = false
317
+ @first.save
318
+ @second.save
319
+
320
+ raise ActiveRecord::Rollback
321
+ end
322
+
323
+ assert @first.approved?, "First should still be changed in the objects"
324
+ assert !@second.approved?, "Second should still be changed in the objects"
325
+
326
+ assert !Topic.find(1).approved?, "First shouldn't have been approved"
327
+ assert Topic.find(2).approved?, "Second should still be approved"
328
+ end
329
+
330
+ def test_invalid_keys_for_transaction
331
+ assert_raise ArgumentError do
332
+ Topic.transaction :nested => true do
333
+ end
334
+ end
335
+ end
336
+
337
+ def test_force_savepoint_in_nested_transaction
338
+ Topic.transaction do
339
+ @first.approved = true
340
+ @second.approved = false
341
+ @first.save!
342
+ @second.save!
343
+
344
+ begin
345
+ Topic.transaction :requires_new => true do
346
+ @first.happy = false
347
+ @first.save!
348
+ raise
349
+ end
350
+ rescue
351
+ end
352
+ end
353
+
354
+ assert @first.reload.approved?
355
+ assert !@second.reload.approved?
356
+ end if Topic.connection.supports_savepoints?
357
+
358
+ def test_force_savepoint_on_instance
359
+ @first.transaction do
360
+ @first.approved = true
361
+ @second.approved = false
362
+ @first.save!
363
+ @second.save!
364
+
365
+ begin
366
+ @second.transaction :requires_new => true do
367
+ @first.happy = false
368
+ @first.save!
369
+ raise
370
+ end
371
+ rescue
372
+ end
373
+ end
374
+
375
+ assert @first.reload.approved?
376
+ assert !@second.reload.approved?
377
+ end if Topic.connection.supports_savepoints?
378
+
379
+ def test_no_savepoint_in_nested_transaction_without_force
380
+ Topic.transaction do
381
+ @first.approved = true
382
+ @second.approved = false
383
+ @first.save!
384
+ @second.save!
385
+
386
+ begin
387
+ Topic.transaction do
388
+ @first.approved = false
389
+ @first.save!
390
+ raise
391
+ end
392
+ rescue
393
+ end
394
+ end
395
+
396
+ assert !@first.reload.approved?
397
+ assert !@second.reload.approved?
398
+ end if Topic.connection.supports_savepoints?
399
+
400
+ def test_many_savepoints
401
+ Topic.transaction do
402
+ @first.content = "One"
403
+ @first.save!
404
+
405
+ begin
406
+ Topic.transaction :requires_new => true do
407
+ @first.content = "Two"
408
+ @first.save!
409
+
410
+ begin
411
+ Topic.transaction :requires_new => true do
412
+ @first.content = "Three"
413
+ @first.save!
414
+
415
+ begin
416
+ Topic.transaction :requires_new => true do
417
+ @first.content = "Four"
418
+ @first.save!
419
+ raise
420
+ end
421
+ rescue
422
+ end
423
+
424
+ @three = @first.reload.content
425
+ raise
426
+ end
427
+ rescue
428
+ end
429
+
430
+ @two = @first.reload.content
431
+ raise
432
+ end
433
+ rescue
434
+ end
435
+
436
+ @one = @first.reload.content
437
+ end
438
+
439
+ assert_equal "One", @one
440
+ assert_equal "Two", @two
441
+ assert_equal "Three", @three
442
+ end if Topic.connection.supports_savepoints?
443
+
444
+ def test_using_named_savepoints
445
+ Topic.transaction do
446
+ @first.approved = true
447
+ @first.save!
448
+ Topic.connection.create_savepoint("first")
449
+
450
+ @first.approved = false
451
+ @first.save!
452
+ Topic.connection.rollback_to_savepoint("first")
453
+ assert @first.reload.approved?
454
+
455
+ @first.approved = false
456
+ @first.save!
457
+ Topic.connection.release_savepoint("first")
458
+ assert_not @first.reload.approved?
459
+ end
460
+ end if Topic.connection.supports_savepoints?
461
+
462
+ def test_releasing_named_savepoints
463
+ Topic.transaction do
464
+ Topic.connection.create_savepoint("another")
465
+ Topic.connection.release_savepoint("another")
466
+
467
+ # The savepoint is now gone and we can't remove it again.
468
+ assert_raises(ActiveRecord::StatementInvalid) do
469
+ Topic.connection.release_savepoint("another")
470
+ end
471
+ end
472
+ end
473
+
474
+ def test_savepoints_name
475
+ Topic.transaction do
476
+ assert_nil Topic.connection.current_savepoint_name
477
+ assert_nil Topic.connection.current_transaction.savepoint_name
478
+
479
+ Topic.transaction(requires_new: true) do
480
+ assert_equal "active_record_1", Topic.connection.current_savepoint_name
481
+ assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
482
+
483
+ Topic.transaction(requires_new: true) do
484
+ assert_equal "active_record_2", Topic.connection.current_savepoint_name
485
+ assert_equal "active_record_2", Topic.connection.current_transaction.savepoint_name
486
+ end
487
+
488
+ assert_equal "active_record_1", Topic.connection.current_savepoint_name
489
+ assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
490
+ end
491
+ end
492
+ end
493
+
494
+ def test_rollback_when_commit_raises
495
+ assert_called(Topic.connection, :begin_db_transaction) do
496
+ Topic.connection.stub(:commit_db_transaction, ->{ raise('OH NOES') }) do
497
+ assert_called(Topic.connection, :rollback_db_transaction) do
498
+
499
+ e = assert_raise RuntimeError do
500
+ Topic.transaction do
501
+ # do nothing
502
+ end
503
+ end
504
+ assert_equal 'OH NOES', e.message
505
+ end
506
+ end
507
+ end
508
+ end
509
+
510
+ def test_rollback_when_saving_a_frozen_record
511
+ topic = Topic.new(:title => 'test')
512
+ topic.freeze
513
+ e = assert_raise(frozen_error_class) { topic.save }
514
+ # Not good enough, but we can't do much
515
+ # about it since there is no specific error
516
+ # for frozen objects.
517
+ assert_match(/frozen/i, e.message)
518
+ assert !topic.persisted?, "not persisted"
519
+ assert_nil topic.id
520
+ assert topic.frozen?, 'not frozen'
521
+ end
522
+
523
+ def test_rollback_when_thread_killed
524
+ return if in_memory_db?
525
+
526
+ queue = Queue.new
527
+ thread = Thread.new do
528
+ Topic.transaction do
529
+ @first.approved = true
530
+ @second.approved = false
531
+ @first.save
532
+
533
+ queue.push nil
534
+ sleep
535
+
536
+ @second.save
537
+ end
538
+ end
539
+
540
+ queue.pop
541
+ thread.kill
542
+ thread.join
543
+
544
+ assert @first.approved?, "First should still be changed in the objects"
545
+ assert !@second.approved?, "Second should still be changed in the objects"
546
+
547
+ assert !Topic.find(1).approved?, "First shouldn't have been approved"
548
+ assert Topic.find(2).approved?, "Second should still be approved"
549
+ end
550
+
551
+ def test_restore_active_record_state_for_all_records_in_a_transaction
552
+ topic_without_callbacks = Class.new(ActiveRecord::Base) do
553
+ self.table_name = 'topics'
554
+ end
555
+
556
+ topic_1 = Topic.new(:title => 'test_1')
557
+ topic_2 = Topic.new(:title => 'test_2')
558
+ topic_3 = topic_without_callbacks.new(:title => 'test_3')
559
+
560
+ Topic.transaction do
561
+ assert topic_1.save
562
+ assert topic_2.save
563
+ assert topic_3.save
564
+ @first.save
565
+ @second.destroy
566
+ assert topic_1.persisted?, 'persisted'
567
+ assert_not_nil topic_1.id
568
+ assert topic_2.persisted?, 'persisted'
569
+ assert_not_nil topic_2.id
570
+ assert topic_3.persisted?, 'persisted'
571
+ assert_not_nil topic_3.id
572
+ assert @first.persisted?, 'persisted'
573
+ assert_not_nil @first.id
574
+ assert @second.destroyed?, 'destroyed'
575
+ raise ActiveRecord::Rollback
576
+ end
577
+
578
+ assert !topic_1.persisted?, 'not persisted'
579
+ assert_nil topic_1.id
580
+ assert !topic_2.persisted?, 'not persisted'
581
+ assert_nil topic_2.id
582
+ assert !topic_3.persisted?, 'not persisted'
583
+ assert_nil topic_3.id
584
+ assert @first.persisted?, 'persisted'
585
+ assert_not_nil @first.id
586
+ assert !@second.destroyed?, 'not destroyed'
587
+ end
588
+
589
+ def test_restore_frozen_state_after_double_destroy
590
+ topic = Topic.create
591
+ reply = topic.replies.create
592
+
593
+ Topic.transaction do
594
+ topic.destroy # calls #destroy on reply (since dependent: destroy)
595
+ reply.destroy
596
+
597
+ raise ActiveRecord::Rollback
598
+ end
599
+
600
+ assert_not reply.frozen?
601
+ assert_not topic.frozen?
602
+ end
603
+
604
+ def test_rollback_of_frozen_records
605
+ topic = Topic.create.freeze
606
+ Topic.transaction do
607
+ topic.destroy
608
+ raise ActiveRecord::Rollback
609
+ end
610
+ assert topic.frozen?, 'frozen'
611
+ end
612
+
613
+ def test_rollback_for_freshly_persisted_records
614
+ topic = Topic.create
615
+ Topic.transaction do
616
+ topic.destroy
617
+ raise ActiveRecord::Rollback
618
+ end
619
+ assert topic.persisted?, 'persisted'
620
+ end
621
+
622
+ def test_sqlite_add_column_in_transaction
623
+ return true unless current_adapter?(:SQLite3Adapter)
624
+
625
+ # Test first if column creation/deletion works correctly when no
626
+ # transaction is in place.
627
+ #
628
+ # We go back to the connection for the column queries because
629
+ # Topic.columns is cached and won't report changes to the DB
630
+
631
+ assert_nothing_raised do
632
+ Topic.reset_column_information
633
+ Topic.connection.add_column('topics', 'stuff', :string)
634
+ assert Topic.column_names.include?('stuff')
635
+
636
+ Topic.reset_column_information
637
+ Topic.connection.remove_column('topics', 'stuff')
638
+ assert !Topic.column_names.include?('stuff')
639
+ end
640
+
641
+ if Topic.connection.supports_ddl_transactions?
642
+ assert_nothing_raised do
643
+ Topic.transaction { Topic.connection.add_column('topics', 'stuff', :string) }
644
+ end
645
+ else
646
+ Topic.transaction do
647
+ assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) }
648
+ raise ActiveRecord::Rollback
649
+ end
650
+ end
651
+ ensure
652
+ begin
653
+ Topic.connection.remove_column('topics', 'stuff')
654
+ rescue
655
+ ensure
656
+ Topic.reset_column_information
657
+ end
658
+ end
659
+
660
+ def test_transactions_state_from_rollback
661
+ connection = Topic.connection
662
+ transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
663
+
664
+ assert transaction.open?
665
+ assert !transaction.state.rolledback?
666
+ assert !transaction.state.committed?
667
+
668
+ transaction.rollback
669
+
670
+ assert transaction.state.rolledback?
671
+ assert !transaction.state.committed?
672
+ end
673
+
674
+ def test_transactions_state_from_commit
675
+ connection = Topic.connection
676
+ transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
677
+
678
+ assert transaction.open?
679
+ assert !transaction.state.rolledback?
680
+ assert !transaction.state.committed?
681
+
682
+ transaction.commit
683
+
684
+ assert !transaction.state.rolledback?
685
+ assert transaction.state.committed?
686
+ end
687
+
688
+ def test_transaction_rollback_with_primarykeyless_tables
689
+ connection = ActiveRecord::Base.connection
690
+ connection.create_table(:transaction_without_primary_keys, force: true, id: false) do |t|
691
+ t.integer :thing_id
692
+ end
693
+
694
+ klass = Class.new(ActiveRecord::Base) do
695
+ self.table_name = 'transaction_without_primary_keys'
696
+ after_commit { } # necessary to trigger the has_transactional_callbacks branch
697
+ end
698
+
699
+ assert_no_difference(-> { klass.count }) do
700
+ ActiveRecord::Base.transaction do
701
+ klass.create!
702
+ raise ActiveRecord::Rollback
703
+ end
704
+ end
705
+ ensure
706
+ connection.drop_table 'transaction_without_primary_keys'
707
+ #, if_exists: true
708
+ end
709
+
710
+ private
711
+
712
+ %w(validation save destroy).each do |filter|
713
+ define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic|
714
+ meta = class << topic; self; end
715
+ meta.send("define_method", "before_#{filter}_for_transaction") do
716
+ Book.create
717
+ throw(:abort)
718
+ end
719
+ end
720
+ end
721
+ end
722
+
723
+ class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
724
+ self.use_transactional_tests = true
725
+ fixtures :topics
726
+
727
+ def test_automatic_savepoint_in_outer_transaction
728
+ @first = Topic.find(1)
729
+
730
+ begin
731
+ Topic.transaction do
732
+ @first.approved = true
733
+ @first.save!
734
+ raise
735
+ end
736
+ rescue
737
+ assert !@first.reload.approved?
738
+ end
739
+ end
740
+
741
+ def test_no_automatic_savepoint_for_inner_transaction
742
+ @first = Topic.find(1)
743
+
744
+ Topic.transaction do
745
+ @first.approved = true
746
+ @first.save!
747
+
748
+ begin
749
+ Topic.transaction do
750
+ @first.approved = false
751
+ @first.save!
752
+ raise
753
+ end
754
+ rescue
755
+ end
756
+ end
757
+
758
+ assert !@first.reload.approved?
759
+ end
760
+ end if Topic.connection.supports_savepoints?
761
+
762
+ if current_adapter?(:PostgreSQLAdapter)
763
+ class ConcurrentTransactionTest < TransactionTest
764
+ # This will cause transactions to overlap and fail unless they are performed on
765
+ # separate database connections.
766
+ unless in_memory_db?
767
+ def test_transaction_per_thread
768
+ threads = 3.times.map do
769
+ Thread.new do
770
+ Topic.transaction do
771
+ topic = Topic.find(1)
772
+ topic.approved = !topic.approved?
773
+ assert topic.save!
774
+ topic.approved = !topic.approved?
775
+ assert topic.save!
776
+ end
777
+ Topic.connection.close
778
+ end
779
+ end
780
+
781
+ threads.each(&:join)
782
+ end
783
+ end
784
+
785
+ # Test for dirty reads among simultaneous transactions.
786
+ def test_transaction_isolation__read_committed
787
+ # Should be invariant.
788
+ original_salary = Developer.find(1).salary
789
+ temporary_salary = 200000
790
+
791
+ assert_nothing_raised do
792
+ threads = (1..3).map do
793
+ Thread.new do
794
+ Developer.transaction do
795
+ # Expect original salary.
796
+ dev = Developer.find(1)
797
+ assert_equal original_salary, dev.salary
798
+
799
+ dev.salary = temporary_salary
800
+ dev.save!
801
+
802
+ # Expect temporary salary.
803
+ dev = Developer.find(1)
804
+ assert_equal temporary_salary, dev.salary
805
+
806
+ dev.salary = original_salary
807
+ dev.save!
808
+
809
+ # Expect original salary.
810
+ dev = Developer.find(1)
811
+ assert_equal original_salary, dev.salary
812
+ end
813
+ Developer.connection.close
814
+ end
815
+ end
816
+
817
+ # Keep our eyes peeled.
818
+ threads << Thread.new do
819
+ 10.times do
820
+ sleep 0.05
821
+ Developer.transaction do
822
+ # Always expect original salary.
823
+ assert_equal original_salary, Developer.find(1).salary
824
+ end
825
+ end
826
+ Developer.connection.close
827
+ end
828
+
829
+ threads.each(&:join)
830
+ end
831
+
832
+ assert_equal original_salary, Developer.find(1).salary
833
+ end
834
+ end
835
+ end