activerecord 1.0.0 → 4.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 (255) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +213 -0
  5. data/examples/performance.rb +172 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +180 -84
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +248 -0
  10. data/lib/active_record/associations/association_scope.rb +135 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +92 -0
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +35 -0
  13. data/lib/active_record/associations/builder/association.rb +108 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  17. data/lib/active_record/associations/builder/has_many.rb +15 -0
  18. data/lib/active_record/associations/builder/has_one.rb +25 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +608 -0
  21. data/lib/active_record/associations/collection_proxy.rb +986 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +58 -39
  23. data/lib/active_record/associations/has_many_association.rb +116 -85
  24. data/lib/active_record/associations/has_many_through_association.rb +197 -0
  25. data/lib/active_record/associations/has_one_association.rb +102 -0
  26. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +235 -0
  31. data/lib/active_record/associations/join_helper.rb +45 -0
  32. data/lib/active_record/associations/preloader/association.rb +121 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  42. data/lib/active_record/associations/preloader.rb +178 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +1437 -431
  46. data/lib/active_record/attribute_assignment.rb +201 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +70 -0
  48. data/lib/active_record/attribute_methods/dirty.rb +118 -0
  49. data/lib/active_record/attribute_methods/primary_key.rb +122 -0
  50. data/lib/active_record/attribute_methods/query.rb +40 -0
  51. data/lib/active_record/attribute_methods/read.rb +107 -0
  52. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  53. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -0
  54. data/lib/active_record/attribute_methods/write.rb +63 -0
  55. data/lib/active_record/attribute_methods.rb +393 -0
  56. data/lib/active_record/autosave_association.rb +426 -0
  57. data/lib/active_record/base.rb +268 -930
  58. data/lib/active_record/callbacks.rb +203 -230
  59. data/lib/active_record/coders/yaml_column.rb +38 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +638 -0
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +390 -0
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +129 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +501 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +873 -0
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +389 -275
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  71. data/lib/active_record/connection_adapters/column.rb +318 -0
  72. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +517 -90
  75. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  76. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  77. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  79. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  80. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  81. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  82. data/lib/active_record/connection_adapters/postgresql_adapter.rb +911 -138
  83. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  84. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +624 -0
  85. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  86. data/lib/active_record/connection_handling.rb +98 -0
  87. data/lib/active_record/core.rb +463 -0
  88. data/lib/active_record/counter_cache.rb +122 -0
  89. data/lib/active_record/dynamic_matchers.rb +131 -0
  90. data/lib/active_record/errors.rb +213 -0
  91. data/lib/active_record/explain.rb +38 -0
  92. data/lib/active_record/explain_registry.rb +30 -0
  93. data/lib/active_record/explain_subscriber.rb +29 -0
  94. data/lib/active_record/fixture_set/file.rb +55 -0
  95. data/lib/active_record/fixtures.rb +892 -138
  96. data/lib/active_record/inheritance.rb +200 -0
  97. data/lib/active_record/integration.rb +60 -0
  98. data/lib/active_record/locale/en.yml +47 -0
  99. data/lib/active_record/locking/optimistic.rb +181 -0
  100. data/lib/active_record/locking/pessimistic.rb +77 -0
  101. data/lib/active_record/log_subscriber.rb +82 -0
  102. data/lib/active_record/migration/command_recorder.rb +164 -0
  103. data/lib/active_record/migration/join_table.rb +15 -0
  104. data/lib/active_record/migration.rb +1015 -0
  105. data/lib/active_record/model_schema.rb +345 -0
  106. data/lib/active_record/nested_attributes.rb +546 -0
  107. data/lib/active_record/null_relation.rb +65 -0
  108. data/lib/active_record/persistence.rb +509 -0
  109. data/lib/active_record/query_cache.rb +56 -0
  110. data/lib/active_record/querying.rb +62 -0
  111. data/lib/active_record/railtie.rb +205 -0
  112. data/lib/active_record/railties/console_sandbox.rb +5 -0
  113. data/lib/active_record/railties/controller_runtime.rb +50 -0
  114. data/lib/active_record/railties/databases.rake +402 -0
  115. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  116. data/lib/active_record/readonly_attributes.rb +30 -0
  117. data/lib/active_record/reflection.rb +544 -87
  118. data/lib/active_record/relation/batches.rb +93 -0
  119. data/lib/active_record/relation/calculations.rb +399 -0
  120. data/lib/active_record/relation/delegation.rb +125 -0
  121. data/lib/active_record/relation/finder_methods.rb +349 -0
  122. data/lib/active_record/relation/merger.rb +161 -0
  123. data/lib/active_record/relation/predicate_builder.rb +106 -0
  124. data/lib/active_record/relation/query_methods.rb +1044 -0
  125. data/lib/active_record/relation/spawn_methods.rb +73 -0
  126. data/lib/active_record/relation.rb +655 -0
  127. data/lib/active_record/result.rb +67 -0
  128. data/lib/active_record/runtime_registry.rb +17 -0
  129. data/lib/active_record/sanitization.rb +168 -0
  130. data/lib/active_record/schema.rb +65 -0
  131. data/lib/active_record/schema_dumper.rb +204 -0
  132. data/lib/active_record/schema_migration.rb +39 -0
  133. data/lib/active_record/scoping/default.rb +146 -0
  134. data/lib/active_record/scoping/named.rb +175 -0
  135. data/lib/active_record/scoping.rb +82 -0
  136. data/lib/active_record/serialization.rb +22 -0
  137. data/lib/active_record/serializers/xml_serializer.rb +197 -0
  138. data/lib/active_record/statement_cache.rb +26 -0
  139. data/lib/active_record/store.rb +156 -0
  140. data/lib/active_record/tasks/database_tasks.rb +203 -0
  141. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  142. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  143. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  146. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  147. data/lib/active_record/test_case.rb +96 -0
  148. data/lib/active_record/timestamp.rb +119 -0
  149. data/lib/active_record/transactions.rb +366 -69
  150. data/lib/active_record/translation.rb +22 -0
  151. data/lib/active_record/validations/associated.rb +49 -0
  152. data/lib/active_record/validations/presence.rb +65 -0
  153. data/lib/active_record/validations/uniqueness.rb +225 -0
  154. data/lib/active_record/validations.rb +64 -185
  155. data/lib/active_record/version.rb +11 -0
  156. data/lib/active_record.rb +149 -24
  157. data/lib/rails/generators/active_record/migration/migration_generator.rb +62 -0
  158. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  159. data/lib/rails/generators/active_record/migration/templates/migration.rb +39 -0
  160. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  161. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  162. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  163. data/lib/rails/generators/active_record.rb +23 -0
  164. metadata +261 -161
  165. data/CHANGELOG +0 -581
  166. data/README +0 -361
  167. data/RUNNING_UNIT_TESTS +0 -36
  168. data/dev-utils/eval_debugger.rb +0 -9
  169. data/examples/associations.png +0 -0
  170. data/examples/associations.rb +0 -87
  171. data/examples/shared_setup.rb +0 -15
  172. data/examples/validation.rb +0 -88
  173. data/install.rb +0 -60
  174. data/lib/active_record/associations/association_collection.rb +0 -70
  175. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -107
  176. data/lib/active_record/deprecated_associations.rb +0 -70
  177. data/lib/active_record/observer.rb +0 -71
  178. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  179. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  180. data/lib/active_record/support/clean_logger.rb +0 -10
  181. data/lib/active_record/support/inflector.rb +0 -70
  182. data/lib/active_record/vendor/mysql.rb +0 -1117
  183. data/lib/active_record/vendor/simple.rb +0 -702
  184. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  185. data/lib/active_record/wrappings.rb +0 -59
  186. data/rakefile +0 -122
  187. data/test/abstract_unit.rb +0 -16
  188. data/test/aggregations_test.rb +0 -34
  189. data/test/all.sh +0 -8
  190. data/test/associations_test.rb +0 -477
  191. data/test/base_test.rb +0 -513
  192. data/test/class_inheritable_attributes_test.rb +0 -33
  193. data/test/connections/native_mysql/connection.rb +0 -24
  194. data/test/connections/native_postgresql/connection.rb +0 -24
  195. data/test/connections/native_sqlite/connection.rb +0 -24
  196. data/test/deprecated_associations_test.rb +0 -336
  197. data/test/finder_test.rb +0 -67
  198. data/test/fixtures/accounts/signals37 +0 -3
  199. data/test/fixtures/accounts/unknown +0 -2
  200. data/test/fixtures/auto_id.rb +0 -4
  201. data/test/fixtures/column_name.rb +0 -3
  202. data/test/fixtures/companies/first_client +0 -6
  203. data/test/fixtures/companies/first_firm +0 -4
  204. data/test/fixtures/companies/second_client +0 -6
  205. data/test/fixtures/company.rb +0 -37
  206. data/test/fixtures/company_in_module.rb +0 -33
  207. data/test/fixtures/course.rb +0 -3
  208. data/test/fixtures/courses/java +0 -2
  209. data/test/fixtures/courses/ruby +0 -2
  210. data/test/fixtures/customer.rb +0 -30
  211. data/test/fixtures/customers/david +0 -6
  212. data/test/fixtures/db_definitions/mysql.sql +0 -96
  213. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  214. data/test/fixtures/db_definitions/postgresql.sql +0 -113
  215. data/test/fixtures/db_definitions/postgresql2.sql +0 -4
  216. data/test/fixtures/db_definitions/sqlite.sql +0 -85
  217. data/test/fixtures/db_definitions/sqlite2.sql +0 -4
  218. data/test/fixtures/default.rb +0 -2
  219. data/test/fixtures/developer.rb +0 -8
  220. data/test/fixtures/developers/david +0 -2
  221. data/test/fixtures/developers/jamis +0 -2
  222. data/test/fixtures/developers_projects/david_action_controller +0 -2
  223. data/test/fixtures/developers_projects/david_active_record +0 -2
  224. data/test/fixtures/developers_projects/jamis_active_record +0 -2
  225. data/test/fixtures/entrant.rb +0 -3
  226. data/test/fixtures/entrants/first +0 -3
  227. data/test/fixtures/entrants/second +0 -3
  228. data/test/fixtures/entrants/third +0 -3
  229. data/test/fixtures/fixture_database.sqlite +0 -0
  230. data/test/fixtures/fixture_database_2.sqlite +0 -0
  231. data/test/fixtures/movie.rb +0 -5
  232. data/test/fixtures/movies/first +0 -2
  233. data/test/fixtures/movies/second +0 -2
  234. data/test/fixtures/project.rb +0 -3
  235. data/test/fixtures/projects/action_controller +0 -2
  236. data/test/fixtures/projects/active_record +0 -2
  237. data/test/fixtures/reply.rb +0 -21
  238. data/test/fixtures/subscriber.rb +0 -5
  239. data/test/fixtures/subscribers/first +0 -2
  240. data/test/fixtures/subscribers/second +0 -2
  241. data/test/fixtures/topic.rb +0 -20
  242. data/test/fixtures/topics/first +0 -9
  243. data/test/fixtures/topics/second +0 -8
  244. data/test/fixtures_test.rb +0 -20
  245. data/test/inflector_test.rb +0 -104
  246. data/test/inheritance_test.rb +0 -125
  247. data/test/lifecycle_test.rb +0 -110
  248. data/test/modules_test.rb +0 -21
  249. data/test/multiple_db_test.rb +0 -46
  250. data/test/pk_test.rb +0 -57
  251. data/test/reflection_test.rb +0 -78
  252. data/test/thread_safety_test.rb +0 -33
  253. data/test/transactions_test.rb +0 -83
  254. data/test/unconnected_test.rb +0 -24
  255. data/test/validations_test.rb +0 -126
