activerecord 2.3.18 → 3.0.0.beta

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 (378) hide show
  1. data/CHANGELOG +105 -34
  2. data/examples/performance.rb +3 -39
  3. data/examples/simple.rb +14 -0
  4. data/lib/active_record.rb +81 -47
  5. data/lib/active_record/aggregations.rb +1 -3
  6. data/lib/active_record/association_preload.rb +39 -54
  7. data/lib/active_record/associations.rb +262 -419
  8. data/lib/active_record/associations/association_collection.rb +85 -100
  9. data/lib/active_record/associations/association_proxy.rb +20 -18
  10. data/lib/active_record/associations/belongs_to_association.rb +8 -8
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
  12. data/lib/active_record/associations/has_many_association.rb +11 -19
  13. data/lib/active_record/associations/has_many_through_association.rb +30 -183
  14. data/lib/active_record/associations/has_one_association.rb +10 -10
  15. data/lib/active_record/associations/has_one_through_association.rb +13 -11
  16. data/lib/active_record/associations/through_association_scope.rb +153 -0
  17. data/lib/active_record/attribute_methods.rb +17 -370
  18. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +87 -0
  20. data/lib/active_record/attribute_methods/primary_key.rb +44 -0
  21. data/lib/active_record/attribute_methods/query.rb +37 -0
  22. data/lib/active_record/attribute_methods/read.rb +116 -0
  23. data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
  24. data/lib/active_record/attribute_methods/write.rb +37 -0
  25. data/lib/active_record/autosave_association.rb +20 -41
  26. data/lib/active_record/base.rb +357 -1180
  27. data/lib/active_record/batches.rb +10 -16
  28. data/lib/active_record/callbacks.rb +66 -126
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
  30. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
  39. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
  40. data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
  41. data/lib/active_record/fixtures.rb +21 -25
  42. data/lib/active_record/locale/en.yml +9 -27
  43. data/lib/active_record/locking/optimistic.rb +16 -48
  44. data/lib/active_record/migration.rb +59 -46
  45. data/lib/active_record/named_scope.rb +85 -92
  46. data/lib/active_record/nested_attributes.rb +18 -24
  47. data/lib/active_record/observer.rb +18 -94
  48. data/lib/active_record/railtie.rb +83 -0
  49. data/lib/active_record/railties/controller_runtime.rb +38 -0
  50. data/lib/active_record/railties/databases.rake +477 -0
  51. data/lib/active_record/railties/subscriber.rb +27 -0
  52. data/lib/active_record/reflection.rb +2 -15
  53. data/lib/active_record/relation.rb +339 -0
  54. data/lib/active_record/relation/calculations.rb +259 -0
  55. data/lib/active_record/relation/finder_methods.rb +315 -0
  56. data/lib/active_record/relation/predicate_builder.rb +46 -0
  57. data/lib/active_record/relation/query_methods.rb +218 -0
  58. data/lib/active_record/relation/spawn_methods.rb +102 -0
  59. data/lib/active_record/schema_dumper.rb +10 -6
  60. data/lib/active_record/serialization.rb +31 -74
  61. data/lib/active_record/serializers/xml_serializer.rb +33 -121
  62. data/lib/active_record/session_store.rb +1 -9
  63. data/lib/active_record/test_case.rb +1 -3
  64. data/lib/active_record/timestamp.rb +7 -5
  65. data/lib/active_record/transactions.rb +9 -9
  66. data/lib/active_record/validations.rb +51 -1100
  67. data/lib/active_record/validations/associated.rb +47 -0
  68. data/lib/active_record/validations/uniqueness.rb +181 -0
  69. data/lib/active_record/version.rb +3 -3
  70. data/lib/generators/active_record.rb +30 -0
  71. data/lib/generators/active_record/migration/migration_generator.rb +25 -0
  72. data/lib/generators/active_record/migration/templates/migration.rb +11 -0
  73. data/lib/generators/active_record/model/model_generator.rb +33 -0
  74. data/lib/generators/active_record/model/templates/migration.rb +16 -0
  75. data/lib/generators/active_record/model/templates/model.rb +5 -0
  76. data/lib/generators/active_record/observer/observer_generator.rb +15 -0
  77. data/lib/generators/active_record/observer/templates/observer.rb +2 -0
  78. data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  79. data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
  80. metadata +67 -325
  81. data/RUNNING_UNIT_TESTS +0 -36
  82. data/Rakefile +0 -268
  83. data/install.rb +0 -30
  84. data/lib/active_record/calculations.rb +0 -321
  85. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
  86. data/lib/active_record/dirty.rb +0 -183
  87. data/lib/active_record/serializers/json_serializer.rb +0 -91
  88. data/lib/activerecord.rb +0 -2
  89. data/test/assets/example.log +0 -1
  90. data/test/assets/flowers.jpg +0 -0
  91. data/test/cases/aaa_create_tables_test.rb +0 -24
  92. data/test/cases/active_schema_test_mysql.rb +0 -122
  93. data/test/cases/active_schema_test_postgresql.rb +0 -24
  94. data/test/cases/adapter_test.rb +0 -144
  95. data/test/cases/aggregations_test.rb +0 -167
  96. data/test/cases/ar_schema_test.rb +0 -32
  97. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  98. data/test/cases/associations/callbacks_test.rb +0 -161
  99. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  100. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  101. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  102. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  103. data/test/cases/associations/eager_singularization_test.rb +0 -145
  104. data/test/cases/associations/eager_test.rb +0 -852
  105. data/test/cases/associations/extension_test.rb +0 -62
  106. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  107. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  108. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  109. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  110. data/test/cases/associations/has_one_associations_test.rb +0 -330
  111. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  112. data/test/cases/associations/inner_join_association_test.rb +0 -93
  113. data/test/cases/associations/inverse_associations_test.rb +0 -566
  114. data/test/cases/associations/join_model_test.rb +0 -712
  115. data/test/cases/associations_test.rb +0 -282
  116. data/test/cases/attribute_methods_test.rb +0 -305
  117. data/test/cases/autosave_association_test.rb +0 -1218
  118. data/test/cases/base_test.rb +0 -2166
  119. data/test/cases/batches_test.rb +0 -81
  120. data/test/cases/binary_test.rb +0 -30
  121. data/test/cases/calculations_test.rb +0 -360
  122. data/test/cases/callbacks_observers_test.rb +0 -38
  123. data/test/cases/callbacks_test.rb +0 -438
  124. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  125. data/test/cases/column_alias_test.rb +0 -17
  126. data/test/cases/column_definition_test.rb +0 -70
  127. data/test/cases/connection_pool_test.rb +0 -25
  128. data/test/cases/connection_test_firebird.rb +0 -8
  129. data/test/cases/connection_test_mysql.rb +0 -65
  130. data/test/cases/copy_table_test_sqlite.rb +0 -80
  131. data/test/cases/counter_cache_test.rb +0 -84
  132. data/test/cases/database_statements_test.rb +0 -12
  133. data/test/cases/datatype_test_postgresql.rb +0 -204
  134. data/test/cases/date_time_test.rb +0 -37
  135. data/test/cases/default_test_firebird.rb +0 -16
  136. data/test/cases/defaults_test.rb +0 -111
  137. data/test/cases/deprecated_finder_test.rb +0 -30
  138. data/test/cases/dirty_test.rb +0 -316
  139. data/test/cases/finder_respond_to_test.rb +0 -76
  140. data/test/cases/finder_test.rb +0 -1098
  141. data/test/cases/fixtures_test.rb +0 -661
  142. data/test/cases/helper.rb +0 -68
  143. data/test/cases/i18n_test.rb +0 -46
  144. data/test/cases/inheritance_test.rb +0 -262
  145. data/test/cases/invalid_date_test.rb +0 -24
  146. data/test/cases/json_serialization_test.rb +0 -219
  147. data/test/cases/lifecycle_test.rb +0 -193
  148. data/test/cases/locking_test.rb +0 -350
  149. data/test/cases/method_scoping_test.rb +0 -704
  150. data/test/cases/migration_test.rb +0 -1649
  151. data/test/cases/migration_test_firebird.rb +0 -124
  152. data/test/cases/mixin_test.rb +0 -96
  153. data/test/cases/modules_test.rb +0 -109
  154. data/test/cases/multiple_db_test.rb +0 -85
  155. data/test/cases/named_scope_test.rb +0 -372
  156. data/test/cases/nested_attributes_test.rb +0 -840
  157. data/test/cases/pk_test.rb +0 -119
  158. data/test/cases/pooled_connections_test.rb +0 -103
  159. data/test/cases/query_cache_test.rb +0 -129
  160. data/test/cases/readonly_test.rb +0 -107
  161. data/test/cases/reflection_test.rb +0 -234
  162. data/test/cases/reload_models_test.rb +0 -22
  163. data/test/cases/repair_helper.rb +0 -50
  164. data/test/cases/reserved_word_test_mysql.rb +0 -176
  165. data/test/cases/sanitize_test.rb +0 -25
  166. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  167. data/test/cases/schema_dumper_test.rb +0 -211
  168. data/test/cases/schema_test_postgresql.rb +0 -178
  169. data/test/cases/serialization_test.rb +0 -47
  170. data/test/cases/sp_test_mysql.rb +0 -16
  171. data/test/cases/synonym_test_oracle.rb +0 -17
  172. data/test/cases/timestamp_test.rb +0 -75
  173. data/test/cases/transactions_test.rb +0 -543
  174. data/test/cases/unconnected_test.rb +0 -32
  175. data/test/cases/validations_i18n_test.rb +0 -925
  176. data/test/cases/validations_test.rb +0 -1684
  177. data/test/cases/xml_serialization_test.rb +0 -240
  178. data/test/cases/yaml_serialization_test.rb +0 -11
  179. data/test/config.rb +0 -5
  180. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  181. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  182. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  183. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  184. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  185. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  186. data/test/connections/native_db2/connection.rb +0 -25
  187. data/test/connections/native_firebird/connection.rb +0 -26
  188. data/test/connections/native_frontbase/connection.rb +0 -27
  189. data/test/connections/native_mysql/connection.rb +0 -25
  190. data/test/connections/native_openbase/connection.rb +0 -21
  191. data/test/connections/native_oracle/connection.rb +0 -27
  192. data/test/connections/native_postgresql/connection.rb +0 -21
  193. data/test/connections/native_sqlite/connection.rb +0 -25
  194. data/test/connections/native_sqlite3/connection.rb +0 -25
  195. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  196. data/test/connections/native_sybase/connection.rb +0 -23
  197. data/test/fixtures/accounts.yml +0 -29
  198. data/test/fixtures/all/developers.yml +0 -0
  199. data/test/fixtures/all/people.csv +0 -0
  200. data/test/fixtures/all/tasks.yml +0 -0
  201. data/test/fixtures/author_addresses.yml +0 -5
  202. data/test/fixtures/author_favorites.yml +0 -4
  203. data/test/fixtures/authors.yml +0 -9
  204. data/test/fixtures/binaries.yml +0 -132
  205. data/test/fixtures/books.yml +0 -7
  206. data/test/fixtures/categories.yml +0 -14
  207. data/test/fixtures/categories/special_categories.yml +0 -9
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  209. data/test/fixtures/categories_ordered.yml +0 -7
  210. data/test/fixtures/categories_posts.yml +0 -23
  211. data/test/fixtures/categorizations.yml +0 -17
  212. data/test/fixtures/clubs.yml +0 -6
  213. data/test/fixtures/comments.yml +0 -59
  214. data/test/fixtures/companies.yml +0 -56
  215. data/test/fixtures/computers.yml +0 -4
  216. data/test/fixtures/courses.yml +0 -7
  217. data/test/fixtures/customers.yml +0 -26
  218. data/test/fixtures/developers.yml +0 -21
  219. data/test/fixtures/developers_projects.yml +0 -17
  220. data/test/fixtures/edges.yml +0 -6
  221. data/test/fixtures/entrants.yml +0 -14
  222. data/test/fixtures/faces.yml +0 -11
  223. data/test/fixtures/fk_test_has_fk.yml +0 -3
  224. data/test/fixtures/fk_test_has_pk.yml +0 -2
  225. data/test/fixtures/funny_jokes.yml +0 -10
  226. data/test/fixtures/interests.yml +0 -33
  227. data/test/fixtures/items.yml +0 -4
  228. data/test/fixtures/jobs.yml +0 -7
  229. data/test/fixtures/legacy_things.yml +0 -3
  230. data/test/fixtures/mateys.yml +0 -4
  231. data/test/fixtures/member_types.yml +0 -6
  232. data/test/fixtures/members.yml +0 -6
  233. data/test/fixtures/memberships.yml +0 -20
  234. data/test/fixtures/men.yml +0 -5
  235. data/test/fixtures/minimalistics.yml +0 -2
  236. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  237. data/test/fixtures/mixins.yml +0 -29
  238. data/test/fixtures/movies.yml +0 -7
  239. data/test/fixtures/naked/csv/accounts.csv +0 -1
  240. data/test/fixtures/naked/yml/accounts.yml +0 -1
  241. data/test/fixtures/naked/yml/companies.yml +0 -1
  242. data/test/fixtures/naked/yml/courses.yml +0 -1
  243. data/test/fixtures/organizations.yml +0 -5
  244. data/test/fixtures/owners.yml +0 -7
  245. data/test/fixtures/parrots.yml +0 -27
  246. data/test/fixtures/parrots_pirates.yml +0 -7
  247. data/test/fixtures/people.yml +0 -15
  248. data/test/fixtures/pets.yml +0 -14
  249. data/test/fixtures/pirates.yml +0 -9
  250. data/test/fixtures/polymorphic_designs.yml +0 -19
  251. data/test/fixtures/polymorphic_prices.yml +0 -19
  252. data/test/fixtures/posts.yml +0 -52
  253. data/test/fixtures/price_estimates.yml +0 -7
  254. data/test/fixtures/projects.yml +0 -7
  255. data/test/fixtures/readers.yml +0 -9
  256. data/test/fixtures/references.yml +0 -17
  257. data/test/fixtures/reserved_words/distinct.yml +0 -5
  258. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  259. data/test/fixtures/reserved_words/group.yml +0 -14
  260. data/test/fixtures/reserved_words/select.yml +0 -8
  261. data/test/fixtures/reserved_words/values.yml +0 -7
  262. data/test/fixtures/ships.yml +0 -5
  263. data/test/fixtures/sponsors.yml +0 -9
  264. data/test/fixtures/subscribers.yml +0 -7
  265. data/test/fixtures/subscriptions.yml +0 -12
  266. data/test/fixtures/taggings.yml +0 -28
  267. data/test/fixtures/tags.yml +0 -7
  268. data/test/fixtures/tasks.yml +0 -7
  269. data/test/fixtures/tees.yml +0 -4
  270. data/test/fixtures/ties.yml +0 -4
  271. data/test/fixtures/topics.yml +0 -42
  272. data/test/fixtures/toys.yml +0 -4
  273. data/test/fixtures/treasures.yml +0 -10
  274. data/test/fixtures/vertices.yml +0 -4
  275. data/test/fixtures/warehouse-things.yml +0 -3
  276. data/test/fixtures/zines.yml +0 -5
  277. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  278. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  279. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  280. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  281. data/test/migrations/duplicate/3_foo.rb +0 -7
  282. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  283. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  284. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  285. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  286. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  287. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  288. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  289. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  290. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  291. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  292. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  293. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  294. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  295. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  296. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  297. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  298. data/test/models/author.rb +0 -151
  299. data/test/models/auto_id.rb +0 -4
  300. data/test/models/binary.rb +0 -2
  301. data/test/models/bird.rb +0 -9
  302. data/test/models/book.rb +0 -4
  303. data/test/models/categorization.rb +0 -5
  304. data/test/models/category.rb +0 -34
  305. data/test/models/citation.rb +0 -6
  306. data/test/models/club.rb +0 -13
  307. data/test/models/column_name.rb +0 -3
  308. data/test/models/comment.rb +0 -29
  309. data/test/models/company.rb +0 -173
  310. data/test/models/company_in_module.rb +0 -78
  311. data/test/models/computer.rb +0 -3
  312. data/test/models/contact.rb +0 -16
  313. data/test/models/contract.rb +0 -5
  314. data/test/models/course.rb +0 -3
  315. data/test/models/customer.rb +0 -73
  316. data/test/models/default.rb +0 -2
  317. data/test/models/developer.rb +0 -101
  318. data/test/models/edge.rb +0 -5
  319. data/test/models/entrant.rb +0 -3
  320. data/test/models/essay.rb +0 -3
  321. data/test/models/event.rb +0 -3
  322. data/test/models/event_author.rb +0 -8
  323. data/test/models/face.rb +0 -7
  324. data/test/models/guid.rb +0 -2
  325. data/test/models/interest.rb +0 -5
  326. data/test/models/invoice.rb +0 -4
  327. data/test/models/item.rb +0 -7
  328. data/test/models/job.rb +0 -5
  329. data/test/models/joke.rb +0 -3
  330. data/test/models/keyboard.rb +0 -3
  331. data/test/models/legacy_thing.rb +0 -3
  332. data/test/models/line_item.rb +0 -3
  333. data/test/models/man.rb +0 -9
  334. data/test/models/matey.rb +0 -4
  335. data/test/models/member.rb +0 -12
  336. data/test/models/member_detail.rb +0 -5
  337. data/test/models/member_type.rb +0 -3
  338. data/test/models/membership.rb +0 -9
  339. data/test/models/minimalistic.rb +0 -2
  340. data/test/models/mixed_case_monkey.rb +0 -3
  341. data/test/models/movie.rb +0 -5
  342. data/test/models/order.rb +0 -4
  343. data/test/models/organization.rb +0 -6
  344. data/test/models/owner.rb +0 -5
  345. data/test/models/parrot.rb +0 -22
  346. data/test/models/person.rb +0 -16
  347. data/test/models/pet.rb +0 -5
  348. data/test/models/pirate.rb +0 -80
  349. data/test/models/polymorphic_design.rb +0 -3
  350. data/test/models/polymorphic_price.rb +0 -3
  351. data/test/models/post.rb +0 -102
  352. data/test/models/price_estimate.rb +0 -3
  353. data/test/models/project.rb +0 -30
  354. data/test/models/reader.rb +0 -4
  355. data/test/models/reference.rb +0 -4
  356. data/test/models/reply.rb +0 -46
  357. data/test/models/ship.rb +0 -19
  358. data/test/models/ship_part.rb +0 -7
  359. data/test/models/sponsor.rb +0 -4
  360. data/test/models/subject.rb +0 -4
  361. data/test/models/subscriber.rb +0 -8
  362. data/test/models/subscription.rb +0 -4
  363. data/test/models/tag.rb +0 -7
  364. data/test/models/tagging.rb +0 -10
  365. data/test/models/task.rb +0 -3
  366. data/test/models/tee.rb +0 -4
  367. data/test/models/tie.rb +0 -4
  368. data/test/models/topic.rb +0 -80
  369. data/test/models/toy.rb +0 -6
  370. data/test/models/treasure.rb +0 -8
  371. data/test/models/vertex.rb +0 -9
  372. data/test/models/warehouse_thing.rb +0 -5
  373. data/test/models/zine.rb +0 -3
  374. data/test/schema/mysql_specific_schema.rb +0 -31
  375. data/test/schema/postgresql_specific_schema.rb +0 -114
  376. data/test/schema/schema.rb +0 -550
  377. data/test/schema/schema2.rb +0 -6
  378. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -1,4 +1,5 @@
