activerecord 1.0.0 → 2.0.0

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 (311) hide show
  1. data/CHANGELOG +4928 -3
  2. data/README +45 -46
  3. data/RUNNING_UNIT_TESTS +8 -11
  4. data/Rakefile +247 -0
  5. data/install.rb +8 -38
  6. data/lib/active_record/aggregations.rb +64 -49
  7. data/lib/active_record/associations/association_collection.rb +217 -47
  8. data/lib/active_record/associations/association_proxy.rb +159 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
  12. data/lib/active_record/associations/has_many_association.rb +145 -75
  13. data/lib/active_record/associations/has_many_through_association.rb +283 -0
  14. data/lib/active_record/associations/has_one_association.rb +96 -0
  15. data/lib/active_record/associations.rb +1537 -304
  16. data/lib/active_record/attribute_methods.rb +328 -0
  17. data/lib/active_record/base.rb +2001 -588
  18. data/lib/active_record/calculations.rb +269 -0
  19. data/lib/active_record/callbacks.rb +169 -165
  20. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  23. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
  31. data/lib/active_record/fixtures.rb +946 -100
  32. data/lib/active_record/locking/optimistic.rb +144 -0
  33. data/lib/active_record/locking/pessimistic.rb +77 -0
  34. data/lib/active_record/migration.rb +417 -0
  35. data/lib/active_record/observer.rb +142 -32
  36. data/lib/active_record/query_cache.rb +23 -0
  37. data/lib/active_record/reflection.rb +163 -70
  38. data/lib/active_record/schema.rb +58 -0
  39. data/lib/active_record/schema_dumper.rb +171 -0
  40. data/lib/active_record/serialization.rb +98 -0
  41. data/lib/active_record/serializers/json_serializer.rb +71 -0
  42. data/lib/active_record/serializers/xml_serializer.rb +315 -0
  43. data/lib/active_record/timestamp.rb +41 -0
  44. data/lib/active_record/transactions.rb +87 -57
  45. data/lib/active_record/validations.rb +909 -122
  46. data/lib/active_record/vendor/db2.rb +362 -0
  47. data/lib/active_record/vendor/mysql.rb +126 -29
  48. data/lib/active_record/version.rb +9 -0
  49. data/lib/active_record.rb +35 -7
  50. data/lib/activerecord.rb +1 -0
  51. data/test/aaa_create_tables_test.rb +72 -0
  52. data/test/abstract_unit.rb +73 -5
  53. data/test/active_schema_test_mysql.rb +43 -0
  54. data/test/adapter_test.rb +105 -0
  55. data/test/adapter_test_sqlserver.rb +95 -0
  56. data/test/aggregations_test.rb +110 -16
  57. data/test/all.sh +2 -2
  58. data/test/ar_schema_test.rb +33 -0
  59. data/test/association_inheritance_reload.rb +14 -0
  60. data/test/associations/ar_joins_test.rb +0 -0
  61. data/test/associations/callbacks_test.rb +147 -0
  62. data/test/associations/cascaded_eager_loading_test.rb +110 -0
  63. data/test/associations/eager_singularization_test.rb +145 -0
  64. data/test/associations/eager_test.rb +442 -0
  65. data/test/associations/extension_test.rb +47 -0
  66. data/test/associations/inner_join_association_test.rb +88 -0
  67. data/test/associations/join_model_test.rb +553 -0
  68. data/test/associations_test.rb +1930 -267
  69. data/test/attribute_methods_test.rb +146 -0
  70. data/test/base_test.rb +1316 -84
  71. data/test/binary_test.rb +32 -0
  72. data/test/calculations_test.rb +251 -0
  73. data/test/callbacks_test.rb +400 -0
  74. data/test/class_inheritable_attributes_test.rb +3 -4
  75. data/test/column_alias_test.rb +17 -0
  76. data/test/connection_test_firebird.rb +8 -0
  77. data/test/connection_test_mysql.rb +30 -0
  78. data/test/connections/native_db2/connection.rb +25 -0
  79. data/test/connections/native_firebird/connection.rb +26 -0
  80. data/test/connections/native_frontbase/connection.rb +27 -0
  81. data/test/connections/native_mysql/connection.rb +21 -18
  82. data/test/connections/native_openbase/connection.rb +21 -0
  83. data/test/connections/native_oracle/connection.rb +27 -0
  84. data/test/connections/native_postgresql/connection.rb +17 -18
  85. data/test/connections/native_sqlite/connection.rb +17 -16
  86. data/test/connections/native_sqlite3/connection.rb +25 -0
  87. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  88. data/test/connections/native_sybase/connection.rb +23 -0
  89. data/test/copy_table_test_sqlite.rb +69 -0
  90. data/test/datatype_test_postgresql.rb +203 -0
  91. data/test/date_time_test.rb +37 -0
  92. data/test/default_test_firebird.rb +16 -0
  93. data/test/defaults_test.rb +67 -0
  94. data/test/deprecated_finder_test.rb +30 -0
  95. data/test/finder_test.rb +607 -32
  96. data/test/fixtures/accounts.yml +28 -0
  97. data/test/fixtures/all/developers.yml +0 -0
  98. data/test/fixtures/all/people.csv +0 -0
  99. data/test/fixtures/all/tasks.yml +0 -0
  100. data/test/fixtures/author.rb +107 -0
  101. data/test/fixtures/author_favorites.yml +4 -0
  102. data/test/fixtures/authors.yml +7 -0
  103. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  104. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  105. data/test/fixtures/bad_fixtures/blank_line +3 -0
  106. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  107. data/test/fixtures/bad_fixtures/missing_value +1 -0
  108. data/test/fixtures/binaries.yml +132 -0
  109. data/test/fixtures/binary.rb +2 -0
  110. data/test/fixtures/book.rb +4 -0
  111. data/test/fixtures/books.yml +7 -0
  112. data/test/fixtures/categories/special_categories.yml +9 -0
  113. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  114. data/test/fixtures/categories.yml +14 -0
  115. data/test/fixtures/categories_ordered.yml +7 -0
  116. data/test/fixtures/categories_posts.yml +23 -0
  117. data/test/fixtures/categorization.rb +5 -0
  118. data/test/fixtures/categorizations.yml +17 -0
  119. data/test/fixtures/category.rb +26 -0
  120. data/test/fixtures/citation.rb +6 -0
  121. data/test/fixtures/comment.rb +23 -0
  122. data/test/fixtures/comments.yml +59 -0
  123. data/test/fixtures/companies.yml +55 -0
  124. data/test/fixtures/company.rb +81 -4
  125. data/test/fixtures/company_in_module.rb +32 -6
  126. data/test/fixtures/computer.rb +4 -0
  127. data/test/fixtures/computers.yml +4 -0
  128. data/test/fixtures/contact.rb +16 -0
  129. data/test/fixtures/courses.yml +7 -0
  130. data/test/fixtures/customer.rb +28 -3
  131. data/test/fixtures/customers.yml +17 -0
  132. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  133. data/test/fixtures/db_definitions/db2.sql +235 -0
  134. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  135. data/test/fixtures/db_definitions/db22.sql +5 -0
  136. data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
  137. data/test/fixtures/db_definitions/firebird.sql +310 -0
  138. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  139. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  140. data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
  141. data/test/fixtures/db_definitions/frontbase.sql +273 -0
  142. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  143. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  144. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  145. data/test/fixtures/db_definitions/openbase.sql +318 -0
  146. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  148. data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
  149. data/test/fixtures/db_definitions/oracle.sql +330 -0
  150. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  151. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  152. data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
  153. data/test/fixtures/db_definitions/postgresql.sql +217 -38
  154. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/postgresql2.sql +2 -2
  156. data/test/fixtures/db_definitions/schema.rb +354 -0
  157. data/test/fixtures/db_definitions/schema2.rb +11 -0
  158. data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
  159. data/test/fixtures/db_definitions/sqlite.sql +139 -5
  160. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  161. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  162. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  163. data/test/fixtures/db_definitions/sybase.sql +222 -0
  164. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  165. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  166. data/test/fixtures/developer.rb +70 -6
  167. data/test/fixtures/developers.yml +21 -0
  168. data/test/fixtures/developers_projects/david_action_controller +2 -1
  169. data/test/fixtures/developers_projects/david_active_record +2 -1
  170. data/test/fixtures/developers_projects.yml +17 -0
  171. data/test/fixtures/edge.rb +5 -0
  172. data/test/fixtures/edges.yml +6 -0
  173. data/test/fixtures/entrants.yml +14 -0
  174. data/test/fixtures/example.log +1 -0
  175. data/test/fixtures/fk_test_has_fk.yml +3 -0
  176. data/test/fixtures/fk_test_has_pk.yml +2 -0
  177. data/test/fixtures/flowers.jpg +0 -0
  178. data/test/fixtures/funny_jokes.yml +10 -0
  179. data/test/fixtures/item.rb +7 -0
  180. data/test/fixtures/items.yml +4 -0
  181. data/test/fixtures/joke.rb +3 -0
  182. data/test/fixtures/keyboard.rb +3 -0
  183. data/test/fixtures/legacy_thing.rb +3 -0
  184. data/test/fixtures/legacy_things.yml +3 -0
  185. data/test/fixtures/matey.rb +4 -0
  186. data/test/fixtures/mateys.yml +4 -0
  187. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  188. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  189. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  190. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  191. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  192. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  193. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  194. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  195. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  196. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  197. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  198. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  199. data/test/fixtures/minimalistic.rb +2 -0
  200. data/test/fixtures/minimalistics.yml +2 -0
  201. data/test/fixtures/mixed_case_monkey.rb +3 -0
  202. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  203. data/test/fixtures/mixins.yml +29 -0
  204. data/test/fixtures/movies.yml +7 -0
  205. data/test/fixtures/naked/csv/accounts.csv +1 -0
  206. data/test/fixtures/naked/yml/accounts.yml +1 -0
  207. data/test/fixtures/naked/yml/companies.yml +1 -0
  208. data/test/fixtures/naked/yml/courses.yml +1 -0
  209. data/test/fixtures/order.rb +4 -0
  210. data/test/fixtures/parrot.rb +13 -0
  211. data/test/fixtures/parrots.yml +27 -0
  212. data/test/fixtures/parrots_pirates.yml +7 -0
  213. data/test/fixtures/people.yml +3 -0
  214. data/test/fixtures/person.rb +4 -0
  215. data/test/fixtures/pirate.rb +5 -0
  216. data/test/fixtures/pirates.yml +9 -0
  217. data/test/fixtures/post.rb +59 -0
  218. data/test/fixtures/posts.yml +48 -0
  219. data/test/fixtures/project.rb +27 -2
  220. data/test/fixtures/projects.yml +7 -0
  221. data/test/fixtures/reader.rb +4 -0
  222. data/test/fixtures/readers.yml +4 -0
  223. data/test/fixtures/reply.rb +18 -2
  224. data/test/fixtures/reserved_words/distinct.yml +5 -0
  225. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  226. data/test/fixtures/reserved_words/group.yml +14 -0
  227. data/test/fixtures/reserved_words/select.yml +8 -0
  228. data/test/fixtures/reserved_words/values.yml +7 -0
  229. data/test/fixtures/ship.rb +3 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/subject.rb +4 -0
  232. data/test/fixtures/subscriber.rb +4 -3
  233. data/test/fixtures/tag.rb +7 -0
  234. data/test/fixtures/tagging.rb +10 -0
  235. data/test/fixtures/taggings.yml +25 -0
  236. data/test/fixtures/tags.yml +7 -0
  237. data/test/fixtures/task.rb +3 -0
  238. data/test/fixtures/tasks.yml +7 -0
  239. data/test/fixtures/topic.rb +20 -3
  240. data/test/fixtures/topics.yml +22 -0
  241. data/test/fixtures/treasure.rb +4 -0
  242. data/test/fixtures/treasures.yml +10 -0
  243. data/test/fixtures/vertex.rb +9 -0
  244. data/test/fixtures/vertices.yml +4 -0
  245. data/test/fixtures_test.rb +574 -8
  246. data/test/inheritance_test.rb +113 -27
  247. data/test/json_serialization_test.rb +180 -0
  248. data/test/lifecycle_test.rb +56 -29
  249. data/test/locking_test.rb +273 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +933 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_test.rb +95 -0
  254. data/test/modules_test.rb +23 -10
  255. data/test/multiple_db_test.rb +17 -3
  256. data/test/pk_test.rb +59 -15
  257. data/test/query_cache_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +124 -27
  260. data/test/reserved_word_test_mysql.rb +177 -0
  261. data/test/schema_authorization_test_postgresql.rb +75 -0
  262. data/test/schema_dumper_test.rb +131 -0
  263. data/test/schema_test_postgresql.rb +64 -0
  264. data/test/serialization_test.rb +47 -0
  265. data/test/synonym_test_oracle.rb +17 -0
  266. data/test/table_name_test_sqlserver.rb +23 -0
  267. data/test/threaded_connections_test.rb +48 -0
  268. data/test/transactions_test.rb +227 -29
  269. data/test/unconnected_test.rb +14 -6
  270. data/test/validations_test.rb +1293 -32
  271. data/test/xml_serialization_test.rb +202 -0
  272. metadata +347 -143
  273. data/dev-utils/eval_debugger.rb +0 -9
  274. data/examples/associations.rb +0 -87
  275. data/examples/shared_setup.rb +0 -15
  276. data/examples/validation.rb +0 -88
  277. data/lib/active_record/deprecated_associations.rb +0 -70
  278. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  279. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  280. data/lib/active_record/support/clean_logger.rb +0 -10
  281. data/lib/active_record/support/inflector.rb +0 -70
  282. data/lib/active_record/vendor/simple.rb +0 -702
  283. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  284. data/lib/active_record/wrappings.rb +0 -59
  285. data/rakefile +0 -122
  286. data/test/deprecated_associations_test.rb +0 -336
  287. data/test/fixtures/accounts/signals37 +0 -3
  288. data/test/fixtures/accounts/unknown +0 -2
  289. data/test/fixtures/companies/first_client +0 -6
  290. data/test/fixtures/companies/first_firm +0 -4
  291. data/test/fixtures/companies/second_client +0 -6
  292. data/test/fixtures/courses/java +0 -2
  293. data/test/fixtures/courses/ruby +0 -2
  294. data/test/fixtures/customers/david +0 -6
  295. data/test/fixtures/db_definitions/mysql.sql +0 -96
  296. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  297. data/test/fixtures/developers/david +0 -2
  298. data/test/fixtures/developers/jamis +0 -2
  299. data/test/fixtures/entrants/first +0 -3
  300. data/test/fixtures/entrants/second +0 -3
  301. data/test/fixtures/entrants/third +0 -3
  302. data/test/fixtures/fixture_database.sqlite +0 -0
  303. data/test/fixtures/fixture_database_2.sqlite +0 -0
  304. data/test/fixtures/movies/first +0 -2
  305. data/test/fixtures/movies/second +0 -2
  306. data/test/fixtures/projects/action_controller +0 -2
  307. data/test/fixtures/projects/active_record +0 -2
  308. data/test/fixtures/topics/first +0 -9
  309. data/test/fixtures/topics/second +0 -8
  310. data/test/inflector_test.rb +0 -104
  311. data/test/thread_safety_test.rb +0 -33