@@ -1,326 +1,440 @@
1
- require 'benchmark'
2
1
  require 'date'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/util'
4
+ require 'active_support/core_ext/benchmark'
5
+ require 'active_record/connection_adapters/schema_cache'
6
+ require 'active_record/connection_adapters/abstract/schema_dumper'
7
+ require 'monitor'
3
8
 
4
9
  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
10
+ module ConnectionAdapters # :nodoc:
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :Column
14
+ autoload :ConnectionSpecification
15
+
16
+ autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
17
+ autoload :IndexDefinition
18
+ autoload :ColumnDefinition
19
+ autoload :TableDefinition
20
+ autoload :Table
21
+ autoload :AlterTable
11
22
  end
12
23
 
13
- # The class -> [adapter_method, config] map
14
- @@defined_connections = {}
24
+ autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
25
+ autoload :ConnectionHandler
26
+ autoload :ConnectionManagement
27
+ end
15
28
 
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:
29
+ autoload_under 'abstract' do
30
+ autoload :SchemaStatements
31
+ autoload :DatabaseStatements
32
+ autoload :DatabaseLimits
33
+ autoload :Quoting
34
+ autoload :ConnectionPool
35
+ autoload :QueryCache
36
+ end
37
+
38
+ autoload_at 'active_record/connection_adapters/abstract/transaction' do
39
+ autoload :ClosedTransaction
40
+ autoload :RealTransaction
41
+ autoload :SavepointTransaction
42
+ end
43
+
44
+ # Active Record supports multiple database systems. AbstractAdapter and
45
+ # related classes form the abstraction layer which makes this possible.
46
+ # An AbstractAdapter represents a connection to a database, and provides an
47
+ # abstract interface for database-specific functionality such as establishing
48
+ # a connection, escaping values, building the right SQL fragments for ':offset'
49
+ # and ':limit' options, etc.
49
50
  #
