ibm_db 3.0.4-x86-mingw32 → 3.0.5-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 (463) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -1
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/README +225 -225
  6. data/ext/Makefile.nt32 +181 -181
  7. data/ext/Makefile.nt32.191 +212 -212
  8. data/ext/extconf.rb +291 -291
  9. data/ext/ibm_db.c +11887 -11884
  10. data/ext/ruby_ibm_db.h +241 -241
  11. data/ext/ruby_ibm_db_cli.c +866 -866
  12. data/ext/ruby_ibm_db_cli.h +500 -500
  13. data/init.rb +41 -41
  14. data/lib/IBM_DB.rb +27 -27
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3177 -3177
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  18. data/lib/mswin32/ibm_db.rb +122 -122
  19. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  20. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  21. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  22. data/test/active_record/connection_adapters/fake_adapter.rb +46 -46
  23. data/test/assets/example.log +1 -1
  24. data/test/assets/test.txt +1 -1
  25. data/test/cases/adapter_test.rb +276 -261
  26. data/test/cases/aggregations_test.rb +158 -158
  27. data/test/cases/ar_schema_test.rb +161 -161
  28. data/test/cases/associations/association_scope_test.rb +21 -21
  29. data/test/cases/associations/belongs_to_associations_test.rb +1029 -1029
  30. data/test/cases/associations/callbacks_test.rb +192 -192
  31. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  32. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +26 -26
  33. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  34. data/test/cases/associations/eager_load_nested_include_test.rb +128 -128
  35. data/test/cases/associations/eager_singularization_test.rb +148 -148
  36. data/test/cases/associations/eager_test.rb +1429 -1411
  37. data/test/cases/associations/extension_test.rb +82 -82
  38. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +972 -932
  39. data/test/cases/associations/has_many_associations_test.rb +2182 -2162
  40. data/test/cases/associations/has_many_through_associations_test.rb +1204 -1204
  41. data/test/cases/associations/has_one_associations_test.rb +610 -610
  42. data/test/cases/associations/has_one_through_associations_test.rb +380 -380
  43. data/test/cases/associations/inner_join_association_test.rb +139 -139
  44. data/test/cases/associations/inverse_associations_test.rb +706 -693
  45. data/test/cases/associations/join_model_test.rb +754 -754
  46. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  47. data/test/cases/associations/required_test.rb +82 -82
  48. data/test/cases/associations_test.rb +380 -380
  49. data/test/cases/attribute_decorators_test.rb +125 -125
  50. data/test/cases/attribute_methods/read_test.rb +60 -60
  51. data/test/cases/attribute_methods/serialization_test.rb +29 -29
  52. data/test/cases/attribute_methods_test.rb +952 -952
  53. data/test/cases/attribute_set_test.rb +210 -200
  54. data/test/cases/attribute_test.rb +180 -180
  55. data/test/cases/attributes_test.rb +136 -136
  56. data/test/cases/autosave_association_test.rb +1595 -1595
  57. data/test/cases/base_test.rb +1664 -1638
  58. data/test/cases/batches_test.rb +212 -212
  59. data/test/cases/binary_test.rb +52 -52
  60. data/test/cases/bind_parameter_test.rb +100 -100
  61. data/test/cases/calculations_test.rb +646 -646
  62. data/test/cases/callbacks_test.rb +543 -543
  63. data/test/cases/clone_test.rb +40 -40
  64. data/test/cases/coders/yaml_column_test.rb +63 -63
  65. data/test/cases/column_alias_test.rb +17 -17
  66. data/test/cases/column_definition_test.rb +123 -123
  67. data/test/cases/connection_adapters/adapter_leasing_test.rb +54 -54
  68. data/test/cases/connection_adapters/connection_handler_test.rb +53 -53
  69. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  70. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +293 -293
  71. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +65 -65
  72. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  73. data/test/cases/connection_adapters/schema_cache_test.rb +56 -56
  74. data/test/cases/connection_adapters/type_lookup_test.rb +110 -110
  75. data/test/cases/connection_management_test.rb +122 -122
  76. data/test/cases/connection_pool_test.rb +346 -346
  77. data/test/cases/connection_specification/resolver_test.rb +116 -116
  78. data/test/cases/core_test.rb +112 -112
  79. data/test/cases/counter_cache_test.rb +209 -209
  80. data/test/cases/custom_locking_test.rb +17 -17
  81. data/test/cases/database_statements_test.rb +19 -19
  82. data/test/cases/date_time_test.rb +61 -61
  83. data/test/cases/defaults_test.rb +223 -223
  84. data/test/cases/dirty_test.rb +785 -775
  85. data/test/cases/disconnected_test.rb +28 -28
  86. data/test/cases/dup_test.rb +157 -157
  87. data/test/cases/enum_test.rb +290 -290
  88. data/test/cases/explain_subscriber_test.rb +64 -64
  89. data/test/cases/explain_test.rb +76 -76
  90. data/test/cases/finder_respond_to_test.rb +60 -60
  91. data/test/cases/finder_test.rb +1169 -1166
  92. data/test/cases/fixture_set/file_test.rb +138 -138
  93. data/test/cases/fixtures_test.rb +908 -897
  94. data/test/cases/forbidden_attributes_protection_test.rb +99 -99
  95. data/test/cases/habtm_destroy_order_test.rb +61 -61
  96. data/test/cases/helper.rb +210 -210
  97. data/test/cases/hot_compatibility_test.rb +54 -54
  98. data/test/cases/i18n_test.rb +45 -45
  99. data/test/cases/inheritance_test.rb +375 -375
  100. data/test/cases/integration_test.rb +139 -139
  101. data/test/cases/invalid_connection_test.rb +22 -22
  102. data/test/cases/invalid_date_test.rb +32 -32
  103. data/test/cases/invertible_migration_test.rb +295 -295
  104. data/test/cases/json_serialization_test.rb +302 -302
  105. data/test/cases/locking_test.rb +477 -477
  106. data/test/cases/log_subscriber_test.rb +136 -136
  107. data/test/cases/migration/change_schema_test - Copy.rb +448 -448
  108. data/test/cases/migration/change_schema_test.rb +512 -472
  109. data/test/cases/migration/change_table_test.rb +224 -224
  110. data/test/cases/migration/column_attributes_test.rb +192 -192
  111. data/test/cases/migration/column_positioning_test.rb +56 -56
  112. data/test/cases/migration/columns_test.rb +304 -304
  113. data/test/cases/migration/command_recorder_test.rb +305 -305
  114. data/test/cases/migration/create_join_table_test.rb +148 -148
  115. data/test/cases/migration/foreign_key_test - Changed.rb +325 -325
  116. data/test/cases/migration/foreign_key_test.rb +328 -360
  117. data/test/cases/migration/helper.rb +39 -39
  118. data/test/cases/migration/index_test.rb +216 -216
  119. data/test/cases/migration/logger_test.rb +36 -36
  120. data/test/cases/migration/pending_migrations_test.rb +53 -53
  121. data/test/cases/migration/references_foreign_key_test.rb +169 -214
  122. data/test/cases/migration/references_index_test.rb +101 -101
  123. data/test/cases/migration/references_statements_test.rb +116 -116
  124. data/test/cases/migration/rename_table_test.rb +93 -93
  125. data/test/cases/migration/table_and_index_test.rb +24 -24
  126. data/test/cases/migration_test.rb +959 -959
  127. data/test/cases/migrator_test.rb +388 -388
  128. data/test/cases/mixin_test.rb +70 -70
  129. data/test/cases/modules_test.rb +173 -173
  130. data/test/cases/multiparameter_attributes_test.rb +350 -350
  131. data/test/cases/multiple_db_test.rb +115 -115
  132. data/test/cases/nested_attributes_test.rb +1070 -1057
  133. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  134. data/test/cases/persistence_test.rb +909 -909
  135. data/test/cases/pooled_connections_test.rb +81 -81
  136. data/test/cases/primary_keys_test.rb +237 -237
  137. data/test/cases/query_cache_test.rb +326 -326
  138. data/test/cases/quoting_test.rb +156 -156
  139. data/test/cases/readonly_test.rb +118 -118
  140. data/test/cases/reaper_test.rb +85 -85
  141. data/test/cases/reflection_test.rb +463 -454
  142. data/test/cases/relation/delegation_test.rb +68 -68
  143. data/test/cases/relation/merging_test.rb +161 -161
  144. data/test/cases/relation/mutation_test.rb +165 -165
  145. data/test/cases/relation/predicate_builder_test.rb +14 -14
  146. data/test/cases/relation/where_chain_test.rb +181 -181
  147. data/test/cases/relation/where_test.rb +300 -300
  148. data/test/cases/relation/where_test2.rb +36 -36
  149. data/test/cases/relation_test.rb +319 -297
  150. data/test/cases/relations_test.rb +1815 -1815
  151. data/test/cases/reload_models_test.rb +22 -22
  152. data/test/cases/result_test.rb +80 -80
  153. data/test/cases/sanitize_test.rb +83 -83
  154. data/test/cases/schema_dumper_test.rb +463 -463
  155. data/test/cases/scoping/default_scoping_test.rb +454 -454
  156. data/test/cases/scoping/named_scoping_test.rb +524 -524
  157. data/test/cases/scoping/relation_scoping_test.rb +357 -357
  158. data/test/cases/serialization_test.rb +104 -104
  159. data/test/cases/serialized_attribute_test.rb +277 -277
  160. data/test/cases/statement_cache_test.rb +98 -98
  161. data/test/cases/store_test.rb +194 -194
  162. data/test/cases/tasks/database_tasks_test.rb +398 -396
  163. data/test/cases/tasks/mysql_rake_test.rb +324 -311
  164. data/test/cases/tasks/postgresql_rake_test.rb +250 -245
  165. data/test/cases/tasks/sqlite_rake_test.rb +193 -193
  166. data/test/cases/test_case.rb +123 -123
  167. data/test/cases/timestamp_test.rb +467 -468
  168. data/test/cases/transaction_callbacks_test.rb +452 -452
  169. data/test/cases/transaction_isolation_test.rb +106 -106
  170. data/test/cases/transactions_test.rb +817 -817
  171. data/test/cases/type/decimal_test.rb +56 -51
  172. data/test/cases/type/integer_test.rb +121 -121
  173. data/test/cases/type/string_test.rb +36 -36
  174. data/test/cases/type/type_map_test.rb +177 -177
  175. data/test/cases/type/unsigned_integer_test.rb +18 -18
  176. data/test/cases/types_test.rb +141 -141
  177. data/test/cases/unconnected_test.rb +33 -33
  178. data/test/cases/validations/association_validation_test.rb +86 -86
  179. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  180. data/test/cases/validations/i18n_validation_test.rb +90 -90
  181. data/test/cases/validations/length_validation_test.rb +47 -47
  182. data/test/cases/validations/presence_validation_test.rb +68 -68
  183. data/test/cases/validations/uniqueness_validation_test.rb +457 -434
  184. data/test/cases/validations_repair_helper.rb +23 -23
  185. data/test/cases/validations_test.rb +165 -165
  186. data/test/cases/view_test.rb +119 -113
  187. data/test/cases/xml_serialization_test.rb +457 -457
  188. data/test/cases/yaml_serialization_test.rb +126 -86
  189. data/test/config.rb +5 -5
  190. data/test/config.yml +154 -154
  191. data/test/connections/native_ibm_db/connection.rb +43 -43
  192. data/test/fixtures/accounts.yml +29 -29
  193. data/test/fixtures/admin/accounts.yml +2 -2
  194. data/test/fixtures/admin/randomly_named_a9.yml +7 -7
  195. data/test/fixtures/admin/randomly_named_b0.yml +7 -7
  196. data/test/fixtures/admin/users.yml +10 -10
  197. data/test/fixtures/author_addresses.yml +17 -17
  198. data/test/fixtures/author_favorites.yml +3 -3
  199. data/test/fixtures/authors.yml +23 -23
  200. data/test/fixtures/binaries.yml +133 -133
  201. data/test/fixtures/books.yml +11 -11
  202. data/test/fixtures/bulbs.yml +5 -5
  203. data/test/fixtures/cars.yml +9 -9
  204. data/test/fixtures/categories.yml +19 -19
  205. data/test/fixtures/categories/special_categories.yml +9 -9
  206. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  207. data/test/fixtures/categories_ordered.yml +7 -7
  208. data/test/fixtures/categories_posts.yml +31 -31
  209. data/test/fixtures/categorizations.yml +23 -23
  210. data/test/fixtures/clubs.yml +8 -8
  211. data/test/fixtures/collections.yml +3 -3
  212. data/test/fixtures/colleges.yml +3 -3
  213. data/test/fixtures/comments.yml +65 -65
  214. data/test/fixtures/companies.yml +67 -67
  215. data/test/fixtures/computers.yml +10 -10
  216. data/test/fixtures/courses.yml +8 -8
  217. data/test/fixtures/customers.yml +25 -25
  218. data/test/fixtures/dashboards.yml +6 -6
  219. data/test/fixtures/developers.yml +21 -21
  220. data/test/fixtures/developers_projects.yml +16 -16
  221. data/test/fixtures/dog_lovers.yml +7 -7
  222. data/test/fixtures/dogs.yml +4 -4
  223. data/test/fixtures/doubloons.yml +3 -3
  224. data/test/fixtures/edges.yml +5 -5
  225. data/test/fixtures/entrants.yml +14 -14
  226. data/test/fixtures/essays.yml +6 -6
  227. data/test/fixtures/faces.yml +11 -11
  228. data/test/fixtures/fk_test_has_fk.yml +3 -3
  229. data/test/fixtures/fk_test_has_pk.yml +1 -1
  230. data/test/fixtures/friendships.yml +4 -4
  231. data/test/fixtures/funny_jokes.yml +10 -10
  232. data/test/fixtures/interests.yml +33 -33
  233. data/test/fixtures/items.yml +3 -3
  234. data/test/fixtures/jobs.yml +7 -7
  235. data/test/fixtures/legacy_things.yml +3 -3
  236. data/test/fixtures/mateys.yml +4 -4
  237. data/test/fixtures/member_details.yml +8 -8
  238. data/test/fixtures/member_types.yml +6 -6
  239. data/test/fixtures/members.yml +11 -11
  240. data/test/fixtures/memberships.yml +34 -34
  241. data/test/fixtures/men.yml +5 -5
  242. data/test/fixtures/minimalistics.yml +2 -2
  243. data/test/fixtures/minivans.yml +5 -5
  244. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  245. data/test/fixtures/mixins.yml +29 -29
  246. data/test/fixtures/movies.yml +7 -7
  247. data/test/fixtures/naked/csv/accounts.csv +1 -1
  248. data/test/fixtures/naked/yml/accounts.yml +1 -1
  249. data/test/fixtures/naked/yml/companies.yml +1 -1
  250. data/test/fixtures/naked/yml/courses.yml +1 -1
  251. data/test/fixtures/organizations.yml +5 -5
  252. data/test/fixtures/other_topics.yml +42 -42
  253. data/test/fixtures/owners.yml +9 -9
  254. data/test/fixtures/parrots.yml +27 -27
  255. data/test/fixtures/parrots_pirates.yml +7 -7
  256. data/test/fixtures/people.yml +24 -24
  257. data/test/fixtures/peoples_treasures.yml +3 -3
  258. data/test/fixtures/pets.yml +19 -19
  259. data/test/fixtures/pirates.yml +12 -12
  260. data/test/fixtures/posts.yml +80 -80
  261. data/test/fixtures/price_estimates.yml +7 -7
  262. data/test/fixtures/products.yml +4 -4
  263. data/test/fixtures/projects.yml +7 -7
  264. data/test/fixtures/randomly_named_a9.yml +7 -7
  265. data/test/fixtures/ratings.yml +14 -14
  266. data/test/fixtures/readers.yml +11 -11
  267. data/test/fixtures/references.yml +17 -17
  268. data/test/fixtures/reserved_words/distinct.yml +5 -5
  269. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  270. data/test/fixtures/reserved_words/group.yml +14 -14
  271. data/test/fixtures/reserved_words/select.yml +8 -8
  272. data/test/fixtures/reserved_words/values.yml +7 -7
  273. data/test/fixtures/ships.yml +6 -6
  274. data/test/fixtures/speedometers.yml +8 -8
  275. data/test/fixtures/sponsors.yml +12 -12
  276. data/test/fixtures/string_key_objects.yml +7 -7
  277. data/test/fixtures/subscribers.yml +10 -10
  278. data/test/fixtures/subscriptions.yml +12 -12
  279. data/test/fixtures/taggings.yml +78 -78
  280. data/test/fixtures/tags.yml +11 -11
  281. data/test/fixtures/tasks.yml +7 -7
  282. data/test/fixtures/teapots.yml +3 -3
  283. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  284. data/test/fixtures/to_be_linked/users.yml +10 -10
  285. data/test/fixtures/topics.yml +49 -49
  286. data/test/fixtures/toys.yml +14 -14
  287. data/test/fixtures/traffic_lights.yml +9 -9
  288. data/test/fixtures/treasures.yml +10 -10
  289. data/test/fixtures/uuid_children.yml +3 -3
  290. data/test/fixtures/uuid_parents.yml +2 -2
  291. data/test/fixtures/variants.yml +4 -4
  292. data/test/fixtures/vegetables.yml +19 -19
  293. data/test/fixtures/vertices.yml +3 -3
  294. data/test/fixtures/warehouse_things.yml +2 -2
  295. data/test/fixtures/zines.yml +5 -5
  296. data/test/ibm_db_test.rb +24 -24
  297. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  298. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  299. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  300. data/test/migrations/missing/1000_people_have_middle_names.rb +8 -8
  301. data/test/migrations/missing/1_people_have_last_names.rb +8 -8
  302. data/test/migrations/missing/3_we_need_reminders.rb +11 -11
  303. data/test/migrations/missing/4_innocent_jointable.rb +11 -11
  304. data/test/migrations/rename/1_we_need_things.rb +10 -10
  305. data/test/migrations/rename/2_rename_things.rb +8 -8
  306. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  307. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  308. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  309. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  310. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  311. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  312. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  313. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  314. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  315. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  316. data/test/migrations/valid/2_we_need_reminders.rb +11 -11
  317. data/test/migrations/valid/3_innocent_jointable.rb +11 -11
  318. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  319. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +11 -11
  320. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +11 -11
  321. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  322. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  323. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  324. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  325. data/test/models/admin.rb +4 -4
  326. data/test/models/admin/account.rb +2 -2
  327. data/test/models/admin/randomly_named_c1.rb +3 -3
  328. data/test/models/admin/user.rb +40 -40
  329. data/test/models/aircraft.rb +4 -4
  330. data/test/models/arunit2_model.rb +3 -3
  331. data/test/models/author.rb +212 -212
  332. data/test/models/auto_id.rb +4 -4
  333. data/test/models/autoloadable/extra_firm.rb +2 -2
  334. data/test/models/binary.rb +1 -1
  335. data/test/models/bird.rb +12 -12
  336. data/test/models/book.rb +18 -18
  337. data/test/models/boolean.rb +2 -2
  338. data/test/models/bulb.rb +51 -51
  339. data/test/models/cake_designer.rb +3 -3
  340. data/test/models/car.rb +26 -26
  341. data/test/models/carrier.rb +2 -2
  342. data/test/models/categorization.rb +19 -19
  343. data/test/models/category.rb +35 -35
  344. data/test/models/chef.rb +7 -3
  345. data/test/models/citation.rb +3 -3
  346. data/test/models/club.rb +23 -23
  347. data/test/models/college.rb +10 -10
  348. data/test/models/column.rb +3 -3
  349. data/test/models/column_name.rb +3 -3
  350. data/test/models/comment.rb +64 -64
  351. data/test/models/company.rb +228 -225
  352. data/test/models/company_in_module.rb +98 -98
  353. data/test/models/computer.rb +3 -3
  354. data/test/models/contact.rb +41 -41
  355. data/test/models/contract.rb +20 -20
  356. data/test/models/country.rb +7 -7
  357. data/test/models/course.rb +6 -6
  358. data/test/models/customer.rb +77 -77
  359. data/test/models/customer_carrier.rb +14 -14
  360. data/test/models/dashboard.rb +3 -3
  361. data/test/models/default.rb +2 -2
  362. data/test/models/department.rb +4 -4
  363. data/test/models/developer.rb +255 -252
  364. data/test/models/dog.rb +5 -5
  365. data/test/models/dog_lover.rb +5 -5
  366. data/test/models/doubloon.rb +12 -12
  367. data/test/models/drink_designer.rb +3 -3
  368. data/test/models/edge.rb +5 -5
  369. data/test/models/electron.rb +5 -5
  370. data/test/models/engine.rb +4 -4
  371. data/test/models/entrant.rb +3 -3
  372. data/test/models/essay.rb +5 -5
  373. data/test/models/event.rb +2 -2
  374. data/test/models/eye.rb +37 -37
  375. data/test/models/face.rb +9 -9
  376. data/test/models/friendship.rb +6 -6
  377. data/test/models/guid.rb +1 -1
  378. data/test/models/hotel.rb +9 -6
  379. data/test/models/image.rb +3 -3
  380. data/test/models/interest.rb +5 -5
  381. data/test/models/invoice.rb +4 -4
  382. data/test/models/item.rb +7 -7
  383. data/test/models/job.rb +7 -7
  384. data/test/models/joke.rb +7 -7
  385. data/test/models/keyboard.rb +3 -3
  386. data/test/models/legacy_thing.rb +3 -3
  387. data/test/models/lesson.rb +11 -11
  388. data/test/models/line_item.rb +3 -3
  389. data/test/models/liquid.rb +4 -4
  390. data/test/models/man.rb +11 -11
  391. data/test/models/matey.rb +4 -4
  392. data/test/models/member.rb +41 -41
  393. data/test/models/member_detail.rb +7 -7
  394. data/test/models/member_type.rb +3 -3
  395. data/test/models/membership.rb +35 -35
  396. data/test/models/minimalistic.rb +2 -2
  397. data/test/models/minivan.rb +9 -9
  398. data/test/models/mixed_case_monkey.rb +3 -3
  399. data/test/models/molecule.rb +6 -6
  400. data/test/models/movie.rb +5 -5
  401. data/test/models/order.rb +4 -4
  402. data/test/models/organization.rb +14 -14
  403. data/test/models/owner.rb +34 -34
  404. data/test/models/parrot.rb +29 -29
  405. data/test/models/person.rb +143 -143
  406. data/test/models/personal_legacy_thing.rb +4 -4
  407. data/test/models/pet.rb +15 -15
  408. data/test/models/pirate.rb +92 -92
  409. data/test/models/possession.rb +3 -3
  410. data/test/models/post.rb +264 -264
  411. data/test/models/price_estimate.rb +4 -4
  412. data/test/models/professor.rb +5 -5
  413. data/test/models/project.rb +31 -29
  414. data/test/models/publisher.rb +2 -2
  415. data/test/models/publisher/article.rb +4 -4
  416. data/test/models/publisher/magazine.rb +3 -3
  417. data/test/models/randomly_named_c1.rb +3 -3
  418. data/test/models/rating.rb +4 -4
  419. data/test/models/reader.rb +23 -23
  420. data/test/models/record.rb +2 -2
  421. data/test/models/reference.rb +22 -22
  422. data/test/models/reply.rb +61 -61
  423. data/test/models/ship.rb +33 -33
  424. data/test/models/ship_part.rb +7 -7
  425. data/test/models/shop.rb +17 -17
  426. data/test/models/shop_account.rb +6 -6
  427. data/test/models/speedometer.rb +6 -6
  428. data/test/models/sponsor.rb +7 -7
  429. data/test/models/string_key_object.rb +3 -3
  430. data/test/models/student.rb +4 -4
  431. data/test/models/subject.rb +16 -16
  432. data/test/models/subscriber.rb +8 -8
  433. data/test/models/subscription.rb +4 -4
  434. data/test/models/tag.rb +7 -7
  435. data/test/models/tagging.rb +13 -13
  436. data/test/models/task.rb +5 -5
  437. data/test/models/topic.rb +124 -124
  438. data/test/models/toy.rb +6 -6
  439. data/test/models/traffic_light.rb +4 -4
  440. data/test/models/treasure.rb +14 -14
  441. data/test/models/treaty.rb +7 -7
  442. data/test/models/tyre.rb +11 -11
  443. data/test/models/uuid_child.rb +3 -3
  444. data/test/models/uuid_parent.rb +3 -3
  445. data/test/models/vegetables.rb +24 -24
  446. data/test/models/vehicle.rb +6 -6
  447. data/test/models/vertex.rb +9 -9
  448. data/test/models/warehouse_thing.rb +5 -5
  449. data/test/models/wheel.rb +3 -3
  450. data/test/models/without_table.rb +3 -3
  451. data/test/models/zine.rb +3 -3
  452. data/test/schema/mysql2_specific_schema.rb +58 -58
  453. data/test/schema/mysql_specific_schema.rb +70 -70
  454. data/test/schema/oracle_specific_schema.rb +43 -43
  455. data/test/schema/postgresql_specific_schema.rb +202 -202
  456. data/test/schema/schema.rb +952 -938
  457. data/test/schema/sqlite_specific_schema.rb +21 -21
  458. data/test/support/config.rb +43 -43
  459. data/test/support/connection.rb +22 -22
  460. data/test/support/connection_helper.rb +14 -14
  461. data/test/support/ddl_helper.rb +8 -8
  462. data/test/support/schema_dumping_helper.rb +20 -20
  463. metadata +2 -2