@@ -1,325 +1,171 @@
1
1
  require 'benchmark'
2
2
  require 'date'
3
+ require 'bigdecimal'
4
+ require 'bigdecimal/util'
3
5
 
4
- module ActiveRecord
5
- class Base
6
- class ConnectionSpecification #:nodoc:
7
- attr_reader :config, :adapter_method
8
- def initialize (config, adapter_method)
9
- @config, @adapter_method = config, adapter_method
10
- end
11
- end
6
+ require 'active_record/connection_adapters/abstract/schema_definitions'
7
+ require 'active_record/connection_adapters/abstract/schema_statements'
8
+ require 'active_record/connection_adapters/abstract/database_statements'
9
+ require 'active_record/connection_adapters/abstract/quoting'
10
+ require 'active_record/connection_adapters/abstract/connection_specification'
11
+ require 'active_record/connection_adapters/abstract/query_cache'
12
12
 
13
- # The class -> [adapter_method, config] map
14
- @@defined_connections = {}
15
-
16
- # Establishes the connection to the database. Accepts a hash as input where
17
- # the :adapter key must be specified with the name of a database adapter (in lower-case)
18
- # example for regular databases (MySQL, Postgresql, etc):
19
- #
20
- # ActiveRecord::Base.establish_connection(
21
- # :adapter => "mysql",
22
- # :host => "localhost",
23
- # :username => "myuser",
24
- # :password => "mypass",
25
- # :database => "somedatabase"
26
- # )
27
- #
28
- # Example for SQLite database:
29
- #
30
- # ActiveRecord::Base.establish_connection(
31
- # :adapter => "sqlite",
32
- # :dbfile => "path/to/dbfile"
33
- # )
34
- #
35
- # Also accepts keys as strings (for parsing from yaml for example):
36
- # ActiveRecord::Base.establish_connection(
37
- # "adapter" => "sqlite",
38
- # "dbfile" => "path/to/dbfile"
39
- # )
40
- #
41
- # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
42
- # may be returned on an error.
43
- #
44
- # == Connecting to another database for a single model
45
- #
46
- # To support different connections for different classes, you can
47
- # simply call establish_connection with the classes you wish to have
48
- # different connections for:
49
- #
50
- # class Courses < ActiveRecord::Base
51
- # ...
52
- # end
13
+ module ActiveRecord
14
+ module ConnectionAdapters # :nodoc:
15
+ # All the concrete database adapters follow the interface laid down in this class.
16
+ # You can use this interface directly by borrowing the database connection from the Base with
17
+ # Base.connection.
53
18
  #