50
- # class Courses < ActiveRecord::Base
51
- # ...
52
- # end
51
+ # All the concrete database adapters follow the interface laid down in this class.
52
+ # ActiveRecord::Base.connection returns an AbstractAdapter object, which
53
+ # you can use.
53
54
  #
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
55
+ # Most of the methods in the adapter are useful during migrations. Most
56
+ # notably, the instance methods provided by SchemaStatement are very useful.
57
+ class AbstractAdapter
58
+ include Quoting, DatabaseStatements, SchemaStatements
59
+ include DatabaseLimits
60
+ include QueryCache
61
+ include ActiveSupport::Callbacks
62
+ include MonitorMixin
63
+ include ColumnDumper
64
+
65
+ SIMPLE_INT = /\A\d+\z/
66
+
67
+ define_callbacks :checkout, :checkin
68
+
69
+ attr_accessor :visitor, :pool
70
+ attr_reader :schema_cache, :last_use, :in_use, :logger
71
+ alias :in_use? :in_use
72
+
73
+ def self.type_cast_config_to_integer(config)
74
+ if config =~ SIMPLE_INT
75
+ config.to_i
76
+ else
77
+ config
83
78
  end
84
- klass = klass.superclass
85
79
  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
80
+
81
+ def self.type_cast_config_to_boolean(config)
82
+ if config == "false"
83
+ false
95
84
  else