@@ -1,477 +1,477 @@
1
- require 'thread'
2
- require "cases/helper"
3
- require 'models/person'
4
- require 'models/job'
5
- require 'models/reader'
6
- require 'models/ship'
7
- require 'models/legacy_thing'
8
- require 'models/personal_legacy_thing'
9
- require 'models/reference'
10
- require 'models/string_key_object'
11
- require 'models/car'
12
- require 'models/bulb'
13
- require 'models/engine'
14
- require 'models/wheel'
15
- require 'models/treasure'
16
-
17
- class LockWithoutDefault < ActiveRecord::Base; end
18
-
19
- class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
20
- self.table_name = :lock_without_defaults_cust
21
- self.column_defaults # to test @column_defaults caching.
22
- self.locking_column = :custom_lock_version
23
- end
24
-
25
- class ReadonlyNameShip < Ship
26
- attr_readonly :name
27
- end
28
-
29
- class OptimisticLockingTest < ActiveRecord::TestCase
30
- fixtures :people, :legacy_things, :references, :string_key_objects, :peoples_treasures
31
-
32
- def test_lock_version_is_incremented
33
- p1 = Person.find(1)
34
- assert_equal 0, p1.lock_version
35
-
36
- p1.first_name = 'anika2'
37
- p1.save!
38
-
39
- assert_equal 1, p1.lock_version
40
- end
41
-
42
- def test_non_integer_lock_existing
43
- s1 = StringKeyObject.find("record1")
44
- s2 = StringKeyObject.find("record1")
45
- assert_equal 0, s1.lock_version
46
- assert_equal 0, s2.lock_version
47
-
48
- s1.name = 'updated record'
49
- s1.save!
50
- assert_equal 1, s1.lock_version
51
- assert_equal 0, s2.lock_version
52
-
53
- s2.name = 'doubly updated record'
54
- assert_raise(ActiveRecord::StaleObjectError) { s2.save! }
55
- end
56
-
57
- def test_non_integer_lock_destroy
58
- s1 = StringKeyObject.find("record1")
59
- s2 = StringKeyObject.find("record1")
60
- assert_equal 0, s1.lock_version
61
- assert_equal 0, s2.lock_version
62
-
63
- s1.name = 'updated record'
64
- s1.save!
65
- assert_equal 1, s1.lock_version
66
- assert_equal 0, s2.lock_version
67
- assert_raise(ActiveRecord::StaleObjectError) { s2.destroy }
68
-
69
- assert s1.destroy
70
- assert s1.frozen?
71
- assert s1.destroyed?
72
- assert_raises(ActiveRecord::RecordNotFound) { StringKeyObject.find("record1") }
73
- end
74
-
75
- def test_lock_existing
76
- p1 = Person.find(1)
77
- p2 = Person.find(1)
78
- assert_equal 0, p1.lock_version
79
- assert_equal 0, p2.lock_version
80
-
81
- p1.first_name = 'stu'
82
- p1.save!
83
- assert_equal 1, p1.lock_version
84
- assert_equal 0, p2.lock_version
85
-
86
- p2.first_name = 'sue'
87
- assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
88
- end
89
-
90
- # See Lighthouse ticket #1966
91
- def test_lock_destroy
92
- p1 = Person.find(1)
93
- p2 = Person.find(1)
94
- assert_equal 0, p1.lock_version
95
- assert_equal 0, p2.lock_version
96
-
97
- p1.first_name = 'stu'
98
- p1.save!
99
- assert_equal 1, p1.lock_version
100
- assert_equal 0, p2.lock_version
101
-
102
- assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
103
-
104
- assert p1.destroy
105
- assert p1.frozen?
106
- assert p1.destroyed?
107
- assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
108
- end
109
-
110
- def test_lock_repeating
111
- p1 = Person.find(1)
112
- p2 = Person.find(1)
113
- assert_equal 0, p1.lock_version
114
- assert_equal 0, p2.lock_version
115
-
116
- p1.first_name = 'stu'
117
- p1.save!
118
- assert_equal 1, p1.lock_version
119
- assert_equal 0, p2.lock_version
120
-
121
- p2.first_name = 'sue'
122
- assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
123
- p2.first_name = 'sue2'
124
- assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
125
- end
126
-
127
- def test_lock_new
128
- p1 = Person.new(:first_name => 'anika')
129
- assert_equal 0, p1.lock_version
130
-
131
- p1.first_name = 'anika2'
132
- p1.save!
133
- p2 = Person.find(p1.id)
134
- assert_equal 0, p1.lock_version
135
- assert_equal 0, p2.lock_version
136
-
137
- p1.first_name = 'anika3'
138
- p1.save!
139
- assert_equal 1, p1.lock_version
140
- assert_equal 0, p2.lock_version
141
-
142
- p2.first_name = 'sue'
143
- assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
144
- end
145
-
146
- def test_lock_exception_record
147
- p1 = Person.new(:first_name => 'mira')
148
- assert_equal 0, p1.lock_version
149
-
150
- p1.first_name = 'mira2'
151
- p1.save!
152
- p2 = Person.find(p1.id)
153
- assert_equal 0, p1.lock_version
154
- assert_equal 0, p2.lock_version
155
-
156
- p1.first_name = 'mira3'
157
- p1.save!
158
-
159
- p2.first_name = 'sue'
160
- error = assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
161
- assert_equal(error.record.object_id, p2.object_id)
162
- end
163
-
164
- def test_lock_new_with_nil
165
- p1 = Person.new(:first_name => 'anika')
166
- p1.save!
167
- p1.lock_version = nil # simulate bad fixture or column with no default
168
- p1.save!
169
- assert_equal 1, p1.lock_version
170
- end
171
-
172
- def test_touch_existing_lock
173
- p1 = Person.find(1)
174
- assert_equal 0, p1.lock_version
175
-
176
- p1.touch
177
- assert_equal 1, p1.lock_version
178
- end
179
-
180
- def test_lock_column_name_existing
181
- t1 = LegacyThing.find(1)
182
- t2 = LegacyThing.find(1)
183
- assert_equal 0, t1.version
184
- assert_equal 0, t2.version
185
-
186
- t1.tps_report_number = 700
187
- t1.save!
188
- assert_equal 1, t1.version
189
- assert_equal 0, t2.version
190
-
191
- t2.tps_report_number = 800
192
- assert_raise(ActiveRecord::StaleObjectError) { t2.save! }
193
- end
194
-
195
- def test_lock_column_is_mass_assignable
196
- p1 = Person.create(:first_name => 'bianca')
197
- assert_equal 0, p1.lock_version
198
- assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
199
-
200
- p1.first_name = 'bianca2'
201
- p1.save!
202
- assert_equal 1, p1.lock_version
203
- assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
204
- end
205
-
206
- def test_lock_without_default_sets_version_to_zero
207
- t1 = LockWithoutDefault.new
208
- assert_equal 0, t1.lock_version
209
-
210
- t1.save
211
- t1 = LockWithoutDefault.find(t1.id)
212
- assert_equal 0, t1.lock_version
213
- end
214
-
215
- def test_lock_with_custom_column_without_default_sets_version_to_zero
216
- t1 = LockWithCustomColumnWithoutDefault.new
217
- assert_equal 0, t1.custom_lock_version
218
- assert_nil t1.custom_lock_version_before_type_cast
219
-
220
- t1.save!
221
- t1.reload
222
- assert_equal 0, t1.custom_lock_version
223
- assert [0, "0"].include?(t1.custom_lock_version_before_type_cast)
224
- end
225
-
226
- def test_readonly_attributes
227
- assert_equal Set.new([ 'name' ]), ReadonlyNameShip.readonly_attributes
228
-
229
- s = ReadonlyNameShip.create(:name => "unchangeable name")
230
- s.reload
231
- assert_equal "unchangeable name", s.name
232
-
233
- s.update(name: "changed name")
234
- s.reload
235
- assert_equal "unchangeable name", s.name
236
- end
237
-
238
- def test_quote_table_name
239
- ref = references(:michael_magician)
240
- ref.favourite = !ref.favourite
241
- assert ref.save
242
- end
243
-
244
- # Useful for partial updates, don't only update the lock_version if there
245
- # is nothing else being updated.
246
- def test_update_without_attributes_does_not_only_update_lock_version
247
- assert_nothing_raised do
248
- p1 = Person.create!(:first_name => 'anika')
249
- lock_version = p1.lock_version
250
- p1.save
251
- p1.reload
252
- assert_equal lock_version, p1.lock_version
253
- end
254
- end
255
-
256
- def test_polymorphic_destroy_with_dependencies_and_lock_version
257
- car = Car.create!
258
-
259
- assert_difference 'car.wheels.count' do
260
- car.wheels << Wheel.create!
261
- end
262
- assert_difference 'car.wheels.count', -1 do
263
- car.destroy
264
- end
265
- assert car.destroyed?
266
- end
267
-
268
- def test_removing_has_and_belongs_to_many_associations_upon_destroy
269
- p = RichPerson.create! first_name: 'Jon'
270
- p.treasures.create!
271
- assert !p.treasures.empty?
272
- p.destroy
273
- assert p.treasures.empty?
274
- assert RichPerson.connection.select_all("SELECT * FROM peoples_treasures WHERE rich_person_id = 1").empty?
275
- end
276
-
277
- def test_yaml_dumping_with_lock_column
278
- t1 = LockWithoutDefault.new
279
- t2 = YAML.load(YAML.dump(t1))
280
-
281
- assert_equal t1.attributes, t2.attributes
282
- end
283
- end
284
-
285
- class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
286
- fixtures :people, :legacy_things, :references
287
-
288
- # need to disable transactional fixtures, because otherwise the sqlite3
289
- # adapter (at least) chokes when we try and change the schema in the middle
290
- # of a test (see test_increment_counter_*).
291
- self.use_transactional_fixtures = false
292
-
293
- { :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
294
- define_method("test_increment_counter_updates_#{name}") do
295
- counter_test model, 1 do |id|
296
- model.increment_counter :test_count, id
297
- end
298
- end
299
-
300
- define_method("test_decrement_counter_updates_#{name}") do
301
- counter_test model, -1 do |id|
302
- model.decrement_counter :test_count, id
303
- end
304
- end
305
-
306
- define_method("test_update_counters_updates_#{name}") do
307
- counter_test model, 1 do |id|
308
- model.update_counters id, :test_count => 1
309
- end
310
- end
311
- end
312
-
313
- # See Lighthouse ticket #1966
314
- def test_destroy_dependents
315
- # Establish dependent relationship between Person and PersonalLegacyThing
316
- add_counter_column_to(Person, 'personal_legacy_things_count')
317
- PersonalLegacyThing.reset_column_information
318
-
319
- # Make sure that counter incrementing doesn't cause problems
320
- p1 = Person.new(:first_name => 'fjord')
321
- p1.save!
322
- t = PersonalLegacyThing.new(:person => p1)
323
- t.save!
324
- p1.reload
325
- assert_equal 1, p1.personal_legacy_things_count
326
- assert p1.destroy
327
- assert_equal true, p1.frozen?
328
- assert_raises(ActiveRecord::RecordNotFound) { Person.find(p1.id) }
329
- assert_raises(ActiveRecord::RecordNotFound) { PersonalLegacyThing.find(t.id) }
330
- ensure
331
- remove_counter_column_from(Person, 'personal_legacy_things_count')
332
- PersonalLegacyThing.reset_column_information
333
- end
334
-
335
- private
336
-
337
- def add_counter_column_to(model, col='test_count')
338
- model.connection.add_column model.table_name, col, :integer, :null => false, :default => 0
339
- model.reset_column_information
340
- end
341
-
342
- def remove_counter_column_from(model, col = :test_count)
343
- model.connection.remove_column model.table_name, col
344
- model.reset_column_information
345
- end
346
-
347
- def counter_test(model, expected_count)
348
- add_counter_column_to(model)
349
- object = model.first
350
- assert_equal 0, object.test_count
351
- assert_equal 0, object.send(model.locking_column)
352
- yield object.id
353
- object.reload
354
- assert_equal expected_count, object.test_count
355
- assert_equal 1, object.send(model.locking_column)
356
- ensure
357
- remove_counter_column_from(model)
358
- end
359
- end
360
-
361
-
362
- # TODO: test against the generated SQL since testing locking behavior itself
363
- # is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
364
- # blocks, so separate script called by Kernel#system is needed.
365
- # (See exec vs. async_exec in the PostgreSQL adapter.)
366
- unless in_memory_db?
367
- class PessimisticLockingTest < ActiveRecord::TestCase
368
- self.use_transactional_fixtures = false
369
- fixtures :people, :readers
370
-
371
- def setup
372
- Person.connection_pool.clear_reloadable_connections!
373
- # Avoid introspection queries during tests.
374
- Person.columns; Reader.columns
375
- end
376
-
377
- # Test typical find.
378
- def test_sane_find_with_lock
379
- assert_nothing_raised do
380
- Person.transaction do
381
- Person.lock.find(1)
382
- end
383
- end
384
- end
385
-
386
- # PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
387
- unless current_adapter?(:PostgreSQLAdapter)
388
- # Test locked eager find.
389
- def test_eager_find_with_lock
390
- assert_nothing_raised do
391
- Person.transaction do
392
- Person.includes(:readers).lock.find(1)
393
- end
394
- end
395
- end
396
- end
397
-
398
- # Locking a record reloads it.
399
- def test_sane_lock_method
400
- assert_nothing_raised do
401
- Person.transaction do
402
- person = Person.find 1
403
- old, person.first_name = person.first_name, 'fooman'
404
- person.lock!
405
- assert_equal old, person.first_name
406
- end
407
- end
408
- end
409
-
410
- def test_with_lock_commits_transaction
411
- person = Person.find 1
412
- person.with_lock do
413
- person.first_name = 'fooman'
414
- person.save!
415
- end
416
- assert_equal 'fooman', person.reload.first_name
417
- end
418
-
419
- def test_with_lock_rolls_back_transaction
420
- person = Person.find 1
421
- old = person.first_name
422
- person.with_lock do
423
- person.first_name = 'fooman'
424
- person.save!
425
- raise 'oops'
426
- end rescue nil
427
- assert_equal old, person.reload.first_name
428
- end
429
-
430
- if current_adapter?(:PostgreSQLAdapter)
431
- def test_lock_sending_custom_lock_statement
432
- Person.transaction do
433
- person = Person.find(1)
434
- assert_sql(/LIMIT 1 FOR SHARE NOWAIT/) do
435
- person.lock!('FOR SHARE NOWAIT')
436
- end
437
- end
438
- end
439
- end
440
-
441
- if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
442
- def test_no_locks_no_wait
443
- first, second = duel { Person.find 1 }
444
- assert first.end > second.end
445
- end
446
-
447
- protected
448
- def duel(zzz = 5)
449
- t0, t1, t2, t3 = nil, nil, nil, nil
450
-
451
- a = Thread.new do
452
- t0 = Time.now
453
- Person.transaction do
454
- yield
455
- sleep zzz # block thread 2 for zzz seconds
456
- end
457
- t1 = Time.now
458
- end
459
-
460
- b = Thread.new do
461
- sleep zzz / 2.0 # ensure thread 1 tx starts first
462
- t2 = Time.now
463
- Person.transaction { yield }
464
- t3 = Time.now
465
- end
466
-
467
- a.join
468
- b.join
469
-
470
- assert t1 > t0 + zzz
471
- assert t2 > t0
472
- assert t3 > t2
473
- [t0.to_f..t1.to_f, t2.to_f..t3.to_f]
474
- end
475
- end
476
- end
477
- end
1
+ require 'thread'
2
+ require "cases/helper"
3
+ require 'models/person'
4
+ require 'models/job'
5
+ require 'models/reader'
6
+ require 'models/ship'
7
+ require 'models/legacy_thing'
8
+ require 'models/personal_legacy_thing'
9
+ require 'models/reference'
10
+ require 'models/string_key_object'
11
+ require 'models/car'
12
+ require 'models/bulb'
13
+ require 'models/engine'
14
+ require 'models/wheel'
15
+ require 'models/treasure'
16
+
17
+ class LockWithoutDefault < ActiveRecord::Base; end
18
+
19
+ class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
20
+ self.table_name = :lock_without_defaults_cust
21
+ self.column_defaults # to test @column_defaults caching.
22
+ self.locking_column = :custom_lock_version
23
+ end
24
+
25
+ class ReadonlyNameShip < Ship
26
+ attr_readonly :name
27
+ end
28
+
29
+ class OptimisticLockingTest < ActiveRecord::TestCase
30
+ fixtures :people, :legacy_things, :references, :string_key_objects, :peoples_treasures
31
+
32
+ def test_lock_version_is_incremented
33
+ p1 = Person.find(1)
34
+ assert_equal 0, p1.lock_version
35
+
36
+ p1.first_name = 'anika2'
37
+ p1.save!
38
+
39
+ assert_equal 1, p1.lock_version
40
+ end
41
+
42
+ def test_non_integer_lock_existing
43
+ s1 = StringKeyObject.find("record1")
44
+ s2 = StringKeyObject.find("record1")
45
+ assert_equal 0, s1.lock_version
46
+ assert_equal 0, s2.lock_version
47
+
48
+ s1.name = 'updated record'
49
+ s1.save!
50
+ assert_equal 1, s1.lock_version
51
+ assert_equal 0, s2.lock_version
52
+
53
+ s2.name = 'doubly updated record'
54
+ assert_raise(ActiveRecord::StaleObjectError) { s2.save! }
55
+ end
56
+
57
+ def test_non_integer_lock_destroy
58
+ s1 = StringKeyObject.find("record1")
59
+ s2 = StringKeyObject.find("record1")
60
+ assert_equal 0, s1.lock_version
61
+ assert_equal 0, s2.lock_version
62
+
63
+ s1.name = 'updated record'
64
+ s1.save!
65
+ assert_equal 1, s1.lock_version
66
+ assert_equal 0, s2.lock_version
67
+ assert_raise(ActiveRecord::StaleObjectError) { s2.destroy }
68
+
69
+ assert s1.destroy
70
+ assert s1.frozen?
71
+ assert s1.destroyed?
72
+ assert_raises(ActiveRecord::RecordNotFound) { StringKeyObject.find("record1") }
73
+ end
74
+
75
+ def test_lock_existing
76
+ p1 = Person.find(1)
77
+ p2 = Person.find(1)
78
+ assert_equal 0, p1.lock_version
79
+ assert_equal 0, p2.lock_version
80
+
81
+ p1.first_name = 'stu'
82
+ p1.save!
83
+ assert_equal 1, p1.lock_version
84
+ assert_equal 0, p2.lock_version
85
+
86
+ p2.first_name = 'sue'
87
+ assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
88
+ end
89
+
90
+ # See Lighthouse ticket #1966
91
+ def test_lock_destroy
92
+ p1 = Person.find(1)
93
+ p2 = Person.find(1)
94
+ assert_equal 0, p1.lock_version
95
+ assert_equal 0, p2.lock_version
96
+
97
+ p1.first_name = 'stu'
98
+ p1.save!
99
+ assert_equal 1, p1.lock_version
100
+ assert_equal 0, p2.lock_version
101
+
102
+ assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
103
+
104
+ assert p1.destroy
105
+ assert p1.frozen?
106
+ assert p1.destroyed?
107
+ assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
108
+ end
109
+
110
+ def test_lock_repeating
111
+ p1 = Person.find(1)
112
+ p2 = Person.find(1)
113
+ assert_equal 0, p1.lock_version
114
+ assert_equal 0, p2.lock_version
115
+
116
+ p1.first_name = 'stu'
117
+ p1.save!
118
+ assert_equal 1, p1.lock_version
119
+ assert_equal 0, p2.lock_version
120
+
121
+ p2.first_name = 'sue'
122
+ assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
123
+ p2.first_name = 'sue2'
124
+ assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
125
+ end
126
+
127
+ def test_lock_new
128
+ p1 = Person.new(:first_name => 'anika')
129
+ assert_equal 0, p1.lock_version
130
+
131
+ p1.first_name = 'anika2'
132
+ p1.save!
133
+ p2 = Person.find(p1.id)
134
+ assert_equal 0, p1.lock_version
135
+ assert_equal 0, p2.lock_version
136
+
137
+ p1.first_name = 'anika3'
138
+ p1.save!
139
+ assert_equal 1, p1.lock_version
140
+ assert_equal 0, p2.lock_version
141
+
142
+ p2.first_name = 'sue'
143
+ assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
144
+ end
145
+
146
+ def test_lock_exception_record
147
+ p1 = Person.new(:first_name => 'mira')
148
+ assert_equal 0, p1.lock_version
149
+
150
+ p1.first_name = 'mira2'
151
+ p1.save!
152
+ p2 = Person.find(p1.id)
153
+ assert_equal 0, p1.lock_version
154
+ assert_equal 0, p2.lock_version
155
+
156
+ p1.first_name = 'mira3'
157
+ p1.save!
158
+
159
+ p2.first_name = 'sue'
160
+ error = assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
161
+ assert_equal(error.record.object_id, p2.object_id)
162
+ end
163
+
164
+ def test_lock_new_with_nil
165
+ p1 = Person.new(:first_name => 'anika')
166
+ p1.save!
167
+ p1.lock_version = nil # simulate bad fixture or column with no default
168
+ p1.save!
169
+ assert_equal 1, p1.lock_version
170
+ end
171
+
172
+ def test_touch_existing_lock
173
+ p1 = Person.find(1)
174
+ assert_equal 0, p1.lock_version
175
+
176
+ p1.touch
177
+ assert_equal 1, p1.lock_version
178
+ end
179
+
180
+ def test_lock_column_name_existing
181
+ t1 = LegacyThing.find(1)
182
+ t2 = LegacyThing.find(1)
183
+ assert_equal 0, t1.version
184
+ assert_equal 0, t2.version
185
+
186
+ t1.tps_report_number = 700
187
+ t1.save!
188
+ assert_equal 1, t1.version
189
+ assert_equal 0, t2.version
190
+
191
+ t2.tps_report_number = 800
192
+ assert_raise(ActiveRecord::StaleObjectError) { t2.save! }
193
+ end
194
+
195
+ def test_lock_column_is_mass_assignable
196
+ p1 = Person.create(:first_name => 'bianca')
197
+ assert_equal 0, p1.lock_version
198
+ assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
199
+
200
+ p1.first_name = 'bianca2'
201
+ p1.save!
202
+ assert_equal 1, p1.lock_version
203
+ assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
204
+ end
205
+
206
+ def test_lock_without_default_sets_version_to_zero
207
+ t1 = LockWithoutDefault.new
208
+ assert_equal 0, t1.lock_version
209
+
210
+ t1.save
211
+ t1 = LockWithoutDefault.find(t1.id)
212
+ assert_equal 0, t1.lock_version
213
+ end
214
+
215
+ def test_lock_with_custom_column_without_default_sets_version_to_zero
216
+ t1 = LockWithCustomColumnWithoutDefault.new
217
+ assert_equal 0, t1.custom_lock_version
218
+ assert_nil t1.custom_lock_version_before_type_cast
219
+
220
+ t1.save!
221
+ t1.reload
222
+ assert_equal 0, t1.custom_lock_version
223
+ assert [0, "0"].include?(t1.custom_lock_version_before_type_cast)
224
+ end
225
+
226
+ def test_readonly_attributes
227
+ assert_equal Set.new([ 'name' ]), ReadonlyNameShip.readonly_attributes
228
+
229
+ s = ReadonlyNameShip.create(:name => "unchangeable name")
230
+ s.reload
231
+ assert_equal "unchangeable name", s.name
232
+
233
+ s.update(name: "changed name")
234
+ s.reload
235
+ assert_equal "unchangeable name", s.name
236
+ end
237
+
238
+ def test_quote_table_name
239
+ ref = references(:michael_magician)
240
+ ref.favourite = !ref.favourite
241
+ assert ref.save
242
+ end
243
+
244
+ # Useful for partial updates, don't only update the lock_version if there
245
+ # is nothing else being updated.
246
+ def test_update_without_attributes_does_not_only_update_lock_version
247
+ assert_nothing_raised do
248
+ p1 = Person.create!(:first_name => 'anika')
249
+ lock_version = p1.lock_version
250
+ p1.save
251
+ p1.reload
252
+ assert_equal lock_version, p1.lock_version
253
+ end
254
+ end
255
+
256
+ def test_polymorphic_destroy_with_dependencies_and_lock_version
257
+ car = Car.create!
258
+
259
+ assert_difference 'car.wheels.count' do
260
+ car.wheels << Wheel.create!
261
+ end
262
+ assert_difference 'car.wheels.count', -1 do
263
+ car.destroy
264
+ end
265
+ assert car.destroyed?
266
+ end
267
+
268
+ def test_removing_has_and_belongs_to_many_associations_upon_destroy
269
+ p = RichPerson.create! first_name: 'Jon'
270
+ p.treasures.create!
271
+ assert !p.treasures.empty?
272
+ p.destroy
273
+ assert p.treasures.empty?
274
+ assert RichPerson.connection.select_all("SELECT * FROM peoples_treasures WHERE rich_person_id = 1").empty?
275
+ end
276
+
277
+ def test_yaml_dumping_with_lock_column
278
+ t1 = LockWithoutDefault.new
279
+ t2 = YAML.load(YAML.dump(t1))
280
+
281
+ assert_equal t1.attributes, t2.attributes
282
+ end
283
+ end
284
+
285
+ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
286
+ fixtures :people, :legacy_things, :references
287
+
288
+ # need to disable transactional fixtures, because otherwise the sqlite3
289
+ # adapter (at least) chokes when we try and change the schema in the middle
290
+ # of a test (see test_increment_counter_*).
291
+ self.use_transactional_fixtures = false
292
+
293
+ { :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
294
+ define_method("test_increment_counter_updates_#{name}") do
295
+ counter_test model, 1 do |id|
296
+ model.increment_counter :test_count, id
297
+ end
298
+ end
299
+
300
+ define_method("test_decrement_counter_updates_#{name}") do
301
+ counter_test model, -1 do |id|
302
+ model.decrement_counter :test_count, id
303
+ end
304
+ end
305
+
306
+ define_method("test_update_counters_updates_#{name}") do
307
+ counter_test model, 1 do |id|
308
+ model.update_counters id, :test_count => 1
309
+ end
310
+ end
311
+ end
312
+
313
+ # See Lighthouse ticket #1966
314
+ def test_destroy_dependents
315
+ # Establish dependent relationship between Person and PersonalLegacyThing
316
+ add_counter_column_to(Person, 'personal_legacy_things_count')
317
+ PersonalLegacyThing.reset_column_information
318
+
319
+ # Make sure that counter incrementing doesn't cause problems
320
+ p1 = Person.new(:first_name => 'fjord')
321
+ p1.save!
322
+ t = PersonalLegacyThing.new(:person => p1)
323
+ t.save!
324
+ p1.reload
325
+ assert_equal 1, p1.personal_legacy_things_count
326
+ assert p1.destroy
327
+ assert_equal true, p1.frozen?
328
+ assert_raises(ActiveRecord::RecordNotFound) { Person.find(p1.id) }
329
+ assert_raises(ActiveRecord::RecordNotFound) { PersonalLegacyThing.find(t.id) }
330
+ ensure
331
+ remove_counter_column_from(Person, 'personal_legacy_things_count')
332
+ PersonalLegacyThing.reset_column_information
333
+ end
334
+
335
+ private
336
+
337
+ def add_counter_column_to(model, col='test_count')
338
+ model.connection.add_column model.table_name, col, :integer, :null => false, :default => 0
339
+ model.reset_column_information
340
+ end
341
+
342
+ def remove_counter_column_from(model, col = :test_count)
343
+ model.connection.remove_column model.table_name, col
344
+ model.reset_column_information
345
+ end
346
+
347
+ def counter_test(model, expected_count)
348
+ add_counter_column_to(model)
349
+ object = model.first
350
+ assert_equal 0, object.test_count
351
+ assert_equal 0, object.send(model.locking_column)
352
+ yield object.id
353
+ object.reload
354
+ assert_equal expected_count, object.test_count
355
+ assert_equal 1, object.send(model.locking_column)
356
+ ensure
357
+ remove_counter_column_from(model)
358
+ end
359
+ end
360
+
361
+
362
+ # TODO: test against the generated SQL since testing locking behavior itself
363
+ # is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
364
+ # blocks, so separate script called by Kernel#system is needed.
365
+ # (See exec vs. async_exec in the PostgreSQL adapter.)
366
+ unless in_memory_db?
367
+ class PessimisticLockingTest < ActiveRecord::TestCase
368
+ self.use_transactional_fixtures = false
369
+ fixtures :people, :readers
370
+
371
+ def setup
372
+ Person.connection_pool.clear_reloadable_connections!
373
+ # Avoid introspection queries during tests.
374
+ Person.columns; Reader.columns
375
+ end
376
+
377
+ # Test typical find.
378
+ def test_sane_find_with_lock
379
+ assert_nothing_raised do
380
+ Person.transaction do
381
+ Person.lock.find(1)
382
+ end
383
+ end
384
+ end
385
+
386
+ # PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
387
+ unless current_adapter?(:PostgreSQLAdapter)
388
+ # Test locked eager find.
389
+ def test_eager_find_with_lock
390
+ assert_nothing_raised do
391
+ Person.transaction do
392
+ Person.includes(:readers).lock.find(1)
393
+ end
394
+ end
395
+ end
396
+ end
397
+
398
+ # Locking a record reloads it.
399
+ def test_sane_lock_method
400
+ assert_nothing_raised do
401
+ Person.transaction do
402
+ person = Person.find 1
403
+ old, person.first_name = person.first_name, 'fooman'
404
+ person.lock!
405
+ assert_equal old, person.first_name
406
+ end
407
+ end
408
+ end
409
+
410
+ def test_with_lock_commits_transaction
411
+ person = Person.find 1
412
+ person.with_lock do
413
+ person.first_name = 'fooman'
414
+ person.save!
415
+ end
416
+ assert_equal 'fooman', person.reload.first_name
417
+ end
418
+
419
+ def test_with_lock_rolls_back_transaction
420
+ person = Person.find 1
421
+ old = person.first_name
422
+ person.with_lock do
423
+ person.first_name = 'fooman'
424
+ person.save!
425
+ raise 'oops'
426
+ end rescue nil
427
+ assert_equal old, person.reload.first_name
428
+ end
429
+
430
+ if current_adapter?(:PostgreSQLAdapter)
431
+ def test_lock_sending_custom_lock_statement
432
+ Person.transaction do
433
+ person = Person.find(1)
434
+ assert_sql(/LIMIT 1 FOR SHARE NOWAIT/) do
435
+ person.lock!('FOR SHARE NOWAIT')
436
+ end
437
+ end
438
+ end
439
+ end
440
+
441
+ if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
442
+ def test_no_locks_no_wait
443
+ first, second = duel { Person.find 1 }
444
+ assert first.end > second.end
445
+ end
446
+
447
+ protected
448
+ def duel(zzz = 5)
449
+ t0, t1, t2, t3 = nil, nil, nil, nil
450
+
451
+ a = Thread.new do
452
+ t0 = Time.now
453
+ Person.transaction do
454
+ yield
455
+ sleep zzz # block thread 2 for zzz seconds
456
+ end
457
+ t1 = Time.now
458
+ end
459
+
460
+ b = Thread.new do
461
+ sleep zzz / 2.0 # ensure thread 1 tx starts first
462
+ t2 = Time.now
463
+ Person.transaction { yield }
464
+ t3 = Time.now
465
+ end
466
+
467
+ a.join
468
+ b.join
469
+
470
+ assert t1 > t0 + zzz
471
+ assert t2 > t0
472
+ assert t3 > t2
473
+ [t0.to_f..t1.to_f, t2.to_f..t3.to_f]
474
+ end
475
+ end
476
+ end
477
+ end