54
- # Courses.establish_connection( ... )
55
- def self.establish_connection(spec)
56
- if spec.instance_of? ConnectionSpecification
57
- @@defined_connections[self] = spec
58
- else
59
- if spec.nil? then raise AdapterNotSpecified end
60
- symbolize_strings_in_hash(spec)
61
- unless spec.key?(:adapter) then raise AdapterNotSpecified end
62
-
63
- adapter_method = "#{spec[:adapter]}_connection"
64
- unless methods.include?(adapter_method) then raise AdapterNotFound end
65
- remove_connection
66
- @@defined_connections[self] = ConnectionSpecification.new(spec, adapter_method)
67
- end
68
- end
69
-
70
- # Locate the connection of the nearest super class. This can be an
71
- # active or defined connections: if it is the latter, it will be
72
- # opened and set as the active connection for the class it was defined
73
- # for (not necessarily the current class).
74
- def self.retrieve_connection #:nodoc:
75
- klass = self
76
- until klass == ActiveRecord::Base.superclass
77
- Thread.current['active_connections'] ||= {}
78
- if Thread.current['active_connections'][klass]
79
- return Thread.current['active_connections'][klass]
80
- elsif @@defined_connections[klass]
81
- klass.connection = @@defined_connections[klass]
82
- return self.connection
83
- end
84
- klass = klass.superclass
85
- end
86
- raise ConnectionNotEstablished
87
- end
88
-
89
- # Returns true if a connection that's accessible to this class have already been opened.
90
- def self.connected?
91
- klass = self
92
- until klass == ActiveRecord::Base.superclass
93
- if Thread.current['active_connections'].is_a?(Hash) && Thread.current['active_connections'][klass]
94
- return true
95
- else
96
- klass = klass.superclass
97
- end
98
- end
99
- return false
100
- end
101
-
102
- # Remove the connection for this class. This will close the active
103
- # connection and the defined connection (if they exist). The result
104
- # can be used as argument for establish_connection, for easy
105
- # re-establishing of the connection.
106
- def self.remove_connection(klass=self)
107
- conn = @@defined_connections[klass]
108
- @@defined_connections.delete(klass)
109
- Thread.current['active_connections'] ||= {}
110
- Thread.current['active_connections'][klass] = nil
111
- conn.config if conn
112
- end
113
-
114
- # Set the connection for the class.
115
- def self.connection=(spec)
116
- raise ConnectionNotEstablished unless spec
117
- conn = self.send(spec.adapter_method, spec.config)
118
- Thread.current['active_connections'] ||= {}
119
- Thread.current['active_connections'][self] = conn
120
- end
19
+ # Most of the methods in the adapter are useful during migrations. Most
20
+ # notably, SchemaStatements#create_table, SchemaStatements#drop_table,
21
+ # SchemaStatements#add_index, SchemaStatements#remove_index,
22
+ # SchemaStatements#add_column, SchemaStatements#change_column and
23
+ # SchemaStatements#remove_column are very useful.
24
+ class AbstractAdapter
25
+ include Quoting, DatabaseStatements, SchemaStatements
26
+ include QueryCache
27
+ @@row_even = true
121
28
 
