activerecord_authorails 1.0.0

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 (270) hide show
  1. data/CHANGELOG +3043 -0
  2. data/README +360 -0
  3. data/RUNNING_UNIT_TESTS +64 -0
  4. data/Rakefile +226 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/associations.rb +87 -0
  7. data/examples/shared_setup.rb +15 -0
  8. data/examples/validation.rb +85 -0
  9. data/install.rb +30 -0
  10. data/lib/active_record.rb +85 -0
  11. data/lib/active_record/acts/list.rb +244 -0
  12. data/lib/active_record/acts/nested_set.rb +211 -0
  13. data/lib/active_record/acts/tree.rb +89 -0
  14. data/lib/active_record/aggregations.rb +191 -0
  15. data/lib/active_record/associations.rb +1637 -0
  16. data/lib/active_record/associations/association_collection.rb +190 -0
  17. data/lib/active_record/associations/association_proxy.rb +158 -0
  18. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  19. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  20. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
  21. data/lib/active_record/associations/has_many_association.rb +210 -0
  22. data/lib/active_record/associations/has_many_through_association.rb +247 -0
  23. data/lib/active_record/associations/has_one_association.rb +80 -0
  24. data/lib/active_record/attribute_methods.rb +75 -0
  25. data/lib/active_record/base.rb +2164 -0
  26. data/lib/active_record/calculations.rb +270 -0
  27. data/lib/active_record/callbacks.rb +367 -0
  28. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
  34. data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
  35. data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
  36. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
  38. data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
  39. data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
  40. data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
  41. data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
  42. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
  43. data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
  44. data/lib/active_record/deprecated_associations.rb +104 -0
  45. data/lib/active_record/deprecated_finders.rb +44 -0
  46. data/lib/active_record/fixtures.rb +628 -0
  47. data/lib/active_record/locking/optimistic.rb +106 -0
  48. data/lib/active_record/locking/pessimistic.rb +77 -0
  49. data/lib/active_record/migration.rb +394 -0
  50. data/lib/active_record/observer.rb +178 -0
  51. data/lib/active_record/query_cache.rb +64 -0
  52. data/lib/active_record/reflection.rb +222 -0
  53. data/lib/active_record/schema.rb +58 -0
  54. data/lib/active_record/schema_dumper.rb +149 -0
  55. data/lib/active_record/timestamp.rb +51 -0
  56. data/lib/active_record/transactions.rb +136 -0
  57. data/lib/active_record/validations.rb +843 -0
  58. data/lib/active_record/vendor/db2.rb +362 -0
  59. data/lib/active_record/vendor/mysql.rb +1214 -0
  60. data/lib/active_record/vendor/simple.rb +693 -0
  61. data/lib/active_record/version.rb +9 -0
  62. data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
  63. data/lib/active_record/wrappings.rb +58 -0
  64. data/lib/active_record/xml_serialization.rb +308 -0
  65. data/test/aaa_create_tables_test.rb +59 -0
  66. data/test/abstract_unit.rb +77 -0
  67. data/test/active_schema_test_mysql.rb +31 -0
  68. data/test/adapter_test.rb +87 -0
  69. data/test/adapter_test_sqlserver.rb +81 -0
  70. data/test/aggregations_test.rb +95 -0
  71. data/test/all.sh +8 -0
  72. data/test/ar_schema_test.rb +33 -0
  73. data/test/association_inheritance_reload.rb +14 -0
  74. data/test/associations/callbacks_test.rb +126 -0
  75. data/test/associations/cascaded_eager_loading_test.rb +138 -0
  76. data/test/associations/eager_test.rb +393 -0
  77. data/test/associations/extension_test.rb +42 -0
  78. data/test/associations/join_model_test.rb +497 -0
  79. data/test/associations_test.rb +1809 -0
  80. data/test/attribute_methods_test.rb +49 -0
  81. data/test/base_test.rb +1586 -0
  82. data/test/binary_test.rb +37 -0
  83. data/test/calculations_test.rb +219 -0
  84. data/test/callbacks_test.rb +377 -0
  85. data/test/class_inheritable_attributes_test.rb +32 -0
  86. data/test/column_alias_test.rb +17 -0
  87. data/test/connection_test_firebird.rb +8 -0
  88. data/test/connections/native_db2/connection.rb +25 -0
  89. data/test/connections/native_firebird/connection.rb +26 -0
  90. data/test/connections/native_frontbase/connection.rb +27 -0
  91. data/test/connections/native_mysql/connection.rb +24 -0
  92. data/test/connections/native_openbase/connection.rb +21 -0
  93. data/test/connections/native_oracle/connection.rb +27 -0
  94. data/test/connections/native_postgresql/connection.rb +23 -0
  95. data/test/connections/native_sqlite/connection.rb +34 -0
  96. data/test/connections/native_sqlite3/connection.rb +34 -0
  97. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  98. data/test/connections/native_sqlserver/connection.rb +23 -0
  99. data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
  100. data/test/connections/native_sybase/connection.rb +23 -0
  101. data/test/copy_table_sqlite.rb +64 -0
  102. data/test/datatype_test_postgresql.rb +52 -0
  103. data/test/default_test_firebird.rb +16 -0
  104. data/test/defaults_test.rb +60 -0
  105. data/test/deprecated_associations_test.rb +396 -0
  106. data/test/deprecated_finder_test.rb +151 -0
  107. data/test/empty_date_time_test.rb +25 -0
  108. data/test/finder_test.rb +504 -0
  109. data/test/fixtures/accounts.yml +28 -0
  110. data/test/fixtures/author.rb +99 -0
  111. data/test/fixtures/author_favorites.yml +4 -0
  112. data/test/fixtures/authors.yml +7 -0
  113. data/test/fixtures/auto_id.rb +4 -0
  114. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  115. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  116. data/test/fixtures/bad_fixtures/blank_line +3 -0
  117. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  118. data/test/fixtures/bad_fixtures/missing_value +1 -0
  119. data/test/fixtures/binary.rb +2 -0
  120. data/test/fixtures/categories.yml +14 -0
  121. data/test/fixtures/categories/special_categories.yml +9 -0
  122. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  123. data/test/fixtures/categories_ordered.yml +7 -0
  124. data/test/fixtures/categories_posts.yml +23 -0
  125. data/test/fixtures/categorization.rb +5 -0
  126. data/test/fixtures/categorizations.yml +17 -0
  127. data/test/fixtures/category.rb +20 -0
  128. data/test/fixtures/column_name.rb +3 -0
  129. data/test/fixtures/comment.rb +23 -0
  130. data/test/fixtures/comments.yml +59 -0
  131. data/test/fixtures/companies.yml +55 -0
  132. data/test/fixtures/company.rb +107 -0
  133. data/test/fixtures/company_in_module.rb +59 -0
  134. data/test/fixtures/computer.rb +3 -0
  135. data/test/fixtures/computers.yml +4 -0
  136. data/test/fixtures/course.rb +3 -0
  137. data/test/fixtures/courses.yml +7 -0
  138. data/test/fixtures/customer.rb +55 -0
  139. data/test/fixtures/customers.yml +17 -0
  140. data/test/fixtures/db_definitions/db2.drop.sql +32 -0
  141. data/test/fixtures/db_definitions/db2.sql +231 -0
  142. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  143. data/test/fixtures/db_definitions/db22.sql +5 -0
  144. data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
  145. data/test/fixtures/db_definitions/firebird.sql +304 -0
  146. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  148. data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
  149. data/test/fixtures/db_definitions/frontbase.sql +268 -0
  150. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  151. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  152. data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
  153. data/test/fixtures/db_definitions/mysql.sql +234 -0
  154. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  156. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  157. data/test/fixtures/db_definitions/openbase.sql +302 -0
  158. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  159. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  160. data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
  161. data/test/fixtures/db_definitions/oracle.sql +325 -0
  162. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  163. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  164. data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
  165. data/test/fixtures/db_definitions/postgresql.sql +263 -0
  166. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  167. data/test/fixtures/db_definitions/postgresql2.sql +5 -0
  168. data/test/fixtures/db_definitions/schema.rb +60 -0
  169. data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
  170. data/test/fixtures/db_definitions/sqlite.sql +215 -0
  171. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  172. data/test/fixtures/db_definitions/sqlite2.sql +5 -0
  173. data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
  174. data/test/fixtures/db_definitions/sqlserver.sql +243 -0
  175. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  176. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  177. data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
  178. data/test/fixtures/db_definitions/sybase.sql +218 -0
  179. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  180. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  181. data/test/fixtures/default.rb +2 -0
  182. data/test/fixtures/developer.rb +52 -0
  183. data/test/fixtures/developers.yml +21 -0
  184. data/test/fixtures/developers_projects.yml +17 -0
  185. data/test/fixtures/developers_projects/david_action_controller +3 -0
  186. data/test/fixtures/developers_projects/david_active_record +3 -0
  187. data/test/fixtures/developers_projects/jamis_active_record +2 -0
  188. data/test/fixtures/edge.rb +5 -0
  189. data/test/fixtures/edges.yml +6 -0
  190. data/test/fixtures/entrant.rb +3 -0
  191. data/test/fixtures/entrants.yml +14 -0
  192. data/test/fixtures/fk_test_has_fk.yml +3 -0
  193. data/test/fixtures/fk_test_has_pk.yml +2 -0
  194. data/test/fixtures/flowers.jpg +0 -0
  195. data/test/fixtures/funny_jokes.yml +10 -0
  196. data/test/fixtures/joke.rb +6 -0
  197. data/test/fixtures/keyboard.rb +3 -0
  198. data/test/fixtures/legacy_thing.rb +3 -0
  199. data/test/fixtures/legacy_things.yml +3 -0
  200. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  201. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  202. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  203. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  204. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  205. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  206. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  207. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  208. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  209. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  210. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  211. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  212. data/test/fixtures/mixed_case_monkey.rb +3 -0
  213. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  214. data/test/fixtures/mixin.rb +63 -0
  215. data/test/fixtures/mixins.yml +127 -0
  216. data/test/fixtures/movie.rb +5 -0
  217. data/test/fixtures/movies.yml +7 -0
  218. data/test/fixtures/naked/csv/accounts.csv +1 -0
  219. data/test/fixtures/naked/yml/accounts.yml +1 -0
  220. data/test/fixtures/naked/yml/companies.yml +1 -0
  221. data/test/fixtures/naked/yml/courses.yml +1 -0
  222. data/test/fixtures/order.rb +4 -0
  223. data/test/fixtures/people.yml +3 -0
  224. data/test/fixtures/person.rb +4 -0
  225. data/test/fixtures/post.rb +58 -0
  226. data/test/fixtures/posts.yml +48 -0
  227. data/test/fixtures/project.rb +27 -0
  228. data/test/fixtures/projects.yml +7 -0
  229. data/test/fixtures/reader.rb +4 -0
  230. data/test/fixtures/readers.yml +4 -0
  231. data/test/fixtures/reply.rb +37 -0
  232. data/test/fixtures/subject.rb +4 -0
  233. data/test/fixtures/subscriber.rb +6 -0
  234. data/test/fixtures/subscribers/first +2 -0
  235. data/test/fixtures/subscribers/second +2 -0
  236. data/test/fixtures/tag.rb +7 -0
  237. data/test/fixtures/tagging.rb +6 -0
  238. data/test/fixtures/taggings.yml +18 -0
  239. data/test/fixtures/tags.yml +7 -0
  240. data/test/fixtures/task.rb +3 -0
  241. data/test/fixtures/tasks.yml +7 -0
  242. data/test/fixtures/topic.rb +25 -0
  243. data/test/fixtures/topics.yml +22 -0
  244. data/test/fixtures/vertex.rb +9 -0
  245. data/test/fixtures/vertices.yml +4 -0
  246. data/test/fixtures_test.rb +401 -0
  247. data/test/inheritance_test.rb +205 -0
  248. data/test/lifecycle_test.rb +137 -0
  249. data/test/locking_test.rb +190 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +768 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_nested_set_test.rb +196 -0
  254. data/test/mixin_test.rb +550 -0
  255. data/test/modules_test.rb +34 -0
  256. data/test/multiple_db_test.rb +60 -0
  257. data/test/pk_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +159 -0
  260. data/test/schema_authorization_test_postgresql.rb +75 -0
  261. data/test/schema_dumper_test.rb +96 -0
  262. data/test/schema_test_postgresql.rb +64 -0
  263. data/test/synonym_test_oracle.rb +17 -0
  264. data/test/table_name_test_sqlserver.rb +23 -0
  265. data/test/threaded_connections_test.rb +48 -0
  266. data/test/transactions_test.rb +230 -0
  267. data/test/unconnected_test.rb +32 -0
  268. data/test/validations_test.rb +1097 -0
  269. data/test/xml_serialization_test.rb +125 -0
  270. metadata +365 -0
