activerecord 2.3.18 → 3.2.22

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (454) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1014 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +222 -0
  5. data/examples/performance.rb +100 -126
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +93 -99
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +247 -0
  10. data/lib/active_record/associations/association_scope.rb +134 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +54 -61
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
  13. data/lib/active_record/associations/builder/association.rb +55 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +88 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  17. data/lib/active_record/associations/builder/has_many.rb +71 -0
  18. data/lib/active_record/associations/builder/has_one.rb +62 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +580 -0
  21. data/lib/active_record/associations/collection_proxy.rb +133 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
  23. data/lib/active_record/associations/has_many_association.rb +60 -79
  24. data/lib/active_record/associations/has_many_through_association.rb +127 -206
  25. data/lib/active_record/associations/has_one_association.rb +55 -114
  26. data/lib/active_record/associations/has_one_through_association.rb +25 -26
  27. data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +214 -0
  31. data/lib/active_record/associations/join_helper.rb +55 -0
  32. data/lib/active_record/associations/preloader/association.rb +125 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/preloader.rb +181 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +693 -1337
  46. data/lib/active_record/attribute_assignment.rb +221 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  48. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  49. data/lib/active_record/attribute_methods/dirty.rb +111 -0
  50. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  51. data/lib/active_record/attribute_methods/query.rb +39 -0
  52. data/lib/active_record/attribute_methods/read.rb +136 -0
  53. data/lib/active_record/attribute_methods/serialization.rb +120 -0
  54. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  55. data/lib/active_record/attribute_methods/write.rb +70 -0
  56. data/lib/active_record/attribute_methods.rb +211 -339
  57. data/lib/active_record/autosave_association.rb +179 -149
  58. data/lib/active_record/base.rb +401 -2907
  59. data/lib/active_record/callbacks.rb +91 -176
  60. data/lib/active_record/coders/yaml_column.rb +41 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
  62. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
  68. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
  71. data/lib/active_record/connection_adapters/column.rb +296 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
  75. data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
  76. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
  77. data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
  78. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  79. data/lib/active_record/counter_cache.rb +123 -0
  80. data/lib/active_record/dynamic_finder_match.rb +41 -14
  81. data/lib/active_record/dynamic_matchers.rb +84 -0
  82. data/lib/active_record/dynamic_scope_match.rb +13 -15
  83. data/lib/active_record/errors.rb +195 -0
  84. data/lib/active_record/explain.rb +86 -0
  85. data/lib/active_record/explain_subscriber.rb +25 -0
  86. data/lib/active_record/fixtures/file.rb +65 -0
  87. data/lib/active_record/fixtures.rb +695 -770
  88. data/lib/active_record/identity_map.rb +162 -0
  89. data/lib/active_record/inheritance.rb +174 -0
  90. data/lib/active_record/integration.rb +60 -0
  91. data/lib/active_record/locale/en.yml +9 -27
  92. data/lib/active_record/locking/optimistic.rb +76 -73
  93. data/lib/active_record/locking/pessimistic.rb +32 -10
  94. data/lib/active_record/log_subscriber.rb +72 -0
  95. data/lib/active_record/migration/command_recorder.rb +105 -0
  96. data/lib/active_record/migration.rb +415 -205
  97. data/lib/active_record/model_schema.rb +368 -0
  98. data/lib/active_record/nested_attributes.rb +153 -63
  99. data/lib/active_record/observer.rb +27 -103
  100. data/lib/active_record/persistence.rb +376 -0
  101. data/lib/active_record/query_cache.rb +49 -8
  102. data/lib/active_record/querying.rb +58 -0
  103. data/lib/active_record/railtie.rb +131 -0
  104. data/lib/active_record/railties/console_sandbox.rb +6 -0
  105. data/lib/active_record/railties/controller_runtime.rb +49 -0
  106. data/lib/active_record/railties/databases.rake +659 -0
  107. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  108. data/lib/active_record/readonly_attributes.rb +26 -0
  109. data/lib/active_record/reflection.rb +269 -120
  110. data/lib/active_record/relation/batches.rb +90 -0
  111. data/lib/active_record/relation/calculations.rb +372 -0
  112. data/lib/active_record/relation/delegation.rb +49 -0
  113. data/lib/active_record/relation/finder_methods.rb +402 -0
  114. data/lib/active_record/relation/predicate_builder.rb +63 -0
  115. data/lib/active_record/relation/query_methods.rb +417 -0
  116. data/lib/active_record/relation/spawn_methods.rb +180 -0
  117. data/lib/active_record/relation.rb +537 -0
  118. data/lib/active_record/result.rb +40 -0
  119. data/lib/active_record/sanitization.rb +194 -0
  120. data/lib/active_record/schema.rb +9 -6
  121. data/lib/active_record/schema_dumper.rb +55 -32
  122. data/lib/active_record/scoping/default.rb +142 -0
  123. data/lib/active_record/scoping/named.rb +200 -0
  124. data/lib/active_record/scoping.rb +152 -0
  125. data/lib/active_record/serialization.rb +8 -91
  126. data/lib/active_record/serializers/xml_serializer.rb +43 -197
  127. data/lib/active_record/session_store.rb +129 -103
  128. data/lib/active_record/store.rb +52 -0
  129. data/lib/active_record/test_case.rb +30 -23
  130. data/lib/active_record/timestamp.rb +95 -52
  131. data/lib/active_record/transactions.rb +212 -66
  132. data/lib/active_record/translation.rb +22 -0
  133. data/lib/active_record/validations/associated.rb +43 -0
  134. data/lib/active_record/validations/uniqueness.rb +180 -0
  135. data/lib/active_record/validations.rb +43 -1106
  136. data/lib/active_record/version.rb +5 -4
  137. data/lib/active_record.rb +121 -48
  138. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  139. data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
  140. data/lib/rails/generators/active_record/migration.rb +15 -0
  141. data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
  142. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  143. data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
  144. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  145. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  146. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  147. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  148. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  149. data/lib/rails/generators/active_record.rb +25 -0
  150. metadata +187 -363
  151. data/CHANGELOG +0 -5904
  152. data/README +0 -351
  153. data/RUNNING_UNIT_TESTS +0 -36
  154. data/Rakefile +0 -268
  155. data/install.rb +0 -30
  156. data/lib/active_record/association_preload.rb +0 -406
  157. data/lib/active_record/associations/association_collection.rb +0 -533
  158. data/lib/active_record/associations/association_proxy.rb +0 -288
  159. data/lib/active_record/batches.rb +0 -85
  160. data/lib/active_record/calculations.rb +0 -321
  161. data/lib/active_record/dirty.rb +0 -183
  162. data/lib/active_record/named_scope.rb +0 -197
  163. data/lib/active_record/serializers/json_serializer.rb +0 -91
  164. data/lib/activerecord.rb +0 -2
  165. data/test/assets/example.log +0 -1
  166. data/test/assets/flowers.jpg +0 -0
  167. data/test/cases/aaa_create_tables_test.rb +0 -24
  168. data/test/cases/active_schema_test_mysql.rb +0 -122
  169. data/test/cases/active_schema_test_postgresql.rb +0 -24
  170. data/test/cases/adapter_test.rb +0 -144
  171. data/test/cases/aggregations_test.rb +0 -167
  172. data/test/cases/ar_schema_test.rb +0 -32
  173. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  174. data/test/cases/associations/callbacks_test.rb +0 -161
  175. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  176. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  177. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  178. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  179. data/test/cases/associations/eager_singularization_test.rb +0 -145
  180. data/test/cases/associations/eager_test.rb +0 -852
  181. data/test/cases/associations/extension_test.rb +0 -62
  182. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  183. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  184. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  185. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  186. data/test/cases/associations/has_one_associations_test.rb +0 -330
  187. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  188. data/test/cases/associations/inner_join_association_test.rb +0 -93
  189. data/test/cases/associations/inverse_associations_test.rb +0 -566
  190. data/test/cases/associations/join_model_test.rb +0 -712
  191. data/test/cases/associations_test.rb +0 -282
  192. data/test/cases/attribute_methods_test.rb +0 -305
  193. data/test/cases/autosave_association_test.rb +0 -1218
  194. data/test/cases/base_test.rb +0 -2166
  195. data/test/cases/batches_test.rb +0 -81
  196. data/test/cases/binary_test.rb +0 -30
  197. data/test/cases/calculations_test.rb +0 -360
  198. data/test/cases/callbacks_observers_test.rb +0 -38
  199. data/test/cases/callbacks_test.rb +0 -438
  200. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  201. data/test/cases/column_alias_test.rb +0 -17
  202. data/test/cases/column_definition_test.rb +0 -70
  203. data/test/cases/connection_pool_test.rb +0 -25
  204. data/test/cases/connection_test_firebird.rb +0 -8
  205. data/test/cases/connection_test_mysql.rb +0 -65
  206. data/test/cases/copy_table_test_sqlite.rb +0 -80
  207. data/test/cases/counter_cache_test.rb +0 -84
  208. data/test/cases/database_statements_test.rb +0 -12
  209. data/test/cases/datatype_test_postgresql.rb +0 -204
  210. data/test/cases/date_time_test.rb +0 -37
  211. data/test/cases/default_test_firebird.rb +0 -16
  212. data/test/cases/defaults_test.rb +0 -111
  213. data/test/cases/deprecated_finder_test.rb +0 -30
  214. data/test/cases/dirty_test.rb +0 -316
  215. data/test/cases/finder_respond_to_test.rb +0 -76
  216. data/test/cases/finder_test.rb +0 -1098
  217. data/test/cases/fixtures_test.rb +0 -661
  218. data/test/cases/helper.rb +0 -68
  219. data/test/cases/i18n_test.rb +0 -46
  220. data/test/cases/inheritance_test.rb +0 -262
  221. data/test/cases/invalid_date_test.rb +0 -24
  222. data/test/cases/json_serialization_test.rb +0 -219
  223. data/test/cases/lifecycle_test.rb +0 -193
  224. data/test/cases/locking_test.rb +0 -350
  225. data/test/cases/method_scoping_test.rb +0 -704
  226. data/test/cases/migration_test.rb +0 -1649
  227. data/test/cases/migration_test_firebird.rb +0 -124
  228. data/test/cases/mixin_test.rb +0 -96
  229. data/test/cases/modules_test.rb +0 -109
  230. data/test/cases/multiple_db_test.rb +0 -85
  231. data/test/cases/named_scope_test.rb +0 -372
  232. data/test/cases/nested_attributes_test.rb +0 -840
  233. data/test/cases/pk_test.rb +0 -119
  234. data/test/cases/pooled_connections_test.rb +0 -103
  235. data/test/cases/query_cache_test.rb +0 -129
  236. data/test/cases/readonly_test.rb +0 -107
  237. data/test/cases/reflection_test.rb +0 -234
  238. data/test/cases/reload_models_test.rb +0 -22
  239. data/test/cases/repair_helper.rb +0 -50
  240. data/test/cases/reserved_word_test_mysql.rb +0 -176
  241. data/test/cases/sanitize_test.rb +0 -25
  242. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  243. data/test/cases/schema_dumper_test.rb +0 -211
  244. data/test/cases/schema_test_postgresql.rb +0 -178
  245. data/test/cases/serialization_test.rb +0 -47
  246. data/test/cases/sp_test_mysql.rb +0 -16
  247. data/test/cases/synonym_test_oracle.rb +0 -17
  248. data/test/cases/timestamp_test.rb +0 -75
  249. data/test/cases/transactions_test.rb +0 -543
  250. data/test/cases/unconnected_test.rb +0 -32
  251. data/test/cases/validations_i18n_test.rb +0 -925
  252. data/test/cases/validations_test.rb +0 -1684
  253. data/test/cases/xml_serialization_test.rb +0 -240
  254. data/test/cases/yaml_serialization_test.rb +0 -11
  255. data/test/config.rb +0 -5
  256. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  257. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  258. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  259. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  260. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  261. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  262. data/test/connections/native_db2/connection.rb +0 -25
  263. data/test/connections/native_firebird/connection.rb +0 -26
  264. data/test/connections/native_frontbase/connection.rb +0 -27
  265. data/test/connections/native_mysql/connection.rb +0 -25
  266. data/test/connections/native_openbase/connection.rb +0 -21
  267. data/test/connections/native_oracle/connection.rb +0 -27
  268. data/test/connections/native_postgresql/connection.rb +0 -21
  269. data/test/connections/native_sqlite/connection.rb +0 -25
  270. data/test/connections/native_sqlite3/connection.rb +0 -25
  271. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  272. data/test/connections/native_sybase/connection.rb +0 -23
  273. data/test/fixtures/accounts.yml +0 -29
  274. data/test/fixtures/all/developers.yml +0 -0
  275. data/test/fixtures/all/people.csv +0 -0
  276. data/test/fixtures/all/tasks.yml +0 -0
  277. data/test/fixtures/author_addresses.yml +0 -5
  278. data/test/fixtures/author_favorites.yml +0 -4
  279. data/test/fixtures/authors.yml +0 -9
  280. data/test/fixtures/binaries.yml +0 -132
  281. data/test/fixtures/books.yml +0 -7
  282. data/test/fixtures/categories/special_categories.yml +0 -9
  283. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  284. data/test/fixtures/categories.yml +0 -14
  285. data/test/fixtures/categories_ordered.yml +0 -7
  286. data/test/fixtures/categories_posts.yml +0 -23
  287. data/test/fixtures/categorizations.yml +0 -17
  288. data/test/fixtures/clubs.yml +0 -6
  289. data/test/fixtures/comments.yml +0 -59
  290. data/test/fixtures/companies.yml +0 -56
  291. data/test/fixtures/computers.yml +0 -4
  292. data/test/fixtures/courses.yml +0 -7
  293. data/test/fixtures/customers.yml +0 -26
  294. data/test/fixtures/developers.yml +0 -21
  295. data/test/fixtures/developers_projects.yml +0 -17
  296. data/test/fixtures/edges.yml +0 -6
  297. data/test/fixtures/entrants.yml +0 -14
  298. data/test/fixtures/faces.yml +0 -11
  299. data/test/fixtures/fk_test_has_fk.yml +0 -3
  300. data/test/fixtures/fk_test_has_pk.yml +0 -2
  301. data/test/fixtures/funny_jokes.yml +0 -10
  302. data/test/fixtures/interests.yml +0 -33
  303. data/test/fixtures/items.yml +0 -4
  304. data/test/fixtures/jobs.yml +0 -7
  305. data/test/fixtures/legacy_things.yml +0 -3
  306. data/test/fixtures/mateys.yml +0 -4
  307. data/test/fixtures/member_types.yml +0 -6
  308. data/test/fixtures/members.yml +0 -6
  309. data/test/fixtures/memberships.yml +0 -20
  310. data/test/fixtures/men.yml +0 -5
  311. data/test/fixtures/minimalistics.yml +0 -2
  312. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  313. data/test/fixtures/mixins.yml +0 -29
  314. data/test/fixtures/movies.yml +0 -7
  315. data/test/fixtures/naked/csv/accounts.csv +0 -1
  316. data/test/fixtures/naked/yml/accounts.yml +0 -1
  317. data/test/fixtures/naked/yml/companies.yml +0 -1
  318. data/test/fixtures/naked/yml/courses.yml +0 -1
  319. data/test/fixtures/organizations.yml +0 -5
  320. data/test/fixtures/owners.yml +0 -7
  321. data/test/fixtures/parrots.yml +0 -27
  322. data/test/fixtures/parrots_pirates.yml +0 -7
  323. data/test/fixtures/people.yml +0 -15
  324. data/test/fixtures/pets.yml +0 -14
  325. data/test/fixtures/pirates.yml +0 -9
  326. data/test/fixtures/polymorphic_designs.yml +0 -19
  327. data/test/fixtures/polymorphic_prices.yml +0 -19
  328. data/test/fixtures/posts.yml +0 -52
  329. data/test/fixtures/price_estimates.yml +0 -7
  330. data/test/fixtures/projects.yml +0 -7
  331. data/test/fixtures/readers.yml +0 -9
  332. data/test/fixtures/references.yml +0 -17
  333. data/test/fixtures/reserved_words/distinct.yml +0 -5
  334. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  335. data/test/fixtures/reserved_words/group.yml +0 -14
  336. data/test/fixtures/reserved_words/select.yml +0 -8
  337. data/test/fixtures/reserved_words/values.yml +0 -7
  338. data/test/fixtures/ships.yml +0 -5
  339. data/test/fixtures/sponsors.yml +0 -9
  340. data/test/fixtures/subscribers.yml +0 -7
  341. data/test/fixtures/subscriptions.yml +0 -12
  342. data/test/fixtures/taggings.yml +0 -28
  343. data/test/fixtures/tags.yml +0 -7
  344. data/test/fixtures/tasks.yml +0 -7
  345. data/test/fixtures/tees.yml +0 -4
  346. data/test/fixtures/ties.yml +0 -4
  347. data/test/fixtures/topics.yml +0 -42
  348. data/test/fixtures/toys.yml +0 -4
  349. data/test/fixtures/treasures.yml +0 -10
  350. data/test/fixtures/vertices.yml +0 -4
  351. data/test/fixtures/warehouse-things.yml +0 -3
  352. data/test/fixtures/zines.yml +0 -5
  353. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  354. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  355. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  356. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  357. data/test/migrations/duplicate/3_foo.rb +0 -7
  358. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  359. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  360. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  361. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  362. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  363. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  364. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  365. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  366. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  367. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  368. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  369. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  370. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  371. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  372. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  373. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  374. data/test/models/author.rb +0 -151
  375. data/test/models/auto_id.rb +0 -4
  376. data/test/models/binary.rb +0 -2
  377. data/test/models/bird.rb +0 -9
  378. data/test/models/book.rb +0 -4
  379. data/test/models/categorization.rb +0 -5
  380. data/test/models/category.rb +0 -34
  381. data/test/models/citation.rb +0 -6
  382. data/test/models/club.rb +0 -13
  383. data/test/models/column_name.rb +0 -3
  384. data/test/models/comment.rb +0 -29
  385. data/test/models/company.rb +0 -173
  386. data/test/models/company_in_module.rb +0 -78
  387. data/test/models/computer.rb +0 -3
  388. data/test/models/contact.rb +0 -16
  389. data/test/models/contract.rb +0 -5
  390. data/test/models/course.rb +0 -3
  391. data/test/models/customer.rb +0 -73
  392. data/test/models/default.rb +0 -2
  393. data/test/models/developer.rb +0 -101
  394. data/test/models/edge.rb +0 -5
  395. data/test/models/entrant.rb +0 -3
  396. data/test/models/essay.rb +0 -3
  397. data/test/models/event.rb +0 -3
  398. data/test/models/event_author.rb +0 -8
  399. data/test/models/face.rb +0 -7
  400. data/test/models/guid.rb +0 -2
  401. data/test/models/interest.rb +0 -5
  402. data/test/models/invoice.rb +0 -4
  403. data/test/models/item.rb +0 -7
  404. data/test/models/job.rb +0 -5
  405. data/test/models/joke.rb +0 -3
  406. data/test/models/keyboard.rb +0 -3
  407. data/test/models/legacy_thing.rb +0 -3
  408. data/test/models/line_item.rb +0 -3
  409. data/test/models/man.rb +0 -9
  410. data/test/models/matey.rb +0 -4
  411. data/test/models/member.rb +0 -12
  412. data/test/models/member_detail.rb +0 -5
  413. data/test/models/member_type.rb +0 -3
  414. data/test/models/membership.rb +0 -9
  415. data/test/models/minimalistic.rb +0 -2
  416. data/test/models/mixed_case_monkey.rb +0 -3
  417. data/test/models/movie.rb +0 -5
  418. data/test/models/order.rb +0 -4
  419. data/test/models/organization.rb +0 -6
  420. data/test/models/owner.rb +0 -5
  421. data/test/models/parrot.rb +0 -22
  422. data/test/models/person.rb +0 -16
  423. data/test/models/pet.rb +0 -5
  424. data/test/models/pirate.rb +0 -80
  425. data/test/models/polymorphic_design.rb +0 -3
  426. data/test/models/polymorphic_price.rb +0 -3
  427. data/test/models/post.rb +0 -102
  428. data/test/models/price_estimate.rb +0 -3
  429. data/test/models/project.rb +0 -30
  430. data/test/models/reader.rb +0 -4
  431. data/test/models/reference.rb +0 -4
  432. data/test/models/reply.rb +0 -46
  433. data/test/models/ship.rb +0 -19
  434. data/test/models/ship_part.rb +0 -7
  435. data/test/models/sponsor.rb +0 -4
  436. data/test/models/subject.rb +0 -4
  437. data/test/models/subscriber.rb +0 -8
  438. data/test/models/subscription.rb +0 -4
  439. data/test/models/tag.rb +0 -7
  440. data/test/models/tagging.rb +0 -10
  441. data/test/models/task.rb +0 -3
  442. data/test/models/tee.rb +0 -4
  443. data/test/models/tie.rb +0 -4
  444. data/test/models/topic.rb +0 -80
  445. data/test/models/toy.rb +0 -6
  446. data/test/models/treasure.rb +0 -8
  447. data/test/models/vertex.rb +0 -9
  448. data/test/models/warehouse_thing.rb +0 -5
  449. data/test/models/zine.rb +0 -3
  450. data/test/schema/mysql_specific_schema.rb +0 -31
  451. data/test/schema/postgresql_specific_schema.rb +0 -114
  452. data/test/schema/schema.rb +0 -550
  453. data/test/schema/schema2.rb +0 -6
  454. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -0,0 +1,676 @@