122
- # Converts all strings in a hash to symbols.
123
- def self.symbolize_strings_in_hash(hash)
124
- hash.each do |key, value|
125
- if key.class == String
126
- hash.delete key
127
- hash[key.intern] = value
128
- end
29
+ def initialize(connection, logger = nil) #:nodoc:
30
+ @connection, @logger = connection, logger
31
+ @runtime = 0
32
+ @last_verification = 0
129
33
  end
130
- end
131
- end
132
34
 
133
- module ConnectionAdapters # :nodoc:
134
- class Column # :nodoc:
135
- attr_reader :name, :default, :type, :limit
136
- # The name should contain the name of the column, such as "name" in "name varchar(250)"
137
- # The default should contain the type-casted default of the column, such as 1 in "count int(11) DEFAULT 1"
138
- # The type parameter should either contain :integer, :float, :datetime, :date, :text, or :string
139
- # The sql_type is just used for extracting the limit, such as 10 in "varchar(10)"
140
- def initialize(name, default, sql_type = nil)
141
- @name, @default, @type = name, default, simplified_type(sql_type)
142
- @limit = extract_limit(sql_type) unless sql_type.nil?
35
+ # Returns the human-readable name of the adapter. Use mixed case - one
36
+ # can always use downcase if needed.
37
+ def adapter_name
38
+ 'Abstract'
143
39
  end