96
- klass = klass.superclass
85
+ config
97
86
  end
98
87
  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
121
88
 
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
89
+ def initialize(connection, logger = nil, pool = nil) #:nodoc:
90
+ super()
91
+
92
+ @connection = connection
93
+ @in_use = false
94
+ @instrumenter = ActiveSupport::Notifications.instrumenter
95
+ @last_use = false
96
+ @logger = logger
97
+ @pool = pool
98
+ @query_cache = Hash.new { |h,sql| h[sql] = {} }
99
+ @query_cache_enabled = false
100
+ @schema_cache = SchemaCache.new self
101
+ @visitor = nil
129
102
  end
130
- end
131
- end
132
103
 
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?
143
- end
144
-
145
- def default
146
- type_cast(@default)
147
- end
148
-
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
104
+ def valid_type?(type)
105
+ true
158
106
  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
107
+
108
+ class SchemaCreation
109
+ def initialize(conn)
110
+ @conn = conn
111
+ @cache = {}
112
+ end
113
+
114
+ def accept(o)
115
+ m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
116
+ send m, o
117
+ end
118
+
119
+ private
120
+
121
+ def visit_AlterTable(o)
122
+ sql = "ALTER TABLE #{quote_table_name(o.name)} "
123
+ sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
124
+ end
125
+
126
+ def visit_AddColumn(o)
127
+ sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
128
+ sql = "ADD #{quote_column_name(o.name)} #{sql_type}"
129
+ add_column_options!(sql, column_options(o))
130
+ end
131
+
132
+ def visit_ColumnDefinition(o)
133
+ sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
134
+ column_sql = "#{quote_column_name(o.name)} #{sql_type}"
135
+ add_column_options!(column_sql, column_options(o)) unless o.primary_key?
136
+ column_sql
137
+ end
138
+
139
+ def visit_TableDefinition(o)
140
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
141
+ create_sql << "#{quote_table_name(o.name)} ("
142
+ create_sql << o.columns.map { |c| accept c }.join(', ')
143
+ create_sql << ") #{o.options}"
144
+ create_sql
145
+ end
146
+
147
+ def column_options(o)
148
+ column_options = {}
149
+ column_options[:null] = o.null unless o.null.nil?
150
+ column_options[:default] = o.default unless o.default.nil?
151
+ column_options[:column] = o
152
+ column_options
171
153
  end