1
+ require 'active_support/core_ext/object/blank'
2
+ require 'arel/visitors/bind_visitor'
3
+
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ class AbstractMysqlAdapter < AbstractAdapter
7
+ class Column < ConnectionAdapters::Column # :nodoc:
8
+ attr_reader :collation
9
+
10
+ def initialize(name, default, sql_type = nil, null = true, collation = nil)
11
+ super(name, default, sql_type, null)
12
+ @collation = collation
13
+ end
14
+
15
+ def extract_default(default)
16
+ if sql_type =~ /blob/i || type == :text
17
+ if default.blank?
18
+ return null ? nil : ''
19
+ else
20
+ raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
21
+ end
22
+ elsif missing_default_forged_as_empty_string?(default)
23
+ nil
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def has_default?
30
+ return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns
31
+ super
32
+ end
33
+
34
+ # Must return the relevant concrete adapter
35
+ def adapter
36
+ raise NotImplementedError
37
+ end
38
+
39
+ def case_sensitive?
40
+ collation && !collation.match(/_ci$/)
41
+ end
42
+
43
+ private
44
+
45
+ def simplified_type(field_type)
46
+ return :boolean if adapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
47
+
48
+ case field_type
49
+ when /enum/i, /set/i then :string
50
+ when /year/i then :integer
51
+ when /bit/i then :binary
52
+ else
53
+ super
54
+ end
55
+ end
56
+
57
+ def extract_limit(sql_type)
58
+ case sql_type
59
+ when /blob|text/i
60
+ case sql_type
61
+ when /tiny/i
62
+ 255
63
+ when /medium/i
64
+ 16777215
65
+ when /long/i
66
+ 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
67
+ else
68
+ super # we could return 65535 here, but we leave it undecorated by default
69
+ end
70
+ when /^bigint/i; 8
71
+ when /^int/i; 4
72
+ when /^mediumint/i; 3
73
+ when /^smallint/i; 2
74
+ when /^tinyint/i; 1
75
+ when /^enum\((.+)\)/i
76
+ $1.split(',').map{|enum| enum.strip.length - 2}.max
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ # MySQL misreports NOT NULL column default when none is given.
83
+ # We can't detect this for columns which may have a legitimate ''
84
+ # default (string) but we can for others (integer, datetime, boolean,
85
+ # and the rest).
86
+ #
87
+ # Test whether the column has default '', is not null, and is not
88
+ # a type allowing default ''.
89
+ def missing_default_forged_as_empty_string?(default)
90
+ type != :string && !null && default == ''
91
+ end
92
+ end
93
+
94
+ ##
95
+ # :singleton-method:
96
+ # By default, the MysqlAdapter will consider all columns of type <tt>tinyint(1)</tt>
97
+ # as boolean. If you wish to disable this emulation (which was the default
98
+ # behavior in versions 0.13.1 and earlier) you can add the following line
99
+ # to your application.rb file:
100
+ #
101
+ # ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
102
+ class_attribute :emulate_booleans
103
+ self.emulate_booleans = true
104
+
105
+ LOST_CONNECTION_ERROR_MESSAGES = [
106
+ "Server shutdown in progress",
107
+ "Broken pipe",
108
+ "Lost connection to MySQL server during query",
109
+ "MySQL server has gone away" ]
110
+
111
+ QUOTED_TRUE, QUOTED_FALSE = '1', '0'
112
+
113
+ NATIVE_DATABASE_TYPES = {
114
+ :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
115
+ :string => { :name => "varchar", :limit => 255 },
116
+ :text => { :name => "text" },
117
+ :integer => { :name => "int", :limit => 4 },
118
+ :float => { :name => "float" },
119
+ :decimal => { :name => "decimal" },
120
+ :datetime => { :name => "datetime" },
121
+ :timestamp => { :name => "datetime" },
122
+ :time => { :name => "time" },
123
+ :date => { :name => "date" },
124
+ :binary => { :name => "blob" },
125
+ :boolean => { :name => "tinyint", :limit => 1 }
126
+ }
127
+
128
+ class BindSubstitution < Arel::Visitors::MySQL # :nodoc:
129
+ include Arel::Visitors::BindVisitor
130
+ end
131
+
132
+ # FIXME: Make the first parameter more similar for the two adapters
133
+ def initialize(connection, logger, connection_options, config)
134
+ super(connection, logger)
135
+ @connection_options, @config = connection_options, config
136
+ @quoted_column_names, @quoted_table_names = {}, {}
137
+
138
+ if config.fetch(:prepared_statements) { true }
139
+ @visitor = Arel::Visitors::MySQL.new self
140
+ else
141
+ @visitor = BindSubstitution.new self
142
+ end
143
+ end
144
+
145
+ def adapter_name #:nodoc:
146
+ self.class::ADAPTER_NAME
147
+ end
148
+
149
+ # Returns true, since this connection adapter supports migrations.
150
+ def supports_migrations?
151
+ true
152
+ end
153
+
154
+ def supports_primary_key?
155
+ true
156
+ end
157
+
158
+ # Returns true, since this connection adapter supports savepoints.
159
+ def supports_savepoints?
160
+ true
161
+ end
162
+
163
+ def supports_bulk_alter? #:nodoc:
164
+ true
165
+ end
166
+
167
+ # Technically MySQL allows to create indexes with the sort order syntax
168
+ # but at the moment (5.5) it doesn't yet implement them
169
+ def supports_index_sort_order?
170
+ true
171
+ end
172
+
173
+ def native_database_types
174
+ NATIVE_DATABASE_TYPES
175
+ end
176
+
177
+ # HELPER METHODS ===========================================
178
+
179
+ # The two drivers have slightly different ways of yielding hashes of results, so
180
+ # this method must be implemented to provide a uniform interface.
181
+ def each_hash(result) # :nodoc:
182
+ raise NotImplementedError
183
+ end
184
+
185
+ # Overridden by the adapters to instantiate their specific Column type.
186
+ def new_column(field, default, type, null, collation) # :nodoc:
187
+ Column.new(field, default, type, null, collation)
188
+ end
189
+
190
+ # Must return the Mysql error number from the exception, if the exception has an
191
+ # error number.
192
+ def error_number(exception) # :nodoc:
193
+ raise NotImplementedError
194
+ end
195
+
196
+ # QUOTING ==================================================
197
+
198
+ def quote(value, column = nil)
199
+ if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
200
+ s = column.class.string_to_binary(value).unpack("H*")[0]
201
+ "x'#{s}'"
202
+ elsif value.kind_of?(BigDecimal)
203
+ value.to_s("F")
204
+ else
205
+ super
206
+ end
207
+ end
208
+
209
+ def quote_column_name(name) #:nodoc:
210
+ @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
211
+ end
212
+
213
+ def quote_table_name(name) #:nodoc:
214
+ @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
215
+ end
216
+
217
+ def quoted_true
218
+ QUOTED_TRUE
219
+ end
220
+
221
+ def quoted_false
222
+ QUOTED_FALSE
223
+ end
224
+
225
+ # REFERENTIAL INTEGRITY ====================================
226
+
227
+ def disable_referential_integrity(&block) #:nodoc:
228
+ old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
229
+
230
+ begin
231
+ update("SET FOREIGN_KEY_CHECKS = 0")
232
+ yield
233
+ ensure
234
+ update("SET FOREIGN_KEY_CHECKS = #{old}")
235
+ end
236
+ end
237
+
238
+ # DATABASE STATEMENTS ======================================
239
+
240
+ # Executes the SQL statement in the context of this connection.
241
+ def execute(sql, name = nil)
242
+ if name == :skip_logging
243
+ @connection.query(sql)
244
+ else
245
+ log(sql, name) { @connection.query(sql) }
246
+ end
247
+ rescue ActiveRecord::StatementInvalid => exception
248
+ if exception.message.split(":").first =~ /Packets out of order/
249
+ raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
250
+ else
251
+ raise
252
+ end
253
+ end
254
+
255
+ # MysqlAdapter has to free a result after using it, so we use this method to write
256
+ # stuff in a abstract way without concerning ourselves about whether it needs to be
257
+ # explicitly freed or not.
258
+ def execute_and_free(sql, name = nil) #:nodoc:
259
+ yield execute(sql, name)
260
+ end
261
+
262
+ def update_sql(sql, name = nil) #:nodoc:
263
+ super
264
+ @connection.affected_rows
265
+ end
266
+
267
+ def begin_db_transaction
268
+ execute "BEGIN"
269
+ rescue Exception
270
+ # Transactions aren't supported
271
+ end
272
+
273
+ def commit_db_transaction #:nodoc:
274
+ execute "COMMIT"
275
+ rescue Exception
276
+ # Transactions aren't supported
277
+ end
278
+
279
+ def rollback_db_transaction #:nodoc:
280
+ execute "ROLLBACK"
281
+ rescue Exception
282
+ # Transactions aren't supported
283
+ end
284
+
285
+ def create_savepoint
286
+ execute("SAVEPOINT #{current_savepoint_name}")
287
+ end
288
+
289
+ def rollback_to_savepoint
290
+ execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
291
+ end
292
+
293
+ def release_savepoint
294
+ execute("RELEASE SAVEPOINT #{current_savepoint_name}")
295
+ end
296
+
297
+ # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
298
+ # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
299
+ # these, we must use a subquery. However, MySQL is too stupid to create a
300
+ # temporary table for this automatically, so we have to give it some prompting
301
+ # in the form of a subsubquery. Ugh!
302
+ def join_to_update(update, select) #:nodoc:
303
+ if select.limit || select.offset || select.orders.any?
304
+ subsubselect = select.clone
305
+ subsubselect.projections = [update.key]
306
+
307
+ subselect = Arel::SelectManager.new(select.engine)
308
+ subselect.project Arel.sql(update.key.name)
309
+ subselect.from subsubselect.as('__active_record_temp')
310
+
311
+ update.where update.key.in(subselect)
312
+ else
313
+ update.table select.source
314
+ update.wheres = select.constraints
315
+ end
316
+ end
317
+
318
+ # SCHEMA STATEMENTS ========================================
319
+
320
+ def structure_dump #:nodoc:
321
+ if supports_views?
322
+ sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
323
+ else
324
+ sql = "SHOW TABLES"
325
+ end
326
+
327
+ select_all(sql).map { |table|
328
+ table.delete('Table_type')
329
+ sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}"
330
+ exec_query(sql).first['Create Table'] + ";\n\n"
331
+ }.join
332
+ end
333
+
334
+ # Drops the database specified on the +name+ attribute
335
+ # and creates it again using the provided +options+.
336
+ def recreate_database(name, options = {})
337
+ drop_database(name)
338
+ create_database(name, options)
339
+ end
340
+
341
+ # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
342
+ # Charset defaults to utf8.
343
+ #
344
+ # Example:
345
+ # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
346
+ # create_database 'matt_development'
347
+ # create_database 'matt_development', :charset => :big5
348
+ def create_database(name, options = {})
349
+ if options[:collation]
350
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
351
+ else
352
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
353
+ end
354
+ end
355
+
356
+ # Drops a MySQL database.
357
+ #
358
+ # Example:
359
+ # drop_database('sebastian_development')
360
+ def drop_database(name) #:nodoc:
361
+ execute "DROP DATABASE IF EXISTS `#{name}`"
362
+ end
363
+
364
+ def current_database
365
+ select_value 'SELECT DATABASE() as db'
366
+ end
367
+
368
+ # Returns the database character set.
369
+ def charset
370
+ show_variable 'character_set_database'
371
+ end
372
+
373
+ # Returns the database collation strategy.
374
+ def collation
375
+ show_variable 'collation_database'
376
+ end
377
+
378
+ def tables(name = nil, database = nil, like = nil) #:nodoc:
379
+ sql = "SHOW TABLES "
380
+ sql << "IN #{quote_table_name(database)} " if database
381
+ sql << "LIKE #{quote(like)}" if like
382
+
383
+ execute_and_free(sql, 'SCHEMA') do |result|
384
+ result.collect { |field| field.first }
385
+ end
386
+ end
387
+
388
+ def table_exists?(name)
389
+ return false unless name
390
+ return true if tables(nil, nil, name).any?
391
+
392
+ name = name.to_s
393
+ schema, table = name.split('.', 2)
394
+
395
+ unless table # A table was provided without a schema
396
+ table = schema
397
+ schema = nil
398
+ end
399
+
400
+ tables(nil, schema, table).any?
401
+ end
402
+
403
+ # Returns an array of indexes for the given table.
404
+ def indexes(table_name, name = nil) #:nodoc:
405
+ indexes = []
406
+ current_index = nil
407
+ execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
408
+ each_hash(result) do |row|
409
+ if current_index != row[:Key_name]
410
+ next if row[:Key_name] == 'PRIMARY' # skip the primary key
411
+ current_index = row[:Key_name]
412
+ indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], [])
413
+ end
414
+
415
+ indexes.last.columns << row[:Column_name]
416
+ indexes.last.lengths << row[:Sub_part]
417
+ end
418
+ end
419
+
420
+ indexes
421
+ end
422
+
423
+ # Returns an array of +Column+ objects for the table specified by +table_name+.
424
+ def columns(table_name, name = nil)#:nodoc:
425
+ sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
426
+ execute_and_free(sql, 'SCHEMA') do |result|
427
+ each_hash(result).map do |field|
428
+ new_column(field[:Field], field[:Default], field[:Type], field[:Null] == "YES", field[:Collation])
429
+ end
430
+ end
431
+ end
432
+
433
+ def create_table(table_name, options = {}) #:nodoc:
434
+ super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
435
+ end
436
+
437
+ def bulk_change_table(table_name, operations) #:nodoc:
438
+ sqls = operations.map do |command, args|
439
+ table, arguments = args.shift, args
440
+ method = :"#{command}_sql"
441
+
442
+ if respond_to?(method, true)
443
+ send(method, table, *arguments)
444
+ else
445
+ raise "Unknown method called : #{method}(#{arguments.inspect})"
446
+ end
447
+ end.flatten.join(", ")
448
+
449
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
450
+ end
451
+
452
+ # Renames a table.
453
+ #
454
+ # Example:
455
+ # rename_table('octopuses', 'octopi')
456
+ def rename_table(table_name, new_name)
457
+ execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
458
+ end
459
+
460
+ def add_column(table_name, column_name, type, options = {})
461
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{add_column_sql(table_name, column_name, type, options)}")
462
+ end
463
+
464
+ def change_column_default(table_name, column_name, default)
465
+ column = column_for(table_name, column_name)
466
+ change_column table_name, column_name, column.sql_type, :default => default
467
+ end
468
+
469
+ def change_column_null(table_name, column_name, null, default = nil)
470
+ column = column_for(table_name, column_name)
471
+
472
+ unless null || default.nil?
473
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
474
+ end
475
+
476
+ change_column table_name, column_name, column.sql_type, :null => null
477
+ end
478
+
479
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
480
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")
481
+ end
482
+
483
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
484
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
485
+ end
486
+
487
+ # Maps logical Rails types to MySQL-specific data types.
488
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
489
+ case type.to_s
490
+ when 'integer'
491
+ case limit
492
+ when 1; 'tinyint'
493
+ when 2; 'smallint'
494
+ when 3; 'mediumint'
495
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
496
+ when 5..8; 'bigint'
497
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
498
+ end
499
+ when 'text'
500
+ case limit
501
+ when 0..0xff; 'tinytext'
502
+ when nil, 0x100..0xffff; 'text'
503
+ when 0x10000..0xffffff; 'mediumtext'
504
+ when 0x1000000..0xffffffff; 'longtext'
505
+ else raise(ActiveRecordError, "No text type has character length #{limit}")
506
+ end
507
+ else
508
+ super
509
+ end
510
+ end
511
+
512
+ def add_column_position!(sql, options)
513
+ if options[:first]
514
+ sql << " FIRST"
515
+ elsif options[:after]
516
+ sql << " AFTER #{quote_column_name(options[:after])}"
517
+ end
518
+ end
519
+
520
+ # SHOW VARIABLES LIKE 'name'
521
+ def show_variable(name)
522
+ variables = select_all("SHOW VARIABLES LIKE '#{name}'")
523
+ variables.first['Value'] unless variables.empty?
524
+ end
525
+
526
+ # Returns a table's primary key and belonging sequence.
527
+ def pk_and_sequence_for(table)
528
+ execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result|
529
+ create_table = each_hash(result).first[:"Create Table"]
530
+ if create_table.to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
531
+ keys = $1.split(",").map { |key| key.gsub(/[`"]/, "") }
532
+ keys.length == 1 ? [keys.first, nil] : nil
533
+ else
534
+ nil
535
+ end
536
+ end
537
+ end
538
+
539
+ # Returns just a table's primary key
540
+ def primary_key(table)
541
+ pk_and_sequence = pk_and_sequence_for(table)
542
+ pk_and_sequence && pk_and_sequence.first
543
+ end
544
+
545
+ def case_sensitive_modifier(node)
546
+ Arel::Nodes::Bin.new(node)
547
+ end
548
+
549
+ def case_insensitive_comparison(table, attribute, column, value)
550
+ if column.case_sensitive?
551
+ super
552
+ else
553
+ table[attribute].eq(value)
554
+ end
555
+ end
556
+
557
+ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
558
+ where_sql
559
+ end
560
+
561
+ protected
562
+
563
+ def add_index_length(option_strings, column_names, options = {})
564
+ if options.is_a?(Hash) && length = options[:length]
565
+ case length
566
+ when Hash
567
+ column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
568
+ when Fixnum
569
+ column_names.each {|name| option_strings[name] += "(#{length})"}
570
+ end
571
+ end
572
+
573
+ return option_strings
574
+ end
575
+
576
+ def quoted_columns_for_index(column_names, options = {})
577
+ option_strings = Hash[column_names.map {|name| [name, '']}]
578
+
579
+ # add index length
580
+ option_strings = add_index_length(option_strings, column_names, options)
581
+
582
+ # add index sort order
583
+ option_strings = add_index_sort_order(option_strings, column_names, options)
584
+
585
+ column_names.map {|name| quote_column_name(name) + option_strings[name]}
586
+ end
587
+
588
+ def translate_exception(exception, message)
589
+ case error_number(exception)
590
+ when 1062
591
+ RecordNotUnique.new(message, exception)
592
+ when 1452
593
+ InvalidForeignKey.new(message, exception)
594
+ else
595
+ super
596
+ end
597
+ end
598
+
599
+ def add_column_sql(table_name, column_name, type, options = {})
600
+ add_column_sql = "ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
601
+ add_column_options!(add_column_sql, options)
602
+ add_column_position!(add_column_sql, options)
603
+ add_column_sql
604
+ end
605
+
606
+ def change_column_sql(table_name, column_name, type, options = {})
607
+ column = column_for(table_name, column_name)
608
+
609
+ unless options_include_default?(options)
610
+ options[:default] = column.default
611
+ end
612
+
613
+ unless options.has_key?(:null)
614
+ options[:null] = column.null
615
+ end
616
+
617
+ change_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
618
+ add_column_options!(change_column_sql, options)
619
+ add_column_position!(change_column_sql, options)
620
+ change_column_sql
621
+ end
622
+
623
+ def rename_column_sql(table_name, column_name, new_column_name)
624
+ options = {}
625
+
626
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
627
+ options[:default] = column.default
628
+ options[:null] = column.null
629
+ else
630
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
631
+ end
632
+
633
+ current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
634
+ rename_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
635
+ add_column_options!(rename_column_sql, options)
636
+ rename_column_sql
637
+ end
638
+
639
+ def remove_column_sql(table_name, *column_names)
640
+ columns_for_remove(table_name, *column_names).map {|column_name| "DROP #{column_name}" }
641
+ end
642
+ alias :remove_columns_sql :remove_column
643
+
644
+ def add_index_sql(table_name, column_name, options = {})
645
+ index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
646
+ "ADD #{index_type} INDEX #{index_name} (#{index_columns})"
647
+ end
648
+
649
+ def remove_index_sql(table_name, options = {})
650
+ index_name = index_name_for_remove(table_name, options)
651
+ "DROP INDEX #{index_name}"
652
+ end
653
+
654
+ def add_timestamps_sql(table_name)
655
+ [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)]
656
+ end
657
+
658
+ def remove_timestamps_sql(table_name)
659
+ [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
660
+ end
661
+
662
+ private
663
+
664
+ def supports_views?
665
+ version[0] >= 5
666
+ end
667
+
668
+ def column_for(table_name, column_name)
669
+ unless column = columns(table_name).find { |c| c.name == column_name.to_s }
670
+ raise "No such column: #{table_name}.#{column_name}"
671
+ end
672
+ column
673
+ end
674
+ end
675
+ end
676
+ end