144
40
 
145
- def default
146
- type_cast(@default)
41
+ # Does this adapter support migrations? Backend specific, as the
42
+ # abstract adapter always returns +false+.
43
+ def supports_migrations?
44
+ false
147
45
  end
148
46
 
149
- def klass
150
- case type
151
- when :integer then Fixnum
152
- when :float then Float
153
- when :datetime then Time
154
- when :date then Date
155
- when :text, :string then String
156
- when :boolean then Object
157
- end
47
+ # Does this adapter support using DISTINCT within COUNT? This is +true+
48
+ # for all adapters except sqlite.
49
+ def supports_count_distinct?
50
+ true
158
51
  end
159
-
160
- def type_cast(value)
161
- if value.nil? then return nil end
162
- case type
163
- when :string then value
164
- when :text then value
165
- when :integer then value.to_i
166
- when :float then value.to_f
167
- when :datetime then string_to_time(value)
168
- when :date then string_to_date(value)
169
- when :boolean then (value == "t" or value == true ? true : false)
170
- else value
171
- end
172
- end
173
-
174
- def human_name
175
- Base.human_attribute_name(@name)
176
- end
177
-
178
- private
179
- def string_to_date(string)
180
- return string if Date === string
181
- date_array = ParseDate.parsedate(string)
182
- # treat 0000-00-00 as nil
183
- Date.new(date_array[0], date_array[1], date_array[2]) rescue nil
184
- end
185
-
186
- def string_to_time(string)
187
- return string if Time === string
188
- time_array = ParseDate.parsedate(string).compact
189
- # treat 0000-00-00 00:00:00 as nil
190
- Time.local(*time_array) rescue nil
191
- end
192
52
 