1
1
  require 'active_record/connection_adapters/abstract_adapter'
2
+ require 'active_support/core_ext/kernel/requires'
2
3
 
3
4
  begin
4
5
  require_library_or_gem 'pg'
@@ -261,12 +262,20 @@ module ActiveRecord
261
262
  true
262
263
  end
263
264
 
264
- # Enable standard-conforming strings if available.
265
- def set_standard_conforming_strings
266
- old, self.client_min_messages = client_min_messages, 'panic'
267
- execute('SET standard_conforming_strings = on') rescue nil
268
- ensure
269
- self.client_min_messages = old
265
+ # Does PostgreSQL support standard conforming strings?
266
+ def supports_standard_conforming_strings?
267
+ # Temporarily set the client message level above error to prevent unintentional
268
+ # error messages in the logs when working on a PostgreSQL database server that
269
+ # does not support standard conforming strings.
270
+ client_min_messages_old = client_min_messages
271
+ self.client_min_messages = 'panic'
272
+
273
+ # postgres-pr does not raise an exception when client_min_messages is set higher
274
+ # than error and "SHOW standard_conforming_strings" fails, but returns an empty
275
+ # PGresult instead.
276
+ has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
277
+ self.client_min_messages = client_min_messages_old
278
+ has_support
270
279
  end