172
- end
173
-
174
- def human_name
175
- Base.human_attribute_name(@name)
176
- end
177
154
 
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
155
+ def quote_column_name(name)
156
+ @conn.quote_column_name name
184
157
  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
158
+
159
+ def quote_table_name(name)
160
+ @conn.quote_table_name name
191
161
  end
192
162
 
193
- def extract_limit(sql_type)
194
- $1.to_i if sql_type =~ /\((.*)\)/
163
+ def type_to_sql(type, limit, precision, scale)
164
+ @conn.type_to_sql type.to_sym, limit, precision, scale
195
165
  end
196
166
 
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
167
+ def add_column_options!(column_sql, column_options)
168
+ @conn.add_column_options! column_sql, column_options
169
+ column_sql
170
+ end
171
+ end
172
+
173
+ def schema_creation
174
+ SchemaCreation.new self
175
+ end
176
+
177
+ def lease
178
+ synchronize do
179
+ unless in_use
180
+ @in_use = true
181
+ @last_use = Time.now
213
182
  end
214
183
  end
215
- end
184
+ end
216
185
 
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
186
+ def schema_cache=(cache)
187
+ cache.connection = self
188
+ @schema_cache = cache
189
+ end
190
+
191
+ def expire
192
+ @in_use = false
193
+ end
194
+
195
+ def unprepared_visitor
196
+ self.class::BindSubstitution.new self
197
+ end
198
+
199
+ def unprepared_statement
200
+ old, @visitor = @visitor, unprepared_visitor
201
+ yield
202
+ ensure
203
+ @visitor = old
204
+ end
222
205
 
223
- include Benchmark
206
+ # Returns the human-readable name of the adapter. Use mixed case - one
207
+ # can always use downcase if needed.
208
+ def adapter_name
209
+ 'Abstract'
210
+ end
224
211
 
225
- def initialize(connection, logger = nil) # :nodoc:
226
- @connection, @logger = connection, logger
227
- @runtime = 0
212
+ # Does this adapter support migrations? Backend specific, as the
213
+ # abstract adapter always returns +false+.
214
+ def supports_migrations?
215
+ false
228
216
  end
229
217
 
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
218
+ # Can this adapter determine the primary key for tables not attached
219
+ # to an Active Record class, such as join tables? Backend specific, as
220
+ # the abstract adapter always returns +false+.
221
+ def supports_primary_key?
222
+ false
223
+ end
235
224
 
236
- # Returns an array of column objects for the table specified by +table_name+.
237
- def columns(table_name, name = nil) end
225
+ # Does this adapter support using DISTINCT within COUNT? This is +true+
226
+ # for all adapters except sqlite.
227
+ def supports_count_distinct?
228
+ true
229
+ end
238
230
 
239
- # Returns the last auto-generated ID from the affected table.
240
- def insert(sql, name = nil, pk = nil, id_value = nil) end
231
+ # Does this adapter support DDL rollbacks in transactions? That is, would
232
+ # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
233
+ # SQL Server, and others support this. MySQL and others do not.
234
+ def supports_ddl_transactions?
235
+ false
236
+ end
241
237
 