193
- def extract_limit(sql_type)
194
- $1.to_i if sql_type =~ /\((.*)\)/
195
- end
196
-
197
- def simplified_type(field_type)
198
- case field_type
199
- when /int/i
200
- :integer
201
- when /float|double|decimal|numeric/i
202
- :float
203
- when /time/i
204
- :datetime
205
- when /date/i
206
- :date
207
- when /(c|b)lob/i, /text/i
208
- :text
209
- when /char/i, /string/i
210
- :string
211
- when /boolean/i
212
- :boolean
213
- end
214
- end
215
- end
53
+ # Should primary key values be selected from their corresponding
54
+ # sequence before the insert statement? If true, next_sequence_value
55
+ # is called before each insert to set the record's primary key.
56
+ # This is false for all adapters but Firebird.
57
+ def prefetch_primary_key?(table_name = nil)
58
+ false
59
+ end
216
60
 
217
- # All the concrete database adapters follow the interface laid down in this class.
218
- # You can use this interface directly by borrowing the database connection from the Base with
219
- # Base.connection.
220
- class AbstractAdapter
221
- @@row_even = true
61
+ def reset_runtime #:nodoc:
62
+ rt, @runtime = @runtime, 0
63
+ rt
64
+ end
222
65
 
223
- include Benchmark
66
+ # QUOTING ==================================================
224
67
 