271
280
 
272
281
  def supports_insert_with_returning?
@@ -290,7 +299,7 @@ module ActiveRecord
290
299
  # QUOTING ==================================================
291
300
 
292
301
  # Escapes binary strings for bytea input to the database.
293
- def escape_bytea(original_value)
302
+ def escape_bytea(value)
294
303
  if @connection.respond_to?(:escape_bytea)
295
304
  self.class.instance_eval do
296
305
  define_method(:escape_bytea) do |value|
@@ -314,40 +323,62 @@ module ActiveRecord
314
323
  end
315
324
  end
316
325
  end
317
- escape_bytea(original_value)
326
+ escape_bytea(value)
318
327
  end
319
328
 
320
329
  # Unescapes bytea output from a database to the binary string it represents.
321
330
  # NOTE: This is NOT an inverse of escape_bytea! This is only to be used
322
331
  # on escaped binary output from database drive.
323
- def unescape_bytea(original_value)
332
+ def unescape_bytea(value)
324
333
  # In each case, check if the value actually is escaped PostgreSQL bytea output
325
334
  # or an unescaped Active Record attribute that was just written.
326
- if @connection.respond_to?(:unescape_bytea)
335
+ if PGconn.respond_to?(:unescape_bytea)
327
336
  self.class.instance_eval do