@@ -0,0 +1,279 @@
1
+ require 'set'
2
+
3
+ module ActiveRecord
4
+ class Base
5
+ class ConnectionSpecification #:nodoc:
6
+ attr_reader :config, :adapter_method
7
+ def initialize (config, adapter_method)
8
+ @config, @adapter_method = config, adapter_method
9
+ end
10
+ end
11
+
12
+ # Check for activity after at least +verification_timeout+ seconds.
13
+ # Defaults to 0 (always check.)
14
+ cattr_accessor :verification_timeout, :instance_writer => false
15
+ @@verification_timeout = 0
16
+
17
+ # The class -> [adapter_method, config] map
18
+ @@defined_connections = {}
19
+
20
+ # The class -> thread id -> adapter cache. (class -> adapter if not allow_concurrency)
21
+ @@active_connections = {}
22
+
23
+ class << self
24
+ # Retrieve the connection cache.
25
+ def thread_safe_active_connections #:nodoc:
26
+ @@active_connections[Thread.current.object_id] ||= {}
27
+ end
28
+
29
+ def single_threaded_active_connections #:nodoc:
30
+ @@active_connections
31
+ end
32
+
33
+ # pick up the right active_connection method from @@allow_concurrency
34
+ if @@allow_concurrency
35
+ alias_method :active_connections, :thread_safe_active_connections
36
+ else
37
+ alias_method :active_connections, :single_threaded_active_connections
38
+ end
39
+
40
+ # set concurrency support flag (not thread safe, like most of the methods in this file)
41
+ def allow_concurrency=(threaded) #:nodoc:
42
+ logger.debug "allow_concurrency=#{threaded}" if logger
43
+ return if @@allow_concurrency == threaded
44
+ clear_all_cached_connections!
45
+ @@allow_concurrency = threaded
46
+ method_prefix = threaded ? "thread_safe" : "single_threaded"
47
+ sing = (class << self; self; end)
48
+ [:active_connections, :scoped_methods].each do |method|
49
+ sing.send(:alias_method, method, "#{method_prefix}_#{method}")
50
+ end
51
+ log_connections if logger
52
+ end
53
+
54
+ def active_connection_name #:nodoc:
55
+ @active_connection_name ||=
56
+ if active_connections[name] || @@defined_connections[name]
57
+ name
58
+ elsif self == ActiveRecord::Base
59
+ nil
60
+ else
61
+ superclass.active_connection_name
62
+ end
63
+ end
64
+
65
+ def clear_active_connection_name #:nodoc:
66
+ @active_connection_name = nil
67
+ subclasses.each { |klass| klass.clear_active_connection_name }
68
+ end
69
+
70
+ # Returns the connection currently associated with the class. This can
71
+ # also be used to "borrow" the connection to do database work unrelated
72
+ # to any of the specific Active Records.
73
+ def connection
74
+ if @active_connection_name && (conn = active_connections[@active_connection_name])
75
+ conn
76
+ else
77
+ # retrieve_connection sets the cache key.
78
+ conn = retrieve_connection
79
+ active_connections[@active_connection_name] = conn
80
+ end
81
+ end
82
+
83
+ # Clears the cache which maps classes to connections.
84
+ def clear_active_connections!
85
+ clear_cache!(@@active_connections) do |name, conn|
86
+ conn.disconnect!
87
+ end
88
+ end
89
+
90
+ # Clears the cache which maps classes
91
+ def clear_reloadable_connections!
92
+ @@active_connections.each do |name, conn|
93
+ if conn.requires_reloading?
94
+ conn.disconnect!
95
+ @@active_connections.delete(name)
96
+ end
97
+ end
98
+ end
99
+
100
+ # Verify active connections.
101
+ def verify_active_connections! #:nodoc:
102
+ if @@allow_concurrency
103
+ remove_stale_cached_threads!(@@active_connections) do |name, conn|
104
+ conn.disconnect!
105
+ end
106
+ end
107
+
108
+ active_connections.each_value do |connection|
109
+ connection.verify!(@@verification_timeout)
110
+ end
111
+ end
112
+
113
+ private
114
+ def clear_cache!(cache, thread_id = nil, &block)
115
+ if cache
116
+ if @@allow_concurrency
117
+ thread_id ||= Thread.current.object_id
118
+ thread_cache, cache = cache, cache[thread_id]
119
+ return unless cache
120
+ end
121
+
122
+ cache.each(&block) if block_given?
123
+ cache.clear
124
+ end
125
+ ensure
126
+ if thread_cache && @@allow_concurrency
127
+ thread_cache.delete(thread_id)
128
+ end
129
+ end
130
+
131
+ # Remove stale threads from the cache.
132
+ def remove_stale_cached_threads!(cache, &block)
133
+ stale = Set.new(cache.keys)
134
+
135
+ Thread.list.each do |thread|
136
+ stale.delete(thread.object_id) if thread.alive?
137
+ end
138
+
139
+ stale.each do |thread_id|
140
+ clear_cache!(cache, thread_id, &block)
141
+ end
142
+ end
143
+
144
+ def clear_all_cached_connections!
145
+ if @@allow_concurrency
146
+ @@active_connections.each_value do |connection_hash_for_thread|
147
+ connection_hash_for_thread.each_value {|conn| conn.disconnect! }
148
+ connection_hash_for_thread.clear
149
+ end
150
+ else
151
+ @@active_connections.each_value {|conn| conn.disconnect! }
152
+ end
153
+ @@active_connections.clear
154
+ end
155
+ end
156
+
157
+ # Returns the connection currently associated with the class. This can
158
+ # also be used to "borrow" the connection to do database work that isn't
159
+ # easily done without going straight to SQL.
160
+ def connection
161
+ self.class.connection
162
+ end
163
+
164
+ # Establishes the connection to the database. Accepts a hash as input where
165
+ # the :adapter key must be specified with the name of a database adapter (in lower-case)
166
+ # example for regular databases (MySQL, Postgresql, etc):
167
+ #
168
+ # ActiveRecord::Base.establish_connection(
169
+ # :adapter => "mysql",
170
+ # :host => "localhost",
171
+ # :username => "myuser",
172
+ # :password => "mypass",
173
+ # :database => "somedatabase"
174
+ # )
175
+ #
176
+ # Example for SQLite database:
177
+ #
178
+ # ActiveRecord::Base.establish_connection(
179
+ # :adapter => "sqlite",
180
+ # :database => "path/to/dbfile"
181
+ # )
182
+ #
183
+ # Also accepts keys as strings (for parsing from yaml for example):
184
+ # ActiveRecord::Base.establish_connection(
185
+ # "adapter" => "sqlite",
186
+ # "database" => "path/to/dbfile"
187
+ # )
188
+ #
189
+ # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
190
+ # may be returned on an error.
191
+ def self.establish_connection(spec = nil)
192
+ case spec
193
+ when nil
194
+ raise AdapterNotSpecified unless defined? RAILS_ENV
195
+ establish_connection(RAILS_ENV)
196
+ when ConnectionSpecification
197
+ clear_active_connection_name
198
+ @active_connection_name = name
199
+ @@defined_connections[name] = spec
200
+ when Symbol, String
201
+ if configuration = configurations[spec.to_s]
202
+ establish_connection(configuration)
203
+ else
204
+ raise AdapterNotSpecified, "#{spec} database is not configured"
205
+ end
206
+ else
207
+ spec = spec.symbolize_keys
208
+ unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
209
+ adapter_method = "#{spec[:adapter]}_connection"
210
+ unless respond_to?(adapter_method) then raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter" end
211
+ remove_connection
212
+ establish_connection(ConnectionSpecification.new(spec, adapter_method))
213
+ end
214
+ end
215
+
216
+ # Locate the connection of the nearest super class. This can be an
217
+ # active or defined connections: if it is the latter, it will be
218
+ # opened and set as the active connection for the class it was defined
219
+ # for (not necessarily the current class).
220
+ def self.retrieve_connection #:nodoc:
221
+ # Name is nil if establish_connection hasn't been called for
222
+ # some class along the inheritance chain up to AR::Base yet.
223
+ if name = active_connection_name
224
+ if conn = active_connections[name]
225
+ # Verify the connection.
226
+ conn.verify!(@@verification_timeout)
227
+ elsif spec = @@defined_connections[name]
228
+ # Activate this connection specification.
229
+ klass = name.constantize
230
+ klass.connection = spec
231
+ conn = active_connections[name]
232
+ end
233
+ end
234
+
235
+ conn or raise ConnectionNotEstablished
236
+ end
237
+
238
+ # Returns true if a connection that's accessible to this class have already been opened.
239
+ def self.connected?
240
+ active_connections[active_connection_name] ? true : false
241
+ end
242
+
243
+ # Remove the connection for this class. This will close the active
244
+ # connection and the defined connection (if they exist). The result
245
+ # can be used as argument for establish_connection, for easy
246
+ # re-establishing of the connection.
247
+ def self.remove_connection(klass=self)
248
+ spec = @@defined_connections[klass.name]
249
+ konn = active_connections[klass.name]
250
+ @@defined_connections.delete_if { |key, value| value == spec }
251
+ active_connections.delete_if { |key, value| value == konn }
252
+ konn.disconnect! if konn
253
+ spec.config if spec
254
+ end
255
+
256
+ # Set the connection for the class.
257
+ def self.connection=(spec) #:nodoc:
258
+ if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter)
259
+ active_connections[name] = spec
260
+ elsif spec.kind_of?(ConnectionSpecification)
261
+ config = spec.config.reverse_merge(:allow_concurrency => @@allow_concurrency)
262
+ self.connection = self.send(spec.adapter_method, config)
263
+ elsif spec.nil?
264
+ raise ConnectionNotEstablished
265
+ else
266
+ establish_connection spec
267
+ end
268
+ end
269
+
270
+ # connection state logging
271
+ def self.log_connections #:nodoc:
272
+ if logger
273
+ logger.info "Defined connections: #{@@defined_connections.inspect}"
274
+ logger.info "Active connections: #{active_connections.inspect}"
275
+ logger.info "Active connection name: #{@active_connection_name}"
276
+ end
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,130 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module DatabaseStatements
4
+ # Returns an array of record hashes with the column names as keys and
5
+ # column values as values.
6
+ def select_all(sql, name = nil)
7
+ select(sql, name)
8
+ end
9
+
10
+ # Returns a record hash with the column names as keys and column values
11
+ # as values.
12
+ def select_one(sql, name = nil)
13
+ result = select(sql, name)
14
+ result.first if result
15
+ end
16
+
17
+ # Returns a single value from a record
18
+ def select_value(sql, name = nil)
19
+ result = select_one(sql, name)
20
+ result.nil? ? nil : result.values.first
21
+ end
22
+
23
+ # Returns an array of the values of the first column in a select:
24
+ # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
25
+ def select_values(sql, name = nil)
26
+ result = select_all(sql, name)
27
+ result.map{ |v| v.values.first }
28
+ end
29
+
30
+ # Executes the SQL statement in the context of this connection.
31
+ def execute(sql, name = nil)
32
+ raise NotImplementedError, "execute is an abstract method"
33
+ end
34
+
35
+ # Returns the last auto-generated ID from the affected table.
36
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
37
+ raise NotImplementedError, "insert is an abstract method"
38
+ end
39
+
40
+ # Executes the update statement and returns the number of rows affected.
41
+ def update(sql, name = nil)
42
+ execute(sql, name)
43
+ end
44
+
45
+ # Executes the delete statement and returns the number of rows affected.
46
+ def delete(sql, name = nil)
47
+ update(sql, name)
48
+ end
49
+
50
+ # Wrap a block in a transaction. Returns result of block.
51
+ def transaction(start_db_transaction = true)
52
+ transaction_open = false
53
+ begin
54
+ if block_given?
55
+ if start_db_transaction
56
+ begin_db_transaction
57
+ transaction_open = true
58
+ end
59
+ yield
60
+ end
61
+ rescue Exception => database_transaction_rollback
62
+ if transaction_open
63
+ transaction_open = false
64
+ rollback_db_transaction
65
+ end
66
+ raise
67
+ end
68
+ ensure
69
+ commit_db_transaction if transaction_open
70
+ end
71
+
72
+ # Begins the transaction (and turns off auto-committing).
73
+ def begin_db_transaction() end
74
+
75
+ # Commits the transaction (and turns on auto-committing).
76
+ def commit_db_transaction() end
77
+
78
+ # Rolls back the transaction (and turns on auto-committing). Must be
79
+ # done if the transaction block raises an exception or returns false.
80
+ def rollback_db_transaction() end
81
+
82
+ # Alias for #add_limit_offset!.
83
+ def add_limit!(sql, options)
84
+ add_limit_offset!(sql, options) if options
85
+ end
86
+
87
+ # Appends +LIMIT+ and +OFFSET+ options to a SQL statement.
88
+ # This method *modifies* the +sql+ parameter.
89
+ # ===== Examples
90
+ # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
91
+ # generates
92
+ # SELECT * FROM suppliers LIMIT 10 OFFSET 50
93
+ def add_limit_offset!(sql, options)
94
+ if limit = options[:limit]
95
+ sql << " LIMIT #{limit}"
96
+ if offset = options[:offset]
97
+ sql << " OFFSET #{offset}"
98
+ end
99
+ end
100
+ end
101
+
102
+ # Appends a locking clause to a SQL statement. *Modifies the +sql+ parameter*.
103
+ # # SELECT * FROM suppliers FOR UPDATE
104
+ # add_lock! 'SELECT * FROM suppliers', :lock => true
105
+ # add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'
106
+ def add_lock!(sql, options)
107
+ case lock = options[:lock]
108
+ when true: sql << ' FOR UPDATE'
109
+ when String: sql << " #{lock}"
110
+ end
111
+ end
112
+
113
+ def default_sequence_name(table, column)
114
+ nil
115
+ end
116
+
117
+ # Set the sequence to the max value of the table's column.
118
+ def reset_sequence!(table, column, sequence = nil)
119
+ # Do nothing by default. Implement for PostgreSQL, Oracle, ...
120
+ end
121
+
122
+ protected
123
+ # Returns an array of record hashes with the column names as keys and
124
+ # column values as values.
125
+ def select(sql, name = nil)
126
+ raise NotImplementedError, "select is an abstract method"
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,58 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module Quoting
4
+ # Quotes the column value to help prevent
5
+ # {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
6
+ def quote(value, column = nil)
7
+ # records are quoted as their primary key
8
+ return value.quoted_id if value.respond_to?(:quoted_id)
9
+
10
+ case value
11
+ when String, ActiveSupport::Multibyte::Chars
12
+ value = value.to_s
13
+ if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
14
+ "'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
15
+ elsif column && [:integer, :float].include?(column.type)
16
+ value = column.type == :integer ? value.to_i : value.to_f
17
+ value.to_s
18
+ else
19
+ "'#{quote_string(value)}'" # ' (for ruby-mode)
20
+ end
21
+ when NilClass then "NULL"
22
+ when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
23
+ when FalseClass then (column && column.type == :integer ? '0' : quoted_false)
24
+ when Float, Fixnum, Bignum then value.to_s
25
+ # BigDecimals need to be output in a non-normalized form and quoted.
26
+ when BigDecimal then value.to_s('F')
27
+ when Date then "'#{value.to_s}'"
28
+ when Time, DateTime then "'#{quoted_date(value)}'"
29
+ else "'#{quote_string(value.to_yaml)}'"
30
+ end
31
+ end
32
+
33
+ # Quotes a string, escaping any ' (single quote) and \ (backslash)
34
+ # characters.
35
+ def quote_string(s)
36
+ s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
37
+ end
38
+
39
+ # Returns a quoted form of the column name. This is highly adapter
40
+ # specific.
41
+ def quote_column_name(name)
42
+ name
43
+ end
44
+
45
+ def quoted_true
46
+ "'t'"
47
+ end
48
+
49
+ def quoted_false
50
+ "'f'"
51
+ end
52
+
53
+ def quoted_date(value)
54
+ value.strftime("%Y-%m-%d %H:%M:%S")
55
+ end
56
+ end
57
+ end
58
+ end