225
- def initialize(connection, logger = nil) # :nodoc:
226
- @connection, @logger = connection, logger
227
- @runtime = 0
68
+ # Override to return the quoted table name if the database needs it
69
+ def quote_table_name(name)
70
+ name
228
71
  end
229
72
 
230
- # Returns an array of record hashes with the column names as a keys and fields as values.
231
- def select_all(sql, name = nil) end
232
-
233
- # Returns a record hash with the column names as a keys and fields as values.
234
- def select_one(sql, name = nil) end
235
-
236
- # Returns an array of column objects for the table specified by +table_name+.
237
- def columns(table_name, name = nil) end
73
+ # REFERENTIAL INTEGRITY ====================================
238
74
 
239
- # Returns the last auto-generated ID from the affected table.
240
- def insert(sql, name = nil, pk = nil, id_value = nil) end
75
+ # Override to turn off referential integrity while executing +&block+
76
+ def disable_referential_integrity(&block)
77
+ yield
78
+ end
241
79
 
242
- # Executes the update statement.
243
- def update(sql, name = nil) end
80
+ # CONNECTION MANAGEMENT ====================================
244
81
 
245
- # Executes the delete statement.
246
- def delete(sql, name = nil) end
82
+ # Is this connection active and ready to perform queries?
83
+ def active?
84
+ @active != false
85
+ end
247
86
 
248
- def reset_runtime # :nodoc:
249
- rt = @runtime
250
- @runtime = 0
251
- return rt
87
+ # Close this connection and open a new one in its place.
88
+ def reconnect!
89
+ @active = true
252
90
  end
253
91
 
254
- # Begins the transaction (and turns off auto-committing).
255
- def begin_db_transaction() end
256
-
257
- # Commits the transaction (and turns on auto-committing).
258
- def commit_db_transaction() end
92
+ # Close this connection
93
+ def disconnect!
94
+ @active = false
95
+ end
259
96
 
260
- # Rollsback the transaction (and turns on auto-committing). Must be done if the transaction block
261
- # raises an exception or returns false.
262
- def rollback_db_transaction() end
97
+ # Returns true if its safe to reload the connection between requests for development mode.
98
+ # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
99
+ def requires_reloading?
100
+ false
101
+ end
263
102
 