328
337
  define_method(:unescape_bytea) do |value|
329
- @connection.unescape_bytea(value) if value
338
+ if value =~ /\\\d{3}/
339
+ PGconn.unescape_bytea(value)
340
+ else
341
+ value
342
+ end
330
343
  end
331
344
  end
332
- elsif PGconn.respond_to?(:unescape_bytea)
345
+ else
333
346
  self.class.instance_eval do
334
347
  define_method(:unescape_bytea) do |value|
335
- PGconn.unescape_bytea(value) if value
348
+ if value =~ /\\\d{3}/
349
+ result = ''
350
+ i, max = 0, value.size
351
+ while i < max
352
+ char = value[i]
353
+ if char == ?\\
354
+ if value[i+1] == ?\\
355
+ char = ?\\
356
+ i += 1
357
+ else
358
+ char = value[i+1..i+3].oct
359
+ i += 3
360
+ end
361
+ end
362
+ result << char
363
+ i += 1
364
+ end
365
+ result
366
+ else
367
+ value
368
+ end
336
369
  end
337
370
  end
338
- else
339
- raise 'Your PostgreSQL connection does not support unescape_bytea. Try upgrading to pg 0.9.0 or later.'
340
371
  end
341
- unescape_bytea(original_value)
372
+ unescape_bytea(value)
342
373
  end
