activerecord_csi 2.3.5.p6

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 (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,434 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module SchemaStatements
4
+ # Returns a Hash of mappings from the abstract data types to the native
5
+ # database types. See TableDefinition#column for details on the recognized
6
+ # abstract data types.
7
+ def native_database_types
8
+ {}
9
+ end
10
+
11
+ # This is the maximum length a table alias can be
12
+ def table_alias_length
13
+ 255
14
+ end
15
+
16
+ # Truncates a table alias according to the limits of the current adapter.
17
+ def table_alias_for(table_name)
18
+ table_name[0..table_alias_length-1].gsub(/\./, '_')
19
+ end
20
+
21
+ # def tables(name = nil) end
22
+
23
+ def table_exists?(table_name)
24
+ tables.include?(table_name.to_s)
25
+ end
26
+
27
+ # Returns an array of indexes for the given table.
28
+ # def indexes(table_name, name = nil) end
29
+
30
+ # Returns an array of Column objects for the table specified by +table_name+.
31
+ # See the concrete implementation for details on the expected parameter values.
32
+ def columns(table_name, name = nil) end
33
+
34
+ # Creates a new table with the name +table_name+. +table_name+ may either
35
+ # be a String or a Symbol.
36
+ #
37
+ # There are two ways to work with +create_table+. You can use the block
38
+ # form or the regular form, like this:
39
+ #
40
+ # === Block form
41
+ # # create_table() passes a TableDefinition object to the block.
42
+ # # This form will not only create the table, but also columns for the
43
+ # # table.
44
+ # create_table(:suppliers) do |t|
45
+ # t.column :name, :string, :limit => 60
46
+ # # Other fields here
47
+ # end
48
+ #
49
+ # === Regular form
50
+ # # Creates a table called 'suppliers' with no columns.
51
+ # create_table(:suppliers)
52
+ # # Add a column to 'suppliers'.
53
+ # add_column(:suppliers, :name, :string, {:limit => 60})
54
+ #
55
+ # The +options+ hash can include the following keys:
56
+ # [<tt>:id</tt>]
57
+ # Whether to automatically add a primary key column. Defaults to true.
58
+ # Join tables for +has_and_belongs_to_many+ should set <tt>:id => false</tt>.
59
+ # [<tt>:primary_key</tt>]
60
+ # The name of the primary key, if one is to be added automatically.
61
+ # Defaults to +id+.
62
+ # [<tt>:options</tt>]
63
+ # Any extra options you want appended to the table definition.
64
+ # [<tt>:temporary</tt>]
65
+ # Make a temporary table.
66
+ # [<tt>:force</tt>]
67
+ # Set to true to drop the table before creating it.
68
+ # Defaults to false.
69
+ #
70
+ # ===== Examples
71
+ # ====== Add a backend specific option to the generated SQL (MySQL)
72
+ # create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
73
+ # generates:
74
+ # CREATE TABLE suppliers (
75
+ # id int(11) DEFAULT NULL auto_increment PRIMARY KEY
76
+ # ) ENGINE=InnoDB DEFAULT CHARSET=utf8
77
+ #
78
+ # ====== Rename the primary key column
79
+ # create_table(:objects, :primary_key => 'guid') do |t|
80
+ # t.column :name, :string, :limit => 80
81
+ # end
82
+ # generates:
83
+ # CREATE TABLE objects (
84
+ # guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
85
+ # name varchar(80)
86
+ # )
87
+ #
88
+ # ====== Do not add a primary key column
89
+ # create_table(:categories_suppliers, :id => false) do |t|
90
+ # t.column :category_id, :integer
91
+ # t.column :supplier_id, :integer
92
+ # end
93
+ # generates:
94
+ # CREATE TABLE categories_suppliers (
95
+ # category_id int,
96
+ # supplier_id int
97
+ # )
98
+ #
99
+ # See also TableDefinition#column for details on how to create columns.
100
+ def create_table(table_name, options = {})
101
+ table_definition = TableDefinition.new(self)
102
+ table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
103
+
104
+ yield table_definition
105
+
106
+ if options[:force] && table_exists?(table_name)
107
+ drop_table(table_name, options)
108
+ end
109
+
110
+ create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
111
+ create_sql << "#{quote_table_name(table_name)} ("
112
+ create_sql << table_definition.to_sql
113
+ create_sql << ") #{options[:options]}"
114
+ execute create_sql
115
+ end
116
+
117
+ # A block for changing columns in +table+.
118
+ #
119
+ # === Example
120
+ # # change_table() yields a Table instance
121
+ # change_table(:suppliers) do |t|
122
+ # t.column :name, :string, :limit => 60
123
+ # # Other column alterations here
124
+ # end
125
+ #
126
+ # ===== Examples
127
+ # ====== Add a column
128
+ # change_table(:suppliers) do |t|
129
+ # t.column :name, :string, :limit => 60
130
+ # end
131
+ #
132
+ # ====== Add 2 integer columns
133
+ # change_table(:suppliers) do |t|
134
+ # t.integer :width, :height, :null => false, :default => 0
135
+ # end
136
+ #
137
+ # ====== Add created_at/updated_at columns
138
+ # change_table(:suppliers) do |t|
139
+ # t.timestamps
140
+ # end
141
+ #
142
+ # ====== Add a foreign key column
143
+ # change_table(:suppliers) do |t|
144
+ # t.references :company
145
+ # end
146
+ #
147
+ # Creates a <tt>company_id(integer)</tt> column
148
+ #
149
+ # ====== Add a polymorphic foreign key column
150
+ # change_table(:suppliers) do |t|
151
+ # t.belongs_to :company, :polymorphic => true
152
+ # end
153
+ #
154
+ # Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
155
+ #
156
+ # ====== Remove a column
157
+ # change_table(:suppliers) do |t|
158
+ # t.remove :company
159
+ # end
160
+ #
161
+ # ====== Remove several columns
162
+ # change_table(:suppliers) do |t|
163
+ # t.remove :company_id
164
+ # t.remove :width, :height
165
+ # end
166
+ #
167
+ # ====== Remove an index
168
+ # change_table(:suppliers) do |t|
169
+ # t.remove_index :company_id
170
+ # end
171
+ #
172
+ # See also Table for details on
173
+ # all of the various column transformation
174
+ def change_table(table_name)
175
+ yield Table.new(table_name, self)
176
+ end
177
+
178
+ # Renames a table.
179
+ # ===== Example
180
+ # rename_table('octopuses', 'octopi')
181
+ def rename_table(table_name, new_name)
182
+ raise NotImplementedError, "rename_table is not implemented"
183
+ end
184
+
185
+ # Drops a table from the database.
186
+ def drop_table(table_name, options = {})
187
+ execute "DROP TABLE #{quote_table_name(table_name)}"
188
+ end
189
+
190
+ # Adds a new column to the named table.
191
+ # See TableDefinition#column for details of the options you can use.
192
+ def add_column(table_name, column_name, type, options = {})
193
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
194
+ add_column_options!(add_column_sql, options)
195
+ execute(add_column_sql)
196
+ end
197
+
198
+ # Removes the column(s) from the table definition.
199
+ # ===== Examples
200
+ # remove_column(:suppliers, :qualification)
201
+ # remove_columns(:suppliers, :qualification, :experience)
202
+ def remove_column(table_name, *column_names)
203
+ column_names.flatten.each do |column_name|
204
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
205
+ end
206
+ end
207
+ alias :remove_columns :remove_column
208
+
209
+ # Changes the column's definition according to the new options.
210
+ # See TableDefinition#column for details of the options you can use.
211
+ # ===== Examples
212
+ # change_column(:suppliers, :name, :string, :limit => 80)
213
+ # change_column(:accounts, :description, :text)
214
+ def change_column(table_name, column_name, type, options = {})
215
+ raise NotImplementedError, "change_column is not implemented"
216
+ end
217
+
218
+ # Sets a new default value for a column. If you want to set the default
219
+ # value to +NULL+, you are out of luck. You need to
220
+ # DatabaseStatements#execute the appropriate SQL statement yourself.
221
+ # ===== Examples
222
+ # change_column_default(:suppliers, :qualification, 'new')
223
+ # change_column_default(:accounts, :authorized, 1)
224
+ def change_column_default(table_name, column_name, default)
225
+ raise NotImplementedError, "change_column_default is not implemented"
226
+ end
227
+
228
+ # Renames a column.
229
+ # ===== Example
230
+ # rename_column(:suppliers, :description, :name)
231
+ def rename_column(table_name, column_name, new_column_name)
232
+ raise NotImplementedError, "rename_column is not implemented"
233
+ end
234
+
235
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
236
+ # an Array of Symbols.
237
+ #
238
+ # The index will be named after the table and the first column name,
239
+ # unless you pass <tt>:name</tt> as an option.
240
+ #
241
+ # When creating an index on multiple columns, the first column is used as a name
242
+ # for the index. For example, when you specify an index on two columns
243
+ # [<tt>:first</tt>, <tt>:last</tt>], the DBMS creates an index for both columns as well as an
244
+ # index for the first column <tt>:first</tt>. Using just the first name for this index
245
+ # makes sense, because you will never have to create a singular index with this
246
+ # name.
247
+ #
248
+ # ===== Examples
249
+ # ====== Creating a simple index
250
+ # add_index(:suppliers, :name)
251
+ # generates
252
+ # CREATE INDEX suppliers_name_index ON suppliers(name)
253
+ # ====== Creating a unique index
254
+ # add_index(:accounts, [:branch_id, :party_id], :unique => true)
255
+ # generates
256
+ # CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
257
+ # ====== Creating a named index
258
+ # add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
259
+ # generates
260
+ # CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
261
+ def add_index(table_name, column_name, options = {})
262
+ column_names = Array(column_name)
263
+ index_name = index_name(table_name, :column => column_names)
264
+
265
+ if Hash === options # legacy support, since this param was a string
266
+ index_type = options[:unique] ? "UNIQUE" : ""
267
+ index_name = options[:name] || index_name
268
+ else
269
+ index_type = options
270
+ end
271
+ quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
272
+ execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
273
+ end
274
+
275
+ # Remove the given index from the table.
276
+ #
277
+ # Remove the suppliers_name_index in the suppliers table.
278
+ # remove_index :suppliers, :name
279
+ # Remove the index named accounts_branch_id_index in the accounts table.
280
+ # remove_index :accounts, :column => :branch_id
281
+ # Remove the index named accounts_branch_id_party_id_index in the accounts table.
282
+ # remove_index :accounts, :column => [:branch_id, :party_id]
283
+ # Remove the index named by_branch_party in the accounts table.
284
+ # remove_index :accounts, :name => :by_branch_party
285
+ def remove_index(table_name, options = {})
286
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
287
+ end
288
+
289
+ def index_name(table_name, options) #:nodoc:
290
+ if Hash === options # legacy support
291
+ if options[:column]
292
+ "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
293
+ elsif options[:name]
294
+ options[:name]
295
+ else
296
+ raise ArgumentError, "You must specify the index name"
297
+ end
298
+ else
299
+ index_name(table_name, :column => options)
300
+ end
301
+ end
302
+
303
+ # Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
304
+ # entire structure of the database.
305
+ def structure_dump
306
+ end
307
+
308
+ def dump_schema_information #:nodoc:
309
+ sm_table = ActiveRecord::Migrator.schema_migrations_table_name
310
+ migrated = select_values("SELECT version FROM #{sm_table}")
311
+ migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
312
+ end
313
+
314
+ # Should not be called normally, but this operation is non-destructive.
315
+ # The migrations module handles this automatically.
316
+ def initialize_schema_migrations_table
317
+ sm_table = ActiveRecord::Migrator.schema_migrations_table_name
318
+
319
+ unless tables.detect { |t| t == sm_table }
320
+ create_table(sm_table, :id => false) do |schema_migrations_table|
321
+ schema_migrations_table.column :version, :string, :null => false
322
+ end
323
+ add_index sm_table, :version, :unique => true,
324
+ :name => "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
325
+
326
+ # Backwards-compatibility: if we find schema_info, assume we've
327
+ # migrated up to that point:
328
+ si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
329
+
330
+ if tables.detect { |t| t == si_table }
331
+
332
+ old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
333
+ assume_migrated_upto_version(old_version)
334
+ drop_table(si_table)
335
+ end
336
+ end
337
+ end
338
+
339
+ def assume_migrated_upto_version(version)
340
+ version = version.to_i
341
+ sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
342
+
343
+ migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
344
+ versions = Dir['db/migrate/[0-9]*_*.rb'].map do |filename|
345
+ filename.split('/').last.split('_').first.to_i
346
+ end
347
+
348
+ unless migrated.include?(version)
349
+ execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
350
+ end
351
+
352
+ inserted = Set.new
353
+ (versions - migrated).each do |v|
354
+ if inserted.include?(v)
355
+ raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
356
+ elsif v < version
357
+ execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
358
+ inserted << v
359
+ end
360
+ end
361
+ end
362
+
363
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
364
+ if native = native_database_types[type]
365
+ column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
366
+
367
+ if type == :decimal # ignore limit, use precision and scale
368
+ scale ||= native[:scale]
369
+
370
+ if precision ||= native[:precision]
371
+ if scale
372
+ column_type_sql << "(#{precision},#{scale})"
373
+ else
374
+ column_type_sql << "(#{precision})"
375
+ end
376
+ elsif scale
377
+ raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
378
+ end
379
+
380
+ elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
381
+ column_type_sql << "(#{limit})"
382
+ end
383
+
384
+ column_type_sql
385
+ else
386
+ type
387
+ end
388
+ end
389
+
390
+ def add_column_options!(sql, options) #:nodoc:
391
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
392
+ # must explicitly check for :null to allow change_column to work on migrations
393
+ if options[:null] == false
394
+ sql << " NOT NULL"
395
+ end
396
+ end
397
+
398
+ # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
399
+ # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
400
+ #
401
+ # distinct("posts.id", "posts.created_at desc")
402
+ def distinct(columns, order_by)
403
+ "DISTINCT #{columns}"
404
+ end
405
+
406
+ # ORDER BY clause for the passed order option.
407
+ # PostgreSQL overrides this due to its stricter standards compliance.
408
+ def add_order_by_for_association_limiting!(sql, options)
409
+ sql << " ORDER BY #{options[:order]}"
410
+ end
411
+
412
+ # Adds timestamps (created_at and updated_at) columns to the named table.
413
+ # ===== Examples
414
+ # add_timestamps(:suppliers)
415
+ def add_timestamps(table_name)
416
+ add_column table_name, :created_at, :datetime
417
+ add_column table_name, :updated_at, :datetime
418
+ end
419
+
420
+ # Removes the timestamp columns (created_at and updated_at) from the table definition.
421
+ # ===== Examples
422
+ # remove_timestamps(:suppliers)
423
+ def remove_timestamps(table_name)
424
+ remove_column table_name, :updated_at
425
+ remove_column table_name, :created_at
426
+ end
427
+
428
+ protected
429
+ def options_include_default?(options)
430
+ options.include?(:default) && !(options[:null] == false && options[:default].nil?)
431
+ end
432
+ end
433
+ end
434
+ end
@@ -0,0 +1,241 @@
1
+ require 'benchmark'
2
+ require 'date'
3
+ require 'bigdecimal'
4
+ require 'bigdecimal/util'
5
+
6
+ # TODO: Autoload these files
7
+ require 'active_record/connection_adapters/abstract/schema_definitions'
8
+ require 'active_record/connection_adapters/abstract/schema_statements'
9
+ require 'active_record/connection_adapters/abstract/database_statements'
10
+ require 'active_record/connection_adapters/abstract/quoting'
11
+ require 'active_record/connection_adapters/abstract/connection_pool'
12
+ require 'active_record/connection_adapters/abstract/connection_specification'
13
+ require 'active_record/connection_adapters/abstract/query_cache'
14
+
15
+ module ActiveRecord
16
+ module ConnectionAdapters # :nodoc:
17
+ # ActiveRecord supports multiple database systems. AbstractAdapter and
18
+ # related classes form the abstraction layer which makes this possible.
19
+ # An AbstractAdapter represents a connection to a database, and provides an
20
+ # abstract interface for database-specific functionality such as establishing
21
+ # a connection, escaping values, building the right SQL fragments for ':offset'
22
+ # and ':limit' options, etc.
23
+ #
24
+ # All the concrete database adapters follow the interface laid down in this class.
25
+ # ActiveRecord::Base.connection returns an AbstractAdapter object, which
26
+ # you can use.
27
+ #
28
+ # Most of the methods in the adapter are useful during migrations. Most
29
+ # notably, the instance methods provided by SchemaStatement are very useful.
30
+ class AbstractAdapter
31
+ include Quoting, DatabaseStatements, SchemaStatements
32
+ include QueryCache
33
+ include ActiveSupport::Callbacks
34
+ define_callbacks :checkout, :checkin
35
+
36
+ @@row_even = true
37
+
38
+ def initialize(connection, logger = nil) #:nodoc:
39
+ @connection, @logger = connection, logger
40
+ @runtime = 0
41
+ @last_verification = 0
42
+ @query_cache_enabled = false
43
+ end
44
+
45
+ # Returns the human-readable name of the adapter. Use mixed case - one
46
+ # can always use downcase if needed.
47
+ def adapter_name
48
+ 'Abstract'
49
+ end
50
+
51
+ # Does this adapter support migrations? Backend specific, as the
52
+ # abstract adapter always returns +false+.
53
+ def supports_migrations?
54
+ false
55
+ end
56
+
57
+ # Can this adapter determine the primary key for tables not attached
58
+ # to an ActiveRecord class, such as join tables? Backend specific, as
59
+ # the abstract adapter always returns +false+.
60
+ def supports_primary_key?
61
+ false
62
+ end
63
+
64
+ # Does this adapter support using DISTINCT within COUNT? This is +true+
65
+ # for all adapters except sqlite.
66
+ def supports_count_distinct?
67
+ true
68
+ end
69
+
70
+ # Does this adapter support DDL rollbacks in transactions? That is, would
71
+ # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
72
+ # SQL Server, and others support this. MySQL and others do not.
73
+ def supports_ddl_transactions?
74
+ false
75
+ end
76
+
77
+ # Does this adapter support savepoints? PostgreSQL and MySQL do, SQLite
78
+ # does not.
79
+ def supports_savepoints?
80
+ false
81
+ end
82
+
83
+ # Should primary key values be selected from their corresponding
84
+ # sequence before the insert statement? If true, next_sequence_value
85
+ # is called before each insert to set the record's primary key.
86
+ # This is false for all adapters but Firebird.
87
+ def prefetch_primary_key?(table_name = nil)
88
+ false
89
+ end
90
+
91
+ def reset_runtime #:nodoc:
92
+ rt, @runtime = @runtime, 0
93
+ rt
94
+ end
95
+
96
+ # QUOTING ==================================================
97
+
98
+ # Override to return the quoted table name. Defaults to column quoting.
99
+ def quote_table_name(name)
100
+ quote_column_name(name)
101
+ end
102
+
103
+ # REFERENTIAL INTEGRITY ====================================
104
+
105
+ # Override to turn off referential integrity while executing <tt>&block</tt>.
106
+ def disable_referential_integrity(&block)
107
+ yield
108
+ end
109
+
110
+ # CONNECTION MANAGEMENT ====================================
111
+
112
+ # Checks whether the connection to the database is still active. This includes
113
+ # checking whether the database is actually capable of responding, i.e. whether
114
+ # the connection isn't stale.
115
+ def active?
116
+ @active != false
117
+ end
118
+
119
+ # Disconnects from the database if already connected, and establishes a
120
+ # new connection with the database.
121
+ def reconnect!
122
+ @active = true
123
+ end
124
+
125
+ # Disconnects from the database if already connected. Otherwise, this
126
+ # method does nothing.
127
+ def disconnect!
128
+ @active = false
129
+ end
130
+
131
+ # Reset the state of this connection, directing the DBMS to clear
132
+ # transactions and other connection-related server-side state. Usually a
133
+ # database-dependent operation.
134
+ #
135
+ # The default implementation does nothing; the implementation should be
136
+ # overridden by concrete adapters.
137
+ def reset!
138
+ # this should be overridden by concrete adapters
139
+ end
140
+
141
+ # Returns true if its safe to reload the connection between requests for development mode.
142
+ def requires_reloading?
143
+ true
144
+ end
145
+
146
+ # Checks whether the connection to the database is still active (i.e. not stale).
147
+ # This is done under the hood by calling <tt>active?</tt>. If the connection
148
+ # is no longer active, then this method will reconnect to the database.
149
+ def verify!(*ignored)
150
+ reconnect! unless active?
151
+ end
152
+
153
+ # Provides access to the underlying database driver for this adapter. For
154
+ # example, this method returns a Mysql object in case of MysqlAdapter,
155
+ # and a PGconn object in case of PostgreSQLAdapter.
156
+ #
157
+ # This is useful for when you need to call a proprietary method such as
158
+ # PostgreSQL's lo_* methods.
159
+ def raw_connection
160
+ @connection
161
+ end
162
+
163
+ def open_transactions
164
+ @open_transactions ||= 0
165
+ end
166
+
167
+ def increment_open_transactions
168
+ @open_transactions ||= 0
169
+ @open_transactions += 1
170
+ end
171
+
172
+ def decrement_open_transactions
173
+ @open_transactions -= 1
174
+ end
175
+
176
+ def transaction_joinable=(joinable)
177
+ @transaction_joinable = joinable
178
+ end
179
+
180
+ def create_savepoint
181
+ end
182
+
183
+ def rollback_to_savepoint
184
+ end
185
+
186
+ def release_savepoint
187
+ end
188
+
189
+ def current_savepoint_name
190
+ "active_record_#{open_transactions}"
191
+ end
192
+
193
+ def log_info(sql, name, ms)
194
+ if @logger && @logger.debug?
195
+ name = '%s (%.1fms)' % [name || 'SQL', ms]
196
+ @logger.debug(format_log_entry(name, sql.squeeze(' ')))
197
+ end
198
+ end
199
+
200
+ protected
201
+ def log(sql, name)
202
+ if block_given?
203
+ result = nil
204
+ ms = Benchmark.ms { result = yield }
205
+ @runtime += ms
206
+ log_info(sql, name, ms)
207
+ result
208
+ else
209
+ log_info(sql, name, 0)
210
+ nil
211
+ end
212
+ rescue Exception => e
213
+ # Log message and raise exception.
214
+ # Set last_verification to 0, so that connection gets verified
215
+ # upon reentering the request loop
216
+ @last_verification = 0
217
+ message = "#{e.class.name}: #{e.message}: #{sql}"
218
+ log_info(message, name, 0)
219
+ raise ActiveRecord::StatementInvalid, message
220
+ end
221
+
222
+ def format_log_entry(message, dump = nil)
223
+ if ActiveRecord::Base.colorize_logging
224
+ if @@row_even
225
+ @@row_even = false
226
+ message_color, dump_color = "4;36;1", "0;1"
227
+ else
228
+ @@row_even = true
229
+ message_color, dump_color = "4;35;1", "0"
230
+ end
231
+
232
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
233
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
234
+ log_entry
235
+ else
236
+ "%s %s" % [message, dump]
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end