264
- def quote(value, column = nil)
265
- case value
266
- when String then "'#{value.gsub(/\\/,'\&\&').gsub(/'/, "''")}'" # ' (for ruby-mode)
267
- when NilClass then "NULL"
268
- when TrueClass then (column && column.type == :boolean ? "'t'" : "1")
269
- when FalseClass then (column && column.type == :boolean ? "'f'" : "0")
270
- when Float, Fixnum, Bignum, Date then "'#{value.to_s}'"
271
- when Time, DateTime then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
272
- else "'#{value.to_yaml.gsub(/'/, "''")}'"
103
+ # Lazily verify this connection, calling +active?+ only if it hasn't
104
+ # been called for +timeout+ seconds.
105
+ def verify!(timeout)
106
+ now = Time.now.to_i
107
+ if (now - @last_verification) > timeout
108
+ reconnect! unless active?
109
+ @last_verification = now
273
110
  end
274
111
  end
275
112
 
276
- def quote_column_name(name)
277
- return name
113
+ # Provides access to the underlying database connection. Useful for
114
+ # when you need to call a proprietary method such as postgresql's lo_*
115
+ # methods
116
+ def raw_connection
117
+ @connection
278
118
  end
279
119
 
280
- # Returns a string of the CREATE TABLE SQL statements for recreating the entire structure of the database.
281
- def structure_dump() end
120
+ def log_info(sql, name, runtime)
121
+ if @logger && @logger.debug?
122
+ name = "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})"
123
+ @logger.debug format_log_entry(name, sql.squeeze(' '))
124
+ end
125
+ end
282
126
 
283
127
  protected
284
- def log(sql, name, connection, &action)
285
- begin
286
- if @logger.nil?
287
- action.call(connection)
288
- else
128
+ def log(sql, name)
129
+ if block_given?
130
+ if @logger and @logger.debug?
289
131
  result = nil
290
- bm = measure { result = action.call(connection) }
291
- @runtime += bm.real
292
- log_info(sql, name, bm.real)
132
+ seconds = Benchmark.realtime { result = yield }
133
+ @runtime += seconds
134
+ log_info(sql, name, seconds)
293
135
  result
136
+ else
137
+ yield
294
138
  end
295
- rescue => e
296
- log_info("#{e.message}: #{sql}", name, 0)
297
- raise ActiveRecord::StatementInvalid, "#{e.message}: #{sql}"
139
+ else
140
+ log_info(sql, name, 0)
141
+ nil
298
142
  end
299
- end
300
-
301
- def log_info(sql, name, runtime)
302
- if @logger.nil? then return end
303
-
304
- @logger.info(
305
- format_log_entry(
306
- "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})",
307
- sql.gsub(/ +/, " ")
308
- )
309
- )
143
+ rescue Exception => e
144
+ # Log message and raise exception.
145
+ # Set last_verification to 0, so that connection gets verified
146
+ # upon reentering the request loop
147
+ @last_verification = 0
148
+ message = "#{e.class.name}: #{e.message}: #{sql}"
149
+ log_info(message, name, 0)
150
+ raise ActiveRecord::StatementInvalid, message
310
151
  end
311
152
 
312
153
  def format_log_entry(message, dump = nil)
313
- if @@row_even then
314
- @@row_even = false; caller_color = "1;32"; message_color = "4;33"; dump_color = "1;37"
154
+ if ActiveRecord::Base.colorize_logging
155
+ if @@row_even
156
+ @@row_even = false
157
+ message_color, dump_color = "4;36;1", "0;1"
158
+ else
159
+ @@row_even = true
160
+ message_color, dump_color = "4;35;1", "0"
161
+ end
162
+
163
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
164
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
165
+ log_entry
315
166
  else
316
- @@row_even = true; caller_color = "1;36"; message_color = "4;35"; dump_color = "0;37"
167
+ "%s %s" % [message, dump]
317
168
  end
318
-
319
- log_entry = " \e[#{message_color}m#{message}\e[m"
320
- log_entry << " \e[#{dump_color}m%s\e[m" % dump if dump.kind_of?(String) && !dump.nil?
321
- log_entry << " \e[#{dump_color}m%p\e[m" % dump if !dump.kind_of?(String) && !dump.nil?
322
- log_entry
323
169
  end
324
170
  end
325
171
  end