343
374
 
344
375
  # Quotes PostgreSQL-specific data types for SQL input.
345
376
  def quote(value, column = nil) #:nodoc:
346
377
  if value.kind_of?(String) && column && column.type == :binary
347
- "'#{escape_bytea(value)}'"
348
- elsif value.kind_of?(String) && column && column.sql_type == 'xml'
349
- "xml '#{quote_string(value)}'"
350
- elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
378
+ "#{quoted_string_prefix}'#{escape_bytea(value)}'"
379
+ elsif value.kind_of?(String) && column && column.sql_type =~ /^xml$/
380
+ "xml E'#{quote_string(value)}'"
381
+ elsif value.kind_of?(Numeric) && column && column.sql_type =~ /^money$/
351
382
  # Not truly string input, so doesn't require (or allow) escape string syntax.
352
383
  "'#{value.to_s}'"
353
384
  elsif value.kind_of?(String) && column && column.sql_type =~ /^bit/
@@ -363,7 +394,7 @@ module ActiveRecord
363
394
  end
364
395
 
365
396
  # Quotes strings for use in SQL input in the postgres driver for better performance.
366
- def quote_string(original_value) #:nodoc:
397
+ def quote_string(s) #:nodoc:
367
398
  if @connection.respond_to?(:escape)
368
399
  self.class.instance_eval do