242
- # Executes the update statement.
243
- def update(sql, name = nil) end
238
+ def supports_bulk_alter?
239
+ false
240
+ end
244
241
 
245
- # Executes the delete statement.
246
- def delete(sql, name = nil) end
242
+ # Does this adapter support savepoints? PostgreSQL and MySQL do,
243
+ # SQLite < 3.6.8 does not.
244
+ def supports_savepoints?
245
+ false
246
+ end
247
247
 
248
- def reset_runtime # :nodoc:
249
- rt = @runtime
250
- @runtime = 0
251
- return rt
248
+ # Should primary key values be selected from their corresponding
249
+ # sequence before the insert statement? If true, next_sequence_value
250
+ # is called before each insert to set the record's primary key.
251
+ # This is false for all adapters but Firebird.
252
+ def prefetch_primary_key?(table_name = nil)
253
+ false
252
254
  end
253
255
 
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
256
+ # Does this adapter support index sort order?
257
+ def supports_index_sort_order?
258
+ false
259
+ end
259
260
 
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
261
+ # Does this adapter support partial indices?
262
+ def supports_partial_index?
263
+ false
264
+ end
263
265
 
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(/'/, "''")}'"
273
- end
266
+ # Does this adapter support explain? As of this writing sqlite3,
267
+ # mysql2, and postgresql are the only ones that do.
268
+ def supports_explain?
269
+ false
274
270
  end
275
271
 
276
- def quote_column_name(name)
277
- return name
272
+ # Does this adapter support setting the isolation level for a transaction?
273
+ def supports_transaction_isolation?
274
+ false
278
275
  end
279
276
 
280
- # Returns a string of the CREATE TABLE SQL statements for recreating the entire structure of the database.
281
- def structure_dump() end
277
+ # Does this adapter support database extensions? As of this writing only
278
+ # postgresql does.
279
+ def supports_extensions?
280
+ false
281
+ end
282
282
 
283
- protected
284
- def log(sql, name, connection, &action)
285
- begin
286
- if @logger.nil?
287
- action.call(connection)
288
- else
289
- result = nil
290
- bm = measure { result = action.call(connection) }
291
- @runtime += bm.real
292
- log_info(sql, name, bm.real)
293
- result
294
- end
295
- rescue => e
296
- log_info("#{e.message}: #{sql}", name, 0)
297
- raise ActiveRecord::StatementInvalid, "#{e.message}: #{sql}"
298
- end
299
- end
283
+ # A list of extensions, to be filled in by adapters that support them. At
284
+ # the moment only postgresql does.
285
+ def extensions
286
+ []
287
+ end
300
288
 
301
- def log_info(sql, name, runtime)
302
- if @logger.nil? then return end
289
+ # A list of index algorithms, to be filled by adapters that support them.
290
+ # MySQL and PostgreSQL have support for them right now.
291
+ def index_algorithms
292
+ {}
293
+ end
303
294
 
304
- @logger.info(
305
- format_log_entry(
306
- "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})",
307
- sql.gsub(/ +/, " ")
308
- )
309
- )
310
- end
295
+ # QUOTING ==================================================
311
296
 
312
- 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"
315
- else
316
- @@row_even = true; caller_color = "1;36"; message_color = "4;35"; dump_color = "0;37"
317
- 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
- end
297
+ # Returns a bind substitution value given a +column+ and list of current
298
+ # +binds+.
299
+ def substitute_at(column, index)
300
+ Arel::Nodes::BindParam.new '?'
301
+ end
302
+
303
+ # REFERENTIAL INTEGRITY ====================================
304
+
305
+ # Override to turn off referential integrity while executing <tt>&block</tt>.
306
+ def disable_referential_integrity
307
+ yield
308
+ end
309
+
310
+ # CONNECTION MANAGEMENT ====================================
311
+
312
+ # Checks whether the connection to the database is still active. This includes
313
+ # checking whether the database is actually capable of responding, i.e. whether
314
+ # the connection isn't stale.
315
+ def active?
316
+ end
317
+
318
+ # Disconnects from the database if already connected, and establishes a
319
+ # new connection with the database. Implementors should call super if they
320
+ # override the default implementation.
321
+ def reconnect!
322
+ clear_cache!
323
+ reset_transaction
324
+ end
325
+
326
+ # Disconnects from the database if already connected. Otherwise, this
327
+ # method does nothing.
328
+ def disconnect!
329
+ clear_cache!
330
+ reset_transaction
331
+ end
332
+
333
+ # Reset the state of this connection, directing the DBMS to clear
334
+ # transactions and other connection-related server-side state. Usually a
335
+ # database-dependent operation.
336
+ #
337
+ # The default implementation does nothing; the implementation should be
338
+ # overridden by concrete adapters.
339
+ def reset!
340
+ # this should be overridden by concrete adapters
341
+ end
342
+
343
+ ###
344
+ # Clear any caching the database adapter may be doing, for example
345
+ # clearing the prepared statement cache. This is database specific.
346
+ def clear_cache!
347
+ # this should be overridden by concrete adapters
348
+ end
349
+
350
+ # Returns true if its required to reload the connection between requests for development mode.
351
+ # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
352
+ def requires_reloading?
353
+ false
354
+ end
355
+
356
+ # Checks whether the connection to the database is still active (i.e. not stale).
357
+ # This is done under the hood by calling <tt>active?</tt>. If the connection
358
+ # is no longer active, then this method will reconnect to the database.
359
+ def verify!(*ignored)
360
+ reconnect! unless active?
361
+ end
362
+
363
+ # Provides access to the underlying database driver for this adapter. For
364
+ # example, this method returns a Mysql object in case of MysqlAdapter,
365
+ # and a PGconn object in case of PostgreSQLAdapter.
366
+ #
367
+ # This is useful for when you need to call a proprietary method such as
368
+ # PostgreSQL's lo_* methods.
369
+ def raw_connection
370
+ @connection
371
+ end
372
+
373
+ def open_transactions
374
+ @transaction.number
375
+ end
376
+
377
+ def increment_open_transactions
378
+ ActiveSupport::Deprecation.warn "#increment_open_transactions is deprecated and has no effect"
379
+ end
380
+
381
+ def decrement_open_transactions
382
+ ActiveSupport::Deprecation.warn "#decrement_open_transactions is deprecated and has no effect"
383
+ end
384
+
385
+ def transaction_joinable=(joinable)
386
+ message = "#transaction_joinable= is deprecated. Please pass the :joinable option to #begin_transaction instead."
387
+ ActiveSupport::Deprecation.warn message
388
+ @transaction.joinable = joinable
389
+ end
390
+
391
+ def create_savepoint
392
+ end
393
+
394
+ def rollback_to_savepoint
395
+ end
396
+
397
+ def release_savepoint
398
+ end
399
+
400
+ def case_sensitive_modifier(node)
401
+ node
402
+ end
403
+
404
+ def case_insensitive_comparison(table, attribute, column, value)
405
+ table[attribute].lower.eq(table.lower(value))
406
+ end
407
+
408
+ def current_savepoint_name
409
+ "active_record_#{open_transactions}"
410
+ end
411
+
412
+ # Check the connection back in to the connection pool
413
+ def close
414
+ pool.checkin self
415
+ end
416
+
417
+ protected
418
+
419
+ def log(sql, name = "SQL", binds = [])
420
+ @instrumenter.instrument(
421
+ "sql.active_record",
422
+ :sql => sql,
423
+ :name => name,
424
+ :connection_id => object_id,
425
+ :binds => binds) { yield }
426
+ rescue => e
427
+ message = "#{e.class.name}: #{e.message}: #{sql}"
428
+ @logger.error message if @logger
429
+ exception = translate_exception(e, message)
430
+ exception.set_backtrace e.backtrace
431
+ raise exception
432
+ end
433
+
434
+ def translate_exception(exception, message)
435
+ # override in derived class
436
+ ActiveRecord::StatementInvalid.new(message, exception)
437
+ end
324
438
  end
325
439
  end
326
440
  end