369
400
  define_method(:quote_string) do |s|
@@ -383,7 +414,7 @@ module ActiveRecord
383
414
  remove_method(:quote_string)
384
415
  end
385
416
  end
386
- quote_string(original_value)
417
+ quote_string(s)
387
418
  end
388
419
 
389
420
  # Checks the following cases:
@@ -479,6 +510,7 @@ module ActiveRecord
479
510
  end
480
511
  end
481
512
  end
513
+ alias :create :insert
482
514
 
483
515
  # create a 2D array representing the result set
484
516
  def result_as_array(res) #:nodoc:
@@ -859,12 +891,9 @@ module ActiveRecord
859
891
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
860
892
  end
861
893
 
862
- def remove_index!(table_name, index_name) #:nodoc:
863
- execute "DROP INDEX #{quote_table_name(index_name)}"
864
- end
865
-
866
- def index_name_length
867
- 63
894
+ # Drops an index from a table.
895
+ def remove_index(table_name, options = {})
896
+ execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}"
868
897
  end
869
898
 
870
899
  # Maps logical Rails types to PostgreSQL-specific data types.
@@ -900,20 +929,6 @@ module ActiveRecord
900
929
  sql << order_columns * ', '
901
930
  end
902
931
 
903
- # Returns an ORDER BY clause for the passed order option.
904
- #
905
- # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
906
- # by wrapping the +sql+ string as a sub-select and ordering in that query.
907
- def add_order_by_for_association_limiting!(sql, options) #:nodoc:
908
- return sql if options[:order].blank?
909
-
910
- order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
911
- order.map! { |s| 'DESC' if s =~ /\bdesc$/i }
912
- order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{s}" }.join(', ')
913
-
914
- sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
915
- end
916
-
917
932
  protected
918
933
  # Returns the version of the connected PostgreSQL version.
919
934
  def postgresql_version
@@ -931,6 +946,17 @@ module ActiveRecord
931
946
  end
932
947
  end
933
948
 
949
+ def translate_exception(exception, message)
950
+ case exception.message
951
+ when /duplicate key value violates unique constraint/
952
+ RecordNotUnique.new(message, exception)
953
+ when /violates foreign key constraint/
954
+ InvalidForeignKey.new(message, exception)
955
+ else
956
+ super
957
+ end
958
+ end
959
+
934
960
  private
935
961
  # The internal PostgreSQL identifier of the money data type.
936
962
  MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
@@ -944,6 +970,17 @@ module ActiveRecord
944
970
  # Ignore async_exec and async_query when using postgres-pr.
945
971
  @async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
946
972
 
973
+ # Use escape string syntax if available. We cannot do this lazily when encountering
974
+ # the first string, because that could then break any transactions in progress.
975
+ # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
976
+ # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
977
+ # support escape string syntax. Don't override the inherited quoted_string_prefix.
978
+ if supports_standard_conforming_strings?
979
+ self.class.instance_eval do
980
+ define_method(:quoted_string_prefix) { 'E' }
981
+ end
982
+ end
983
+
947
984
  # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
948
985
  # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
949
986
  # should know about this but can't detect it there, so deal with it here.
@@ -961,7 +998,7 @@ module ActiveRecord
961
998
  configure_connection
962
999
  end
963
1000
 
964
- # Configures the encoding, verbosity, and schema search path of the connection.
1001
+ # Configures the encoding, verbosity, schema search path, and time zone of the connection.
965
1002
  # This is called by #connect and should not be called manually.
966
1003
  def configure_connection
967
1004
  if @config[:encoding]
@@ -973,9 +1010,10 @@ module ActiveRecord
973
1010
  end
974
1011
  self.client_min_messages = @config[:min_messages] if @config[:min_messages]
975
1012
  self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
976
-
977
- # Use standard-conforming strings if available so we don't have to do the E'...' dance.
978
- set_standard_conforming_strings
1013
+
1014
+ # If using ActiveRecord's time zone support configure the connection to return
1015
+ # TIMESTAMP WITH ZONE types in UTC.
1016
+ execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc
979
1017
  end
980
1018
 
981
1019
  # Returns the current ID of a table's sequence.
@@ -24,11 +24,17 @@ module ActiveRecord
24
24
 
25
25
  module ConnectionAdapters #:nodoc:
26
26
  class SQLite3Adapter < SQLiteAdapter # :nodoc:
27
- def table_structure(table_name)
28
- @connection.table_info(quote_table_name(table_name)).tap do |structure|
29
- raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
27
+
28
+ # Returns the current database encoding format as a string, eg: 'UTF-8'
29
+ def encoding
30
+ if @connection.respond_to?(:encoding)
31
+ @connection.encoding[0]['encoding']
32
+ else
33
+ encoding = @connection.send(:get_query_pragma, 'encoding')
34
+ encoding[0]['encoding']
30
35
  end
31
36
  end
37
+
32
38
  end
33
39
  end
34
40
  end
@@ -1,51 +1,21 @@
1
- # encoding: binary
2
1
  require 'active_record/connection_adapters/abstract_adapter'
2
+ require 'active_support/core_ext/kernel/requires'
3
3
 
4
4
  module ActiveRecord
5
5
  class Base
6
6
  class << self
7
- # Establishes a connection to the database that's used by all Active Record objects
8
- def sqlite_connection(config) # :nodoc:
9
- parse_sqlite_config!(config)
10
-
11
- unless self.class.const_defined?(:SQLite)
12
- require_library_or_gem(config[:adapter])
13
-
14
- db = SQLite::Database.new(config[:database], 0)
15
- db.show_datatypes = "ON" if !defined? SQLite::Version
16
- db.results_as_hash = true if defined? SQLite::Version
17
- db.type_translation = false
18
-
19
- message = "Support for SQLite2Adapter and DeprecatedSQLiteAdapter has been removed from Rails 3. "
20
- message << "You should migrate to SQLite 3+ or use the plugin from git://github.com/rails/sqlite2_adapter.git with Rails 3."
21
- ActiveSupport::Deprecation.warn(message)
22
-
23
- # "Downgrade" deprecated sqlite API
24
- if SQLite.const_defined?(:Version)
25
- ConnectionAdapters::SQLite2Adapter.new(db, logger, config)
26
- else
27
- ConnectionAdapters::DeprecatedSQLiteAdapter.new(db, logger, config)
28
- end
29
- end
30
- end
31
-
32
7
  private
33
8
  def parse_sqlite_config!(config)
34
- if config.include?(:dbfile)
35
- ActiveSupport::Deprecation.warn "Please update config/database.yml to use 'database' instead of 'dbfile'"
36
- end
37
-
38
- config[:database] ||= config[:dbfile]
39
9
  # Require database.
40
10
  unless config[:database]
41
11
  raise ArgumentError, "No database file specified. Missing argument: database"
42
12
  end
43
13
 
44
- # Allow database path relative to RAILS_ROOT, but only if
14
+ # Allow database path relative to Rails.root, but only if
45
15
  # the database path is not the special path that tells
46
16
  # Sqlite to build a database only in memory.
47
- if Object.const_defined?(:RAILS_ROOT) && ':memory:' != config[:database]
48
- config[:database] = File.expand_path(config[:database], RAILS_ROOT)
17
+ if defined?(Rails.root) && ':memory:' != config[:database]
18
+ config[:database] = File.expand_path(config[:database], Rails.root)
49
19
  end
50
20
  end
51
21
  end
@@ -55,7 +25,6 @@ module ActiveRecord
55
25
  class SQLiteColumn < Column #:nodoc:
56
26
  class << self
57
27
  def string_to_binary(value)
58
- value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
59
28
  value.gsub(/\0|\%/n) do |b|
60
29
  case b
61
30
  when "\0" then "%00"
@@ -65,7 +34,6 @@ module ActiveRecord
65
34
  end
66
35
 
67
36
  def binary_to_string(value)
68
- value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
69
37
  value.gsub(/%00|%25/n) do |b|
70
38
  case b
71
39
  when "%00" then "\0"
@@ -123,7 +91,7 @@ module ActiveRecord
123
91
  def supports_add_column?
124
92
  sqlite_version >= '3.1.6'
125
93
  end
126
-
94
+
127
95
  def disconnect!
128
96
  super
129
97
  @connection.close rescue nil
@@ -162,7 +130,17 @@ module ActiveRecord
162
130
  end
163
131
 
164
132
  def quote_column_name(name) #:nodoc:
165
- %Q("#{name.to_s.gsub('"', '""')}")
133
+ %Q("#{name}")
134
+ end
135
+
136
+ # Quote date/time values for use in SQL input. Includes microseconds
137
+ # if the value is a Time responding to usec.
138
+ def quoted_date(value) #:nodoc:
139
+ if value.acts_like?(:time) && value.respond_to?(:usec)
140
+ "#{super}.#{sprintf("%06d", value.usec)}"
141
+ else
142
+ super
143
+ end
166
144
  end
167
145
 
168
146
 
@@ -185,6 +163,7 @@ module ActiveRecord
185
163
  def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
186
164
  super || @connection.last_insert_row_id
187
165
  end
166
+ alias :create :insert_sql
188
167
 
189
168
  def select_rows(sql, name = nil)
190
169
  execute(sql, name).map do |row|
@@ -204,12 +183,6 @@ module ActiveRecord
204
183
  catch_schema_changes { @connection.rollback }
205
184
  end
206
185
 
207
- # SELECT ... FOR UPDATE is redundant since the table is locked.
208
- def add_lock!(sql, options) #:nodoc:
209
- sql
210
- end
211
-
212
-
213
186
  # SCHEMA STATEMENTS ========================================
214
187
 
215
188
  def tables(name = nil) #:nodoc:
@@ -244,12 +217,12 @@ module ActiveRecord
244
217
  column ? column['name'] : nil
245
218
  end
246
219
 
247
- def remove_index!(table_name, index_name) #:nodoc:
248
- execute "DROP INDEX #{quote_column_name(index_name)}"
220
+ def remove_index(table_name, options={}) #:nodoc:
221
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
249
222
  end
250
223
 
251
224
  def rename_table(name, new_name)
252
- execute "ALTER TABLE #{name} RENAME TO #{new_name}"
225
+ execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
253
226
  end
254
227
 
255
228
  # See: http://www.sqlite.org/lang_altertable.html
@@ -269,7 +242,6 @@ module ActiveRecord
269
242
  end
270
243
 
271
244
  def remove_column(table_name, *column_names) #:nodoc:
272
- raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
273
245
  column_names.flatten.each do |column_name|
274
246
  alter_table(table_name) do |definition|
275
247
  definition.columns.delete(definition[column_name])
@@ -312,8 +284,8 @@ module ActiveRecord
312
284
  alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
313
285
  end
314
286
 
315
- def empty_insert_statement(table_name)
316
- "INSERT INTO #{table_name} VALUES(NULL)"
287
+ def empty_insert_statement_value
288
+ "VALUES(NULL)"
317
289
  end
318
290
 
319
291
  protected
@@ -330,9 +302,9 @@ module ActiveRecord
330
302
  end
331
303
 
332
304
  def table_structure(table_name)
333
- execute("PRAGMA table_info(#{quote_table_name(table_name)})").tap do |structure|
334
- raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
335
- end
305
+ structure = @connection.table_info(quote_table_name(table_name))
306
+ raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
307
+ structure
336
308
  end
337
309
 
338
310
  def alter_table(table_name, options = {}) #:nodoc:
@@ -360,7 +332,7 @@ module ActiveRecord
360
332
  (options[:rename][column.name] ||
361
333
  options[:rename][column.name.to_sym] ||
362
334
  column.name) : column.name
363
-
335
+
364
336
  @definition.column(column_name, column.type,
365
337
  :limit => column.limit, :default => column.default,
366
338
  :null => column.null)
@@ -436,19 +408,16 @@ module ActiveRecord
436
408
  'INTEGER PRIMARY KEY NOT NULL'.freeze
437
409
  end
438
410
  end
439
- end
440
411
 
441
- class SQLite2Adapter < SQLiteAdapter # :nodoc:
442
- def rename_table(name, new_name)
443
- move_table(name, new_name)
444
- end
445
- end
412
+ def translate_exception(exception, message)
413
+ case exception.message
414
+ when /column(s)? .* (is|are) not unique/
415
+ RecordNotUnique.new(message, exception)
416
+ else
417
+ super
418
+ end
419
+ end
446
420
 
447
- class DeprecatedSQLiteAdapter < SQLite2Adapter # :nodoc:
448
- def insert(sql, name = nil, pk = nil, id_value = nil)
449
- execute(sql, name = nil)
450
- id_value || @connection.last_insert_rowid
451
- end
452
421
  end
453
422
  end
454
423
  end